summaryrefslogtreecommitdiff
path: root/chromium/ui
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui')
-rw-r--r--chromium/ui/DIR_METADATA3
-rw-r--r--chromium/ui/OWNERS2
-rw-r--r--chromium/ui/accelerated_widget_mac/BUILD.gn2
-rw-r--r--chromium/ui/accelerated_widget_mac/DEPS1
-rw-r--r--chromium/ui/accelerated_widget_mac/DIR_METADATA3
-rw-r--r--chromium/ui/accelerated_widget_mac/OWNERS1
-rw-r--r--chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm64
-rw-r--r--chromium/ui/accelerated_widget_mac/ca_transaction_observer.h3
-rw-r--r--chromium/ui/accelerated_widget_mac/ca_transaction_observer.mm4
-rw-r--r--chromium/ui/accessibility/BUILD.gn32
-rw-r--r--chromium/ui/accessibility/DIR_METADATA4
-rw-r--r--chromium/ui/accessibility/OWNERS11
-rw-r--r--chromium/ui/accessibility/accessibility_features.cc51
-rw-r--r--chromium/ui/accessibility/accessibility_features.h45
-rw-r--r--chromium/ui/accessibility/accessibility_switches.cc26
-rw-r--r--chromium/ui/accessibility/accessibility_switches.h14
-rw-r--r--chromium/ui/accessibility/ax_action_data.h9
-rw-r--r--chromium/ui/accessibility/ax_action_handler.h4
-rw-r--r--chromium/ui/accessibility/ax_action_handler_base.h4
-rw-r--r--chromium/ui/accessibility/ax_action_target.h16
-rw-r--r--chromium/ui/accessibility/ax_active_popup.cc43
-rw-r--r--chromium/ui/accessibility/ax_active_popup.h8
-rw-r--r--chromium/ui/accessibility/ax_assistant_structure.cc83
-rw-r--r--chromium/ui/accessibility/ax_assistant_structure.h11
-rw-r--r--chromium/ui/accessibility/ax_enum_util.cc12
-rw-r--r--chromium/ui/accessibility/ax_enum_util.h2
-rw-r--r--chromium/ui/accessibility/ax_enums.mojom14
-rw-r--r--chromium/ui/accessibility/ax_event.cc5
-rw-r--r--chromium/ui/accessibility/ax_event.h7
-rw-r--r--chromium/ui/accessibility/ax_event_generator.cc69
-rw-r--r--chromium/ui/accessibility/ax_event_generator.h8
-rw-r--r--chromium/ui/accessibility/ax_event_generator_unittest.cc12
-rw-r--r--chromium/ui/accessibility/ax_generated_tree_unittest.cc58
-rw-r--r--chromium/ui/accessibility/ax_language_detection.h2
-rw-r--r--chromium/ui/accessibility/ax_mode.h11
-rw-r--r--chromium/ui/accessibility/ax_node.cc283
-rw-r--r--chromium/ui/accessibility/ax_node.h137
-rw-r--r--chromium/ui/accessibility/ax_node_data.cc35
-rw-r--r--chromium/ui/accessibility/ax_node_data.h19
-rw-r--r--chromium/ui/accessibility/ax_node_data_unittest.cc2
-rw-r--r--chromium/ui/accessibility/ax_node_position.cc358
-rw-r--r--chromium/ui/accessibility/ax_node_position.h47
-rw-r--r--chromium/ui/accessibility/ax_node_position_perftest.cc2
-rw-r--r--chromium/ui/accessibility/ax_node_position_unittest.cc4317
-rw-r--r--chromium/ui/accessibility/ax_node_unittest.cc125
-rw-r--r--chromium/ui/accessibility/ax_param_traits_macros.h3
-rw-r--r--chromium/ui/accessibility/ax_position.h2292
-rw-r--r--chromium/ui/accessibility/ax_range.h4
-rw-r--r--chromium/ui/accessibility/ax_range_unittest.cc43
-rw-r--r--chromium/ui/accessibility/ax_role_properties.cc78
-rw-r--r--chromium/ui/accessibility/ax_role_properties.h27
-rw-r--r--chromium/ui/accessibility/ax_serializable_tree.cc14
-rw-r--r--chromium/ui/accessibility/ax_serializable_tree.h5
-rw-r--r--chromium/ui/accessibility/ax_table_fuzzer.cc12
-rw-r--r--chromium/ui/accessibility/ax_table_info.cc18
-rw-r--r--chromium/ui/accessibility/ax_table_info.h22
-rw-r--r--chromium/ui/accessibility/ax_table_info_unittest.cc6
-rw-r--r--chromium/ui/accessibility/ax_text_utils.cc27
-rw-r--r--chromium/ui/accessibility/ax_text_utils.h4
-rw-r--r--chromium/ui/accessibility/ax_text_utils_unittest.cc22
-rw-r--r--chromium/ui/accessibility/ax_tree.cc251
-rw-r--r--chromium/ui/accessibility/ax_tree.h78
-rw-r--r--chromium/ui/accessibility/ax_tree_combiner.cc2
-rw-r--r--chromium/ui/accessibility/ax_tree_combiner.h6
-rw-r--r--chromium/ui/accessibility/ax_tree_combiner_unittest.cc2
-rw-r--r--chromium/ui/accessibility/ax_tree_data.cc6
-rw-r--r--chromium/ui/accessibility/ax_tree_data.h20
-rw-r--r--chromium/ui/accessibility/ax_tree_id_registry.h4
-rw-r--r--chromium/ui/accessibility/ax_tree_manager.h10
-rw-r--r--chromium/ui/accessibility/ax_tree_manager_map.cc11
-rw-r--r--chromium/ui/accessibility/ax_tree_manager_map.h6
-rw-r--r--chromium/ui/accessibility/ax_tree_observer.h14
-rw-r--r--chromium/ui/accessibility/ax_tree_serializer.h202
-rw-r--r--chromium/ui/accessibility/ax_tree_serializer_unittest.cc34
-rw-r--r--chromium/ui/accessibility/ax_tree_source.h11
-rw-r--r--chromium/ui/accessibility/ax_tree_source_checker.h68
-rw-r--r--chromium/ui/accessibility/ax_tree_source_checker_unittest.cc58
-rw-r--r--chromium/ui/accessibility/ax_tree_unittest.cc89
-rw-r--r--chromium/ui/accessibility/ax_tree_update.cc81
-rw-r--r--chromium/ui/accessibility/ax_tree_update.h80
-rw-r--r--chromium/ui/accessibility/ax_tree_update_forward.h6
-rw-r--r--chromium/ui/accessibility/extensions/BUILD.gn9
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/BUILD.gn6
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/README23
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/background/tabs_api_handler.js9
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/api.js4
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/mathjax.js4
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/pdf_processor.js2
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/shadydom_loader.js22
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/common/interframe.js2
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/cvox2/background/desktop_automation_handler.js3
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/host/chrome/braille_background.js2
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/manifest.json.jinja249
-rw-r--r--chromium/ui/accessibility/extensions/chromevoxclassic/testing/chromevox_unittest_base.js4
-rw-r--r--chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings.grd6
-rw-r--r--chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_be.xtb2
-rw-r--r--chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_fi.xtb2
-rw-r--r--chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_nl.xtb24
-rw-r--r--chromium/ui/accessibility/mojom/BUILD.gn14
-rw-r--r--chromium/ui/accessibility/mojom/ax_action_data_mojom_traits_unittest.cc3
-rw-r--r--chromium/ui/accessibility/mojom/ax_event.mojom1
-rw-r--r--chromium/ui/accessibility/mojom/ax_event_intent_mojom_traits_unittest.cc4
-rw-r--r--chromium/ui/accessibility/mojom/ax_event_mojom_traits.cc1
-rw-r--r--chromium/ui/accessibility/mojom/ax_event_mojom_traits.h3
-rw-r--r--chromium/ui/accessibility/mojom/ax_event_mojom_traits_unittest.cc4
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc110
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h47
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc30
-rw-r--r--chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits_unittest.cc2
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_data_mojom_traits_unittest.cc2
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_id_mojom_traits_unittest.cc12
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_update.mojom1
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.cc1
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.h5
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc5
-rw-r--r--chromium/ui/accessibility/null_ax_action_target.cc39
-rw-r--r--chromium/ui/accessibility/null_ax_action_target.h11
-rw-r--r--chromium/ui/accessibility/null_ax_action_target_unittest.cc14
-rw-r--r--chromium/ui/accessibility/platform/BUILD.gn24
-rw-r--r--chromium/ui/accessibility/platform/ax_android_constants.cc4
-rw-r--r--chromium/ui/accessibility/platform/ax_android_constants.h2
-rw-r--r--chromium/ui/accessibility/platform/ax_fragment_root_win.cc5
-rw-r--r--chromium/ui/accessibility/platform/ax_fragment_root_win.h2
-rw-r--r--chromium/ui/accessibility/platform/ax_fragment_root_win_unittest.cc60
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc60
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_auralinux.h1
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_base.cc79
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_base.h43
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_base_unittest.cc41
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_delegate.h44
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_delegate_base.cc71
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_delegate_base.h12
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_mac.mm95
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc7
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_textprovider_win.cc6
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_textprovider_win.h1
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc104
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc210
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h4
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc765
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win.cc436
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win.h30
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc152
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win_unittest.h6
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_relation_win.cc34
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_relation_win.h8
-rw-r--r--chromium/ui/accessibility/platform/ax_private_webkit_constants_mac.h96
-rw-r--r--chromium/ui/accessibility/platform/ax_private_webkit_constants_mac.mm91
-rw-r--r--chromium/ui/accessibility/platform/ax_system_caret_win.cc2
-rw-r--r--chromium/ui/accessibility/platform/ax_unique_id.cc4
-rw-r--r--chromium/ui/accessibility/platform/ax_unique_id_unittest.cc18
-rw-r--r--chromium/ui/accessibility/platform/compute_attributes.cc7
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_event_recorder.cc24
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_event_recorder.h73
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_inspect.cc (renamed from chromium/ui/accessibility/platform/inspect/inspect.cc)16
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_inspect.h (renamed from chromium/ui/accessibility/platform/inspect/inspect.h)17
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_inspect_utils_auralinux.cc443
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_inspect_utils_auralinux.h23
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_inspect_utils_win.cc748
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_inspect_utils_win.h49
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_property_node.cc (renamed from chromium/ui/accessibility/platform/inspect/property_node.cc)4
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_property_node.h (renamed from chromium/ui/accessibility/platform/inspect/property_node.h)6
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_property_node_unittest.cc (renamed from chromium/ui/accessibility/platform/inspect/property_node_unittest.cc)5
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_tree_formatter.cc (renamed from chromium/ui/accessibility/platform/inspect/tree_formatter.cc)13
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_tree_formatter.h120
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc228
-rw-r--r--chromium/ui/accessibility/platform/inspect/ax_tree_formatter_base.h129
-rw-r--r--chromium/ui/accessibility/platform/inspect/tree_formatter.h87
-rw-r--r--chromium/ui/accessibility/platform/test_ax_node_wrapper.cc26
-rw-r--r--chromium/ui/accessibility/platform/test_ax_node_wrapper.h8
-rw-r--r--chromium/ui/accessibility/platform/uia_registrar_win.cc40
-rw-r--r--chromium/ui/accessibility/platform/uia_registrar_win.h29
-rw-r--r--chromium/ui/accessibility/test_ax_node_helper.cc4
-rw-r--r--chromium/ui/accessibility/test_ax_tree_manager.cc39
-rw-r--r--chromium/ui/accessibility/test_ax_tree_manager.h7
-rw-r--r--chromium/ui/android/BUILD.gn52
-rw-r--r--chromium/ui/android/OWNERS3
-rw-r--r--chromium/ui/android/color_helpers.cc32
-rw-r--r--chromium/ui/android/color_helpers.h38
-rw-r--r--chromium/ui/android/color_helpers_unittest.cc58
-rw-r--r--chromium/ui/android/delegated_frame_host_android.cc67
-rw-r--r--chromium/ui/android/delegated_frame_host_android.h19
-rw-r--r--chromium/ui/android/junit/src/org/chromium/ui/base/ActivityAndroidPermissionDelegateTest.java47
-rw-r--r--chromium/ui/android/junit/src/org/chromium/ui/base/ClipboardTest.java9
-rw-r--r--chromium/ui/android/overscroll_glow.cc4
-rw-r--r--chromium/ui/android/overscroll_glow.h2
-rw-r--r--chromium/ui/android/view_android.cc2
-rw-r--r--chromium/ui/android/window_android.cc28
-rw-r--r--chromium/ui/android/window_android.h5
-rw-r--r--chromium/ui/aura/BUILD.gn5
-rw-r--r--chromium/ui/aura/DIR_METADATA3
-rw-r--r--chromium/ui/aura/OWNERS1
-rw-r--r--chromium/ui/aura/client/aura_constants.cc5
-rw-r--r--chromium/ui/aura/client/aura_constants.h18
-rw-r--r--chromium/ui/aura/client/drag_drop_client_observer.h3
-rw-r--r--chromium/ui/aura/client/drag_drop_delegate.cc8
-rw-r--r--chromium/ui/aura/client/drag_drop_delegate.h27
-rw-r--r--chromium/ui/aura/env.cc31
-rw-r--r--chromium/ui/aura/env.h21
-rw-r--r--chromium/ui/aura/env_observer.h3
-rw-r--r--chromium/ui/aura/event_injector.cc2
-rw-r--r--chromium/ui/aura/gestures/DIR_METADATA4
-rw-r--r--chromium/ui/aura/gestures/OWNERS6
-rw-r--r--chromium/ui/aura/gestures/gesture_recognizer_unittest.cc94
-rw-r--r--chromium/ui/aura/native_window_occlusion_tracker_unittest.cc73
-rw-r--r--chromium/ui/aura/native_window_occlusion_tracker_win.cc158
-rw-r--r--chromium/ui/aura/native_window_occlusion_tracker_win.h25
-rw-r--r--chromium/ui/aura/scoped_simple_keyboard_hook.cc2
-rw-r--r--chromium/ui/aura/scoped_window_capture_request.cc42
-rw-r--r--chromium/ui/aura/scoped_window_capture_request.h50
-rw-r--r--chromium/ui/aura/test/ui_controls_ozone.cc3
-rw-r--r--chromium/ui/aura/test/ui_controls_ozone.h3
-rw-r--r--chromium/ui/aura/window.cc69
-rw-r--r--chromium/ui/aura/window.h56
-rw-r--r--chromium/ui/aura/window_event_dispatcher.cc17
-rw-r--r--chromium/ui/aura/window_event_dispatcher.h5
-rw-r--r--chromium/ui/aura/window_event_dispatcher_unittest.cc82
-rw-r--r--chromium/ui/aura/window_occlusion_tracker.cc21
-rw-r--r--chromium/ui/aura/window_occlusion_tracker.h5
-rw-r--r--chromium/ui/aura/window_targeter.cc95
-rw-r--r--chromium/ui/aura/window_targeter.h13
-rw-r--r--chromium/ui/aura/window_targeter_unittest.cc37
-rw-r--r--chromium/ui/aura/window_tree_host.cc28
-rw-r--r--chromium/ui/aura/window_tree_host.h16
-rw-r--r--chromium/ui/aura/window_tree_host_observer.h6
-rw-r--r--chromium/ui/aura/window_tree_host_platform.cc24
-rw-r--r--chromium/ui/aura/window_tree_host_platform_unittest.cc40
-rw-r--r--chromium/ui/aura/window_tree_host_unittest.cc5
-rw-r--r--chromium/ui/aura/window_unittest.cc88
-rw-r--r--chromium/ui/aura_extra/BUILD.gn1
-rw-r--r--chromium/ui/aura_extra/DIR_METADATA3
-rw-r--r--chromium/ui/aura_extra/OWNERS1
-rw-r--r--chromium/ui/aura_extra/skia_vector_resource.cc3
-rw-r--r--chromium/ui/base/BUILD.gn125
-rw-r--r--chromium/ui/base/DEPS1
-rw-r--r--chromium/ui/base/OWNERS2
-rw-r--r--chromium/ui/base/accelerators/accelerator.cc9
-rw-r--r--chromium/ui/base/accelerators/accelerator_history.cc56
-rw-r--r--chromium/ui/base/accelerators/accelerator_history.h9
-rw-r--r--chromium/ui/base/accelerators/accelerator_history_unittest.cc20
-rw-r--r--chromium/ui/base/accelerators/accelerator_manager.cc7
-rw-r--r--chromium/ui/base/accelerators/accelerator_manager.h6
-rw-r--r--chromium/ui/base/accelerators/accelerator_manager_unittest.cc3
-rw-r--r--chromium/ui/base/accelerators/global_media_keys_listener_win.h1
-rw-r--r--chromium/ui/base/accelerators/media_keys_listener.h7
-rw-r--r--chromium/ui/base/accelerators/media_keys_listener_linux.cc34
-rw-r--r--chromium/ui/base/accelerators/media_keys_listener_mac.mm12
-rw-r--r--chromium/ui/base/accelerators/media_keys_listener_win.cc15
-rw-r--r--chromium/ui/base/accelerators/system_media_controls_media_keys_listener.cc144
-rw-r--r--chromium/ui/base/accelerators/system_media_controls_media_keys_listener.h74
-rw-r--r--chromium/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc166
-rw-r--r--chromium/ui/base/clipboard/BUILD.gn26
-rw-r--r--chromium/ui/base/clipboard/OWNERS4
-rw-r--r--chromium/ui/base/clipboard/README.md18
-rw-r--r--chromium/ui/base/clipboard/clipboard.cc13
-rw-r--r--chromium/ui/base/clipboard/clipboard.h38
-rw-r--r--chromium/ui/base/clipboard/clipboard_android.cc23
-rw-r--r--chromium/ui/base/clipboard/clipboard_android.h5
-rw-r--r--chromium/ui/base/clipboard/clipboard_constants.cc2
-rw-r--r--chromium/ui/base/clipboard/clipboard_data.cc3
-rw-r--r--chromium/ui/base/clipboard/clipboard_data.h12
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type.h1
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type_android.cc8
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type_aura.cc8
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type_mac.mm6
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type_win.cc5
-rw-r--r--chromium/ui/base/clipboard/clipboard_mac.h5
-rw-r--r--chromium/ui/base/clipboard/clipboard_mac.mm47
-rw-r--r--chromium/ui/base/clipboard/clipboard_metrics.h3
-rw-r--r--chromium/ui/base/clipboard/clipboard_monitor.cc3
-rw-r--r--chromium/ui/base/clipboard/clipboard_monitor.h3
-rw-r--r--chromium/ui/base/clipboard/clipboard_non_backed.cc81
-rw-r--r--chromium/ui/base/clipboard/clipboard_non_backed.h7
-rw-r--r--chromium/ui/base/clipboard/clipboard_non_backed_unittest.cc53
-rw-r--r--chromium/ui/base/clipboard/clipboard_observer.cc4
-rw-r--r--chromium/ui/base/clipboard/clipboard_observer.h3
-rw-r--r--chromium/ui/base/clipboard/clipboard_ozone.cc276
-rw-r--r--chromium/ui/base/clipboard/clipboard_ozone.h7
-rw-r--r--chromium/ui/base/clipboard/clipboard_test_template.h79
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_win.cc50
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_win.h5
-rw-r--r--chromium/ui/base/clipboard/clipboard_win.cc107
-rw-r--r--chromium/ui/base/clipboard/clipboard_win.h5
-rw-r--r--chromium/ui/base/clipboard/clipboard_x11.cc146
-rw-r--r--chromium/ui/base/clipboard/clipboard_x11.h7
-rw-r--r--chromium/ui/base/clipboard/file_info.cc167
-rw-r--r--chromium/ui/base/clipboard/file_info.h46
-rw-r--r--chromium/ui/base/clipboard/file_info_fuzzer.cc17
-rw-r--r--chromium/ui/base/clipboard/file_info_unittest.cc114
-rw-r--r--chromium/ui/base/clipboard/scoped_clipboard_writer.cc8
-rw-r--r--chromium/ui/base/clipboard/scoped_clipboard_writer.h6
-rw-r--r--chromium/ui/base/cocoa/menu_controller_unittest.mm5
-rw-r--r--chromium/ui/base/cocoa/nsmenuitem_additions.h38
-rw-r--r--chromium/ui/base/cocoa/nsmenuitem_additions.mm197
-rw-r--r--chromium/ui/base/cocoa/nsmenuitem_additions_unittest.mm471
-rw-r--r--chromium/ui/base/cursor/BUILD.gn22
-rw-r--r--chromium/ui/base/cursor/cursor.h7
-rw-r--r--chromium/ui/base/cursor/cursor_aura.cc (renamed from chromium/ui/base/cursor/cursor_ozone.cc)0
-rw-r--r--chromium/ui/base/cursor/cursor_factory.cc120
-rw-r--r--chromium/ui/base/cursor/cursor_factory.h6
-rw-r--r--chromium/ui/base/cursor/cursor_loader.cc (renamed from chromium/ui/base/cursor/cursor_loader_ozone.cc)56
-rw-r--r--chromium/ui/base/cursor/cursor_loader.h53
-rw-r--r--chromium/ui/base/cursor/cursor_loader_ozone.h55
-rw-r--r--chromium/ui/base/cursor/cursor_loader_unittest.cc28
-rw-r--r--chromium/ui/base/cursor/cursor_loader_win.h34
-rw-r--r--chromium/ui/base/cursor/cursor_util.cc5
-rw-r--r--chromium/ui/base/cursor/cursor_win.cc17
-rw-r--r--chromium/ui/base/cursor/cursors_aura.cc13
-rw-r--r--chromium/ui/base/cursor/mojom/cursor.mojom2
-rw-r--r--chromium/ui/base/cursor/mojom/cursor_mojom_traits_unittest.cc3
-rw-r--r--chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.cc4
-rw-r--r--chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h13
-rw-r--r--chromium/ui/base/cursor/win/win_cursor.cc19
-rw-r--r--chromium/ui/base/cursor/win/win_cursor.h35
-rw-r--r--chromium/ui/base/cursor/win/win_cursor_factory.cc (renamed from chromium/ui/base/cursor/cursor_loader_win.cc)134
-rw-r--r--chromium/ui/base/cursor/win/win_cursor_factory.h46
-rw-r--r--chromium/ui/base/data_transfer_policy/BUILD.gn11
-rw-r--r--chromium/ui/base/data_transfer_policy/data_transfer_endpoint.cc14
-rw-r--r--chromium/ui/base/data_transfer_policy/data_transfer_endpoint.h34
-rw-r--r--chromium/ui/base/data_transfer_policy/data_transfer_endpoint_unittest.cc71
-rw-r--r--chromium/ui/base/data_transfer_policy/data_transfer_policy_controller.h20
-rw-r--r--chromium/ui/base/dragdrop/drag_drop_types.cc23
-rw-r--r--chromium/ui/base/dragdrop/drag_drop_types.h10
-rw-r--r--chromium/ui/base/dragdrop/file_info/BUILD.gn13
-rw-r--r--chromium/ui/base/dragdrop/file_info/file_info.cc21
-rw-r--r--chromium/ui/base/dragdrop/file_info/file_info.h26
-rw-r--r--chromium/ui/base/dragdrop/mojom/drag_drop_types.mojom11
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider.h2
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm2
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc13
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed.h6
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed_unittest.cc94
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc62
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_x11.cc15
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_x11.h8
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_x11_unittest.cc4
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_unittest.cc2
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc54
-rw-r--r--chromium/ui/base/emoji/emoji_panel_helper.h3
-rw-r--r--chromium/ui/base/idle/BUILD.gn9
-rw-r--r--chromium/ui/base/idle/idle_linux.cc2
-rw-r--r--chromium/ui/base/ime/BUILD.gn13
-rw-r--r--chromium/ui/base/ime/DIR_METADATA5
-rw-r--r--chromium/ui/base/ime/OWNERS1
-rw-r--r--chromium/ui/base/ime/character_composer_unittest.cc2
-rw-r--r--chromium/ui/base/ime/chromeos/BUILD.gn16
-rw-r--r--chromium/ui/base/ime/dummy_input_method.cc3
-rw-r--r--chromium/ui/base/ime/dummy_input_method.h2
-rw-r--r--chromium/ui/base/ime/dummy_text_input_client.cc20
-rw-r--r--chromium/ui/base/ime/dummy_text_input_client.h13
-rw-r--r--chromium/ui/base/ime/fake_text_input_client.cc183
-rw-r--r--chromium/ui/base/ime/fake_text_input_client.h101
-rw-r--r--chromium/ui/base/ime/fuchsia/BUILD.gn5
-rw-r--r--chromium/ui/base/ime/fuchsia/input_method_fuchsia.cc5
-rw-r--r--chromium/ui/base/ime/fuchsia/input_method_fuchsia.h9
-rw-r--r--chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.h43
-rw-r--r--chromium/ui/base/ime/fuchsia/virtual_keyboard_controller_fuchsia.cc (renamed from chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc)21
-rw-r--r--chromium/ui/base/ime/fuchsia/virtual_keyboard_controller_fuchsia.h43
-rw-r--r--chromium/ui/base/ime/init/BUILD.gn10
-rw-r--r--chromium/ui/base/ime/init/input_method_initializer.cc19
-rw-r--r--chromium/ui/base/ime/input_method.h4
-rw-r--r--chromium/ui/base/ime/input_method_base.cc9
-rw-r--r--chromium/ui/base/ime/input_method_base.h6
-rw-r--r--chromium/ui/base/ime/input_method_base_unittest.cc14
-rw-r--r--chromium/ui/base/ime/input_method_keyboard_controller_stub.cc30
-rw-r--r--chromium/ui/base/ime/input_method_keyboard_controller_stub.h34
-rw-r--r--chromium/ui/base/ime/linux/BUILD.gn3
-rw-r--r--chromium/ui/base/ime/linux/input_method_auralinux.cc8
-rw-r--r--chromium/ui/base/ime/linux/input_method_auralinux_unittest.cc4
-rw-r--r--chromium/ui/base/ime/linux/text_edit_command_auralinux.cc5
-rw-r--r--chromium/ui/base/ime/mock_input_method.cc3
-rw-r--r--chromium/ui/base/ime/mock_input_method.h6
-rw-r--r--chromium/ui/base/ime/text_edit_commands.h12
-rw-r--r--chromium/ui/base/ime/text_input_client.h34
-rw-r--r--chromium/ui/base/ime/utf_offset_unittest.cc1
-rw-r--r--chromium/ui/base/ime/virtual_keyboard_controller.h (renamed from chromium/ui/base/ime/input_method_keyboard_controller.h)19
-rw-r--r--chromium/ui/base/ime/virtual_keyboard_controller_observer.h (renamed from chromium/ui/base/ime/input_method_keyboard_controller_observer.h)10
-rw-r--r--chromium/ui/base/ime/virtual_keyboard_controller_stub.cc30
-rw-r--r--chromium/ui/base/ime/virtual_keyboard_controller_stub.h34
-rw-r--r--chromium/ui/base/ime/win/imm32_manager.cc1
-rw-r--r--chromium/ui/base/ime/win/input_method_win_base.cc2
-rw-r--r--chromium/ui/base/ime/win/input_method_win_imm32.cc4
-rw-r--r--chromium/ui/base/ime/win/input_method_win_tsf.cc8
-rw-r--r--chromium/ui/base/ime/win/mock_tsf_bridge.cc5
-rw-r--r--chromium/ui/base/ime/win/mock_tsf_bridge.h1
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc10
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h14
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc19
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h21
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc28
-rw-r--r--chromium/ui/base/ime/win/tsf_bridge.cc20
-rw-r--r--chromium/ui/base/ime/win/tsf_bridge.h11
-rw-r--r--chromium/ui/base/ime/win/tsf_input_policy_unittest.cc346
-rw-r--r--chromium/ui/base/ime/win/tsf_input_scope.cc2
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store.cc104
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store.h14
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store_unittest.cc472
-rw-r--r--chromium/ui/base/l10n/l10n_font_util.cc21
-rw-r--r--chromium/ui/base/l10n/l10n_font_util.h14
-rw-r--r--chromium/ui/base/l10n/l10n_util.cc133
-rw-r--r--chromium/ui/base/l10n/l10n_util.h27
-rw-r--r--chromium/ui/base/l10n/l10n_util_android.cc18
-rw-r--r--chromium/ui/base/l10n/l10n_util_unittest.cc54
-rw-r--r--chromium/ui/base/l10n/time_format.cc6
-rw-r--r--chromium/ui/base/layout_unittest.cc3
-rw-r--r--chromium/ui/base/models/dialog_model.cc20
-rw-r--r--chromium/ui/base/models/dialog_model.h52
-rw-r--r--chromium/ui/base/models/dialog_model_field.cc57
-rw-r--r--chromium/ui/base/models/dialog_model_field.h109
-rw-r--r--chromium/ui/base/models/dialog_model_host.h11
-rw-r--r--chromium/ui/base/models/dialog_model_unittest.cc164
-rw-r--r--chromium/ui/base/models/list_selection_model.cc40
-rw-r--r--chromium/ui/base/models/list_selection_model.h9
-rw-r--r--chromium/ui/base/models/list_selection_model_unittest.cc22
-rw-r--r--chromium/ui/base/models/menu_model.cc4
-rw-r--r--chromium/ui/base/models/menu_model.h4
-rw-r--r--chromium/ui/base/models/simple_menu_model.cc9
-rw-r--r--chromium/ui/base/models/simple_menu_model.h5
-rw-r--r--chromium/ui/base/pointer/touch_ui_controller.cc4
-rw-r--r--chromium/ui/base/pointer/touch_ui_controller.h3
-rw-r--r--chromium/ui/base/pointer/touch_ui_controller_unittest.cc3
-rw-r--r--chromium/ui/base/prediction/empty_predictor.cc3
-rw-r--r--chromium/ui/base/prediction/empty_predictor.h3
-rw-r--r--chromium/ui/base/prediction/input_predictor.h6
-rw-r--r--chromium/ui/base/prediction/input_predictor_unittest_helpers.h4
-rw-r--r--chromium/ui/base/prediction/kalman_predictor.cc3
-rw-r--r--chromium/ui/base/prediction/kalman_predictor.h3
-rw-r--r--chromium/ui/base/prediction/least_squares_predictor.cc3
-rw-r--r--chromium/ui/base/prediction/least_squares_predictor.h3
-rw-r--r--chromium/ui/base/prediction/linear_predictor.cc3
-rw-r--r--chromium/ui/base/prediction/linear_predictor.h3
-rw-r--r--chromium/ui/base/prediction/linear_resampling.cc50
-rw-r--r--chromium/ui/base/prediction/linear_resampling.h16
-rw-r--r--chromium/ui/base/prediction/linear_resampling_unittest.cc136
-rw-r--r--chromium/ui/base/resource/data_pack.cc2
-rw-r--r--chromium/ui/base/resource/resource_bundle.cc123
-rw-r--r--chromium/ui/base/resource/resource_bundle.h54
-rw-r--r--chromium/ui/base/resource/resource_bundle_android.cc11
-rw-r--r--chromium/ui/base/resource/resource_bundle_unittest.cc3
-rw-r--r--chromium/ui/base/resource/resource_bundle_win.cc6
-rw-r--r--chromium/ui/base/resource/resource_bundle_win.h7
-rw-r--r--chromium/ui/base/template_expressions.cc3
-rw-r--r--chromium/ui/base/ui_base_features.cc89
-rw-r--r--chromium/ui/base/ui_base_features.h44
-rw-r--r--chromium/ui/base/ui_base_switches_util.cc3
-rw-r--r--chromium/ui/base/ui_features.gni20
-rw-r--r--chromium/ui/base/webui/resource_path.h15
-rw-r--r--chromium/ui/base/webui/web_ui_util.cc5
-rw-r--r--chromium/ui/base/win/hwnd_subclass.cc2
-rw-r--r--chromium/ui/base/win/shell.h12
-rw-r--r--chromium/ui/base/x/BUILD.gn3
-rw-r--r--chromium/ui/base/x/selection_owner.cc79
-rw-r--r--chromium/ui/base/x/selection_owner.h36
-rw-r--r--chromium/ui/base/x/selection_requestor.cc43
-rw-r--r--chromium/ui/base/x/selection_requestor.h21
-rw-r--r--chromium/ui/base/x/selection_requestor_unittest.cc15
-rw-r--r--chromium/ui/base/x/selection_utils.cc34
-rw-r--r--chromium/ui/base/x/x11_cursor.cc1
-rw-r--r--chromium/ui/base/x/x11_cursor.h1
-rw-r--r--chromium/ui/base/x/x11_cursor_factory.cc115
-rw-r--r--chromium/ui/base/x/x11_cursor_factory.h6
-rw-r--r--chromium/ui/base/x/x11_cursor_loader.cc16
-rw-r--r--chromium/ui/base/x/x11_cursor_loader.h2
-rw-r--r--chromium/ui/base/x/x11_display_manager.cc12
-rw-r--r--chromium/ui/base/x/x11_display_manager.h2
-rw-r--r--chromium/ui/base/x/x11_display_util.cc7
-rw-r--r--chromium/ui/base/x/x11_drag_context.cc25
-rw-r--r--chromium/ui/base/x/x11_drag_context.h1
-rw-r--r--chromium/ui/base/x/x11_drag_drop_client.cc60
-rw-r--r--chromium/ui/base/x/x11_gl_egl_utility.cc13
-rw-r--r--chromium/ui/base/x/x11_gl_egl_utility.h7
-rw-r--r--chromium/ui/base/x/x11_idle_query.cc3
-rw-r--r--chromium/ui/base/x/x11_menu_list.cc9
-rw-r--r--chromium/ui/base/x/x11_menu_registrar.cc18
-rw-r--r--chromium/ui/base/x/x11_menu_registrar.h16
-rw-r--r--chromium/ui/base/x/x11_os_exchange_data_provider.cc53
-rw-r--r--chromium/ui/base/x/x11_pointer_grab.cc2
-rw-r--r--chromium/ui/base/x/x11_screensaver_window_finder.cc24
-rw-r--r--chromium/ui/base/x/x11_shm_image_pool.cc29
-rw-r--r--chromium/ui/base/x/x11_shm_image_pool.h7
-rw-r--r--chromium/ui/base/x/x11_software_bitmap_presenter.cc6
-rw-r--r--chromium/ui/base/x/x11_software_bitmap_presenter.h2
-rw-r--r--chromium/ui/base/x/x11_user_input_monitor.cc12
-rw-r--r--chromium/ui/base/x/x11_user_input_monitor.h7
-rw-r--r--chromium/ui/base/x/x11_util.cc260
-rw-r--r--chromium/ui/base/x/x11_util.h151
-rw-r--r--chromium/ui/base/x/x11_whole_screen_move_loop.cc9
-rw-r--r--chromium/ui/base/x/x11_whole_screen_move_loop.h7
-rw-r--r--chromium/ui/base/x/x11_window.cc194
-rw-r--r--chromium/ui/base/x/x11_window.h17
-rw-r--r--chromium/ui/base/x/x11_workspace_handler.cc26
-rw-r--r--chromium/ui/base/x/x11_workspace_handler.h16
-rw-r--r--chromium/ui/base/x/xwmstartupcheck/xwmstartupcheck.cc2
-rw-r--r--chromium/ui/chromeos/BUILD.gn5
-rw-r--r--chromium/ui/chromeos/events/BUILD.gn5
-rw-r--r--chromium/ui/chromeos/strings/BUILD.gn62
-rw-r--r--chromium/ui/color/BUILD.gn3
-rw-r--r--chromium/ui/color/DIR_METADATA3
-rw-r--r--chromium/ui/color/OWNERS2
-rw-r--r--chromium/ui/compositor/BUILD.gn12
-rw-r--r--chromium/ui/compositor/DIR_METADATA4
-rw-r--r--chromium/ui/compositor/OWNERS3
-rw-r--r--chromium/ui/compositor/animation_throughput_reporter.cc41
-rw-r--r--chromium/ui/compositor/animation_throughput_reporter.h5
-rw-r--r--chromium/ui/compositor/animation_throughput_reporter_unittest.cc228
-rw-r--r--chromium/ui/compositor/compositor.cc45
-rw-r--r--chromium/ui/compositor/compositor.h30
-rw-r--r--chromium/ui/compositor/compositor_observer.h13
-rw-r--r--chromium/ui/compositor/compositor_switches.cc3
-rw-r--r--chromium/ui/compositor/compositor_unittest.cc45
-rw-r--r--chromium/ui/compositor/float_animation_curve_adapter.cc2
-rw-r--r--chromium/ui/compositor/float_animation_curve_adapter.h6
-rw-r--r--chromium/ui/compositor/layer.cc19
-rw-r--r--chromium/ui/compositor/layer.h20
-rw-r--r--chromium/ui/compositor/layer_animation_element.cc8
-rw-r--r--chromium/ui/compositor/layer_animation_observer.cc20
-rw-r--r--chromium/ui/compositor/layer_animation_observer.h16
-rw-r--r--chromium/ui/compositor/layer_animation_sequence.cc42
-rw-r--r--chromium/ui/compositor/layer_animation_sequence.h16
-rw-r--r--chromium/ui/compositor/layer_animation_sequence_unittest.cc22
-rw-r--r--chromium/ui/compositor/layer_animator.cc2
-rw-r--r--chromium/ui/compositor/layer_animator.h3
-rw-r--r--chromium/ui/compositor/layer_animator_unittest.cc297
-rw-r--r--chromium/ui/compositor/layer_owner.h4
-rw-r--r--chromium/ui/compositor/layer_unittest.cc22
-rw-r--r--chromium/ui/compositor/throughput_tracker.cc5
-rw-r--r--chromium/ui/compositor/throughput_tracker_unittest.cc39
-rw-r--r--chromium/ui/compositor/total_animation_throughput_reporter.cc91
-rw-r--r--chromium/ui/compositor/total_animation_throughput_reporter.h89
-rw-r--r--chromium/ui/compositor/total_animation_throughput_reporter_unittest.cc356
-rw-r--r--chromium/ui/compositor/transform_animation_curve_adapter.cc95
-rw-r--r--chromium/ui/compositor/transform_animation_curve_adapter.h49
-rw-r--r--chromium/ui/compositor/transform_animation_curve_adapter_unittest.cc84
-rw-r--r--chromium/ui/compositor/transform_recorder.cc2
-rw-r--r--chromium/ui/compositor_extra/DIR_METADATA3
-rw-r--r--chromium/ui/compositor_extra/OWNERS1
-rw-r--r--chromium/ui/content_accelerators/BUILD.gn1
-rw-r--r--chromium/ui/content_accelerators/DIR_METADATA3
-rw-r--r--chromium/ui/content_accelerators/OWNERS1
-rw-r--r--chromium/ui/content_accelerators/accelerator_util.cc3
-rw-r--r--chromium/ui/display/BUILD.gn8
-rw-r--r--chromium/ui/display/DIR_METADATA3
-rw-r--r--chromium/ui/display/OWNERS2
-rw-r--r--chromium/ui/display/display.gni4
-rw-r--r--chromium/ui/display/display_features.cc3
-rw-r--r--chromium/ui/display/display_features.h3
-rw-r--r--chromium/ui/display/display_switches.cc3
-rw-r--r--chromium/ui/display/display_switches.h3
-rw-r--r--chromium/ui/display/fake/fake_display_delegate.cc13
-rw-r--r--chromium/ui/display/fake/fake_display_snapshot.cc25
-rw-r--r--chromium/ui/display/fake/fake_display_snapshot.h6
-rw-r--r--chromium/ui/display/manager/BUILD.gn4
-rw-r--r--chromium/ui/display/manager/DEPS1
-rw-r--r--chromium/ui/display/manager/configure_displays_task.cc318
-rw-r--r--chromium/ui/display/manager/configure_displays_task.h62
-rw-r--r--chromium/ui/display/manager/configure_displays_task_unittest.cc1504
-rw-r--r--chromium/ui/display/manager/display_change_observer.cc14
-rw-r--r--chromium/ui/display/manager/display_change_observer_unittest.cc10
-rw-r--r--chromium/ui/display/manager/display_configurator.cc6
-rw-r--r--chromium/ui/display/manager/display_configurator_unittest.cc159
-rw-r--r--chromium/ui/display/manager/display_manager.cc37
-rw-r--r--chromium/ui/display/manager/display_manager.h15
-rw-r--r--chromium/ui/display/manager/display_manager_utilities.cc5
-rw-r--r--chromium/ui/display/manager/display_util.cc5
-rw-r--r--chromium/ui/display/manager/display_util.h9
-rw-r--r--chromium/ui/display/manager/managed_display_info_unittest.cc3
-rw-r--r--chromium/ui/display/manager/touch_device_manager.cc64
-rw-r--r--chromium/ui/display/manager/touch_device_manager.h2
-rw-r--r--chromium/ui/display/manager/update_display_configuration_task_unittest.cc51
-rw-r--r--chromium/ui/display/mojom/display_mojom_traits_unittest.cc58
-rw-r--r--chromium/ui/display/mojom/display_snapshot.mojom2
-rw-r--r--chromium/ui/display/mojom/display_snapshot_mojom_traits.cc10
-rw-r--r--chromium/ui/display/mojom/display_snapshot_mojom_traits.h10
-rw-r--r--chromium/ui/display/screen.h2
-rw-r--r--chromium/ui/display/types/display_mode.cc12
-rw-r--r--chromium/ui/display/types/display_mode.h2
-rw-r--r--chromium/ui/display/types/display_snapshot.cc34
-rw-r--r--chromium/ui/display/types/display_snapshot.h51
-rw-r--r--chromium/ui/display/types/native_display_delegate.h3
-rw-r--r--chromium/ui/display/unified_desktop_utils.cc2
-rw-r--r--chromium/ui/display/util/BUILD.gn3
-rw-r--r--chromium/ui/display/util/DIR_METADATA3
-rw-r--r--chromium/ui/display/util/OWNERS2
-rw-r--r--chromium/ui/display/util/display_util.cc2
-rw-r--r--chromium/ui/display/win/color_profile_reader.cc8
-rw-r--r--chromium/ui/display/win/local_process_window_finder_win.cc13
-rw-r--r--chromium/ui/display/win/local_process_window_finder_win.h5
-rw-r--r--chromium/ui/display/win/screen_win.cc12
-rw-r--r--chromium/ui/display/win/screen_win.h9
-rw-r--r--chromium/ui/events/BUILD.gn15
-rw-r--r--chromium/ui/events/android/OWNERS3
-rw-r--r--chromium/ui/events/base_event_utils.cc5
-rw-r--r--chromium/ui/events/blink/OWNERS3
-rw-r--r--chromium/ui/events/blink/blink_event_util.cc4
-rw-r--r--chromium/ui/events/blink/blink_event_util_unittest.cc12
-rw-r--r--chromium/ui/events/devices/device_data_manager_unittest.cc8
-rw-r--r--chromium/ui/events/devices/x11/BUILD.gn1
-rw-r--r--chromium/ui/events/devices/x11/device_data_manager_x11.cc7
-rw-r--r--chromium/ui/events/devices/x11/device_list_cache_x11.cc5
-rw-r--r--chromium/ui/events/devices/x11/touch_factory_x11.cc4
-rw-r--r--chromium/ui/events/event.cc76
-rw-r--r--chromium/ui/events/event.h29
-rw-r--r--chromium/ui/events/event_handler.cc8
-rw-r--r--chromium/ui/events/event_handler.h5
-rw-r--r--chromium/ui/events/event_utils.cc91
-rw-r--r--chromium/ui/events/event_utils.h18
-rw-r--r--chromium/ui/events/gesture_detection/OWNERS3
-rw-r--r--chromium/ui/events/gesture_detection/gesture_configuration.cc10
-rw-r--r--chromium/ui/events/gesture_detection/gesture_configuration_aura.cc7
-rw-r--r--chromium/ui/events/gesture_detection/gesture_detector.cc3
-rw-r--r--chromium/ui/events/gestures/OWNERS3
-rw-r--r--chromium/ui/events/gestures/gesture_provider_aura.cc5
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer_impl.cc2
-rw-r--r--chromium/ui/events/keyboard_hook_base.cc2
-rw-r--r--chromium/ui/events/keycodes/BUILD.gn1
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion_xkb.cc5
-rw-r--r--chromium/ui/events/mojom/mojom_traits_unittest.cc36
-rw-r--r--chromium/ui/events/ozone/BUILD.gn6
-rw-r--r--chromium/ui/events/ozone/device/device_manager_manual.cc7
-rw-r--r--chromium/ui/events/ozone/evdev/BUILD.gn3
-rw-r--r--chromium/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc4
-rw-r--r--chromium/ui/events/ozone/evdev/device_event_dispatcher_evdev.h11
-rw-r--r--chromium/ui/events/ozone/evdev/event_converter_evdev_impl.cc4
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_info.cc6
-rw-r--r--chromium/ui/events/ozone/evdev/event_factory_evdev.cc11
-rw-r--r--chromium/ui/events/ozone/evdev/event_factory_evdev.h5
-rw-r--r--chromium/ui/events/ozone/evdev/input_controller_evdev.cc50
-rw-r--r--chromium/ui/events/ozone/evdev/input_controller_evdev.h34
-rw-r--r--chromium/ui/events/ozone/evdev/input_controller_evdev_unittest.cc60
-rw-r--r--chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc13
-rw-r--r--chromium/ui/events/ozone/evdev/input_device_settings_evdev.h4
-rw-r--r--chromium/ui/events/ozone/evdev/input_injector_evdev.cc2
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/gesture_feedback.cc5
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc9
-rw-r--r--chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.cc2
-rw-r--r--chromium/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc3
-rw-r--r--chromium/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc54
-rw-r--r--chromium/ui/events/ozone/layout/BUILD.gn5
-rw-r--r--chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc13
-rw-r--r--chromium/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h3
-rw-r--r--chromium/ui/events/platform/x11/BUILD.gn4
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source.cc230
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source.h147
-rw-r--r--chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc15
-rw-r--r--chromium/ui/events/scoped_target_handler.cc18
-rw-r--r--chromium/ui/events/scoped_target_handler.h10
-rw-r--r--chromium/ui/events/win/keyboard_hook_monitor.h42
-rw-r--r--chromium/ui/events/win/keyboard_hook_monitor_impl.cc60
-rw-r--r--chromium/ui/events/win/keyboard_hook_monitor_impl.h57
-rw-r--r--chromium/ui/events/win/keyboard_hook_observer.h28
-rw-r--r--chromium/ui/events/win/modifier_keyboard_hook_win.cc8
-rw-r--r--chromium/ui/events/x/BUILD.gn3
-rw-r--r--chromium/ui/events/x/events_x_utils.cc7
-rw-r--r--chromium/ui/events/x/keyboard_hook_x11.cc1
-rw-r--r--chromium/ui/file_manager/BUILD.gn397
-rw-r--r--chromium/ui/file_manager/audio_player/BUILD.gn50
-rw-r--r--chromium/ui/file_manager/audio_player/elements/BUILD.gn13
-rw-r--r--chromium/ui/file_manager/audio_player/js/BUILD.gn99
-rw-r--r--chromium/ui/file_manager/base/gn/js_test_gen_html.gni14
-rw-r--r--chromium/ui/file_manager/base/js/BUILD.gn31
-rw-r--r--chromium/ui/file_manager/base/tools/tests/empty_dependency_list.gn4
-rw-r--r--chromium/ui/file_manager/base/tools/tests/empty_dependency_list_expected.gn6
-rw-r--r--chromium/ui/file_manager/base/tools/tests/single_line_dependency_list.gn4
-rw-r--r--chromium/ui/file_manager/base/tools/tests/single_line_dependency_list_expected.gn7
-rw-r--r--chromium/ui/file_manager/externs/BUILD.gn85
-rw-r--r--chromium/ui/file_manager/externs/background/BUILD.gn158
-rw-r--r--chromium/ui/file_manager/file_manager/BUILD.gn165
-rw-r--r--chromium/ui/file_manager/file_manager/background/js/BUILD.gn806
-rw-r--r--chromium/ui/file_manager/file_manager/common/js/BUILD.gn157
-rw-r--r--chromium/ui/file_manager/file_manager/cws_widget/BUILD.gn91
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/elements/BUILD.gn345
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/js/BUILD.gn1577
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn233
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn796
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/js/ui/table/BUILD.gn85
-rw-r--r--chromium/ui/file_manager/file_manager/test/BUILD.gn14
-rw-r--r--chromium/ui/file_manager/gallery/js/BUILD.gn8
-rw-r--r--chromium/ui/file_manager/gallery/js/image_editor/BUILD.gn111
-rw-r--r--chromium/ui/file_manager/image_loader/BUILD.gn139
-rw-r--r--chromium/ui/file_manager/integration_tests/BUILD.gn1
-rw-r--r--chromium/ui/file_manager/integration_tests/file_manager/BUILD.gn7
-rw-r--r--chromium/ui/file_manager/video_player/js/BUILD.gn183
-rw-r--r--chromium/ui/gfx/BUILD.gn65
-rw-r--r--chromium/ui/gfx/DEPS1
-rw-r--r--chromium/ui/gfx/OWNERS1
-rw-r--r--chromium/ui/gfx/android/android_surface_control_compat.cc40
-rw-r--r--chromium/ui/gfx/android/android_surface_control_compat.h6
-rw-r--r--chromium/ui/gfx/animation/BUILD.gn4
-rw-r--r--chromium/ui/gfx/animation/animation.cc7
-rw-r--r--chromium/ui/gfx/animation/keyframe/BUILD.gn50
-rw-r--r--chromium/ui/gfx/animation/keyframe/animation_curve.cc48
-rw-r--r--chromium/ui/gfx/animation/keyframe/animation_curve.h109
-rw-r--r--chromium/ui/gfx/animation/keyframe/keyframe_animation_export.h29
-rw-r--r--chromium/ui/gfx/animation/keyframe/keyframe_animation_unittest.cc695
-rw-r--r--chromium/ui/gfx/animation/keyframe/keyframe_effect.cc418
-rw-r--r--chromium/ui/gfx/animation/keyframe/keyframe_effect.h119
-rw-r--r--chromium/ui/gfx/animation/keyframe/keyframe_model.cc257
-rw-r--r--chromium/ui/gfx/animation/keyframe/keyframe_model.h206
-rw-r--r--chromium/ui/gfx/animation/keyframe/keyframed_animation_curve.cc515
-rw-r--r--chromium/ui/gfx/animation/keyframe/keyframed_animation_curve.h292
-rw-r--r--chromium/ui/gfx/animation/keyframe/keyframed_animation_curve_unittest.cc993
-rw-r--r--chromium/ui/gfx/animation/keyframe/target_property.h19
-rw-r--r--chromium/ui/gfx/animation/keyframe/timing_function.cc182
-rw-r--r--chromium/ui/gfx/animation/keyframe/timing_function.h143
-rw-r--r--chromium/ui/gfx/animation/keyframe/transition.cc19
-rw-r--r--chromium/ui/gfx/animation/keyframe/transition.h25
-rw-r--r--chromium/ui/gfx/animation/tween.cc20
-rw-r--r--chromium/ui/gfx/animation/tween.h27
-rw-r--r--chromium/ui/gfx/bidi_line_iterator.cc4
-rw-r--r--chromium/ui/gfx/buffer_types.h4
-rw-r--r--chromium/ui/gfx/buffer_usage_util.cc4
-rw-r--r--chromium/ui/gfx/canvas_skia.cc9
-rw-r--r--chromium/ui/gfx/color_space.cc23
-rw-r--r--chromium/ui/gfx/color_space.h5
-rw-r--r--chromium/ui/gfx/color_space_unittest.cc2
-rw-r--r--chromium/ui/gfx/color_transform.cc50
-rw-r--r--chromium/ui/gfx/color_transform_unittest.cc50
-rw-r--r--chromium/ui/gfx/color_utils.h5
-rw-r--r--chromium/ui/gfx/display_color_spaces.cc3
-rw-r--r--chromium/ui/gfx/font_fallback_skia_unittest.cc1
-rw-r--r--chromium/ui/gfx/font_fallback_unittest.cc7
-rw-r--r--chromium/ui/gfx/font_fallback_win.cc6
-rw-r--r--chromium/ui/gfx/font_fallback_win_unittest.cc8
-rw-r--r--chromium/ui/gfx/font_render_params_linux.cc5
-rw-r--r--chromium/ui/gfx/font_render_params_linux_unittest.cc5
-rw-r--r--chromium/ui/gfx/geometry/BUILD.gn2
-rw-r--r--chromium/ui/gfx/geometry/axis_transform2d.h19
-rw-r--r--chromium/ui/gfx/geometry/mojom/geometry.mojom1
-rw-r--r--chromium/ui/gfx/geometry/resize_utils.cc112
-rw-r--r--chromium/ui/gfx/geometry/resize_utils.h41
-rw-r--r--chromium/ui/gfx/geometry/resize_utils_unittest.cc181
-rw-r--r--chromium/ui/gfx/gpu_extra_info.h17
-rw-r--r--chromium/ui/gfx/gpu_memory_buffer.cc25
-rw-r--r--chromium/ui/gfx/gpu_memory_buffer.h9
-rw-r--r--chromium/ui/gfx/icon_util.cc10
-rw-r--r--chromium/ui/gfx/icon_util_unittest.cc8
-rw-r--r--chromium/ui/gfx/image/image_skia.cc71
-rw-r--r--chromium/ui/gfx/image/image_skia.h18
-rw-r--r--chromium/ui/gfx/image/image_skia_operations.cc34
-rw-r--r--chromium/ui/gfx/image/image_skia_operations_unittest.cc23
-rw-r--r--chromium/ui/gfx/image/image_skia_rep_default.cc14
-rw-r--r--chromium/ui/gfx/image/image_skia_rep_default.h16
-rw-r--r--chromium/ui/gfx/image/image_skia_rep_ios.cc3
-rw-r--r--chromium/ui/gfx/image/mojom/BUILD.gn2
-rw-r--r--chromium/ui/gfx/image/mojom/image.mojom7
-rw-r--r--chromium/ui/gfx/image/mojom/image_skia_mojom_traits.cc19
-rw-r--r--chromium/ui/gfx/image/mojom/image_skia_mojom_traits.h8
-rw-r--r--chromium/ui/gfx/image/mojom/image_traits_unittest.cc150
-rw-r--r--chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc15
-rw-r--r--chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc2
-rw-r--r--chromium/ui/gfx/linux/gbm_defines.h1
-rw-r--r--chromium/ui/gfx/linux/gbm_util.cc7
-rw-r--r--chromium/ui/gfx/linux/gpu_memory_buffer_support_x11.cc11
-rw-r--r--chromium/ui/gfx/mac/io_surface.cc17
-rw-r--r--chromium/ui/gfx/mac/io_surface_hdr_metadata.cc42
-rw-r--r--chromium/ui/gfx/mac/io_surface_hdr_metadata.h31
-rw-r--r--chromium/ui/gfx/mac/io_surface_unittest.cc38
-rw-r--r--chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm17
-rw-r--r--chromium/ui/gfx/mojom/BUILD.gn45
-rw-r--r--chromium/ui/gfx/mojom/buffer_types.mojom2
-rw-r--r--chromium/ui/gfx/mojom/buffer_types_mojom_traits.h9
-rw-r--r--chromium/ui/gfx/mojom/color_space_mojom_traits.h2
-rw-r--r--chromium/ui/gfx/mojom/display_color_spaces_mojom_traits.h10
-rw-r--r--chromium/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc12
-rw-r--r--chromium/ui/gfx/mojom/gpu_extra_info_mojom_traits.h13
-rw-r--r--chromium/ui/gfx/mojom/mojom_traits_unittest.cc8
-rw-r--r--chromium/ui/gfx/native_widget_types.h9
-rw-r--r--chromium/ui/gfx/nine_image_painter_unittest.cc10
-rw-r--r--chromium/ui/gfx/platform_font_mac.mm95
-rw-r--r--chromium/ui/gfx/platform_font_mac_unittest.mm13
-rw-r--r--chromium/ui/gfx/platform_font_skia.cc3
-rw-r--r--chromium/ui/gfx/render_text.cc40
-rw-r--r--chromium/ui/gfx/render_text.h1
-rw-r--r--chromium/ui/gfx/render_text_api_fuzzer.cc18
-rw-r--r--chromium/ui/gfx/render_text_harfbuzz.cc2
-rw-r--r--chromium/ui/gfx/render_text_test_api.h4
-rw-r--r--chromium/ui/gfx/render_text_unittest.cc212
-rw-r--r--chromium/ui/gfx/rendering_pipeline.cc298
-rw-r--r--chromium/ui/gfx/rendering_pipeline.h83
-rw-r--r--chromium/ui/gfx/rendering_stage_scheduler.cc163
-rw-r--r--chromium/ui/gfx/rendering_stage_scheduler.h35
-rw-r--r--chromium/ui/gfx/rrect_f.cc7
-rw-r--r--chromium/ui/gfx/rrect_f.h2
-rw-r--r--chromium/ui/gfx/rrect_f_unittest.cc2
-rw-r--r--chromium/ui/gfx/skbitmap_operations.cc75
-rw-r--r--chromium/ui/gfx/skia_util.cc1
-rw-r--r--chromium/ui/gfx/system_fonts_win_unittest.cc6
-rw-r--r--chromium/ui/gfx/text_elider_unittest.cc56
-rw-r--r--chromium/ui/gfx/text_utils.cc63
-rw-r--r--chromium/ui/gfx/text_utils.h24
-rw-r--r--chromium/ui/gfx/text_utils_unittest.cc98
-rw-r--r--chromium/ui/gfx/transform.cc9
-rw-r--r--chromium/ui/gfx/transform.h7
-rw-r--r--chromium/ui/gfx/transform_operation.cc514
-rw-r--r--chromium/ui/gfx/transform_operation.h79
-rw-r--r--chromium/ui/gfx/transform_operations.cc384
-rw-r--r--chromium/ui/gfx/transform_operations.h140
-rw-r--r--chromium/ui/gfx/transform_operations_unittest.cc1812
-rw-r--r--chromium/ui/gfx/transform_util.cc35
-rw-r--r--chromium/ui/gfx/transform_util.h10
-rw-r--r--chromium/ui/gfx/win/window_impl.cc11
-rw-r--r--chromium/ui/gfx/win/window_impl.h4
-rw-r--r--chromium/ui/gfx/x/BUILD.gn230
-rw-r--r--chromium/ui/gfx/x/connection.cc431
-rw-r--r--chromium/ui/gfx/x/connection.h188
-rw-r--r--chromium/ui/gfx/x/connection_unittest.cc38
-rw-r--r--chromium/ui/gfx/x/event.cc8
-rw-r--r--chromium/ui/gfx/x/event.h15
-rw-r--r--chromium/ui/gfx/x/future.h114
-rw-r--r--chromium/ui/gfx/x/gen_xproto.py336
-rw-r--r--chromium/ui/gfx/x/generated_protos/README.txt10
-rw-r--r--chromium/ui/gfx/x/generated_protos/bigreq.cc118
-rw-r--r--chromium/ui/gfx/x/generated_protos/bigreq.h103
-rw-r--r--chromium/ui/gfx/x/generated_protos/composite.cc504
-rw-r--r--chromium/ui/gfx/x/generated_protos/composite.h230
-rw-r--r--chromium/ui/gfx/x/generated_protos/damage.cc400
-rw-r--r--chromium/ui/gfx/x/generated_protos/damage.h208
-rw-r--r--chromium/ui/gfx/x/generated_protos/dpms.cc470
-rw-r--r--chromium/ui/gfx/x/generated_protos/dpms.h211
-rw-r--r--chromium/ui/gfx/x/generated_protos/dri2.cc1316
-rw-r--r--chromium/ui/gfx/x/generated_protos/dri2.h474
-rw-r--r--chromium/ui/gfx/x/generated_protos/dri3.cc855
-rw-r--r--chromium/ui/gfx/x/generated_protos/dri3.h294
-rw-r--r--chromium/ui/gfx/x/generated_protos/extension_manager.cc149
-rw-r--r--chromium/ui/gfx/x/generated_protos/extension_manager.h158
-rw-r--r--chromium/ui/gfx/x/generated_protos/ge.cc137
-rw-r--r--chromium/ui/gfx/x/generated_protos/ge.h109
-rw-r--r--chromium/ui/gfx/x/generated_protos/glx.cc8598
-rw-r--r--chromium/ui/gfx/x/generated_protos/glx.h2235
-rw-r--r--chromium/ui/gfx/x/generated_protos/present.cc825
-rw-r--r--chromium/ui/gfx/x/generated_protos/present.h426
-rw-r--r--chromium/ui/gfx/x/generated_protos/randr.cc4599
-rw-r--r--chromium/ui/gfx/x/generated_protos/randr.h1337
-rw-r--r--chromium/ui/gfx/x/generated_protos/read_error.cc530
-rw-r--r--chromium/ui/gfx/x/generated_protos/read_event.cc1260
-rw-r--r--chromium/ui/gfx/x/generated_protos/record.cc1040
-rw-r--r--chromium/ui/gfx/x/generated_protos/record.h292
-rw-r--r--chromium/ui/gfx/x/generated_protos/render.cc2960
-rw-r--r--chromium/ui/gfx/x/generated_protos/render.h1047
-rw-r--r--chromium/ui/gfx/x/generated_protos/res.cc680
-rw-r--r--chromium/ui/gfx/x/generated_protos/res.h249
-rw-r--r--chromium/ui/gfx/x/generated_protos/screensaver.cc644
-rw-r--r--chromium/ui/gfx/x/generated_protos/screensaver.h293
-rw-r--r--chromium/ui/gfx/x/generated_protos/shape.cc784
-rw-r--r--chromium/ui/gfx/x/generated_protos/shape.h311
-rw-r--r--chromium/ui/gfx/x/generated_protos/shm.cc722
-rw-r--r--chromium/ui/gfx/x/generated_protos/shm.h286
-rw-r--r--chromium/ui/gfx/x/generated_protos/sync.cc1530
-rw-r--r--chromium/ui/gfx/x/generated_protos/sync.h526
-rw-r--r--chromium/ui/gfx/x/generated_protos/xc_misc.cc277
-rw-r--r--chromium/ui/gfx/x/generated_protos/xc_misc.h137
-rw-r--r--chromium/ui/gfx/x/generated_protos/xevie.cc406
-rw-r--r--chromium/ui/gfx/x/generated_protos/xevie.h188
-rw-r--r--chromium/ui/gfx/x/generated_protos/xf86dri.cc972
-rw-r--r--chromium/ui/gfx/x/generated_protos/xf86dri.h304
-rw-r--r--chromium/ui/gfx/x/generated_protos/xf86vidmode.cc2197
-rw-r--r--chromium/ui/gfx/x/generated_protos/xf86vidmode.h683
-rw-r--r--chromium/ui/gfx/x/generated_protos/xfixes.cc1987
-rw-r--r--chromium/ui/gfx/x/generated_protos/xfixes.h795
-rw-r--r--chromium/ui/gfx/x/generated_protos/xinerama.cc508
-rw-r--r--chromium/ui/gfx/x/generated_protos/xinerama.h194
-rw-r--r--chromium/ui/gfx/x/generated_protos/xinput.cc7683
-rw-r--r--chromium/ui/gfx/x/generated_protos/xinput.h3234
-rw-r--r--chromium/ui/gfx/x/generated_protos/xkb.cc6879
-rw-r--r--chromium/ui/gfx/x/generated_protos/xkb.h2858
-rw-r--r--chromium/ui/gfx/x/generated_protos/xprint.cc1708
-rw-r--r--chromium/ui/gfx/x/generated_protos/xprint.h584
-rw-r--r--chromium/ui/gfx/x/generated_protos/xproto.cc11439
-rw-r--r--chromium/ui/gfx/x/generated_protos/xproto.h4408
-rw-r--r--chromium/ui/gfx/x/generated_protos/xselinux.cc1683
-rw-r--r--chromium/ui/gfx/x/generated_protos/xselinux.h428
-rw-r--r--chromium/ui/gfx/x/generated_protos/xtest.cc309
-rw-r--r--chromium/ui/gfx/x/generated_protos/xtest.h174
-rw-r--r--chromium/ui/gfx/x/generated_protos/xv.cc1967
-rw-r--r--chromium/ui/gfx/x/generated_protos/xv.h779
-rw-r--r--chromium/ui/gfx/x/generated_protos/xvmc.cc857
-rw-r--r--chromium/ui/gfx/x/generated_protos/xvmc.h263
-rw-r--r--chromium/ui/gfx/x/keyboard_state.cc7
-rw-r--r--chromium/ui/gfx/x/property_cache.cc90
-rw-r--r--chromium/ui/gfx/x/property_cache.h85
-rw-r--r--chromium/ui/gfx/x/property_cache_unittest.cc173
-rw-r--r--chromium/ui/gfx/x/ref_counted_fd.cc37
-rw-r--r--chromium/ui/gfx/x/ref_counted_fd.h54
-rw-r--r--chromium/ui/gfx/x/scoped_ignore_errors.cc2
-rw-r--r--chromium/ui/gfx/x/x11_atom_cache.cc110
-rw-r--r--chromium/ui/gfx/x/x11_atom_cache.h20
-rw-r--r--chromium/ui/gfx/x/x11_path.cc10
-rw-r--r--chromium/ui/gfx/x/x11_path.h14
-rw-r--r--chromium/ui/gfx/x/x11_window_event_manager.cc (renamed from chromium/ui/events/x/x11_window_event_manager.cc)48
-rw-r--r--chromium/ui/gfx/x/x11_window_event_manager.h (renamed from chromium/ui/events/x/x11_window_event_manager.h)27
-rw-r--r--chromium/ui/gfx/x/xlib.h2
-rw-r--r--chromium/ui/gfx/x/xlib_support.cc30
-rw-r--r--chromium/ui/gfx/x/xlib_support.h7
-rw-r--r--chromium/ui/gfx/x/xlib_xcb.h12
-rw-r--r--chromium/ui/gfx/x/xproto_internal.cc72
-rw-r--r--chromium/ui/gfx/x/xproto_internal.h22
-rw-r--r--chromium/ui/gfx/x/xproto_types.cc92
-rw-r--r--chromium/ui/gfx/x/xproto_types.h138
-rw-r--r--chromium/ui/gfx/x/xproto_util.cc42
-rw-r--r--chromium/ui/gfx/x/xproto_util.h107
-rw-r--r--chromium/ui/gl/BUILD.gn13
-rw-r--r--chromium/ui/gl/DIR_METADATA4
-rw-r--r--chromium/ui/gl/OWNERS6
-rw-r--r--chromium/ui/gl/angle_platform_impl.cc4
-rw-r--r--chromium/ui/gl/dc_layer_tree.cc160
-rw-r--r--chromium/ui/gl/dc_layer_tree.h84
-rw-r--r--chromium/ui/gl/direct_composition_child_surface_win.cc1
-rw-r--r--chromium/ui/gl/direct_composition_surface_win.cc36
-rw-r--r--chromium/ui/gl/direct_composition_surface_win.h6
-rw-r--r--chromium/ui/gl/direct_composition_surface_win_unittest.cc9
-rw-r--r--chromium/ui/gl/features.gni8
-rwxr-xr-xchromium/ui/gl/generate_bindings.py2
-rw-r--r--chromium/ui/gl/gl_angle_util_win.cc3
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_egl.cc161
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_gl.cc1031
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_glx.cc97
-rw-r--r--chromium/ui/gl/gl_context.cc15
-rw-r--r--chromium/ui/gl/gl_context.h10
-rw-r--r--chromium/ui/gl/gl_context_egl.cc24
-rw-r--r--chromium/ui/gl/gl_context_glx_unittest.cc1
-rw-r--r--chromium/ui/gl/gl_features.cc21
-rw-r--r--chromium/ui/gl/gl_features.h3
-rw-r--r--chromium/ui/gl/gl_gl_api_implementation.cc2
-rw-r--r--chromium/ui/gl/gl_glx_api_implementation.cc7
-rw-r--r--chromium/ui/gl/gl_image.cc4
-rw-r--r--chromium/ui/gl/gl_image_egl.cc1
-rw-r--r--chromium/ui/gl/gl_image_glx_native_pixmap.cc15
-rw-r--r--chromium/ui/gl/gl_image_io_surface.h4
-rw-r--r--chromium/ui/gl/gl_image_io_surface.mm5
-rw-r--r--chromium/ui/gl/gl_image_io_surface_egl.mm1
-rw-r--r--chromium/ui/gl/gl_image_native_pixmap.cc1
-rw-r--r--chromium/ui/gl/gl_implementation.cc11
-rw-r--r--chromium/ui/gl/gl_implementation.h6
-rw-r--r--chromium/ui/gl/gl_surface.cc16
-rw-r--r--chromium/ui/gl/gl_surface.h13
-rw-r--r--chromium/ui/gl/gl_surface_egl.cc92
-rw-r--r--chromium/ui/gl/gl_surface_egl.h7
-rw-r--r--chromium/ui/gl/gl_surface_egl_surface_control.cc17
-rw-r--r--chromium/ui/gl/gl_surface_egl_surface_control.h3
-rw-r--r--chromium/ui/gl/gl_surface_egl_unittest.cc1
-rw-r--r--chromium/ui/gl/gl_surface_egl_x11.cc25
-rw-r--r--chromium/ui/gl/gl_surface_egl_x11.h7
-rw-r--r--chromium/ui/gl/gl_surface_egl_x11_gles2.cc13
-rw-r--r--chromium/ui/gl/gl_surface_egl_x11_gles2.h4
-rw-r--r--chromium/ui/gl/gl_surface_glx.cc11
-rw-r--r--chromium/ui/gl/gl_surface_glx.h4
-rw-r--r--chromium/ui/gl/gl_surface_glx_x11.cc29
-rw-r--r--chromium/ui/gl/gl_surface_glx_x11.h8
-rw-r--r--chromium/ui/gl/gl_switches.cc20
-rw-r--r--chromium/ui/gl/gl_switches.h5
-rw-r--r--chromium/ui/gl/gl_utils.cc4
-rw-r--r--chromium/ui/gl/gl_version_info.cc73
-rw-r--r--chromium/ui/gl/gl_version_info.h1
-rw-r--r--chromium/ui/gl/gl_version_info_unittest.cc71
-rw-r--r--chromium/ui/gl/gl_visual_picker_glx.cc1
-rw-r--r--chromium/ui/gl/glx_util.cc12
-rw-r--r--chromium/ui/gl/hdr_metadata_helper_win.cc11
-rw-r--r--chromium/ui/gl/hdr_metadata_helper_win_unittest.cc6
-rw-r--r--chromium/ui/gl/init/BUILD.gn9
-rw-r--r--chromium/ui/gl/init/create_gr_gl_interface.cc104
-rw-r--r--chromium/ui/gl/init/gl_factory.cc9
-rw-r--r--chromium/ui/gl/init/gl_factory.h3
-rw-r--r--chromium/ui/gl/init/gl_initializer.h5
-rw-r--r--chromium/ui/gl/init/gl_initializer_android.cc18
-rw-r--r--chromium/ui/gl/init/gl_initializer_angle.cc21
-rw-r--r--chromium/ui/gl/init/gl_initializer_linux_x11.cc34
-rw-r--r--chromium/ui/gl/init/gl_initializer_mac.cc27
-rw-r--r--chromium/ui/gl/init/gl_initializer_win.cc26
-rw-r--r--chromium/ui/gl/swap_chain_presenter.cc57
-rw-r--r--chromium/ui/gl/yuv_to_rgb_converter.cc18
-rw-r--r--chromium/ui/gl/yuv_to_rgb_converter.h1
-rw-r--r--chromium/ui/gtk/BUILD.gn21
-rw-r--r--chromium/ui/gtk/DIR_METADATA3
-rw-r--r--chromium/ui/gtk/OWNERS2
-rw-r--r--chromium/ui/gtk/gdk_pixbuf.fragment1
-rw-r--r--chromium/ui/gtk/gdk_pixbuf.sigs3
-rw-r--r--chromium/ui/gtk/gtk_ui.cc119
-rw-r--r--chromium/ui/gtk/gtk_ui_delegate.h11
-rw-r--r--chromium/ui/gtk/gtk_util.cc59
-rw-r--r--chromium/ui/gtk/gtk_util.h15
-rw-r--r--chromium/ui/gtk/input_method_context_impl_gtk.cc1
-rw-r--r--chromium/ui/gtk/input_method_context_impl_gtk.h8
-rw-r--r--chromium/ui/gtk/native_theme_gtk.cc30
-rw-r--r--chromium/ui/gtk/native_theme_gtk.h1
-rw-r--r--chromium/ui/gtk/nav_button_provider_gtk.cc64
-rw-r--r--chromium/ui/gtk/printing/DIR_METADATA3
-rw-r--r--chromium/ui/gtk/printing/OWNERS2
-rw-r--r--chromium/ui/gtk/select_file_dialog_impl.cc2
-rw-r--r--chromium/ui/gtk/select_file_dialog_impl_gtk.cc232
-rw-r--r--chromium/ui/gtk/select_file_dialog_impl_gtk.h7
-rw-r--r--chromium/ui/gtk/settings_provider_gsettings.cc20
-rw-r--r--chromium/ui/gtk/settings_provider_gsettings.h5
-rw-r--r--chromium/ui/gtk/x/gtk_event_loop_x11.cc104
-rw-r--r--chromium/ui/gtk/x/gtk_event_loop_x11.h13
-rw-r--r--chromium/ui/gtk/x/gtk_ui_delegate_x11.cc17
-rw-r--r--chromium/ui/gtk/x/gtk_ui_delegate_x11.h1
-rw-r--r--chromium/ui/latency/DIR_METADATA3
-rw-r--r--chromium/ui/latency/OWNERS5
-rw-r--r--chromium/ui/latency/ipc/DIR_METADATA3
-rw-r--r--chromium/ui/latency/ipc/OWNERS2
-rw-r--r--chromium/ui/latency/latency_info.cc3
-rw-r--r--chromium/ui/latency/latency_info.dot1
-rw-r--r--chromium/ui/latency/latency_tracker.cc22
-rw-r--r--chromium/ui/login/BUILD.gn3
-rw-r--r--chromium/ui/login/DIR_METADATA3
-rw-r--r--chromium/ui/login/OWNERS1
-rw-r--r--chromium/ui/login/account_picker/chromeos_screen_account_picker.css150
-rw-r--r--chromium/ui/login/account_picker/chromeos_screen_account_picker.html11
-rw-r--r--chromium/ui/login/account_picker/chromeos_screen_account_picker.js412
-rw-r--r--chromium/ui/login/account_picker/chromeos_user_pod_row.css1218
-rw-r--r--chromium/ui/login/account_picker/chromeos_user_pod_row.js4741
-rw-r--r--chromium/ui/login/account_picker/chromeos_user_pod_template.css34
-rw-r--r--chromium/ui/login/account_picker/chromeos_user_pod_template.html257
-rw-r--r--chromium/ui/login/account_picker/screen_account_picker.css74
-rw-r--r--chromium/ui/login/account_picker/screen_account_picker.html8
-rw-r--r--chromium/ui/login/account_picker/screen_account_picker.js403
-rw-r--r--chromium/ui/login/account_picker/user_pod_row.css1017
-rw-r--r--chromium/ui/login/account_picker/user_pod_row.js3656
-rw-r--r--chromium/ui/login/account_picker/user_pod_template.css14
-rw-r--r--chromium/ui/login/account_picker/user_pod_template.html229
-rw-r--r--chromium/ui/login/display_manager.js125
-rw-r--r--chromium/ui/login/display_manager_types.js30
-rw-r--r--chromium/ui/login/login_ui_tools.js31
-rw-r--r--chromium/ui/login/oobe.css98
-rw-r--r--chromium/ui/message_center/BUILD.gn2
-rw-r--r--chromium/ui/message_center/DIR_METADATA4
-rw-r--r--chromium/ui/message_center/OWNERS3
-rw-r--r--chromium/ui/message_center/fake_message_center.cc11
-rw-r--r--chromium/ui/message_center/message_center_impl.cc2
-rw-r--r--chromium/ui/message_center/message_center_impl_unittest.cc5
-rw-r--r--chromium/ui/message_center/notification_list.cc3
-rw-r--r--chromium/ui/message_center/popup_timers_controller.cc5
-rw-r--r--chromium/ui/message_center/public/cpp/BUILD.gn1
-rw-r--r--chromium/ui/message_center/public/cpp/notification.cc5
-rw-r--r--chromium/ui/message_center/public/cpp/notification.h25
-rw-r--r--chromium/ui/message_center/views/message_popup_collection.cc21
-rw-r--r--chromium/ui/message_center/views/message_popup_collection.h16
-rw-r--r--chromium/ui/message_center/views/message_popup_collection_unittest.cc9
-rw-r--r--chromium/ui/message_center/views/message_popup_view.cc22
-rw-r--r--chromium/ui/message_center/views/message_popup_view.h14
-rw-r--r--chromium/ui/message_center/views/message_view.cc19
-rw-r--r--chromium/ui/message_center/views/message_view.h3
-rw-r--r--chromium/ui/message_center/views/message_view_factory.cc2
-rw-r--r--chromium/ui/message_center/views/message_view_factory.h2
-rw-r--r--chromium/ui/message_center/views/notification_control_buttons_view.cc14
-rw-r--r--chromium/ui/message_center/views/notification_control_buttons_view.h14
-rw-r--r--chromium/ui/message_center/views/notification_header_view.cc9
-rw-r--r--chromium/ui/message_center/views/notification_header_view.h9
-rw-r--r--chromium/ui/message_center/views/notification_header_view_unittest.cc10
-rw-r--r--chromium/ui/message_center/views/notification_view_md.h3
-rw-r--r--chromium/ui/message_center/views/notification_view_md_unittest.cc7
-rw-r--r--chromium/ui/message_center/views/padded_button.cc13
-rw-r--r--chromium/ui/message_center/views/padded_button.h11
-rw-r--r--chromium/ui/message_center/views/proportional_image_view.cc10
-rw-r--r--chromium/ui/message_center/views/proportional_image_view.h11
-rw-r--r--chromium/ui/native_theme/DIR_METADATA3
-rw-r--r--chromium/ui/native_theme/OWNERS2
-rw-r--r--chromium/ui/native_theme/common_theme.cc703
-rw-r--r--chromium/ui/native_theme/native_theme.cc52
-rw-r--r--chromium/ui/native_theme/native_theme.h39
-rw-r--r--chromium/ui/native_theme/native_theme_android.cc89
-rw-r--r--chromium/ui/native_theme/native_theme_android.h16
-rw-r--r--chromium/ui/native_theme/native_theme_aura.cc4
-rw-r--r--chromium/ui/native_theme/native_theme_base.cc73
-rw-r--r--chromium/ui/native_theme/native_theme_base.h29
-rw-r--r--chromium/ui/native_theme/native_theme_color_id.h6
-rw-r--r--chromium/ui/native_theme/native_theme_features.cc13
-rw-r--r--chromium/ui/native_theme/native_theme_features.h4
-rw-r--r--chromium/ui/native_theme/native_theme_mac.mm15
-rw-r--r--chromium/ui/native_theme/native_theme_mac_unittest.mm23
-rw-r--r--chromium/ui/native_theme/native_theme_win.cc22
-rw-r--r--chromium/ui/native_theme/native_theme_win_unittest.cc28
-rw-r--r--chromium/ui/native_theme/test_native_theme.cc4
-rw-r--r--chromium/ui/native_theme/test_native_theme.h8
-rw-r--r--chromium/ui/ozone/BUILD.gn3
-rw-r--r--chromium/ui/ozone/DIR_METADATA4
-rw-r--r--chromium/ui/ozone/OWNERS3
-rw-r--r--chromium/ui/ozone/common/egl_util.cc46
-rw-r--r--chromium/ui/ozone/common/features.cc2
-rw-r--r--chromium/ui/ozone/common/gl_surface_egl_readback.cc1
-rw-r--r--chromium/ui/ozone/demo/window_manager.cc11
-rw-r--r--chromium/ui/ozone/demo/window_manager.h2
-rw-r--r--chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc6
-rw-r--r--chromium/ui/ozone/platform/cast/DIR_METADATA3
-rw-r--r--chromium/ui/ozone/platform/cast/OWNERS2
-rw-r--r--chromium/ui/ozone/platform/drm/BUILD.gn5
-rw-r--r--chromium/ui/ozone/platform/drm/DIR_METADATA3
-rw-r--r--chromium/ui/ozone/platform/drm/OWNERS2
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util.cc114
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util.h2
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc173
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/DEPS1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc10
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h5
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_device.cc47
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_device.h22
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_display.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h8
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc42
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc13
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc8
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h4
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc11
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread.cc10
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_window.cc10
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_window.h5
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc7
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc9
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc117
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h31
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc281
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc33
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc10
-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.cc30
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc72
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc88
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h42
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h31
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager.cc350
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager.h42
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc505
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_cursor.cc7
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc12
-rw-r--r--chromium/ui/ozone/platform/drm/host/host_drm_device.cc7
-rw-r--r--chromium/ui/ozone/platform/drm/ozone_platform_drm.cc16
-rw-r--r--chromium/ui/ozone/platform/headless/ozone_platform_headless.cc4
-rw-r--r--chromium/ui/ozone/platform/scenic/overlay_manager_scenic.cc5
-rw-r--r--chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc3
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc3
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc1
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface_factory.h1
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window.cc11
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window.h8
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc17
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h9
-rw-r--r--chromium/ui/ozone/platform/wayland/BUILD.gn35
-rw-r--r--chromium/ui/ozone/platform/wayland/DEPS2
-rw-r--r--chromium/ui/ozone/platform/wayland/common/data_util.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland.cc24
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland.h20
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_object.cc4
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_object.h10
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_util.cc28
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_util.h7
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_util_unittest.cc71
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc63
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h11
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc30
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc25
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.h4
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc32
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h16
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc7
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc3
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h1
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc246
-rw-r--r--chromium/ui/ozone/platform/wayland/host/DEPS2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc17
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc27
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h1
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc42
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_object_factory.h8
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc119
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h11
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h53
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.cc (renamed from chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.cc)2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h98
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc41
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc6
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc210
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h50
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc175
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h28
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc232
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection.cc70
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection.h11
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc28
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor.h30
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc156
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h90
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc134
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc24
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device.h9
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc8
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h27
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc203
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc232
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h61
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc446
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc27
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h8
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc60
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source.h15
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc32
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc63
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc20
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h27
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc11
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc20
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_popup.cc21
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_popup.h9
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_screen.cc19
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc6
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_shm.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_surface.cc110
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_surface.h23
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc398
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h100
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_touch.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_touch.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window.cc235
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window.h76
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc28
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h15
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc142
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc42
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc419
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc13
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h14
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc53
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc353
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h46
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc358
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h75
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc202
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h88
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc22
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h5
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_offer.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc14
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.cc262
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.h64
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.cc74
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h56
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc166
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h72
-rw-r--r--chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc11
-rw-r--r--chromium/ui/ozone/platform/wayland/test/mock_surface.cc35
-rw-r--r--chromium/ui/ozone/platform/wayland/test/mock_surface.h7
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_compositor.cc10
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_compositor.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_data_offer.cc18
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_data_offer.h10
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc7
-rw-r--r--chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc127
-rw-r--r--chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h68
-rw-r--r--chromium/ui/ozone/platform/wayland/test/wayland_test.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc180
-rw-r--r--chromium/ui/ozone/platform/x11/BUILD.gn6
-rw-r--r--chromium/ui/ozone/platform/x11/client_native_pixmap_factory_x11.cc4
-rw-r--r--chromium/ui/ozone/platform/x11/gl_egl_utility_x11.cc13
-rw-r--r--chromium/ui/ozone/platform/x11/gl_egl_utility_x11.h4
-rw-r--r--chromium/ui/ozone/platform/x11/ozone_platform_x11.cc33
-rw-r--r--chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc83
-rw-r--r--chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h14
-rw-r--r--chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc15
-rw-r--r--chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h8
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone.cc16
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone.h7
-rw-r--r--chromium/ui/ozone/platform/x11/x11_surface_factory.cc41
-rw-r--r--chromium/ui/ozone/platform/x11/x11_surface_factory.h14
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc5
-rw-r--r--chromium/ui/ozone/public/input_controller.cc3
-rw-r--r--chromium/ui/ozone/public/input_controller.h11
-rw-r--r--chromium/ui/ozone/public/mojom/device_cursor.mojom3
-rw-r--r--chromium/ui/ozone/public/mojom/drm_device.mojom6
-rw-r--r--chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom18
-rw-r--r--chromium/ui/ozone/public/overlay_manager_ozone.h9
-rw-r--r--chromium/ui/ozone/public/overlay_surface_candidate.h2
-rw-r--r--chromium/ui/ozone/public/ozone_platform.cc2
-rw-r--r--chromium/ui/ozone/public/ozone_platform.h32
-rw-r--r--chromium/ui/ozone/public/ozone_switches.cc6
-rw-r--r--chromium/ui/ozone/public/ozone_switches.h4
-rw-r--r--chromium/ui/ozone/public/platform_gl_egl_utility.cc29
-rw-r--r--chromium/ui/ozone/public/platform_gl_egl_utility.h14
-rw-r--r--chromium/ui/ozone/public/surface_factory_ozone.cc3
-rw-r--r--chromium/ui/ozone/public/surface_factory_ozone.h3
-rw-r--r--chromium/ui/platform_window/DEPS1
-rw-r--r--chromium/ui/platform_window/DIR_METADATA3
-rw-r--r--chromium/ui/platform_window/OWNERS1
-rw-r--r--chromium/ui/platform_window/extensions/wayland_extension.h21
-rw-r--r--chromium/ui/platform_window/extensions/x11_extension_delegate.h10
-rw-r--r--chromium/ui/platform_window/platform_window.cc4
-rw-r--r--chromium/ui/platform_window/platform_window.h4
-rw-r--r--chromium/ui/platform_window/platform_window_delegate.cc5
-rw-r--r--chromium/ui/platform_window/platform_window_delegate.h7
-rw-r--r--chromium/ui/platform_window/platform_window_init_properties.cc7
-rw-r--r--chromium/ui/platform_window/platform_window_init_properties.h14
-rw-r--r--chromium/ui/platform_window/win/BUILD.gn1
-rw-r--r--chromium/ui/platform_window/win/win_window.cc7
-rw-r--r--chromium/ui/platform_window/x11/BUILD.gn2
-rw-r--r--chromium/ui/platform_window/x11/atk_event_conversion.cc7
-rw-r--r--chromium/ui/platform_window/x11/atk_event_conversion.h2
-rw-r--r--chromium/ui/platform_window/x11/x11_window.cc99
-rw-r--r--chromium/ui/platform_window/x11/x11_window.h37
-rw-r--r--chromium/ui/platform_window/x11/x11_window_manager.cc2
-rw-r--r--chromium/ui/resources/BUILD.gn7
-rw-r--r--chromium/ui/resources/DIR_METADATA3
-rw-r--r--chromium/ui/resources/OWNERS2
-rw-r--r--chromium/ui/shell_dialogs/BUILD.gn5
-rw-r--r--chromium/ui/shell_dialogs/DIR_METADATA3
-rw-r--r--chromium/ui/shell_dialogs/OWNERS1
-rw-r--r--chromium/ui/shell_dialogs/execute_select_file_win.cc29
-rw-r--r--chromium/ui/shell_dialogs/execute_select_file_win.h10
-rw-r--r--chromium/ui/shell_dialogs/execute_select_file_win_unittest.cc2
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_fuchsia.cc1
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm10
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_win.cc38
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_win.h2
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_win_unittest.cc27
-rw-r--r--chromium/ui/shell_dialogs/shell_dialog_linux.cc3
-rw-r--r--chromium/ui/snapshot/DIR_METADATA3
-rw-r--r--chromium/ui/snapshot/OWNERS1
-rw-r--r--chromium/ui/snapshot/screenshot_grabber.h5
-rw-r--r--chromium/ui/snapshot/snapshot_mac_unittest.mm8
-rw-r--r--chromium/ui/strings/DIR_METADATA3
-rw-r--r--chromium/ui/strings/OWNERS1
-rw-r--r--chromium/ui/strings/app_locale_settings.grd12
-rw-r--r--chromium/ui/strings/translations/ui_strings_af.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_am.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_ar.xtb10
-rw-r--r--chromium/ui/strings/translations/ui_strings_as.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_az.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_be.xtb8
-rw-r--r--chromium/ui/strings/translations/ui_strings_bg.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_bn.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_bs.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_ca.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_cs.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_da.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_de.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_el.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_en-GB.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_es-419.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_es.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_et.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_eu.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_fa.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_fi.xtb8
-rw-r--r--chromium/ui/strings/translations/ui_strings_fil.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_fr-CA.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_fr.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_gl.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_gu.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_hi.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_hr.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_hu.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_hy.xtb22
-rw-r--r--chromium/ui/strings/translations/ui_strings_id.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_is.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_it.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_iw.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_ja.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_ka.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_kk.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_km.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_kn.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_ko.xtb8
-rw-r--r--chromium/ui/strings/translations/ui_strings_ky.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_lo.xtb8
-rw-r--r--chromium/ui/strings/translations/ui_strings_lt.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_lv.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_mk.xtb8
-rw-r--r--chromium/ui/strings/translations/ui_strings_ml.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_mn.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_mr.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_ms.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_my.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_ne.xtb8
-rw-r--r--chromium/ui/strings/translations/ui_strings_nl.xtb10
-rw-r--r--chromium/ui/strings/translations/ui_strings_no.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_or.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_pa.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_pl.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_pt-BR.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_pt-PT.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_ro.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_ru.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_si.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_sk.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_sl.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_sq.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_sr-Latn.xtb8
-rw-r--r--chromium/ui/strings/translations/ui_strings_sr.xtb8
-rw-r--r--chromium/ui/strings/translations/ui_strings_sv.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_sw.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_ta.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_te.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_th.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_tr.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_uk.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_ur.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_uz.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_vi.xtb12
-rw-r--r--chromium/ui/strings/translations/ui_strings_zh-CN.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_zh-HK.xtb6
-rw-r--r--chromium/ui/strings/translations/ui_strings_zh-TW.xtb8
-rw-r--r--chromium/ui/strings/translations/ui_strings_zu.xtb6
-rw-r--r--chromium/ui/strings/ui_strings.grd36
-rw-r--r--chromium/ui/strings/ui_strings_grd/IDS_APP_SHOW_CLIPBOARD_HISTORY.png.sha11
-rw-r--r--chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_HISTORY_DELETE_BUTTON.png.sha11
-rw-r--r--chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_HISTORY_ITEM_DELETION.png.sha11
-rw-r--r--chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_MENU_HTML.png.sha11
-rw-r--r--chromium/ui/strings/ui_strings_grd/IDS_CONCAT_TWO_STRINGS_WITH_COMMA.png.sha11
-rw-r--r--chromium/ui/strings/ui_strings_grd/IDS_CONCAT_TWO_STRINGS_WITH_PERIODS.png.sha11
-rw-r--r--chromium/ui/surface/DIR_METADATA3
-rw-r--r--chromium/ui/surface/OWNERS2
-rw-r--r--chromium/ui/touch_selection/BUILD.gn5
-rw-r--r--chromium/ui/touch_selection/DIR_METADATA4
-rw-r--r--chromium/ui/touch_selection/OWNERS2
-rw-r--r--chromium/ui/touch_selection/touch_selection_controller.cc27
-rw-r--r--chromium/ui/touch_selection/touch_selection_controller.h3
-rw-r--r--chromium/ui/touch_selection/touch_selection_controller_unittest.cc53
-rw-r--r--chromium/ui/touch_selection/touch_selection_draggable.h9
-rw-r--r--chromium/ui/views/BUILD.gn70
-rw-r--r--chromium/ui/views/DEPS1
-rw-r--r--chromium/ui/views/DIR_METADATA3
-rw-r--r--chromium/ui/views/OWNERS2
-rw-r--r--chromium/ui/views/accessibility/DIR_METADATA4
-rw-r--r--chromium/ui/views/accessibility/OWNERS3
-rw-r--r--chromium/ui/views/accessibility/accessibility_alert_window.cc4
-rw-r--r--chromium/ui/views/accessibility/accessibility_alert_window.h4
-rw-r--r--chromium/ui/views/accessibility/accessibility_alert_window_unittest.cc2
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.cc60
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.h50
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc77
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_wrapper.h12
-rw-r--r--chromium/ui/views/accessibility/ax_root_obj_wrapper.cc8
-rw-r--r--chromium/ui/views/accessibility/ax_root_obj_wrapper.h3
-rw-r--r--chromium/ui/views/accessibility/ax_tree_source_views.cc8
-rw-r--r--chromium/ui/views/accessibility/ax_tree_source_views.h3
-rw-r--r--chromium/ui/views/accessibility/ax_view_obj_wrapper.cc15
-rw-r--r--chromium/ui/views/accessibility/ax_view_obj_wrapper.h8
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view.cc53
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view.h13
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view_unittest.cc360
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view_wrapper.cc8
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view_wrapper.h4
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc15
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.h13
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.cc8
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.h9
-rw-r--r--chromium/ui/views/accessibility/view_accessibility.cc200
-rw-r--r--chromium/ui/views/accessibility/view_accessibility.h122
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc346
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate.h64
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc109
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.h13
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm7
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc678
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_win.cc8
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc140
-rw-r--r--chromium/ui/views/accessibility/views_ax_tree_manager.cc61
-rw-r--r--chromium/ui/views/accessibility/views_ax_tree_manager.h40
-rw-r--r--chromium/ui/views/accessibility/views_ax_tree_manager_unittest.cc80
-rw-r--r--chromium/ui/views/accessibility/widget_ax_tree_id_map.cc55
-rw-r--r--chromium/ui/views/accessibility/widget_ax_tree_id_map.h41
-rw-r--r--chromium/ui/views/accessible_pane_view_unittest.cc3
-rw-r--r--chromium/ui/views/animation/animation_delegate_views.cc5
-rw-r--r--chromium/ui/views/animation/animation_delegate_views.h4
-rw-r--r--chromium/ui/views/animation/bubble_slide_animator.cc101
-rw-r--r--chromium/ui/views/animation/bubble_slide_animator.h116
-rw-r--r--chromium/ui/views/animation/bubble_slide_animator_unittest.cc376
-rw-r--r--chromium/ui/views/animation/compositor_animation_runner.h1
-rw-r--r--chromium/ui/views/animation/ink_drop.cc4
-rw-r--r--chromium/ui/views/animation/ink_drop.h12
-rw-r--r--chromium/ui/views/animation/ink_drop_event_handler.cc6
-rw-r--r--chromium/ui/views/animation/ink_drop_event_handler.h6
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.cc2
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.h2
-rw-r--r--chromium/ui/views/animation/ink_drop_painted_layer_delegates.h5
-rw-r--r--chromium/ui/views/animation/installable_ink_drop.cc2
-rw-r--r--chromium/ui/views/animation/installable_ink_drop.h4
-rw-r--r--chromium/ui/views/animation/widget_fade_animator.cc104
-rw-r--r--chromium/ui/views/animation/widget_fade_animator.h125
-rw-r--r--chromium/ui/views/animation/widget_fade_animator_unittest.cc276
-rw-r--r--chromium/ui/views/background.cc23
-rw-r--r--chromium/ui/views/bubble/DIR_METADATA3
-rw-r--r--chromium/ui/views/bubble/OWNERS2
-rw-r--r--chromium/ui/views/bubble/bubble_border.cc25
-rw-r--r--chromium/ui/views/bubble/bubble_border.h27
-rw-r--r--chromium/ui/views/bubble/bubble_border_unittest.cc4
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.cc49
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.h19
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_model_host.cc34
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_model_host.h3
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.cc77
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.h37
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view_unittest.cc53
-rw-r--r--chromium/ui/views/bubble/tooltip_icon.cc5
-rw-r--r--chromium/ui/views/bubble/tooltip_icon.h4
-rw-r--r--chromium/ui/views/button_drag_utils.cc2
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac.mm6
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm18
-rw-r--r--chromium/ui/views/cocoa/native_widget_mac_ns_window_host.h2
-rw-r--r--chromium/ui/views/cocoa/native_widget_mac_ns_window_host.mm14
-rw-r--r--chromium/ui/views/cocoa/text_input_host.mm4
-rw-r--r--chromium/ui/views/color_chooser/color_chooser_unittest.cc20
-rw-r--r--chromium/ui/views/color_chooser/color_chooser_view.cc254
-rw-r--r--chromium/ui/views/color_chooser/color_chooser_view.h94
-rw-r--r--chromium/ui/views/controls/button/button.cc6
-rw-r--r--chromium/ui/views/controls/button/button.h4
-rw-r--r--chromium/ui/views/controls/button/button_unittest.cc4
-rw-r--r--chromium/ui/views/controls/button/checkbox.cc2
-rw-r--r--chromium/ui/views/controls/button/checkbox.h2
-rw-r--r--chromium/ui/views/controls/button/image_button.cc16
-rw-r--r--chromium/ui/views/controls/button/image_button.h9
-rw-r--r--chromium/ui/views/controls/button/image_button_unittest.cc2
-rw-r--r--chromium/ui/views/controls/button/label_button.cc5
-rw-r--r--chromium/ui/views/controls/button/label_button.h5
-rw-r--r--chromium/ui/views/controls/button/label_button_label.cc12
-rw-r--r--chromium/ui/views/controls/button/label_button_label.h9
-rw-r--r--chromium/ui/views/controls/button/label_button_unittest.cc49
-rw-r--r--chromium/ui/views/controls/button/menu_button.h13
-rw-r--r--chromium/ui/views/controls/button/menu_button_controller.cc4
-rw-r--r--chromium/ui/views/controls/button/menu_button_controller.h2
-rw-r--r--chromium/ui/views/controls/combobox/combobox.cc8
-rw-r--r--chromium/ui/views/controls/combobox/combobox.h5
-rw-r--r--chromium/ui/views/controls/dot_indicator.cc75
-rw-r--r--chromium/ui/views/controls/dot_indicator.h43
-rw-r--r--chromium/ui/views/controls/editable_combobox/editable_combobox.cc17
-rw-r--r--chromium/ui/views/controls/editable_combobox/editable_combobox.h5
-rw-r--r--chromium/ui/views/controls/focus_ring.cc6
-rw-r--r--chromium/ui/views/controls/focus_ring.h4
-rw-r--r--chromium/ui/views/controls/image_view.h4
-rw-r--r--chromium/ui/views/controls/label.cc103
-rw-r--r--chromium/ui/views/controls/label.h25
-rw-r--r--chromium/ui/views/controls/label_unittest.cc40
-rw-r--r--chromium/ui/views/controls/link.cc4
-rw-r--r--chromium/ui/views/controls/link.h2
-rw-r--r--chromium/ui/views/controls/menu/README.md198
-rw-r--r--chromium/ui/views/controls/menu/menu_config.h7
-rw-r--r--chromium/ui/views/controls/menu/menu_config_chromeos.cc6
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.cc155
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.h26
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_unittest.cc68
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.cc19
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.h19
-rw-r--r--chromium/ui/views/controls/menu/menu_host.cc5
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.cc78
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.h15
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view_unittest.cc62
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.cc2
-rw-r--r--chromium/ui/views/controls/menu/menu_runner.cc2
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm290
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.cc30
-rw-r--r--chromium/ui/views/controls/menu/menu_separator.cc6
-rw-r--r--chromium/ui/views/controls/menu/menu_separator.h2
-rw-r--r--chromium/ui/views/controls/menu/menu_types.h1
-rw-r--r--chromium/ui/views/controls/menu/native_menu_win.cc13
-rw-r--r--chromium/ui/views/controls/menu/native_menu_win.h5
-rw-r--r--chromium/ui/views/controls/menu/new_badge.h2
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.cc3
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.h3
-rw-r--r--chromium/ui/views/controls/message_box_view.cc6
-rw-r--r--chromium/ui/views/controls/message_box_view.h3
-rw-r--r--chromium/ui/views/controls/native/native_view_host_mac.mm7
-rw-r--r--chromium/ui/views/controls/prefix_selector.cc18
-rw-r--r--chromium/ui/views/controls/prefix_selector.h12
-rw-r--r--chromium/ui/views/controls/prefix_selector_unittest.cc32
-rw-r--r--chromium/ui/views/controls/progress_bar.cc15
-rw-r--r--chromium/ui/views/controls/scroll_view.cc123
-rw-r--r--chromium/ui/views/controls/scroll_view.h37
-rw-r--r--chromium/ui/views/controls/scroll_view_unittest.cc82
-rw-r--r--chromium/ui/views/controls/separator.cc4
-rw-r--r--chromium/ui/views/controls/styled_label_unittest.cc8
-rw-r--r--chromium/ui/views/controls/tabbed_pane/DIR_METADATA3
-rw-r--r--chromium/ui/views/controls/tabbed_pane/OWNERS2
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc5
-rw-r--r--chromium/ui/views/controls/table/table_header.cc9
-rw-r--r--chromium/ui/views/controls/table/table_header.h9
-rw-r--r--chromium/ui/views/controls/table/table_view.cc58
-rw-r--r--chromium/ui/views/controls/table/table_view.h13
-rw-r--r--chromium/ui/views/controls/table/table_view_unittest.cc73
-rw-r--r--chromium/ui/views/controls/textarea/textarea.cc114
-rw-r--r--chromium/ui/views/controls/textarea/textarea.h36
-rw-r--r--chromium/ui/views/controls/textarea/textarea_unittest.cc299
-rw-r--r--chromium/ui/views/controls/textfield/DIR_METADATA3
-rw-r--r--chromium/ui/views/controls/textfield/OWNERS2
-rw-r--r--chromium/ui/views/controls/textfield/textfield.cc468
-rw-r--r--chromium/ui/views/controls/textfield/textfield.h62
-rw-r--r--chromium/ui/views/controls/textfield/textfield_controller.cc7
-rw-r--r--chromium/ui/views/controls/textfield/textfield_controller.h5
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.cc48
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.h21
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model_unittest.cc5
-rw-r--r--chromium/ui/views/controls/textfield/textfield_unittest.cc1064
-rw-r--r--chromium/ui/views/controls/textfield/textfield_unittest.h184
-rw-r--r--chromium/ui/views/controls/theme_tracking_image_view.cc36
-rw-r--r--chromium/ui/views/controls/theme_tracking_image_view.h41
-rw-r--r--chromium/ui/views/controls/tree/tree_view_unittest.cc17
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu_base.cc2
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu_base.h7
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu_chromeos.cc79
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu_chromeos.h51
-rw-r--r--chromium/ui/views/controls/webview/OWNERS1
-rw-r--r--chromium/ui/views/controls/webview/web_contents_set_background_color.cc27
-rw-r--r--chromium/ui/views/controls/webview/web_contents_set_background_color.h5
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.cc8
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.h16
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view_unittest.cc5
-rw-r--r--chromium/ui/views/controls/webview/webview.cc85
-rw-r--r--chromium/ui/views/controls/webview/webview.h23
-rw-r--r--chromium/ui/views/controls/webview/webview_unittest.cc26
-rw-r--r--chromium/ui/views/corewm/DEPS2
-rw-r--r--chromium/ui/views/corewm/tooltip_aura.cc17
-rw-r--r--chromium/ui/views/corewm/tooltip_controller.cc4
-rw-r--r--chromium/ui/views/corewm/tooltip_controller.h3
-rw-r--r--chromium/ui/views/corewm/tooltip_win.cc3
-rw-r--r--chromium/ui/views/debug/BUILD.gn8
-rw-r--r--chromium/ui/views/debug/DEPS6
-rw-r--r--chromium/ui/views/debug/debugger_utils.cc147
-rw-r--r--chromium/ui/views/debug/debugger_utils.h54
-rw-r--r--chromium/ui/views/event_monitor_aura.cc10
-rw-r--r--chromium/ui/views/examples/BUILD.gn10
-rw-r--r--chromium/ui/views/examples/README.md53
-rw-r--r--chromium/ui/views/examples/bubble_example.cc29
-rw-r--r--chromium/ui/views/examples/bubble_example.h6
-rw-r--r--chromium/ui/views/examples/button_example.cc4
-rw-r--r--chromium/ui/views/examples/create_examples.cc2
-rw-r--r--chromium/ui/views/examples/examples_main_proc.cc8
-rw-r--r--chromium/ui/views/examples/examples_views_delegate_chromeos.cc8
-rw-r--r--chromium/ui/views/examples/examples_views_delegate_chromeos.h5
-rw-r--r--chromium/ui/views/examples/examples_window.cc27
-rw-r--r--chromium/ui/views/examples/examples_window.h2
-rw-r--r--chromium/ui/views/examples/examples_with_content_main.cc4
-rw-r--r--chromium/ui/views/examples/textarea_example.cc36
-rw-r--r--chromium/ui/views/examples/textarea_example.h26
-rw-r--r--chromium/ui/views/examples/vector_example.cc2
-rw-r--r--chromium/ui/views/examples/views_examples_resources.grd2
-rw-r--r--chromium/ui/views/features.gni3
-rw-r--r--chromium/ui/views/focus/focus_manager.cc12
-rw-r--r--chromium/ui/views/layout/animating_layout_manager.cc12
-rw-r--r--chromium/ui/views/layout/animating_layout_manager_unittest.cc14
-rw-r--r--chromium/ui/views/layout/box_layout_view.cc31
-rw-r--r--chromium/ui/views/layout/box_layout_view.h2
-rw-r--r--chromium/ui/views/layout/flex_layout_view.cc36
-rw-r--r--chromium/ui/views/layout/flex_layout_view.h2
-rw-r--r--chromium/ui/views/layout/grid_layout.cc2
-rw-r--r--chromium/ui/views/layout/layout_manager.h8
-rw-r--r--chromium/ui/views/layout/layout_manager_base.cc7
-rw-r--r--chromium/ui/views/layout/layout_manager_base.h8
-rw-r--r--chromium/ui/views/metadata/metadata_impl_macros.h69
-rw-r--r--chromium/ui/views/metadata/metadata_macros_internal.h78
-rw-r--r--chromium/ui/views/metadata/metadata_types.cc10
-rw-r--r--chromium/ui/views/metadata/metadata_types.h28
-rw-r--r--chromium/ui/views/metadata/metadata_unittest.cc71
-rw-r--r--chromium/ui/views/metadata/property_metadata.h166
-rw-r--r--chromium/ui/views/metadata/type_conversion.cc451
-rw-r--r--chromium/ui/views/metadata/type_conversion.h226
-rw-r--r--chromium/ui/views/metadata/type_conversion_unittest.cc115
-rw-r--r--chromium/ui/views/selection_controller.cc5
-rw-r--r--chromium/ui/views/style/platform_style.cc15
-rw-r--r--chromium/ui/views/style/platform_style.h6
-rw-r--r--chromium/ui/views/style/platform_style_mac.mm13
-rw-r--r--chromium/ui/views/style/typography.cc6
-rw-r--r--chromium/ui/views/style/typography.h3
-rw-r--r--chromium/ui/views/style/typography_provider.cc89
-rw-r--r--chromium/ui/views/style/typography_provider.h9
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.cc36
-rw-r--r--chromium/ui/views/touchui/touch_selection_menu_views.cc5
-rw-r--r--chromium/ui/views/view.cc274
-rw-r--r--chromium/ui/views/view.h129
-rw-r--r--chromium/ui/views/view_class_properties.cc1
-rw-r--r--chromium/ui/views/view_class_properties.h6
-rw-r--r--chromium/ui/views/view_tracker.cc4
-rw-r--r--chromium/ui/views/view_tracker.h5
-rw-r--r--chromium/ui/views/view_unittest.cc14
-rw-r--r--chromium/ui/views/view_utils.cc67
-rw-r--r--chromium/ui/views/view_utils.h31
-rw-r--r--chromium/ui/views/views_delegate.cc6
-rw-r--r--chromium/ui/views/views_delegate.h6
-rw-r--r--chromium/ui/views/views_features.cc8
-rw-r--r--chromium/ui/views/views_features.h1
-rw-r--r--chromium/ui/views/views_test_suite.cc5
-rw-r--r--chromium/ui/views/views_test_suite.h16
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc14
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h4
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc50
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc18
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h11
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc19
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h10
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc7
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen.cc3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc5
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_win.h1
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc12
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h29
-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_linux.cc11
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc20
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc62
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h16
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc137
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc29
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h3
-rw-r--r--chromium/ui/views/widget/desktop_aura/window_move_client_platform.cc2
-rw-r--r--chromium/ui/views/widget/desktop_aura/window_shape_updater.cc80
-rw-r--r--chromium/ui/views/widget/desktop_aura/window_shape_updater.h49
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_drag_drop_client_unittest.cc44
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc38
-rw-r--r--chromium/ui/views/widget/drop_helper.cc14
-rw-r--r--chromium/ui/views/widget/drop_helper.h7
-rw-r--r--chromium/ui/views/widget/focus_manager_event_handler.cc4
-rw-r--r--chromium/ui/views/widget/focus_manager_event_handler.h2
-rw-r--r--chromium/ui/views/widget/native_widget_aura.cc46
-rw-r--r--chromium/ui/views/widget/native_widget_aura.h8
-rw-r--r--chromium/ui/views/widget/native_widget_aura_unittest.cc4
-rw-r--r--chromium/ui/views/widget/native_widget_delegate.h3
-rw-r--r--chromium/ui/views/widget/native_widget_mac.mm2
-rw-r--r--chromium/ui/views/widget/native_widget_mac_unittest.mm32
-rw-r--r--chromium/ui/views/widget/root_view.cc86
-rw-r--r--chromium/ui/views/widget/root_view.h37
-rw-r--r--chromium/ui/views/widget/root_view_unittest.cc88
-rw-r--r--chromium/ui/views/widget/unique_widget_ptr.cc10
-rw-r--r--chromium/ui/views/widget/unique_widget_ptr_unittest.cc10
-rw-r--r--chromium/ui/views/widget/widget.cc51
-rw-r--r--chromium/ui/views/widget/widget.h40
-rw-r--r--chromium/ui/views/widget/widget_delegate.cc11
-rw-r--r--chromium/ui/views/widget/widget_delegate.h20
-rw-r--r--chromium/ui/views/widget/widget_delegate_unittest.cc22
-rw-r--r--chromium/ui/views/widget/widget_interactive_uitest.cc11
-rw-r--r--chromium/ui/views/widget/widget_unittest.cc54
-rw-r--r--chromium/ui/views/widget/widget_utils.cc8
-rw-r--r--chromium/ui/views/widget/widget_utils.h4
-rw-r--r--chromium/ui/views/win/fullscreen_handler.cc3
-rw-r--r--chromium/ui/views/win/fullscreen_handler.h3
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.cc73
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.h8
-rw-r--r--chromium/ui/views/window/custom_frame_view.cc9
-rw-r--r--chromium/ui/views/window/custom_frame_view.h9
-rw-r--r--chromium/ui/views/window/dialog_client_view.cc13
-rw-r--r--chromium/ui/views/window/dialog_delegate.cc17
-rw-r--r--chromium/ui/views/window/dialog_delegate.h18
-rw-r--r--chromium/ui/views/window/dialog_delegate_unittest.cc6
-rw-r--r--chromium/ui/views/window/frame_background.cc1
-rw-r--r--chromium/ui/views/window/frame_background.h4
-rw-r--r--chromium/ui/views/window/frame_caption_button.cc66
-rw-r--r--chromium/ui/views/window/frame_caption_button.h18
-rw-r--r--chromium/ui/views/window/frame_caption_button_unittest.cc7
-rw-r--r--chromium/ui/views/window/native_frame_view.cc9
-rw-r--r--chromium/ui/views/window/native_frame_view.h15
-rw-r--r--chromium/ui/views/window/non_client_view.h20
-rw-r--r--chromium/ui/views/window/window_resize_utils.cc107
-rw-r--r--chromium/ui/views/window/window_resize_utils.h56
-rw-r--r--chromium/ui/views/window/window_resize_utils_unittest.cc161
-rw-r--r--chromium/ui/views/window/window_shape.cc10
-rw-r--r--chromium/ui/views/window/window_shape.h1
-rw-r--r--chromium/ui/views_content_client/BUILD.gn8
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts_aura.cc3
-rw-r--r--chromium/ui/web_dialogs/DIR_METADATA3
-rw-r--r--chromium/ui/web_dialogs/OWNERS1
-rw-r--r--chromium/ui/web_dialogs/web_dialog_ui.cc4
-rw-r--r--chromium/ui/webui/BUILD.gn22
-rw-r--r--chromium/ui/webui/OWNERS2
-rw-r--r--chromium/ui/webui/resources/BUILD.gn17
-rw-r--r--chromium/ui/webui/resources/cr_components/BUILD.gn122
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html2
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_browser_proxy.js1
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.html48
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.js4
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_entry.html2
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_list.js4
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn6
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/bluetooth/BUILD.gn23
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn243
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.html205
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js215
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_camera.svg1
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_checked.svg1
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_switch_camera.svg1
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.html16
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.js18
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html25
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.js44
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.html96
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.js117
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html16
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js74
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup_icons.html18
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_types.js15
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.html89
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.js80
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/default_esim_profile.svg1
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html35
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js443
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.html2
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.js40
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.html2
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.js98
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.html10
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.js9
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.js55
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.html45
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.js45
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.html17
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.js37
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/provisioning_page.html8
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html19
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js67
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html49
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.js91
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.html8
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.js18
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.html40
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.js47
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.js4
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn221
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_1x.svg1
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_2x.svg1
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html5
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.js6
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.js6
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/icons.html12
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js14
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html45
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js5
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js9
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html29
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_1x.pngbin10988 -> 0 bytes
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_2x.pngbin24434 -> 0 bytes
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html21
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html173
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js30
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html126
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js6
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn28
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.html2
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.js76
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js12
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html1
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js19
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_icon.html72
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_icons.html8
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_list.html6
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.html63
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.js192
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_list_types.js13
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_select.html1
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_select.js77
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html10
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js53
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/onc_mojo.js45
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn99
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html65
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.js309
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.html3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.js79
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.html41
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.js47
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.html4
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.js16
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html141
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.js106
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.html54
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.js151
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/os_cr_components.gni24
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/BUILD.gn3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js25
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn25
-rw-r--r--chromium/ui/webui/resources/cr_components/cr_components_images.grdp134
-rw-r--r--chromium/ui/webui/resources/cr_components/customize_themes/BUILD.gn12
-rw-r--r--chromium/ui/webui/resources/cr_components/customize_themes/browser_proxy.js24
-rw-r--r--chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.html82
-rw-r--r--chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.js56
-rw-r--r--chromium/ui/webui/resources/cr_components/customize_themes/theme_icon.html2
-rw-r--r--chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_components/omnibox/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_components/omnibox/cr_autocomplete_match_list.js9
-rw-r--r--chromium/ui/webui/resources/cr_elements/BUILD.gn26
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/BUILD.gn10
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js2
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/os_cr_elements.gni1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_action_menu/BUILD.gn4
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js26
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_button/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_button/cr_button.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html3
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_expand_button/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js11
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js3
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_icon_button/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_input/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_input/cr_input.html8
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_input/cr_input.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html3
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_lazy_render/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_link_row/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html5
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_lottie/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js5
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html26
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js83
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_card_radio_button.html7
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js26
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_slider/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_tabs/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.js13
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn34
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html15
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js28
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html12
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.js18
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_view_manager/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_view_manager/cr_view_manager.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/icons.html4
-rw-r--r--chromium/ui/webui/resources/cr_elements/mwb_shared_style.html21
-rw-r--r--chromium/ui/webui/resources/cr_elements/mwb_shared_vars.html11
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js1
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html2
-rw-r--r--chromium/ui/webui/resources/cr_elements/shared_style_css.html23
-rw-r--r--chromium/ui/webui/resources/cr_elements/shared_vars_css.html1
-rw-r--r--chromium/ui/webui/resources/cr_elements_images.grdp54
-rw-r--r--chromium/ui/webui/resources/css/BUILD.gn6
-rw-r--r--chromium/ui/webui/resources/css/bubble.css97
-rw-r--r--chromium/ui/webui/resources/css/bubble_button.css20
-rw-r--r--chromium/ui/webui/resources/css/controlled_indicator.css100
-rw-r--r--chromium/ui/webui/resources/html/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/html/cr/ui/overlay.html1
-rw-r--r--chromium/ui/webui/resources/html/test_loader.html4
-rw-r--r--chromium/ui/webui/resources/images/BUILD.gn77
-rw-r--r--chromium/ui/webui/resources/images/icon_tabs.svg1
-rw-r--r--chromium/ui/webui/resources/images/menu.svg1
-rw-r--r--chromium/ui/webui/resources/images/supervisor_account.svg1
-rw-r--r--chromium/ui/webui/resources/js/BUILD.gn20
-rw-r--r--chromium/ui/webui/resources/js/assert.js2
-rw-r--r--chromium/ui/webui/resources/js/color_utils.js6
-rw-r--r--chromium/ui/webui/resources/js/cr/BUILD.gn2
-rw-r--r--chromium/ui/webui/resources/js/cr/event_target.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/BUILD.gn59
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/array_data_model.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/bubble.js569
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/bubble_button.js94
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/card_slider.js693
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/command.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js128
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/dialogs.js41
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/focus_grid.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/focus_outline_manager.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/focus_row_behavior.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/focus_without_ink.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/grid.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/keyboard_shortcut_list.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list.js10
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list_item.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list_selection_controller.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list_selection_model.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/menu.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/menu_button.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/overlay.js158
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/position_util.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/splitter.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/store.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/store_client.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/tabs.js1
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/touch_handler.js884
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/tree.js1
-rw-r--r--chromium/ui/webui/resources/js/event_tracker.js2
-rw-r--r--chromium/ui/webui/resources/js/i18n_behavior.js2
-rw-r--r--chromium/ui/webui/resources/js/icon.js1
-rw-r--r--chromium/ui/webui/resources/js/list_property_update_behavior.js84
-rw-r--r--chromium/ui/webui/resources/js/load_time_data.js2
-rw-r--r--chromium/ui/webui/resources/js/parse_html_subset.js12
-rw-r--r--chromium/ui/webui/resources/js/plural_string_proxy.js42
-rw-r--r--chromium/ui/webui/resources/js/promise_resolver.js2
-rw-r--r--chromium/ui/webui/resources/js/search_highlight_utils.js1
-rw-r--r--chromium/ui/webui/resources/js/test_loader.js12
-rw-r--r--chromium/ui/webui/resources/js/test_loader_util.js17
-rw-r--r--chromium/ui/webui/resources/js/util.js2
-rw-r--r--chromium/ui/webui/resources/js/web_ui_listener_behavior.js2
-rw-r--r--chromium/ui/webui/resources/tools/generate_grd.py16
-rwxr-xr-xchromium/ui/webui/resources/tools/generate_grd_test.py9
-rw-r--r--chromium/ui/webui/resources/tools/js_modulizer.gni3
-rw-r--r--chromium/ui/webui/resources/webui_resources.grd89
-rw-r--r--chromium/ui/webui/untrusted_web_ui_browsertest_util.cc51
-rw-r--r--chromium/ui/webui/untrusted_web_ui_browsertest_util.h57
-rw-r--r--chromium/ui/webui/untrusted_web_ui_controller.cc20
-rw-r--r--chromium/ui/webui/untrusted_web_ui_controller.h28
-rw-r--r--chromium/ui/webui/untrusted_web_ui_controller_factory.cc66
-rw-r--r--chromium/ui/webui/untrusted_web_ui_controller_factory.h57
-rw-r--r--chromium/ui/webui/webui_config.cc18
-rw-r--r--chromium/ui/webui/webui_config.h50
-rw-r--r--chromium/ui/wm/BUILD.gn7
-rw-r--r--chromium/ui/wm/DIR_METADATA3
-rw-r--r--chromium/ui/wm/OWNERS1
-rw-r--r--chromium/ui/wm/core/accelerator_filter.cc18
-rw-r--r--chromium/ui/wm/core/accelerator_filter.h9
-rw-r--r--chromium/ui/wm/core/compound_event_filter.cc7
-rw-r--r--chromium/ui/wm/core/compound_event_filter.h2
-rw-r--r--chromium/ui/wm/core/compound_event_filter_unittest.cc14
-rw-r--r--chromium/ui/wm/core/focus_controller.cc61
-rw-r--r--chromium/ui/wm/core/focus_controller.h7
-rw-r--r--chromium/ui/wm/core/ime_util_chromeos.cc36
-rw-r--r--chromium/ui/wm/core/ime_util_chromeos.h26
-rw-r--r--chromium/ui/wm/core/ime_util_chromeos_unittest.cc19
-rw-r--r--chromium/ui/wm/core/shadow_controller.cc19
-rw-r--r--chromium/ui/wm/core/transient_window_manager.cc2
-rw-r--r--chromium/ui/wm/core/window_animations.cc27
-rw-r--r--chromium/ui/wm/core/window_animations_unittest.cc35
-rw-r--r--chromium/ui/wm/core/window_modality_controller.cc4
-rw-r--r--chromium/ui/wm/core/window_modality_controller.h2
2059 files changed, 155506 insertions, 36923 deletions
diff --git a/chromium/ui/DIR_METADATA b/chromium/ui/DIR_METADATA
new file mode 100644
index 00000000000..f31293e3139
--- /dev/null
+++ b/chromium/ui/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI"
+}
diff --git a/chromium/ui/OWNERS b/chromium/ui/OWNERS
index b9e44dd600a..cd4f28bc0c8 100644
--- a/chromium/ui/OWNERS
+++ b/chromium/ui/OWNERS
@@ -1,3 +1,4 @@
+set noparent
sadrul@chromium.org
sky@chromium.org
thakis@chromium.org
@@ -15,4 +16,3 @@ per-file *.xtb=file://tools/translation/TRANSLATION_OWNERS
# For Fuchsia-specific changes:
per-file *fuchsia*=file://build/fuchsia/OWNERS
per-file *scenic*=file://build/fuchsia/OWNERS
-# COMPONENT: UI
diff --git a/chromium/ui/accelerated_widget_mac/BUILD.gn b/chromium/ui/accelerated_widget_mac/BUILD.gn
index b9795661986..dfd37911a72 100644
--- a/chromium/ui/accelerated_widget_mac/BUILD.gn
+++ b/chromium/ui/accelerated_widget_mac/BUILD.gn
@@ -30,11 +30,13 @@ component("accelerated_widget_mac") {
deps = [
"//base",
"//components/metal_util",
+ "//media",
"//skia",
"//ui/base",
"//ui/events",
"//ui/events:events_base",
"//ui/gfx",
+ "//ui/gfx:gfx_io_surface_hdr_metadata",
"//ui/gfx/geometry",
"//ui/gl",
]
diff --git a/chromium/ui/accelerated_widget_mac/DEPS b/chromium/ui/accelerated_widget_mac/DEPS
index 8ed6f073fc0..b232b787a31 100644
--- a/chromium/ui/accelerated_widget_mac/DEPS
+++ b/chromium/ui/accelerated_widget_mac/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+components/metal_util",
"+gpu/GLES2",
+ "+media/base/mac/color_space_util_mac.h",
"+third_party/skia",
"+ui/base/cocoa",
"+ui/base",
diff --git a/chromium/ui/accelerated_widget_mac/DIR_METADATA b/chromium/ui/accelerated_widget_mac/DIR_METADATA
new file mode 100644
index 00000000000..d00c92336b8
--- /dev/null
+++ b/chromium/ui/accelerated_widget_mac/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals>PlatformIntegration"
+}
diff --git a/chromium/ui/accelerated_widget_mac/OWNERS b/chromium/ui/accelerated_widget_mac/OWNERS
index 33f4cc854e8..4eb0cb4e607 100644
--- a/chromium/ui/accelerated_widget_mac/OWNERS
+++ b/chromium/ui/accelerated_widget_mac/OWNERS
@@ -1,2 +1 @@
ccameron@chromium.org
-# COMPONENT: Internals>PlatformIntegration
diff --git a/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm b/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
index d67941273ae..e4610b0da4e 100644
--- a/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
+++ b/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
@@ -13,12 +13,15 @@
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/mac/foundation_util.h"
#include "base/trace_event/trace_event.h"
#include "components/metal_util/hdr_copier_layer.h"
+#include "media/base/mac/color_space_util_mac.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/cocoa/animation_utils.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/geometry/dip_util.h"
+#include "ui/gfx/mac/io_surface_hdr_metadata.h"
#include "ui/gl/ca_renderer_layer_params.h"
#include "ui/gl/gl_image_io_surface.h"
@@ -31,10 +34,8 @@ namespace {
bool AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(
AVSampleBufferDisplayLayer* av_layer,
CVPixelBufferRef cv_pixel_buffer) {
- OSStatus os_status = noErr;
-
base::ScopedCFTypeRef<CMVideoFormatDescriptionRef> video_info;
- os_status = CMVideoFormatDescriptionCreateForImageBuffer(
+ OSStatus os_status = CMVideoFormatDescriptionCreateForImageBuffer(
nullptr, cv_pixel_buffer, video_info.InitializeInto());
if (os_status != noErr) {
LOG(ERROR) << "CMVideoFormatDescriptionCreateForImageBuffer failed with "
@@ -104,7 +105,8 @@ bool AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(
// of and retain |io_surface| until it is no longer being displayed.
bool AVSampleBufferDisplayLayerEnqueueIOSurface(
AVSampleBufferDisplayLayer* av_layer,
- IOSurfaceRef io_surface) {
+ IOSurfaceRef io_surface,
+ const gfx::ColorSpace& io_surface_color_space) {
CVReturn cv_return = kCVReturnSuccess;
base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer;
@@ -115,6 +117,55 @@ bool AVSampleBufferDisplayLayerEnqueueIOSurface(
return false;
}
+ if (__builtin_available(macos 11.0, *)) {
+ if (io_surface_color_space ==
+ gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT2020,
+ gfx::ColorSpace::TransferID::SMPTEST2084,
+ gfx::ColorSpace::MatrixID::BT2020_NCL,
+ gfx::ColorSpace::RangeID::LIMITED) ||
+ io_surface_color_space ==
+ gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT2020,
+ gfx::ColorSpace::TransferID::ARIB_STD_B67,
+ gfx::ColorSpace::MatrixID::BT2020_NCL,
+ gfx::ColorSpace::RangeID::LIMITED)) {
+ CVBufferSetAttachment(cv_pixel_buffer, kCVImageBufferColorPrimariesKey,
+ kCVImageBufferColorPrimaries_ITU_R_2020,
+ kCVAttachmentMode_ShouldPropagate);
+ CVBufferSetAttachment(cv_pixel_buffer, kCVImageBufferYCbCrMatrixKey,
+ kCVImageBufferYCbCrMatrix_ITU_R_2020,
+ kCVAttachmentMode_ShouldPropagate);
+ CVBufferSetAttachment(
+ cv_pixel_buffer, kCVImageBufferTransferFunctionKey,
+ io_surface_color_space.GetTransferID() ==
+ gfx::ColorSpace::TransferID::ARIB_STD_B67
+ ? kCVImageBufferTransferFunction_ITU_R_2100_HLG
+ : kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ,
+ kCVAttachmentMode_ShouldPropagate);
+
+ // Transfer stashed HDR metadata from the IOSurface to the CVPixelBuffer.
+ //
+ // Note: It'd be nice to find a way to set this on the IOSurface itself
+ // in some way that propagates to the CVPixelBuffer, but thus far we
+ // haven't been able to find a way.
+ gfx::HDRMetadata hdr_metadata;
+ if (IOSurfaceGetHDRMetadata(io_surface, hdr_metadata)) {
+ if (!(hdr_metadata.mastering_metadata == gfx::MasteringMetadata())) {
+ CVBufferSetAttachment(
+ cv_pixel_buffer, kCVImageBufferMasteringDisplayColorVolumeKey,
+ media::GenerateMasteringDisplayColorVolume(hdr_metadata),
+ kCVAttachmentMode_ShouldPropagate);
+ }
+ if (hdr_metadata.max_content_light_level ||
+ hdr_metadata.max_frame_average_light_level) {
+ CVBufferSetAttachment(
+ cv_pixel_buffer, kCVImageBufferContentLightLevelInfoKey,
+ media::GenerateContentLightLevelInfo(hdr_metadata),
+ kCVAttachmentMode_ShouldPropagate);
+ }
+ }
+ }
+ }
+
return AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(av_layer,
cv_pixel_buffer);
}
@@ -441,6 +492,7 @@ CARendererLayerTree::ContentLayer::ContentLayer(
switch (IOSurfaceGetPixelFormat(io_surface)) {
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
type = CALayerType::kVideo;
+ video_type_can_downgrade = !io_surface_color_space.IsHDR();
break;
case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
type = CALayerType::kVideo;
@@ -828,8 +880,8 @@ void CARendererLayerTree::ContentLayer::CommitToCA(CALayer* superlayer,
<< "AVSampleBufferDisplayLayerEnqueueCVPixelBuffer failed";
}
} else {
- result =
- AVSampleBufferDisplayLayerEnqueueIOSurface(av_layer, io_surface);
+ result = AVSampleBufferDisplayLayerEnqueueIOSurface(
+ av_layer, io_surface, io_surface_color_space);
if (!result) {
LOG(ERROR) << "AVSampleBufferDisplayLayerEnqueueIOSurface failed";
}
diff --git a/chromium/ui/accelerated_widget_mac/ca_transaction_observer.h b/chromium/ui/accelerated_widget_mac/ca_transaction_observer.h
index 04b3ba9d462..eb8618095b8 100644
--- a/chromium/ui/accelerated_widget_mac/ca_transaction_observer.h
+++ b/chromium/ui/accelerated_widget_mac/ca_transaction_observer.h
@@ -22,7 +22,7 @@ namespace ui {
// CATransactionCoordinator is an interface to undocumented macOS APIs which
// run callbacks at different stages of committing a CATransaction to the
// window server. There is no guarantee that it will call registered observers
-// at all: it does nothing on macOS older than 10.11.
+// at all.
//
// - Pre-commit: After all outstanding CATransactions have committed and after
// layout, but before the new layer tree has been sent to the window server.
@@ -84,7 +84,6 @@ class ACCELERATED_WIDGET_MAC_EXPORT CATransactionCoordinator {
CATransactionCoordinator();
~CATransactionCoordinator();
- API_AVAILABLE(macos(10.11))
void SynchronizeImpl();
void PreCommitHandler();
void PostCommitHandler();
diff --git a/chromium/ui/accelerated_widget_mac/ca_transaction_observer.mm b/chromium/ui/accelerated_widget_mac/ca_transaction_observer.mm
index e6d8b28fa43..af02cc27bcb 100644
--- a/chromium/ui/accelerated_widget_mac/ca_transaction_observer.mm
+++ b/chromium/ui/accelerated_widget_mac/ca_transaction_observer.mm
@@ -19,7 +19,6 @@ typedef enum {
kCATransactionPhasePostCommit,
} CATransactionPhase;
-API_AVAILABLE(macos(10.11))
@interface CATransaction ()
+ (void)addCommitHandler:(void (^)(void))block
forPhase:(CATransactionPhase)phase;
@@ -116,8 +115,7 @@ CATransactionCoordinator::~CATransactionCoordinator() = default;
void CATransactionCoordinator::Synchronize() {
if (disabled_for_testing_)
return;
- if (@available(macos 10.11, *))
- SynchronizeImpl();
+ SynchronizeImpl();
}
void CATransactionCoordinator::AddPreCommitObserver(
diff --git a/chromium/ui/accessibility/BUILD.gn b/chromium/ui/accessibility/BUILD.gn
index 4c192cb260d..3e693fd9e01 100644
--- a/chromium/ui/accessibility/BUILD.gn
+++ b/chromium/ui/accessibility/BUILD.gn
@@ -42,6 +42,12 @@ component("ax_base") {
"accessibility_features.h",
"accessibility_switches.cc",
"accessibility_switches.h",
+ "ax_action_data.cc",
+ "ax_action_data.h",
+ "ax_action_handler.cc",
+ "ax_action_handler.h",
+ "ax_action_handler_base.cc",
+ "ax_action_handler_base.h",
"ax_base_export.h",
"ax_enum_util.cc",
"ax_enum_util.h",
@@ -59,8 +65,15 @@ component("ax_base") {
"ax_relative_bounds.h",
"ax_role_properties.cc",
"ax_role_properties.h",
+ "ax_tree_data.cc",
+ "ax_tree_data.h",
"ax_tree_id.cc",
"ax_tree_id.h",
+ "ax_tree_id_registry.cc",
+ "ax_tree_id_registry.h",
+ "ax_tree_update.cc",
+ "ax_tree_update.h",
+ "ax_tree_update_forward.h",
]
public_deps = [
@@ -74,6 +87,8 @@ component("ax_base") {
"//ui/gfx/geometry",
"//ui/strings",
]
+
+ deps = [ "//build:chromeos_buildflags" ]
}
#if (is_win) {
@@ -88,12 +103,6 @@ component("accessibility") {
defines = [ "AX_IMPLEMENTATION" ]
sources = [
- "ax_action_data.cc",
- "ax_action_data.h",
- "ax_action_handler.cc",
- "ax_action_handler.h",
- "ax_action_handler_base.cc",
- "ax_action_handler_base.h",
"ax_action_target.h",
"ax_active_popup.cc",
"ax_active_popup.h",
@@ -123,10 +132,6 @@ component("accessibility") {
"ax_tree.h",
"ax_tree_combiner.cc",
"ax_tree_combiner.h",
- "ax_tree_data.cc",
- "ax_tree_data.h",
- "ax_tree_id_registry.cc",
- "ax_tree_id_registry.h",
"ax_tree_manager.h",
"ax_tree_manager_map.cc",
"ax_tree_manager_map.h",
@@ -136,8 +141,6 @@ component("accessibility") {
"ax_tree_serializer.h",
"ax_tree_source.h",
"ax_tree_source_checker.h",
- "ax_tree_update.h",
- "ax_tree_update_forward.h",
"null_ax_action_target.cc",
"null_ax_action_target.h",
]
@@ -206,7 +209,7 @@ static_library("test_support") {
]
}
- deps = [ ":accessibility" ]
+ public_deps = [ ":accessibility" ]
}
test("accessibility_unittests") {
@@ -218,6 +221,7 @@ test("accessibility_unittests") {
"ax_language_detection_unittest.cc",
"ax_node_data_unittest.cc",
"ax_node_position_unittest.cc",
+ "ax_node_unittest.cc",
"ax_range_unittest.cc",
"ax_role_properties_unittest.cc",
"ax_table_info_unittest.cc",
@@ -238,7 +242,7 @@ test("accessibility_unittests") {
"platform/ax_platform_node_unittest.cc",
"platform/ax_platform_node_unittest.h",
"platform/ax_unique_id_unittest.cc",
- "platform/inspect/property_node_unittest.cc",
+ "platform/inspect/ax_property_node_unittest.cc",
"run_all_unittests.cc",
]
diff --git a/chromium/ui/accessibility/DIR_METADATA b/chromium/ui/accessibility/DIR_METADATA
new file mode 100644
index 00000000000..fe89fde6463
--- /dev/null
+++ b/chromium/ui/accessibility/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+ component: "Internals>Accessibility"
+}
+team_email: "chromium-accessibility@chromium.org"
diff --git a/chromium/ui/accessibility/OWNERS b/chromium/ui/accessibility/OWNERS
index eb3d99c271a..717b0e5ab98 100644
--- a/chromium/ui/accessibility/OWNERS
+++ b/chromium/ui/accessibility/OWNERS
@@ -1,10 +1,10 @@
-dmazzoni@chromium.org
-dtseng@chromium.org
+abigailbklein@google.com
aboxhall@chromium.org
-nektar@chromium.org
-dougt@chromium.org
aleventhal@chromium.org
+dmazzoni@chromium.org
+dtseng@chromium.org
katie@chromium.org
+nektar@chromium.org
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
@@ -13,6 +13,3 @@ per-file *_param_traits*.*=set noparent
per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS
per-file ax_language_detection*=chrishall@chromium.org
-
-# TEAM: chromium-accessibility@chromium.org
-# COMPONENT: Internals>Accessibility
diff --git a/chromium/ui/accessibility/accessibility_features.cc b/chromium/ui/accessibility/accessibility_features.cc
index 57377907436..04a19ee4f94 100644
--- a/chromium/ui/accessibility/accessibility_features.cc
+++ b/chromium/ui/accessibility/accessibility_features.cc
@@ -6,9 +6,19 @@
#include "base/feature_list.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
namespace features {
+// Enable recognizing "aria-virtualcontent" as a valid aria property.
+const base::Feature kEnableAccessibilityAriaVirtualContent{
+ "AccessibilityAriaVirtualContent", base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsAccessibilityAriaVirtualContentEnabled() {
+ return base::FeatureList::IsEnabled(
+ ::features::kEnableAccessibilityAriaVirtualContent);
+}
+
// Enable exposing "display: none" nodes to the browser process AXTree
const base::Feature kEnableAccessibilityExposeDisplayNone{
"AccessibilityExposeDisplayNone", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -76,21 +86,31 @@ bool IsIChromeAccessibleEnabled() {
}
#endif // defined(OS_WIN)
-#if defined(OS_CHROMEOS)
-const base::Feature kAccessibilityCursorColor{"AccessibilityCursorColor",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-bool IsAccessibilityCursorColorEnabled() {
- return base::FeatureList::IsEnabled(::features::kAccessibilityCursorColor);
-}
-
+#if BUILDFLAG(IS_CHROMEOS_ASH)
const base::Feature kMagnifierNewFocusFollowing{
"MagnifierNewFocusFollowing", base::FEATURE_ENABLED_BY_DEFAULT};
bool IsMagnifierNewFocusFollowingEnabled() {
return base::FeatureList::IsEnabled(::features::kMagnifierNewFocusFollowing);
}
-#endif // defined(OS_CHROMEOS)
+
+const base::Feature kMagnifierPanningImprovements{
+ "MagnifierPanningImprovements", base::FEATURE_ENABLED_BY_DEFAULT};
+
+bool IsMagnifierPanningImprovementsEnabled() {
+ return base::FeatureList::IsEnabled(
+ ::features::kMagnifierPanningImprovements);
+}
+
+const base::Feature kMagnifierContinuousMouseFollowingModeSetting{
+ "MagnifierContinuousMouseFollowingModeSetting",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsMagnifierContinuousMouseFollowingModeSettingEnabled() {
+ return base::FeatureList::IsEnabled(
+ ::features::kMagnifierContinuousMouseFollowingModeSetting);
+}
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
const base::Feature kAugmentExistingImageLabels{
"AugmentExistingImageLabels", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -107,14 +127,21 @@ bool IsUseAXPositionForDocumentMarkersEnabled() {
::features::kUseAXPositionForDocumentMarkers);
}
-#if defined(OS_CHROMEOS)
+const base::Feature kEnableAriaElementReflection{
+ "EnableAriaElementReflection", base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsAriaElementReflectionEnabled() {
+ return base::FeatureList::IsEnabled(::features::kEnableAriaElementReflection);
+}
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
const base::Feature kSelectToSpeakNavigationControl{
- "SelectToSpeakNavigationControl", base::FEATURE_DISABLED_BY_DEFAULT};
+ "SelectToSpeakNavigationControl", base::FEATURE_ENABLED_BY_DEFAULT};
bool IsSelectToSpeakNavigationControlEnabled() {
return base::FeatureList::IsEnabled(
::features::kSelectToSpeakNavigationControl);
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace features
diff --git a/chromium/ui/accessibility/accessibility_features.h b/chromium/ui/accessibility/accessibility_features.h
index 23110de37bc..0fd6eca4895 100644
--- a/chromium/ui/accessibility/accessibility_features.h
+++ b/chromium/ui/accessibility/accessibility_features.h
@@ -8,10 +8,18 @@
#include "base/feature_list.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/accessibility/ax_base_export.h"
namespace features {
+AX_BASE_EXPORT extern const base::Feature
+ kEnableAccessibilityAriaVirtualContent;
+
+// Returns true if "aria-virtualcontent" should be recognized as a valid aria
+// property.
+AX_BASE_EXPORT bool IsAccessibilityAriaVirtualContentEnabled();
+
AX_BASE_EXPORT extern const base::Feature kEnableAccessibilityExposeDisplayNone;
// Returns true if "display: none" nodes should be exposed to the
@@ -62,20 +70,30 @@ AX_BASE_EXPORT bool IsIChromeAccessibleEnabled();
#endif // defined(OS_WIN)
-#if defined(OS_CHROMEOS)
-AX_BASE_EXPORT extern const base::Feature kAccessibilityCursorColor;
-
-// Returns true if the accessibility cursor color feature is enabled, letting
-// users pick a custom cursor color.
-AX_BASE_EXPORT bool IsAccessibilityCursorColorEnabled();
-
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Enables new magnifier focus following feature, which provides a richer
// focus following experience.
AX_BASE_EXPORT extern const base::Feature kMagnifierNewFocusFollowing;
// Returns true if the new magnifier focus following feature is enabled.
AX_BASE_EXPORT bool IsMagnifierNewFocusFollowingEnabled();
-#endif // defined(OS_CHROMEOS)
+
+// Enables new magnifier panning improvements feature, which adds
+// additional keyboard and mouse panning functionality in Magnifier.
+AX_BASE_EXPORT extern const base::Feature kMagnifierPanningImprovements;
+
+// Returns true if the new magnifier panning improvements feature is enabled.
+AX_BASE_EXPORT bool IsMagnifierPanningImprovementsEnabled();
+
+// Enables ability to choose new continuous mouse following mode in Magnifier
+// settings.
+AX_BASE_EXPORT extern const base::Feature
+ kMagnifierContinuousMouseFollowingModeSetting;
+
+// Returns true if the feature to allow choosing the new continuous mouse
+// following mode in Magnifier settings is enabled.
+AX_BASE_EXPORT bool IsMagnifierContinuousMouseFollowingModeSettingEnabled();
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Enables Get Image Descriptions to augment existing images labels,
// rather than only provide descriptions for completely unlabeled images.
@@ -96,14 +114,21 @@ AX_BASE_EXPORT extern const base::Feature kUseAXPositionForDocumentMarkers;
// nodes and which is different for each platform.
AX_BASE_EXPORT bool IsUseAXPositionForDocumentMarkersEnabled();
-#if defined(OS_CHROMEOS)
+// Enable support for ARIA element reflection, for example
+// element.ariaActiveDescendantElement = child;
+AX_BASE_EXPORT extern const base::Feature kEnableAriaElementReflection;
+
+// Returns true if ARIA element reflection is enabled.
+AX_BASE_EXPORT bool IsAriaElementReflectionEnabled();
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Enables enhanced Select-to-speak features that allow users broader control
// of TTS (pause, resume, skip between sentences and paragraphs).
AX_BASE_EXPORT extern const base::Feature kSelectToSpeakNavigationControl;
// Returns true if enhanced Select-to-speak features are enabled.
AX_BASE_EXPORT bool IsSelectToSpeakNavigationControlEnabled();
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace features
diff --git a/chromium/ui/accessibility/accessibility_switches.cc b/chromium/ui/accessibility/accessibility_switches.cc
index 5fe682f65a8..be3f94f7ce9 100644
--- a/chromium/ui/accessibility/accessibility_switches.cc
+++ b/chromium/ui/accessibility/accessibility_switches.cc
@@ -13,6 +13,14 @@ namespace switches {
const char kEnableExperimentalAccessibilityAutoclick[] =
"enable-experimental-accessibility-autoclick";
+// Enables the experimental dictation extension on Chrome OS that hasn't
+// launched yet.
+const char kEnableExperimentalAccessibilityDictationExtension[] =
+ "enable-experimental-accessibility-dictation-extension";
+
+const char kEnableExperimentalAccessibilityDictationOffline[] =
+ "enable-experimental-accessibility-dictation-offline";
+
// Enables support for visually debugging the accessibility labels
// feature, which provides images descriptions for screen reader users.
const char kEnableExperimentalAccessibilityLabelsDebugging[] =
@@ -32,14 +40,24 @@ const char kEnableExperimentalAccessibilityLanguageDetectionDynamic[] =
const char kEnableExperimentalAccessibilitySwitchAccessText[] =
"enable-experimental-accessibility-switch-access-text";
-// Enables annotations feature that hasn't launched yet.
-const char kEnableExperimentalAccessibilityChromeVoxAnnotations[] =
- "enable-experimental-accessibility-chromevox-annotations";
-
// Enables Switch Access point scanning. This feature hasn't launched yet.
const char kEnableSwitchAccessPointScanning[] =
"enable-switch-access-point-scanning";
+// Enables the Switch Access setup guide that hasn't launched yet.
+const char kEnableExperimentalAccessibilitySwitchAccessSetupGuide[] =
+ "enable-experimental-accessibility-switch-access-setup-guide";
+
+bool IsExperimentalAccessibilityDictationExtensionEnabled() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ ::switches::kEnableExperimentalAccessibilityDictationExtension);
+}
+
+bool IsExperimentalAccessibilityDictationOfflineEnabled() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ ::switches::kEnableExperimentalAccessibilityDictationOffline);
+}
+
bool IsExperimentalAccessibilityLanguageDetectionEnabled() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
::switches::kEnableExperimentalAccessibilityLanguageDetection);
diff --git a/chromium/ui/accessibility/accessibility_switches.h b/chromium/ui/accessibility/accessibility_switches.h
index fa841feeb62..6a5280cb817 100644
--- a/chromium/ui/accessibility/accessibility_switches.h
+++ b/chromium/ui/accessibility/accessibility_switches.h
@@ -13,6 +13,10 @@ namespace switches {
AX_BASE_EXPORT extern const char kEnableExperimentalAccessibilityAutoclick[];
AX_BASE_EXPORT extern const char
+ kEnableExperimentalAccessibilityDictationExtension[];
+AX_BASE_EXPORT extern const char
+ kEnableExperimentalAccessibilityDictationOffline[];
+AX_BASE_EXPORT extern const char
kEnableExperimentalAccessibilityLabelsDebugging[];
AX_BASE_EXPORT extern const char
kEnableExperimentalAccessibilityLanguageDetection[];
@@ -20,9 +24,15 @@ AX_BASE_EXPORT extern const char
kEnableExperimentalAccessibilityLanguageDetectionDynamic[];
AX_BASE_EXPORT extern const char
kEnableExperimentalAccessibilitySwitchAccessText[];
-AX_BASE_EXPORT extern const char
- kEnableExperimentalAccessibilityChromeVoxAnnotations[];
AX_BASE_EXPORT extern const char kEnableSwitchAccessPointScanning[];
+AX_BASE_EXPORT extern const char
+ kEnableExperimentalAccessibilitySwitchAccessSetupGuide[];
+
+// Returns true if experimental accessibility dictation extension is enabled.
+AX_BASE_EXPORT bool IsExperimentalAccessibilityDictationExtensionEnabled();
+
+// Returns true if experimental accessibility offline dictation is enabled.
+AX_BASE_EXPORT bool IsExperimentalAccessibilityDictationOfflineEnabled();
// Returns true if experimental accessibility language detection is enabled.
AX_BASE_EXPORT bool IsExperimentalAccessibilityLanguageDetectionEnabled();
diff --git a/chromium/ui/accessibility/ax_action_data.h b/chromium/ui/accessibility/ax_action_data.h
index 1527ae9a26d..796f04c40ea 100644
--- a/chromium/ui/accessibility/ax_action_data.h
+++ b/chromium/ui/accessibility/ax_action_data.h
@@ -5,8 +5,11 @@
#ifndef UI_ACCESSIBILITY_AX_ACTION_DATA_H_
#define UI_ACCESSIBILITY_AX_ACTION_DATA_H_
+#include <string>
+
+#include "ui/accessibility/ax_base_export.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
-#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree_id.h"
#include "ui/gfx/geometry/rect.h"
@@ -14,7 +17,7 @@ namespace ui {
// A compact representation of an accessibility action and the arguments
// associated with that action.
-struct AX_EXPORT AXActionData {
+struct AX_BASE_EXPORT AXActionData {
AXActionData();
AXActionData(const AXActionData& other);
~AXActionData();
@@ -58,7 +61,7 @@ struct AX_EXPORT AXActionData {
int32_t end_index = -1;
// For custom action.
- int custom_action_id = -1;
+ AXNodeID custom_action_id = kInvalidAXNodeID;
// The target rect for the action.
gfx::Rect target_rect;
diff --git a/chromium/ui/accessibility/ax_action_handler.h b/chromium/ui/accessibility/ax_action_handler.h
index d999a0e35d6..0b7cdf6861a 100644
--- a/chromium/ui/accessibility/ax_action_handler.h
+++ b/chromium/ui/accessibility/ax_action_handler.h
@@ -6,7 +6,7 @@
#define UI_ACCESSIBILITY_AX_ACTION_HANDLER_H_
#include "ui/accessibility/ax_action_handler_base.h"
-#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_base_export.h"
namespace ui {
@@ -16,7 +16,7 @@ namespace ui {
//
// If you need more control over how the AXTreeID associated to this class is
// set, please inherit directly from AXActionHandlerBase instead.
-class AX_EXPORT AXActionHandler : public AXActionHandlerBase {
+class AX_BASE_EXPORT AXActionHandler : public AXActionHandlerBase {
protected:
AXActionHandler();
};
diff --git a/chromium/ui/accessibility/ax_action_handler_base.h b/chromium/ui/accessibility/ax_action_handler_base.h
index 2e2b5b09d91..ee2522edad2 100644
--- a/chromium/ui/accessibility/ax_action_handler_base.h
+++ b/chromium/ui/accessibility/ax_action_handler_base.h
@@ -5,7 +5,7 @@
#ifndef UI_ACCESSIBILITY_AX_ACTION_HANDLER_BASE_H_
#define UI_ACCESSIBILITY_AX_ACTION_HANDLER_BASE_H_
-#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_base_export.h"
#include "ui/accessibility/ax_tree_id.h"
namespace ui {
@@ -20,7 +20,7 @@ struct AXActionData;
//
// Subclasses can use |tree_id| when annotating their |AXNodeData| for clients
// to respond with the appropriate target node id.
-class AX_EXPORT AXActionHandlerBase {
+class AX_BASE_EXPORT AXActionHandlerBase {
public:
virtual ~AXActionHandlerBase();
diff --git a/chromium/ui/accessibility/ax_action_target.h b/chromium/ui/accessibility/ax_action_target.h
index fe2797afde1..2fd2379ba29 100644
--- a/chromium/ui/accessibility/ax_action_target.h
+++ b/chromium/ui/accessibility/ax_action_target.h
@@ -11,6 +11,8 @@
namespace ui {
+struct AXActionData;
+
// AXActionTarget is an abstract interface that can be used to carry out
// accessibility actions on nodes from an AXTreeSource without knowing the
// concrete class of that AXTreeSource.
@@ -21,25 +23,18 @@ class AXActionTarget {
enum class Type { kNull, kBlink, kPdf };
virtual Type GetType() const = 0;
- virtual bool ClearAccessibilityFocus() const = 0;
- virtual bool Click() const = 0;
- virtual bool Decrement() const = 0;
- virtual bool Increment() const = 0;
- virtual bool Focus() const = 0;
+ virtual bool PerformAction(const AXActionData& action_data) const = 0;
+
virtual gfx::Rect GetRelativeBounds() const = 0;
virtual gfx::Point GetScrollOffset() const = 0;
virtual gfx::Point MinimumScrollOffset() const = 0;
virtual gfx::Point MaximumScrollOffset() const = 0;
- virtual bool SetAccessibilityFocus() const = 0;
virtual void SetScrollOffset(const gfx::Point& point) const = 0;
virtual bool SetSelected(bool selected) const = 0;
virtual bool SetSelection(const AXActionTarget* anchor_object,
int anchor_offset,
const AXActionTarget* focus_object,
int focus_offset) const = 0;
- virtual bool SetSequentialFocusNavigationStartingPoint() const = 0;
- virtual bool SetValue(const std::string& value) const = 0;
- virtual bool ShowContextMenu() const = 0;
// Make this object visible by scrolling as many nested scrollable views as
// needed.
virtual bool ScrollToMakeVisible() const = 0;
@@ -50,9 +45,6 @@ class AXActionTarget {
ax::mojom::ScrollAlignment horizontal_scroll_alignment,
ax::mojom::ScrollAlignment vertical_scroll_alignment,
ax::mojom::ScrollBehavior scroll_behavior) const = 0;
- // Scroll this object to a given point in global coordinates of the top-level
- // window.
- virtual bool ScrollToGlobalPoint(const gfx::Point& point) const = 0;
protected:
AXActionTarget() = default;
diff --git a/chromium/ui/accessibility/ax_active_popup.cc b/chromium/ui/accessibility/ax_active_popup.cc
index 570838ff537..f459bbf3a31 100644
--- a/chromium/ui/accessibility/ax_active_popup.cc
+++ b/chromium/ui/accessibility/ax_active_popup.cc
@@ -4,33 +4,44 @@
#include "ui/accessibility/ax_active_popup.h"
+#include "base/macros.h"
+#include "base/no_destructor.h"
+
namespace ui {
-// Represents a global storage for the view accessibility for an
-// autofill popup. It is a singleton wrapper around the ax unique id of the
-// autofill popup. This singleton is used for communicating the live status of
-// the autofill popup between web contents and views.
-// The assumption here is that only one autofill popup can exist at a time.
-static base::NoDestructor<base::Optional<int32_t>> g_active_popup_ax_unique_id;
-
-base::Optional<int32_t> GetActivePopupAxUniqueId() {
- return *g_active_popup_ax_unique_id;
+
+namespace {
+
+base::Optional<AXNodeID>& GetActivePopupAXUniqueIdInstance() {
+ // Keeps track of the unique ID that can be used to retrieve the
+ // `ViewAccessibility` object that is handling the accessibility for the
+ // currently active autofill popup. This singleton is used for communicating
+ // the live status of the autofill popup between web contents and Views. The
+ // assumption here is that only one autofill popup can exist at a time.
+ static base::NoDestructor<base::Optional<AXNodeID>> active_popup_ax_unique_id;
+ return *active_popup_ax_unique_id;
+}
+
+} // namespace
+
+base::Optional<AXNodeID> GetActivePopupAxUniqueId() {
+ return GetActivePopupAXUniqueIdInstance();
}
-void SetActivePopupAxUniqueId(base::Optional<int32_t> ax_unique_id) {
+void SetActivePopupAxUniqueId(base::Optional<AXNodeID> ax_unique_id) {
// When an instance of autofill popup hides, the caller of popup hide should
- // make sure g_active_popup_ax_unique_id is cleared. The assumption is that
+ // make sure active_popup_ax_unique_id is cleared. The assumption is that
// there can only be one active autofill popup existing at a time. If on
- // popup showing, we encounter g_active_popup_ax_unique_id is already set,
+ // popup showing, we encounter active_popup_ax_unique_id is already set,
// this would indicate two autofill popups are showing at the same time or
// previous on popup hide call did not clear the variable, so we should fail
- // DCHECK here.
- DCHECK(!GetActivePopupAxUniqueId());
+ // via DCHECK here.
+ DCHECK(!GetActivePopupAXUniqueIdInstance());
- *g_active_popup_ax_unique_id = ax_unique_id;
+ GetActivePopupAXUniqueIdInstance() = ax_unique_id;
}
void ClearActivePopupAxUniqueId() {
- *g_active_popup_ax_unique_id = base::nullopt;
+ GetActivePopupAXUniqueIdInstance() = base::nullopt;
}
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_active_popup.h b/chromium/ui/accessibility/ax_active_popup.h
index 111c8c5468e..9d6f1abb775 100644
--- a/chromium/ui/accessibility/ax_active_popup.h
+++ b/chromium/ui/accessibility/ax_active_popup.h
@@ -5,15 +5,15 @@
#ifndef UI_ACCESSIBILITY_AX_ACTIVE_POPUP_H_
#define UI_ACCESSIBILITY_AX_ACTIVE_POPUP_H_
-#include "base/macros.h"
-#include "base/no_destructor.h"
#include "base/optional.h"
#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_node_data.h"
namespace ui {
-AX_EXPORT base::Optional<int32_t> GetActivePopupAxUniqueId();
-AX_EXPORT void SetActivePopupAxUniqueId(base::Optional<int32_t> ax_unique_id);
+AX_EXPORT base::Optional<AXNodeID> GetActivePopupAxUniqueId();
+
+AX_EXPORT void SetActivePopupAxUniqueId(base::Optional<AXNodeID> ax_unique_id);
AX_EXPORT void ClearActivePopupAxUniqueId();
diff --git a/chromium/ui/accessibility/ax_assistant_structure.cc b/chromium/ui/accessibility/ax_assistant_structure.cc
index 1d3419861e1..127063bbf69 100644
--- a/chromium/ui/accessibility/ax_assistant_structure.cc
+++ b/chromium/ui/accessibility/ax_assistant_structure.cc
@@ -4,7 +4,7 @@
#include "ui/accessibility/ax_assistant_structure.h"
-#include <string>
+#include <utility>
#include "base/logging.h"
#include "base/optional.h"
@@ -34,15 +34,6 @@ bool HasFocusableChild(const AXNode* node) {
return false;
}
-bool HasOnlyTextChildren(const AXNode* node) {
- for (size_t i = 0; i < node->GetUnignoredChildCount(); ++i) {
- AXNode* child = node->GetUnignoredChildAtIndex(i);
- if (!child->IsText())
- return false;
- }
- return true;
-}
-
// TODO(muyuanli): share with BrowserAccessibility.
bool IsSimpleTextControl(const AXNode* node, uint32_t state) {
return (node->data().role == ax::mojom::Role::kTextField ||
@@ -111,7 +102,7 @@ base::string16 GetInnerText(const AXNode* node) {
return text;
}
-base::string16 GetValue(const AXNode* node, bool show_password) {
+base::string16 GetValue(const AXNode* node) {
base::string16 value =
node->data().GetString16Attribute(ax::mojom::StringAttribute::kValue);
@@ -122,51 +113,27 @@ base::string16 GetValue(const AXNode* node, bool show_password) {
value = GetInnerText(node);
}
- if (node->data().HasState(ax::mojom::State::kProtected)) {
- if (!show_password) {
- value = base::string16(value.size(), kSecurePasswordBullet);
- }
- }
+ // Always obscure passwords.
+ if (node->data().HasState(ax::mojom::State::kProtected))
+ value = base::string16(value.size(), kSecurePasswordBullet);
return value;
}
-bool HasOnlyTextAndImageChildren(const AXNode* node) {
- for (size_t i = 0; i < node->GetUnignoredChildCount(); ++i) {
- AXNode* child = node->GetUnignoredChildAtIndex(i);
- if (!child->IsText() && !ui::IsImage(child->data().role)) {
- return false;
- }
- }
- return true;
-}
-
-bool IsFocusable(const AXNode* node) {
- if (node->data().role == ax::mojom::Role::kIframe ||
- node->data().role == ax::mojom::Role::kIframePresentational ||
- (node->data().role == ax::mojom::Role::kRootWebArea &&
- node->GetUnignoredParent())) {
- return node->data().HasStringAttribute(ax::mojom::StringAttribute::kName);
- }
- return node->data().HasState(ax::mojom::State::kFocusable);
-}
-
-base::string16 GetText(const AXNode* node, bool show_password) {
- if (node->data().role == ax::mojom::Role::kWebArea ||
+base::string16 GetText(const AXNode* node) {
+ if (node->data().role == ax::mojom::Role::kPdfRoot ||
node->data().role == ax::mojom::Role::kIframe ||
node->data().role == ax::mojom::Role::kIframePresentational) {
return base::string16();
}
- ax::mojom::NameFrom name_from = static_cast<ax::mojom::NameFrom>(
- node->data().GetIntAttribute(ax::mojom::IntAttribute::kNameFrom));
- if (ui::IsListItem(node->data().role) &&
- name_from == ax::mojom::NameFrom::kContents) {
- if (!node->children().empty() && !HasOnlyTextChildren(node))
- return base::string16();
+ ax::mojom::NameFrom name_from = node->data().GetNameFrom();
+
+ if (!ui::IsLeaf(node) && name_from == ax::mojom::NameFrom::kContents) {
+ return base::string16();
}
- base::string16 value = GetValue(node, show_password);
+ base::string16 value = GetValue(node);
if (!value.empty()) {
if (node->data().HasState(ax::mojom::State::kEditable))
@@ -206,15 +173,15 @@ base::string16 GetText(const AXNode* node, bool show_password) {
if (text.empty())
text = value;
- if (node->data().role == ax::mojom::Role::kRootWebArea)
+ if (node->data().role == ax::mojom::Role::kRootWebArea ||
+ node->data().role == ax::mojom::Role::kPdfRoot) {
return text;
+ }
- if (text.empty() &&
- (HasOnlyTextChildren(node) ||
- (IsFocusable(node) && HasOnlyTextAndImageChildren(node)))) {
+ if (text.empty() && IsLeaf(node)) {
for (size_t i = 0; i < node->GetUnignoredChildCount(); ++i) {
AXNode* child = node->GetUnignoredChildAtIndex(i);
- text += GetText(child, show_password);
+ text += GetText(child);
}
}
@@ -224,6 +191,7 @@ base::string16 GetText(const AXNode* node, bool show_password) {
node->data().GetString16Attribute(ax::mojom::StringAttribute::kUrl);
text = AXUrlBaseText(url);
}
+
return text;
}
@@ -279,7 +247,6 @@ AssistantNode* AddChild(AssistantTree* tree) {
struct WalkAXTreeConfig {
bool should_select_leaf;
- const bool show_password;
};
void WalkAXTreeDepthFirst(const AXNode* node,
@@ -289,7 +256,7 @@ void WalkAXTreeDepthFirst(const AXNode* node,
WalkAXTreeConfig* config,
AssistantTree* assistant_tree,
AssistantNode* result) {
- result->text = GetText(node, config->show_password);
+ result->text = GetText(node);
result->class_name =
AXRoleToAndroidClassName(node->data().role, node->GetUnignoredParent());
result->role = AXRoleToString(node->data().role);
@@ -342,8 +309,7 @@ void WalkAXTreeDepthFirst(const AXNode* node,
}
if (config->should_select_leaf) {
- end_selection =
- static_cast<int32_t>(GetText(node, config->show_password).length());
+ end_selection = static_cast<int32_t>(GetText(node).length());
}
if (unignored_selection.focus_object_id == node->id()) {
@@ -355,6 +321,9 @@ void WalkAXTreeDepthFirst(const AXNode* node,
base::make_optional<gfx::Range>(start_selection, end_selection);
}
+ result->html_tag =
+ node->GetStringAttribute(ax::mojom::StringAttribute::kHtmlTag);
+
for (size_t i = 0; i < node->GetUnignoredChildCount(); ++i) {
AXNode* child = node->GetUnignoredChildAtIndex(i);
auto* n = AddChild(assistant_tree);
@@ -378,8 +347,7 @@ AssistantTree::AssistantTree(const AssistantTree& other) {
nodes.emplace_back(std::make_unique<AssistantNode>(*node));
}
-std::unique_ptr<AssistantTree> CreateAssistantTree(const AXTreeUpdate& update,
- bool show_password) {
+std::unique_ptr<AssistantTree> CreateAssistantTree(const AXTreeUpdate& update) {
auto tree = std::make_unique<AXSerializableTree>();
auto assistant_tree = std::make_unique<AssistantTree>();
auto* root = AddChild(assistant_tree.get());
@@ -387,7 +355,6 @@ std::unique_ptr<AssistantTree> CreateAssistantTree(const AXTreeUpdate& update,
LOG(FATAL) << tree->error();
WalkAXTreeConfig config{
false, // should_select_leaf
- show_password // show_password
};
WalkAXTreeDepthFirst(tree->root(), gfx::Rect(), update, tree.get(), &config,
assistant_tree.get(), root);
@@ -425,7 +392,6 @@ const char* AXRoleToAndroidClassName(ax::mojom::Role role, bool has_parent) {
case ax::mojom::Role::kColorWell:
case ax::mojom::Role::kComboBoxMenuButton:
case ax::mojom::Role::kDate:
- case ax::mojom::Role::kPopUpButton:
case ax::mojom::Role::kInputTime:
return kAXSpinnerClassname;
case ax::mojom::Role::kButton:
@@ -454,6 +420,7 @@ const char* AXRoleToAndroidClassName(ax::mojom::Role role, bool has_parent) {
case ax::mojom::Role::kList:
case ax::mojom::Role::kListBox:
case ax::mojom::Role::kDescriptionList:
+ case ax::mojom::Role::kDirectory:
return kAXListViewClassname;
case ax::mojom::Role::kDialog:
return kAXDialogClassname;
diff --git a/chromium/ui/accessibility/ax_assistant_structure.h b/chromium/ui/accessibility/ax_assistant_structure.h
index 7ec9a49b988..4e8358a7072 100644
--- a/chromium/ui/accessibility/ax_assistant_structure.h
+++ b/chromium/ui/accessibility/ax_assistant_structure.h
@@ -5,7 +5,10 @@
#ifndef UI_ACCESSIBILITY_AX_ASSISTANT_STRUCTURE_H_
#define UI_ACCESSIBILITY_AX_ASSISTANT_STRUCTURE_H_
-#include <cstdint>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
#include <vector>
#include "base/macros.h"
@@ -49,6 +52,9 @@ struct AssistantNode {
// a closest approximation of Android's views to keep the server happy.
std::string class_name;
+ // HTML tag name
+ std::string html_tag;
+
// Accessibility functionality of the node inferred from DOM or based on HTML
// role attribute.
base::Optional<std::string> role;
@@ -63,8 +69,7 @@ struct AssistantTree {
std::vector<std::unique_ptr<AssistantNode>> nodes;
};
-std::unique_ptr<AssistantTree> CreateAssistantTree(const AXTreeUpdate& update,
- bool show_password);
+std::unique_ptr<AssistantTree> CreateAssistantTree(const AXTreeUpdate& update);
base::string16 AXUrlBaseText(base::string16 url);
const char* AXRoleToAndroidClassName(ax::mojom::Role role, bool has_parent);
diff --git a/chromium/ui/accessibility/ax_enum_util.cc b/chromium/ui/accessibility/ax_enum_util.cc
index 4a5f05468d4..e2660e79bd6 100644
--- a/chromium/ui/accessibility/ax_enum_util.cc
+++ b/chromium/ui/accessibility/ax_enum_util.cc
@@ -414,6 +414,8 @@ const char* ToString(ax::mojom::Role role) {
return "paragraph";
case ax::mojom::Role::kPdfActionableHighlight:
return "pdfActionableHighlight";
+ case ax::mojom::Role::kPdfRoot:
+ return "pdfRoot";
case ax::mojom::Role::kPluginObject:
return "pluginObject";
case ax::mojom::Role::kPopUpButton:
@@ -462,8 +464,6 @@ const char* ToString(ax::mojom::Role role) {
return "searchBox";
case ax::mojom::Role::kSlider:
return "slider";
- case ax::mojom::Role::kSliderThumb:
- return "sliderThumb";
case ax::mojom::Role::kSpinButton:
return "spinButton";
case ax::mojom::Role::kSplitter:
@@ -512,8 +512,6 @@ const char* ToString(ax::mojom::Role role) {
return "tooltip";
case ax::mojom::Role::kVideo:
return "video";
- case ax::mojom::Role::kWebArea:
- return "webArea";
case ax::mojom::Role::kWebView:
return "webView";
case ax::mojom::Role::kWindow:
@@ -806,6 +804,8 @@ const char* ToString(ax::mojom::StringAttribute string_attribute) {
return "url";
case ax::mojom::StringAttribute::kValue:
return "value";
+ case ax::mojom::StringAttribute::kVirtualContent:
+ return "virtualContent";
}
return "";
@@ -1005,6 +1005,8 @@ const char* ToString(ax::mojom::BoolAttribute bool_attribute) {
return "isPageBreakingObject";
case ax::mojom::BoolAttribute::kHasAriaAttribute:
return "hasAriaAttribute";
+ case ax::mojom::BoolAttribute::kTouchPassthrough:
+ return "touchPassthrough";
}
return "";
@@ -1373,8 +1375,6 @@ const char* ToString(ax::mojom::AriaCurrentState aria_current_state) {
return "step";
case ax::mojom::AriaCurrentState::kLocation:
return "location";
- case ax::mojom::AriaCurrentState::kUnclippedLocation:
- return "unclippedLocation";
case ax::mojom::AriaCurrentState::kDate:
return "date";
case ax::mojom::AriaCurrentState::kTime:
diff --git a/chromium/ui/accessibility/ax_enum_util.h b/chromium/ui/accessibility/ax_enum_util.h
index aa6caa94af7..549560d6d88 100644
--- a/chromium/ui/accessibility/ax_enum_util.h
+++ b/chromium/ui/accessibility/ax_enum_util.h
@@ -8,10 +8,10 @@
#include <map>
#include <string>
+#include "base/containers/contains.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
#include "ui/accessibility/ax_base_export.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
diff --git a/chromium/ui/accessibility/ax_enums.mojom b/chromium/ui/accessibility/ax_enums.mojom
index ef0eb7f4423..cd405e5f946 100644
--- a/chromium/ui/accessibility/ax_enums.mojom
+++ b/chromium/ui/accessibility/ax_enums.mojom
@@ -252,7 +252,8 @@ enum Role {
kNote,
kPane,
kParagraph,
- kPdfActionableHighlight, // PDF specific highlight role.
+ kPdfActionableHighlight,
+ kPdfRoot,
kPluginObject,
kPopUpButton,
kPortal,
@@ -274,7 +275,6 @@ enum Role {
kSearchBox,
kSection,
kSlider,
- kSliderThumb,
kSpinButton,
kSplitter,
kStaticText,
@@ -302,7 +302,6 @@ enum Role {
kTreeItem,
kUnknown,
kVideo,
- kWebArea,
kWebView,
kWindow,
};
@@ -531,6 +530,9 @@ enum StringAttribute {
kTooltip,
kUrl,
kValue,
+ // TODO(bebeaudr): kAriaVirtualContent is currently a string attribute to
+ // facilitate prototyping. Make it an enum when we're done prototyping.
+ kVirtualContent,
};
enum IntAttribute {
@@ -764,6 +766,11 @@ enum BoolAttribute {
// True if the node has any ARIA attributes set.
kHasAriaAttribute,
+
+ // This element allows touches to be passed through when a screen reader
+ // is in touch exploration mode, e.g. a virtual keyboard normally
+ // behaves this way.
+ kTouchPassthrough,
};
enum IntListAttribute {
@@ -1009,7 +1016,6 @@ enum AriaCurrentState {
kPage,
kStep,
kLocation,
- kUnclippedLocation,
kDate,
kTime,
};
diff --git a/chromium/ui/accessibility/ax_event.cc b/chromium/ui/accessibility/ax_event.cc
index ecb80d908e4..0b346140701 100644
--- a/chromium/ui/accessibility/ax_event.cc
+++ b/chromium/ui/accessibility/ax_event.cc
@@ -14,11 +14,13 @@ AXEvent::AXEvent() = default;
AXEvent::AXEvent(AXNodeData::AXID id,
ax::mojom::Event event_type,
ax::mojom::EventFrom event_from,
+ ax::mojom::Action event_from_action,
const std::vector<AXEventIntent>& event_intents,
int action_request_id)
: id(id),
event_type(event_type),
event_from(event_from),
+ event_from_action(event_from_action),
event_intents(event_intents),
action_request_id(action_request_id) {}
@@ -35,6 +37,9 @@ std::string AXEvent::ToString() const {
result += " on node id=" + base::NumberToString(id);
if (event_from != ax::mojom::EventFrom::kNone)
result += std::string(" from ") + ui::ToString(event_from);
+ if (event_from_action != ax::mojom::Action::kNone)
+ result += std::string(" from accessibility action ") +
+ ui::ToString(event_from_action);
if (!event_intents.empty()) {
result += " caused by [ ";
for (const AXEventIntent& intent : event_intents) {
diff --git a/chromium/ui/accessibility/ax_event.h b/chromium/ui/accessibility/ax_event.h
index 86869b617ca..6eb3c1007ab 100644
--- a/chromium/ui/accessibility/ax_event.h
+++ b/chromium/ui/accessibility/ax_event.h
@@ -20,6 +20,7 @@ struct AX_BASE_EXPORT AXEvent final {
AXEvent(AXNodeData::AXID id,
ax::mojom::Event event_type,
ax::mojom::EventFrom event_from = ax::mojom::EventFrom::kNone,
+ ax::mojom::Action event_from_action = ax::mojom::Action::kNone,
const std::vector<AXEventIntent>& event_intents = {},
int action_request_id = -1);
virtual ~AXEvent();
@@ -35,6 +36,12 @@ struct AX_BASE_EXPORT AXEvent final {
// The source of the event.
ax::mojom::EventFrom event_from = ax::mojom::EventFrom::kNone;
+ // The accessibility action that caused the event. The difference between
+ // event_from_action and event_intents is that event_from_action refers to
+ // an action from an accessibility API call, while event_intents refers to
+ // user actions.
+ ax::mojom::Action event_from_action = ax::mojom::Action::kNone;
+
// Describes what caused an accessibility event to be raised. For example, in
// the case of a selection changed event, the selection could have been
// extended to the beginning of the previous word, or it could have been moved
diff --git a/chromium/ui/accessibility/ax_event_generator.cc b/chromium/ui/accessibility/ax_event_generator.cc
index 6428ce8eba8..00041032b6e 100644
--- a/chromium/ui/accessibility/ax_event_generator.cc
+++ b/chromium/ui/accessibility/ax_event_generator.cc
@@ -6,7 +6,7 @@
#include <algorithm>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_role_properties.h"
@@ -73,16 +73,16 @@ void RemoveEventsDueToIgnoredChanged(
// Add a particular AXEventGenerator::IgnoredChangedState to
// |ignored_changed_states|.
void AddIgnoredChangedState(
- AXEventGenerator::IgnoredChangedStatesBitset& ignored_changed_states,
- AXEventGenerator::IgnoredChangedState state) {
- ignored_changed_states.set(static_cast<size_t>(state));
+ const AXEventGenerator::IgnoredChangedState& state,
+ AXEventGenerator::IgnoredChangedStatesBitset* ignored_changed_states) {
+ ignored_changed_states->set(static_cast<size_t>(state));
}
// Returns true if |ignored_changed_states| contains a particular
// AXEventGenerator::IgnoredChangedState.
bool HasIgnoredChangedState(
- AXEventGenerator::IgnoredChangedStatesBitset& ignored_changed_states,
- AXEventGenerator::IgnoredChangedState state) {
+ const AXEventGenerator::IgnoredChangedStatesBitset& ignored_changed_states,
+ const AXEventGenerator::IgnoredChangedState& state) {
return ignored_changed_states[static_cast<size_t>(state)];
}
@@ -91,8 +91,12 @@ bool HasIgnoredChangedState(
AXEventGenerator::EventParams::EventParams(
const Event event,
const ax::mojom::EventFrom event_from,
+ const ax::mojom::Action event_from_action,
const std::vector<AXEventIntent>& event_intents)
- : event(event), event_from(event_from), event_intents(event_intents) {}
+ : event(event),
+ event_from(event_from),
+ event_from_action(event_from_action),
+ event_intents(event_intents) {}
AXEventGenerator::EventParams::EventParams(const EventParams& other) = default;
@@ -159,21 +163,23 @@ AXEventGenerator::AXEventGenerator() = default;
AXEventGenerator::AXEventGenerator(AXTree* tree) : tree_(tree) {
if (tree_)
- tree_event_observer_.Add(tree_);
+ tree_event_observation_.Observe(tree_);
}
AXEventGenerator::~AXEventGenerator() = default;
void AXEventGenerator::SetTree(AXTree* new_tree) {
- if (tree_)
- tree_event_observer_.Remove(tree_);
+ if (tree_) {
+ DCHECK(tree_event_observation_.IsObservingSource(tree_));
+ tree_event_observation_.Reset();
+ }
tree_ = new_tree;
if (tree_)
- tree_event_observer_.Add(tree_);
+ tree_event_observation_.Observe(tree_);
}
void AXEventGenerator::ReleaseTree() {
- tree_event_observer_.RemoveAll();
+ tree_event_observation_.Reset();
tree_ = nullptr;
}
@@ -221,7 +227,7 @@ void AXEventGenerator::AddEvent(AXNode* node, AXEventGenerator::Event event) {
std::set<EventParams>& node_events = tree_events_[node];
node_events.emplace(event, ax::mojom::EventFrom::kNone,
- tree_->event_intents());
+ ax::mojom::Action::kNone, tree_->event_intents());
}
void AXEventGenerator::OnNodeDataChanged(AXTree* tree,
@@ -423,6 +429,9 @@ void AXEventGenerator::OnIntAttributeChanged(AXTree* tree,
AddEvent(node, Event::CHECKED_STATE_CHANGED);
AddEvent(node, Event::WIN_IACCESSIBLE_STATE_CHANGED);
break;
+ case ax::mojom::IntAttribute::kAriaCurrentState:
+ AddEvent(node, Event::ARIA_CURRENT_CHANGED);
+ break;
case ax::mojom::IntAttribute::kDropeffect:
AddEvent(node, Event::DROPEFFECT_CHANGED);
break;
@@ -596,8 +605,8 @@ void AXEventGenerator::OnIntListAttributeChanged(
AddEvent(node, Event::FLOW_TO_CHANGED);
// Fire FLOW_FROM_CHANGED for all nodes added or removed
- for (int32_t id : ComputeIntListDifference(old_value, new_value)) {
- if (auto* target_node = tree->GetFromId(id))
+ for (AXNodeID id : ComputeIntListDifference(old_value, new_value)) {
+ if (AXNode* target_node = tree->GetFromId(id))
AddEvent(target_node, Event::FLOW_FROM_CHANGED);
}
break;
@@ -783,7 +792,7 @@ void AXEventGenerator::FireValueInTextFieldChangedEvent(AXTree* tree,
void AXEventGenerator::FireRelationSourceEvents(AXTree* tree,
AXNode* target_node) {
- int32_t target_id = target_node->id();
+ AXNodeID target_id = target_node->id();
std::set<AXNode*> source_nodes;
auto callback = [&](const auto& entry) {
const auto& target_to_sources = entry.second;
@@ -792,7 +801,7 @@ void AXEventGenerator::FireRelationSourceEvents(AXTree* tree,
return;
auto sources = sources_it->second;
- std::for_each(sources.begin(), sources.end(), [&](int32_t source_id) {
+ std::for_each(sources.begin(), sources.end(), [&](AXNodeID source_id) {
AXNode* source_node = tree->GetFromId(source_id);
if (!source_node || source_nodes.count(source_node) > 0)
@@ -870,13 +879,13 @@ void AXEventGenerator::TrimEventsDueToAncestorIgnoredChanged(
// Propagate ancestor's show/hide states to |node|'s entry in the map.
if (HasIgnoredChangedState(parent_map_iter->second,
IgnoredChangedState::kHide)) {
- AddIgnoredChangedState(ancestor_ignored_changed_states,
- IgnoredChangedState::kHide);
+ AddIgnoredChangedState(IgnoredChangedState::kHide,
+ &ancestor_ignored_changed_states);
}
if (HasIgnoredChangedState(parent_map_iter->second,
IgnoredChangedState::kShow)) {
- AddIgnoredChangedState(ancestor_ignored_changed_states,
- IgnoredChangedState::kShow);
+ AddIgnoredChangedState(IgnoredChangedState::kShow,
+ &ancestor_ignored_changed_states);
}
// If |node| has IGNORED changed with show/hide state that matches one of
@@ -895,11 +904,11 @@ void AXEventGenerator::TrimEventsDueToAncestorIgnoredChanged(
}
if (node->IsIgnored()) {
- AddIgnoredChangedState(ancestor_ignored_changed_states,
- IgnoredChangedState::kHide);
+ AddIgnoredChangedState(IgnoredChangedState::kHide,
+ &ancestor_ignored_changed_states);
} else {
- AddIgnoredChangedState(ancestor_ignored_changed_states,
- IgnoredChangedState::kShow);
+ AddIgnoredChangedState(IgnoredChangedState::kShow,
+ &ancestor_ignored_changed_states);
}
}
@@ -912,11 +921,11 @@ void AXEventGenerator::TrimEventsDueToAncestorIgnoredChanged(
if (curr_events_iter != tree_events_.end() &&
HasEvent(curr_events_iter->second, Event::IGNORED_CHANGED)) {
if (node->IsIgnored()) {
- AddIgnoredChangedState(ancestor_ignored_changed_states,
- IgnoredChangedState::kHide);
+ AddIgnoredChangedState(IgnoredChangedState::kHide,
+ &ancestor_ignored_changed_states);
} else {
- AddIgnoredChangedState(ancestor_ignored_changed_states,
- IgnoredChangedState::kShow);
+ AddIgnoredChangedState(IgnoredChangedState::kShow,
+ &ancestor_ignored_changed_states);
}
return;
@@ -1070,6 +1079,8 @@ const char* ToString(AXEventGenerator::Event event) {
return "activeDescendantChanged";
case AXEventGenerator::Event::ALERT:
return "alert";
+ case AXEventGenerator::Event::ARIA_CURRENT_CHANGED:
+ return "ariaCurrentChanged";
case AXEventGenerator::Event::ATK_TEXT_OBJECT_ATTRIBUTE_CHANGED:
return "atkTextObjectAttributeChanged";
case AXEventGenerator::Event::ATOMIC_CHANGED:
diff --git a/chromium/ui/accessibility/ax_event_generator.h b/chromium/ui/accessibility/ax_event_generator.h
index 1d58988a789..d98b5e39e64 100644
--- a/chromium/ui/accessibility/ax_event_generator.h
+++ b/chromium/ui/accessibility/ax_event_generator.h
@@ -9,9 +9,10 @@
#include <map>
#include <ostream>
#include <set>
+#include <string>
#include <vector>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/accessibility/ax_event_intent.h"
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_tree.h"
@@ -29,6 +30,7 @@ class AX_EXPORT AXEventGenerator : public AXTreeObserver {
ACCESS_KEY_CHANGED,
ACTIVE_DESCENDANT_CHANGED,
ALERT,
+ ARIA_CURRENT_CHANGED,
// ATK treats alignment, indentation, and other format-related attributes as
// text attributes even when they are only applicable to the entire object.
// And it lacks an event for use when object attributes have changed.
@@ -117,6 +119,7 @@ class AX_EXPORT AXEventGenerator : public AXTreeObserver {
struct AX_EXPORT EventParams {
EventParams(Event event,
ax::mojom::EventFrom event_from,
+ ax::mojom::Action event_from_action,
const std::vector<AXEventIntent>& event_intents);
EventParams(const EventParams& other);
~EventParams();
@@ -126,6 +129,7 @@ class AX_EXPORT AXEventGenerator : public AXTreeObserver {
Event event;
ax::mojom::EventFrom event_from;
+ ax::mojom::Action event_from_action;
std::vector<AXEventIntent> event_intents;
};
@@ -314,7 +318,7 @@ class AX_EXPORT AXEventGenerator : public AXTreeObserver {
// Please make sure that this ScopedObserver is always declared last in order
// to prevent any use-after-free.
- ScopedObserver<AXTree, AXTreeObserver> tree_event_observer_{this};
+ base::ScopedObservation<AXTree, AXTreeObserver> tree_event_observation_{this};
};
AX_EXPORT std::ostream& operator<<(std::ostream& os,
diff --git a/chromium/ui/accessibility/ax_event_generator_unittest.cc b/chromium/ui/accessibility/ax_event_generator_unittest.cc
index 491578eaffe..e612489e4b7 100644
--- a/chromium/ui/accessibility/ax_event_generator_unittest.cc
+++ b/chromium/ui/accessibility/ax_event_generator_unittest.cc
@@ -104,11 +104,14 @@ TEST(AXEventGeneratorTest, IterateThroughEmptyEventSets) {
// Node3 contains IGNORED_CHANGED, SUBTREE_CREATED, NAME_CHANGED.
std::set<AXEventGenerator::EventParams> node3_events;
node3_events.emplace(AXEventGenerator::Event::IGNORED_CHANGED,
- ax::mojom::EventFrom::kNone, tree.event_intents());
+ ax::mojom::EventFrom::kNone, ax::mojom::Action::kNone,
+ tree.event_intents());
node3_events.emplace(AXEventGenerator::Event::SUBTREE_CREATED,
- ax::mojom::EventFrom::kNone, tree.event_intents());
+ ax::mojom::EventFrom::kNone, ax::mojom::Action::kNone,
+ tree.event_intents());
node3_events.emplace(AXEventGenerator::Event::NAME_CHANGED,
- ax::mojom::EventFrom::kNone, tree.event_intents());
+ ax::mojom::EventFrom::kNone, ax::mojom::Action::kNone,
+ tree.event_intents());
// Node4 contains no event.
std::set<AXEventGenerator::EventParams> node4_events;
// Node5 contains no event.
@@ -118,7 +121,8 @@ TEST(AXEventGeneratorTest, IterateThroughEmptyEventSets) {
// Node7 contains IGNORED_CHANGED.
std::set<AXEventGenerator::EventParams> node7_events;
node7_events.emplace(AXEventGenerator::Event::IGNORED_CHANGED,
- ax::mojom::EventFrom::kNone, tree.event_intents());
+ ax::mojom::EventFrom::kNone, ax::mojom::Action::kNone,
+ tree.event_intents());
// Node8 contains no event.
std::set<AXEventGenerator::EventParams> node8_events;
// Node9 contains no event.
diff --git a/chromium/ui/accessibility/ax_generated_tree_unittest.cc b/chromium/ui/accessibility/ax_generated_tree_unittest.cc
index 3c180fa061d..d099a095df5 100644
--- a/chromium/ui/accessibility/ax_generated_tree_unittest.cc
+++ b/chromium/ui/accessibility/ax_generated_tree_unittest.cc
@@ -52,10 +52,9 @@ std::string TreeToString(const AXTree& tree) {
}
AXTreeUpdate SerializeEntireTree(AXSerializableTree& tree) {
- std::unique_ptr<AXTreeSource<const AXNode*, AXNodeData, AXTreeData>>
- tree_source(tree.CreateTreeSource());
- AXTreeSerializer<const AXNode*, AXNodeData, AXTreeData> serializer(
- tree_source.get());
+ std::unique_ptr<AXTreeSource<const AXNode*>> tree_source(
+ tree.CreateTreeSource());
+ AXTreeSerializer<const AXNode*> serializer(tree_source.get());
AXTreeUpdate update;
CHECK(serializer.SerializeChanges(tree.root(), &update));
return update;
@@ -247,22 +246,24 @@ TEST(AXGeneratedTreeTest, SerializeGeneratedTrees) {
// Start by serializing tree0 and unserializing it into a new
// empty tree |dst_tree|.
- std::unique_ptr<AXTreeSource<const AXNode*, AXNodeData, AXTreeData>>
- tree0_source(tree0.CreateTreeSource());
- AXTreeSerializer<const AXNode*, AXNodeData, AXTreeData> serializer(
- tree0_source.get());
+ std::unique_ptr<AXTreeSource<const AXNode*>> tree0_source(
+ tree0.CreateTreeSource());
+ AXTreeSerializer<const AXNode*> serializer(tree0_source.get());
AXTreeUpdate update0;
ASSERT_TRUE(serializer.SerializeChanges(tree0.root(), &update0));
AXTree dst_tree;
- ASSERT_TRUE(dst_tree.Unserialize(update0));
+ ASSERT_TRUE(dst_tree.Unserialize(update0))
+ << dst_tree.error() << "\n"
+ << TreeToString(dst_tree)
+ << "\nTree update: " << update0.ToString();
// At this point, |dst_tree| should now be identical to |tree0|.
EXPECT_EQ(TreeToString(tree0), TreeToString(dst_tree));
// Next, pretend that tree0 turned into tree1.
- std::unique_ptr<AXTreeSource<const AXNode*, AXNodeData, AXTreeData>>
- tree1_source(tree1.CreateTreeSource());
+ std::unique_ptr<AXTreeSource<const AXNode*>> tree1_source(
+ tree1.CreateTreeSource());
serializer.ChangeTreeSourceForTesting(tree1_source.get());
// Invalidate a subtree rooted at one of the nodes.
@@ -275,7 +276,12 @@ TEST(AXGeneratedTreeTest, SerializeGeneratedTrees) {
AXTreeUpdate update;
ASSERT_TRUE(
serializer.SerializeChanges(tree1.GetFromId(id), &update));
- ASSERT_TRUE(dst_tree.Unserialize(update));
+ std::string tree_before_str = TreeToString(dst_tree);
+ ASSERT_TRUE(dst_tree.Unserialize(update))
+ << dst_tree.error() << "\nTree before : " << tree_before_str
+ << "\nTree after : " << TreeToString(dst_tree)
+ << "\nExpected after: " << TreeToString(tree1)
+ << "\nTree update : " << update.ToString();
}
// After the sequence of updates, |dst_tree| should now be
@@ -327,11 +333,17 @@ TEST(AXGeneratedTreeTest, GeneratedTreesWithIgnoredNodes) {
AXEventGenerator event_generator(&fat_tree);
AXTreeUpdate update =
MakeTreeUpdateFromIgnoredChanges(fat_tree, fat_tree1);
- ASSERT_TRUE(fat_tree.Unserialize(update));
+ std::string fat_tree_before_str = TreeToString(fat_tree);
+ ASSERT_TRUE(fat_tree.Unserialize(update))
+ << fat_tree.error() << "\nTree before : " << fat_tree_before_str
+ << "\nTree after :" << TreeToString(fat_tree)
+ << "\nExpected after: " << TreeToString(fat_tree1)
+ << "\nTree update : " << update.ToString();
+
EXPECT_EQ(TreeToString(fat_tree), TreeToString(fat_tree1));
// Capture the events generated.
- std::map<AXNode::AXID, std::set<AXEventGenerator::Event>> actual_events;
+ std::map<AXNodeID, std::set<AXEventGenerator::Event>> actual_events;
for (const AXEventGenerator::TargetedEvent& event : event_generator) {
if (event.node->IsIgnored() ||
event.event_params.event ==
@@ -346,17 +358,23 @@ TEST(AXGeneratedTreeTest, GeneratedTreesWithIgnoredNodes) {
// the generated events.
AXEventGenerator skinny_event_generator(&skinny_tree);
AXTreeUpdate skinny_update = SerializeEntireTree(skinny_tree1);
- ASSERT_TRUE(skinny_tree.Unserialize(skinny_update));
+ std::string skinny_tree_before_str = TreeToString(skinny_tree);
+ ASSERT_TRUE(skinny_tree.Unserialize(skinny_update))
+ << skinny_tree.error()
+ << "\nTree before : " << skinny_tree_before_str
+ << "\nTree after :" << TreeToString(skinny_tree)
+ << "\nExpected after: " << TreeToString(skinny_tree1)
+ << "\nTree update : " << skinny_update.ToString();
+
EXPECT_EQ(TreeToString(skinny_tree), TreeToString(skinny_tree1));
- std::map<AXNode::AXID, std::set<AXEventGenerator::Event>>
- expected_events;
+ std::map<AXNodeID, std::set<AXEventGenerator::Event>> expected_events;
for (const AXEventGenerator::TargetedEvent& event :
skinny_event_generator)
expected_events[event.node->id()].insert(event.event_params.event);
for (auto& entry : expected_events) {
- AXNode::AXID node_id = entry.first;
+ AXNodeID node_id = entry.first;
for (auto& event_type : entry.second) {
EXPECT_TRUE(actual_events[node_id].find(event_type) !=
actual_events[node_id].end())
@@ -365,7 +383,7 @@ TEST(AXGeneratedTreeTest, GeneratedTreesWithIgnoredNodes) {
}
for (auto& entry : actual_events) {
- AXNode::AXID node_id = entry.first;
+ AXNodeID node_id = entry.first;
for (auto& event_type : entry.second) {
EXPECT_TRUE(expected_events[node_id].find(event_type) !=
expected_events[node_id].end())
@@ -379,7 +397,7 @@ TEST(AXGeneratedTreeTest, GeneratedTreesWithIgnoredNodes) {
// correctly.
AXTreeUpdate skinny_tree_serialized = SerializeEntireTree(skinny_tree);
for (size_t i = 0; i < skinny_tree_serialized.nodes.size(); i++) {
- AXNode::AXID id = skinny_tree_serialized.nodes[i].id;
+ AXNodeID id = skinny_tree_serialized.nodes[i].id;
AXNode* skinny_tree_node = skinny_tree.GetFromId(id);
AXNode* fat_tree_node = fat_tree.GetFromId(id);
diff --git a/chromium/ui/accessibility/ax_language_detection.h b/chromium/ui/accessibility/ax_language_detection.h
index 035530a86f9..7a6e4062cdb 100644
--- a/chromium/ui/accessibility/ax_language_detection.h
+++ b/chromium/ui/accessibility/ax_language_detection.h
@@ -220,7 +220,7 @@ class AX_EXPORT AXLanguageInfoStats {
class AX_EXPORT AXLanguageDetectionObserver : public ui::AXTreeObserver {
public:
// Observer constructor will register itself with the provided AXTree.
- AXLanguageDetectionObserver(AXTree* tree);
+ explicit AXLanguageDetectionObserver(AXTree* tree);
// Observer destructor will remove itself as an observer from the AXTree.
~AXLanguageDetectionObserver() override;
diff --git a/chromium/ui/accessibility/ax_mode.h b/chromium/ui/accessibility/ax_mode.h
index e3586665723..afa151ee47d 100644
--- a/chromium/ui/accessibility/ax_mode.h
+++ b/chromium/ui/accessibility/ax_mode.h
@@ -71,7 +71,7 @@ class AX_BASE_EXPORT AXMode {
constexpr AXMode() : flags_(0) {}
constexpr AXMode(uint32_t flags) : flags_(flags) {}
- bool has_mode(uint32_t flag) const { return (flags_ & flag) > 0; }
+ bool has_mode(uint32_t flag) const { return (flags_ & flag) == flag; }
void set_mode(uint32_t flag, bool value) {
flags_ = value ? (flags_ | flag) : (flags_ & ~flag);
@@ -96,11 +96,20 @@ class AX_BASE_EXPORT AXMode {
uint32_t flags_;
};
+// Used when an AT that only require basic accessibility information, such as
+// a dictation tool, is present.
+static constexpr AXMode kAXModeBasic(AXMode::kNativeAPIs |
+ AXMode::kWebContents);
+
+// Used when complete accessibility access is desired but a third-party AT is
+// not present.
static constexpr AXMode kAXModeWebContentsOnly(AXMode::kWebContents |
AXMode::kInlineTextBoxes |
AXMode::kScreenReader |
AXMode::kHTML);
+// Used when an AT that requires full accessibility access, such as a screen
+// reader, is present.
static constexpr AXMode kAXModeComplete(AXMode::kNativeAPIs |
AXMode::kWebContents |
AXMode::kInlineTextBoxes |
diff --git a/chromium/ui/accessibility/ax_node.cc b/chromium/ui/accessibility/ax_node.cc
index 6fddfb98d71..49c9dc1515d 100644
--- a/chromium/ui/accessibility/ax_node.cc
+++ b/chromium/ui/accessibility/ax_node.cc
@@ -4,30 +4,33 @@
#include "ui/accessibility/ax_node.h"
+#include <string.h>
+
#include <algorithm>
#include <utility>
-#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
-#include "third_party/skia/include/core/SkColor.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_language_detection.h"
#include "ui/accessibility/ax_role_properties.h"
#include "ui/accessibility/ax_table_info.h"
#include "ui/accessibility/ax_tree.h"
+#include "ui/gfx/color_utils.h"
#include "ui/gfx/transform.h"
namespace ui {
-constexpr AXNode::AXID AXNode::kInvalidAXID;
+// Definition of static class members.
+constexpr base::char16 AXNode::kEmbeddedCharacter[];
+constexpr int AXNode::kEmbeddedCharacterLength;
AXNode::AXNode(AXNode::OwnerTree* tree,
AXNode* parent,
- int32_t id,
+ AXNodeID id,
size_t index_in_parent,
size_t unignored_index_in_parent)
: tree_(tree),
@@ -89,6 +92,7 @@ AXNode* AXNode::GetLastUnignoredChild() const {
}
AXNode* AXNode::GetDeepestFirstUnignoredChild() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
if (!GetUnignoredChildCount())
return nullptr;
@@ -101,6 +105,7 @@ AXNode* AXNode::GetDeepestFirstUnignoredChild() const {
}
AXNode* AXNode::GetDeepestLastUnignoredChild() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
if (!GetUnignoredChildCount())
return nullptr;
@@ -287,6 +292,7 @@ AXNode* AXNode::GetPreviousUnignoredSibling() const {
}
AXNode* AXNode::GetNextUnignoredInTreeOrder() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
if (GetUnignoredChildCount())
return GetFirstUnignoredChild();
@@ -303,6 +309,7 @@ AXNode* AXNode::GetNextUnignoredInTreeOrder() const {
}
AXNode* AXNode::GetPreviousUnignoredInTreeOrder() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
AXNode* sibling = GetPreviousUnignoredSibling();
if (!sibling)
return GetUnignoredParent();
@@ -379,7 +386,7 @@ void AXNode::SetData(const AXNodeData& src) {
data_ = src;
}
-void AXNode::SetLocation(int32_t offset_container_id,
+void AXNode::SetLocation(AXNodeID offset_container_id,
const gfx::RectF& location,
gfx::Transform* transform) {
data_.relative_bounds.offset_container_id = offset_container_id;
@@ -410,6 +417,9 @@ void AXNode::Destroy() {
}
bool AXNode::IsDescendantOf(const AXNode* ancestor) const {
+ if (!ancestor)
+ return false;
+
if (this == ancestor)
return true;
if (parent())
@@ -419,6 +429,7 @@ bool AXNode::IsDescendantOf(const AXNode* ancestor) const {
}
std::vector<int> AXNode::GetOrComputeLineStartOffsets() {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
std::vector<int> line_offsets;
if (data().GetIntListAttribute(ax::mojom::IntListAttribute::kCachedLineStarts,
&line_offsets)) {
@@ -434,6 +445,7 @@ std::vector<int> AXNode::GetOrComputeLineStartOffsets() {
void AXNode::ComputeLineStartOffsets(std::vector<int>* line_offsets,
int* start_offset) const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
DCHECK(line_offsets);
DCHECK(start_offset);
for (const AXNode* child : children()) {
@@ -458,6 +470,29 @@ void AXNode::ComputeLineStartOffsets(std::vector<int>* line_offsets,
}
}
+SkColor AXNode::ComputeColor() const {
+ return ComputeColorAttribute(ax::mojom::IntAttribute::kColor);
+}
+
+SkColor AXNode::ComputeBackgroundColor() const {
+ return ComputeColorAttribute(ax::mojom::IntAttribute::kBackgroundColor);
+}
+
+SkColor AXNode::ComputeColorAttribute(ax::mojom::IntAttribute attr) const {
+ SkColor color = GetIntAttribute(attr);
+ AXNode* ancestor = parent();
+
+ // If the color has some transparency, keep blending with background
+ // colors until we get an opaque color or reach the root.
+ while (ancestor && SkColorGetA(color) != SK_AlphaOPAQUE) {
+ SkColor background_color = ancestor->GetIntAttribute(attr);
+ color = color_utils::GetResultingPaintColor(color, background_color);
+ ancestor = ancestor->parent();
+ }
+
+ return color;
+}
+
const std::string& AXNode::GetInheritedStringAttribute(
ax::mojom::StringAttribute attribute) const {
const AXNode* current_node = this;
@@ -486,21 +521,43 @@ void AXNode::ClearLanguageInfo() {
language_info_.reset();
}
-std::string AXNode::GetHypertext() const {
- if (IsLeaf())
- return GetInnerText();
+base::string16 AXNode::GetHypertext() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
+
+ // Hypertext is not exposed for descendants of leaf nodes. For such nodes,
+ // their inner text is equivalent to their hypertext. Otherwise, we would
+ // never be able to compute equivalent ancestor positions in text fields given
+ // an AXPosition on an inline text box descendant, because there is often an
+ // ignored generic container between the text descendants and the text field
+ // node.
+ //
+ // For example, look at the following accessibility tree and the text
+ // positions indicated using "<>" symbols in the inner text of every node, and
+ // then imagine what would happen if the generic container was represented by
+ // an "embedded object replacement character" in the text of its text field
+ // parent.
+ // ++kTextField "Hell<o>" IsLeaf=true
+ // ++++kGenericContainer "Hell<o>" ignored IsChildOfLeaf=true
+ // ++++++kStaticText "Hell<o>" IsChildOfLeaf=true
+ // ++++++++kInlineTextBox "Hell<o>" IsChildOfLeaf=true
+ if (IsLeaf() || IsChildOfLeaf())
+ return base::UTF8ToUTF16(GetInnerText());
// Construct the hypertext for this node, which contains the concatenation of
- // the inner text of this node's textual children, and an embedded object
- // character for all the other children.
- const std::string embedded_character_str("\xEF\xBF\xBC");
- std::string hypertext;
+ // the inner text of this node's textual children, and an "object replacement
+ // character" for all the other children.
+ //
+ // Note that the word "hypertext" comes from the IAccessible2 Standard and has
+ // nothing to do with HTML.
+ const base::string16 embedded_character_str(kEmbeddedCharacter);
+ DCHECK_EQ(int{embedded_character_str.length()}, kEmbeddedCharacterLength);
+ base::string16 hypertext;
for (auto it = UnignoredChildrenBegin(); it != UnignoredChildrenEnd(); ++it) {
// Similar to Firefox, we don't expose text nodes in IAccessible2 and ATK
// hypertext with the embedded object character. We copy all of their text
// instead.
if (it->IsText()) {
- hypertext += it->GetInnerText();
+ hypertext += base::UTF8ToUTF16(it->GetInnerText());
} else {
hypertext += embedded_character_str;
}
@@ -509,6 +566,8 @@ std::string AXNode::GetHypertext() const {
}
std::string AXNode::GetInnerText() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
+
// If a text field has no descendants, then we compute its inner text from its
// value or its placeholder. Otherwise we prefer to look at its descendant
// text nodes because Blink doesn't always add all trailing white space to the
@@ -568,7 +627,29 @@ std::string AXNode::GetInnerText() const {
return inner_text;
}
+int AXNode::GetInnerTextLength() const {
+ // This is an optimized version of `AXNode::GetInnerText()`.length(). Instead
+ // of concatenating the strings in GetInnerText() to then get their length, we
+ // sum the lengths of the individual strings. This is faster than
+ // concatenating the strings first and then taking their length, especially
+ // when the process is recursive.
+
+ const bool is_plain_text_field_with_descendants =
+ (data().IsTextField() && GetUnignoredChildCount());
+ // Plain text fields are always leaves so we need to exclude them when
+ // computing the length of their inner text if that text should be derived
+ // from their descendant nodes.
+ if (IsLeaf() && !is_plain_text_field_with_descendants)
+ return int{GetInnerText().length()};
+
+ int inner_text_length = 0;
+ for (auto it = UnignoredChildrenBegin(); it != UnignoredChildrenEnd(); ++it)
+ inner_text_length += it->GetInnerTextLength();
+ return inner_text_length;
+}
+
std::string AXNode::GetLanguage() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
// Walk up tree considering both detected and author declared languages.
for (const AXNode* cur = this; cur; cur = cur->parent()) {
// If language detection has assigned a language then we prefer that.
@@ -588,6 +669,7 @@ std::string AXNode::GetLanguage() const {
}
std::string AXNode::GetValueForControl() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
if (data().IsTextField())
return GetValueForTextField();
if (data().IsRangeValueSupported())
@@ -608,6 +690,7 @@ bool AXNode::IsTable() const {
}
base::Optional<int> AXNode::GetTableColCount() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return base::nullopt;
@@ -615,6 +698,7 @@ base::Optional<int> AXNode::GetTableColCount() const {
}
base::Optional<int> AXNode::GetTableRowCount() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return base::nullopt;
@@ -622,6 +706,7 @@ base::Optional<int> AXNode::GetTableRowCount() const {
}
base::Optional<int> AXNode::GetTableAriaColCount() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return base::nullopt;
@@ -629,6 +714,7 @@ base::Optional<int> AXNode::GetTableAriaColCount() const {
}
base::Optional<int> AXNode::GetTableAriaRowCount() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return base::nullopt;
@@ -636,6 +722,7 @@ base::Optional<int> AXNode::GetTableAriaRowCount() const {
}
base::Optional<int> AXNode::GetTableCellCount() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return base::nullopt;
@@ -644,6 +731,7 @@ base::Optional<int> AXNode::GetTableCellCount() const {
}
base::Optional<bool> AXNode::GetTableHasColumnOrRowHeaderNode() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return base::nullopt;
@@ -652,6 +740,7 @@ base::Optional<bool> AXNode::GetTableHasColumnOrRowHeaderNode() const {
}
AXNode* AXNode::GetTableCellFromIndex(int index) const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return nullptr;
@@ -665,6 +754,7 @@ AXNode* AXNode::GetTableCellFromIndex(int index) const {
}
AXNode* AXNode::GetTableCaption() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return nullptr;
@@ -673,6 +763,7 @@ AXNode* AXNode::GetTableCaption() const {
}
AXNode* AXNode::GetTableCellFromCoords(int row_index, int col_index) const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return nullptr;
@@ -687,15 +778,15 @@ AXNode* AXNode::GetTableCellFromCoords(int row_index, int col_index) const {
table_info->cell_ids[size_t{row_index}][size_t{col_index}]);
}
-std::vector<AXNode::AXID> AXNode::GetTableColHeaderNodeIds() const {
+std::vector<AXNodeID> AXNode::GetTableColHeaderNodeIds() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
- return std::vector<AXNode::AXID>();
+ return std::vector<AXNodeID>();
- std::vector<AXNode::AXID> col_header_ids;
+ std::vector<AXNodeID> col_header_ids;
// Flatten and add column header ids of each column to |col_header_ids|.
- for (std::vector<AXNode::AXID> col_headers_at_index :
- table_info->col_headers) {
+ for (std::vector<AXNodeID> col_headers_at_index : table_info->col_headers) {
col_header_ids.insert(col_header_ids.end(), col_headers_at_index.begin(),
col_headers_at_index.end());
}
@@ -703,39 +794,41 @@ std::vector<AXNode::AXID> AXNode::GetTableColHeaderNodeIds() const {
return col_header_ids;
}
-std::vector<AXNode::AXID> AXNode::GetTableColHeaderNodeIds(
- int col_index) const {
+std::vector<AXNodeID> AXNode::GetTableColHeaderNodeIds(int col_index) const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
- return std::vector<AXNode::AXID>();
+ return std::vector<AXNodeID>();
if (col_index < 0 || size_t{col_index} >= table_info->col_count)
- return std::vector<AXNode::AXID>();
+ return std::vector<AXNodeID>();
- return std::vector<AXNode::AXID>(table_info->col_headers[size_t{col_index}]);
+ return std::vector<AXNodeID>(table_info->col_headers[size_t{col_index}]);
}
-std::vector<AXNode::AXID> AXNode::GetTableRowHeaderNodeIds(
- int row_index) const {
+std::vector<AXNodeID> AXNode::GetTableRowHeaderNodeIds(int row_index) const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
- return std::vector<AXNode::AXID>();
+ return std::vector<AXNodeID>();
if (row_index < 0 || size_t{row_index} >= table_info->row_count)
- return std::vector<AXNode::AXID>();
+ return std::vector<AXNodeID>();
- return std::vector<AXNode::AXID>(table_info->row_headers[size_t{row_index}]);
+ return std::vector<AXNodeID>(table_info->row_headers[size_t{row_index}]);
}
-std::vector<AXNode::AXID> AXNode::GetTableUniqueCellIds() const {
+std::vector<AXNodeID> AXNode::GetTableUniqueCellIds() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
- return std::vector<AXNode::AXID>();
+ return std::vector<AXNodeID>();
- return std::vector<AXNode::AXID>(table_info->unique_cell_ids);
+ return std::vector<AXNodeID>(table_info->unique_cell_ids);
}
const std::vector<AXNode*>* AXNode::GetExtraMacNodes() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
// Should only be available on the table node itself, not any of its children.
const AXTableInfo* table_info = tree_->GetTableInfo(this);
if (!table_info)
@@ -766,8 +859,8 @@ base::Optional<int> AXNode::GetTableRowRowIndex() const {
return int{iter->second};
}
-std::vector<AXNode::AXID> AXNode::GetTableRowNodeIds() const {
- std::vector<AXNode::AXID> row_node_ids;
+std::vector<AXNodeID> AXNode::GetTableRowNodeIds() const {
+ std::vector<AXNodeID> row_node_ids;
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return row_node_ids;
@@ -903,39 +996,39 @@ base::Optional<int> AXNode::GetTableCellAriaRowIndex() const {
return int{table_info->cell_data_vector[*index].aria_row_index};
}
-std::vector<AXNode::AXID> AXNode::GetTableCellColHeaderNodeIds() const {
+std::vector<AXNodeID> AXNode::GetTableCellColHeaderNodeIds() const {
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info || table_info->col_count <= 0)
- return std::vector<AXNode::AXID>();
+ return std::vector<AXNodeID>();
// If this node is not a cell, then return the headers for the first column.
int col_index = GetTableCellColIndex().value_or(0);
- return std::vector<AXNode::AXID>(table_info->col_headers[col_index]);
+ return std::vector<AXNodeID>(table_info->col_headers[col_index]);
}
void AXNode::GetTableCellColHeaders(std::vector<AXNode*>* col_headers) const {
DCHECK(col_headers);
- std::vector<int32_t> col_header_ids = GetTableCellColHeaderNodeIds();
+ std::vector<AXNodeID> col_header_ids = GetTableCellColHeaderNodeIds();
IdVectorToNodeVector(col_header_ids, col_headers);
}
-std::vector<AXNode::AXID> AXNode::GetTableCellRowHeaderNodeIds() const {
+std::vector<AXNodeID> AXNode::GetTableCellRowHeaderNodeIds() const {
const AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info || table_info->row_count <= 0)
- return std::vector<AXNode::AXID>();
+ return std::vector<AXNodeID>();
// If this node is not a cell, then return the headers for the first row.
int row_index = GetTableCellRowIndex().value_or(0);
- return std::vector<AXNode::AXID>(table_info->row_headers[row_index]);
+ return std::vector<AXNodeID>(table_info->row_headers[row_index]);
}
void AXNode::GetTableCellRowHeaders(std::vector<AXNode*>* row_headers) const {
DCHECK(row_headers);
- std::vector<int32_t> row_header_ids = GetTableCellRowHeaderNodeIds();
+ std::vector<AXNodeID> row_header_ids = GetTableCellRowHeaderNodeIds();
IdVectorToNodeVector(row_header_ids, row_headers);
}
@@ -975,9 +1068,9 @@ AXTableInfo* AXNode::GetAncestorTableInfo() const {
return nullptr;
}
-void AXNode::IdVectorToNodeVector(const std::vector<int32_t>& ids,
+void AXNode::IdVectorToNodeVector(const std::vector<AXNodeID>& ids,
std::vector<AXNode*>* nodes) const {
- for (int32_t id : ids) {
+ for (AXNodeID id : ids) {
AXNode* node = tree_->GetFromId(id);
if (node)
nodes->push_back(node);
@@ -1173,19 +1266,68 @@ bool AXNode::IsIgnored() const {
return data().IsIgnored();
}
+bool AXNode::IsIgnoredForTextNavigation() const {
+ if (data().role == ax::mojom::Role::kSplitter)
+ return true;
+
+ // A generic container without any unignored children that is not editable
+ // should not be used for text-based navigation. Such nodes don't make sense
+ // for screen readers to land on, since no text will be announced and no
+ // action is possible.
+ if (data().role == ax::mojom::Role::kGenericContainer &&
+ !GetUnignoredChildCount() &&
+ !data().HasState(ax::mojom::State::kEditable)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool AXNode::IsInvisibleOrIgnored() const {
+ if (!data().IsInvisibleOrIgnored())
+ return false;
+
+ return !IsFocusedWithinThisTree();
+}
+
+bool AXNode::IsFocusedWithinThisTree() const {
+ return id() == tree_->data().focus_id;
+}
+
bool AXNode::IsChildOfLeaf() const {
- const AXNode* ancestor = GetUnignoredParent();
- while (ancestor) {
+ for (const AXNode* ancestor = GetUnignoredParent(); ancestor;
+ ancestor = ancestor->GetUnignoredParent()) {
if (ancestor->IsLeaf())
return true;
- ancestor = ancestor->GetUnignoredParent();
}
return false;
}
+bool AXNode::IsEmptyLeaf() const {
+ if (!IsLeaf())
+ return false;
+ if (GetUnignoredChildCount())
+ return !GetInnerTextLength();
+ // Text exposed by ignored leaf (text) nodes is not exposed to the platforms'
+ // accessibility layer, hence such leaf nodes are in effect empty.
+ return IsIgnored() || !GetInnerTextLength();
+}
+
bool AXNode::IsLeaf() const {
- // A node is also a leaf if all of it's descendants are ignored.
- if (children().empty() || !GetUnignoredChildCount())
+ // A node is a leaf if it has no descendants, i.e. if it is at the bottom of
+ // the tree, regardless whether it is ignored or not.
+ if (children().empty())
+ return true;
+
+ // Ignored nodes with any kind of descendants, (ignored or unignored), cannot
+ // be leaves because: A) If some of their descendants are unignored then those
+ // descendants need to be exposed to the platform layer, and B) If all of
+ // their descendants are ignored they are still not at the bottom of the tree.
+ if (IsIgnored())
+ return false;
+
+ // An unignored node is a leaf if all of its descendants are ignored.
+ if (!GetUnignoredChildCount())
return true;
#if defined(OS_WIN)
@@ -1202,6 +1344,10 @@ bool AXNode::IsLeaf() const {
// implementation details, but we want to expose them as leaves to platform
// accessibility APIs because screen readers might be confused if they find
// any children.
+ // TODO(kschmi): <input type="search" contenteditable="true"> will cause
+ // different return values here, even though 'contenteditable' has no effect.
+ // This needs to be modified from the Blink side, so 'kRichlyEditable' isn't
+ // added in this case.
if (data().IsPlainTextField() || IsText())
return true;
@@ -1238,13 +1384,12 @@ bool AXNode::IsInListMarker() const {
if (data().role == ax::mojom::Role::kListMarker)
return true;
- // List marker node's children can only be text elements.
+ // The children of a list marker node can only be text nodes.
if (!IsText())
return false;
- // There is no need to iterate over all the ancestors of the current anchor
- // since a list marker node only has children on 2 levels.
- // i.e.:
+ // There is no need to iterate over all the ancestors of the current node
+ // since a list marker has descendants that are only 2 levels deep, i.e.:
// AXLayoutObject role=kListMarker
// ++StaticText
// ++++InlineTextBox
@@ -1297,15 +1442,41 @@ bool AXNode::IsEmbeddedGroup() const {
return ui::IsSetLike(parent()->data().role);
}
+AXNode* AXNode::GetLowestPlatformAncestor() const {
+ AXNode* current_node = const_cast<AXNode*>(this);
+ AXNode* lowest_unignored_node = current_node;
+ for (; lowest_unignored_node && lowest_unignored_node->IsIgnored();
+ lowest_unignored_node = lowest_unignored_node->parent()) {
+ }
+
+ // `highest_leaf_node` could be nullptr.
+ AXNode* highest_leaf_node = lowest_unignored_node;
+ // For the purposes of this method, a leaf node does not include leaves in the
+ // internal accessibility tree, only in the platform exposed tree.
+ for (AXNode* ancestor_node = lowest_unignored_node; ancestor_node;
+ ancestor_node = ancestor_node->GetUnignoredParent()) {
+ if (ancestor_node->IsLeaf())
+ highest_leaf_node = ancestor_node;
+ }
+ if (highest_leaf_node)
+ return highest_leaf_node;
+
+ if (lowest_unignored_node)
+ return lowest_unignored_node;
+ return current_node;
+}
+
AXNode* AXNode::GetTextFieldAncestor() const {
// The descendants of a text field usually have State::kEditable, however in
// the case of Role::kSearchBox or Role::kSpinButton being the text field
// ancestor, its immediate descendant can have Role::kGenericContainer without
- // State::kEditable.
+ // State::kEditable. Same with inline text boxes.
+ // TODO(nektar): Fix all such inconsistencies in Blink.
for (AXNode* ancestor = const_cast<AXNode*>(this);
ancestor &&
(ancestor->data().HasState(ax::mojom::State::kEditable) ||
- ancestor->data().role == ax::mojom::Role::kGenericContainer);
+ ancestor->data().role == ax::mojom::Role::kGenericContainer ||
+ ancestor->data().role == ax::mojom::Role::kInlineTextBox);
ancestor = ancestor->GetUnignoredParent()) {
if (ancestor->data().IsTextField())
return ancestor;
@@ -1314,8 +1485,8 @@ AXNode* AXNode::GetTextFieldAncestor() const {
}
bool AXNode::IsDescendantOfPlainTextField() const {
- AXNode* textfield_node = GetTextFieldAncestor();
- return textfield_node && textfield_node->data().IsPlainTextField();
+ AXNode* text_field_node = GetTextFieldAncestor();
+ return text_field_node && text_field_node->data().IsPlainTextField();
}
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_node.h b/chromium/ui/accessibility/ax_node.h
index 7c531de5f5a..913c35898ce 100644
--- a/chromium/ui/accessibility/ax_node.h
+++ b/chromium/ui/accessibility/ax_node.h
@@ -13,7 +13,9 @@
#include <vector>
#include "base/optional.h"
+#include "base/strings/string16.h"
#include "build/build_config.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree_id.h"
@@ -22,16 +24,28 @@ namespace ui {
class AXTableInfo;
struct AXLanguageInfo;
+struct AXTreeData;
// One node in an AXTree.
class AX_EXPORT AXNode final {
public:
- // Defines the type used for AXNode IDs.
- using AXID = int32_t;
-
- // If a node is not yet or no longer valid, its ID should have a value of
- // kInvalidAXID.
- static constexpr AXID kInvalidAXID = 0;
+ // Replacement character used to represent an embedded (or, additionally for
+ // text navigation, an empty) object. Encoded in UTF16 format. Part of the
+ // Unicode Standard.
+ //
+ // On some platforms, most objects are represented in the text of their
+ // parents with a special "embedded object character" and not with their
+ // actual text contents. Also on the same platforms, if a node has only
+ // ignored descendants, i.e., it appears to be empty to assistive software, we
+ // need to treat it as a character and a word boundary.
+ //
+ // Note that we cannot use L"..." because it works correctly only on Windows.
+ // TODO(nektar): Consider using UTF8 encoding instead, "\xEF\xBF\xBC".
+ static constexpr base::char16 kEmbeddedCharacter[] = {0xFFFC, 0x0000};
+ // We compute the embedded character's length instead of manually typing it in
+ // order to avoid the two variables getting out of sync in a future update.
+ static constexpr int kEmbeddedCharacterLength =
+ int{sizeof(kEmbeddedCharacter) / sizeof(base::char16) - 1};
// Interface to the tree class that owns an AXNode. We use this instead
// of letting AXNode have a pointer to its AXTree directly so that we're
@@ -41,10 +55,10 @@ class AX_EXPORT AXNode final {
public:
struct Selection {
bool is_backward;
- AXID anchor_object_id;
+ AXNodeID anchor_object_id;
int anchor_offset;
ax::mojom::TextAffinity anchor_affinity;
- AXID focus_object_id;
+ AXNodeID focus_object_id;
int focus_offset;
ax::mojom::TextAffinity focus_affinity;
};
@@ -54,7 +68,9 @@ class AX_EXPORT AXNode final {
// See AXTree::GetTableInfo.
virtual AXTableInfo* GetTableInfo(const AXNode* table_node) const = 0;
// See AXTree::GetFromId.
- virtual AXNode* GetFromId(int32_t id) const = 0;
+ virtual AXNode* GetFromId(AXNodeID id) const = 0;
+ // See AXTree::data.
+ virtual const AXTreeData& data() const = 0;
virtual base::Optional<int> GetPosInSet(const AXNode& node) = 0;
virtual base::Optional<int> GetSetSize(const AXNode& node) = 0;
@@ -93,14 +109,14 @@ class AX_EXPORT AXNode final {
// guaranteed to never change.
AXNode(OwnerTree* tree,
AXNode* parent,
- int32_t id,
+ AXNodeID id,
size_t index_in_parent,
size_t unignored_index_in_parent = 0);
virtual ~AXNode();
// Accessors.
OwnerTree* tree() const { return tree_; }
- AXID id() const { return data_.id; }
+ AXNodeID id() const { return data_.id; }
AXNode* parent() const { return parent_; }
const AXNodeData& data() const { return data_; }
const std::vector<AXNode*>& children() const { return children_; }
@@ -160,7 +176,7 @@ class AX_EXPORT AXNode final {
// The node's location is stored as a relative bounding box, the ID of
// the element it's relative to, and an optional transformation matrix.
// See ax_node_data.h for details.
- void SetLocation(int32_t offset_container_id,
+ void SetLocation(AXNodeID offset_container_id,
const gfx::RectF& location,
gfx::Transform* transform);
@@ -181,13 +197,20 @@ class AX_EXPORT AXNode final {
// reference count and clear out the object's data.
void Destroy();
- // Return true if this object is equal to or a descendant of |ancestor|.
+ // Returns true if this node is equal to or a descendant of |ancestor|.
bool IsDescendantOf(const AXNode* ancestor) const;
// Gets the text offsets where new lines start either from the node's data or
// by computing them and caching the result.
std::vector<int> GetOrComputeLineStartOffsets();
+ // If the color is transparent, blends with the ancestor's color.
+ // Note that this is imperfect; it won't work if a node is absolute-
+ // positioned outside of its ancestor. However, it handles the most
+ // common cases.
+ SkColor ComputeColor() const;
+ SkColor ComputeBackgroundColor() const;
+
// Accessing accessibility attributes.
// See |AXNodeData| for more information.
@@ -305,16 +328,29 @@ class AX_EXPORT AXNode final {
//
// This is how displayed text and embedded objects are represented in
// ATK and IAccessible2 APIs.
- std::string GetHypertext() const;
+ //
+ // TODO(nektar): Consider changing the return value to std::string.
+ base::string16 GetHypertext() const;
- // Returns the text of this node and all descendant nodes; including text
- // found in embedded objects.
+ // Returns the text that is found inside this node and all its descendants;
+ // including text found in embedded objects.
//
// Only text displayed on screen is included. Text from ARIA and HTML
// attributes that is either not displayed on screen, or outside this node, is
// not returned.
std::string GetInnerText() const;
+ // Returns the length of the text (in UTF16 code units) that is found inside
+ // this node and all its descendants; including text found in embedded
+ // objects.
+ //
+ // Only text displayed on screen is counted. Text from ARIA and HTML
+ // attributes that is either not displayed on screen, or outside this node, is
+ // not included.
+ //
+ // The length of the text is in UTF8 code units, not in grapheme clusters.
+ int GetInnerTextLength() const;
+
// Returns a string representing the language code.
//
// This will consider the language declared in the DOM, and may eventually
@@ -325,11 +361,14 @@ class AX_EXPORT AXNode final {
// Returns empty string if no appropriate language was found.
std::string GetLanguage() const;
- // Returns the value of a control such as a text field, a slider, a <select>
- // element, a date picker or an ARIA combo box. In order to minimize
- // cross-process communication between the renderer and the browser, this
- // method may compute the value from the control's inner text in the case of a
- // text field.
+ // Returns the value of a control such as a plain text field, a content
+ // editable, a submit button, a slider, a progress bar, a scroll bar, a meter,
+ // a spinner, a <select> element, a date picker or an ARIA combo box. In order
+ // to minimize cross-process communication between the renderer and the
+ // browser, this method may compute the value from the control's inner text in
+ // the case of a content editable. For range controls, such as sliders and
+ // scroll bars, the value of aria-valuetext takes priority over the value of
+ // aria-valuenow.
std::string GetValueForControl() const;
//
@@ -362,12 +401,12 @@ class AX_EXPORT AXNode final {
AXNode* GetTableCellFromIndex(int index) const;
AXNode* GetTableCellFromCoords(int row_index, int col_index) const;
// Get all the column header node ids of the table.
- std::vector<AXNode::AXID> GetTableColHeaderNodeIds() const;
+ std::vector<AXNodeID> GetTableColHeaderNodeIds() const;
// Get the column header node ids associated with |col_index|.
- std::vector<AXNode::AXID> GetTableColHeaderNodeIds(int col_index) const;
+ std::vector<AXNodeID> GetTableColHeaderNodeIds(int col_index) const;
// Get the row header node ids associated with |row_index|.
- std::vector<AXNode::AXID> GetTableRowHeaderNodeIds(int row_index) const;
- std::vector<AXNode::AXID> GetTableUniqueCellIds() const;
+ std::vector<AXNodeID> GetTableRowHeaderNodeIds(int row_index) const;
+ std::vector<AXNodeID> GetTableUniqueCellIds() const;
// Extra computed nodes for the accessibility tree for macOS:
// one column node for each table column, followed by one
// table header container node, or nullptr if not applicable.
@@ -377,7 +416,7 @@ class AX_EXPORT AXNode final {
bool IsTableRow() const;
base::Optional<int> GetTableRowRowIndex() const;
// Get the node ids that represent rows in a table.
- std::vector<AXNode::AXID> GetTableRowNodeIds() const;
+ std::vector<AXNodeID> GetTableRowNodeIds() const;
#if defined(OS_APPLE)
// Table column-like nodes. These nodes are only present on macOS.
@@ -394,8 +433,8 @@ class AX_EXPORT AXNode final {
base::Optional<int> GetTableCellRowSpan() const;
base::Optional<int> GetTableCellAriaColIndex() const;
base::Optional<int> GetTableCellAriaRowIndex() const;
- std::vector<AXNode::AXID> GetTableCellColHeaderNodeIds() const;
- std::vector<AXNode::AXID> GetTableCellRowHeaderNodeIds() const;
+ std::vector<AXNodeID> GetTableCellColHeaderNodeIds() const;
+ std::vector<AXNodeID> GetTableCellRowHeaderNodeIds() const;
void GetTableCellColHeaders(std::vector<AXNode*>* col_headers) const;
void GetTableCellRowHeaders(std::vector<AXNode*>* row_headers) const;
@@ -425,13 +464,38 @@ class AX_EXPORT AXNode final {
// Returns true if node has ignored state or ignored role.
bool IsIgnored() const;
+ // Some nodes are not ignored but should be skipped during text navigation.
+ // For example, on some platforms screen readers should not stop when
+ // encountering a splitter during character and word navigation.
+ bool IsIgnoredForTextNavigation() const;
+
+ // Returns true if node is invisible or ignored.
+ bool IsInvisibleOrIgnored() const;
+
+ // Returns true if node is focused within this tree.
+ bool IsFocusedWithinThisTree() const;
+
// Returns true if an ancestor of this node (not including itself) is a
// leaf node, meaning that this node is not actually exposed to any
// platform's accessibility layer.
bool IsChildOfLeaf() const;
+ // Returns true if this is a leaf node that has no inner text. Note that all
+ // descendants of a leaf node are not exposed to any platform's accessibility
+ // layer, but they may be used to compute the node's inner text. Note also
+ // that, ignored nodes (leaf or otherwise) do not expose their inner text or
+ // hypertext to the platforms' accessibility layer, but they expose the inner
+ // text or hypertext of their unignored descendants.
+ //
+ // For example, empty text fields might have a set of unignored nested divs
+ // inside them:
+ // ++kTextField
+ // ++++kGenericContainer
+ // ++++++kGenericContainer
+ bool IsEmptyLeaf() const;
+
// Returns true if this is a leaf node, meaning all its
- // children should not be exposed to any platform's native accessibility
+ // descendants should not be exposed to any platform's accessibility
// layer.
//
// The definition of a leaf includes nodes with children that are exclusively
@@ -457,12 +521,19 @@ class AX_EXPORT AXNode final {
// collapsed.
AXNode* GetCollapsedMenuListPopUpButtonAncestor() const;
+ // If this node is exposed to the platform's accessibility layer, returns this
+ // node. Otherwise, returns the lowest ancestor that is exposed to the
+ // platform. (See `IsLeaf()` and `IsIgnored()` for information on what is
+ // exposed to platform APIs.)
+ AXNode* GetLowestPlatformAncestor() const;
+
// If this node is within an editable region, returns the node that is at the
// root of that editable region, otherwise returns nullptr. In accessibility,
// an editable region is synonymous to a text field.
AXNode* GetTextFieldAncestor() const;
- // Returns true if the ancestor of the current node is a plain text field.
+ // Returns true if this node is either a plain text field , or one of its
+ // ancestors is.
bool IsDescendantOfPlainTextField() const;
// Finds and returns a pointer to ordered set containing node.
@@ -474,7 +545,7 @@ class AX_EXPORT AXNode final {
void ComputeLineStartOffsets(std::vector<int>* line_offsets,
int* start_offset) const;
AXTableInfo* GetAncestorTableInfo() const;
- void IdVectorToNodeVector(const std::vector<int32_t>& ids,
+ void IdVectorToNodeVector(const std::vector<AXNodeID>& ids,
std::vector<AXNode*>* nodes) const;
int UpdateUnignoredCachedValuesRecursive(int startIndex);
@@ -495,6 +566,10 @@ class AX_EXPORT AXNode final {
// processes.
std::string GetValueForTextField() const;
+ // Compute the actual value of a color attribute that needs to be
+ // blended with ancestor colors.
+ SkColor ComputeColorAttribute(ax::mojom::IntAttribute color_attr) const;
+
OwnerTree* const tree_; // Owns this.
size_t index_in_parent_;
size_t unignored_index_in_parent_;
diff --git a/chromium/ui/accessibility/ax_node_data.cc b/chromium/ui/accessibility/ax_node_data.cc
index e35efcdc9bb..7d20441ec0b 100644
--- a/chromium/ui/accessibility/ax_node_data.cc
+++ b/chromium/ui/accessibility/ax_node_data.cc
@@ -209,8 +209,7 @@ bool IsNodeIdIntListAttribute(ax::mojom::IntListAttribute attr) {
return false;
}
-AXNodeData::AXNodeData()
- : role(ax::mojom::Role::kUnknown), state(0U), actions(0ULL) {}
+AXNodeData::AXNodeData() : role(ax::mojom::Role::kUnknown) {}
AXNodeData::~AXNodeData() = default;
@@ -1004,11 +1003,27 @@ bool AXNodeData::IsPlainTextField() const {
// We need to check both the role and editable state, because some ARIA text
// fields may in fact not be editable, whilst some editable fields might not
// have the role.
- return !HasState(ax::mojom::State::kRichlyEditable) &&
- (role == ax::mojom::Role::kTextField ||
- role == ax::mojom::Role::kTextFieldWithComboBox ||
- role == ax::mojom::Role::kSearchBox ||
- GetBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot));
+ if (HasState(ax::mojom::State::kRichlyEditable))
+ return false;
+
+ // Blink adds the "kEditableRoot" attribute to all nodes that are at the root
+ // of any editable region, such as an <input> or a <textarea> field.
+ if (GetBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot)) {
+ DCHECK(HasState(ax::mojom::State::kEditable));
+ return true;
+ }
+
+ // Has editable ARIA role, but is not actually editable.
+ // In theory, a webpage author could create a plain text field by using any of
+ // the following ARIA roles, even on elements that do not have the
+ // contenteditable attribute set. For example, <div role="textbox">. However,
+ // in practice it might be difficult to create such a plain text field because
+ // it would be hard to support text selection and a caret without specifying
+ // contenteditable="true"
+ // Exposing these roles as plain text fields is harmless and simplifies tests.
+ return role == ax::mojom::Role::kTextField ||
+ role == ax::mojom::Role::kTextFieldWithComboBox ||
+ role == ax::mojom::Role::kSearchBox;
}
bool AXNodeData::IsRichTextField() const {
@@ -1513,6 +1528,9 @@ std::string AXNodeData::ToString() const {
case ax::mojom::StringAttribute::kValue:
result += " value=" + value;
break;
+ case ax::mojom::StringAttribute::kVirtualContent:
+ result += " virtual_content=" + value;
+ break;
case ax::mojom::StringAttribute::kNone:
break;
}
@@ -1609,6 +1627,9 @@ std::string AXNodeData::ToString() const {
case ax::mojom::BoolAttribute::kHasAriaAttribute:
result += " has_aria_attribute=" + value;
break;
+ case ax::mojom::BoolAttribute::kTouchPassthrough:
+ result += " touch_passthrough=" + value;
+ break;
case ax::mojom::BoolAttribute::kNone:
break;
}
diff --git a/chromium/ui/accessibility/ax_node_data.h b/chromium/ui/accessibility/ax_node_data.h
index f2a979d3316..d5b466a7d20 100644
--- a/chromium/ui/accessibility/ax_node_data.h
+++ b/chromium/ui/accessibility/ax_node_data.h
@@ -23,6 +23,13 @@
namespace ui {
+// Defines the type used for AXNode IDs.
+using AXNodeID = int32_t;
+
+// If a node is not yet or no longer valid, its ID should have a value of
+// kInvalidAXNodeID.
+static constexpr AXNodeID kInvalidAXNodeID = 0;
+
// Return true if |attr| should be interpreted as the id of another node
// in the same tree.
AX_BASE_EXPORT bool IsNodeIdIntAttribute(ax::mojom::IntAttribute attr);
@@ -36,11 +43,11 @@ AX_BASE_EXPORT bool IsNodeIdIntListAttribute(ax::mojom::IntListAttribute attr);
// one process to another.
struct AX_BASE_EXPORT AXNodeData {
// Defines the type used for AXNode IDs.
- using AXID = int32_t;
+ using AXID = AXNodeID;
// If a node is not yet or no longer valid, its ID should have a value of
// kInvalidAXID.
- static constexpr AXID kInvalidAXID = 0;
+ static constexpr AXID kInvalidAXID = kInvalidAXNodeID;
AXNodeData();
virtual ~AXNodeData();
@@ -261,7 +268,7 @@ struct AX_BASE_EXPORT AXNodeData {
bool IsReadOnlyOrDisabled() const;
// Helper to determine if the data belongs to a node that supports
- // range-based value.
+ // range-based values.
bool IsRangeValueSupported() const;
// Helper to determine if the data belongs to a node that supports
@@ -278,10 +285,10 @@ struct AX_BASE_EXPORT AXNodeData {
// As much as possible this should behave as a simple, serializable,
// copyable struct.
- int32_t id = -1;
+ AXNodeID id = kInvalidAXNodeID;
ax::mojom::Role role;
- uint32_t state;
- uint64_t actions;
+ uint32_t state = 0U;
+ uint64_t actions = 0ULL;
std::vector<std::pair<ax::mojom::StringAttribute, std::string>>
string_attributes;
std::vector<std::pair<ax::mojom::IntAttribute, int32_t>> int_attributes;
diff --git a/chromium/ui/accessibility/ax_node_data_unittest.cc b/chromium/ui/accessibility/ax_node_data_unittest.cc
index 90a96afb586..ef07d76edb5 100644
--- a/chromium/ui/accessibility/ax_node_data_unittest.cc
+++ b/chromium/ui/accessibility/ax_node_data_unittest.cc
@@ -6,7 +6,7 @@
#include <set>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_enum_util.h"
#include "ui/accessibility/ax_enums.mojom.h"
diff --git a/chromium/ui/accessibility/ax_node_position.cc b/chromium/ui/accessibility/ax_node_position.cc
index 798bc670cb9..71a3c950d40 100644
--- a/chromium/ui/accessibility/ax_node_position.cc
+++ b/chromium/ui/accessibility/ax_node_position.cc
@@ -4,22 +4,23 @@
#include "ui/accessibility/ax_node_position.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/accessibility/ax_tree_manager.h"
-#include "ui/accessibility/ax_tree_manager_map.h"
+#include "ui/base/buildflags.h"
namespace ui {
+// On some platforms, most objects are represented in the text of their parents
+// with a special "embedded object character" and not with their actual text
+// contents. Also on the same platforms, if a node has only ignored descendants,
+// i.e., it appears to be empty to assistive software, we need to treat it as a
+// character and a word boundary.
AXEmbeddedObjectBehavior g_ax_embedded_object_behavior =
-#if defined(OS_WIN)
+#if defined(OS_WIN) || BUILDFLAG(USE_ATK)
AXEmbeddedObjectBehavior::kExposeCharacter;
#else
AXEmbeddedObjectBehavior::kSuppressCharacter;
-#endif // defined(OS_WIN)
+#endif // defined(OS_WIN) || BUILDFLAG(USE_ATK)
// static
AXNodePosition::AXPositionInstance AXNodePosition::CreatePosition(
@@ -30,7 +31,7 @@ AXNodePosition::AXPositionInstance AXNodePosition::CreatePosition(
return CreateNullPosition();
AXTreeID tree_id = node.tree()->GetAXTreeID();
- if (node.IsText()) {
+ if (node.IsLeaf()) {
return CreateTextPosition(tree_id, node.id(), child_index_or_text_offset,
affinity);
}
@@ -49,345 +50,4 @@ AXNodePosition::AXPositionInstance AXNodePosition::Clone() const {
return AXPositionInstance(new AXNodePosition(*this));
}
-void AXNodePosition::AnchorChild(int child_index,
- AXTreeID* tree_id,
- AXNode::AXID* child_id) const {
- DCHECK(tree_id);
- DCHECK(child_id);
-
- if (!GetAnchor() || child_index < 0 || child_index >= AnchorChildCount()) {
- *tree_id = AXTreeIDUnknown();
- *child_id = AXNode::kInvalidAXID;
- return;
- }
-
- AXNode* child = nullptr;
- const AXTreeManager* child_tree_manager =
- AXTreeManagerMap::GetInstance().GetManagerForChildTree(*GetAnchor());
- if (child_tree_manager) {
- // The child node exists in a separate tree from its parent.
- child = child_tree_manager->GetRootAsAXNode();
- *tree_id = child_tree_manager->GetTreeID();
- } else {
- child = GetAnchor()->children()[size_t{child_index}];
- *tree_id = this->tree_id();
- }
-
- DCHECK(child);
- *child_id = child->id();
-}
-
-int AXNodePosition::AnchorChildCount() const {
- if (!GetAnchor())
- return 0;
-
- const AXTreeManager* child_tree_manager =
- AXTreeManagerMap::GetInstance().GetManagerForChildTree(*GetAnchor());
- if (child_tree_manager)
- return 1;
-
- return int{GetAnchor()->children().size()};
-}
-
-int AXNodePosition::AnchorUnignoredChildCount() const {
- if (!GetAnchor())
- return 0;
-
- return static_cast<int>(GetAnchor()->GetUnignoredChildCount());
-}
-
-int AXNodePosition::AnchorIndexInParent() const {
- return GetAnchor() ? int{GetAnchor()->index_in_parent()} : INVALID_INDEX;
-}
-
-int AXNodePosition::AnchorSiblingCount() const {
- AXNode* parent = GetAnchor()->GetUnignoredParent();
- if (parent)
- return static_cast<int>(parent->GetUnignoredChildCount());
-
- return 0;
-}
-
-base::stack<AXNode*> AXNodePosition::GetAncestorAnchors() const {
- base::stack<AXNode*> anchors;
- AXNode* current_anchor = GetAnchor();
-
- AXNode::AXID current_anchor_id = GetAnchor()->id();
- AXTreeID current_tree_id = tree_id();
-
- AXNode::AXID parent_anchor_id = AXNode::kInvalidAXID;
- AXTreeID parent_tree_id = AXTreeIDUnknown();
-
- while (current_anchor) {
- anchors.push(current_anchor);
- current_anchor = GetParent(
- current_anchor /*child*/, current_tree_id /*child_tree_id*/,
- &parent_tree_id /*parent_tree_id*/, &parent_anchor_id /*parent_id*/);
-
- current_anchor_id = parent_anchor_id;
- current_tree_id = parent_tree_id;
- }
- return anchors;
-}
-
-AXNode* AXNodePosition::GetLowestUnignoredAncestor() const {
- if (!GetAnchor())
- return nullptr;
-
- return GetAnchor()->GetUnignoredParent();
-}
-
-void AXNodePosition::AnchorParent(AXTreeID* tree_id,
- AXNode::AXID* parent_id) const {
- DCHECK(tree_id);
- DCHECK(parent_id);
-
- *tree_id = AXTreeIDUnknown();
- *parent_id = AXNode::kInvalidAXID;
-
- if (!GetAnchor())
- return;
-
- AXNode* parent =
- GetParent(GetAnchor() /*child*/, this->tree_id() /*child_tree_id*/,
- tree_id /*parent_tree_id*/, parent_id /*parent_id*/);
-
- if (!parent) {
- *tree_id = AXTreeIDUnknown();
- *parent_id = AXNode::kInvalidAXID;
- }
-}
-
-AXNode* AXNodePosition::GetNodeInTree(AXTreeID tree_id,
- AXNode::AXID node_id) const {
- if (node_id == AXNode::kInvalidAXID)
- return nullptr;
-
- AXTreeManager* manager = AXTreeManagerMap::GetInstance().GetManager(tree_id);
- if (manager)
- return manager->GetNodeFromTree(tree_id, node_id);
-
- return nullptr;
-}
-
-AXNode::AXID AXNodePosition::GetAnchorID(AXNode* node) const {
- return node->id();
-}
-
-AXTreeID AXNodePosition::GetTreeID(AXNode* node) const {
- return node->tree()->GetAXTreeID();
-}
-
-base::string16 AXNodePosition::GetText() const {
- if (IsNullPosition())
- return base::string16();
-
- // Special case, if a node has only ignored descendants, i.e., it appears to
- // be empty to assistive software, on some platforms we need to still treat it
- // as a character and a word boundary. We achieve this by adding an embedded
- // object character in the text representation used by this class, but we
- // don't expose that character to assistive software that tries to retrieve
- // the node's inner text.
- if (IsEmptyObjectReplacedByCharacter())
- return base::string16(1, kEmbeddedCharacter);
-
- const AXNode* anchor = GetAnchor();
- DCHECK(anchor);
- switch (g_ax_embedded_object_behavior) {
- case AXEmbeddedObjectBehavior::kSuppressCharacter:
- return base::UTF8ToUTF16(anchor->GetInnerText());
- case AXEmbeddedObjectBehavior::kExposeCharacter:
- return base::UTF8ToUTF16(anchor->GetHypertext());
- }
-}
-
-bool AXNodePosition::IsInLineBreak() const {
- if (IsNullPosition())
- return false;
- DCHECK(GetAnchor());
- return GetAnchor()->IsLineBreak();
-}
-
-bool AXNodePosition::IsInTextObject() const {
- if (IsNullPosition())
- return false;
- DCHECK(GetAnchor());
- return GetAnchor()->IsText();
-}
-
-bool AXNodePosition::IsInWhiteSpace() const {
- if (IsNullPosition())
- return false;
- DCHECK(GetAnchor());
- return GetAnchor()->IsLineBreak() ||
- base::ContainsOnlyChars(GetText(), base::kWhitespaceUTF16);
-}
-
-// This override is an optimized version AXPosition::MaxTextOffset. Instead of
-// concatenating the strings in GetText() to then get their text length, we sum
-// the lengths of the individual strings. This is faster than concatenating the
-// strings first and then taking their length, especially when the process
-// is recursive.
-int AXNodePosition::MaxTextOffset() const {
- if (IsNullPosition())
- return INVALID_OFFSET;
-
- if (IsEmptyObjectReplacedByCharacter())
- return 1;
-
- const AXNode* anchor = GetAnchor();
- DCHECK(anchor);
- // TODO(nektar): Replace with PlatformChildCount when AXNodePosition and
- // BrowserAccessibilityPosition will be merged.
- if (!AnchorChildCount() || anchor->IsText())
- return base::UTF8ToUTF16(anchor->GetInnerText()).length();
-
- int text_length = 0;
- // This is an optimization over retrieving the text of the whole subtree and
- // then finding its length. It saves time by adding lengths instead of
- // concatenating strings.
- for (int i = 0; i < AnchorChildCount(); ++i)
- text_length += CreateChildPositionAt(i)->MaxTextOffset();
-
- return text_length;
-}
-
-bool AXNodePosition::IsEmbeddedObjectInParent() const {
- switch (g_ax_embedded_object_behavior) {
- case AXEmbeddedObjectBehavior::kSuppressCharacter:
- return false;
- case AXEmbeddedObjectBehavior::kExposeCharacter:
- // We don't need to expose an "embedded object character" for textual
- // nodes and nodes that are invisible to platform APIs. Textual nodes are
- // represented by their actual text.
- return !IsNullPosition() && !GetAnchor()->IsText() &&
- !GetAnchor()->IsDescendantOfPlainTextField() &&
- GetAnchor()->IsChildOfLeaf();
- }
-}
-
-bool AXNodePosition::IsInLineBreakingObject() const {
- if (IsNullPosition())
- return false;
- DCHECK(GetAnchor());
- return GetAnchor()->data().GetBoolAttribute(
- ax::mojom::BoolAttribute::kIsLineBreakingObject) &&
- !GetAnchor()->IsInListMarker();
-}
-
-ax::mojom::Role AXNodePosition::GetAnchorRole() const {
- if (IsNullPosition())
- return ax::mojom::Role::kNone;
- DCHECK(GetAnchor());
- return GetRole(GetAnchor());
-}
-
-ax::mojom::Role AXNodePosition::GetRole(AXNode* node) const {
- return node->data().role;
-}
-
-AXNodeTextStyles AXNodePosition::GetTextStyles() const {
- // Check either the current anchor or its parent for text styles.
- AXNodeTextStyles current_anchor_text_styles =
- !IsNullPosition() ? GetAnchor()->data().GetTextStyles()
- : AXNodeTextStyles();
- if (current_anchor_text_styles.IsUnset()) {
- AXPositionInstance parent = CreateParentPosition();
- if (!parent->IsNullPosition())
- return parent->GetAnchor()->data().GetTextStyles();
- }
- return current_anchor_text_styles;
-}
-
-std::vector<int32_t> AXNodePosition::GetWordStartOffsets() const {
- if (IsNullPosition())
- return std::vector<int32_t>();
- DCHECK(GetAnchor());
-
- // Embedded object replacement characters are not represented in |kWordStarts|
- // attribute.
- if (IsEmptyObjectReplacedByCharacter())
- return {0};
-
- return GetAnchor()->data().GetIntListAttribute(
- ax::mojom::IntListAttribute::kWordStarts);
-}
-
-std::vector<int32_t> AXNodePosition::GetWordEndOffsets() const {
- if (IsNullPosition())
- return std::vector<int32_t>();
- DCHECK(GetAnchor());
-
- // Embedded object replacement characters are not represented in |kWordEnds|
- // attribute. Since the whole text exposed inside of an embedded object is of
- // length 1 (the embedded object replacement character), the word end offset
- // is positioned at 1. Because we want to treat the embedded object
- // replacement characters as ordinary characters, it wouldn't be consistent to
- // assume they have no length and return 0 instead of 1.
- if (IsEmptyObjectReplacedByCharacter())
- return {1};
-
- return GetAnchor()->data().GetIntListAttribute(
- ax::mojom::IntListAttribute::kWordEnds);
-}
-
-AXNode::AXID AXNodePosition::GetNextOnLineID(AXNode::AXID node_id) const {
- if (IsNullPosition())
- return AXNode::kInvalidAXID;
- AXNode* node = GetNodeInTree(tree_id(), node_id);
- int next_on_line_id;
- if (!node || !node->data().GetIntAttribute(
- ax::mojom::IntAttribute::kNextOnLineId, &next_on_line_id)) {
- return AXNode::kInvalidAXID;
- }
- return static_cast<AXNode::AXID>(next_on_line_id);
-}
-
-AXNode::AXID AXNodePosition::GetPreviousOnLineID(AXNode::AXID node_id) const {
- if (IsNullPosition())
- return AXNode::kInvalidAXID;
- AXNode* node = GetNodeInTree(tree_id(), node_id);
- int previous_on_line_id;
- if (!node ||
- !node->data().GetIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
- &previous_on_line_id)) {
- return AXNode::kInvalidAXID;
- }
- return static_cast<AXNode::AXID>(previous_on_line_id);
-}
-
-AXNode* AXNodePosition::GetParent(AXNode* child,
- AXTreeID child_tree_id,
- AXTreeID* parent_tree_id,
- AXNode::AXID* parent_id) {
- DCHECK(parent_tree_id);
- DCHECK(parent_id);
-
- *parent_tree_id = AXTreeIDUnknown();
- *parent_id = AXNode::kInvalidAXID;
-
- if (!child)
- return nullptr;
-
- AXNode* parent = child->parent();
- *parent_tree_id = child_tree_id;
-
- if (!parent) {
- AXTreeManager* manager =
- AXTreeManagerMap::GetInstance().GetManager(child_tree_id);
- if (manager) {
- parent = manager->GetParentNodeFromParentTreeAsAXNode();
- *parent_tree_id = manager->GetParentTreeID();
- }
- }
-
- if (!parent) {
- *parent_tree_id = AXTreeIDUnknown();
- return parent;
- }
-
- *parent_id = parent->id();
- return parent;
-}
-
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_node_position.h b/chromium/ui/accessibility/ax_node_position.h
index e7d03f6c302..cd2b0b0746e 100644
--- a/chromium/ui/accessibility/ax_node_position.h
+++ b/chromium/ui/accessibility/ax_node_position.h
@@ -5,17 +5,10 @@
#ifndef UI_ACCESSIBILITY_AX_NODE_POSITION_H_
#define UI_ACCESSIBILITY_AX_NODE_POSITION_H_
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/containers/stack.h"
-#include "base/strings/string16.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_position.h"
-#include "ui/accessibility/ax_tree_id.h"
namespace ui {
@@ -35,46 +28,6 @@ class AX_EXPORT AXNodePosition : public AXPosition<AXNodePosition, AXNode> {
AXNodePosition(const AXNodePosition& other);
AXPositionInstance Clone() const override;
-
- base::string16 GetText() const override;
- bool IsInLineBreak() const override;
- bool IsInTextObject() const override;
- bool IsInWhiteSpace() const override;
- int MaxTextOffset() const override;
-
- protected:
- void AnchorChild(int child_index,
- AXTreeID* tree_id,
- AXNode::AXID* child_id) const override;
- int AnchorChildCount() const override;
- int AnchorUnignoredChildCount() const override;
- int AnchorIndexInParent() const override;
- int AnchorSiblingCount() const override;
- base::stack<AXNode*> GetAncestorAnchors() const override;
- AXNode* GetLowestUnignoredAncestor() const override;
- void AnchorParent(AXTreeID* tree_id, AXNode::AXID* parent_id) const override;
- AXNode* GetNodeInTree(AXTreeID tree_id, AXNode::AXID node_id) const override;
- AXNode::AXID GetAnchorID(AXNode* node) const override;
- AXTreeID GetTreeID(AXNode* node) const override;
-
- bool IsEmbeddedObjectInParent() const override;
- bool IsInLineBreakingObject() const override;
- ax::mojom::Role GetAnchorRole() const override;
- ax::mojom::Role GetRole(AXNode* node) const override;
- AXNodeTextStyles GetTextStyles() const override;
- std::vector<int32_t> GetWordStartOffsets() const override;
- std::vector<int32_t> GetWordEndOffsets() const override;
- AXNode::AXID GetNextOnLineID(AXNode::AXID node_id) const override;
- AXNode::AXID GetPreviousOnLineID(AXNode::AXID node_id) const override;
-
- private:
- // Returns the parent node of the provided child. Returns the parent
- // node's tree id and node id through the provided output parameters,
- // |parent_tree_id| and |parent_id|.
- static AXNode* GetParent(AXNode* child,
- AXTreeID child_tree_id,
- AXTreeID* parent_tree_id,
- AXNode::AXID* parent_id);
};
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_node_position_perftest.cc b/chromium/ui/accessibility/ax_node_position_perftest.cc
index 9c94098bde2..7489a2f12fa 100644
--- a/chromium/ui/accessibility/ax_node_position_perftest.cc
+++ b/chromium/ui/accessibility/ax_node_position_perftest.cc
@@ -68,7 +68,7 @@ void AXPositionPerfTest::SetUp() {
constexpr int kStaticTextNodesStartIndex =
kGroupNodesStartIndex + kNumberOfGroups;
- AXNode::AXID current_id = 0;
+ AXNodeID current_id = 0;
std::vector<AXNodeData> nodes;
nodes.resize(1 + kNumberOfGroups + kNumberOfStaticTextNodes);
diff --git a/chromium/ui/accessibility/ax_node_position_unittest.cc b/chromium/ui/accessibility/ax_node_position_unittest.cc
index 3e69e24f3b1..23296741f08 100644
--- a/chromium/ui/accessibility/ax_node_position_unittest.cc
+++ b/chromium/ui/accessibility/ax_node_position_unittest.cc
@@ -12,6 +12,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/strings/strcat.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -33,15 +34,15 @@ using TestPositionRange = AXRange<AXPosition<AXNodePosition, AXNode>>;
namespace {
-constexpr AXNode::AXID ROOT_ID = 1;
-constexpr AXNode::AXID BUTTON_ID = 2;
-constexpr AXNode::AXID CHECK_BOX_ID = 3;
-constexpr AXNode::AXID TEXT_FIELD_ID = 4;
-constexpr AXNode::AXID STATIC_TEXT1_ID = 5;
-constexpr AXNode::AXID INLINE_BOX1_ID = 6;
-constexpr AXNode::AXID LINE_BREAK_ID = 7;
-constexpr AXNode::AXID STATIC_TEXT2_ID = 8;
-constexpr AXNode::AXID INLINE_BOX2_ID = 9;
+constexpr AXNodeID ROOT_ID = 1;
+constexpr AXNodeID BUTTON_ID = 2;
+constexpr AXNodeID CHECK_BOX_ID = 3;
+constexpr AXNodeID TEXT_FIELD_ID = 4;
+constexpr AXNodeID STATIC_TEXT1_ID = 5;
+constexpr AXNodeID INLINE_BOX1_ID = 6;
+constexpr AXNodeID LINE_BREAK_ID = 7;
+constexpr AXNodeID STATIC_TEXT2_ID = 8;
+constexpr AXNodeID INLINE_BOX2_ID = 9;
// A group of basic and extended characters.
constexpr const wchar_t* kGraphemeClusters[] = {
@@ -81,19 +82,34 @@ class AXPositionTest : public testing::Test, public TestAXTreeManager {
AXNodeData& page_3_data,
AXNodeData& page_3_text_data) const;
+ // Creates a browser window with a forest of accessibility trees: A more
+ // complex Views tree, plus a tree for the whole webpage, containing one
+ // additional tree representing an out-of-process iframe. Returns a vector
+ // containing the three managers for the trees in an out argument. (Note that
+ // fatal assertions can only be propagated from a `void` method.)
+ void CreateBrowserWindow(AXNodeData& window,
+ AXNodeData& back_button,
+ AXNodeData& web_view,
+ AXNodeData& root_web_area,
+ AXNodeData& iframe_root,
+ AXNodeData& paragraph,
+ AXNodeData& address_bar,
+ std::vector<TestAXTreeManager>& out_managers) const;
+
// Creates a document with three static text objects each containing text in a
// different language.
std::unique_ptr<AXTree> CreateMultilingualDocument(
std::vector<int>* text_offsets) const;
void AssertTextLengthEquals(const AXTree* tree,
- AXNode::AXID node_id,
+ AXNodeID node_id,
int expected_text_length) const;
// Creates a new AXTree from a vector of nodes.
// Assumes the first node in the vector is the root.
std::unique_ptr<AXTree> CreateAXTree(
- const std::vector<AXNodeData>& nodes) const;
+ const std::vector<AXNodeData>& nodes,
+ const AXTreeID& parent_tree_id = AXTreeID()) const;
AXNodeData root_;
AXNodeData button_;
@@ -106,6 +122,9 @@ class AXPositionTest : public testing::Test, public TestAXTreeManager {
AXNodeData inline_box2_;
private:
+ // Manages a minimalistic Views tree that is hosting the test webpage.
+ TestAXTreeManager views_tree_manager_;
+
DISALLOW_COPY_AND_ASSIGN(AXPositionTest);
};
@@ -218,7 +237,7 @@ struct TextNavigationTestParam {
base::RepeatingCallback<TestPositionType(const TestPositionType&)> TestMethod;
// The node at which the test should start.
- AXNode::AXID start_node_id;
+ AXNodeID start_node_id;
// The text offset at which the test should start.
int start_offset;
@@ -251,6 +270,39 @@ void AXPositionTest::SetUp() {
// Most tests use kSuppressCharacter behavior.
g_ax_embedded_object_behavior = AXEmbeddedObjectBehavior::kSuppressCharacter;
+ // First create a minimalistic Views tree that would host the test webpage.
+ // Window (BrowserRootView)
+ // ++NonClientView
+ // ++++WebView
+
+ AXNodeData window;
+ window.id = 1;
+ window.role = ax::mojom::Role::kWindow;
+ window.SetName("Test page - Google Chrome");
+ window.AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ "BrowserRootView");
+
+ AXNodeData non_client_view;
+ non_client_view.id = 2;
+ non_client_view.role = ax::mojom::Role::kClient;
+ non_client_view.SetName("Google Chrome");
+ non_client_view.AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ "NonClientView");
+ window.child_ids = {non_client_view.id};
+
+ AXNodeData web_view;
+ web_view.id = 3;
+ web_view.role = ax::mojom::Role::kWebView;
+ web_view.AddState(ax::mojom::State::kInvisible);
+ web_view.SetNameExplicitlyEmpty();
+ web_view.AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ "WebView");
+ non_client_view.child_ids = {web_view.id};
+
+ std::unique_ptr<AXTree> views_tree =
+ CreateAXTree({window, non_client_view, web_view});
+
+ // Now create the webpage tree.
// root_
// |
// +------------+-----------+
@@ -358,11 +410,19 @@ void AXPositionTest::SetUp() {
line_break_, static_text2_, inline_box2_};
initial_state.has_tree_data = true;
initial_state.tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
+ initial_state.tree_data.parent_tree_id = views_tree->GetAXTreeID();
initial_state.tree_data.title = "Dialog title";
// "SetTree" is defined in "TestAXTreeManager" and it passes ownership of the
// created AXTree to the manager.
SetTree(std::make_unique<AXTree>(initial_state));
+
+ AXTreeUpdate views_tree_update;
+ web_view.AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
+ GetTreeID().ToString());
+ views_tree_update.nodes = {web_view};
+ ASSERT_TRUE(views_tree->Unserialize(views_tree_update));
+ views_tree_manager_ = TestAXTreeManager(std::move(views_tree));
}
std::unique_ptr<AXTree> AXPositionTest::CreateMultipageDocument(
@@ -374,7 +434,7 @@ std::unique_ptr<AXTree> AXPositionTest::CreateMultipageDocument(
AXNodeData& page_3_data,
AXNodeData& page_3_text_data) const {
root_data.id = 1;
- root_data.role = ax::mojom::Role::kDocument;
+ root_data.role = ax::mojom::Role::kPdfRoot;
page_1_data.id = 2;
page_1_data.role = ax::mojom::Role::kRegion;
@@ -417,6 +477,133 @@ std::unique_ptr<AXTree> AXPositionTest::CreateMultipageDocument(
page_2_text_data, page_3_data, page_3_text_data});
}
+void AXPositionTest::CreateBrowserWindow(
+ AXNodeData& window,
+ AXNodeData& back_button,
+ AXNodeData& web_view,
+ AXNodeData& root_web_area,
+ AXNodeData& iframe_root,
+ AXNodeData& paragraph,
+ AXNodeData& address_bar,
+ std::vector<TestAXTreeManager>& out_managers) const {
+ // First tree: Views.
+ window.id = 1;
+ window.role = ax::mojom::Role::kWindow;
+ window.SetName("Test page - Google Chrome");
+ window.AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ "BrowserRootView");
+
+ AXNodeData non_client_view;
+ non_client_view.id = 2;
+ non_client_view.role = ax::mojom::Role::kClient;
+ non_client_view.SetName("Google Chrome");
+ non_client_view.AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ "NonClientView");
+ window.child_ids = {non_client_view.id};
+
+ AXNodeData browser_view;
+ browser_view.id = 3;
+ browser_view.role = ax::mojom::Role::kClient;
+ browser_view.AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ "BrowserView");
+
+ AXNodeData toolbar;
+ toolbar.id = 4;
+ toolbar.role = ax::mojom::Role::kPane;
+ toolbar.AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ "ToolbarView");
+ browser_view.child_ids = {toolbar.id};
+
+ back_button.id = 5;
+ back_button.role = ax::mojom::Role::kButton;
+ back_button.AddState(ax::mojom::State::kFocusable);
+ back_button.SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kPress);
+ back_button.SetHasPopup(ax::mojom::HasPopup::kMenu);
+ back_button.SetName("Back");
+ back_button.SetNameFrom(ax::mojom::NameFrom::kContents);
+ back_button.SetDescription("Press to go back, context menu to see history");
+ back_button.AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ "ToolbarButton");
+ back_button.AddAction(ax::mojom::Action::kShowContextMenu);
+ toolbar.child_ids = {back_button.id};
+
+ web_view.id = 6;
+ web_view.role = ax::mojom::Role::kWebView;
+ web_view.AddState(ax::mojom::State::kInvisible);
+ web_view.SetNameExplicitlyEmpty();
+ web_view.AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ "WebView");
+
+ address_bar.id = 7;
+ address_bar.role = ax::mojom::Role::kTextField;
+ address_bar.SetName("Address and search bar");
+ address_bar.SetNameFrom(ax::mojom::NameFrom::kAttribute);
+ address_bar.SetValue("test.com");
+ address_bar.AddStringAttribute(ax::mojom::StringAttribute::kAutoComplete,
+ "both");
+ address_bar.AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ "OmniboxViewViews");
+ address_bar.AddAction(ax::mojom::Action::kShowContextMenu);
+
+ non_client_view.child_ids = {browser_view.id, web_view.id, address_bar.id};
+
+ // Second tree: webpage.
+ root_web_area.id = 1;
+ root_web_area.role = ax::mojom::Role::kRootWebArea;
+ root_web_area.AddState(ax::mojom::State::kFocusable);
+ root_web_area.SetName("Test page");
+ root_web_area.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+
+ AXNodeData iframe;
+ iframe.id = 2;
+ iframe.role = ax::mojom::Role::kIframe;
+ iframe.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+
+ paragraph.id = 3;
+ paragraph.role = ax::mojom::Role::kParagraph;
+ paragraph.SetName("After iframe");
+ paragraph.SetNameFrom(ax::mojom::NameFrom::kContents);
+ paragraph.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+
+ root_web_area.child_ids = {iframe.id, paragraph.id};
+
+ // Third tree: out-of-process iframe.
+ iframe_root.id = 1;
+ iframe_root.role = ax::mojom::Role::kRootWebArea;
+ iframe_root.AddState(ax::mojom::State::kFocusable);
+ iframe_root.SetName("Inside iframe");
+ iframe_root.SetNameFrom(ax::mojom::NameFrom::kContents);
+ iframe_root.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+
+ std::unique_ptr<AXTree> views_tree =
+ CreateAXTree({window, non_client_view, browser_view, toolbar, back_button,
+ web_view, address_bar});
+ std::unique_ptr<AXTree> webpage_tree = CreateAXTree(
+ {root_web_area, iframe, paragraph}, views_tree->GetAXTreeID());
+ std::unique_ptr<AXTree> iframe_tree =
+ CreateAXTree({iframe_root}, webpage_tree->GetAXTreeID());
+
+ AXTreeUpdate views_tree_update;
+ web_view.AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
+ webpage_tree->GetAXTreeID().ToString());
+ views_tree_update.nodes = {web_view};
+ ASSERT_TRUE(views_tree->Unserialize(views_tree_update));
+
+ AXTreeUpdate webpage_tree_update;
+ iframe.AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
+ iframe_tree->GetAXTreeID().ToString());
+ webpage_tree_update.nodes = {iframe};
+ ASSERT_TRUE(webpage_tree->Unserialize(webpage_tree_update));
+
+ out_managers.emplace_back(std::move(views_tree));
+ out_managers.emplace_back(std::move(webpage_tree));
+ out_managers.emplace_back(std::move(iframe_tree));
+}
+
std::unique_ptr<AXTree> AXPositionTest::CreateMultilingualDocument(
std::vector<int>* text_offsets) const {
EXPECT_NE(nullptr, text_offsets);
@@ -475,7 +662,7 @@ std::unique_ptr<AXTree> AXPositionTest::CreateMultilingualDocument(
}
void AXPositionTest::AssertTextLengthEquals(const AXTree* tree,
- AXNode::AXID node_id,
+ AXNodeID node_id,
int expected_text_length) const {
TestPositionType text_position = AXNodePosition::CreateTextPosition(
tree->data().tree_id, node_id, 0 /* text_offset */,
@@ -488,10 +675,12 @@ void AXPositionTest::AssertTextLengthEquals(const AXTree* tree,
}
std::unique_ptr<AXTree> AXPositionTest::CreateAXTree(
- const std::vector<AXNodeData>& nodes) const {
+ const std::vector<AXNodeData>& nodes,
+ const AXTreeID& parent_tree_id) const {
EXPECT_FALSE(nodes.empty());
AXTreeUpdate update;
update.tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
+ update.tree_data.parent_tree_id = parent_tree_id;
update.has_tree_data = true;
update.root_id = nodes[0].id;
update.nodes = nodes;
@@ -729,6 +918,14 @@ TEST_F(AXPositionTest, IsIgnored) {
// We now need to update the tree structure to test ignored tree and text
// positions.
+ //
+ // ++root_data
+ // ++++static_text_data_1 "One" ignored
+ // ++++++inline_box_data_1 "One" ignored
+ // ++++container_data ignored
+ // ++++++static_text_data_2 "Two"
+ // ++++++++inline_box_data_2 "Two"
+
AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
@@ -737,6 +934,7 @@ TEST_F(AXPositionTest, IsIgnored) {
static_text_data_1.id = 2;
static_text_data_1.role = ax::mojom::Role::kStaticText;
static_text_data_1.SetName("One");
+ static_text_data_1.AddState(ax::mojom::State::kIgnored);
AXNodeData inline_box_data_1;
inline_box_data_1.id = 3;
@@ -772,25 +970,15 @@ TEST_F(AXPositionTest, IsIgnored) {
// Text positions.
//
- TestPositionType text_position_1 = AXNodePosition::CreateTextPosition(
- GetTreeID(), root_data.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(text_position_1->IsTextPosition());
- // Since the leaf node containing the text that is pointed to is ignored, this
- // position should be ignored.
- EXPECT_TRUE(text_position_1->IsIgnored());
-
- // Create a text position before the letter "e" in "One".
- TestPositionType text_position_2 = AXNodePosition::CreateTextPosition(
- GetTreeID(), root_data.id, 2 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(text_position_2->IsTextPosition());
- // Same as above.
- EXPECT_TRUE(text_position_2->IsIgnored());
+ // A "before text" position on the root should not be ignored, despite the
+ // fact that the leaf equivalent position is, because AXPosition always
+ // adjusts to an unignored position if asked to find the leaf equivalent
+ // position. In other words, the text of ignored leaves is not propagated to
+ // the inner text of their ancestors.
// Create a text position before the letter "T" in "Two".
TestPositionType text_position_3 = AXNodePosition::CreateTextPosition(
- GetTreeID(), root_data.id, 3 /* text_offset */,
+ GetTreeID(), root_data.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
ASSERT_TRUE(text_position_3->IsTextPosition());
// Since the leaf node containing the text that is pointed to is not ignored,
@@ -800,7 +988,7 @@ TEST_F(AXPositionTest, IsIgnored) {
// Create a text position before the letter "w" in "Two".
TestPositionType text_position_4 = AXNodePosition::CreateTextPosition(
- GetTreeID(), root_data.id, 4 /* text_offset */,
+ GetTreeID(), root_data.id, 1 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
ASSERT_TRUE(text_position_4->IsTextPosition());
// Same as above.
@@ -815,7 +1003,7 @@ TEST_F(AXPositionTest, IsIgnored) {
EXPECT_TRUE(text_position_5->IsIgnored());
// Whilst a text position on its static text child should not be ignored since
- // there is nothing ignore below the generic container.
+ // there is nothing ignored below the generic container.
TestPositionType text_position_6 = AXNodePosition::CreateTextPosition(
GetTreeID(), static_text_data_2.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
@@ -833,14 +1021,12 @@ TEST_F(AXPositionTest, IsIgnored) {
// Tree positions.
//
- // A "before children" position on the root should not be ignored, despite the
- // fact that the leaf equivalent position is, because we can always adjust to
- // an unignored position if asked to find the leaf equivalent unignored
- // position.
+ // A "before children" position on the root should be ignored because the
+ // first child of the root is ignored.
TestPositionType tree_position_1 = AXNodePosition::CreateTreePosition(
GetTreeID(), root_data.id, 0 /* child_index */);
ASSERT_TRUE(tree_position_1->IsTreePosition());
- EXPECT_FALSE(tree_position_1->IsIgnored());
+ EXPECT_TRUE(tree_position_1->IsIgnored());
// A tree position pointing to an ignored child node should be ignored.
TestPositionType tree_position_2 = AXNodePosition::CreateTreePosition(
@@ -867,11 +1053,11 @@ TEST_F(AXPositionTest, IsIgnored) {
ASSERT_TRUE(tree_position_5->IsTreePosition());
EXPECT_TRUE(tree_position_5->IsIgnored());
- // A "before text" position on an unignored node should not be ignored.
+ // A "before text" position on an ignored node should be ignored.
TestPositionType tree_position_6 = AXNodePosition::CreateTreePosition(
GetTreeID(), static_text_data_1.id, AXNodePosition::BEFORE_TEXT);
ASSERT_TRUE(tree_position_6->IsTreePosition());
- EXPECT_FALSE(tree_position_6->IsIgnored());
+ EXPECT_TRUE(tree_position_6->IsIgnored());
}
TEST_F(AXPositionTest, GetTextFromNullPosition) {
@@ -1583,8 +1769,10 @@ TEST_F(AXPositionTest, AtStartAndEndOfLineInsideTextField) {
AXNodeData text_field_data_1;
text_field_data_1.id = 2;
text_field_data_1.role = ax::mojom::Role::kTextField;
- // "kIsLineBreakingObject" and the "kEditable" state are not strictly
- // necessary but are added for completeness.
+ text_field_data_1.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot,
+ true);
+ text_field_data_1.AddState(ax::mojom::State::kEditable);
+ // "kIsLineBreakingObject" is not strictly necessary.
text_field_data_1.AddBoolAttribute(
ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
text_field_data_1.AddState(ax::mojom::State::kEditable);
@@ -1595,16 +1783,19 @@ TEST_F(AXPositionTest, AtStartAndEndOfLineInsideTextField) {
AXNodeData static_text_data_1;
static_text_data_1.id = 3;
static_text_data_1.role = ax::mojom::Role::kStaticText;
+ static_text_data_1.AddState(ax::mojom::State::kEditable);
static_text_data_1.SetName(" Text field one ");
AXNodeData inline_box_data_1;
inline_box_data_1.id = 4;
inline_box_data_1.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_data_1.AddState(ax::mojom::State::kEditable);
inline_box_data_1.SetName(" ");
AXNodeData inline_box_data_2;
inline_box_data_2.id = 5;
inline_box_data_2.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_data_2.AddState(ax::mojom::State::kEditable);
inline_box_data_1.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
inline_box_data_2.id);
inline_box_data_2.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
@@ -1614,6 +1805,7 @@ TEST_F(AXPositionTest, AtStartAndEndOfLineInsideTextField) {
AXNodeData inline_box_data_3;
inline_box_data_3.id = 6;
inline_box_data_3.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_data_3.AddState(ax::mojom::State::kEditable);
inline_box_data_2.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
inline_box_data_3.id);
inline_box_data_3.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
@@ -1623,11 +1815,12 @@ TEST_F(AXPositionTest, AtStartAndEndOfLineInsideTextField) {
AXNodeData text_field_data_2;
text_field_data_2.id = 7;
text_field_data_2.role = ax::mojom::Role::kTextField;
- // "kIsLineBreakingObject" and the "kEditable" state are not strictly
- // necessary but are added for completeness.
+ text_field_data_2.AddState(ax::mojom::State::kEditable);
+ text_field_data_2.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot,
+ true);
+ // "kIsLineBreakingObject" is not strictly necessary.
text_field_data_2.AddBoolAttribute(
ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
- text_field_data_1.AddState(ax::mojom::State::kEditable);
// Notice that there are three lines, the first and the last one include only
// a single space.
text_field_data_2.SetValue(" Text field two ");
@@ -1635,21 +1828,25 @@ TEST_F(AXPositionTest, AtStartAndEndOfLineInsideTextField) {
AXNodeData static_text_data_2;
static_text_data_2.id = 8;
static_text_data_2.role = ax::mojom::Role::kStaticText;
+ static_text_data_2.AddState(ax::mojom::State::kEditable);
static_text_data_2.SetName(" Text field two ");
AXNodeData inline_box_data_4;
inline_box_data_4.id = 9;
inline_box_data_4.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_data_4.AddState(ax::mojom::State::kEditable);
inline_box_data_4.SetName(" ");
AXNodeData inline_box_data_5;
inline_box_data_5.id = 10;
inline_box_data_5.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_data_5.AddState(ax::mojom::State::kEditable);
inline_box_data_5.SetName("Text field two");
AXNodeData inline_box_data_6;
inline_box_data_6.id = 11;
inline_box_data_6.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_data_6.AddState(ax::mojom::State::kEditable);
inline_box_data_6.SetName(" ");
static_text_data_1.child_ids = {inline_box_data_1.id, inline_box_data_2.id,
@@ -1815,7 +2012,7 @@ TEST_F(AXPositionTest, AtEndOfParagraphWithTextPosition) {
EXPECT_FALSE(text_position->AtEndOfParagraph());
// The end of |inline_box2_| is the end of paragraph since it's
- // followed by the end of document.
+ // followed by the end of the whole content.
text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), inline_box2_.id, 6 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
@@ -2351,7 +2548,7 @@ TEST_F(AXPositionTest, AtStartOrEndOfParagraphOnAListMarker) {
}
TEST_F(AXPositionTest,
- AtStartOrEndOfParagraphWithLeadingAndTrailingDocumentWhitespace) {
+ AtStartOrEndOfParagraphWithLeadingAndTrailingWhitespace) {
// This test ensures that "At{Start|End}OfParagraph" work correctly when a
// text position is on a preserved newline character.
//
@@ -2854,53 +3051,54 @@ TEST_F(AXPositionTest, LowestCommonAncestor) {
ASSERT_NE(nullptr, inline_box2_position);
ASSERT_TRUE(inline_box2_position->IsTextPosition());
- TestPositionType test_position =
- root_position->LowestCommonAncestor(*null_position.get());
+ TestPositionType test_position = root_position->LowestCommonAncestor(
+ *null_position.get(), ax::mojom::MoveDirection::kForward);
EXPECT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsNullPosition());
- test_position = root_position->LowestCommonAncestor(*root_position.get());
- EXPECT_NE(nullptr, test_position);
+ test_position = root_position->LowestCommonAncestor(
+ *root_position.get(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(root_.id, test_position->anchor_id());
// The child index should be for an "after children" position, i.e. it should
// be unchanged.
EXPECT_EQ(3, test_position->child_index());
- test_position =
- button_position->LowestCommonAncestor(*text_field_position.get());
- EXPECT_NE(nullptr, test_position);
+ test_position = button_position->LowestCommonAncestor(
+ *text_field_position.get(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(root_.id, test_position->anchor_id());
// The child index should point to the button.
EXPECT_EQ(0, test_position->child_index());
- test_position =
- static_text2_position->LowestCommonAncestor(*static_text1_position.get());
- EXPECT_NE(nullptr, test_position);
+ test_position = static_text2_position->LowestCommonAncestor(
+ *static_text1_position.get(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(text_field_.id, test_position->anchor_id());
// The child index should point to the second static text node.
EXPECT_EQ(2, test_position->child_index());
- test_position =
- static_text1_position->LowestCommonAncestor(*text_field_position.get());
- EXPECT_NE(nullptr, test_position);
+ test_position = static_text1_position->LowestCommonAncestor(
+ *text_field_position.get(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(text_field_.id, test_position->anchor_id());
// The child index should point to the first static text node.
EXPECT_EQ(0, test_position->child_index());
- test_position =
- inline_box1_position->LowestCommonAncestor(*inline_box2_position.get());
- EXPECT_NE(nullptr, test_position);
+ test_position = inline_box1_position->LowestCommonAncestor(
+ *inline_box2_position.get(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(text_field_.id, test_position->anchor_id());
EXPECT_EQ(0, test_position->text_offset());
- test_position =
- inline_box2_position->LowestCommonAncestor(*inline_box1_position.get());
- EXPECT_NE(nullptr, test_position);
+ test_position = inline_box2_position->LowestCommonAncestor(
+ *inline_box1_position.get(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(text_field_.id, test_position->anchor_id());
// The text offset should point to the second line.
@@ -3108,6 +3306,16 @@ TEST_F(AXPositionTest, AsLeafTreePositionWithTextPosition) {
EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
EXPECT_EQ(0, test_position->child_index());
+ // Nodes with no text should not be skipped when finding the leaf text
+ // position, otherwise a "before text" position could accidentally turn into
+ // an "after text" one.
+ // ++kTextField "" (empty)
+ // ++++kStaticText "" (empty)
+ // ++++++kInlineTextBox "" (empty)
+ // A TextPosition anchor=kTextField text_offset=0, should turn into a leaf
+ // text position at the start of kInlineTextBox and not after it. In this
+ // case, the deepest first child of the root is the button, regardless as to
+ // whether it has no text inside it.
text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), root_.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
@@ -3117,7 +3325,7 @@ TEST_F(AXPositionTest, AsLeafTreePositionWithTextPosition) {
ASSERT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsLeafTreePosition());
EXPECT_EQ(GetTreeID(), test_position->tree_id());
- EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
+ EXPECT_EQ(button_.id, test_position->anchor_id());
EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
text_position = AXNodePosition::CreateTextPosition(
@@ -3433,8 +3641,11 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) {
TEST_F(AXPositionTest, AsLeafTextPositionWithTextPositionAndEmptyTextSandwich) {
// This test updates the tree structure to test a specific edge case -
- // AsLeafTextPosition when there is an empty leaf text node between
- // two non-empty text nodes.
+ // `AsLeafTextPosition` when there is an empty leaf text node between
+ // two non-empty text nodes. Empty leaf nodes should not be skipped when
+ // finding the leaf equivalent position, otherwise important controls (e.g.
+ // buttons) that are unlabelled could accidentally be skipped while
+ // navigating.
AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
@@ -3460,7 +3671,8 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPositionAndEmptyTextSandwich) {
SetTree(CreateAXTree({root_data, text_data, button_data, more_text_data}));
// Create a text position on the root pointing to just after the
- // first static text leaf node.
+ // first static text leaf node. Even though the button has empty inner text,
+ // still, it should not be skipped when finding the leaf text position.
TestPositionType text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), root_data.id, 9 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
@@ -3488,7 +3700,168 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPositionAndEmptyTextSandwich) {
EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
}
+TEST_F(AXPositionTest, AsLeafTextPositionWithTextPositionAndEmbeddedObject) {
+ g_ax_embedded_object_behavior = AXEmbeddedObjectBehavior::kExposeCharacter;
+
+ // ++1 kRootWebArea "<embedded_object><embedded_object>"
+ // ++++2 kImage alt="Test image"
+ // ++++3 kParagraph "<embedded_object>"
+ // ++++++4 kLink "Hello"
+ // ++++++++5 kStaticText "Hello"
+ // ++++++++++6 kInlineTextBox "Hello"
+ AXNodeData root;
+ AXNodeData image;
+ AXNodeData paragraph;
+ AXNodeData link;
+ AXNodeData static_text;
+ AXNodeData inline_box;
+
+ root.id = 1;
+ image.id = 2;
+ paragraph.id = 3;
+ link.id = 4;
+ static_text.id = 5;
+ inline_box.id = 6;
+
+ root.role = ax::mojom::Role::kRootWebArea;
+ root.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ root.child_ids = {image.id, paragraph.id};
+
+ image.role = ax::mojom::Role::kImage;
+ image.SetName("Test image");
+ // Alt text should not appear in the tree's text representation, so we need to
+ // set the right NameFrom.
+ image.SetNameFrom(ax::mojom::NameFrom::kAttribute);
+
+ paragraph.role = ax::mojom::Role::kParagraph;
+ paragraph.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+ paragraph.child_ids = {link.id};
+
+ link.role = ax::mojom::Role::kLink;
+ link.AddState(ax::mojom::State::kLinked);
+ link.child_ids = {static_text.id};
+
+ static_text.role = ax::mojom::Role::kStaticText;
+ static_text.SetName("Hello");
+ static_text.child_ids = {inline_box.id};
+
+ inline_box.role = ax::mojom::Role::kInlineTextBox;
+ inline_box.SetName("Hello");
+
+ SetTree(
+ CreateAXTree({root, image, paragraph, link, static_text, inline_box}));
+
+ TestPositionType before_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, before_root);
+ TestPositionType middle_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, middle_root);
+ TestPositionType middle_root_upstream = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kUpstream);
+ ASSERT_NE(nullptr, middle_root_upstream);
+ TestPositionType after_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 2 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, after_root);
+ // A position with an upstream affinity after the root should make no
+ // difference compared with a downstream affinity, but we'll test it for
+ // completeness.
+ TestPositionType after_root_upstream = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 2 /* text_offset */,
+ ax::mojom::TextAffinity::kUpstream);
+ ASSERT_NE(nullptr, after_root_upstream);
+
+ TestPositionType before_image = AXNodePosition::CreateTextPosition(
+ GetTreeID(), image.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, before_image);
+ // Alt text should not appear in the tree's text representation, but since the
+ // image is both a character and a word boundary it should be replaced by the
+ // "embedded object replacement character" in the text representation.
+ TestPositionType after_image = AXNodePosition::CreateTextPosition(
+ GetTreeID(), image.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, after_image);
+
+ TestPositionType before_paragraph = AXNodePosition::CreateTextPosition(
+ GetTreeID(), paragraph.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, before_paragraph);
+ // The paragraph has a link inside it, so it will only expose a single
+ // "embedded object replacement character".
+ TestPositionType after_paragraph = AXNodePosition::CreateTextPosition(
+ GetTreeID(), paragraph.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, after_paragraph);
+ // A position with an upstream affinity after the paragraph should make no
+ // difference compared with a downstream affinity, but we'll test it for
+ // completeness.
+ TestPositionType after_paragraph_upstream =
+ AXNodePosition::CreateTextPosition(GetTreeID(), paragraph.id,
+ 1 /* text_offset */,
+ ax::mojom::TextAffinity::kUpstream);
+ ASSERT_NE(nullptr, after_paragraph_upstream);
+
+ TestPositionType before_link = AXNodePosition::CreateTextPosition(
+ GetTreeID(), link.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, before_link);
+ // The llink has the text "Hello" inside it.
+ TestPositionType after_link = AXNodePosition::CreateTextPosition(
+ GetTreeID(), link.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, after_link);
+ // A position with an upstream affinity after the link should make no
+ // difference compared with a downstream affinity, but we'll test it for
+ // completeness.
+ TestPositionType after_link_upstream = AXNodePosition::CreateTextPosition(
+ GetTreeID(), link.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kUpstream);
+ ASSERT_NE(nullptr, after_link_upstream);
+
+ TestPositionType before_inline_box = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, before_inline_box);
+ // The inline box has the text "Hello" inside it.
+ TestPositionType after_inline_box = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, after_inline_box);
+
+ EXPECT_EQ(*before_root->AsLeafTextPosition(), *before_image);
+ EXPECT_EQ(*middle_root->AsLeafTextPosition(), *before_inline_box);
+ // As mentioned above, alt text should not appear in the tree's text
+ // representation, but since the image is both a character and a word boundary
+ // it should be replaced by the "embedded object replacement character" in the
+ // text representation.
+ EXPECT_EQ(*middle_root_upstream->AsLeafTextPosition(), *after_image);
+ EXPECT_EQ(*after_root->AsLeafTextPosition(), *after_inline_box);
+ EXPECT_EQ(*after_root_upstream->AsLeafTextPosition(), *after_inline_box);
+
+ EXPECT_EQ(*before_paragraph->AsLeafTextPosition(), *before_inline_box);
+ EXPECT_EQ(*after_paragraph->AsLeafTextPosition(), *after_inline_box);
+ EXPECT_EQ(*after_paragraph_upstream->AsLeafTextPosition(), *after_inline_box);
+
+ EXPECT_EQ(*before_link->AsLeafTextPosition(), *before_inline_box);
+ EXPECT_EQ(*after_link->AsLeafTextPosition(), *after_inline_box);
+ EXPECT_EQ(*after_link_upstream->AsLeafTextPosition(), *after_inline_box);
+}
+
TEST_F(AXPositionTest, AsUnignoredPosition) {
+ // ++root_data
+ // ++++static_text_data_1 "1"
+ // ++++++inline_box_data_1 "1"
+ // ++++++inline_box_data_1 "2" ignored
+ // ++++container_data ignored
+ // ++++++static_data_2 "3"
+ // ++++++++inline_box_data_2 "3"
+
AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
@@ -3496,7 +3869,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
AXNodeData static_text_data_1;
static_text_data_1.id = 2;
static_text_data_1.role = ax::mojom::Role::kStaticText;
- static_text_data_1.SetName("12");
+ static_text_data_1.SetName("1");
AXNodeData inline_box_data_1;
inline_box_data_1.id = 3;
@@ -3545,33 +3918,33 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
TestPositionType text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), container_data.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(text_position->IsIgnored());
+ EXPECT_TRUE(text_position->IsIgnored());
TestPositionType test_position = text_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveForward);
ASSERT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(root_data.id, test_position->anchor_id());
- EXPECT_EQ(2, test_position->text_offset());
+ EXPECT_EQ(1, test_position->text_offset());
EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
// "After text" position.
text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), container_data.id, 1 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(text_position->IsIgnored());
+ EXPECT_TRUE(text_position->IsIgnored());
// Changing the adjustment behavior should not affect the outcome.
test_position = text_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveBackward);
ASSERT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(root_data.id, test_position->anchor_id());
- EXPECT_EQ(3, test_position->text_offset());
+ EXPECT_EQ(2, test_position->text_offset());
EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
// "Before children" position.
TestPositionType tree_position = AXNodePosition::CreateTreePosition(
GetTreeID(), container_data.id, 0 /* child_index */);
- ASSERT_TRUE(tree_position->IsIgnored());
+ EXPECT_TRUE(tree_position->IsIgnored());
test_position = tree_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveForward);
ASSERT_NE(nullptr, test_position);
@@ -3582,7 +3955,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
// "After children" position.
tree_position = AXNodePosition::CreateTreePosition(
GetTreeID(), container_data.id, 1 /* child_index */);
- ASSERT_TRUE(tree_position->IsIgnored());
+ EXPECT_TRUE(tree_position->IsIgnored());
// Changing the adjustment behavior should not affect the outcome.
test_position = tree_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveBackward);
@@ -3595,7 +3968,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
// whose last child is ignored.
tree_position = AXNodePosition::CreateTreePosition(
GetTreeID(), static_text_data_1.id, 2 /* child_index */);
- ASSERT_TRUE(tree_position->IsIgnored());
+ EXPECT_TRUE(tree_position->IsIgnored());
test_position = tree_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveBackward);
ASSERT_NE(nullptr, test_position);
@@ -3616,7 +3989,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), root_data.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(text_position->IsIgnored());
+ EXPECT_TRUE(text_position->IsIgnored());
test_position = text_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveForward);
ASSERT_NE(nullptr, test_position);
@@ -3628,7 +4001,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), root_data.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(text_position->IsIgnored());
+ EXPECT_TRUE(text_position->IsIgnored());
// Changing the adjustment behavior should not change the outcome.
test_position = text_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveBackward);
@@ -3640,7 +4013,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
tree_position = AXNodePosition::CreateTreePosition(GetTreeID(), root_data.id,
1 /* child_index */);
- ASSERT_TRUE(tree_position->IsIgnored());
+ EXPECT_TRUE(tree_position->IsIgnored());
test_position = tree_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveForward);
ASSERT_NE(nullptr, test_position);
@@ -3659,7 +4032,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
// "After children" position.
tree_position = AXNodePosition::CreateTreePosition(GetTreeID(), root_data.id,
2 /* child_index */);
- ASSERT_TRUE(tree_position->IsIgnored());
+ EXPECT_TRUE(tree_position->IsIgnored());
test_position = tree_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveForward);
ASSERT_NE(nullptr, test_position);
@@ -3678,7 +4051,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
// "Before children" position.
tree_position = AXNodePosition::CreateTreePosition(
GetTreeID(), container_data.id, 0 /* child_index */);
- ASSERT_TRUE(tree_position->IsIgnored());
+ EXPECT_TRUE(tree_position->IsIgnored());
test_position = tree_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveForward);
ASSERT_NE(nullptr, test_position);
@@ -3689,7 +4062,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
// "After children" position.
tree_position = AXNodePosition::CreateTreePosition(
GetTreeID(), container_data.id, 1 /* child_index */);
- ASSERT_TRUE(tree_position->IsIgnored());
+ EXPECT_TRUE(tree_position->IsIgnored());
// Changing the adjustment behavior should not affect the outcome.
test_position = tree_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveBackward);
@@ -3698,13 +4071,10 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
EXPECT_EQ(inline_box_data_3.id, test_position->anchor_id());
EXPECT_EQ(0, test_position->child_index());
- // 3. As a last resort, we move either to the next or previous unignored
- // position in the accessibility tree, based on the "adjustment_behavior".
-
text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), root_data.id, 1 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(text_position->IsIgnored());
+ EXPECT_TRUE(text_position->IsIgnored());
test_position = text_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveForward);
ASSERT_NE(nullptr, test_position);
@@ -3716,7 +4086,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), inline_box_data_2.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(text_position->IsIgnored());
+ EXPECT_TRUE(text_position->IsIgnored());
test_position = text_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveForward);
ASSERT_NE(nullptr, test_position);
@@ -3728,7 +4098,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), inline_box_data_2.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(text_position->IsIgnored());
+ EXPECT_TRUE(text_position->IsIgnored());
test_position = text_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveBackward);
ASSERT_NE(nullptr, test_position);
@@ -3740,14 +4110,14 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
tree_position = AXNodePosition::CreateTreePosition(
GetTreeID(), inline_box_data_2.id, AXNodePosition::BEFORE_TEXT);
- ASSERT_TRUE(tree_position->IsIgnored());
+ EXPECT_TRUE(tree_position->IsIgnored());
+
test_position = tree_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveForward);
ASSERT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(inline_box_data_3.id, test_position->anchor_id());
EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
- ASSERT_TRUE(tree_position->IsIgnored());
test_position = tree_position->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveBackward);
@@ -3757,7 +4127,7 @@ TEST_F(AXPositionTest, AsUnignoredPosition) {
EXPECT_EQ(0, test_position->child_index());
}
-TEST_F(AXPositionTest, CreatePositionAtTextBoundaryDocumentStartEndIsIgnored) {
+TEST_F(AXPositionTest, CreatePositionAtTextBoundaryContentStartEndIsIgnored) {
// +-root_data
// +-static_text_data_1
// | +-inline_box_data_1 IGNORED
@@ -3767,15 +4137,15 @@ TEST_F(AXPositionTest, CreatePositionAtTextBoundaryDocumentStartEndIsIgnored) {
// | +-inline_box_data_3
// +-static_text_data_4
// +-inline_box_data_4 IGNORED
- constexpr AXNode::AXID ROOT_ID = 1;
- constexpr AXNode::AXID STATIC_TEXT1_ID = 2;
- constexpr AXNode::AXID STATIC_TEXT2_ID = 3;
- constexpr AXNode::AXID STATIC_TEXT3_ID = 4;
- constexpr AXNode::AXID STATIC_TEXT4_ID = 5;
- constexpr AXNode::AXID INLINE_BOX1_ID = 6;
- constexpr AXNode::AXID INLINE_BOX2_ID = 7;
- constexpr AXNode::AXID INLINE_BOX3_ID = 8;
- constexpr AXNode::AXID INLINE_BOX4_ID = 9;
+ constexpr AXNodeID ROOT_ID = 1;
+ constexpr AXNodeID STATIC_TEXT1_ID = 2;
+ constexpr AXNodeID STATIC_TEXT2_ID = 3;
+ constexpr AXNodeID STATIC_TEXT3_ID = 4;
+ constexpr AXNodeID STATIC_TEXT4_ID = 5;
+ constexpr AXNodeID INLINE_BOX1_ID = 6;
+ constexpr AXNodeID INLINE_BOX2_ID = 7;
+ constexpr AXNodeID INLINE_BOX3_ID = 8;
+ constexpr AXNodeID INLINE_BOX4_ID = 9;
AXNodeData root_data;
root_data.id = ROOT_ID;
@@ -4106,8 +4476,8 @@ TEST_F(AXPositionTest, CreatePositionAtPreviousFormatStartWithTreePosition) {
EXPECT_EQ(button_.id, test_position->anchor_id());
EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
- // StopAtLastAnchorBoundary should stop at the start of the document while
- // CrossBoundary should return a null position when crossing it.
+ // StopAtLastAnchorBoundary should stop at the start of the whole content
+ // while CrossBoundary should return a null position when crossing it.
test_position = test_position->CreatePreviousFormatStartPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
@@ -4159,8 +4529,8 @@ TEST_F(AXPositionTest, CreatePositionAtPreviousFormatStartWithTextPosition) {
EXPECT_EQ(button_.id, test_position->anchor_id());
EXPECT_EQ(0, test_position->text_offset());
- // StopAtLastAnchorBoundary should stop at the start of the document while
- // CrossBoundary should return a null position when crossing it.
+ // StopAtLastAnchorBoundary should stop at the start of the whole content
+ // while CrossBoundary should return a null position when crossing it.
test_position = test_position->CreatePreviousFormatStartPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
@@ -4229,7 +4599,7 @@ TEST_F(AXPositionTest, CreatePositionAtNextFormatEndWithTreePosition) {
EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
EXPECT_EQ(0, test_position->child_index());
- // StopAtLastAnchorBoundary should stop at the end of the document while
+ // StopAtLastAnchorBoundary should stop at the end of the whole content while
// CrossBoundary should return a null position when crossing it.
test_position = test_position->CreateNextFormatEndPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
@@ -4287,7 +4657,7 @@ TEST_F(AXPositionTest, CreatePositionAtNextFormatEndWithTextPosition) {
EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
EXPECT_EQ(6, test_position->text_offset());
- // StopAtLastAnchorBoundary should stop at the end of the document while
+ // StopAtLastAnchorBoundary should stop at the end of the whole content while
// CrossBoundary should return a null position when crossing it.
test_position = test_position->CreateNextFormatEndPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
@@ -4324,7 +4694,7 @@ TEST_F(AXPositionTest, CreatePositionAtFormatBoundaryWithTextPosition) {
SetTree(CreateAXTree({root_data, text_data, more_text_data}));
- // Test CreatePreviousFormatStartPosition at the start of the document.
+ // Test CreatePreviousFormatStartPosition at the start of the whole content.
TestPositionType text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), text_data.id, 8 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
@@ -4337,7 +4707,7 @@ TEST_F(AXPositionTest, CreatePositionAtFormatBoundaryWithTextPosition) {
EXPECT_EQ(text_data.id, test_position->anchor_id());
EXPECT_EQ(0, test_position->text_offset());
- // Test CreateNextFormatEndPosition at the end of the document.
+ // Test CreateNextFormatEndPosition at the end of the whole content.
text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), more_text_data.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
@@ -4618,78 +4988,102 @@ TEST_F(AXPositionTest, MoveByFormatWithIgnoredNodes) {
}
}
-TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTextPosition) {
+TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithNullPosition) {
+ TestPositionType null_position = AXNodePosition::CreateNullPosition();
+ ASSERT_NE(nullptr, null_position);
+ TestPositionType test_position =
+ null_position->CreatePreviousPageStartPosition(
+ AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+ EXPECT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsNullPosition());
+
+ test_position = null_position->CreateNextPageStartPosition(
+ AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+ EXPECT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsNullPosition());
+
+ test_position = null_position->CreatePreviousPageEndPosition(
+ AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+ EXPECT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsNullPosition());
+
+ test_position = null_position->CreatePreviousPageStartPosition(
+ AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+ EXPECT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsNullPosition());
+}
+
+TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTreePosition) {
AXNodeData root_data, page_1_data, page_1_text_data, page_2_data,
page_2_text_data, page_3_data, page_3_text_data;
SetTree(CreateMultipageDocument(root_data, page_1_data, page_1_text_data,
page_2_data, page_2_text_data, page_3_data,
page_3_text_data));
- // Test CreateNextPageStartPosition at the start of the document.
- TestPositionType text_position = AXNodePosition::CreateTextPosition(
- GetTreeID(), page_1_text_data.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_NE(nullptr, text_position);
- ASSERT_TRUE(text_position->IsTextPosition());
+ // Test CreateNextPageStartPosition at the start of the whole content.
+ TestPositionType tree_position = AXNodePosition::CreateTreePosition(
+ GetTreeID(), page_1_data.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ ASSERT_TRUE(tree_position->IsTreePosition());
// StopIfAlreadyAtBoundary shouldn't move at all since it's at a boundary.
- TestPositionType test_position = text_position->CreateNextPageStartPosition(
+ TestPositionType test_position = tree_position->CreateNextPageStartPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
- EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->text_offset());
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_EQ(page_1_data.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
- test_position = text_position->CreateNextPageStartPosition(
+ test_position = tree_position->CreateNextPageStartPosition(
AXBoundaryBehavior::CrossBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->text_offset());
+ EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
- test_position = text_position->CreateNextPageStartPosition(
+ test_position = tree_position->CreateNextPageStartPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->text_offset());
+ EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
- // Test CreateNextPageEndPosition until the end of document is reached.
- test_position = test_position->CreateNextPageEndPosition(
+ // Test CreateNextPageEndPosition until the end of content is reached.
+ test_position = tree_position->CreateNextPageEndPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
- EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(19, test_position->text_offset());
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_EQ(page_1_data.id, test_position->anchor_id());
+ EXPECT_EQ(1, test_position->child_index());
test_position = test_position->CreateNextPageEndPosition(
AXBoundaryBehavior::CrossBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
- EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
- EXPECT_EQ(24, test_position->text_offset());
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
test_position = test_position->CreateNextPageEndPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
- EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
- EXPECT_EQ(24, test_position->text_offset());
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
- // StopAtLastAnchorBoundary shouldn't move past the end of the document.
+ // StopAtLastAnchorBoundary shouldn't move past the end of the whole content.
test_position = test_position->CreateNextPageStartPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
- EXPECT_EQ(24, test_position->text_offset());
+ EXPECT_EQ(0, test_position->child_index());
test_position = test_position->CreateNextPageEndPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
- EXPECT_EQ(24, test_position->text_offset());
+ EXPECT_EQ(0, test_position->child_index());
// Moving forward past the end should return a null position.
TestPositionType null_position = test_position->CreateNextPageStartPosition(
@@ -4702,63 +5096,64 @@ TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTextPosition) {
EXPECT_NE(nullptr, null_position);
EXPECT_TRUE(null_position->IsNullPosition());
- // Now move backward through the document.
- text_position = test_position->CreatePreviousPageEndPosition(
+ // Now move backward through the accessibility tree.
+ tree_position = test_position->CreatePreviousPageEndPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
- EXPECT_NE(nullptr, text_position);
- EXPECT_TRUE(text_position->IsTextPosition());
- EXPECT_EQ(page_3_text_data.id, text_position->anchor_id());
- EXPECT_EQ(24, text_position->text_offset());
+ EXPECT_NE(nullptr, tree_position);
+ EXPECT_TRUE(tree_position->IsTreePosition());
+ EXPECT_EQ(page_3_text_data.id, tree_position->anchor_id());
+ EXPECT_EQ(0, tree_position->child_index());
- test_position = text_position->CreatePreviousPageEndPosition(
+ test_position = tree_position->CreatePreviousPageEndPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(19, test_position->text_offset());
+ EXPECT_EQ(0, test_position->child_index());
- test_position = text_position->CreatePreviousPageEndPosition(
+ test_position = tree_position->CreatePreviousPageEndPosition(
AXBoundaryBehavior::CrossBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(19, test_position->text_offset());
+ EXPECT_EQ(0, test_position->child_index());
test_position = test_position->CreatePreviousPageStartPosition(
AXBoundaryBehavior::CrossBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->text_offset());
+ EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
test_position = test_position->CreatePreviousPageStartPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->text_offset());
+ EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
test_position = test_position->CreatePreviousPageStartPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->text_offset());
+ EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
- // StopAtLastAnchorBoundary shouldn't move past the start of the document.
+ // StopAtLastAnchorBoundary shouldn't move past the start of the whole
+ // content.
test_position = test_position->CreatePreviousPageStartPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->text_offset());
+ EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
test_position = test_position->CreatePreviousPageEndPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->text_offset());
+ EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
// Moving before the start should return a null position.
null_position = test_position->CreatePreviousPageStartPosition(
@@ -4772,77 +5167,78 @@ TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTextPosition) {
EXPECT_TRUE(null_position->IsNullPosition());
}
-TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTreePosition) {
+TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTextPosition) {
AXNodeData root_data, page_1_data, page_1_text_data, page_2_data,
page_2_text_data, page_3_data, page_3_text_data;
SetTree(CreateMultipageDocument(root_data, page_1_data, page_1_text_data,
page_2_data, page_2_text_data, page_3_data,
page_3_text_data));
- // Test CreateNextPageStartPosition at the start of the document.
- TestPositionType tree_position = AXNodePosition::CreateTreePosition(
- GetTreeID(), page_1_data.id, 0 /* child_index */);
- ASSERT_NE(nullptr, tree_position);
- ASSERT_TRUE(tree_position->IsTreePosition());
+ // Test CreateNextPageStartPosition at the start of the whole content.
+ TestPositionType text_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), page_1_text_data.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ ASSERT_TRUE(text_position->IsTextPosition());
// StopIfAlreadyAtBoundary shouldn't move at all since it's at a boundary.
- TestPositionType test_position = tree_position->CreateNextPageStartPosition(
+ TestPositionType test_position = text_position->CreateNextPageStartPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
- EXPECT_EQ(page_1_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->child_index());
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
- test_position = tree_position->CreateNextPageStartPosition(
+ test_position = text_position->CreateNextPageStartPosition(
AXBoundaryBehavior::CrossBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
+ EXPECT_EQ(0, test_position->text_offset());
- test_position = tree_position->CreateNextPageStartPosition(
+ test_position = text_position->CreateNextPageStartPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
+ EXPECT_EQ(0, test_position->text_offset());
- // Test CreateNextPageEndPosition until the end of document is reached.
- test_position = tree_position->CreateNextPageEndPosition(
+ // Test CreateNextPageEndPosition until the end of content is reached.
+ test_position = test_position->CreateNextPageEndPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
- EXPECT_EQ(page_1_data.id, test_position->anchor_id());
- EXPECT_EQ(1, test_position->child_index());
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
+ EXPECT_EQ(19, test_position->text_offset());
test_position = test_position->CreateNextPageEndPosition(
AXBoundaryBehavior::CrossBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
- EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->child_index());
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
+ EXPECT_EQ(24, test_position->text_offset());
test_position = test_position->CreateNextPageEndPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
- EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->child_index());
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
+ EXPECT_EQ(24, test_position->text_offset());
- // StopAtLastAnchorBoundary shouldn't move past the end of the document.
+ // StopAtLastAnchorBoundary shouldn't move past the end of the whole content.
test_position = test_position->CreateNextPageStartPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->child_index());
+ EXPECT_EQ(24, test_position->text_offset());
test_position = test_position->CreateNextPageEndPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->child_index());
+ EXPECT_EQ(24, test_position->text_offset());
// Moving forward past the end should return a null position.
TestPositionType null_position = test_position->CreateNextPageStartPosition(
@@ -4855,63 +5251,64 @@ TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTreePosition) {
EXPECT_NE(nullptr, null_position);
EXPECT_TRUE(null_position->IsNullPosition());
- // Now move backward through the document.
- tree_position = test_position->CreatePreviousPageEndPosition(
+ // Now move backward through the accessibility tree.
+ text_position = test_position->CreatePreviousPageEndPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
- EXPECT_NE(nullptr, tree_position);
- EXPECT_TRUE(tree_position->IsTreePosition());
- EXPECT_EQ(page_3_text_data.id, tree_position->anchor_id());
- EXPECT_EQ(0, tree_position->child_index());
+ EXPECT_NE(nullptr, text_position);
+ EXPECT_TRUE(text_position->IsTextPosition());
+ EXPECT_EQ(page_3_text_data.id, text_position->anchor_id());
+ EXPECT_EQ(24, text_position->text_offset());
- test_position = tree_position->CreatePreviousPageEndPosition(
+ test_position = text_position->CreatePreviousPageEndPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->child_index());
+ EXPECT_EQ(19, test_position->text_offset());
- test_position = tree_position->CreatePreviousPageEndPosition(
+ test_position = text_position->CreatePreviousPageEndPosition(
AXBoundaryBehavior::CrossBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(0, test_position->child_index());
+ EXPECT_EQ(19, test_position->text_offset());
test_position = test_position->CreatePreviousPageStartPosition(
AXBoundaryBehavior::CrossBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
- EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
+ EXPECT_EQ(0, test_position->text_offset());
test_position = test_position->CreatePreviousPageStartPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
- EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
+ EXPECT_EQ(0, test_position->text_offset());
test_position = test_position->CreatePreviousPageStartPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
- EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
+ EXPECT_EQ(0, test_position->text_offset());
- // StopAtLastAnchorBoundary shouldn't move past the start of the document.
+ // StopAtLastAnchorBoundary shouldn't move past the start of the whole
+ // content.
test_position = test_position->CreatePreviousPageStartPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
- EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
+ EXPECT_EQ(0, test_position->text_offset());
test_position = test_position->CreatePreviousPageEndPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
- EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
+ EXPECT_EQ(0, test_position->text_offset());
// Moving before the start should return a null position.
null_position = test_position->CreatePreviousPageStartPosition(
@@ -4925,47 +5322,13 @@ TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTreePosition) {
EXPECT_TRUE(null_position->IsNullPosition());
}
-TEST_F(AXPositionTest, CreatePagePositionWithNullPosition) {
- TestPositionType null_position = AXNodePosition::CreateNullPosition();
- ASSERT_NE(nullptr, null_position);
- TestPositionType test_position =
- null_position->CreatePreviousPageStartPosition(
- AXBoundaryBehavior::StopIfAlreadyAtBoundary);
- EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsNullPosition());
-
- test_position = null_position->CreateNextPageStartPosition(
- AXBoundaryBehavior::StopIfAlreadyAtBoundary);
- EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsNullPosition());
-
- test_position = null_position->CreatePreviousPageEndPosition(
- AXBoundaryBehavior::StopIfAlreadyAtBoundary);
- EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsNullPosition());
-
- test_position = null_position->CreatePreviousPageStartPosition(
- AXBoundaryBehavior::StopIfAlreadyAtBoundary);
- EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsNullPosition());
-}
-
-TEST_F(AXPositionTest, CreatePositionAtStartOfDocumentWithNullPosition) {
- TestPositionType null_position = AXNodePosition::CreateNullPosition();
- ASSERT_NE(nullptr, null_position);
- TestPositionType test_position =
- null_position->CreatePositionAtStartOfDocument();
- EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsNullPosition());
-}
-
-TEST_F(AXPositionTest, CreatePagePositionWithNonPaginatedDocument) {
+TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithNonPaginatedDocument) {
TestPositionType text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), static_text1_.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
ASSERT_NE(nullptr, text_position);
- // Non-paginated documents should move to the start of the document for
+ // Non-paginated documents should move to the start of the whole content for
// CreatePreviousPageStartPosition (treating the entire document as a single
// page)
TestPositionType test_position =
@@ -4991,7 +5354,7 @@ TEST_F(AXPositionTest, CreatePagePositionWithNonPaginatedDocument) {
EXPECT_TRUE(test_position->IsNullPosition());
// Since there are no distinct pages, CreateNextPageEndPosition should move
- // to the end of the document, as if it's one large page.
+ // to the end of the whole content, as if it's one large page.
test_position = text_position->CreateNextPageEndPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
EXPECT_NE(nullptr, test_position);
@@ -5000,158 +5363,1452 @@ TEST_F(AXPositionTest, CreatePagePositionWithNonPaginatedDocument) {
EXPECT_EQ(6, test_position->text_offset());
// CreatePreviousPageStartPosition should move back to the beginning of the
- // document
+ // whole content.
test_position = test_position->CreatePreviousPageStartPosition(
AXBoundaryBehavior::CrossBoundary);
EXPECT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(button_.id, test_position->anchor_id());
EXPECT_EQ(0, test_position->text_offset());
+}
- // Since there's no next page, CreateNextPageStartPosition should return a
- // null position
- test_position = test_position->CreateNextPageStartPosition(
- AXBoundaryBehavior::CrossBoundary);
+TEST_F(AXPositionTest, CreatePositionAtStartOfAXTreeWithNullPosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+
+ TestPositionType null_position = AXNodePosition::CreateNullPosition();
+ ASSERT_NE(nullptr, null_position);
+ TestPositionType test_position =
+ null_position->CreatePositionAtStartOfAXTree();
EXPECT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsNullPosition());
+ EXPECT_FALSE(test_position->AtStartOfAXTree());
+}
- // Since there's no previous page, CreatePreviousPageEndPosition should return
- // a null position
- test_position = text_position->CreatePreviousPageEndPosition(
- AXBoundaryBehavior::CrossBoundary);
+TEST_F(AXPositionTest, CreatePositionAtStartOfAXTreeWithTreePosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+ const AXTreeID views_tree_id = trees[0].GetTree()->GetAXTreeID();
+ const AXTreeID webpage_tree_id = trees[1].GetTree()->GetAXTreeID();
+ const AXTreeID iframe_tree_id = trees[2].GetTree()->GetAXTreeID();
+
+ TestPositionType tree_position = AXNodePosition::CreateTreePosition(
+ views_tree_id, window.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ TestPositionType test_position =
+ tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, window.id,
+ 1 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ views_tree_id, back_button.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ views_tree_id, back_button.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, web_view.id,
+ 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, web_view.id,
+ 1 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, root_web_area.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, root_web_area.id, 1 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, paragraph.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, paragraph.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ iframe_tree_id, iframe_root.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(iframe_tree_id, test_position->tree_id());
+ EXPECT_EQ(iframe_root.id, test_position->anchor_id());
+ EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ iframe_tree_id, iframe_root.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(iframe_tree_id, test_position->tree_id());
+ EXPECT_EQ(iframe_root.id, test_position->anchor_id());
+ EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
+}
+
+TEST_F(AXPositionTest, CreatePositionAtStartOfAXTreeWithTextPosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+ const AXTreeID views_tree_id = trees[0].GetTree()->GetAXTreeID();
+ const AXTreeID webpage_tree_id = trees[1].GetTree()->GetAXTreeID();
+ const AXTreeID iframe_tree_id = trees[2].GetTree()->GetAXTreeID();
+
+ TestPositionType text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, window.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ TestPositionType test_position =
+ text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, window.id, 4 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, back_button.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, back_button.id, 4 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, web_view.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, web_view.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, root_web_area.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, root_web_area.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, paragraph.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, paragraph.id, 12 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ iframe_tree_id, iframe_root.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(iframe_tree_id, test_position->tree_id());
+ EXPECT_EQ(iframe_root.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ iframe_tree_id, iframe_root.id, 13 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfAXTree());
+ EXPECT_EQ(iframe_tree_id, test_position->tree_id());
+ EXPECT_EQ(iframe_root.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+}
+
+TEST_F(AXPositionTest, CreatePositionAtEndOfAXTreeWithNullPosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+
+ TestPositionType null_position = AXNodePosition::CreateNullPosition();
+ ASSERT_NE(nullptr, null_position);
+ TestPositionType test_position = null_position->CreatePositionAtEndOfAXTree();
EXPECT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsNullPosition());
+ EXPECT_FALSE(test_position->AtEndOfAXTree());
+}
- // Since there's no previous page, CreatePreviousPageStartPosition should
- // return a null position
- test_position = text_position->CreatePreviousPageStartPosition(
- AXBoundaryBehavior::CrossBoundary);
+TEST_F(AXPositionTest, CreatePositionAtEndOfAXTreeWithTreePosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+ const AXTreeID views_tree_id = trees[0].GetTree()->GetAXTreeID();
+ const AXTreeID webpage_tree_id = trees[1].GetTree()->GetAXTreeID();
+ const AXTreeID iframe_tree_id = trees[2].GetTree()->GetAXTreeID();
+
+ TestPositionType tree_position = AXNodePosition::CreateTreePosition(
+ views_tree_id, window.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ TestPositionType test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, window.id,
+ 1 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ views_tree_id, back_button.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ views_tree_id, back_button.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, web_view.id,
+ 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, web_view.id,
+ 1 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, root_web_area.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, root_web_area.id, 1 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, paragraph.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, paragraph.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ iframe_tree_id, iframe_root.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(iframe_tree_id, test_position->tree_id());
+ EXPECT_EQ(iframe_root.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ iframe_tree_id, iframe_root.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(iframe_tree_id, test_position->tree_id());
+ EXPECT_EQ(iframe_root.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+}
+
+TEST_F(AXPositionTest, CreatePositionAtEndOfAXTreeWithTextPosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+ const AXTreeID views_tree_id = trees[0].GetTree()->GetAXTreeID();
+ const AXTreeID webpage_tree_id = trees[1].GetTree()->GetAXTreeID();
+ const AXTreeID iframe_tree_id = trees[2].GetTree()->GetAXTreeID();
+
+ TestPositionType text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, window.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ TestPositionType test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, window.id, 4 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, back_button.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, back_button.id, 4 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, web_view.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, web_view.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, root_web_area.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(12, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, root_web_area.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(12, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, paragraph.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(12, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, paragraph.id, 12 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(12, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ iframe_tree_id, iframe_root.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(iframe_tree_id, test_position->tree_id());
+ EXPECT_EQ(iframe_root.id, test_position->anchor_id());
+ EXPECT_EQ(13, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ iframe_tree_id, iframe_root.id, 13 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfAXTree();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfAXTree());
+ EXPECT_EQ(iframe_tree_id, test_position->tree_id());
+ EXPECT_EQ(iframe_root.id, test_position->anchor_id());
+ EXPECT_EQ(13, test_position->text_offset());
+}
+
+TEST_F(AXPositionTest, CreatePositionAtStartOfContentWithNullPosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+
+ TestPositionType null_position = AXNodePosition::CreateNullPosition();
+ ASSERT_NE(nullptr, null_position);
+ TestPositionType test_position =
+ null_position->CreatePositionAtStartOfContent();
EXPECT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsNullPosition());
}
-TEST_F(AXPositionTest, CreatePositionAtStartOfDocumentWithTreePosition) {
+TEST_F(AXPositionTest, CreatePositionAtStartOfContentWithTreePosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+ const AXTreeID views_tree_id = trees[0].GetTree()->GetAXTreeID();
+ const AXTreeID webpage_tree_id = trees[1].GetTree()->GetAXTreeID();
+ const AXTreeID iframe_tree_id = trees[2].GetTree()->GetAXTreeID();
+
TestPositionType tree_position = AXNodePosition::CreateTreePosition(
- GetTreeID(), root_.id, 0 /* child_index */);
+ views_tree_id, window.id, 0 /* child_index */);
ASSERT_NE(nullptr, tree_position);
TestPositionType test_position =
- tree_position->CreatePositionAtStartOfDocument();
- EXPECT_NE(nullptr, test_position);
- EXPECT_EQ(root_.id, test_position->anchor_id());
+ tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
- tree_position = AXNodePosition::CreateTreePosition(GetTreeID(), root_.id,
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, window.id,
1 /* child_index */);
ASSERT_NE(nullptr, tree_position);
- test_position = tree_position->CreatePositionAtStartOfDocument();
- EXPECT_NE(nullptr, test_position);
- EXPECT_EQ(root_.id, test_position->anchor_id());
+ test_position = tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
tree_position = AXNodePosition::CreateTreePosition(
- GetTreeID(), inline_box1_.id, 0 /* child_index */);
+ views_tree_id, back_button.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
ASSERT_NE(nullptr, tree_position);
- test_position = tree_position->CreatePositionAtStartOfDocument();
- EXPECT_NE(nullptr, test_position);
- EXPECT_EQ(root_.id, test_position->anchor_id());
+ test_position = tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ views_tree_id, back_button.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, web_view.id,
+ 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, web_view.id,
+ 1 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, root_web_area.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, root_web_area.id, 1 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, paragraph.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, paragraph.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ iframe_tree_id, iframe_root.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ iframe_tree_id, iframe_root.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
}
-TEST_F(AXPositionTest, CreatePositionAtStartOfDocumentWithTextPosition) {
+TEST_F(AXPositionTest, CreatePositionAtStartOfContentWithTextPosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+ const AXTreeID views_tree_id = trees[0].GetTree()->GetAXTreeID();
+ const AXTreeID webpage_tree_id = trees[1].GetTree()->GetAXTreeID();
+ const AXTreeID iframe_tree_id = trees[2].GetTree()->GetAXTreeID();
+
TestPositionType text_position = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 0 /* text_offset */,
+ views_tree_id, window.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
ASSERT_NE(nullptr, text_position);
TestPositionType test_position =
- text_position->CreatePositionAtStartOfDocument();
- EXPECT_NE(nullptr, test_position);
- EXPECT_EQ(root_.id, test_position->anchor_id());
+ text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
text_position = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 1 /* text_offset */,
- ax::mojom::TextAffinity::kUpstream);
+ views_tree_id, window.id, 4 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
ASSERT_NE(nullptr, text_position);
- test_position = text_position->CreatePositionAtStartOfDocument();
- EXPECT_NE(nullptr, test_position);
- EXPECT_EQ(root_.id, test_position->anchor_id());
- // Affinity should have been reset to the default value.
- EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
+ test_position = text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, back_button.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, back_button.id, 4 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, web_view.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, web_view.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(window.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, root_web_area.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, root_web_area.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, paragraph.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, paragraph.id, 12 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ iframe_tree_id, iframe_root.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ iframe_tree_id, iframe_root.id, 13 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtStartOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtStartOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(root_web_area.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
}
-TEST_F(AXPositionTest, CreatePositionAtEndOfDocumentWithNullPosition) {
+TEST_F(AXPositionTest, CreatePositionAtEndOfContentWithNullPosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+
TestPositionType null_position = AXNodePosition::CreateNullPosition();
ASSERT_NE(nullptr, null_position);
TestPositionType test_position =
- null_position->CreatePositionAtEndOfDocument();
+ null_position->CreatePositionAtEndOfContent();
EXPECT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsNullPosition());
}
-TEST_F(AXPositionTest, CreatePositionAtEndOfDocumentWithTreePosition) {
+TEST_F(AXPositionTest, CreatePositionAtEndOfContentWithTreePosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+ const AXTreeID views_tree_id = trees[0].GetTree()->GetAXTreeID();
+ const AXTreeID webpage_tree_id = trees[1].GetTree()->GetAXTreeID();
+ const AXTreeID iframe_tree_id = trees[2].GetTree()->GetAXTreeID();
+
TestPositionType tree_position = AXNodePosition::CreateTreePosition(
- GetTreeID(), root_.id, 3 /* child_index */);
+ views_tree_id, window.id, 0 /* child_index */);
ASSERT_NE(nullptr, tree_position);
TestPositionType test_position =
- tree_position->CreatePositionAtEndOfDocument();
- EXPECT_NE(nullptr, test_position);
- EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
+ tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
- tree_position = AXNodePosition::CreateTreePosition(GetTreeID(), root_.id,
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, window.id,
1 /* child_index */);
ASSERT_NE(nullptr, tree_position);
- test_position = tree_position->CreatePositionAtEndOfDocument();
- EXPECT_NE(nullptr, test_position);
- EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
+ test_position = tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
tree_position = AXNodePosition::CreateTreePosition(
- GetTreeID(), inline_box1_.id, 0 /* child_index */);
+ views_tree_id, back_button.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
ASSERT_NE(nullptr, tree_position);
- test_position = tree_position->CreatePositionAtEndOfDocument();
- EXPECT_NE(nullptr, test_position);
- EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
+ test_position = tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ views_tree_id, back_button.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, web_view.id,
+ 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(views_tree_id, web_view.id,
+ 1 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, root_web_area.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, root_web_area.id, 1 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, paragraph.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ webpage_tree_id, paragraph.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ iframe_tree_id, iframe_root.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ iframe_tree_id, iframe_root.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(0, test_position->child_index());
}
-TEST_F(AXPositionTest, CreatePositionAtEndOfDocumentWithTextPosition) {
+TEST_F(AXPositionTest, CreatePositionAtEndOfContentWithTextPosition) {
+ // Create three accessibility trees as follows:
+ //
+ // Window (First tree)
+ // ++NonClientView
+ // ++++BrowserView
+ // ++++++ToolbarView
+ // ++++++++kButton name="Back"
+ // ++++WebView
+ // ++++++kRootWebArea (Second tree)
+ // ++++++++kIframe
+ // ++++++++++kRootWebArea name="Inside iframe" (Third tree)
+ // ++++++++kParagraph name="After iframe"
+ // ++++TextField (Address bar - part of first tree.)
+ AXNodeData window, back_button, web_view, root_web_area, iframe_root,
+ paragraph, address_bar;
+ std::vector<TestAXTreeManager> trees;
+ ASSERT_NO_FATAL_FAILURE(CreateBrowserWindow(window, back_button, web_view,
+ root_web_area, iframe_root,
+ paragraph, address_bar, trees));
+ const AXTreeID views_tree_id = trees[0].GetTree()->GetAXTreeID();
+ const AXTreeID webpage_tree_id = trees[1].GetTree()->GetAXTreeID();
+ const AXTreeID iframe_tree_id = trees[2].GetTree()->GetAXTreeID();
+
TestPositionType text_position = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 6 /* text_offset */,
+ views_tree_id, window.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
ASSERT_NE(nullptr, text_position);
TestPositionType test_position =
- text_position->CreatePositionAtEndOfDocument();
- EXPECT_NE(nullptr, test_position);
- EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
+ text_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
text_position = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 5 /* text_offset */,
- ax::mojom::TextAffinity::kUpstream);
+ views_tree_id, window.id, 4 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
ASSERT_NE(nullptr, text_position);
- test_position = text_position->CreatePositionAtEndOfDocument();
- EXPECT_NE(nullptr, test_position);
- EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
- // Affinity should have been reset to the default value.
- EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
-}
+ test_position = text_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
-TEST_F(AXPositionTest, AtLastNodeInTree) {
- TestPositionType text_position = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 6 /* text_offset */,
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, back_button.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
ASSERT_NE(nullptr, text_position);
- EXPECT_FALSE(text_position->AtLastNodeInTree());
- EXPECT_FALSE(text_position->AsTreePosition()->AtLastNodeInTree());
+ test_position = text_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
- TestPositionType test_position =
- text_position->CreatePositionAtEndOfDocument();
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, back_button.id, 4 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfContent();
ASSERT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->AtLastNodeInTree());
- EXPECT_TRUE(test_position->AsTreePosition()->AtLastNodeInTree());
- EXPECT_FALSE(text_position->CreateNullPosition()->AtLastNodeInTree());
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
- TestPositionType on_last_node_but_not_at_maxtextoffset =
- AXNodePosition::CreateTextPosition(GetTreeID(), inline_box2_.id,
- 1 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_NE(nullptr, on_last_node_but_not_at_maxtextoffset);
- EXPECT_TRUE(on_last_node_but_not_at_maxtextoffset->AtLastNodeInTree());
- EXPECT_TRUE(on_last_node_but_not_at_maxtextoffset->AsTreePosition()
- ->AtLastNodeInTree());
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, web_view.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ views_tree_id, web_view.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(views_tree_id, test_position->tree_id());
+ EXPECT_EQ(address_bar.id, test_position->anchor_id());
+ EXPECT_EQ(8, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, root_web_area.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(12, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, root_web_area.id, 12 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(12, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, paragraph.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(12, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ webpage_tree_id, paragraph.id, 12 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(12, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ iframe_tree_id, iframe_root.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(12, test_position->text_offset());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ iframe_tree_id, iframe_root.id, 13 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreatePositionAtEndOfContent();
+ ASSERT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition());
+ EXPECT_TRUE(test_position->AtEndOfContent());
+ EXPECT_EQ(webpage_tree_id, test_position->tree_id());
+ EXPECT_EQ(paragraph.id, test_position->anchor_id());
+ EXPECT_EQ(12, test_position->text_offset());
}
TEST_F(AXPositionTest, CreateChildPositionAtWithNullPosition) {
@@ -5214,22 +6871,76 @@ TEST_F(AXPositionTest, CreateParentPositionWithNullPosition) {
TEST_F(AXPositionTest, CreateParentPositionWithTreePosition) {
TestPositionType tree_position = AXNodePosition::CreateTreePosition(
- GetTreeID(), check_box_.id, 0 /* child_index */);
+ GetTreeID(), check_box_.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
ASSERT_NE(nullptr, tree_position);
TestPositionType test_position = tree_position->CreateParentPosition();
EXPECT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTreePosition());
EXPECT_EQ(root_.id, test_position->anchor_id());
- // |child_index| should point to the check box node.
+ // |child_index| should point to the check box node because the original
+ // position was a "before text" position on the check box.
EXPECT_EQ(1, test_position->child_index());
- EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
+
+ // Create a position that points at the end of the first line, right after the
+ // check box: an "after text" position on the check box.
+ tree_position = AXNodePosition::CreateTreePosition(GetTreeID(), check_box_.id,
+ 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ test_position = tree_position->CreateParentPosition();
+ EXPECT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_EQ(root_.id, test_position->anchor_id());
+ // |child_index| should point to after the check box node because the original
+ // position was an "after text" position.
+ EXPECT_EQ(2, test_position->child_index());
tree_position = AXNodePosition::CreateTreePosition(GetTreeID(), root_.id,
1 /* child_index */);
ASSERT_NE(nullptr, tree_position);
test_position = tree_position->CreateParentPosition();
EXPECT_NE(nullptr, test_position);
- EXPECT_TRUE(test_position->IsNullPosition());
+ EXPECT_TRUE(test_position->IsTreePosition())
+ << "We should cross into a minimalistic Views tree.";
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box2_.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ ASSERT_TRUE(tree_position->IsTreePosition());
+
+ test_position = tree_position->CreateParentPosition();
+ EXPECT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_EQ(static_text2_.id, test_position->anchor_id());
+ // A "before text" position on the inline text box should result in a "before
+ // children" position on the static text parent.
+ EXPECT_EQ(0, test_position->child_index());
+
+ test_position = test_position->CreateParentPosition();
+ EXPECT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_EQ(text_field_.id, test_position->anchor_id());
+ EXPECT_EQ(2, test_position->child_index());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box2_.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ ASSERT_TRUE(tree_position->IsTreePosition());
+
+ test_position = tree_position->CreateParentPosition();
+ EXPECT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_EQ(static_text2_.id, test_position->anchor_id());
+ // An "After text" position on the inline text box should result in an "after
+ // children" position on the static text parent.
+ EXPECT_EQ(1, test_position->child_index());
+
+ test_position = test_position->CreateParentPosition();
+ EXPECT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTreePosition());
+ EXPECT_EQ(text_field_.id, test_position->anchor_id());
+ EXPECT_EQ(3, test_position->child_index());
}
TEST_F(AXPositionTest, CreateParentPositionWithTextPosition) {
@@ -5245,16 +6956,23 @@ TEST_F(AXPositionTest, CreateParentPositionWithTextPosition) {
EXPECT_TRUE(test_position->IsTextPosition());
EXPECT_EQ(root_.id, test_position->anchor_id());
EXPECT_EQ(0, test_position->text_offset());
- // Since the same text offset in the root could be used to point to the
- // beginning of the second line, affinity should have been adjusted to
- // upstream.
- EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, test_position->affinity());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root_.id, 2 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ test_position = text_position->CreateParentPosition();
+ EXPECT_NE(nullptr, test_position);
+ EXPECT_TRUE(test_position->IsTextPosition())
+ << "We should cross into a minimalistic Views tree.";
text_position = AXNodePosition::CreateTextPosition(
GetTreeID(), inline_box2_.id, 5 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
ASSERT_NE(nullptr, text_position);
ASSERT_TRUE(text_position->IsTextPosition());
+
test_position = text_position->CreateParentPosition();
EXPECT_NE(nullptr, test_position);
EXPECT_TRUE(test_position->IsTextPosition());
@@ -5272,6 +6990,1115 @@ TEST_F(AXPositionTest, CreateParentPositionWithTextPosition) {
EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
}
+TEST_F(AXPositionTest, CreateParentPositionWithMoveDirection) {
+ // This test only applies when "object replacement characters" are used in the
+ // accessibility tree, e.g., in IAccessible2, UI Automation and Linux ATK
+ // APIs.
+ g_ax_embedded_object_behavior = AXEmbeddedObjectBehavior::kExposeCharacter;
+
+ // This test ensures that "CreateParentPosition" (and by extension
+ // "CreateAncestorPosition") works correctly when it is given either a tree or
+ // a text position whose parent position is inside an "object replacement
+ // character". The resulting parent position should be either before or after
+ // the "object replacement character", based on the provided move direction.
+ //
+ // Nodes represented by an embedded object character, such as a link, a
+ // paragraph, a text field or a check box, may create an ambiguity as to where
+ // the parent position should be located. For example, look at the following
+ // accessibility tree.
+ //
+ // ++1 kRootWebArea isLineBreakingObject
+ // ++++2 kLink "<embedded_object>"
+ // ++++++3 kStaticText "Hello"
+ // ++++++++4 kInlineTextBox "hello"
+ // ++++++5 kParagraph "<embedded_object>"
+ // ++++++++6 kStaticText "world."
+ // ++++++++++7 kInlineTextBox "world."
+ //
+ // The parent position of a text position inside the inline text box with the
+ // word "world", may either be before or after the paragraph. They are both
+ // equally valid and the choice depends on which navigation operation we are
+ // trying to accomplish, e.g. move to the start of the line vs. the end.
+
+ AXNodeData root_1;
+ AXNodeData link_2;
+ AXNodeData static_text_3;
+ AXNodeData inline_box_4;
+ AXNodeData paragraph_5;
+ AXNodeData static_text_6;
+ AXNodeData inline_box_7;
+
+ root_1.id = 1;
+ link_2.id = 2;
+ static_text_3.id = 3;
+ inline_box_4.id = 4;
+ paragraph_5.id = 5;
+ static_text_6.id = 6;
+ inline_box_7.id = 7;
+
+ root_1.role = ax::mojom::Role::kRootWebArea;
+ root_1.child_ids = {link_2.id};
+ root_1.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+
+ link_2.role = ax::mojom::Role::kLink;
+ link_2.child_ids = {static_text_3.id, paragraph_5.id};
+
+ static_text_3.role = ax::mojom::Role::kStaticText;
+ static_text_3.child_ids = {inline_box_4.id};
+ static_text_3.SetName("Hello");
+
+ inline_box_4.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_4.SetName("Hello");
+
+ paragraph_5.role = ax::mojom::Role::kParagraph;
+ paragraph_5.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+ paragraph_5.child_ids = {static_text_6.id};
+
+ static_text_6.role = ax::mojom::Role::kStaticText;
+ static_text_6.child_ids = {inline_box_7.id};
+ static_text_6.SetName("world.");
+
+ inline_box_7.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_7.SetName("world.");
+
+ SetTree(CreateAXTree({root_1, link_2, static_text_3, inline_box_4,
+ paragraph_5, static_text_6, inline_box_7}));
+
+ //
+ // Tree positions.
+ //
+
+ // Find the equivalent position on the root, when the original position is
+ // before "Hello", with a forward direction.
+ TestPositionType tree_position = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_4.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ TestPositionType ancestor_position = tree_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTreePosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The child index should be before the "object replacement character" for the
+ // link in the root's text, because the original index was before "Hello",
+ // i.e., before all the text contained in the link. The move direction should
+ // not matter.
+ EXPECT_EQ(0, ancestor_position->child_index());
+
+ // Find the equivalent position on the root, when the original position is
+ // before "Hello", with a backward direction.
+ tree_position = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_4.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ ancestor_position = tree_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTreePosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The child index should be before the "object replacement character" for the
+ // link in the root's text, because the original index was before "Hello",
+ // i.e., before all the text contained in the link. The move direction should
+ // not matter.
+ EXPECT_EQ(0, ancestor_position->child_index());
+
+ // Find the equivalent position on the root, when the original position is
+ // after "Hello", with a forward direction.
+ tree_position = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_4.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ ancestor_position = tree_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTreePosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The child index should be after the "object replacement character" for the
+ // link in the root's text, because the original index was after "Hello",
+ // i.e., in the middle of the link's text, and the direction was forward.
+ EXPECT_EQ(1, ancestor_position->child_index());
+
+ // Find the equivalent position on the root, when the original position is
+ // after "Hello", with a backward direction.
+ tree_position = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_4.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ ancestor_position = tree_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTreePosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The child index should be before the "object replacement character" for the
+ // link in the root's text, because even though the original index was after
+ // "Hello" the direction was backward.
+ EXPECT_EQ(0, ancestor_position->child_index());
+
+ // Find the equivalent position on the root, when the original position is
+ // after "world.", with a forward direction.
+ tree_position = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_7.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ ancestor_position = tree_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTreePosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The child index should be after the "object replacement character" for the
+ // link in the root's text, because the original index was after "world.",
+ // i.e., after all of the text in the link. The move direction should not
+ // matter.
+ EXPECT_EQ(1, ancestor_position->child_index());
+
+ // Find the equivalent position on the root, when the original position is
+ // after "world.", with a backward direction.
+ tree_position = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_7.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ ancestor_position = tree_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTreePosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The child index should be after the "object replacement character" for the
+ // link in the root's text, because the original index was after "world.",
+ // i.e., after all of the text in the link. The move direction should not
+ // matter.
+ EXPECT_EQ(1, ancestor_position->child_index());
+
+ //
+ // Text positions.
+ //
+
+ // Find the equivalent position on the root, when the original position is
+ // before "Hello", with a forward direction.
+ TestPositionType text_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_4.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ ancestor_position = text_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTextPosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The text offset should be before the "object replacement character" for the
+ // link in the root's text, because the original offset was before "Hello",
+ // i.e., before all the text contained in the link. The move direction should
+ // not matter.
+ EXPECT_EQ(0, ancestor_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream,
+ ancestor_position->affinity());
+
+ // Find the equivalent position on the root, when the original position is
+ // before "Hello", with a backward direction.
+ text_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_4.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ ancestor_position = text_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTextPosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The text offset should be before the "object replacement character" for the
+ // link in the root's text, because the original offset was before "Hello",
+ // i.e., before all the text contained in the link. The move direction should
+ // not matter.
+ EXPECT_EQ(0, ancestor_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream,
+ ancestor_position->affinity());
+
+ // Find the equivalent position on the root, when the original position is
+ // after "Hello", with a forward direction.
+ text_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_4.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ ancestor_position = text_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTextPosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The text offset should be after the "object replacement character" for the
+ // link in the root's text, because the original offset was after "Hello" and
+ // the move direction was forward.
+ EXPECT_EQ(1, ancestor_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream,
+ ancestor_position->affinity());
+
+ // Find the equivalent position on the root, when the original position is
+ // after "Hello", with a backward direction.
+ text_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_4.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ ancestor_position = text_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTextPosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The text offset should be before the "object replacement character" for the
+ // link in the root's text, because even though the original offset was after
+ // "Hello", the move direction was backward.
+ EXPECT_EQ(0, ancestor_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream,
+ ancestor_position->affinity());
+
+ // Find the equivalent position on the root, when the original position is
+ // inside "world.", with a forward direction.
+ text_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_7.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ ancestor_position = text_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTextPosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The text offset should be after the "object replacement character" for the
+ // link in the root's text, because the original offset was inside "world."
+ // and the move direction was forward.
+ EXPECT_EQ(1, ancestor_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream,
+ ancestor_position->affinity());
+
+ // Find the equivalent position on the root, when the original position is
+ // inside "world.", with a backward direction.
+ text_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_7.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ ancestor_position = text_position->CreateAncestorPosition(
+ GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+ ASSERT_NE(nullptr, ancestor_position);
+ EXPECT_TRUE(ancestor_position->IsTextPosition());
+ EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
+ // The text offset should be before the "object replacement character" for the
+ // link in the root's text, because even though the original offset was inside
+ // "world.", the move direction was backward.
+ EXPECT_EQ(0, ancestor_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream,
+ ancestor_position->affinity());
+}
+
+TEST_F(AXPositionTest, CreateParentAndLeafPositionWithIgnoredNodes) {
+ // The text of ignored nodes should not be visible in the tree's text
+ // representation, but the text of their unignored children should.
+ // `AXPosition::CreateParentPosition` should be able to work even when called
+ // on an ignored position, and it should also be able to produce parent
+ // positions on ignored nodes that have the correct text offset and affinity.
+ // `AXPosition::AsLeafTextPosition`, on the other hand, should skip all
+ // ignored nodes.
+ //
+ // Simulate a tree with two lines of text and some ignored nodes between them:
+ // ++kRootWebArea "HelloWorld"
+ // ++++kGenericContainer ignored
+ // ++++++kStaticText "Hello"
+ // ++++++++kInlineTextBox "Hello"
+ // ++++kStaticText "Ignored1"
+ // ++++++kInlineTextBox "Ignored1"
+ // ++++kStaticText "Ignored2"
+ // ++++++kInlineTextBox "Ignored2"
+ // ++++kStaticText "World"
+ // ++++++kInlineTextBox "World"
+ AXNodeData root;
+ AXNodeData generic_container_ignored;
+ AXNodeData static_text_1;
+ AXNodeData inline_box_1;
+ AXNodeData static_text_ignored_1;
+ AXNodeData inline_box_ignored_1;
+ AXNodeData static_text_ignored_2;
+ AXNodeData inline_box_ignored_2;
+ AXNodeData static_text_2;
+ AXNodeData inline_box_2;
+
+ root.id = 1;
+ generic_container_ignored.id = 2;
+ static_text_1.id = 3;
+ inline_box_1.id = 4;
+ static_text_2.id = 5;
+ inline_box_2.id = 6;
+ static_text_ignored_1.id = 7;
+ inline_box_ignored_1.id = 8;
+ static_text_ignored_2.id = 9;
+ inline_box_ignored_2.id = 10;
+
+ root.role = ax::mojom::Role::kRootWebArea;
+ root.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ root.child_ids = {generic_container_ignored.id, static_text_ignored_1.id,
+ static_text_ignored_2.id, static_text_2.id};
+
+ generic_container_ignored.role = ax::mojom::Role::kGenericContainer;
+ generic_container_ignored.AddState(ax::mojom::State::kIgnored);
+ generic_container_ignored.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ generic_container_ignored.child_ids = {static_text_1.id};
+
+ static_text_1.role = ax::mojom::Role::kStaticText;
+ static_text_1.SetName("Hello");
+ static_text_1.child_ids = {inline_box_1.id};
+
+ inline_box_1.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_1.SetName("Hello");
+
+ static_text_ignored_1.role = ax::mojom::Role::kStaticText;
+ static_text_ignored_1.AddState(ax::mojom::State::kIgnored);
+ static_text_ignored_1.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ static_text_ignored_1.SetName("Ignored1");
+ static_text_ignored_1.child_ids = {inline_box_ignored_1.id};
+
+ inline_box_ignored_1.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_ignored_1.AddState(ax::mojom::State::kIgnored);
+ inline_box_ignored_1.SetName("Ignored1");
+
+ static_text_ignored_2.role = ax::mojom::Role::kStaticText;
+ static_text_ignored_2.AddState(ax::mojom::State::kIgnored);
+ static_text_ignored_2.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ static_text_ignored_2.SetName("Ignored2");
+ static_text_ignored_2.child_ids = {inline_box_ignored_2.id};
+
+ inline_box_ignored_2.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_ignored_2.AddState(ax::mojom::State::kIgnored);
+ inline_box_ignored_2.SetName("Ignored2");
+
+ static_text_2.role = ax::mojom::Role::kStaticText;
+ static_text_2.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ static_text_2.SetName("World");
+ static_text_2.child_ids = {inline_box_2.id};
+
+ inline_box_2.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_2.SetName("World");
+
+ SetTree(CreateAXTree({root, generic_container_ignored, static_text_1,
+ inline_box_1, static_text_ignored_1,
+ inline_box_ignored_1, static_text_ignored_2,
+ inline_box_ignored_2, static_text_2, inline_box_2}));
+
+ // "<H>elloWorld"
+ TestPositionType before_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_root->IsNullPosition());
+
+ // "Hello<W>orld"
+ // On the end of the first line after "Hello".
+ TestPositionType middle_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(middle_root->IsNullPosition());
+
+ // "Hello<W>orld"
+ // At the start of the second line before "World".
+ TestPositionType middle_root_upstream = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kUpstream);
+ ASSERT_FALSE(middle_root_upstream->IsNullPosition());
+
+ // "HelloWorld<>"
+ // Note that since this is the end of content there is no next line after the
+ // end of the root, so a downstream affinity would still work even though
+ // technically the position is at the end of the last line.
+ TestPositionType after_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 10 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(after_root->IsNullPosition());
+
+ // "<H>ello"
+ TestPositionType before_inline_box_1 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_1.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_inline_box_1->IsNullPosition());
+ // "Hello<>"
+ TestPositionType after_inline_box_1 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_1.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(after_inline_box_1->IsNullPosition());
+
+ // "<I>gnored1"
+ TestPositionType before_inline_box_ignored_1 =
+ AXNodePosition::CreateTextPosition(GetTreeID(), inline_box_ignored_1.id,
+ 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_inline_box_ignored_1->IsNullPosition());
+ ASSERT_TRUE(before_inline_box_ignored_1->IsIgnored());
+
+ TestPositionType before_inline_box_ignored_1_tree =
+ AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_ignored_1.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_FALSE(before_inline_box_ignored_1_tree->IsNullPosition());
+ ASSERT_TRUE(before_inline_box_ignored_1_tree->IsIgnored());
+ TestPositionType after_inline_box_ignored_1_tree =
+ AXNodePosition::CreateTreePosition(GetTreeID(), inline_box_ignored_1.id,
+ 0 /* child_index */);
+ ASSERT_FALSE(after_inline_box_ignored_1_tree->IsNullPosition());
+ ASSERT_TRUE(after_inline_box_ignored_1_tree->IsIgnored());
+
+ // "<I>gnored2"
+ TestPositionType before_inline_box_ignored_2 =
+ AXNodePosition::CreateTextPosition(GetTreeID(), inline_box_ignored_2.id,
+ 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_inline_box_ignored_2->IsNullPosition());
+ ASSERT_TRUE(before_inline_box_ignored_2->IsIgnored());
+
+ TestPositionType before_inline_box_ignored_2_tree =
+ AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_ignored_2.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_FALSE(before_inline_box_ignored_2_tree->IsNullPosition());
+ ASSERT_TRUE(before_inline_box_ignored_2_tree->IsIgnored());
+ TestPositionType after_inline_box_ignored_2_tree =
+ AXNodePosition::CreateTreePosition(GetTreeID(), inline_box_ignored_2.id,
+ 0 /* child_index */);
+ ASSERT_FALSE(after_inline_box_ignored_2_tree->IsNullPosition());
+ ASSERT_TRUE(after_inline_box_ignored_2_tree->IsIgnored());
+
+ // "<W>orld"
+ TestPositionType before_inline_box_2 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_2.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_inline_box_2->IsNullPosition());
+ // "World<>"
+ TestPositionType after_inline_box_2 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_2.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(after_inline_box_2->IsNullPosition());
+
+ TestPositionType parent_position =
+ before_inline_box_1->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(generic_container_ignored.id, parent_position->anchor_id());
+ EXPECT_EQ(0, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, parent_position->affinity());
+
+ TestPositionType leaf_position = before_root->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ EXPECT_EQ(inline_box_1.id, leaf_position->anchor_id());
+ EXPECT_EQ(0, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+
+ // `inline_box_1` is on a different line from `inline_box_2`, hence the
+ // equivalent position on the root should have an upstream affinity, despite
+ // the fact that the intermitiary parent position is on an ignored generic
+ // container.
+ parent_position =
+ after_inline_box_1->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsIgnored());
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(generic_container_ignored.id, parent_position->anchor_id());
+ EXPECT_EQ(5, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, parent_position->affinity());
+ // Move one more level up to get to the root.
+ parent_position = parent_position->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_FALSE(parent_position->IsIgnored());
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(5, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, parent_position->affinity());
+
+ leaf_position = middle_root_upstream->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ EXPECT_EQ(inline_box_1.id, leaf_position->anchor_id());
+ EXPECT_EQ(5, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+
+ // By design, positions on ignored nodes between the two lines will be
+ // considered as part of the previous line when finding the unignored root
+ // equivalent position.
+ parent_position = before_inline_box_ignored_1->CreateParentPosition()
+ ->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(5, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, parent_position->affinity());
+
+ parent_position = before_inline_box_ignored_1_tree->CreateParentPosition()
+ ->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(1, parent_position->child_index());
+
+ parent_position = after_inline_box_ignored_1_tree->CreateParentPosition()
+ ->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(2, parent_position->child_index());
+
+ parent_position = before_inline_box_ignored_2->CreateParentPosition()
+ ->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(5, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, parent_position->affinity());
+
+ parent_position = before_inline_box_ignored_2_tree->CreateParentPosition()
+ ->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(2, parent_position->child_index());
+
+ parent_position = after_inline_box_ignored_2_tree->CreateParentPosition()
+ ->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(3, parent_position->child_index());
+
+ // `inline_box_2` is on the next line, hence the root equivalent position
+ // should have a downstream affinity.
+ parent_position =
+ before_inline_box_2->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(5, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, parent_position->affinity());
+
+ leaf_position = middle_root->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ EXPECT_EQ(inline_box_2.id, leaf_position->anchor_id());
+ EXPECT_EQ(0, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+
+ parent_position =
+ after_inline_box_2->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(10, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, parent_position->affinity());
+
+ leaf_position = after_root->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ EXPECT_EQ(inline_box_2.id, leaf_position->anchor_id());
+ EXPECT_EQ(5, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+}
+
+TEST_F(AXPositionTest, CreateParentAndLeafPositionWithEmptyNodes) {
+ // `AXPosition::CreateParentPosition` should be able to work even when called
+ // on a position that is anchored to a node with no text in it, such as a
+ // button with no value or inner text. Similarly,
+ // `AXPosition::AsLeafTextPosition` should not skip any empty nodes.
+ //
+ // Simulate a tree with two lines of text and some empty nodes between them:
+ // ++kRootWebArea "HelloWorld"
+ // ++++kCheckbox "Hello"
+ // ++++++kStaticText "Hello"
+ // ++++++++kInlineTextBox "Hello"
+ // ++++kStaticText ""
+ // ++++++kInlineTextBox ""
+ // ++++kButton (empty)
+ // ++++kStaticText "World"
+ // ++++++kInlineTextBox "World"
+ AXNodeData root;
+ AXNodeData check_box;
+ AXNodeData static_text_1;
+ AXNodeData inline_box_1;
+ AXNodeData static_text_empty;
+ AXNodeData inline_box_empty;
+ AXNodeData button_empty;
+ AXNodeData static_text_2;
+ AXNodeData inline_box_2;
+
+ root.id = 1;
+ check_box.id = 2;
+ static_text_1.id = 3;
+ inline_box_1.id = 4;
+ static_text_empty.id = 5;
+ inline_box_empty.id = 6;
+ button_empty.id = 7;
+ static_text_2.id = 8;
+ inline_box_2.id = 9;
+
+ root.role = ax::mojom::Role::kRootWebArea;
+ root.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ root.child_ids = {check_box.id, static_text_empty.id, button_empty.id,
+ static_text_2.id};
+
+ check_box.role = ax::mojom::Role::kCheckBox;
+ check_box.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+ check_box.child_ids = {static_text_1.id};
+
+ static_text_1.role = ax::mojom::Role::kStaticText;
+ static_text_1.SetName("Hello");
+ static_text_1.child_ids = {inline_box_1.id};
+
+ inline_box_1.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_1.SetName("Hello");
+
+ static_text_empty.role = ax::mojom::Role::kStaticText;
+ static_text_empty.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ static_text_empty.child_ids = {inline_box_empty.id};
+
+ inline_box_empty.role = ax::mojom::Role::kInlineTextBox;
+
+ button_empty.role = ax::mojom::Role::kButton;
+ button_empty.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+
+ static_text_2.role = ax::mojom::Role::kStaticText;
+ static_text_2.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ static_text_2.SetName("World");
+ static_text_2.child_ids = {inline_box_2.id};
+
+ inline_box_2.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_2.SetName("World");
+
+ SetTree(CreateAXTree({root, check_box, static_text_1, inline_box_1,
+ static_text_empty, inline_box_empty, button_empty,
+ static_text_2, inline_box_2}));
+
+ // "<H>elloWorld"
+ TestPositionType before_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_root->IsNullPosition());
+ // "Hello<W>orld"
+ TestPositionType middle_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(middle_root->IsNullPosition());
+ TestPositionType middle_root_upstream = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kUpstream);
+ ASSERT_FALSE(middle_root_upstream->IsNullPosition());
+ // "HelloWorld<>"
+ TestPositionType after_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 10 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(after_root->IsNullPosition());
+
+ // "<H>ello"
+ TestPositionType before_inline_box_1 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_1.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_inline_box_1->IsNullPosition());
+ // "Hello<>"
+ TestPositionType after_inline_box_1 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_1.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(after_inline_box_1->IsNullPosition());
+
+ TestPositionType before_inline_box_empty = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_empty.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_inline_box_empty->IsNullPosition());
+
+ TestPositionType before_inline_box_empty_tree =
+ AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_empty.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_FALSE(before_inline_box_empty_tree->IsNullPosition());
+ TestPositionType after_inline_box_empty_tree =
+ AXNodePosition::CreateTreePosition(GetTreeID(), inline_box_empty.id,
+ 0 /* child_index */);
+ ASSERT_FALSE(after_inline_box_empty_tree->IsNullPosition());
+
+ TestPositionType before_button_empty = AXNodePosition::CreateTextPosition(
+ GetTreeID(), button_empty.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_button_empty->IsNullPosition());
+
+ TestPositionType before_button_empty_tree =
+ AXNodePosition::CreateTreePosition(
+ GetTreeID(), button_empty.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_FALSE(before_button_empty_tree->IsNullPosition());
+ TestPositionType after_button_empty_tree = AXNodePosition::CreateTreePosition(
+ GetTreeID(), button_empty.id, 0 /* child_index */);
+ ASSERT_FALSE(after_button_empty_tree->IsNullPosition());
+
+ // "<W>orld"
+ TestPositionType before_inline_box_2 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_2.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_inline_box_2->IsNullPosition());
+ // "World<>"
+ TestPositionType after_inline_box_2 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_2.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(after_inline_box_2->IsNullPosition());
+
+ TestPositionType parent_position =
+ before_inline_box_1->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(check_box.id, parent_position->anchor_id());
+ EXPECT_EQ(0, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, parent_position->affinity());
+
+ TestPositionType leaf_position = before_root->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ EXPECT_EQ(inline_box_1.id, leaf_position->anchor_id());
+ EXPECT_EQ(0, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+
+ // `inline_box_1` is on a different line from `inline_box_2`, hence the
+ // equivalent position on the check box should have had an upstream affinity.
+ // However, since there are a handful of empty nodes between the check box and
+ // the second line, those empty nodes form the end of the line, not the check
+ // box.
+ parent_position =
+ after_inline_box_1->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(check_box.id, parent_position->anchor_id());
+ EXPECT_EQ(5, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, parent_position->affinity());
+
+ leaf_position = middle_root_upstream->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ EXPECT_EQ(inline_box_1.id, leaf_position->anchor_id());
+ EXPECT_EQ(5, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+
+ // By design, positions on empty nodes between the two lines will be
+ // considered as part of the previous line when finding the unignored root
+ // equivalent position.
+ parent_position =
+ before_inline_box_empty->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(5, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, parent_position->affinity());
+
+ parent_position = before_inline_box_empty_tree->CreateParentPosition()
+ ->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(1, parent_position->child_index());
+
+ parent_position = after_inline_box_empty_tree->CreateParentPosition()
+ ->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(2, parent_position->child_index());
+
+ parent_position = before_button_empty->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(5, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, parent_position->affinity());
+
+ parent_position = before_button_empty_tree->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(2, parent_position->child_index());
+
+ parent_position = after_button_empty_tree->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(3, parent_position->child_index());
+
+ // `inline_box_2` is on the next line, hence the root equivalent position
+ // should have a downstream affinity.
+ parent_position =
+ before_inline_box_2->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(5, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, parent_position->affinity());
+
+ leaf_position = middle_root->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ // Empty nodes should not be skipped when finding the leaf equivalent
+ // position. (inline_box_empty and not inline_box_2.)
+ EXPECT_EQ(inline_box_empty.id, leaf_position->anchor_id());
+ EXPECT_EQ(0, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+
+ parent_position =
+ after_inline_box_2->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(10, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, parent_position->affinity());
+
+ leaf_position = after_root->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ EXPECT_EQ(inline_box_2.id, leaf_position->anchor_id());
+ EXPECT_EQ(5, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+}
+
+TEST_F(AXPositionTest, CreateParentAndLeafPositionWithEmbeddedObjects) {
+ g_ax_embedded_object_behavior = AXEmbeddedObjectBehavior::kExposeCharacter;
+
+ // ++kRootWebArea "<embedded>Hello<embedded>"
+ // ++++kParagraph "Paragraph"
+ // ++++++kStaticText "Paragraph"
+ // ++++++++kInlineTextBox "Paragraph"
+ // ++++kStaticText "Hello"
+ // ++++++kInlineTextBox "Hello"
+ // ++++kButton (empty)
+ AXNodeData root;
+ AXNodeData paragraph;
+ AXNodeData static_text_1;
+ AXNodeData inline_box_1;
+ AXNodeData static_text_2;
+ AXNodeData inline_box_2;
+ AXNodeData button_empty;
+
+ root.id = 1;
+ paragraph.id = 2;
+ static_text_1.id = 3;
+ inline_box_1.id = 4;
+ static_text_2.id = 5;
+ inline_box_2.id = 6;
+ button_empty.id = 7;
+
+ root.role = ax::mojom::Role::kRootWebArea;
+ root.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ root.child_ids = {paragraph.id, static_text_2.id, button_empty.id};
+
+ paragraph.role = ax::mojom::Role::kParagraph;
+ paragraph.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+ paragraph.child_ids = {static_text_1.id};
+
+ static_text_1.role = ax::mojom::Role::kStaticText;
+ static_text_1.SetName("Paragraph");
+ static_text_1.child_ids = {inline_box_1.id};
+
+ inline_box_1.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_1.SetName("Paragraph");
+
+ static_text_2.role = ax::mojom::Role::kStaticText;
+ static_text_2.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ static_text_2.SetName("Hello");
+ static_text_2.child_ids = {inline_box_2.id};
+
+ inline_box_2.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_2.SetName("Hello");
+
+ button_empty.role = ax::mojom::Role::kButton;
+ button_empty.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+
+ SetTree(CreateAXTree({root, paragraph, static_text_1, inline_box_1,
+ static_text_2, inline_box_2, button_empty}));
+
+ TestPositionType before_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_root->IsNullPosition());
+
+ // The root's first child is an embedded object, i.e. a paragraph. Create two
+ // positions: one after the paragraph (upstream affinity), and the other
+ // before the word "Hello" that comes after the paragraph (downstream
+ // affinity).
+ TestPositionType middle_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, AXNode::kEmbeddedCharacterLength /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(middle_root->IsNullPosition());
+ TestPositionType middle_root_upstream = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, AXNode::kEmbeddedCharacterLength /* text_offset */,
+ ax::mojom::TextAffinity::kUpstream);
+ ASSERT_FALSE(middle_root_upstream->IsNullPosition());
+
+ // The root has 7 characters: two embedded objects and the word "Hello".
+ TestPositionType after_root = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root.id, 7 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(after_root->IsNullPosition());
+
+ // "<P>aragraph"
+ TestPositionType before_inline_box_1 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_1.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_inline_box_1->IsNullPosition());
+ // "Paragraph<>"
+ TestPositionType after_inline_box_1 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_1.id, 9 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(after_inline_box_1->IsNullPosition());
+
+ TestPositionType after_inline_box_1_tree = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_1.id, 0 /* child_index */);
+ ASSERT_FALSE(after_inline_box_1_tree->IsNullPosition());
+
+ // "<H>ello"
+ TestPositionType before_inline_box_2 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_2.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_inline_box_2->IsNullPosition());
+ // "Hello<>"
+ TestPositionType after_inline_box_2 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_2.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(after_inline_box_2->IsNullPosition());
+
+ TestPositionType before_inline_box_2_tree =
+ AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_2.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_FALSE(before_inline_box_2_tree->IsNullPosition());
+ TestPositionType after_inline_box_2_tree = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_2.id, 0 /* child_index */);
+ ASSERT_FALSE(after_inline_box_2_tree->IsNullPosition());
+
+ TestPositionType before_button_empty = AXNodePosition::CreateTextPosition(
+ GetTreeID(), button_empty.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_FALSE(before_button_empty->IsNullPosition());
+
+ TestPositionType before_button_empty_tree =
+ AXNodePosition::CreateTreePosition(
+ GetTreeID(), button_empty.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_FALSE(before_button_empty_tree->IsNullPosition());
+ TestPositionType after_button_empty_tree = AXNodePosition::CreateTreePosition(
+ GetTreeID(), button_empty.id, 0 /* child_index */);
+ ASSERT_FALSE(after_button_empty_tree->IsNullPosition());
+
+ TestPositionType parent_position = before_inline_box_1->CreateParentPosition()
+ ->CreateParentPosition()
+ ->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(0, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, parent_position->affinity());
+
+ TestPositionType leaf_position = before_root->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ EXPECT_EQ(inline_box_1.id, leaf_position->anchor_id());
+ EXPECT_EQ(0, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+
+ // `inline_box_1` is on a different line from `inline_box_2`, hence the
+ // equivalent position on the root should have an upstream affinity.
+ parent_position = after_inline_box_1->CreateParentPosition()
+ ->CreateParentPosition()
+ ->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(AXNode::kEmbeddedCharacterLength, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, parent_position->affinity());
+
+ parent_position = after_inline_box_1_tree->CreateParentPosition()
+ ->CreateParentPosition()
+ ->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(1, parent_position->child_index());
+
+ leaf_position = middle_root_upstream->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ EXPECT_EQ(inline_box_1.id, leaf_position->anchor_id());
+ EXPECT_EQ(9, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+
+ parent_position =
+ before_inline_box_2->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(AXNode::kEmbeddedCharacterLength, parent_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, parent_position->affinity());
+
+ leaf_position = middle_root->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ EXPECT_EQ(inline_box_2.id, leaf_position->anchor_id());
+ EXPECT_EQ(0, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+
+ parent_position =
+ after_inline_box_2->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ // The text offset should be after the paragraph, which is an embedded object,
+ // and the word "Hello".
+ EXPECT_EQ(6, parent_position->text_offset());
+ // Since the word "Hello" is on a different line from the empty button, the
+ // affinity at the end of the word should be upstream.
+ EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, parent_position->affinity());
+
+ parent_position =
+ before_inline_box_2_tree->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(1, parent_position->child_index());
+
+ parent_position =
+ after_inline_box_2_tree->CreateParentPosition()->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(2, parent_position->child_index());
+
+ parent_position = before_button_empty->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTextPosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ // The empty button comes in the root's hypertext after the paragraph, which
+ // is an embedded object, and the word "Hello".
+ EXPECT_EQ(6, parent_position->text_offset());
+ // The empty button should start a new line, hence the affinity should be
+ // downstream.
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, parent_position->affinity());
+
+ parent_position = before_button_empty_tree->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(2, parent_position->child_index());
+
+ parent_position = after_button_empty_tree->CreateParentPosition();
+ ASSERT_NE(nullptr, parent_position);
+ EXPECT_TRUE(parent_position->IsTreePosition());
+ EXPECT_EQ(root.id, parent_position->anchor_id());
+ EXPECT_EQ(3, parent_position->child_index());
+
+ leaf_position = after_root->AsLeafTextPosition();
+ ASSERT_NE(nullptr, leaf_position);
+ EXPECT_TRUE(leaf_position->IsTextPosition());
+ EXPECT_EQ(button_empty.id, leaf_position->anchor_id());
+ // Empty leaf objects are replaced by the embedded object character.
+ EXPECT_EQ(AXNode::kEmbeddedCharacterLength, leaf_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, leaf_position->affinity());
+}
+
TEST_F(AXPositionTest, CreateNextAndPreviousLeafTextPositionWithNullPosition) {
TestPositionType null_position = AXNodePosition::CreateNullPosition();
ASSERT_NE(nullptr, null_position);
@@ -6041,12 +8868,12 @@ TEST_F(AXPositionTest, AsValidPositionInDescendantOfEmptyObject) {
update.nodes = {static_text_3, inline_box_4};
ASSERT_TRUE(GetTree()->Unserialize(update));
- EXPECT_FALSE(text_position->IsValid());
+ EXPECT_TRUE(text_position->IsValid());
text_position = text_position->AsValidPosition();
EXPECT_TRUE(text_position->IsValid());
EXPECT_EQ(1, text_position->text_offset());
- EXPECT_FALSE(tree_position->IsValid());
+ EXPECT_TRUE(tree_position->IsValid());
tree_position = tree_position->AsValidPosition();
EXPECT_TRUE(tree_position->IsValid());
EXPECT_EQ(0, tree_position->child_index());
@@ -6700,13 +9527,12 @@ TEST_F(AXPositionTest, OperatorEquals) {
ASSERT_TRUE(text_position2->IsTextPosition());
EXPECT_EQ(*text_position1, *text_position2);
- // Affinities should not matter.
text_position2 = AXNodePosition::CreateTextPosition(
GetTreeID(), inline_box1_.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kUpstream);
ASSERT_NE(nullptr, text_position2);
ASSERT_TRUE(text_position2->IsTextPosition());
- EXPECT_EQ(*text_position1, *text_position2);
+ EXPECT_GT(*text_position1, *text_position2);
// Text offsets should match.
text_position1 = AXNodePosition::CreateTextPosition(
@@ -6729,20 +9555,6 @@ TEST_F(AXPositionTest, OperatorEquals) {
ASSERT_TRUE(text_position2->IsTextPosition());
EXPECT_EQ(*text_position1, *text_position2);
- // Two text positions that are consecutive, one "before text" and one "after
- // text".
- text_position1 = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_NE(nullptr, text_position1);
- ASSERT_TRUE(text_position1->IsTextPosition());
- text_position2 = AXNodePosition::CreateTextPosition(
- GetTreeID(), line_break_.id, 1 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_NE(nullptr, text_position2);
- ASSERT_TRUE(text_position2->IsTextPosition());
- EXPECT_EQ(*text_position1, *text_position2);
-
// Two "after text" positions on a parent and child should be equivalent, in
// the middle of the document...
text_position1 = AXNodePosition::CreateTextPosition(
@@ -6768,8 +9580,8 @@ TEST_F(AXPositionTest, OperatorEquals) {
ax::mojom::TextAffinity::kDownstream);
ASSERT_NE(nullptr, text_position2);
ASSERT_TRUE(text_position2->IsTextPosition());
- // Validate that we're actually at the end of the document by normalizing to
- // the equivalent "before character" position.
+ // Validate that we're actually at the end of the whole content by normalizing
+ // to the equivalent "before character" position.
EXPECT_TRUE(
text_position1->AsLeafTextPositionBeforeCharacter()->IsNullPosition());
EXPECT_TRUE(
@@ -6808,8 +9620,8 @@ TEST_F(AXPositionTest, OperatorEqualsSameTextOffsetDifferentAnchorIdRoot) {
ASSERT_NE(nullptr, text_position_two);
ASSERT_TRUE(text_position_two->IsTextPosition());
- ASSERT_TRUE(*text_position_one == *text_position_two);
- ASSERT_TRUE(*text_position_two == *text_position_one);
+ EXPECT_TRUE(*text_position_one == *text_position_two);
+ EXPECT_TRUE(*text_position_two == *text_position_one);
}
TEST_F(AXPositionTest, OperatorEqualsSameTextOffsetDifferentAnchorIdLeaf) {
@@ -6829,6 +9641,479 @@ TEST_F(AXPositionTest, OperatorEqualsSameTextOffsetDifferentAnchorIdLeaf) {
ASSERT_TRUE(*text_position_two == *text_position_one);
}
+TEST_F(AXPositionTest, OperatorEqualsTextPositionsInTextField) {
+ g_ax_embedded_object_behavior = AXEmbeddedObjectBehavior::kExposeCharacter;
+
+ // ++1 kRootWebArea
+ // ++++2 kTextField editable
+ // ++++++3 kGenericContainer editable
+ // ++++++++4 kStaticText editable "Hello"
+ // ++++++++++5 kInlineTextBox "Hello"
+ AXNodeData root_1;
+ AXNodeData text_field_2;
+ AXNodeData generic_container_3;
+ AXNodeData static_text_4;
+ AXNodeData inline_box_5;
+
+ root_1.id = 1;
+ text_field_2.id = 2;
+ generic_container_3.id = 3;
+ static_text_4.id = 4;
+ inline_box_5.id = 5;
+
+ root_1.role = ax::mojom::Role::kRootWebArea;
+ root_1.child_ids = {text_field_2.id};
+
+ text_field_2.role = ax::mojom::Role::kTextField;
+ text_field_2.AddState(ax::mojom::State::kEditable);
+ text_field_2.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot, true);
+ text_field_2.child_ids = {generic_container_3.id};
+
+ generic_container_3.role = ax::mojom::Role::kGenericContainer;
+ generic_container_3.AddState(ax::mojom::State::kEditable);
+ generic_container_3.child_ids = {static_text_4.id};
+
+ static_text_4.role = ax::mojom::Role::kStaticText;
+ static_text_4.SetName("Hello");
+ static_text_4.child_ids = {inline_box_5.id};
+
+ inline_box_5.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_5.SetName("Hello");
+
+ SetTree(CreateAXTree({root_1, text_field_2, generic_container_3,
+ static_text_4, inline_box_5}));
+
+ // TextPosition anchor_id=5 anchor_role=inlineTextBox text_offset=4
+ // annotated_text=hell<o>
+ TestPositionType inline_text_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_5.id, 4 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, inline_text_position);
+
+ // TextPosition anchor_id=2 anchor_role=textField text_offset=4
+ // annotated_text=hell<o>
+ TestPositionType text_field_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), text_field_2.id, 4 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_field_position);
+
+ // Validate that two positions in the text field with the same text offsets
+ // but different anchors are logically equal.
+ EXPECT_EQ(*inline_text_position, *text_field_position);
+ EXPECT_EQ(*text_field_position, *inline_text_position);
+}
+
+TEST_F(AXPositionTest, OperatorEqualsTextPositionsInSearchBox) {
+ g_ax_embedded_object_behavior = AXEmbeddedObjectBehavior::kExposeCharacter;
+
+ // ++1 kRootWebArea
+ // ++++2 kSearchBox editable editableRoot=true
+ // ++++++3 kGenericContainer
+ // ++++++++4 kGenericContainer editable
+ // ++++++++++5 kStaticText editable "Hello"
+ // ++++++++++++6 kInlineTextBox "Hello"
+ // ++++7 kButton
+ // ++++++8 kStaticText "X"
+ // ++++++++9 kInlineTextBox "X"
+ AXNodeData root_1;
+ AXNodeData search_box_2;
+ AXNodeData generic_container_3;
+ AXNodeData generic_container_4;
+ AXNodeData static_text_5;
+ AXNodeData inline_box_6;
+ AXNodeData button_7;
+ AXNodeData static_text_8;
+ AXNodeData inline_box_9;
+
+ root_1.id = 1;
+ search_box_2.id = 2;
+ generic_container_3.id = 3;
+ generic_container_4.id = 4;
+ static_text_5.id = 5;
+ inline_box_6.id = 6;
+ button_7.id = 7;
+ static_text_8.id = 8;
+ inline_box_9.id = 9;
+
+ root_1.role = ax::mojom::Role::kRootWebArea;
+ root_1.child_ids = {search_box_2.id, button_7.id};
+
+ search_box_2.role = ax::mojom::Role::kSearchBox;
+ search_box_2.AddState(ax::mojom::State::kEditable);
+ search_box_2.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot, true);
+ search_box_2.child_ids = {generic_container_3.id};
+
+ generic_container_3.role = ax::mojom::Role::kGenericContainer;
+ generic_container_3.child_ids = {generic_container_4.id};
+
+ generic_container_4.role = ax::mojom::Role::kGenericContainer;
+ generic_container_4.AddState(ax::mojom::State::kEditable);
+ generic_container_4.child_ids = {static_text_5.id};
+
+ static_text_5.role = ax::mojom::Role::kStaticText;
+ static_text_5.SetName("Hello");
+ static_text_5.child_ids = {inline_box_6.id};
+
+ inline_box_6.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_6.SetName("Hello");
+
+ button_7.role = ax::mojom::Role::kButton;
+ button_7.child_ids = {static_text_8.id};
+
+ static_text_8.role = ax::mojom::Role::kStaticText;
+ static_text_8.SetName("X");
+ static_text_8.child_ids = {inline_box_9.id};
+
+ inline_box_9.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_9.SetName("X");
+
+ SetTree(CreateAXTree({root_1, search_box_2, generic_container_3,
+ generic_container_4, static_text_5, inline_box_6,
+ button_7, static_text_8, inline_box_9}));
+
+ // TextPosition anchor_role=inlineTextBox_6 text_offset=5
+ // annotated_text=hello<>
+ TestPositionType inline_text_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_6.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, inline_text_position);
+
+ // TextPosition anchor_role=search_box_2 text_offset=5 annotated_text=hello<>
+ TestPositionType search_box_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), search_box_2.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, search_box_position);
+
+ EXPECT_EQ(*search_box_position, *inline_text_position);
+ EXPECT_EQ(*inline_text_position, *search_box_position);
+
+ // TextPosition anchor_role=static_text_8 text_offset=0 annotated_text=<X>
+ TestPositionType static_text_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), static_text_8.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, static_text_position);
+
+ // TextPosition anchor_role=button_7 text_offset=0 annotated_text=<X>
+ TestPositionType button_position = AXNodePosition::CreateTextPosition(
+ GetTreeID(), button_7.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, button_position);
+
+ EXPECT_EQ(*button_position, *static_text_position);
+ EXPECT_EQ(*static_text_position, *button_position);
+}
+
+TEST_F(AXPositionTest, OperatorsTreePositionsAroundEmbeddedCharacter) {
+ g_ax_embedded_object_behavior = AXEmbeddedObjectBehavior::kExposeCharacter;
+
+ // ++1 kRootWebArea "<embedded_object><embedded_object>"
+ // ++++2 kParagraph "<embedded_object>"
+ // ++++++3 kLink "Hello"
+ // ++++++++4 kStaticText "Hello"
+ // ++++++++++5 kInlineTextBox "Hello"
+ // ++++6 kParagraph "World"
+ // ++++++7 kStaticText "World"
+ // ++++++++8 kInlineTextBox "World"
+ AXNodeData root_1;
+ AXNodeData paragraph_2;
+ AXNodeData link_3;
+ AXNodeData static_text_4;
+ AXNodeData inline_box_5;
+ AXNodeData paragraph_6;
+ AXNodeData static_text_7;
+ AXNodeData inline_box_8;
+
+ root_1.id = 1;
+ paragraph_2.id = 2;
+ link_3.id = 3;
+ static_text_4.id = 4;
+ inline_box_5.id = 5;
+ paragraph_6.id = 6;
+ static_text_7.id = 7;
+ inline_box_8.id = 8;
+
+ root_1.role = ax::mojom::Role::kRootWebArea;
+ root_1.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+ root_1.child_ids = {paragraph_2.id, paragraph_6.id};
+
+ paragraph_2.role = ax::mojom::Role::kParagraph;
+ paragraph_2.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+ paragraph_2.child_ids = {link_3.id};
+
+ link_3.role = ax::mojom::Role::kLink;
+ link_3.AddState(ax::mojom::State::kLinked);
+ link_3.child_ids = {static_text_4.id};
+
+ static_text_4.role = ax::mojom::Role::kStaticText;
+ static_text_4.SetName("Hello");
+ static_text_4.child_ids = {inline_box_5.id};
+
+ inline_box_5.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_5.SetName("Hello");
+
+ paragraph_6.role = ax::mojom::Role::kParagraph;
+ paragraph_6.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+ paragraph_6.child_ids = {static_text_7.id};
+
+ static_text_7.role = ax::mojom::Role::kStaticText;
+ static_text_7.SetName("World");
+ static_text_7.child_ids = {inline_box_8.id};
+
+ inline_box_8.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_8.SetName("World");
+
+ SetTree(
+ CreateAXTree({root_1, paragraph_2, link_3, static_text_4, inline_box_5,
+ paragraph_6, static_text_7, inline_box_8}));
+
+ TestPositionType before_root_1 = AXNodePosition::CreateTreePosition(
+ GetTreeID(), root_1.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, before_root_1);
+ TestPositionType middle_root_1 = AXNodePosition::CreateTreePosition(
+ GetTreeID(), root_1.id, 1 /* child_index */);
+ ASSERT_NE(nullptr, middle_root_1);
+ TestPositionType after_root_1 = AXNodePosition::CreateTreePosition(
+ GetTreeID(), root_1.id, 2 /* child_index */);
+ ASSERT_NE(nullptr, after_root_1);
+
+ TestPositionType before_paragraph_2 = AXNodePosition::CreateTreePosition(
+ GetTreeID(), paragraph_2.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, before_paragraph_2);
+ TestPositionType after_paragraph_2 = AXNodePosition::CreateTreePosition(
+ GetTreeID(), paragraph_2.id, 1 /* child_index */);
+ ASSERT_NE(nullptr, after_paragraph_2);
+
+ TestPositionType before_paragraph_6 = AXNodePosition::CreateTreePosition(
+ GetTreeID(), paragraph_6.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, before_paragraph_6);
+ TestPositionType after_paragraph_6 = AXNodePosition::CreateTreePosition(
+ GetTreeID(), paragraph_6.id, 1 /* child_index */);
+ ASSERT_NE(nullptr, before_paragraph_6);
+
+ TestPositionType before_inline_box_5 = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_5.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, before_inline_box_5);
+ TestPositionType after_inline_box_5 = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_5.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, after_inline_box_5);
+
+ TestPositionType before_inline_box_8 = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_8.id,
+ AXNodePosition::BEFORE_TEXT /* child_index */);
+ ASSERT_NE(nullptr, before_inline_box_8);
+ TestPositionType after_inline_box_8 = AXNodePosition::CreateTreePosition(
+ GetTreeID(), inline_box_8.id, 0 /* child_index */);
+ ASSERT_NE(nullptr, after_inline_box_8);
+
+ EXPECT_EQ(*before_root_1, *before_paragraph_2);
+ EXPECT_EQ(*before_paragraph_2, *before_root_1);
+ EXPECT_EQ(*before_root_1, *before_inline_box_5);
+ EXPECT_EQ(*before_inline_box_5, *before_root_1);
+
+ EXPECT_LT(*before_root_1, *middle_root_1);
+ EXPECT_GT(*before_paragraph_6, *before_inline_box_5);
+ EXPECT_LT(*before_paragraph_2, *before_inline_box_8);
+
+ EXPECT_EQ(*middle_root_1, *before_paragraph_6);
+ EXPECT_EQ(*before_paragraph_6, *middle_root_1);
+ EXPECT_EQ(*middle_root_1, *before_inline_box_8);
+ EXPECT_EQ(*before_inline_box_8, *middle_root_1);
+
+ // Since tree positions do not have affinity, all of the following positions
+ // should be equivalent.
+ EXPECT_EQ(*middle_root_1, *after_paragraph_2);
+ EXPECT_EQ(*after_paragraph_2, *middle_root_1);
+ EXPECT_EQ(*middle_root_1, *after_inline_box_5);
+ EXPECT_EQ(*after_inline_box_5, *middle_root_1);
+
+ EXPECT_EQ(*after_root_1, *after_paragraph_6);
+ EXPECT_EQ(*after_paragraph_6, *after_root_1);
+ EXPECT_EQ(*after_root_1, *after_inline_box_8);
+ EXPECT_EQ(*after_inline_box_8, *after_root_1);
+}
+
+TEST_F(AXPositionTest, OperatorsTextPositionsAroundEmbeddedCharacter) {
+ g_ax_embedded_object_behavior = AXEmbeddedObjectBehavior::kExposeCharacter;
+
+ // ++1 kRootWebArea "<embedded_object><embedded_object>"
+ // ++++2 kParagraph "<embedded_object>"
+ // ++++++3 kLink "Hello"
+ // ++++++++4 kStaticText "Hello"
+ // ++++++++++5 kInlineTextBox "Hello"
+ // ++++6 kParagraph "World"
+ // ++++++7 kStaticText "World"
+ // ++++++++8 kInlineTextBox "World"
+ AXNodeData root_1;
+ AXNodeData paragraph_2;
+ AXNodeData link_3;
+ AXNodeData static_text_4;
+ AXNodeData inline_box_5;
+ AXNodeData paragraph_6;
+ AXNodeData static_text_7;
+ AXNodeData inline_box_8;
+
+ root_1.id = 1;
+ paragraph_2.id = 2;
+ link_3.id = 3;
+ static_text_4.id = 4;
+ inline_box_5.id = 5;
+ paragraph_6.id = 6;
+ static_text_7.id = 7;
+ inline_box_8.id = 8;
+
+ root_1.role = ax::mojom::Role::kRootWebArea;
+ root_1.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+ root_1.child_ids = {paragraph_2.id, paragraph_6.id};
+
+ paragraph_2.role = ax::mojom::Role::kParagraph;
+ paragraph_2.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+ paragraph_2.child_ids = {link_3.id};
+
+ link_3.role = ax::mojom::Role::kLink;
+ link_3.AddState(ax::mojom::State::kLinked);
+ link_3.child_ids = {static_text_4.id};
+
+ static_text_4.role = ax::mojom::Role::kStaticText;
+ static_text_4.SetName("Hello");
+ static_text_4.child_ids = {inline_box_5.id};
+
+ inline_box_5.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_5.SetName("Hello");
+
+ paragraph_6.role = ax::mojom::Role::kParagraph;
+ paragraph_6.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+ paragraph_6.child_ids = {static_text_7.id};
+
+ static_text_7.role = ax::mojom::Role::kStaticText;
+ static_text_7.SetName("World");
+ static_text_7.child_ids = {inline_box_8.id};
+
+ inline_box_8.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_8.SetName("World");
+
+ SetTree(
+ CreateAXTree({root_1, paragraph_2, link_3, static_text_4, inline_box_5,
+ paragraph_6, static_text_7, inline_box_8}));
+
+ TestPositionType before_root_1 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root_1.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, before_root_1);
+ TestPositionType middle_root_1 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root_1.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, middle_root_1);
+ TestPositionType middle_root_1_upstream = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root_1.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kUpstream);
+ ASSERT_NE(nullptr, middle_root_1_upstream);
+ TestPositionType after_root_1 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), root_1.id, 2 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, after_root_1);
+
+ TestPositionType before_paragraph_2 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), paragraph_2.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, before_paragraph_2);
+ // The first paragraph has a link inside it, so it will only expose a single
+ // "embedded object replacement character".
+ TestPositionType after_paragraph_2 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), paragraph_2.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, after_paragraph_2);
+
+ TestPositionType before_paragraph_6 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), paragraph_6.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, before_paragraph_6);
+ // The second paragraph contains "World".
+ TestPositionType after_paragraph_6 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), paragraph_6.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, before_paragraph_6);
+
+ TestPositionType before_inline_box_5 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_5.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, before_inline_box_5);
+ TestPositionType middle_inline_box_5 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_5.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, middle_inline_box_5);
+ // "Hello".
+ TestPositionType after_inline_box_5 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_5.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, after_inline_box_5);
+
+ TestPositionType before_inline_box_8 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_8.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, before_inline_box_8);
+ TestPositionType middle_inline_box_8 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_8.id, 1 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, middle_inline_box_8);
+ // "World".
+ TestPositionType after_inline_box_8 = AXNodePosition::CreateTextPosition(
+ GetTreeID(), inline_box_8.id, 5 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, after_inline_box_8);
+
+ EXPECT_EQ(*before_root_1, *before_paragraph_2);
+ EXPECT_EQ(*before_paragraph_2, *before_root_1);
+ EXPECT_EQ(*before_root_1, *before_inline_box_5);
+ EXPECT_EQ(*before_inline_box_5, *before_root_1);
+
+ EXPECT_LT(*before_root_1, *middle_root_1);
+ EXPECT_GT(*before_paragraph_6, *before_inline_box_5);
+ EXPECT_LT(*before_paragraph_2, *before_inline_box_8);
+
+ EXPECT_EQ(*middle_root_1, *before_paragraph_6);
+ EXPECT_EQ(*before_paragraph_6, *middle_root_1);
+ EXPECT_EQ(*middle_root_1, *before_inline_box_8);
+ EXPECT_EQ(*before_inline_box_8, *middle_root_1);
+
+ EXPECT_GT(*middle_root_1, *after_paragraph_2);
+ EXPECT_LT(*after_paragraph_2, *middle_root_1);
+ EXPECT_GT(*middle_root_1, *after_inline_box_5);
+ EXPECT_LT(*after_inline_box_5, *middle_root_1);
+
+ // An upstream affinity on the root before the second paragraph attaches the
+ // position to the end of the previous line, i.e. moves it to the end of the
+ // first paragraph.
+ EXPECT_LT(*middle_root_1_upstream, *middle_root_1);
+ EXPECT_EQ(*middle_root_1_upstream, *after_paragraph_2);
+ EXPECT_EQ(*after_paragraph_2, *middle_root_1_upstream);
+ EXPECT_EQ(*middle_root_1_upstream, *after_inline_box_5);
+ EXPECT_EQ(*after_inline_box_5, *middle_root_1_upstream);
+
+ // According to the IAccessible2 Spec, a position inside an embedded object
+ // should be equivalent to a position right after it, if the former is not at
+ // the object's start.
+ EXPECT_EQ(*middle_root_1_upstream, *middle_inline_box_5);
+ EXPECT_EQ(*middle_inline_box_5, *middle_root_1_upstream);
+
+ EXPECT_EQ(*after_root_1, *after_paragraph_6);
+ EXPECT_EQ(*after_paragraph_6, *after_root_1);
+ EXPECT_EQ(*after_root_1, *after_inline_box_8);
+ EXPECT_EQ(*after_inline_box_8, *after_root_1);
+
+ // According to the IAccessible2 Spec, a position inside an embedded object
+ // should be equivalent to a position right after it, if the former is not at
+ // the object's start.
+ EXPECT_EQ(*after_root_1, *middle_inline_box_8);
+ EXPECT_EQ(*middle_inline_box_8, *after_root_1);
+}
+
TEST_F(AXPositionTest, OperatorsLessThanAndGreaterThan) {
TestPositionType null_position1 = AXNodePosition::CreateNullPosition();
ASSERT_NE(nullptr, null_position1);
@@ -6933,25 +10218,35 @@ TEST_F(AXPositionTest, OperatorsLessThanAndGreaterThan) {
EXPECT_GT(*text_position1, *text_position2);
EXPECT_LT(*text_position2, *text_position1);
- // Two consecutive positions. One "before text" and one "after text".
+ // Two consecutive positions. One "before text" and one "after text". When
+ // converted to their ancestor equivalent positions in the text field, one
+ // will have an upstream affinity and the other a downstream affinity. This is
+ // because one position is right after the line break character while the
+ // other at the start of the line after the line break. The positions are not
+ // equivalent because line break characters always appear at the end of the
+ // line and they are part of the line they end. One way to understand why this
+ // makes sense is to think what should the behavior be when a line break
+ // character is on a blank line of its own? The line break character in that
+ // case forms the blank line's text contents.
text_position2 = AXNodePosition::CreateTextPosition(
GetTreeID(), line_break_.id, 1 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
ASSERT_NE(nullptr, text_position2);
ASSERT_TRUE(text_position2->IsTextPosition());
- EXPECT_EQ(*text_position1, *text_position2);
+ EXPECT_GT(*text_position1, *text_position2);
+ EXPECT_LT(*text_position2, *text_position1);
- // A text position at the end of the document versus one that isn't.
+ // A text position at the end of the whole content versus one that isn't.
text_position1 = AXNodePosition::CreateTextPosition(
GetTreeID(), inline_box2_.id, 6 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
ASSERT_NE(nullptr, text_position1);
ASSERT_TRUE(text_position1->IsTextPosition());
- // Validate that we're actually at the end of the document by normalizing to
- // the equivalent "before character" position.
+ // Validate that we're actually at the end of the whole content by normalizing
+ // to the equivalent "before character" position.
EXPECT_TRUE(
text_position1->AsLeafTextPositionBeforeCharacter()->IsNullPosition());
- // Now create the not-at-end-of-document position and compare.
+ // Now create the not-at-end-of-content position and compare.
text_position2 = AXNodePosition::CreateTextPosition(
GetTreeID(), static_text2_.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
@@ -7507,14 +10802,12 @@ TEST_F(AXPositionTest, CreatePreviousWordPositionInList) {
TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
g_ax_embedded_object_behavior = AXEmbeddedObjectBehavior::kExposeCharacter;
- const base::string16 embedded_character_str(
- 1, AXNodePosition::kEmbeddedCharacter);
// ++1 kRootWebArea
// ++++2 kStaticText
// ++++++3 kInlineTextBox
// ++++4 kTextField
- // ++++++5 kGenericContainer
+ // ++++++5 kGenericContainer ignored
// ++++6 kStaticText
// ++++++7 kInlineTextBox
// ++++8 kHeading
@@ -7525,6 +10818,7 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
// ++++13 kStaticText
// ++++14 kButton
// ++++++15 kGenericContainer ignored
+ // ++++++16 kGenericContainer ignored
AXNodeData root_1;
AXNodeData static_text_2;
AXNodeData inline_box_3;
@@ -7540,6 +10834,7 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
AXNodeData static_text_13;
AXNodeData button_14;
AXNodeData generic_container_15;
+ AXNodeData generic_container_16;
root_1.id = 1;
static_text_2.id = 2;
@@ -7556,6 +10851,7 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
static_text_13.id = 13;
button_14.id = 14;
generic_container_15.id = 15;
+ generic_container_16.id = 16;
root_1.role = ax::mojom::Role::kRootWebArea;
root_1.child_ids = {static_text_2.id, text_field_4.id,
@@ -7575,9 +10871,11 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
std::vector<int32_t>{6});
text_field_4.role = ax::mojom::Role::kTextField;
+ text_field_4.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot, true);
text_field_4.child_ids = {generic_container_5.id};
generic_container_5.role = ax::mojom::Role::kGenericContainer;
+ generic_container_5.AddState(ax::mojom::State::kIgnored);
static_text_6.role = ax::mojom::Role::kStaticText;
static_text_6.SetName(" world");
@@ -7613,16 +10911,18 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
static_text_13.SetName("hey");
button_14.role = ax::mojom::Role::kButton;
- button_14.child_ids = {generic_container_15.id};
+ button_14.child_ids = {generic_container_15.id, generic_container_16.id};
generic_container_15.role = ax::mojom::Role::kGenericContainer;
generic_container_15.AddState(ax::mojom::State::kIgnored);
+ generic_container_16.role = ax::mojom::Role::kGenericContainer;
+ generic_container_16.AddState(ax::mojom::State::kIgnored);
- SetTree(CreateAXTree({root_1, static_text_2, inline_box_3, text_field_4,
- generic_container_5, static_text_6, inline_box_7,
- heading_8, static_text_9, inline_box_10,
- generic_container_11, generic_container_12,
- static_text_13, button_14, generic_container_15}));
+ SetTree(CreateAXTree(
+ {root_1, static_text_2, inline_box_3, text_field_4, generic_container_5,
+ static_text_6, inline_box_7, heading_8, static_text_9, inline_box_10,
+ generic_container_11, generic_container_12, static_text_13, button_14,
+ generic_container_15, generic_container_16}));
// CreateNextWordStartPosition tests.
TestPositionType position = AXNodePosition::CreateTextPosition(
@@ -7632,10 +10932,10 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
TestPositionType result_position =
position->CreateNextWordStartPosition(AXBoundaryBehavior::CrossBoundary);
EXPECT_TRUE(result_position->IsTextPosition());
- EXPECT_EQ(generic_container_5.id, result_position->anchor_id());
+ EXPECT_EQ(text_field_4.id, result_position->anchor_id());
EXPECT_EQ(0, result_position->text_offset());
EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, result_position->affinity());
- EXPECT_EQ(embedded_character_str, result_position->GetText());
+ EXPECT_EQ(AXNode::kEmbeddedCharacter, result_position->GetText());
position = std::move(result_position);
result_position =
@@ -7651,10 +10951,10 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
result_position = position->CreatePreviousWordStartPosition(
AXBoundaryBehavior::CrossBoundary);
EXPECT_TRUE(result_position->IsTextPosition());
- EXPECT_EQ(generic_container_5.id, result_position->anchor_id());
+ EXPECT_EQ(text_field_4.id, result_position->anchor_id());
EXPECT_EQ(0, result_position->text_offset());
EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, result_position->affinity());
- EXPECT_EQ(embedded_character_str, result_position->GetText());
+ EXPECT_EQ(AXNode::kEmbeddedCharacter, result_position->GetText());
position = std::move(result_position);
result_position = position->CreatePreviousWordStartPosition(
@@ -7679,10 +10979,13 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
result_position =
position->CreateNextWordEndPosition(AXBoundaryBehavior::CrossBoundary);
EXPECT_TRUE(result_position->IsTextPosition());
- EXPECT_EQ(generic_container_5.id, result_position->anchor_id());
+ // The position would be on `text_field_4` instead of on `generic_container_5`
+ // because the latter is ignored, and by design we prefer not to create
+ // positions on ignored nodes if it could be avoided.
+ EXPECT_EQ(text_field_4.id, result_position->anchor_id());
EXPECT_EQ(1, result_position->text_offset());
EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, result_position->affinity());
- EXPECT_EQ(embedded_character_str, result_position->GetText());
+ EXPECT_EQ(AXNode::kEmbeddedCharacter, result_position->GetText());
position = std::move(result_position);
result_position =
@@ -7698,10 +11001,13 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
result_position = position->CreatePreviousWordEndPosition(
AXBoundaryBehavior::CrossBoundary);
EXPECT_TRUE(result_position->IsTextPosition());
- EXPECT_EQ(generic_container_5.id, result_position->anchor_id());
+ // The position would be on `text_field_4` instead of on `generic_container_5`
+ // because the latter is ignored, and by design we prefer not to create
+ // positions on ignored nodes if it could be avoided.
+ EXPECT_EQ(text_field_4.id, result_position->anchor_id());
EXPECT_EQ(1, result_position->text_offset());
EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, result_position->affinity());
- EXPECT_EQ(embedded_character_str, result_position->GetText());
+ EXPECT_EQ(AXNode::kEmbeddedCharacter, result_position->GetText());
position = std::move(result_position);
result_position = position->CreatePreviousWordEndPosition(
@@ -7712,62 +11018,54 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, result_position->affinity());
EXPECT_EQ(base::WideToUTF16(L"Hello "), result_position->GetText());
- // GetText() with embedded object replacement character test.
+ // Positions on descendants of empty objects that have been replaced by the
+ // "embedded object replacement character" are valid, to allow for navigating
+ // inside of text controls.
position = AXNodePosition::CreateTextPosition(
GetTreeID(), generic_container_5.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
+ EXPECT_FALSE(position->IsNullPosition());
+ EXPECT_TRUE(position->GetText().empty());
- EXPECT_EQ(embedded_character_str, position->GetText());
-
- // GetText() on a node that is the parent of a set of text nodes and a
- // non-text node, the latter represented by an embedded object replacement
- // character.
+ // `AXPosition::GetText()` on a node that is the parent of a set of text nodes
+ // and a non-text node, the latter represented by an embedded object
+ // replacement character.
position = AXNodePosition::CreateTextPosition(
GetTreeID(), root_1.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
+ // Hello <embedded> world<embedded><embedded>hey<embedded><embedded>
base::string16 expected_text =
- base::WideToUTF16(L"Hello ") + AXNodePosition::kEmbeddedCharacter +
- base::WideToUTF16(L" world") + AXNodePosition::kEmbeddedCharacter +
- AXNodePosition::kEmbeddedCharacter + base::WideToUTF16(L"hey") +
- AXNodePosition::kEmbeddedCharacter;
+ base::StrCat({STRING16_LITERAL("Hello "), AXNode::kEmbeddedCharacter,
+ STRING16_LITERAL(" world"), AXNode::kEmbeddedCharacter,
+ AXNode::kEmbeddedCharacter, STRING16_LITERAL("hey"),
+ AXNode::kEmbeddedCharacter});
EXPECT_EQ(expected_text, position->GetText());
- // MaxTextOffset() on a non-text node. This is represented by an embedded
- // object replacement character.
+ // A position on an empty object that has been replaced by an "embedded object
+ // replacement character".
position = AXNodePosition::CreateTextPosition(
- GetTreeID(), generic_container_5.id, 0 /* text_offset */,
+ GetTreeID(), text_field_4.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
- EXPECT_EQ(1, position->MaxTextOffset());
+ EXPECT_EQ(AXNode::kEmbeddedCharacterLength, position->MaxTextOffset())
+ << *position;
- // Parent positions created from a position inside a node represented by an
- // embedded object replacement character.
position = position->CreateParentPosition();
- EXPECT_TRUE(result_position->IsTextPosition());
- EXPECT_EQ(inline_box_3.id, result_position->anchor_id());
- EXPECT_EQ(6, result_position->text_offset());
- EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, result_position->affinity());
- EXPECT_EQ(base::WideToUTF16(L"Hello "), result_position->GetText());
- EXPECT_EQ(1, position->MaxTextOffset());
+ // Hello <embedded> world<embedded><embedded>hey<embedded>
+ EXPECT_EQ(19, position->MaxTextOffset()) << *position;
- position = position->CreateParentPosition();
- EXPECT_TRUE(result_position->IsTextPosition());
- EXPECT_EQ(inline_box_3.id, result_position->anchor_id());
- EXPECT_EQ(6, result_position->text_offset());
- EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, result_position->affinity());
- EXPECT_EQ(base::WideToUTF16(L"Hello "), result_position->GetText());
- EXPECT_EQ(22, position->MaxTextOffset());
-
- // MaxTextOffset() on a node which is the parent of a set of text nodes and an
- // a non-text node, the latter represented by an embedded object replacement
- // character.
+ // `AXPosition::MaxTextOffset()` on a node which is the parent of a set of
+ // text nodes and non-text nodes, the latter represented by "embedded object
+ // replacement characters".
+ //
+ // Hello <embedded> world<embedded><embedded>hey<embedded>
position = AXNodePosition::CreateTextPosition(
GetTreeID(), root_1.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
- EXPECT_EQ(22, position->MaxTextOffset());
+ EXPECT_EQ(19, position->MaxTextOffset()) << *position;
// The following is to test a specific edge case with heading navigation,
- // occurring in AXPosition::CreatePreviousFormatStartPosition.
+ // occurring in `AXPosition::CreatePreviousFormatStartPosition`.
//
// When the position is at the beginning of an unignored empty object,
// preceded by an ignored empty object, which is itself preceded by a heading
@@ -7803,11 +11101,24 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
text_position = text_position->CreateNextParagraphEndPosition(
AXBoundaryBehavior::StopAtLastAnchorBoundary);
ASSERT_NE(nullptr, text_position);
- EXPECT_TRUE(text_position->IsTextPosition());
EXPECT_TRUE(text_position->IsLeafTextPosition());
EXPECT_EQ(button_14.id, text_position->anchor_id());
EXPECT_EQ(1, text_position->text_offset());
EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, text_position->affinity());
+
+ // We shouldn't infinitely loop when trying to get the previous position
+ // from a descendant of embedded object character.
+ TestPositionType generic_container_position =
+ AXNodePosition::CreateTreePosition(GetTreeID(), generic_container_16.id,
+ AXNodePosition::BEFORE_TEXT);
+ ASSERT_NE(nullptr, generic_container_position);
+ ASSERT_TRUE(generic_container_position->IsTreePosition());
+ EXPECT_EQ(generic_container_16.id, generic_container_position->anchor_id());
+ text_position = generic_container_position->CreatePreviousLeafTextPosition();
+ EXPECT_NE(nullptr, text_position);
+ EXPECT_TRUE(text_position->IsTextPosition());
+ EXPECT_EQ(GetTreeID(), text_position->tree_id());
+ EXPECT_EQ(button_14.id, text_position->anchor_id());
}
TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterEmbedObject) {
@@ -7839,7 +11150,7 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterEmbedObject) {
// Create tree manager for child tree.
AXNodeData child_root;
child_root.id = 1;
- child_root.role = ax::mojom::Role::kDocument;
+ child_root.role = ax::mojom::Role::kPdfRoot;
AXTreeUpdate update;
update.tree_data.tree_id = child_tree_id;
@@ -8063,148 +11374,6 @@ TEST_P(AXPositionTextNavigationTestWithParam,
}
}
-TEST_F(AXPositionTest, TextPositionComparisonTextField) {
- g_ax_embedded_object_behavior = AXEmbeddedObjectBehavior::kExposeCharacter;
-
- // ++1 kRootWebArea
- // ++++2 kTextField editable
- // ++++++3 kGenericContainer editable
- // ++++++++4 kStaticText editable "Hello"
- // ++++++++++5 kInlineTextBox "Hello"
- AXNodeData root_1;
- AXNodeData text_field_2;
- AXNodeData generic_container_3;
- AXNodeData static_text_4;
- AXNodeData inline_box_5;
-
- root_1.id = 1;
- text_field_2.id = 2;
- generic_container_3.id = 3;
- static_text_4.id = 4;
- inline_box_5.id = 5;
-
- root_1.role = ax::mojom::Role::kRootWebArea;
- root_1.child_ids = {text_field_2.id};
-
- text_field_2.role = ax::mojom::Role::kTextField;
- text_field_2.AddState(ax::mojom::State::kEditable);
- text_field_2.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot, true);
- text_field_2.child_ids = {generic_container_3.id};
-
- generic_container_3.role = ax::mojom::Role::kGenericContainer;
- generic_container_3.AddState(ax::mojom::State::kEditable);
- generic_container_3.child_ids = {static_text_4.id};
-
- static_text_4.role = ax::mojom::Role::kStaticText;
- static_text_4.SetName("Hello");
- static_text_4.child_ids = {inline_box_5.id};
-
- inline_box_5.role = ax::mojom::Role::kInlineTextBox;
- inline_box_5.SetName("Hello");
-
- SetTree(CreateAXTree({root_1, text_field_2, generic_container_3,
- static_text_4, inline_box_5}));
-
- // TextPosition anchor_id=5 anchor_role=inlineTextBox text_offset=4
- // annotated_text=hell<o>
- TestPositionType inline_text_position = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box_5.id, 4, ax::mojom::TextAffinity::kDownstream);
- ASSERT_NE(nullptr, inline_text_position);
-
- // TextPosition anchor_id=2 anchor_role=textField text_offset=4
- // annotated_text=hell<o>
- TestPositionType text_field_position = AXNodePosition::CreateTextPosition(
- GetTreeID(), text_field_2.id, 4, ax::mojom::TextAffinity::kDownstream);
- ASSERT_NE(nullptr, text_field_position);
-
- // Validate that two positions in the text field with the same text offsets
- // but different anchors are logically equal.
- EXPECT_EQ(*inline_text_position, *text_field_position);
- EXPECT_EQ(*text_field_position, *inline_text_position);
-}
-
-TEST_F(AXPositionTest, TextPositionComparisonSearchBox) {
- g_ax_embedded_object_behavior = AXEmbeddedObjectBehavior::kExposeCharacter;
-
- // ++1 kRootWebArea
- // ++++2 kSearchBox editable editableRoot=true
- // ++++++3 kGenericContainer
- // ++++++++4 kGenericContainer editable
- // ++++++++++5 kStaticText editable "Hello"
- // ++++++++++++6 kInlineTextBox "Hello"
- // ++++7 kButton
- // ++++++8 kStaticText "X"
- // ++++++++9 kInlineTextBox "X"
- AXNodeData root_1;
- AXNodeData search_box_2;
- AXNodeData generic_container_3;
- AXNodeData generic_container_4;
- AXNodeData static_text_5;
- AXNodeData inline_box_6;
- AXNodeData button_7;
- AXNodeData static_text_8;
- AXNodeData inline_box_9;
-
- root_1.id = 1;
- search_box_2.id = 2;
- generic_container_3.id = 3;
- generic_container_4.id = 4;
- static_text_5.id = 5;
- inline_box_6.id = 6;
- button_7.id = 7;
- static_text_8.id = 8;
- inline_box_9.id = 9;
-
- root_1.role = ax::mojom::Role::kRootWebArea;
- root_1.child_ids = {search_box_2.id, button_7.id};
-
- search_box_2.role = ax::mojom::Role::kSearchBox;
- search_box_2.AddState(ax::mojom::State::kEditable);
- search_box_2.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot, true);
- search_box_2.child_ids = {generic_container_3.id};
-
- generic_container_3.role = ax::mojom::Role::kGenericContainer;
- generic_container_3.child_ids = {generic_container_4.id};
-
- generic_container_4.role = ax::mojom::Role::kGenericContainer;
- generic_container_4.AddState(ax::mojom::State::kEditable);
- generic_container_4.child_ids = {static_text_5.id};
-
- static_text_5.role = ax::mojom::Role::kStaticText;
- static_text_5.SetName("Hello");
- static_text_5.child_ids = {inline_box_6.id};
-
- inline_box_6.role = ax::mojom::Role::kInlineTextBox;
- inline_box_6.SetName("Hello");
-
- button_7.role = ax::mojom::Role::kButton;
- button_7.child_ids = {static_text_8.id};
-
- static_text_8.role = ax::mojom::Role::kStaticText;
- static_text_8.SetName("X");
- static_text_8.child_ids = {inline_box_9.id};
-
- inline_box_9.role = ax::mojom::Role::kInlineTextBox;
- inline_box_9.SetName("X");
-
- SetTree(CreateAXTree({root_1, search_box_2, generic_container_3,
- generic_container_4, static_text_5, inline_box_6,
- button_7, static_text_8, inline_box_9}));
-
- // TextPosition anchor_role=inlineTextBox text_offset=5 annotated_text=hello<>
- TestPositionType inline_text_position = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box_6.id, 5, ax::mojom::TextAffinity::kDownstream);
- ASSERT_NE(nullptr, inline_text_position);
-
- // TextPosition anchor_role=searchBox text_offset=5 annotated_text=hello<>
- TestPositionType search_box_position = AXNodePosition::CreateTextPosition(
- GetTreeID(), search_box_2.id, 5, ax::mojom::TextAffinity::kDownstream);
- ASSERT_NE(nullptr, search_box_position);
-
- EXPECT_EQ(*search_box_position, *inline_text_position);
- EXPECT_EQ(*inline_text_position, *search_box_position);
-}
-
//
// Instantiations of parameterized tests.
//
diff --git a/chromium/ui/accessibility/ax_node_unittest.cc b/chromium/ui/accessibility/ax_node_unittest.cc
new file mode 100644
index 00000000000..ce7500ef022
--- /dev/null
+++ b/chromium/ui/accessibility/ax_node_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/ax_node.h"
+
+#include "testing/gtest/include/gtest/gtest.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_data.h"
+#include "ui/accessibility/ax_tree_id.h"
+
+namespace ui {
+
+TEST(AXNodeTest, GetLowestPlatformAncestor) {
+ // ++kRootWebArea
+ // ++++kButton (IsLeaf=false)
+ // ++++++kGenericContainer ignored
+ // ++++++++kStaticText "Hello"
+ // ++++++++++kInlineTextBox "Hello" (IsLeaf=true)
+ // ++++kTextField "World" (IsLeaf=true)
+ // ++++++kStaticText "World"
+ // ++++++++kInlineTextBox "World" (IsLeaf=true)
+ AXNodeData root;
+ AXNodeData button;
+ AXNodeData generic_container;
+ AXNodeData static_text_1;
+ AXNodeData inline_box_1;
+ AXNodeData text_field;
+ AXNodeData static_text_2;
+ AXNodeData inline_box_2;
+
+ root.id = 1;
+ button.id = 2;
+ generic_container.id = 3;
+ static_text_1.id = 4;
+ inline_box_1.id = 5;
+ text_field.id = 6;
+ static_text_2.id = 7;
+ inline_box_2.id = 8;
+
+ root.role = ax::mojom::Role::kRootWebArea;
+ root.child_ids = {button.id, text_field.id};
+
+ button.role = ax::mojom::Role::kButton;
+ button.SetValue("Hello");
+ button.child_ids = {generic_container.id};
+
+ generic_container.role = ax::mojom::Role::kGenericContainer;
+ generic_container.AddState(ax::mojom::State::kIgnored);
+ generic_container.child_ids = {static_text_1.id};
+
+ static_text_1.role = ax::mojom::Role::kStaticText;
+ static_text_1.SetName("Hello");
+ static_text_1.child_ids = {inline_box_1.id};
+
+ inline_box_1.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_1.SetName("Hello");
+
+ text_field.role = ax::mojom::Role::kTextField;
+ text_field.AddState(ax::mojom::State::kEditable);
+ text_field.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot, true);
+ text_field.SetValue("World");
+ text_field.child_ids = {static_text_2.id};
+
+ static_text_2.role = ax::mojom::Role::kStaticText;
+ static_text_2.AddState(ax::mojom::State::kEditable);
+ static_text_2.SetName("World");
+ static_text_2.child_ids = {inline_box_2.id};
+
+ inline_box_2.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_2.AddState(ax::mojom::State::kEditable);
+ inline_box_2.SetName("World");
+
+ AXTreeUpdate initial_state;
+ initial_state.root_id = root.id;
+ initial_state.nodes = {root, button, generic_container,
+ static_text_1, inline_box_1, text_field,
+ static_text_2, inline_box_2};
+ initial_state.has_tree_data = true;
+
+ AXTreeData tree_data;
+ tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
+ tree_data.title = "Application";
+ initial_state.tree_data = tree_data;
+
+ AXTree tree;
+ ASSERT_TRUE(tree.Unserialize(initial_state));
+
+ const AXNode* root_node = tree.root();
+ ASSERT_EQ(root.id, root_node->id());
+ EXPECT_EQ(root_node, root_node->GetLowestPlatformAncestor());
+
+ const AXNode* button_node = root_node->children()[0];
+ ASSERT_EQ(button.id, button_node->id());
+ EXPECT_EQ(button_node, button_node->GetLowestPlatformAncestor());
+
+ const AXNode* generic_container_node = button_node->children()[0];
+ ASSERT_EQ(generic_container.id, generic_container_node->id());
+ EXPECT_EQ(button_node, generic_container_node->GetLowestPlatformAncestor());
+
+ const AXNode* static_text_1_node = generic_container_node->children()[0];
+ ASSERT_EQ(static_text_1.id, static_text_1_node->id());
+ EXPECT_EQ(static_text_1_node,
+ static_text_1_node->GetLowestPlatformAncestor());
+
+ const AXNode* inline_box_1_node = static_text_1_node->children()[0];
+ ASSERT_EQ(inline_box_1.id, inline_box_1_node->id());
+ EXPECT_EQ(static_text_1_node, inline_box_1_node->GetLowestPlatformAncestor());
+
+ const AXNode* text_field_node = root_node->children()[1];
+ ASSERT_EQ(text_field.id, text_field_node->id());
+ EXPECT_EQ(text_field_node, text_field_node->GetLowestPlatformAncestor());
+
+ const AXNode* static_text_2_node = text_field_node->children()[0];
+ ASSERT_EQ(static_text_2.id, static_text_2_node->id());
+ EXPECT_EQ(text_field_node, static_text_2_node->GetLowestPlatformAncestor());
+
+ const AXNode* inline_box_2_node = static_text_2_node->children()[0];
+ ASSERT_EQ(inline_box_2.id, inline_box_2_node->id());
+ EXPECT_EQ(text_field_node, inline_box_2_node->GetLowestPlatformAncestor());
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/ax_param_traits_macros.h b/chromium/ui/accessibility/ax_param_traits_macros.h
index c653f646f42..df7ce0b9ca6 100644
--- a/chromium/ui/accessibility/ax_param_traits_macros.h
+++ b/chromium/ui/accessibility/ax_param_traits_macros.h
@@ -44,6 +44,7 @@ IPC_ENUM_TRAITS_MAX_VALUE(ax::mojom::TextBoundary,
ax::mojom::TextBoundary::kMaxValue)
IPC_ENUM_TRAITS_MAX_VALUE(ax::mojom::MoveDirection,
ax::mojom::MoveDirection::kMaxValue)
+IPC_ENUM_TRAITS_MAX_VALUE(ax::mojom::Action, ax::mojom::Action::kMaxValue)
IPC_STRUCT_TRAITS_BEGIN(ui::AXRelativeBounds)
IPC_STRUCT_TRAITS_MEMBER(offset_container_id)
@@ -55,6 +56,7 @@ IPC_STRUCT_TRAITS_BEGIN(ui::AXEvent)
IPC_STRUCT_TRAITS_MEMBER(event_type)
IPC_STRUCT_TRAITS_MEMBER(id)
IPC_STRUCT_TRAITS_MEMBER(event_from)
+ IPC_STRUCT_TRAITS_MEMBER(event_from_action)
IPC_STRUCT_TRAITS_MEMBER(event_intents)
IPC_STRUCT_TRAITS_MEMBER(action_request_id)
IPC_STRUCT_TRAITS_END()
@@ -109,6 +111,7 @@ IPC_STRUCT_TRAITS_BEGIN(ui::AXTreeUpdate)
IPC_STRUCT_TRAITS_MEMBER(root_id)
IPC_STRUCT_TRAITS_MEMBER(nodes)
IPC_STRUCT_TRAITS_MEMBER(event_from)
+ IPC_STRUCT_TRAITS_MEMBER(event_from_action)
IPC_STRUCT_TRAITS_MEMBER(event_intents)
IPC_STRUCT_TRAITS_END()
diff --git a/chromium/ui/accessibility/ax_position.h b/chromium/ui/accessibility/ax_position.h
index e68b38c435a..c25deec373c 100644
--- a/chromium/ui/accessibility/ax_position.h
+++ b/chromium/ui/accessibility/ax_position.h
@@ -16,23 +16,66 @@
#include <utility>
#include <vector>
+#include "base/containers/contains.h"
#include "base/containers/stack.h"
#include "base/i18n/break_iterator.h"
#include "base/optional.h"
-#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_enum_util.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_node_text_styles.h"
#include "ui/accessibility/ax_role_properties.h"
#include "ui/accessibility/ax_tree_id.h"
+#include "ui/accessibility/ax_tree_manager.h"
+#include "ui/accessibility/ax_tree_manager_map.h"
#include "ui/gfx/utf16_indexing.h"
namespace ui {
+namespace {
+
+// Returns the parent node of the provided child. Returns the parent node's tree
+// id and node id through the provided output parameters,|parent_tree_id| and
+// |parent_id|.
+AXNode* GetParent(AXNode* child,
+ AXTreeID child_tree_id,
+ AXTreeID* parent_tree_id,
+ AXNodeID* parent_id) {
+ DCHECK(parent_tree_id);
+ DCHECK(parent_id);
+ *parent_tree_id = AXTreeIDUnknown();
+ *parent_id = kInvalidAXNodeID;
+ if (!child)
+ return nullptr;
+
+ AXNode* parent = child->parent();
+ *parent_tree_id = child_tree_id;
+
+ if (!parent) {
+ AXTreeManager* manager =
+ AXTreeManagerMap::GetInstance().GetManager(child_tree_id);
+ if (manager) {
+ parent = manager->GetParentNodeFromParentTreeAsAXNode();
+ *parent_tree_id = manager->GetParentTreeID();
+ }
+ }
+
+ if (!parent) {
+ *parent_tree_id = AXTreeIDUnknown();
+ return parent;
+ }
+
+ *parent_id = parent->id();
+ return parent;
+}
+
+} // namespace
+
// Defines the type of position in the accessibility tree.
// A tree position is used when referring to a specific child of a node in the
// accessibility tree.
@@ -53,6 +96,7 @@ enum class AXBoundaryBehavior {
};
// Describes in further detail what type of boundary a current position is on.
+//
// For complex boundaries such as format boundaries, it can be useful to know
// why a particular boundary was chosen.
enum class AXBoundaryType {
@@ -60,10 +104,12 @@ enum class AXBoundaryType {
kNone,
// At a unit boundary (e.g. a format boundary).
kUnitBoundary,
- // At the start of a document.
- kDocumentStart,
- // At the end of a document.
- kDocumentEnd
+ // At the start of the whole content, possibly spanning multiple accessibility
+ // trees.
+ kContentStart,
+ // At the end of the whole content, possibly spanning multiple accessibility
+ // trees.
+ kContentEnd
};
// When converting to an unignored position, determines how to adjust the new
@@ -90,16 +136,20 @@ enum class AXRangeExpandBehavior {
kRightFirst
};
-// Some platforms require empty objects to be represented by a replacement
-// character in order for text navigation to work correctly. This enum controls
-// whether a replacement character will be exposed for such objects.
+// Some platforms require most objects, including empty objects, to be
+// represented by an "embedded object character" in order for text navigation to
+// work correctly. This enum controls whether a replacement character will be
+// exposed for such objects.
+//
+// When an embedded object is replaced by this special character, the
+// expectations are the same with this character as with other ordinary
+// characters.
//
-// When an embedded object is replaced by a real character, the expectations
-// are the same with this character as with other ordinary characters.
// For example, with UIA on Windows, we need to be able to navigate inside and
// outside of this character as if it was an ordinary character, using the
-// AXPlatformNodeTextRangeProvider methods. Since an embedded object character
-// is the only character in a node, we also treat this character as a word.
+// `AXPlatformNodeTextRangeProvider` methods. Since an "embedded object
+// character" is the only character in a node, we also treat this character as a
+// word.
enum class AXEmbeddedObjectBehavior {
kExposeCharacter,
kSuppressCharacter,
@@ -108,6 +158,14 @@ enum class AXEmbeddedObjectBehavior {
// Controls whether embedded objects are represented by a replacement
// character. This is initialized to a per-platform default but can be
// overridden for testing.
+//
+// On some platforms, most objects are represented in the text of their parents
+// with a special "embedded object character" and not with their actual text
+// contents. Also on the same platforms, if a node has only ignored descendants,
+// i.e., it appears to be empty to assistive software, we need to treat it as a
+// character and a word boundary. For example, an empty text field should act as
+// a character and a word boundary when a screen reader user tries to navigate
+// through it, otherwise the text field would be missed by the user.
AX_EXPORT extern AXEmbeddedObjectBehavior g_ax_embedded_object_behavior;
// Forward declarations.
@@ -169,23 +227,16 @@ class AXPosition {
static const int INVALID_INDEX = -2;
static const int INVALID_OFFSET = -1;
- // Replacement character used to represent an empty object. See
- // AXEmbeddedObjectBehavior for more information.
- //
- // Duplicate of AXPlatformNodeBase::kEmbeddedCharacter because we don't want
- // to include platform specific code in here.
- static constexpr base::char16 kEmbeddedCharacter = L'\xfffc';
-
static AXPositionInstance CreateNullPosition() {
AXPositionInstance new_position(new AXPositionType());
- new_position->Initialize(
- AXPositionKind::NULL_POSITION, AXTreeIDUnknown(), AXNode::kInvalidAXID,
- INVALID_INDEX, INVALID_OFFSET, ax::mojom::TextAffinity::kDownstream);
+ new_position->Initialize(AXPositionKind::NULL_POSITION, AXTreeIDUnknown(),
+ kInvalidAXNodeID, INVALID_INDEX, INVALID_OFFSET,
+ ax::mojom::TextAffinity::kDownstream);
return new_position;
}
static AXPositionInstance CreateTreePosition(AXTreeID tree_id,
- AXNode::AXID anchor_id,
+ AXNodeID anchor_id,
int child_index) {
AXPositionInstance new_position(new AXPositionType());
new_position->Initialize(AXPositionKind::TREE_POSITION, tree_id, anchor_id,
@@ -196,7 +247,7 @@ class AXPosition {
static AXPositionInstance CreateTextPosition(
AXTreeID tree_id,
- AXNode::AXID anchor_id,
+ AXNodeID anchor_id,
int text_offset,
ax::mojom::TextAffinity affinity) {
AXPositionInstance new_position(new AXPositionType());
@@ -216,12 +267,36 @@ class AXPosition {
virtual AXPositionInstance Clone() const = 0;
+ AXPositionInstance CloneWithDownstreamAffinity() const {
+ if (!IsTextPosition()) {
+ NOTREACHED() << "Only text positions have affinity.";
+ return CreateNullPosition();
+ }
+
+ AXPositionInstance clone_with_downstream_affinity = Clone();
+ clone_with_downstream_affinity->affinity_ =
+ ax::mojom::TextAffinity::kDownstream;
+ return clone_with_downstream_affinity;
+ }
+
+ AXPositionInstance CloneWithUpstreamAffinity() const {
+ if (!IsTextPosition()) {
+ NOTREACHED() << "Only text positions have affinity.";
+ return CreateNullPosition();
+ }
+
+ AXPositionInstance clone_with_upstream_affinity = Clone();
+ clone_with_upstream_affinity->affinity_ =
+ ax::mojom::TextAffinity::kUpstream;
+ return clone_with_upstream_affinity;
+ }
+
// A serialization of a position as POD. Not for sharing on disk or sharing
// across thread or process boundaries, just for passing a position to an
// API that works with positions as opaque objects.
struct SerializedPosition {
AXPositionKind kind;
- AXNode::AXID anchor_id;
+ AXNodeID anchor_id;
int child_index;
int text_offset;
ax::mojom::TextAffinity affinity;
@@ -294,12 +369,12 @@ class AXPosition {
if (!IsTextPosition() || text_offset_ > MaxTextOffset())
return str;
- base::string16 text = GetText();
+ const base::string16 text = GetText();
DCHECK_GE(text_offset_, 0);
- int max_text_offset = MaxTextOffset();
- DCHECK_LE(text_offset_, max_text_offset);
+ const size_t max_text_offset = text.size();
+ DCHECK_LE(text_offset_, int{max_text_offset}) << text;
base::string16 annotated_text;
- if (text_offset_ == max_text_offset) {
+ if (text_offset_ == int{max_text_offset}) {
annotated_text = text + base::WideToUTF16(L"<>");
} else {
annotated_text = text.substr(0, text_offset_) + base::WideToUTF16(L"<") +
@@ -311,14 +386,26 @@ class AXPosition {
}
AXTreeID tree_id() const { return tree_id_; }
- AXNode::AXID anchor_id() const { return anchor_id_; }
+ AXNodeID anchor_id() const { return anchor_id_; }
AXNodeType* GetAnchor() const {
- if (tree_id_ == AXTreeIDUnknown() || anchor_id_ == AXNode::kInvalidAXID)
+ if (tree_id_ == AXTreeIDUnknown() || anchor_id_ == kInvalidAXNodeID)
return nullptr;
return GetNodeInTree(tree_id_, anchor_id_);
}
+ int GetAnchorSiblingCount() const {
+ if (IsNullPosition())
+ return 0;
+
+ AXPositionInstance parent_position = AsTreePosition()->CreateParentPosition(
+ ax::mojom::MoveDirection::kBackward);
+ if (!parent_position->IsNullPosition())
+ return parent_position->AnchorChildCount();
+
+ return 0;
+ }
+
AXPositionKind kind() const { return kind_; }
int child_index() const { return child_index_; }
int text_offset() const { return text_offset_; }
@@ -350,10 +437,11 @@ class AXPosition {
// If this position is an "after children" position, consider the
// position to be ignored if the last child is ignored. This is because
- // the last child will not be visible in the unignored tree. If the
- // position is not adjusted, the resulting position would erroneously
- // point before the second child in the unignored subtree rooted at the
- // last child.
+ // the last child will not be visible in the unignored tree.
+ //
+ // For example, in the following tree if the position is not adjusted,
+ // the resulting position would erroneously point before the second
+ // child in the unignored subtree rooted at the last child.
//
// 1 kRootWebArea
// ++2 kGenericContainer ignored
@@ -403,7 +491,6 @@ class AXPosition {
bool IsLeaf() const {
if (IsNullPosition())
return false;
-
return !AnchorChildCount() || IsEmptyObjectReplacedByCharacter();
}
@@ -413,17 +500,16 @@ class AXPosition {
switch (kind_) {
case AXPositionKind::NULL_POSITION:
return tree_id_ == AXTreeIDUnknown() &&
- anchor_id_ == AXNode::kInvalidAXID &&
+ anchor_id_ == kInvalidAXNodeID &&
child_index_ == INVALID_INDEX &&
text_offset_ == INVALID_OFFSET &&
affinity_ == ax::mojom::TextAffinity::kDownstream;
case AXPositionKind::TREE_POSITION:
return GetAnchor() &&
(child_index_ == BEFORE_TEXT ||
- (child_index_ >= 0 && child_index_ <= AnchorChildCount())) &&
- !IsInDescendantOfEmptyObject();
+ (child_index_ >= 0 && child_index_ <= AnchorChildCount()));
case AXPositionKind::TEXT_POSITION:
- if (!GetAnchor() || IsInDescendantOfEmptyObject())
+ if (!GetAnchor())
return false;
// For performance reasons we skip any validation of the text offset
@@ -444,11 +530,9 @@ class AXPosition {
case AXPositionKind::NULL_POSITION:
return false;
case AXPositionKind::TREE_POSITION:
- if (text_offset_ > 0)
- return false;
- if (!IsLeaf() || text_offset_ == 0)
- return child_index_ == 0;
- return child_index_ == BEFORE_TEXT;
+ if (IsLeaf())
+ return child_index_ == BEFORE_TEXT;
+ return child_index_ == 0;
case AXPositionKind::TEXT_POSITION:
return text_offset_ == 0;
}
@@ -535,13 +619,12 @@ class AXPosition {
if (text_position->AtEndOfAnchor() &&
!text_position->AtEndOfTextSpan() &&
text_position->IsInWhiteSpace() &&
- GetNextOnLineID(text_position->anchor_id_) ==
- AXNode::kInvalidAXID) {
+ GetNextOnLineID(text_position->anchor_id_) == kInvalidAXNodeID) {
return true;
}
return GetPreviousOnLineID(text_position->anchor_id_) ==
- AXNode::kInvalidAXID &&
+ kInvalidAXNodeID &&
text_position->AtStartOfAnchor();
}
}
@@ -560,7 +643,7 @@ class AXPosition {
// a non-empty text position in which case the end of line iterators
// must move to the line end of the non-empty content. Specified next
// line IDs are ignored.
- if (!text_position->MaxTextOffset())
+ if (text_position->MaxTextOffset() == 0)
return false;
// If affinity has been used to specify whether the caret is at the end
@@ -598,12 +681,11 @@ class AXPosition {
// in most but not all cases, the parent of an inline text box is a
// static text object, whose end signifies the end of the text span. One
// exception is line breaks.
- if (GetNextOnLineID(text_position->anchor_id_) ==
- AXNode::kInvalidAXID) {
+ if (GetNextOnLineID(text_position->anchor_id_) == kInvalidAXNodeID) {
return (!text_position->AtEndOfTextSpan() &&
text_position->IsInWhiteSpace() &&
GetPreviousOnLineID(text_position->anchor_id_) !=
- AXNode::kInvalidAXID)
+ kInvalidAXNodeID)
? text_position->AtStartOfAnchor()
: text_position->AtEndOfAnchor();
}
@@ -617,16 +699,16 @@ class AXPosition {
// |AtStartOfParagraph| is asymmetric from |AtEndOfParagraph| because of
// trailing whitespace collapse rules.
// The start of a paragraph should be a leaf text position (or equivalent),
- // either at the start of the document, or at the start of the next leaf text
- // position from the one representing the end of the previous paragraph.
+ // either at the start of the whole content, or at the start of the next leaf
+ // text position from the one representing the end of the previous paragraph.
// A position |AsLeafTextPosition| is the start of a paragraph if all of the
// following are true :
// 1. The current leaf text position must be an unignored position at
// the start of an anchor.
// 2. The current position is not whitespace only, unless it is also
- // the first leaf text position within the document.
+ // the first leaf text position within the whole content.
// 3. Either (a) the current leaf text position is the first leaf text
- // position in the document, or (b) there are no line breaking
+ // position in the whole content, or (b) there are no line breaking
// objects between it and the previous non-whitespace leaf text
// position.
bool AtStartOfParagraph() const {
@@ -644,14 +726,16 @@ class AXPosition {
return false;
// 2. The current position is not whitespace only, unless it is also
- // the first leaf text position within the document.
+ // the first leaf text position within the whole content.
if (text_position->IsInWhiteSpace()) {
- return text_position->CreatePreviousLeafTextPosition()
+ return text_position
+ ->CreatePreviousLeafTextPosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary))
->IsNullPosition();
}
// 3. Either (a) the current leaf text position is the first leaf text
- // position in the document, or (b) there are no line breaking
+ // position in the whole content, or (b) there are no line breaking
// objects between it and the previous non-whitespace leaf text
// position.
//
@@ -660,7 +744,7 @@ class AXPosition {
// If a valid position was found, then this position cannot be
// the start of a paragraph.
// This will return a null position when an anchor movement would
- // cross a paragraph boundary, or the start of document was reached.
+ // cross a paragraph boundary, or the start of content was reached.
bool crossed_line_breaking_object_token = false;
const AbortMovePredicate abort_move_predicate =
base::BindRepeating(&AbortMoveAtParagraphBoundary,
@@ -669,12 +753,12 @@ class AXPosition {
AXPositionInstance previous_text_position = text_position->Clone();
do {
previous_text_position =
- previous_text_position->CreatePreviousTextAnchorPosition(
+ previous_text_position->CreatePreviousLeafTextPosition(
abort_move_predicate);
// If the previous position is whitespace, then continue searching
// until a non-whitespace leaf text position is found within the
// current paragraph because whitespace is supposed to be collapsed.
- // There's a chance that |CreatePreviousTextAnchorPosition| will
+ // There's a chance that |CreatePreviousLeafTextPosition| will
// return whitespace that should be appended to a previous paragraph
// rather than separating two pieces of the current paragraph.
} while (previous_text_position->IsInWhiteSpace() ||
@@ -687,14 +771,14 @@ class AXPosition {
// |AtEndOfParagraph| is asymmetric from |AtStartOfParagraph| because of
// trailing whitespace collapse rules.
// The end of a paragraph should be a leaf text position (or equivalent),
- // either at the end of the document, or at the end of the previous leaf text
- // position from the one representing the start of the next paragraph.
- // A position |AsLeafTextPosition| is the end of a paragraph if all of the
+ // either at the end of the whole content, or at the end of the previous leaf
+ // text position from the one representing the start of the next paragraph. A
+ // position |AsLeafTextPosition| is the end of a paragraph if all of the
// following are true :
// 1. The current leaf text position must be an unignored position at
// the end of an anchor.
// 2. Either (a) the current leaf text position is the last leaf text
- // position in the document, or (b) there are no line breaking
+ // position in the whole content, or (b) there are no line breaking
// objects between it and the next leaf text position except when
// the next leaf text position is whitespace only since whitespace
// must be collapsed.
@@ -718,7 +802,7 @@ class AXPosition {
return false;
// 2. Either (a) the current leaf text position is the last leaf text
- // position in the document, or (b) there are no line breaking
+ // position in the whole content, or (b) there are no line breaking
// objects between it and the next leaf text position except when
// the next leaf text position is whitespace only since whitespace
// must be collapsed.
@@ -727,10 +811,10 @@ class AXPosition {
// using the paragraph boundary abort predicate.
// If a null position was found, then this position must be the end of
// a paragraph.
- // |CreateNextTextAnchorPosition| + |AbortMoveAtParagraphBoundary|
+ // |CreateNextLeafTextPosition| + |AbortMoveAtParagraphBoundary|
// will return a null position when an anchor movement would
// cross a paragraph boundary and there is no doubt that it is the end
- // of a paragraph, or the end of document was reached.
+ // of a paragraph, or the end of content was reached.
// There are some fringe cases related to whitespace collapse that
// cannot be handled easily with only |AbortMoveAtParagraphBoundary|.
bool crossed_line_breaking_object_token = false;
@@ -740,7 +824,7 @@ class AXPosition {
AXPositionInstance next_text_position = text_position->Clone();
do {
- next_text_position = next_text_position->CreateNextTextAnchorPosition(
+ next_text_position = next_text_position->CreateNextLeafTextPosition(
abort_move_predicate);
} while (next_text_position->IsIgnored());
if (next_text_position->IsNullPosition())
@@ -771,6 +855,8 @@ class AXPosition {
}
}
+ // Page boundaries are only supported in certain content types, e.g. PDF
+ // documents.
bool AtStartOfPage() const {
AXPositionInstance text_position = AsLeafTextPosition();
switch (text_position->kind_) {
@@ -788,15 +874,17 @@ class AXPosition {
// If a valid position was found, then this position cannot be
// the start of a page.
// This will return a null position when an anchor movement would
- // cross a page boundary, or the start of document was reached.
+ // cross a page boundary, or the start of content was reached.
AXPositionInstance previous_text_position =
- text_position->CreatePreviousTextAnchorPosition(
+ text_position->CreatePreviousLeafTextPosition(
base::BindRepeating(&AbortMoveAtPageBoundary));
return previous_text_position->IsNullPosition();
}
}
}
+ // Page boundaries are only supported in certain content types, e.g. PDF
+ // documents.
bool AtEndOfPage() const {
AXPositionInstance text_position = AsLeafTextPosition();
switch (text_position->kind_) {
@@ -814,45 +902,46 @@ class AXPosition {
// If a valid position was found, then this position cannot be
// the end of a page.
// This will return a null position when an anchor movement would
- // cross a page boundary, or the end of document was reached.
+ // cross a page boundary, or the end of content was reached.
AXPositionInstance next_text_position =
- text_position->CreateNextTextAnchorPosition(
+ text_position->CreateNextLeafTextPosition(
base::BindRepeating(&AbortMoveAtPageBoundary));
return next_text_position->IsNullPosition();
}
}
}
+ // Returns true if this position is at the start of the current accessibility
+ // tree, such as the current iframe, webpage, PDF document, dialog or window.
+ // Note that the current webpage could be made up of multiple accessibility
+ // trees stitched together, e.g. an out-of-process iframe will be in its own
+ // accessibility tree. For the purposes of this method, we don't distinguish
+ // between out-of-process and in-process iframes, treating them both as tree
+ // boundaries.
bool AtStartOfAXTree() const {
- if (IsNullPosition())
+ if (IsNullPosition() || !AtStartOfAnchor())
return false;
- if (AtStartOfAnchor()) {
- AXPositionInstance previous_anchor = CreatePreviousAnchorPosition();
+ AXPositionInstance previous_anchor = CreatePreviousAnchorPosition();
+ // The start of the whole content should also be the start of an AXTree.
+ if (previous_anchor->IsNullPosition())
+ return true;
- // Consider the start of the document as the start of an AXTree.
- if (previous_anchor->IsNullPosition())
- return true;
- else
- return previous_anchor->tree_id() != tree_id();
- }
- return false;
+ return previous_anchor->tree_id() != tree_id();
}
+ // Returns true if this position is at the end of the current accessibility
+ // tree, such as the current iframe, webpage, PDF document, dialog or window.
+ // Note that the current webpage could be made up of multiple accessibility
+ // trees stitched together, e.g. an out-of-process iframe will be in its own
+ // accessibility tree. For the purposes of this method, we don't distinguish
+ // between out-of-process and in-process iframes, treating them both as tree
+ // boundaries.
bool AtEndOfAXTree() const {
- if (IsNullPosition())
+ if (IsNullPosition() || !IsLeaf() || !AtEndOfAnchor())
return false;
- if (AtEndOfAnchor()) {
- AXPositionInstance next_anchor = CreateNextAnchorPosition();
-
- // Consider the end of the document as the end of an AXTree.
- if (next_anchor->IsNullPosition())
- return true;
- else
- return next_anchor->tree_id() != tree_id();
- }
- return false;
+ return *CreatePositionAtEndOfAXTree() == *this;
}
AXBoundaryType GetFormatStartBoundaryType() const {
@@ -862,8 +951,11 @@ class AXPosition {
return AXBoundaryType::kNone;
// Treat the first iterable node as a format boundary.
- if (CreatePreviousLeafTreePosition()->IsNullPosition())
- return AXBoundaryType::kDocumentStart;
+ if (CreatePreviousLeafTreePosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary))
+ ->IsNullPosition()) {
+ return AXBoundaryType::kContentStart;
+ }
// Ignored positions cannot be format boundaries.
if (IsIgnored())
@@ -895,8 +987,10 @@ class AXPosition {
return AXBoundaryType::kNone;
// Treat the last iterable node as a format boundary
- if (CreateNextLeafTreePosition()->IsNullPosition())
- return AXBoundaryType::kDocumentEnd;
+ if (CreateNextLeafTreePosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary))
+ ->IsNullPosition())
+ return AXBoundaryType::kContentEnd;
// Ignored positions cannot be format boundaries.
if (IsIgnored())
@@ -965,39 +1059,42 @@ class AXPosition {
}
}
- bool AtStartOfDocument() const {
- if (IsNullPosition())
+ // Returns true if this position is at the start of all content. This might
+ // refer to e.g. a single webpage (made up of multiple iframes), or a PDF
+ // document. Note that the current webpage could be made up of multiple
+ // accessibility trees stitched together, so even though a position could be
+ // at the start of a specific accessibility tree, it might not be at the start
+ // of the whole content.
+ bool AtStartOfContent() const {
+ if (IsNullPosition() || !AtStartOfAnchor())
return false;
- return IsDocument(GetAnchorRole()) && AtStartOfAnchor();
- }
- bool AtEndOfDocument() const {
- if (IsNullPosition())
- return false;
- return AtLastNodeInTree() && AtEndOfAnchor();
+ return *CreatePositionAtStartOfContent() == *this;
}
- bool AtLastNodeInTree() const {
- if (IsNullPosition())
+ // Returns true if this position is at the end of all content. This might
+ // refer to e.g. a single webpage (made up of multiple iframes), or a PDF
+ // document. Note that the current webpage could be made up of multiple
+ // accessibility trees stitched together, so even though a position could be
+ // at the end of a specific accessibility tree, it might not be at the end of
+ // the whole content.
+ bool AtEndOfContent() const {
+ if (IsNullPosition() || !AtEndOfAnchor())
return false;
- // Avoid a potentionally expensive MaxTextOffset call by only using tree
- // positions. The only thing that matters is whether our anchor_id_ is at
- // the last anchor of the document, so we're free to ignore text_offset_.
- AXPositionInstance tree_position =
- CreateTreePosition(tree_id_, anchor_id_, 0);
- return tree_position->CreateNextAnchorPosition()->IsNullPosition();
+ return *CreatePositionAtEndOfContent() == *this;
}
- // This method finds the lowest common AXNodeType of |this| and |second|.
- AXNodeType* LowestCommonAnchor(const AXPosition& second) const {
- if (IsNullPosition() || second.IsNullPosition())
+ // This method finds the lowest common ancestor node in the accessibility tree
+ // of this and |other| positions' anchor nodes.
+ AXNodeType* LowestCommonAnchor(const AXPosition& other) const {
+ if (IsNullPosition() || other.IsNullPosition())
return nullptr;
- if (GetAnchor() == second.GetAnchor())
+ if (GetAnchor() == other.GetAnchor())
return GetAnchor();
base::stack<AXNodeType*> our_ancestors = GetAncestorAnchors();
- base::stack<AXNodeType*> other_ancestors = second.GetAncestorAnchors();
+ base::stack<AXNodeType*> other_ancestors = other.GetAncestorAnchors();
AXNodeType* common_anchor = nullptr;
while (!our_ancestors.empty() && !other_ancestors.empty() &&
@@ -1015,16 +1112,17 @@ class AXPosition {
// Also, this method uses position instead of tree logic to traverse the tree,
// because positions can handle moving across multiple trees, while trees
// cannot.
- AXPositionInstance LowestCommonAncestor(const AXPosition& second) const {
- return CreateAncestorPosition(LowestCommonAnchor(second));
+ AXPositionInstance LowestCommonAncestor(
+ const AXPosition& other,
+ ax::mojom::MoveDirection move_direction) const {
+ return CreateAncestorPosition(LowestCommonAnchor(other), move_direction);
}
// See "CreateParentPosition" for an explanation of the use of
// |move_direction|.
AXPositionInstance CreateAncestorPosition(
const AXNodeType* ancestor_anchor,
- ax::mojom::MoveDirection move_direction =
- ax::mojom::MoveDirection::kForward) const {
+ ax::mojom::MoveDirection move_direction) const {
if (!ancestor_anchor)
return CreateNullPosition();
@@ -1050,12 +1148,23 @@ class AXPosition {
return CreateNullPosition();
if (AXNodeType* empty_object_node = GetEmptyObjectAncestorNode()) {
- // In this class and on certain platforms, we define the empty object
- // as one that doesn't expose its underlying content. Its content is
- // replaced by the empty object character (string of length 1). A
- // position on a descendant of an empty object is invalid. To make it
- // valid we move the position from the descendant to the empty object
- // node itself.
+ // In this class, (but only on certain platforms), we define the empty
+ // node as a leaf node (see `AXNode::IsLeaf()`) that doesn't have any
+ // content. So that such nodes will act as a character and a word
+ // boundary, we insert an "embedded object replacement character" in
+ // their text contents. This character is a string of length
+ // `AXNode::kEmbeddedCharacterLength`. For example, an empty text
+ // field should act as a character and a word boundary when a screen
+ // reader user tries to navigate through it, otherwise the text field
+ // would be missed by the user.
+ //
+ // Since we just explained that empty leaf nodes expose the "embedded
+ // object replacement character" in their text contents, and since we
+ // assume that all text is found only on leaf nodes, we should hide
+ // any descendants. Thus, a position on a descendant of an empty
+ // object is defined as invalid. To make it valid we move the position
+ // from the descendant to the empty leaf node itself. Otherwise,
+ // character and word navigation won't work properly.
return CreateTreePosition(
position->tree_id(), GetAnchorID(empty_object_node),
position->child_index() == BEFORE_TEXT ? BEFORE_TEXT : 0);
@@ -1080,14 +1189,15 @@ class AXPosition {
// exposed. See comment above in similar implementation for
// AXPositionKind::TREE_POSITION.
//
- // We set the |text_offset_| to either 0 or 1 here because the
- // MaxTextOffset of an empty object is 1 (the empty object character,
- // a string of length 1). If the invalid position was already at the
- // start of the node, we set it to 0.
- return CreateTextPosition(position->tree_id(),
- GetAnchorID(empty_object_node),
- position->text_offset() > 0 ? 1 : 0,
- ax::mojom::TextAffinity::kDownstream);
+ // We set the |text_offset_| to either 0 or the length of the embedded
+ // object character here because the MaxTextOffset of an empty object
+ // is `AXNode::kEmbeddedCharacterLength`. If the invalid position was
+ // already at the start of the node, we set it to 0.
+ return CreateTextPosition(
+ position->tree_id(), GetAnchorID(empty_object_node),
+ position->text_offset() > 0 ? AXNode::kEmbeddedCharacterLength
+ : 0,
+ ax::mojom::TextAffinity::kDownstream);
}
if (position->text_offset_ <= 0) {
@@ -1114,31 +1224,48 @@ class AXPosition {
return Clone();
AXPositionInstance copy = Clone();
- DCHECK(copy);
DCHECK_GE(copy->text_offset_, 0);
+ // Note that by design, `AXPosition::IsLeaf()` excludes the text found in
+ // ignored subtrees from the accessibility tree's text representation. (See
+ // `AXNode::IsEmptyLeaf()`.)
if (copy->IsLeaf()) {
- const int max_text_offset = copy->MaxTextOffset();
- copy->child_index_ =
- (max_text_offset != 0 && copy->text_offset_ != max_text_offset)
- ? BEFORE_TEXT
- : 0;
+ // Even though leaf positions are generally not anchored to a node with a
+ // lot of descendants, still, there is the possibility that the leaf node
+ // is a text field with a large amount of text. We avoid computing
+ // `MaxTextOffset()` unless it is really necessary.
+ if (copy->text_offset_ == 0) {
+ copy->child_index_ = BEFORE_TEXT;
+ } else {
+ const int max_text_offset = copy->MaxTextOffset();
+ copy->child_index_ =
+ copy->text_offset_ != max_text_offset ? BEFORE_TEXT : 0;
+ }
+
copy->kind_ = AXPositionKind::TREE_POSITION;
return copy;
}
- // We stop at the last child that we can reach with the current text offset
- // and ignore any remaining children. This is for defensive programming
- // purposes, in case "MaxTextOffset" doesn't match the total length of all
- // our children. This may happen if, for example, there is a bug in the
- // internal accessibility tree we get from the renderer. In contrast, the
- // current offset could not be greater than the length of all our children
- // because the position would have been invalid.
- int current_offset = 0;
+ // We stop at the first child that we can reach with the current text
+ // offset. We do not attempt to validate `MaxTextOffset()` in case it
+ // doesn't match the total length of all our children. This may happen if,
+ // for example, there is a bug in the internal accessibility tree we get
+ // from the renderer. In contrast, the current offset could not be greater
+ // than the length of all our children because the position would have been
+ // invalid.
+ //
+ // Note that even though ignored children should not contribute any inner
+ // text or hypertext to the tree's text representation, we have to include
+ // them because they might contain unignored descendants. We only exclude
+ // them if they are both ignored and contain no inner text or hypertext. The
+ // latter is to avoid, as much as we can, the possibility that an unignored
+ // position will turn into an ignored one after calling this method.
+
int child_index = 0;
- for (; child_index < copy->AnchorChildCount(); ++child_index) {
+ for (int current_offset = 0; child_index < copy->AnchorChildCount();
+ ++child_index) {
AXPositionInstance child = copy->CreateChildPositionAt(child_index);
- DCHECK(child);
- int child_length = child->MaxTextOffsetInParent();
+ DCHECK(!child->IsNullPosition());
+
// If the text offset falls on the boundary between two adjacent children,
// we look at the affinity to decide whether to place the tree position on
// the first child vs. the second child. Upstream affinity would always
@@ -1147,16 +1274,34 @@ class AXPosition {
// to a text position. In that case, maintaining an upstream affinity
// would place the text position at the end of the first child, whilst
// maintaining a downstream affinity will place the text position at the
- // beginning of the second child.
+ // beginning of the second child. This is vital for text positions on soft
+ // line breaks, as well as text positions before and after character, to
+ // work properly.
//
- // This is vital for text positions on soft line breaks, as well as text
- // positions before and after character, to work properly.
+ // Note that in this context "adjacent children" excludes ignored
+ // children. Note also that children with no inner text or no hypertext
+ // are not skipped, otherwise the following situation will produce an
+ // erroneous tree position:
+ // ++kTextField contenteditable=true "" (empty)
+ // ++++kStaticText "\n" ignored
+ // ++++++kInlineTextBox "\n" ignored
+ // ++++kStaticText "" (empty)
+ // ++++++kInlineTextOffset "" (empty)
+ // TextPosition anchor=kTextField text_offset=0 affinity=downstream
+ // AsTreePosition should produce:
+ // TreePosition anchor=kTextField child_index=1, and not child_index=0 or
+ // child_index=2
//
// See also `CreateLeafTextPositionBeforeCharacter` and
// `CreateLeafTextPositionAfterCharacter`.
+
+ const int child_length = child->MaxTextOffsetInParent();
+ const bool contributes_no_text_in_parent = !child_length;
+ const bool is_anchor_unignored = !child->GetAnchor()->IsIgnored();
if (copy->text_offset_ >= current_offset &&
(copy->text_offset_ < (current_offset + child_length) ||
- (copy->affinity_ == ax::mojom::TextAffinity::kUpstream &&
+ ((copy->affinity_ == ax::mojom::TextAffinity::kUpstream ||
+ (contributes_no_text_in_parent && is_anchor_unignored)) &&
copy->text_offset_ == (current_offset + child_length)))) {
break;
}
@@ -1204,10 +1349,10 @@ class AXPosition {
tree_position =
tree_position->CreateChildPositionAt(tree_position->child_index_);
}
- DCHECK(tree_position && !tree_position->IsNullPosition());
+ DCHECK(!tree_position->IsNullPosition());
} while (!tree_position->IsLeaf());
- DCHECK(tree_position && tree_position->IsLeafTreePosition());
+ DCHECK(tree_position->IsLeafTreePosition());
return tree_position;
}
@@ -1216,17 +1361,18 @@ class AXPosition {
return Clone();
AXPositionInstance copy = Clone();
- DCHECK(copy);
// Check if it is a "before text" position.
if (copy->child_index_ == BEFORE_TEXT) {
- // "Before text" positions can only appear on leaf nodes.
- DCHECK(copy->IsLeaf());
+ DCHECK(copy->IsLeaf())
+ << "Before text positions can only appear on leaf nodes.";
// If the current text offset is valid, we don't touch it to potentially
// allow converting from a text position to a tree position and back
// without losing information.
//
- // We test for INVALID_OFFSET first, due to the possible performance
- // implications of calling MaxTextOffset().
+ // We test for INVALID_OFFSET and greater than 0 first, due to the
+ // possible performance cost of calling `MaxTextOffset()`. Also, if the
+ // text offset is already 0, we don't need to touch it, and if it is less
+ // than `MaxTextOffset()` we don't modify it as explained above.
DCHECK_GE(copy->text_offset_, INVALID_OFFSET)
<< "Unrecognized text offset.";
if (copy->text_offset_ == INVALID_OFFSET ||
@@ -1234,21 +1380,35 @@ class AXPosition {
copy->text_offset_ >= copy->MaxTextOffset())) {
copy->text_offset_ = 0;
}
- } else if (copy->child_index_ == copy->AnchorChildCount()) {
+
+ copy->kind_ = AXPositionKind::TEXT_POSITION;
+ return copy;
+ }
+
+ // Leaf nodes might have descendants that should be hidden for text
+ // navigation purposes, thus we can't rely solely on `AnchorChildCount()`.
+ // Any child index that is not `BEFORE_TEXT` should be treated as indicating
+ // an "after text" position. (See `IsEmptyObjectReplacedByCharacter()` for
+ // more information.)
+ // ++kButton "<embedded_object_character>" (empty)
+ // ++++kGenericContainer ignored (Might sometimes be added by Blink.)
+ if (copy->IsLeaf() || copy->child_index_ == copy->AnchorChildCount()) {
copy->text_offset_ = copy->MaxTextOffset();
- } else {
+ copy->kind_ = AXPositionKind::TEXT_POSITION;
+ return copy;
+ }
+
DCHECK_GE(copy->child_index_, 0);
DCHECK_LT(copy->child_index_, copy->AnchorChildCount());
int new_offset = 0;
for (int i = 0; i <= child_index_; ++i) {
AXPositionInstance child = copy->CreateChildPositionAt(i);
- DCHECK(child);
+ DCHECK(!child->IsNullPosition());
// If the current text offset is valid, we don't touch it to
// potentially allow converting from a text position to a tree
// position and back without losing information. Otherwise, if the
// text_offset is invalid, equals to 0 or is smaller than
- // |new_offset|, we reset it to the beginning of the current child
- // node.
+ // |new_offset|, we reset it to the beginning of the current child.
if (i == child_index_ && copy->text_offset_ <= new_offset) {
copy->text_offset_ = new_offset;
break;
@@ -1269,16 +1429,15 @@ class AXPosition {
new_offset += child_length;
}
- }
- // Affinity should always be left as downstream. The only case when the
- // resulting text position is at the end of the line is when we get an
- // "after text" leaf position, but even in this case downstream is
- // appropriate because there is no ambiguity whetehr the position is at the
- // end of the current line vs. the start of the next line. It would always
- // be the former.
- copy->kind_ = AXPositionKind::TEXT_POSITION;
- return copy;
+ // Affinity should always be left as downstream. The only case when the
+ // resulting text position is at the end of the line is when we get an
+ // "after text" leaf position, but even in this case downstream is
+ // appropriate because there is no ambiguity whether the position is at
+ // the end of the current line vs. the start of the next line. It would
+ // always be the former.
+ copy->kind_ = AXPositionKind::TEXT_POSITION;
+ return copy;
}
AXPositionInstance AsLeafTextPosition() const {
@@ -1289,40 +1448,71 @@ class AXPosition {
// No need to check for "before text" positions here because they are only
// present on leaf anchor nodes.
AXPositionInstance text_position = AsTextPosition();
- int adjusted_offset = text_position->text_offset_;
+ int offset_in_parent = text_position->text_offset_;
do {
- AXPositionInstance child_position =
- text_position->CreateChildPositionAt(0);
- DCHECK(child_position);
-
- // If the text offset corresponds to multiple child positions because some
- // of the children have empty text, the condition "adjusted_offset > 0"
- // below ensures that the first child will be chosen.
+ AXPositionInstance child = text_position->CreateChildPositionAt(0);
+ DCHECK(!child->IsNullPosition());
+
+ // Note that even though ignored children should not contribute any inner
+ // text or hypertext to the tree's text representation, we have to include
+ // them because they might contain unignored descendants. We only exclude
+ // them if they are both ignored and contain no inner text or hypertext.
+ // The latter is to avoid, as much as we can, the possibility that an
+ // unignored position will turn into an ignored one after calling this
+ // method.
for (int i = 1;
- i < text_position->AnchorChildCount() && adjusted_offset > 0; ++i) {
- const int max_text_offset_in_parent =
- child_position->MaxTextOffsetInParent();
- if (adjusted_offset < max_text_offset_in_parent) {
+ i < text_position->AnchorChildCount() && offset_in_parent >= 0;
+ ++i) {
+ const int child_length_in_parent = child->MaxTextOffsetInParent();
+ const bool contributes_no_text_in_parent =
+ (child_length_in_parent == 0);
+ const bool is_anchor_unignored = !child->GetAnchor()->IsIgnored();
+ if (offset_in_parent == 0 && contributes_no_text_in_parent &&
+ is_anchor_unignored) {
+ // If the text offset corresponds to multiple child positions because
+ // some of the children have no inner text or hypertext, the above
+ // condition ensures that the first child will be chosen; unless it is
+ // ignored as explained before.
break;
}
+
+ if (offset_in_parent < child_length_in_parent)
+ break;
+
if (affinity_ == ax::mojom::TextAffinity::kUpstream &&
- adjusted_offset == max_text_offset_in_parent) {
+ offset_in_parent == child_length_in_parent) {
// Maintain upstream affinity so that we'll be able to choose the
// correct leaf anchor if the text offset is right on the boundary
// between two leaves.
- child_position->affinity_ = ax::mojom::TextAffinity::kUpstream;
+ child->affinity_ = ax::mojom::TextAffinity::kUpstream;
break;
}
- child_position = text_position->CreateChildPositionAt(i);
- adjusted_offset -= max_text_offset_in_parent;
+
+ child = text_position->CreateChildPositionAt(i);
+ offset_in_parent -= child_length_in_parent;
+ }
+
+ // The text offset provided by our parent position might need to be
+ // adjusted, if this is an "after text" position and our anchor node is an
+ // embedded object (as determined by `IsEmbeddedObjectInParent()`).
+ // ++kRootWebArea "<embedded_object>"
+ // ++++kParagraph "Hello"
+ // TextPosition anchor=kRootWebArea text_offset=1
+ // should be translated into the following text position
+ // TextPosition anchor=kParagraph text_offset=5 annotated_text=Hello<>
+ // and not into the following one
+ // TextPosition anchor=kParagraph text_offset=1 annotated_text=<H>ello
+ if (child->IsEmbeddedObjectInParent() &&
+ offset_in_parent == child->MaxTextOffsetInParent()) {
+ offset_in_parent -= child->MaxTextOffsetInParent();
+ offset_in_parent += child->MaxTextOffset();
}
- text_position = std::move(child_position);
+ text_position = std::move(child);
} while (!text_position->IsLeaf());
- DCHECK(text_position);
DCHECK(text_position->IsLeafTextPosition());
- text_position->text_offset_ = adjusted_offset;
+ text_position->text_offset_ = offset_in_parent;
// A leaf Text position is always downstream since there is no ambiguity as
// to whether it refers to the end of the current or the start of the next
// line.
@@ -1660,17 +1850,17 @@ class AXPosition {
case ax::mojom::TextBoundary::kWebPage:
DCHECK_EQ(boundary_behavior, AXBoundaryBehavior::CrossBoundary)
- << "We can't reach the start of the document if we are disallowed "
- "from crossing boundaries.";
+ << "We can't reach the start of the whole contents if we are "
+ "disallowed from crossing boundaries.";
switch (direction) {
case ax::mojom::MoveDirection::kNone:
NOTREACHED();
break;
case ax::mojom::MoveDirection::kBackward:
- resulting_position = CreatePositionAtStartOfDocument();
+ resulting_position = CreatePositionAtStartOfContent();
break;
case ax::mojom::MoveDirection::kForward:
- resulting_position = CreatePositionAtEndOfDocument();
+ resulting_position = CreatePositionAtEndOfContent();
break;
}
break;
@@ -1754,96 +1944,80 @@ class AXPosition {
return CreateNullPosition();
}
+ // Creates a position at the start of this position's accessibility tree, e.g.
+ // at the start of the current iframe, PDF plugin, Views tree, dialog, etc. We
+ // don't distinguish between out-of-process and in-process iframes, treating
+ // them both as tree boundaries.
+ //
+ // For a similar method that does not stop at iframe boundaries, see
+ // `CreatePositionAtStartOfContent()`.
AXPositionInstance CreatePositionAtStartOfAXTree() const {
- if (IsNullPosition() || AtStartOfAXTree())
- return Clone();
-
- // First check for positions on nodes which are AXTree boundaries, but where
- // the text position on that node is not at the start of the anchor.
- if (CreatePositionAtStartOfAnchor()->AtStartOfAXTree())
- return CreatePositionAtStartOfAnchor();
-
- // Iterate over tree positions until a boundary is reached.
- AXPositionInstance previous_position = AsTreePosition();
- do {
- previous_position = previous_position->CreatePreviousAnchorPosition();
- } while (!previous_position->AtStartOfAXTree());
-
- // This method should not cross tree boundaries.
- DCHECK_EQ(previous_position->tree_id(), tree_id());
-
+ AXPositionInstance root_position =
+ AsTreePosition()
+ ->CreateAXTreeRootAncestorPosition(
+ ax::mojom::MoveDirection::kBackward)
+ ->CreatePositionAtStartOfAnchor();
if (IsTextPosition())
- previous_position = previous_position->AsTextPosition();
- return previous_position;
+ root_position = root_position->AsTextPosition();
+ DCHECK_EQ(root_position->tree_id_, tree_id_)
+ << "`CreatePositionAtStartOfAXTree` should not cross any tree "
+ "boundaries, neither return the null position.";
+ return root_position;
}
+ // Creates a position at the end of this position's accessibility tree, e.g.
+ // at the end of the current iframe, PDF plugin, Views tree, dialog, etc. We
+ // don't distinguish between out-of-process and in-process iframes, treating
+ // them both as tree boundaries.
+ //
+ // For a similar method that does not stop at iframe boundaries, see
+ // `CreatePositionAtEndOfContent()`.
AXPositionInstance CreatePositionAtEndOfAXTree() const {
- if (IsNullPosition() || AtEndOfAXTree())
- return Clone();
-
- // First check for positions on nodes which are AXTree boundaries, but where
- // the text position on that node is not at the end of the anchor.
- if (CreatePositionAtEndOfAnchor()->AtEndOfAXTree())
- return CreatePositionAtEndOfAnchor();
-
- // Iterate over tree positions until a boundary is reached.
- AXPositionInstance next_position = AsTreePosition();
- do {
- next_position = next_position->CreateNextAnchorPosition()
- ->CreatePositionAtEndOfAnchor();
- } while (!next_position->AtEndOfAXTree());
-
- // This method should not cross tree boundaries.
- DCHECK_EQ(next_position->tree_id(), tree_id());
-
+ AXPositionInstance root_position =
+ AsTreePosition()->CreateAXTreeRootAncestorPosition(
+ ax::mojom::MoveDirection::kBackward);
+ AXPositionInstance last_position =
+ root_position->CreatePositionAtEndOfAnchor()->AsLeafTreePosition();
if (IsTextPosition())
- next_position = next_position->AsTextPosition();
- return next_position->CreatePositionAtEndOfAnchor();
+ last_position = last_position->AsTextPosition();
+ return last_position;
}
- // "document" is defined here as a single, top-level, navigatable unit from
- // a user's perspective. This means that all iframes are part of a single
- // "document" that contains the top-level navigatable page. So this method
- // will break out of an iframe and return a position at the start of the
- // top-level document.
+ // Creates a position at the start of all content, e.g. at the start of the
+ // whole webpage, PDF plugin, Views tree, dialog (native, ARIA or HTML),
+ // window, or the whole desktop.
//
- // Note that this definition is different than HTML's definition of
- // "document", where each iframe has its own document object. For a similar
- // method that stops at iframe boundaries, see
- // CreatePositionAtStartOfAXTree().
- AXPositionInstance CreatePositionAtStartOfDocument() const {
- AXPositionInstance position =
- AsTreePosition()->CreateDocumentAncestorPosition();
- if (!position->IsNullPosition()) {
- position = position->CreatePositionAtStartOfAnchor();
- if (IsTextPosition())
- position = position->AsTextPosition();
- }
- return position;
+ // Note that this method will break out of an out-of-process iframe and return
+ // a position at the start of the top-level document, but it will not break
+ // into the Views tree if present. For a similar method that stops at all
+ // iframe boundaries, see `CreatePositionAtStartOfAXTree()`.
+ AXPositionInstance CreatePositionAtStartOfContent() const {
+ AXPositionInstance root_position =
+ AsTreePosition()
+ ->CreateRootAncestorPosition(ax::mojom::MoveDirection::kBackward)
+ ->CreatePositionAtStartOfAnchor();
+ if (IsTextPosition())
+ root_position = root_position->AsTextPosition();
+ return root_position;
}
- // "document" is defined here as a single, top-level, navigatable unit from
- // a user's perspective. This means that all iframes are part of a single
- // "document" that contains the top-level navigatable page. So this method
- // will break out of an iframe and return a position at the end of the
- // top-level document.
+ // Creates a position at the end of all content, e.g. at the end of the whole
+ // webpage, PDF plugin, Views tree, dialog (native, ARIA or HTML), window, or
+ // the whole desktop.
//
- // Note that this definition is different than HTML's definition of
- // "document", where each iframe has its own document object. For a similar
- // method that stops at iframe boundaries, see CreatePositionAtEndOfAXTree().
- AXPositionInstance CreatePositionAtEndOfDocument() const {
- AXPositionInstance position =
- AsTreePosition()->CreateDocumentAncestorPosition();
- if (!position->IsNullPosition()) {
- while (!position->IsLeaf()) {
- position =
- position->CreateChildPositionAt(position->AnchorChildCount() - 1);
- }
- position = position->CreatePositionAtEndOfAnchor();
- if (IsTextPosition())
- position = position->AsTextPosition();
- }
- return position;
+ // Note that this method will break out of an out-of-process iframe and return
+ // a position at the end of the top-level document, but it will not break into
+ // the Views tree if present. For a similar method that stops at all iframe
+ // boundaries, see `CreatePositionAtEndOfAXTree()`.
+ AXPositionInstance CreatePositionAtEndOfContent() const {
+ AXPositionInstance root_position =
+ AsTreePosition()->CreateRootAncestorPosition(
+ ax::mojom::MoveDirection::kBackward);
+ AXPositionInstance last_position =
+ root_position->CreatePositionAtEndOfAnchor()->AsLeafTreePosition();
+ if (IsTextPosition())
+ last_position = last_position->AsTextPosition();
+ return last_position;
}
AXPositionInstance CreateChildPositionAt(int child_index) const {
@@ -1854,10 +2028,10 @@ class AXPosition {
return CreateNullPosition();
AXTreeID tree_id = AXTreeIDUnknown();
- AXNode::AXID child_id = AXNode::kInvalidAXID;
+ AXNodeID child_id = kInvalidAXNodeID;
AnchorChild(child_index, &tree_id, &child_id);
DCHECK_NE(tree_id, AXTreeIDUnknown());
- DCHECK_NE(child_id, AXNode::kInvalidAXID);
+ DCHECK_NE(child_id, kInvalidAXNodeID);
switch (kind_) {
case AXPositionKind::NULL_POSITION:
NOTREACHED();
@@ -1881,15 +2055,17 @@ class AXPosition {
// Creates a parent equivalent position.
//
- // "move_direction" is used only in the case of a text position, when in
- // the process of searching for a text boundary, and on platforms where child
- // nodes are represented by embedded object characters. On such platforms, the
- // "IsEmbeddedObjectInParent" method returns true. We need to decide whether
- // to create a parent equivalent position that is before or after the child
- // node, since moving to a parent position would always cause us to lose some
- // information. We can't simply re-use the text offset of the child position
- // because by definition the parent node doesn't include all the text of the
- // child node, but only a single embedded object character.
+ // Note that "move_direction" is only taken into consideration when all of
+ // these three conditions apply: This is a text position, we are in the
+ // process of searching for a text boundary, and this is a platform where
+ // child nodes are represented by "object replacement characters". On such
+ // platforms, the `IsEmbeddedObjectInParent` method returns true. We need to
+ // decide whether to create a parent equivalent position that is before or
+ // after the child node, since moving to a parent position would always cause
+ // us to lose some information. We can't simply re-use the text offset of the
+ // child position because by definition the parent node doesn't include all
+ // the text of the child node, but only a single "object replacement
+ // character".
//
// staticText name='Line one' IA2-hypertext='<embedded_object>'
// ++inlineTextBox name='Line one'
@@ -1897,7 +2073,7 @@ class AXPosition {
// If we are given a text position pointing to somewhere inside the
// inlineTextBox, and we move to the parent equivalent position, we need to
// decide whether the parent position would be set to point to before the
- // embedded object character or after it. Both are valid, depending on the
+ // object replacement character or after it. Both are valid, depending on the
// direction on motion, e.g. if we are trying to find the start of the line
// vs. the end of the line.
AXPositionInstance CreateParentPosition(
@@ -1907,22 +2083,61 @@ class AXPosition {
return CreateNullPosition();
AXTreeID tree_id = AXTreeIDUnknown();
- AXNode::AXID parent_id = AXNode::kInvalidAXID;
+ AXNodeID parent_id = kInvalidAXNodeID;
AnchorParent(&tree_id, &parent_id);
- if (tree_id == AXTreeIDUnknown() || parent_id == AXNode::kInvalidAXID)
+ if (tree_id == AXTreeIDUnknown() || parent_id == kInvalidAXNodeID)
return CreateNullPosition();
switch (kind_) {
case AXPositionKind::NULL_POSITION:
NOTREACHED();
return CreateNullPosition();
- case AXPositionKind::TREE_POSITION:
- return CreateTreePosition(tree_id, parent_id, AnchorIndexInParent());
+
+ case AXPositionKind::TREE_POSITION: {
+ int child_index = AnchorIndexInParent();
+ // If this position is an "after children" or an "after text" position,
+ // return either an "after children" position on the parent anchor, or a
+ // position anchored at the next child, depending on whether this is the
+ // last child in its parent anchor.
+ if (AtEndOfAnchor())
+ return CreateTreePosition(tree_id, parent_id, (child_index + 1));
+
+ switch (move_direction) {
+ case ax::mojom::MoveDirection::kNone:
+ NOTREACHED();
+ return CreateNullPosition();
+ case ax::mojom::MoveDirection::kBackward:
+ // "move_direction" is only important when this position is an
+ // "embedded object in parent", i.e., when this position's anchor is
+ // represented by an "object replacement character" in the text of
+ // its parent anchor. In this case we need to keep the child index
+ // to be right before the "object replacement character". If this is
+ // not an "embedded object in parent", then we simply need to use
+ // the "AnchorIndexInParent" for the child index. However, since
+ // "AnchorIndexInParent" always returns a child index that is before
+ // any "object replacement character" in our parent, we use that for
+ // both situations.
+ return CreateTreePosition(tree_id, parent_id, child_index);
+ case ax::mojom::MoveDirection::kForward:
+ // "move_direction" is only important when this position is an
+ // "embedded object in parent", i.e., when this position's anchor is
+ // represented by an "object replacement character" in the text of
+ // its parent anchor. In this case we need to move the child index
+ // to be after the "object replacement character" when this position
+ // is not at the start of its anchor. If this is not an "embedded
+ // object in parent", then we simply need to use the
+ // "AnchorIndexInParent" for the child index.
+ if (!AtStartOfAnchor() && IsEmbeddedObjectInParent())
+ ++child_index;
+ return CreateTreePosition(tree_id, parent_id, child_index);
+ }
+ }
+
case AXPositionKind::TEXT_POSITION: {
// On some platforms, such as Android, Mac and Chrome OS, the inner text
// of a node is made up by concatenating the text of child nodes. On
- // other platforms, such as Windows IA2 and Linux ATK, child nodes are
- // represented by a single embedded object character.
+ // other platforms, such as Windows IAccessible2 and Linux ATK, child
+ // nodes are represented by a single "object replacement character".
//
// If our parent's inner text is a concatenation of all its children's
// text, we need to maintain the affinity and compute the corresponding
@@ -1945,34 +2160,68 @@ class AXPosition {
// "Line one", then the resulting parent equivalent position would be
// the same as the one that would have been computed if the original
// position were at the start of the inline text box for "Line two".
+
const int max_text_offset = MaxTextOffset();
+ DCHECK_LE(text_offset_, max_text_offset);
const int max_text_offset_in_parent =
- IsEmbeddedObjectInParent() ? 1 : max_text_offset;
+ IsEmbeddedObjectInParent() ? AXNode::kEmbeddedCharacterLength
+ : max_text_offset;
int parent_offset = AnchorTextOffsetInParent();
ax::mojom::TextAffinity parent_affinity = affinity_;
- if (max_text_offset == max_text_offset_in_parent) {
+
+ // "max_text_offset > 0" is required to filter out anchor nodes that are
+ // either ignored or empty, i.e. those that contribute no inner text or
+ // hypertext to their parent's text representation. (See example in the
+ // "else" block.)
+ if (max_text_offset > 0 &&
+ max_text_offset == max_text_offset_in_parent) {
// Our parent contains all our text. No information would be lost when
- // moving to a parent equivalent position.
+ // moving to a parent equivalent position. It turns out, that even in
+ // the unusual case where there is a single character in our anchor's
+ // inner text but our anchor is represented in our parent by an
+ // "embedded object replacement character" and not by our inner text,
+ // the outcome is still correct.
parent_offset += text_offset_;
- } else if (text_offset_ > 0) {
- // If "text_offset_" == 0, then the child position is clearly before
- // any embedded object character. No information would be lost when
- // moving to a parent equivalent position, including affinity
- // information. Otherwise, we should decide whether to set the parent
- // position to be before or after the child, based on the direction of
- // motion, and also reset the affinity.
- switch (move_direction) {
- case ax::mojom::MoveDirection::kNone:
- NOTREACHED();
- return CreateNullPosition();
- case ax::mojom::MoveDirection::kBackward:
- // Keep the offset to be right before the embedded object
- // character.
- break;
- case ax::mojom::MoveDirection::kForward:
- // Set the offset to be after the embedded object character.
- parent_offset += max_text_offset_in_parent;
- break;
+ } else {
+ // Our parent represents our anchor node using an "object replacement"
+ // character in its text representation. Or, our anchor is a text node
+ // that is ignored or empty, and so contributes no text in its
+ // parent's text representation. For example:
+ // ++kTextField "Before after."
+ // ++++kStaticText "Before "
+ // ++++kStaticText "Ignored text" ignored
+ // ++++kStaticText "after."
+ // TextPosition anchor=kStaticText (ignored) text_offset=2
+ // annotated_text="Ig<n>ored text"
+
+ if (text_offset_ > 0 && text_offset_ < max_text_offset) {
+ // If this is a "before text" or an "after text" position, i.e. if
+ // "text_offset_" == 0 or "max_text_offset", then the child position
+ // is clearly before or clearly after any "object replacement
+ // character". No information would be lost when moving to a parent
+ // equivalent position, including affinity which can easily be
+ // computed. Otherwise, we should decide whether to set the parent
+ // position to be before or after the child, based on the direction
+ // of motion, and also reset the affinity.
+ switch (move_direction) {
+ case ax::mojom::MoveDirection::kNone:
+ NOTREACHED();
+ return CreateNullPosition();
+ case ax::mojom::MoveDirection::kBackward:
+ // Keep the offset to be right before the embedded object
+ // character.
+ break;
+ case ax::mojom::MoveDirection::kForward:
+ // Set the offset to be after the embedded object character.
+ parent_offset += max_text_offset_in_parent;
+ break;
+ }
+ } else if (text_offset_ == max_text_offset) {
+ // Clearly, this is an "after text" position. The text offset should
+ // be after the "object replacement character". No information would
+ // be lost when moving to a parent equivalent position, including
+ // affinity which can easily be computed.
+ parent_offset += max_text_offset_in_parent;
}
// The original affinity doesn't apply any more. In most cases, it
@@ -1982,9 +2231,6 @@ class AXPosition {
parent_affinity = ax::mojom::TextAffinity::kDownstream;
}
- AXPositionInstance parent_position = CreateTextPosition(
- tree_id, parent_id, parent_offset, parent_affinity);
-
// If the current position is pointing at the end of its anchor, we need
// to check if the parent position has introduced ambiguity as to
// whether it refers to the end of a line or the start of the next.
@@ -1997,11 +2243,13 @@ class AXPosition {
// determined to be at start of line demonstrates the presence of
// ambiguity which is resolved by setting its affinity to upstream.
//
- // We could not have
- // checked if the child was at the end of the line, because our
- // "AtEndOfLine" predicate takes into account trailing line breaks,
- // which would create false positives.
- if (text_offset_ == max_text_offset &&
+ // We could not have checked if the child was at the end of the line,
+ // because our "AtEndOfLine" predicate takes into account trailing line
+ // breaks, which would create false positives.
+
+ AXPositionInstance parent_position = CreateTextPosition(
+ tree_id, parent_id, parent_offset, parent_affinity);
+ if (AtEndOfAnchor() && !parent_position->AtStartOfAnchor() &&
!parent_position->AtEndOfAnchor() &&
parent_position->AtStartOfLine()) {
parent_position->affinity_ = ax::mojom::TextAffinity::kUpstream;
@@ -2052,7 +2300,7 @@ class AXPosition {
// Creates a text position using the previous text-only node as its anchor.
// Assumes that text-only nodes are leaf nodes.
AXPositionInstance CreatePreviousLeafTextPosition() const {
- return CreatePreviousTextAnchorPosition(
+ return CreatePreviousLeafTextPosition(
base::BindRepeating(&DefaultAbortMovePredicate));
}
@@ -2113,11 +2361,11 @@ class AXPosition {
return text_position;
}
- text_position = text_position->CreateNextLeafTextPosition();
- while (!text_position->IsNullPosition() &&
- (text_position->IsIgnored() || !text_position->MaxTextOffset())) {
- text_position = text_position->CreateNextLeafTextPosition();
- }
+ do {
+ text_position = text_position->CreateNextLeafTextPosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary));
+ } while (!text_position->IsNullPosition() &&
+ (text_position->IsIgnored() || !text_position->MaxTextOffset()));
return text_position;
}
@@ -2172,11 +2420,11 @@ class AXPosition {
return text_position;
}
- text_position = text_position->CreatePreviousLeafTextPosition();
- while (!text_position->IsNullPosition() &&
- (text_position->IsIgnored() || !text_position->MaxTextOffset())) {
- text_position = text_position->CreatePreviousLeafTextPosition();
- }
+ do {
+ text_position = text_position->CreatePreviousLeafTextPosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary));
+ } while (!text_position->IsNullPosition() &&
+ (text_position->IsIgnored() || !text_position->MaxTextOffset()));
return text_position->CreatePositionAtEndOfAnchor();
}
@@ -2196,7 +2444,6 @@ class AXPosition {
return Clone();
}
- // There is no next character position.
AXPositionInstance text_position = AsLeafTextPositionBeforeCharacter();
if (text_position->IsNullPosition()) {
if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary ||
@@ -2206,8 +2453,20 @@ class AXPosition {
return text_position;
}
+ // Calling "AsLeafTextPositionBeforeCharacter" should have created a text
+ // position that is either at a grapheme boundary, or a null position. If
+ // our text offset is pointing to a position that is in the middle of a
+ // grapheme cluster, we should not erroneously assume that we are at a
+ // character boundary and stop because we had been asked to "stop if already
+ // at boundary". However, we should not modify our position if
+ // `AsLeafTextPositionBeforeCharacter` has simply moved us to the start of
+ // the next leaf anchor because we originally happened to be at the end of
+ // our current anchor. We also need to ensure that we are comparing two
+ // positions that have the same affinity, since
+ // `AsLeafTextPositionBeforeCharacter` resets the affinity to downstream,
+ // while the original affinity might have been upstream.
if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
- *text_position == *this) {
+ (AtEndOfAnchor() || *text_position == *CloneWithDownstreamAffinity())) {
return Clone();
}
@@ -2259,7 +2518,6 @@ class AXPosition {
return Clone();
}
- // There is no previous character position.
AXPositionInstance text_position = AsLeafTextPositionAfterCharacter();
if (text_position->IsNullPosition()) {
if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary ||
@@ -2269,8 +2527,20 @@ class AXPosition {
return text_position;
}
+ // Calling "AsLeafTextPositionAfterCharacter" should have created a text
+ // position that is either at a grapheme boundary, or a null position. If
+ // our text offset is pointing to a position that is in the middle of a
+ // grapheme cluster, we should not erroneously assume that we are at a
+ // character boundary and stop because we had been asked to "stop if already
+ // at boundary". However, we should not modify our position if
+ // `AsLeafTextPositionAfterCharacter` has simply moved us to the end of the
+ // previous leaf anchor because we originally happened to be at the start of
+ // our current anchor. We also need to ignore any differences that might be
+ // due to the affinity, because that should not be a determining factor as
+ // to whether we would stop if we are already at boundary or not.
if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
- *text_position == *this) {
+ (AtStartOfAnchor() || *text_position == *CloneWithUpstreamAffinity() ||
+ *text_position == *CloneWithDownstreamAffinity())) {
return Clone();
}
@@ -2386,21 +2656,21 @@ class AXPosition {
AXPositionInstance CreatePreviousFormatStartPosition(
AXBoundaryBehavior boundary_behavior) const {
if (IsNullPosition())
- return Clone();
+ return CreateNullPosition();
AXBoundaryType boundary_type = GetFormatStartBoundaryType();
if (boundary_type != AXBoundaryType::kNone) {
if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary ||
(boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary &&
- boundary_type == AXBoundaryType::kDocumentStart)) {
- AXPositionInstance clone = Clone();
+ boundary_type == AXBoundaryType::kContentStart)) {
// In order to make equality checks simpler, affinity should be reset so
// that we would get consistent output from this function regardless of
// input affinity.
- clone->affinity_ = ax::mojom::TextAffinity::kDownstream;
- return clone;
+ if (IsTextPosition())
+ return CloneWithDownstreamAffinity();
+ return Clone();
} else if (boundary_behavior == AXBoundaryBehavior::CrossBoundary &&
- boundary_type == AXBoundaryType::kDocumentStart) {
+ boundary_type == AXBoundaryType::kContentStart) {
// If we're at a format boundary and there are no more text positions
// to traverse, return a null position for cross-boundary moves.
return CreateNullPosition();
@@ -2410,7 +2680,8 @@ class AXPosition {
AXPositionInstance tree_position =
AsTreePosition()->CreatePositionAtStartOfAnchor();
AXPositionInstance previous_tree_position =
- tree_position->CreatePreviousLeafTreePosition();
+ tree_position->CreatePreviousLeafTreePosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary));
// If moving to the start of the current anchor hasn't changed our position
// from the original position, we need to test the previous leaf tree
@@ -2418,16 +2689,19 @@ class AXPosition {
if (AtStartOfAnchor() &&
boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary) {
tree_position = std::move(previous_tree_position);
- previous_tree_position = tree_position->CreatePreviousLeafTreePosition();
+ previous_tree_position = tree_position->CreatePreviousLeafTreePosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary));
}
- // The first position in the document is also a format start boundary, so we
- // should not return NullPosition unless we started from that location.
- while (boundary_type != AXBoundaryType::kDocumentStart &&
+ // The first position in the whole content is also a format start boundary,
+ // so we should not return NullPosition unless we started from that
+ // location.
+ while (boundary_type != AXBoundaryType::kContentStart &&
!previous_tree_position->IsNullPosition() &&
!tree_position->AtStartOfFormat()) {
tree_position = std::move(previous_tree_position);
- previous_tree_position = tree_position->CreatePreviousLeafTreePosition();
+ previous_tree_position = tree_position->CreatePreviousLeafTreePosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary));
}
// If the format boundary is in the same subtree, return a position rooted
@@ -2450,21 +2724,21 @@ class AXPosition {
AXPositionInstance CreateNextFormatEndPosition(
AXBoundaryBehavior boundary_behavior) const {
if (IsNullPosition())
- return Clone();
+ return CreateNullPosition();
AXBoundaryType boundary_type = GetFormatEndBoundaryType();
if (boundary_type != AXBoundaryType::kNone) {
if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary ||
(boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary &&
- boundary_type == AXBoundaryType::kDocumentEnd)) {
- AXPositionInstance clone = Clone();
+ boundary_type == AXBoundaryType::kContentEnd)) {
// In order to make equality checks simpler, affinity should be reset so
// that we would get consistent output from this function regardless of
// input affinity.
- clone->affinity_ = ax::mojom::TextAffinity::kDownstream;
- return clone;
+ if (IsTextPosition())
+ return CloneWithDownstreamAffinity();
+ return Clone();
} else if (boundary_behavior == AXBoundaryBehavior::CrossBoundary &&
- boundary_type == AXBoundaryType::kDocumentEnd) {
+ boundary_type == AXBoundaryType::kContentEnd) {
// If we're at a format boundary and there are no more text positions
// to traverse, return a null position for cross-boundary moves.
return CreateNullPosition();
@@ -2474,7 +2748,9 @@ class AXPosition {
AXPositionInstance tree_position =
AsTreePosition()->CreatePositionAtEndOfAnchor();
AXPositionInstance next_tree_position =
- tree_position->CreateNextLeafTreePosition()
+ tree_position
+ ->CreateNextLeafTreePosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary))
->CreatePositionAtEndOfAnchor();
// If moving to the end of the current anchor hasn't changed our original
@@ -2482,17 +2758,21 @@ class AXPosition {
if (AtEndOfAnchor() &&
boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary) {
tree_position = std::move(next_tree_position);
- next_tree_position = tree_position->CreateNextLeafTreePosition()
+ next_tree_position = tree_position
+ ->CreateNextLeafTreePosition(base::BindRepeating(
+ &AbortMoveAtRootBoundary))
->CreatePositionAtEndOfAnchor();
}
- // The last position in the document is also a format end boundary, so we
- // should not return NullPosition unless we started from that location.
- while (boundary_type != AXBoundaryType::kDocumentEnd &&
+ // The last position in the whole content is also a format end boundary, so
+ // we should not return NullPosition unless we started from that location.
+ while (boundary_type != AXBoundaryType::kContentEnd &&
!next_tree_position->IsNullPosition() &&
!tree_position->AtEndOfFormat()) {
tree_position = std::move(next_tree_position);
- next_tree_position = tree_position->CreateNextLeafTreePosition()
+ next_tree_position = tree_position
+ ->CreateNextLeafTreePosition(base::BindRepeating(
+ &AbortMoveAtRootBoundary))
->CreatePositionAtEndOfAnchor();
}
@@ -2578,7 +2858,8 @@ class AXPosition {
while (!previous_position->IsNullPosition()) {
AXPositionInstance look_back_position =
previous_position->AsLeafTextPosition()
- ->CreatePreviousLeafTextPosition()
+ ->CreatePreviousLeafTextPosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary))
->CreatePositionAtEndOfAnchor();
if (look_back_position->IsNullPosition()) {
// Nowhere to look back to, so our candidate must be a valid paragraph
@@ -2586,7 +2867,9 @@ class AXPosition {
break;
}
AXPositionInstance forward_step_position =
- look_back_position->CreateNextLeafTextPosition()
+ look_back_position
+ ->CreateNextLeafTextPosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary))
->CreatePositionAtEndOfAnchor();
if (*forward_step_position == *previous_position)
break;
@@ -2669,7 +2952,8 @@ class AXPosition {
return CreateNullPosition();
case ax::mojom::MoveDirection::kBackward:
if (text_position->AtStartOfAnchor()) {
- next_position = text_position->CreatePreviousLeafTextPosition();
+ next_position = text_position->CreatePreviousLeafTextPosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary));
} else {
text_position = text_position->CreatePositionAtStartOfAnchor();
DCHECK(!text_position->IsNullPosition());
@@ -2677,7 +2961,8 @@ class AXPosition {
}
break;
case ax::mojom::MoveDirection::kForward:
- next_position = text_position->CreateNextLeafTextPosition();
+ next_position = text_position->CreateNextLeafTextPosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary));
break;
}
@@ -2756,9 +3041,9 @@ class AXPosition {
AdjustmentBehaviorFromBoundaryDirection(move_direction));
// If there are no unignored positions in |move_direction| then
// |text_position| is anchored in ignored content at the start or end
- // of the document.
+ // of the whole content.
// For StopAtLastAnchorBoundary, try to adjust in the opposite direction
- // to return a position within the document just before crossing into
+ // to return a position within the whole content just before crossing into
// the ignored content. This will be the last unignored anchor boundary.
if (unignored_position->IsNullPosition() &&
boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary) {
@@ -2804,12 +3089,16 @@ class AXPosition {
NOTREACHED();
return CreateNullPosition();
case ax::mojom::MoveDirection::kBackward:
- next_position = text_position->CreatePreviousLeafTextPosition()
- ->CreatePositionAtEndOfAnchor();
+ next_position =
+ text_position
+ ->CreatePreviousLeafTextPosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary))
+ ->CreatePositionAtEndOfAnchor();
break;
case ax::mojom::MoveDirection::kForward:
if (text_position->AtEndOfAnchor()) {
- next_position = text_position->CreateNextLeafTextPosition();
+ next_position = text_position->CreateNextLeafTextPosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary));
} else {
text_position = text_position->CreatePositionAtEndOfAnchor();
DCHECK(!text_position->IsNullPosition());
@@ -2893,8 +3182,8 @@ class AXPosition {
// start or the end of the current anchor, so we should always reset to
// downstream affinity in those cases.
if (text_position->affinity_ == ax::mojom::TextAffinity::kUpstream) {
- AXPositionInstance downstream_position = text_position->Clone();
- downstream_position->affinity_ = ax::mojom::TextAffinity::kDownstream;
+ AXPositionInstance downstream_position =
+ text_position->CloneWithDownstreamAffinity();
if (downstream_position->AtStartOfAnchor() ||
downstream_position->AtEndOfAnchor() ||
!at_start_condition.Run(downstream_position)) {
@@ -2908,9 +3197,9 @@ class AXPosition {
AdjustmentBehaviorFromBoundaryDirection(move_direction));
// If there are no unignored positions in |move_direction| then
// |text_position| is anchored in ignored content at the start or end
- // of the document.
+ // of the whole content.
// For StopAtLastAnchorBoundary, try to adjust in the opposite direction
- // to return a position within the document just before crossing into
+ // to return a position within the whole content just before crossing into
// the ignored content. This will be the last unignored anchor boundary.
if (unignored_position->IsNullPosition() &&
boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary) {
@@ -2942,41 +3231,39 @@ class AXPosition {
// different text offsets. Positions are not comparable when one position is
// null and the other is not or if the positions do not have any common
// ancestor.
+ //
// 0: if this position is logically equivalent to the other position
// <0: if this position is logically less than the other position
// >0: if this position is logically greater than the other position
base::Optional<int> CompareTo(const AXPosition& other) const {
- if (this->IsNullPosition() && other.IsNullPosition())
- return base::Optional<int>(0);
- if (this->IsNullPosition() || other.IsNullPosition())
- return base::Optional<int>(base::nullopt);
+ if (IsNullPosition() && other.IsNullPosition())
+ return 0;
+ if (IsNullPosition() || other.IsNullPosition())
+ return base::nullopt;
- // If both positions share an anchor and are of the same type, we can do a
- // straight compare of text offsets or child indices.
- if (GetAnchor() == other.GetAnchor()) {
- if (IsTextPosition() && other.IsTextPosition())
- return text_offset() - other.text_offset();
- if (IsTreePosition() && other.IsTreePosition())
- return child_index() - other.child_index();
- }
+ if (GetAnchor() == other.GetAnchor())
+ return SlowCompareTo(other); // No optimization is necessary.
// Ancestor positions are expensive to compute. If possible, we will avoid
// doing so by computing the ancestor chain of the two positions' anchors.
// If the lowest common ancestor is neither position's anchor, we can use
// the order of the first uncommon ancestors as a proxy for the order of the
- // positions.
+ // positions. Obviously, this heuristic cannot be used if one position is
+ // the ancestor of the other.
//
// In order to do that, we need to normalize text positions at the end of an
// anchor to equivalent positions at the start of the next anchor. Ignored
// positions are a special case in that they need to be shifted to the
// nearest unignored position in order to be normalized. That shifting can
// change the comparison result, so if we have an ignored position, we must
- // use the slow path.
+ // use a different, slower method which does away with many of our
+ // optimizations.
if (IsIgnored() || other.IsIgnored())
return SlowCompareTo(other);
// Normalize any text positions at the end of an anchor to equivalent
- // positions at the start of the next anchor.
+ // positions at the start of the next anchor. This will potentially make the
+ // two positions not be ancestors of one another, if they originally were.
AXPositionInstance normalized_this_position = Clone();
if (normalized_this_position->IsTextPosition()) {
normalized_this_position =
@@ -2991,22 +3278,28 @@ class AXPosition {
if (normalized_this_position->IsNullPosition()) {
if (normalized_other_position->IsNullPosition()) {
- // Both positions normalized to a position past the end of the document.
+ // Both positions normalized to a position past the end of the whole
+ // content. There is no way that they could be ancestors of one another,
+ // so using the slow path is not required.
DCHECK_EQ(SlowCompareTo(other).value(), 0);
return 0;
}
- // |this| normalized to a position past the end of the document.
- DCHECK_GT(SlowCompareTo(other).value(), 0);
- return 1;
- } else if (normalized_other_position->IsNullPosition()) {
- // |other| normalized to a position past the end of the document.
- DCHECK_LT(SlowCompareTo(other).value(), 0);
- return -1;
+ // |this| normalized to a position past the end of the whole content.
+ // Since we don't know if one position is the ancestor of the other, we
+ // need to use the slow path.
+ return SlowCompareTo(other);
+ }
+ if (normalized_other_position->IsNullPosition()) {
+ // |other| normalized to a position past the end of the whole content.
+ // Since we don't know if one position is the ancestor of the other, we
+ // need to use the slow path.
+ return SlowCompareTo(other);
}
// Compute the ancestor stacks of both positions and walk them ourselves
- // rather than calling LowestCommonAnchor(). That way, we can discover the
- // first uncommon ancestors.
+ // rather than calling `LowestCommonAnchor`. That way, we can discover the
+ // first uncommon ancestors which we need to use in order to compare the two
+ // positions.
const AXNodeType* common_anchor = nullptr;
base::stack<AXNodeType*> our_ancestors =
normalized_this_position->GetAncestorAnchors();
@@ -3020,177 +3313,398 @@ class AXPosition {
}
if (!common_anchor)
- return base::Optional<int>(base::nullopt);
+ return base::nullopt;
// If each position has an uncommon ancestor node, we can compare those
- // instead of needing to compute ancestor positions.
- if (!our_ancestors.empty() && !other_ancestors.empty()) {
- AXPositionInstance this_uncommon_tree_position = CreateTreePosition(
- GetTreeID(our_ancestors.top()), GetAnchorID(our_ancestors.top()),
- 0 /*child_index*/);
- int this_uncommon_ancestor_index =
- this_uncommon_tree_position->AnchorIndexInParent();
- AXPositionInstance other_uncommon_tree_position = CreateTreePosition(
- GetTreeID(other_ancestors.top()), GetAnchorID(other_ancestors.top()),
- 0 /*child_index*/);
- int other_uncommon_ancestor_index =
- other_uncommon_tree_position->AnchorIndexInParent();
- DCHECK_NE(this_uncommon_ancestor_index, other_uncommon_ancestor_index)
- << "Deepest uncommon ancestors should truly be uncommon, i.e. not "
- "the same.";
- int result = this_uncommon_ancestor_index - other_uncommon_ancestor_index;
-
- // On platforms that support embedded objects, if a text position is
- // within an embedded object and if it is not at the start of that object,
- // the resulting ancestor position should be adjusted to point after the
- // embedded object. Otherwise, assistive software will not be able to get
- // out of the embedded object if its text is not editable when navigating
- // by character.
- //
- // For example, look at the following accessibility tree and the two
- // example text positions together with their equivalent ancestor
- // positions.
- // ++1 kRootWebArea
- // ++++2 kTextField "Before<embedded_object>after"
- // ++++++3 kStaticText "Before"
- // ++++++++4 kInlineTextBox "Before"
- // ++++++5 kImage "Test image"
- // ++++++6 kStaticText "after"
- // ++++++++7 kInlineTextBox "after"
- //
- // Note that the alt text of an image cannot be navigated with cursor
- // left/right, even when the rest of the contents are in a
- // contenteditable.
- //
- // Ancestor position should not be adjusted:
- // TextPosition anchor_id=kImage text_offset=0 affinity=downstream
- // annotated_text=<T>est image AncestorTextPosition anchor_id=kTextField
- // text_offset=6 affinity=downstream
- // annotated_text=Before<embedded_object>after
- //
- // Ancestor position should be adjusted:
- // TextPosition anchor_id=kImage text_offset=1 affinity=downstream
- // annotated_text=T<e>st image AncestorTextPosition anchor_id=kTextField
- // text_offset=7 affinity=downstream
- // annotated_text=Beforeembedded_object<a>fter
- //
- // Note that since the adjustment to the distance between the ancestor
- // positions could at most be by one, we skip doing this check if the
- // ancestor positions have a distance of more than one since it can never
- // change the outcome of the comparison. Note too that if both ancestor
- // positions need to be adjusted, the adjustments will cancel out.
- if (abs(result) == 1) {
- if (!normalized_this_position->AtStartOfAnchor() &&
- this_uncommon_tree_position->IsEmbeddedObjectInParent()) {
- result += 1;
- }
- if (!normalized_other_position->AtStartOfAnchor() &&
- other_uncommon_tree_position->IsEmbeddedObjectInParent()) {
- result -= 1;
- }
- }
+ // instead of needing to compute ancestor positions. Otherwise we need to
+ // use "SlowCompareTo". Also, if the two positions became equivalent after
+ // being normalized above, we can't compare using this optimized method. We
+ // need to use "SlowCompareTo", because affinity information would have been
+ // lost during the normalization process. See comments in "SlowCompareTo"
+ // for an explanation of how affinity could affect the comparison. If one
+ // position is the ancestor of the other, we need to use "SlowCompareTo",
+ // especially if either or both positions are text positions, because the
+ // conversion to tree positions below would lose information that could
+ // affect the comparison. In the case where the positions are ancestors of
+ // one another, but they are both tree positions, using the "SlowCompareTo"
+ // method will not affect performance, so we still opt for that. Note that
+ // determining whether two positions are ancestors of one another could
+ // easily be accomplished by checking if there are any ancestors left after
+ // removing the common ancestor anchor from either position's ancestor
+ // stack.
+ if (our_ancestors.empty() || other_ancestors.empty())
+ return SlowCompareTo(other);
-#if DCHECK_IS_ON()
- // Validate the optimization.
- int slow_result = SlowCompareTo(other).value();
- DCHECK((result == 0 && slow_result == 0) ||
- (result < 0 && slow_result < 0) ||
- (result > 0 && slow_result > 0));
-#endif
-
- return result;
+ AXPositionInstance this_uncommon_tree_position =
+ CreateTreePosition(GetTreeID(our_ancestors.top()),
+ GetAnchorID(our_ancestors.top()), 0 /*child_index*/);
+ int this_uncommon_ancestor_index =
+ this_uncommon_tree_position->AnchorIndexInParent();
+ AXPositionInstance other_uncommon_tree_position = CreateTreePosition(
+ GetTreeID(other_ancestors.top()), GetAnchorID(other_ancestors.top()),
+ 0 /*child_index*/);
+ int other_uncommon_ancestor_index =
+ other_uncommon_tree_position->AnchorIndexInParent();
+ DCHECK_NE(this_uncommon_ancestor_index, other_uncommon_ancestor_index)
+ << "Deepest uncommon ancestors should truly be uncommon, i.e. not "
+ "the same.";
+ int result = this_uncommon_ancestor_index - other_uncommon_ancestor_index;
+
+ // On platforms that support embedded objects, if a text position is within
+ // an embedded object and if it is not at the start of that object, the
+ // resulting ancestor position should be adjusted to point after the
+ // embedded object. Otherwise, assistive software will not be able to get
+ // out of the embedded object if its text is not editable when navigating by
+ // character or by word. The "SlowCompareTo" method can handle such corner
+ // cases. For some reproduction steps see https://crbug.com/1057831.
+ //
+ // For example, look at the following accessibility tree and the two example
+ // text positions together with their equivalent ancestor positions.
+ // ++1 kRootWebArea
+ // ++++2 kTextField "Before<embedded_object>after"
+ // ++++++3 kStaticText "Before"
+ // ++++++++4 kInlineTextBox "Before"
+ // ++++++5 kImage "Test image"
+ // ++++++6 kStaticText "after"
+ // ++++++++7 kInlineTextBox "after"
+ //
+ // Note that the alt text of an image cannot be navigated with cursor
+ // left/right, even when the rest of the contents are in a contenteditable.
+ //
+ // 1. Ancestor position should not be adjusted:
+ // TextPosition anchor_id=kImage text_offset=0 affinity=downstream
+ // annotated_text=<T>est image
+ //
+ // AncestorTextPosition anchor_id=kTextField text_offset=6
+ // affinity=downstream annotated_text=Before<embedded_object>after
+ //
+ // 2. Ancestor position should be adjusted:
+ // TextPosition anchor_id=kImage text_offset=1 affinity=downstream
+ // annotated_text=T<e>st image
+ //
+ // AncestorTextPosition anchor_id=kTextField text_offset=7
+ // affinity=downstream annotated_text=Beforeembedded_object<a>fter
+ //
+ // Note that since the adjustment to the distance between the ancestor
+ // positions could at most be by one, we skip doing this check if the
+ // ancestor positions have a distance of more than one since it can never
+ // change the outcome of the comparison. We also don't need to perform an
+ // adjustment if one of the positions is not right after the "object
+ // replacement character" representing the object inside which the other
+ // position is located, hence the `AtStartOfAnchor()` and
+ // `IsEmbeddedObjectInParent()` checks.
+ if (abs(result) == 1 &&
+ ((IsTextPosition() && !AtStartOfAnchor() &&
+ this_uncommon_tree_position->IsEmbeddedObjectInParent()) ||
+ (other.IsTextPosition() && !other.AtStartOfAnchor() &&
+ other_uncommon_tree_position->IsEmbeddedObjectInParent()))) {
+ return SlowCompareTo(other);
}
- return SlowCompareTo(other);
+#if DCHECK_IS_ON()
+ // Validate the optimization against the non-optimized version of the
+ // method.
+ int slow_result = SlowCompareTo(other).value();
+ DCHECK((result == 0 && slow_result == 0) ||
+ (result < 0 && slow_result < 0) || (result > 0 && slow_result > 0))
+ << result << " vs. " << slow_result;
+#endif // DCHECK_IS_ON()
+
+ return result;
}
+ // A less optimized, but much slower version of "CompareTo". Should only be
+ // used when optimizations cannot be applied, e.g. when comparing ignored
+ // positions. See "CompareTo" for an explanation of the return values.
base::Optional<int> SlowCompareTo(const AXPosition& other) const {
+ if (IsNullPosition() && other.IsNullPosition())
+ return 0;
+ if (IsNullPosition() || other.IsNullPosition())
+ return base::nullopt;
+
+ // If both positions share an anchor and either one is a text position, or
+ // both are tree positions, we can do a straight comparison of text offsets
+ // or child indices.
+ if (GetAnchor() == other.GetAnchor()) {
+ base::Optional<int> optional_result;
+ ax::mojom::TextAffinity this_affinity;
+ ax::mojom::TextAffinity other_affinity;
+
+ if (IsTextPosition()) {
+ AXPositionInstance other_text_position = other.AsTextPosition();
+ optional_result = text_offset_ - other_text_position->text_offset_;
+ this_affinity = affinity();
+ other_affinity = other_text_position->affinity();
+ }
+
+ if (other.IsTextPosition()) {
+ AXPositionInstance this_text_position = AsTextPosition();
+ optional_result = this_text_position->text_offset_ - other.text_offset_;
+ this_affinity = this_text_position->affinity();
+ other_affinity = other.affinity();
+ }
+
+ if (optional_result) {
+ // Only when the two positions are otherwise equivalent will affinity
+ // play a role.
+ if (*optional_result != 0)
+ return optional_result;
+
+ if (this_affinity == ax::mojom::TextAffinity::kUpstream &&
+ other_affinity == ax::mojom::TextAffinity::kDownstream) {
+ return -1;
+ }
+ if (this_affinity == ax::mojom::TextAffinity::kDownstream &&
+ other_affinity == ax::mojom::TextAffinity::kUpstream) {
+ return 1;
+ }
+
+ return optional_result;
+ }
+
+ return child_index_ - other.child_index_;
+ }
+
// It is potentially costly to compute the parent position of a text
// position, whilst computing the parent position of a tree position is
- // really inexpensive. In order to find the lowest common ancestor,
+ // really inexpensive. In order to find the lowest common ancestor position,
// especially if that ancestor is all the way up to the root of the tree,
- // this will need to be done repeatedly. We avoid the performance hit by
- // converting both positions to tree positions and only falling back to text
- // positions if both are text positions and the lowest common ancestor is
- // not one of their anchors. Essentially, the question we need to answer is:
- // "When are two non equivalent positions going to have the same lowest
- // common ancestor position when converted to tree positions?" The answer is
- // when they are both text positions and they either have the same anchor,
- // or one is the ancestor of the other.
+ // computing the parent position will need to be done repeatedly. We avoid
+ // the performance hit by converting both positions to tree positions and
+ // only falling back to computing ancestor text positions if at least one
+ // position is a text position and they don't have the same anchor.
+ //
+ // Essentially, the question we need to answer is: "When are two non
+ // equivalent positions going to have the same lowest common ancestor
+ // position when converted to tree positions as the ones they had before the
+ // conversion?" In other words, when will
+ // "this->AsTreePosition()->LowestCommonAncestor(*other.AsTreePosition()) ==
+ // other.AsTreePosition()->LowestCommonAncestor(*this->AsTreePosition())"?
+ // The answer is either when they have the same anchor and at least one is a
+ // text position, or when both are text positions and one is an ancestor
+ // position of the other. In all other cases, no information will be lost
+ // when converting to tree positions.
+
const AXNodeType* common_anchor = this->LowestCommonAnchor(other);
if (!common_anchor)
- return base::Optional<int>(base::nullopt);
-
- // Attempt to avoid recomputing the lowest common ancestor because we may
- // already have its anchor in which case just find the text offset.
- if (this->IsTextPosition() && other.IsTextPosition()) {
- // This text position's anchor is the common ancestor of the other text
- // position's anchor.
- if (this->GetAnchor() == common_anchor) {
+ return base::nullopt;
+
+ // If either of the two positions is a text position, and if one position is
+ // an ancestor of the other, we need to compare using text positions,
+ // because converting to tree positions will potentially lose information if
+ // the text offset is anything other than 0 or `MaxTextOffset()`.
+ if (IsTextPosition() || other.IsTextPosition()) {
+ base::Optional<int> optional_result;
+ ax::mojom::TextAffinity this_affinity;
+ ax::mojom::TextAffinity other_affinity;
+
+ // The following two "if" blocks deal with comparisons between a text
+ // position and a tree position that are ancestors of one another. The
+ // third "if" block deals with comparisons between two text positions that
+ // are also ancestors of one another. Obviously, in the case of two text
+ // positions, affinity could always play a role (see comment in the
+ // relevant "if" block for an example). For the first two cases, affinity
+ // still needs to be taken into consideration because an "object
+ // replacement character" could be used to represent child nodes in the
+ // text of their parents. Here is an example of how affinity can influence
+ // a text/tree position comparison.
+ //
+ // 1 kRootWebArea
+ // ++2 kGenericContainer
+ // "<embedded_object_character><embedded_object_character>"
+ // ++3 kButton "Line 1"
+ // ++++++4 kStaticText "Line 1"
+ // ++++++++5 kInlineTextBox "Line 1"
+ // ++++6 kImage "<embedded_object_character>" kIsLineBreakingObject
+ //
+ // TextPosition anchor_id=5 text_offset=2 affinity=downstream
+ // annotated_text=Li<n>e 1
+ //
+ // TreePosition anchor_id=6 child_index=BEFORE_TEXT
+ //
+ // The `LowestCommonAncestor` for both will differ in its affinity:
+ // TextPosition anchor_id=2 text_offset=1 affinity=...
+ // annotated_text=embedded_object_character<embedded_object_character>
+ //
+ // The text position would create a kUpstream position, while the tree
+ // position would create a kDownstream position.
+
+ if (GetAnchor() == common_anchor) {
+ DCHECK_EQ(AsTextPosition()->GetAnchor(), common_anchor)
+ << "AsTextPosition() should never modify the position's anchor.";
+ // This text position's anchor is the common ancestor of the other text
+ // position's anchor. We don't need to compute the ancestor position of
+ // this position at the common anchor, since we already have it.
+ //
+ // Note that we convert the other position to an ancestor text position
+ // using a forward direction, so that if there are any "object
+ // replacement characters", two positions one inside the character and
+ // one after it would compare as equivalent. Otherwise, screen readers
+ // might get stuck inside embedded objects while navigating by character
+ // or word. For some reproduction steps see https://crbug.com/1057831.
+ // Per the IAccessible2 Spec, any selection that partially selects text
+ // inside an embedded object, should select the entire "object
+ // replacement character" in the parent object where the character
+ // appears.
+
AXPositionInstance other_text_position =
- other.CreateAncestorPosition(common_anchor);
- return base::Optional<int>(this->text_offset_ -
- other_text_position->text_offset_);
+ other.AsTextPosition()->CreateAncestorPosition(
+ common_anchor, ax::mojom::MoveDirection::kForward);
+ DCHECK_EQ(other_text_position->GetAnchor(), common_anchor);
+ other_affinity = other_text_position->affinity();
+ AXPositionInstance this_text_position = AsTextPosition();
+ this_affinity = this_text_position->affinity();
+ optional_result = this_text_position->text_offset() -
+ other_text_position->text_offset();
}
- // The other text position's anchor is the common ancestor of this text
- // position's anchor.
if (other.GetAnchor() == common_anchor) {
+ DCHECK_EQ(other.AsTextPosition()->GetAnchor(), common_anchor)
+ << "AsTextPosition() should never modify the position's anchor.";
+ // The other text position's anchor is the common ancestor of this text
+ // position's anchor. We don't need to compute the ancestor position of
+ // the other position at the common anchor, since we already have it.
+ //
+ // Note that we convert this position to an ancestor text position using
+ // a forward direction, so that if there are any "object replacement
+ // characters", two positions one inside the character and one after it
+ // would compare as equivalent. Otherwise, screen readers might get
+ // stuck inside embedded objects while navigating by character or word.
+ // For some reproduction steps see https://crbug.com/1057831.
+ // Per the IAccessible2 Spec, any selection that partially selects text
+ // inside an embedded object, should select the entire "object
+ // replacement character" in the parent object where the character
+ // appears.
+
AXPositionInstance this_text_position =
- this->CreateAncestorPosition(common_anchor);
- return base::Optional<int>(this_text_position->text_offset_ -
- other.text_offset_);
+ AsTextPosition()->CreateAncestorPosition(
+ common_anchor, ax::mojom::MoveDirection::kForward);
+ DCHECK_EQ(this_text_position->GetAnchor(), common_anchor);
+ this_affinity = this_text_position->affinity();
+ AXPositionInstance other_text_position = other.AsTextPosition();
+ other_affinity = other_text_position->affinity();
+ optional_result = this_text_position->text_offset() -
+ other_text_position->AsTextPosition()->text_offset();
}
- // All optimizations failed. Fall back to comparing text positions with
- // the common text position ancestor.
- AXPositionInstance this_text_position_ancestor =
- this->CreateAncestorPosition(common_anchor);
- AXPositionInstance other_text_position_ancestor =
- other.CreateAncestorPosition(common_anchor);
- DCHECK(this_text_position_ancestor->IsTextPosition());
- DCHECK(other_text_position_ancestor->IsTextPosition());
- DCHECK_EQ(common_anchor, this_text_position_ancestor->GetAnchor());
- DCHECK_EQ(common_anchor, other_text_position_ancestor->GetAnchor());
-
- // TODO - This does not take into account |affinity_|, so we may return
- // a false positive when comparing at the end of a line.
- // For example :
- // ++1 kRootWebArea
- // ++++2 kTextField "Line 1\nLine 2"
- // ++++++3 kStaticText "Line 1"
- // ++++++++4 kInlineTextBox "Line 1"
- // ++++++5 kLineBreak "\n"
- // ++++++6 kStaticText "Line 2"
- // ++++++++7 kInlineTextBox "Line 2"
- //
- // TextPosition anchor_id=5 text_offset=1
- // affinity=downstream annotated_text=\n<>
- //
- // TextPosition anchor_id=7 text_offset=0
- // affinity=downstream annotated_text=<L>ine 2
- //
- // |LowestCommonAncestor| for both will be :
- // TextPosition anchor_id=2 text_offset=7
- // ... except anchor_id=5 creates a kUpstream position, while
- // anchor_id=7 creates a kDownstream position.
- return base::Optional<int>(this_text_position_ancestor->text_offset_ -
- other_text_position_ancestor->text_offset_);
+ if (IsTextPosition() && other.IsTextPosition()) {
+ // We should compute and compare using the common ancestor text
+ // position. Computing an ancestor text position will automatically take
+ // affinity into consideration. It will also normalize text positions at
+ // the end of their anchors to equivalent positions at the start of the
+ // next anchor. Additionally, it would normalize positions within
+ // "object replacement characters" to after the character. This would
+ // maintain the characteristics of text position comparisons, since a
+ // particular offset in the tree's text representation could refer to
+ // multiple equivalent positions anchored to different nodes in the
+ // tree.
+ //
+ // Here is an example of how affinity can influence a text position
+ // comparison when at a line boundary:
+ //
+ // 1 kRootWebArea
+ // ++2 kTextField "Line 1Line 2"
+ // ++++3 kStaticText "Line 1"
+ // ++++++4 kInlineTextBox "Line 1"
+ // ++++5 kGenericContainer kIsLineBreakingObject
+ // ++++++6 kStaticText "Line 2"
+ // ++++++++7 kInlineTextBox "Line 2"
+ //
+ // TextPosition anchor_id=4 text_offset=6 affinity=downstream
+ // annotated_text=Line 1<>
+ //
+ // TextPosition anchor_id=7 text_offset=0 affinity=downstream
+ // annotated_text=<L>ine 2
+ //
+ // The `LowestCommonAncestor` for both will differ only in its affinity:
+ // TextPosition anchor_id=2 text_offset=6 affinity=...
+ // annotated_text=Line 1<L>ine 2
+ //
+ // anchor_id=4 would create a kUpstream position, while anchor_id=7
+ // would create a kDownstream position.
+
+ AXPositionInstance this_text_position_ancestor =
+ LowestCommonAncestor(other, ax::mojom::MoveDirection::kForward);
+ AXPositionInstance other_text_position_ancestor =
+ other.LowestCommonAncestor(*this,
+ ax::mojom::MoveDirection::kForward);
+ DCHECK(this_text_position_ancestor->IsTextPosition());
+ DCHECK(other_text_position_ancestor->IsTextPosition());
+
+ this_affinity = this_text_position_ancestor->affinity();
+ other_affinity = other_text_position_ancestor->affinity();
+ optional_result = this_text_position_ancestor->text_offset() -
+ other_text_position_ancestor->text_offset();
+ }
+
+ if (optional_result) {
+ // Only when the two positions are otherwise equivalent will affinity
+ // play a role.
+ if (*optional_result != 0)
+ return optional_result;
+
+ if (this_affinity == ax::mojom::TextAffinity::kUpstream &&
+ other_affinity == ax::mojom::TextAffinity::kDownstream) {
+ return -1;
+ }
+ if (this_affinity == ax::mojom::TextAffinity::kDownstream &&
+ other_affinity == ax::mojom::TextAffinity::kUpstream) {
+ return 1;
+ }
+
+ return optional_result;
+ }
+ }
+
+ // Either position is a tree position. To avoid a performance hit, we should
+ // handle comparison by converting both positions to tree positions. Such a
+ // conversion is valid because no information regarding the text offset
+ // would be needed for carrying out the comparison when at least one of the
+ // positions is a tree position.
+ //
+ // We should also normalize all tree positions to the beginning of their
+ // anchors, unless one of the positions is the ancestor of the other. In the
+ // latter case, such a normalization would potentially lose information if
+ // performed on any of the two positions.
+ // ++kRootWebArea "<embedded_object><embedded_object>"
+ // ++++kParagraph "Paragraph1"
+ // ++++kParagraph "paragraph2"
+ // A tree position at the end of the root web area and a tree position at
+ // the end of the second paragraph should compare as equal. Normalizing any
+ // of the two positions to the start of their respective anchors would make
+ // the two positions unequal.
+ //
+ // Unlike text positions, two tree positions on two adjacent anchors, (the
+ // first position at the end of its anchor, (i.e. an "after children"
+ // position), and the other at its beginning), should not compare as equal.
+ // This is because each position in the tree is unique, unlike an offset in
+ // the tree's text representation which can refer to more than one tree
+ // position. Meanwhile, affinity does not play any role in this case, since
+ // except for "after children" positions, tree positions are collapsed to
+ // the beginning of their parent node when computing their parent position.
+
+ AXPositionInstance this_normalized_tree_position = AsTreePosition();
+ AXPositionInstance other_normalized_tree_position = other.AsTreePosition();
+ if (GetAnchor() != common_anchor &&
+ other_normalized_tree_position->GetAnchor() != common_anchor) {
+ // None of the positions is the ancestor of the other, so normalization
+ // could go ahead.
+ this_normalized_tree_position =
+ this_normalized_tree_position->CreatePositionAtStartOfAnchor();
+ other_normalized_tree_position =
+ other_normalized_tree_position->CreatePositionAtStartOfAnchor();
}
- // All optimizations failed. Fall back to comparing child index with
- // the common tree position ancestor.
AXPositionInstance this_tree_position_ancestor =
- this->AsTreePosition()->CreateAncestorPosition(common_anchor);
+ this_normalized_tree_position->CreateAncestorPosition(
+ common_anchor, ax::mojom::MoveDirection::kBackward);
AXPositionInstance other_tree_position_ancestor =
- other.AsTreePosition()->CreateAncestorPosition(common_anchor);
+ other_normalized_tree_position->CreateAncestorPosition(
+ common_anchor, ax::mojom::MoveDirection::kBackward);
DCHECK(this_tree_position_ancestor->IsTreePosition());
DCHECK(other_tree_position_ancestor->IsTreePosition());
- DCHECK_EQ(common_anchor, this_tree_position_ancestor->GetAnchor());
- DCHECK_EQ(common_anchor, other_tree_position_ancestor->GetAnchor());
-
- return base::Optional<int>(this_tree_position_ancestor->child_index() -
- other_tree_position_ancestor->child_index());
+ return this_tree_position_ancestor->child_index_ -
+ other_tree_position_ancestor->child_index_;
}
// A valid position can become invalid if the underlying tree structure
@@ -3203,10 +3717,18 @@ class AXPosition {
text_offset_ = max_text_offset;
}
- // Returns true if this position is on an empty object node that needs to
- // be represented by an empty object replacement character. It does when the
- // node is a collapsed menu list popup button or has no unignored child and is
- // not a text object. This feature is only enabled on some platforms.
+ // Returns true if this position is on an empty control that needs to be
+ // represented by an "object replacement character". This feature is only
+ // enabled on some platforms.
+ //
+ // This is purely for navigational purposes. We need to expose an "object
+ // replacement character" in empty controls, such as in an empty text field or
+ // a collapsed popup menu. The presence or the absence of accessible content
+ // inside a control might alter whether an "object replacement character"
+ // would be exposed in that control, in contrast to ordinary text such as in
+ // the case of a non-empty plain text field which should only have textual
+ // nodes inside it. This is because empty controls need to act as a word and
+ // character boundary.
bool IsEmptyObjectReplacedByCharacter() const {
if (g_ax_embedded_object_behavior ==
AXEmbeddedObjectBehavior::kSuppressCharacter ||
@@ -3220,42 +3742,38 @@ class AXPosition {
if (GetAnchor()->IsCollapsedMenuListPopUpButton())
return true;
- // All other elements that have unignored descendants should not be treated
- // as empty objects.
- if (AnchorUnignoredChildCount())
+ // All anchor nodes that are empty leaf nodes or have only ignored
+ // descendants should be treated as empty objects. Empty leaf nodes do not
+ // expose their descendants to platform accessibility APIs, but may have
+ // unignored descendants. They do not have any inner text, however, hence
+ // they are still empty from our perspective. For example, an empty text
+ // field may still have an unignored generic container inside it.
+ if (AnchorUnignoredChildCount() && !GetAnchor()->IsEmptyLeaf())
return false;
- // Embed element with non empty children should not be treated as empty
- // objects.
- if (GetAnchorRole() == ax::mojom::Role::kEmbeddedObject &&
+ // <embed> and <object> elements with non empty children should not be
+ // treated as empty objects.
+ if ((GetAnchorRole() == ax::mojom::Role::kEmbeddedObject ||
+ GetAnchorRole() == ax::mojom::Role::kPluginObject) &&
AnchorChildCount() > 0) {
return false;
}
- // All unignored leaf nodes in the AXTree except document and text
- // nodes should be replaced by the embedded object character. Also, nodes
- // that only have ignored children (e.g., a button that contains only an
- // empty div) need to be treated as leaf nodes.
+ // All unignored leaf nodes in the accessibility tree except kRootWebArea,
+ // kPdfRoot, text nodes and nodes that are skipped during text navigation,
+ // should be replaced by the embedded object character. (See
+ // `AXNode::IsIgnoredForTextNavigation()`.) Also, nodes that only have
+ // ignored children (e.g., a button that contains only an empty div) need to
+ // be treated as leaf nodes.
//
// Calling AXPosition::IsIgnored here is not possible as it would create an
// infinite loop. However, GetAnchor()->IsIgnored() is sufficient here
// because we know that the anchor at this position doesn't have an
- // unignored child, making this a leaf tree or text position.
- return !GetAnchor()->IsIgnored() && !IsDocument(GetAnchorRole()) &&
- !IsInTextObject() && !IsIframe(GetAnchorRole());
- }
-
- bool IsInDescendantOfEmptyObject() const {
- if (g_ax_embedded_object_behavior ==
- AXEmbeddedObjectBehavior::kSuppressCharacter ||
- IsNullPosition()) {
- return false;
- }
-
- // Empty objects are only possible on a collapsed popup button parent of a
- // menu list popup or a node that only has ignored descendants. If it has no
- // empty object ancestor, it can't be inside of an empty object.
- return GetEmptyObjectAncestorNode();
+ // unignored child, making this a leaf tree or text position, or a leaf's
+ // descendant.
+ return !GetAnchor()->IsIgnored() &&
+ !IsPlatformDocument(GetAnchorRole()) && !IsInTextObject() &&
+ !IsIframe(GetAnchorRole());
}
AXNodeType* GetEmptyObjectAncestorNode() const {
@@ -3266,13 +3784,20 @@ class AXPosition {
}
if (!GetAnchor()->IsIgnored()) {
- // The only case where a descendant of an empty object can be unignored is
- // when we are inside of a collapsed popup button parent of a menu list
- // popup.
+ // The only cases where a descendant of an empty object can be unignored
+ // is when we are inside of a collapsed popup button which is the parent
+ // of a menu list popup, or inside a generic container that is the child
+ // of an empty text field.
if (AXNodeType* popup_button =
GetAnchor()->GetCollapsedMenuListPopUpButtonAncestor()) {
return popup_button;
}
+
+ if (GetAnchorRole() == ax::mojom::Role::kGenericContainer &&
+ !AnchorUnignoredChildCount()) {
+ return GetAnchor()->GetTextFieldAncestor();
+ }
+
return nullptr;
}
@@ -3305,42 +3830,119 @@ class AXPosition {
// Abstract methods.
- // Returns the text that is present inside the anchor node, including any text
- // found in descendant text nodes, based on the platform's text
- // representation. Some platforms use an embedded object replacement character
- // that replaces the text coming from each child node.
- virtual base::string16 GetText() const = 0;
+ // Returns the text (in UTF16 format) that is present inside the anchor node,
+ // including any text found in descendant text nodes, based on the platform's
+ // text representation. Some platforms use an embedded object replacement
+ // character that replaces the text coming from most child nodes.
+ base::string16 GetText() const {
+ if (IsNullPosition())
+ return base::string16();
+
+ // Special case, if a position's anchor node has only ignored descendants,
+ // i.e., it appears to be empty to assistive software, on some platforms we
+ // need to still treat it as a character and a word boundary. We achieve
+ // this by adding an embedded object character in the text representation
+ // used by this class, but we don't expose that character to assistive
+ // software that tries to retrieve the node's inner text.
+ if (IsEmptyObjectReplacedByCharacter())
+ return AXNode::kEmbeddedCharacter;
+
+ // Special case, if a position's anchor node is hosting another
+ // accessibility tree, return the text that is found in that tree's root.
+ const AXNode* anchor = GetAnchor();
+ const AXTreeManager* child_tree_manager =
+ AXTreeManagerMap::GetInstance().GetManagerForChildTree(*anchor);
+ if (child_tree_manager) {
+ // The child node exists in a separate tree from its parent.
+ anchor = child_tree_manager->GetRootAsAXNode();
+ }
+
+ switch (g_ax_embedded_object_behavior) {
+ case AXEmbeddedObjectBehavior::kSuppressCharacter:
+ return base::UTF8ToUTF16(anchor->GetInnerText());
+ case AXEmbeddedObjectBehavior::kExposeCharacter:
+ return anchor->GetHypertext();
+ }
+ }
// Determines if the anchor containing this position is a <br> or a text
// object whose parent's anchor is an enclosing <br>.
- virtual bool IsInLineBreak() const = 0;
+ bool IsInLineBreak() const {
+ if (IsNullPosition())
+ return false;
+ return GetAnchor()->IsLineBreak();
+ }
// Determines if the anchor containing this position is a text object.
- virtual bool IsInTextObject() const = 0;
+ bool IsInTextObject() const {
+ if (IsNullPosition())
+ return false;
+ return GetAnchor()->IsText();
+ }
// Determines if the text representation of this position's anchor contains
// only whitespace characters; <br> objects span a single '\n' character, so
// positions inside line breaks are also considered "in whitespace".
- virtual bool IsInWhiteSpace() const = 0;
+ bool IsInWhiteSpace() const {
+ if (IsNullPosition())
+ return false;
+ return GetAnchor()->IsLineBreak() ||
+ base::ContainsOnlyChars(GetText(), base::kWhitespaceUTF16);
+ }
// Returns the length of the text that is present inside the anchor node,
// including any text found in descendant text nodes. This is based on the
// platform's text representation. Some platforms use an embedded object
- // character that replaces the text coming from each child node.
+ // character that replaces the text coming from most child nodes.
//
// Similar to "text_offset_", the length of the text is in UTF16 code units,
// not in grapheme clusters.
- virtual int MaxTextOffset() const {
+ int MaxTextOffset() const {
if (IsNullPosition())
return INVALID_OFFSET;
- return int{GetText().length()};
+
+ // Special case: If a node has only ignored descendants, i.e., it appears to
+ // be empty to assistive software, on some platforms we need to still treat
+ // it as a character and a word boundary. We achieve this by adding an
+ // "object replacement character" in the accessibility tree's text
+ // representation, but we don't expose that character to assistive software
+ // that tries to retrieve the node's inner text or hypertext.
+ if (IsEmptyObjectReplacedByCharacter())
+ return AXNode::kEmbeddedCharacterLength;
+
+ // Special case, if a position's anchor node is hosting another
+ // accessibility tree, return the text that is found in that tree's root.
+ const AXNode* anchor = GetAnchor();
+ const AXTreeManager* child_tree_manager =
+ AXTreeManagerMap::GetInstance().GetManagerForChildTree(*anchor);
+ if (child_tree_manager) {
+ // The child node exists in a separate tree from its parent.
+ anchor = child_tree_manager->GetRootAsAXNode();
+ }
+
+ switch (g_ax_embedded_object_behavior) {
+ case AXEmbeddedObjectBehavior::kSuppressCharacter:
+ // TODO(nektar): Switch to anchor->GetInnerTextLength() after AXPosition
+ // switches to using UTF8.
+ return int{base::UTF8ToUTF16(anchor->GetInnerText()).length()};
+ case AXEmbeddedObjectBehavior::kExposeCharacter:
+ return int{anchor->GetHypertext().length()};
+ }
+ }
+
+ // Returns the accessibility role of this position's anchor node. If this is a
+ // "null position", returns `ax::mojom::Role::kUnknown`.
+ ax::mojom::Role GetRole() const {
+ if (IsNullPosition())
+ return ax::mojom::Role::kUnknown;
+ return GetAnchor()->data().role;
}
protected:
AXPosition()
: kind_(AXPositionKind::NULL_POSITION),
tree_id_(AXTreeIDUnknown()),
- anchor_id_(AXNode::kInvalidAXID),
+ anchor_id_(kInvalidAXNodeID),
child_index_(INVALID_INDEX),
text_offset_(INVALID_OFFSET),
affinity_(ax::mojom::TextAffinity::kDownstream) {}
@@ -3362,17 +3964,28 @@ class AXPosition {
return INVALID_OFFSET;
// Calculate how much text there is to the left of this anchor.
- AXPositionInstance tree_position = AsTreePosition();
- DCHECK(tree_position);
- AXPositionInstance parent_position = tree_position->CreateParentPosition();
- DCHECK(parent_position);
+ //
+ // Work with a tree position so as not to incur any performance hit for
+ // calculating the corresponding text offset in the parent anchor on
+ // platforms that do not use an "object replacement character" to represent
+ // child nodes.
+ //
+ // Ignored positions are not visible to platform APIs. As a result, their
+ // inner text or hypertext does not appear in their parent node, but the
+ // text of their unignored children does. (See `AXNode::GetHypertext()` for
+ // the meaning of "hypertext" in this context.
+ AXPositionInstance tree_position =
+ CreatePositionAtStartOfAnchor()->AsTreePosition();
+ DCHECK(!tree_position->IsNullPosition());
+ AXPositionInstance parent_position = tree_position->CreateParentPosition(
+ ax::mojom::MoveDirection::kBackward);
if (parent_position->IsNullPosition())
- return 0;
+ return 0; // There is only a single root node.
int offset_in_parent = 0;
for (int i = 0; i < parent_position->child_index(); ++i) {
AXPositionInstance child = parent_position->CreateChildPositionAt(i);
- DCHECK(child);
+ DCHECK(!child->IsNullPosition());
offset_in_parent += child->MaxTextOffsetInParent();
}
return offset_in_parent;
@@ -3386,7 +3999,7 @@ class AXPosition {
// to move by grapheme boundaries on non-leaf nodes and computing plus caching
// the inner text for all nodes is costly.
std::unique_ptr<base::i18n::BreakIterator> GetGraphemeIterator() const {
- if (!IsTextPosition() || !IsLeaf())
+ if (!IsLeafTextPosition())
return {};
name_ = GetText();
@@ -3399,7 +4012,7 @@ class AXPosition {
void Initialize(AXPositionKind kind,
AXTreeID tree_id,
- int32_t anchor_id,
+ AXNodeID anchor_id,
int child_index,
int text_offset,
ax::mojom::TextAffinity affinity) {
@@ -3414,7 +4027,7 @@ class AXPosition {
// Reset to the null position.
kind_ = AXPositionKind::NULL_POSITION;
tree_id_ = AXTreeIDUnknown();
- anchor_id_ = AXNode::kInvalidAXID;
+ anchor_id_ = kInvalidAXNodeID;
child_index_ = INVALID_INDEX;
text_offset_ = INVALID_OFFSET;
affinity_ = ax::mojom::TextAffinity::kDownstream;
@@ -3422,51 +4035,284 @@ class AXPosition {
}
// Abstract methods.
- virtual void AnchorChild(int child_index,
- AXTreeID* tree_id,
- int32_t* child_id) const = 0;
- virtual int AnchorChildCount() const = 0;
+ void AnchorChild(int child_index,
+ AXTreeID* tree_id,
+ AXNodeID* child_id) const {
+ DCHECK(tree_id);
+ DCHECK(child_id);
+ if (!GetAnchor() || child_index < 0 || child_index >= AnchorChildCount()) {
+ *tree_id = AXTreeIDUnknown();
+ *child_id = kInvalidAXNodeID;
+ return;
+ }
+
+ AXNode* child = nullptr;
+ const AXTreeManager* child_tree_manager =
+ AXTreeManagerMap::GetInstance().GetManagerForChildTree(*GetAnchor());
+ if (child_tree_manager) {
+ // The child node exists in a separate tree from its parent.
+ child = child_tree_manager->GetRootAsAXNode();
+ *tree_id = child_tree_manager->GetTreeID();
+ } else {
+ child = GetAnchor()->children()[size_t{child_index}];
+ *tree_id = this->tree_id();
+ }
+ *child_id = child->id();
+ }
+
+ int AnchorChildCount() const {
+ if (!GetAnchor())
+ return 0;
+
+ const AXTreeManager* child_tree_manager =
+ AXTreeManagerMap::GetInstance().GetManagerForChildTree(*GetAnchor());
+ if (child_tree_manager)
+ return 1;
+
+ return int{GetAnchor()->children().size()};
+ }
+
// When a child is ignored, it looks for unignored nodes of that child's
// children until there are no more descendants.
//
- // E.g.
+ // For example:
// ++TextField
// ++++GenericContainer ignored
// ++++++StaticText "Hello"
// When we call the following method on TextField, it would return 1.
- virtual int AnchorUnignoredChildCount() const = 0;
- virtual int AnchorIndexInParent() const = 0;
- virtual int AnchorSiblingCount() const = 0;
- virtual base::stack<AXNodeType*> GetAncestorAnchors() const = 0;
- virtual AXNodeType* GetLowestUnignoredAncestor() const = 0;
- virtual void AnchorParent(AXTreeID* tree_id, int32_t* parent_id) const = 0;
- virtual AXNodeType* GetNodeInTree(AXTreeID tree_id,
- int32_t node_id) const = 0;
- virtual int32_t GetAnchorID(AXNodeType* node) const = 0;
- virtual AXTreeID GetTreeID(AXNodeType* node) const = 0;
-
- // Returns the length of text that this anchor node takes up in its parent.
+ int AnchorUnignoredChildCount() const {
+ if (!GetAnchor())
+ return 0;
+
+ const AXTreeManager* child_tree_manager =
+ AXTreeManagerMap::GetInstance().GetManagerForChildTree(*GetAnchor());
+ if (child_tree_manager) {
+ DCHECK_EQ(GetAnchor()->GetUnignoredChildCount(), 0u)
+ << "A node cannot be hosting both a child tree and other nodes as "
+ "children.";
+ return 1; // A child tree is never ignored.
+ }
+
+ return int{GetAnchor()->GetUnignoredChildCount()};
+ }
+
+ int AnchorIndexInParent() const {
+ // If this is the root tree, the index in parent will be 0.
+ return GetAnchor() ? int{GetAnchor()->index_in_parent()} : INVALID_INDEX;
+ }
+
+ base::stack<AXNodeType*> GetAncestorAnchors() const {
+ if (!GetAnchor())
+ return base::stack<AXNode*>();
+
+ base::stack<AXNode*> anchors;
+ AXNode* current_anchor = GetAnchor();
+ AXNodeID current_anchor_id = GetAnchor()->id();
+ AXTreeID current_tree_id = tree_id();
+ AXNodeID parent_anchor_id = kInvalidAXNodeID;
+ AXTreeID parent_tree_id = AXTreeIDUnknown();
+
+ while (current_anchor) {
+ anchors.push(current_anchor);
+ current_anchor = GetParent(
+ current_anchor /*child*/, current_tree_id /*child_tree_id*/,
+ &parent_tree_id /*parent_tree_id*/, &parent_anchor_id /*parent_id*/);
+
+ current_anchor_id = parent_anchor_id;
+ current_tree_id = parent_tree_id;
+ }
+ return anchors;
+ }
+
+ AXNodeType* GetLowestUnignoredAncestor() const {
+ if (!GetAnchor())
+ return nullptr;
+ return GetAnchor()->GetLowestPlatformAncestor();
+ }
+
+ void AnchorParent(AXTreeID* tree_id, AXNodeID* parent_id) const {
+ DCHECK(tree_id);
+ DCHECK(parent_id);
+ *tree_id = AXTreeIDUnknown();
+ *parent_id = kInvalidAXNodeID;
+ if (!GetAnchor())
+ return;
+
+ GetParent(GetAnchor() /*child*/, this->tree_id() /*child_tree_id*/,
+ tree_id /*parent_tree_id*/, parent_id /*parent_id*/);
+ }
+
+ AXNodeType* GetNodeInTree(AXTreeID tree_id, AXNodeData::AXID node_id) const {
+ if (node_id == kInvalidAXNodeID)
+ return nullptr;
+
+ AXTreeManager* manager =
+ AXTreeManagerMap::GetInstance().GetManager(tree_id);
+ if (manager)
+ return manager->GetNodeFromTree(tree_id, node_id);
+
+ return nullptr;
+ }
+
+ AXNodeData::AXID GetAnchorID(AXNodeType* node) const { return node->id(); }
+
+ AXTreeID GetTreeID(AXNodeType* node) const {
+ return node->tree()->GetAXTreeID();
+ }
+
+ // Returns the length of text (in UTF16 code points) that this anchor node
+ // takes up in its parent.
+ //
// On some platforms, embedded objects are represented in their parent with a
- // single embedded object character.
+ // single "embedded object character".
int MaxTextOffsetInParent() const {
- return IsEmbeddedObjectInParent() ? 1 : MaxTextOffset();
+ // Ignored anchors are not visible to platform APIs. As a result, their
+ // inner text or hypertext does not appear in their parent node, but the
+ // text of their unignored children does, if any. (See
+ // `AXNode::GetHypertext()` for the meaning of "hypertext" in this context.
+ if (!GetAnchor()->IsIgnored()) {
+ if (IsEmbeddedObjectInParent())
+ return AXNode::kEmbeddedCharacterLength;
+ } else {
+ // Ignored leaf (text) nodes might contain inner text or hypertext, but it
+ // should not be exposed in their parent.
+ if (!AnchorUnignoredChildCount())
+ return 0;
+ }
+ return MaxTextOffset();
}
// Returns whether or not this anchor is represented in their parent with a
- // single embedded object character.
- virtual bool IsEmbeddedObjectInParent() const = 0;
+ // single "object replacement character".
+ bool IsEmbeddedObjectInParent() const {
+ switch (g_ax_embedded_object_behavior) {
+ case AXEmbeddedObjectBehavior::kSuppressCharacter:
+ return false;
+ case AXEmbeddedObjectBehavior::kExposeCharacter:
+ // We expose an "object replacement character" for all nodes except:
+ // A) Textual nodes, such as static text, inline text boxes and line
+ // breaks, and B) Nodes that are invisible to platform APIs.
+ //
+ // In the first case, textual nodes cannot be represented by an "object
+ // replacement character" in the hypertext of their unignored parents,
+ // because we want to maintain compatibility with how Firefox exposes
+ // text in IAccessibleText. In the second case, ignored nodes and nodes
+ // that are descendants of platform leaves should maintain the actual
+ // text of all their static text descendants, otherwise there would be
+ // loss of information while traversing the accessibility tree upwards.
+ // An example of a platform leaf is a plain text field, because all of
+ // the accessibility subtree inside the text field is hidden from
+ // platform APIs. An example of how an ignored node can affect the
+ // hypertext of an unignored ancestor is shown below:
+ // ++kTextField "Hello"
+ // ++++kGenericContainer ignored "Hello"
+ // ++++++kStaticText "Hello"
+ // ++++++++kInlineTextBox "Hello"
+ // The generic container, even though it is ignored, should nevertheless
+ // maintain the text of its static text child and not use an "object
+ // replacement character". Otherwise, the value of the text field would
+ // be wrong.
+ //
+ // Please note that there is one more method that controls whether an
+ // "object replacement character" would be exposed. See
+ // `AXPosition::IsEmptyObjectReplacedByCharacter()`.
+ return !IsNullPosition() && !GetAnchor()->IsIgnored() &&
+ !GetAnchor()->IsText() && !GetAnchor()->IsChildOfLeaf();
+ }
+ }
// Determines if the anchor containing this position produces a hard line
// break in the text representation, e.g. a block level element or a <br>.
- virtual bool IsInLineBreakingObject() const = 0;
+ bool IsInLineBreakingObject() const {
+ if (IsNullPosition())
+ return false;
+ return GetAnchor()->data().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject) &&
+ !GetAnchor()->IsInListMarker();
+ }
+
+ ax::mojom::Role GetAnchorRole() const {
+ if (IsNullPosition())
+ return ax::mojom::Role::kUnknown;
+ return GetRole(GetAnchor());
+ }
+
+ ax::mojom::Role GetRole(AXNodeType* node) const { return node->data().role; }
+
+ AXNodeTextStyles GetTextStyles() const {
+ // Check either the current anchor or its parent for text styles.
+ AXNodeTextStyles current_anchor_text_styles =
+ !IsNullPosition() ? GetAnchor()->data().GetTextStyles()
+ : AXNodeTextStyles();
+ if (current_anchor_text_styles.IsUnset()) {
+ AXPositionInstance parent_position =
+ AsTreePosition()->CreateParentPosition(
+ ax::mojom::MoveDirection::kBackward);
+ if (!parent_position->IsNullPosition())
+ return parent_position->GetAnchor()->data().GetTextStyles();
+ }
+ return current_anchor_text_styles;
+ }
+
+ std::vector<int32_t> GetWordStartOffsets() const {
+ if (IsNullPosition())
+ return std::vector<int32_t>();
+ DCHECK(GetAnchor());
+
+ // Embedded object replacement characters are not represented in the
+ // "kWordStarts" attribute so we need to special case them here.
+ if (IsEmptyObjectReplacedByCharacter())
+ return {0};
+
+ return GetAnchor()->data().GetIntListAttribute(
+ ax::mojom::IntListAttribute::kWordStarts);
+ }
+
+ std::vector<int32_t> GetWordEndOffsets() const {
+ if (IsNullPosition())
+ return std::vector<int32_t>();
+ DCHECK(GetAnchor());
+
+ // Embedded object replacement characters are not represented in the
+ // "kWordEnds" attribute so we need to special case them here.
+ //
+ // Since the whole text exposed inside of an embedded object is of
+ // length 1 (the embedded object replacement character), the word end offset
+ // is positioned at 1. Because we want to treat the embedded object
+ // replacement characters as ordinary characters, it wouldn't be consistent
+ // to assume they have no length and return 0 instead of 1.
+ if (IsEmptyObjectReplacedByCharacter())
+ return {1};
+
+ return GetAnchor()->data().GetIntListAttribute(
+ ax::mojom::IntListAttribute::kWordEnds);
+ }
- virtual ax::mojom::Role GetAnchorRole() const = 0;
- virtual ax::mojom::Role GetRole(AXNodeType* node) const = 0;
- virtual AXNodeTextStyles GetTextStyles() const = 0;
- virtual std::vector<int32_t> GetWordStartOffsets() const = 0;
- virtual std::vector<int32_t> GetWordEndOffsets() const = 0;
- virtual int32_t GetNextOnLineID(int32_t node_id) const = 0;
- virtual int32_t GetPreviousOnLineID(int32_t node_id) const = 0;
+ AXNodeData::AXID GetNextOnLineID(AXNodeData::AXID node_id) const {
+ if (IsNullPosition())
+ return kInvalidAXNodeID;
+ AXNode* node = GetNodeInTree(tree_id(), node_id);
+ int next_on_line_id;
+ if (!node ||
+ !node->data().GetIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
+ &next_on_line_id)) {
+ return kInvalidAXNodeID;
+ }
+ return static_cast<AXNodeID>(next_on_line_id);
+ }
+
+ AXNodeData::AXID GetPreviousOnLineID(AXNodeData::AXID node_id) const {
+ if (IsNullPosition())
+ return kInvalidAXNodeID;
+ AXNode* node = GetNodeInTree(tree_id(), node_id);
+ int previous_on_line_id;
+ if (!node ||
+ !node->data().GetIntAttribute(
+ ax::mojom::IntAttribute::kPreviousOnLineId, &previous_on_line_id)) {
+ return kInvalidAXNodeID;
+ }
+ return static_cast<AXNodeID>(previous_on_line_id);
+ }
private:
// Defines the relationship between positions during traversal.
@@ -3500,12 +4346,13 @@ class AXPosition {
// We are at the end of text span if |this| position has
// role::kInlineTextBox, the parent of |this| has role::kStaticText, and the
- // anchor node of |this| is the last child of parent's children.
+ // anchor node of |this| is the last child of its parent's children.
const bool is_last_child =
- AnchorIndexInParent() == (AnchorSiblingCount() - 1);
+ AnchorIndexInParent() == (GetAnchorSiblingCount() - 1);
- return is_last_child && GetRole(GetLowestUnignoredAncestor()) ==
- ax::mojom::Role::kStaticText;
+ DCHECK(GetAnchor());
+ return is_last_child &&
+ GetRole(GetAnchor()->parent()) == ax::mojom::Role::kStaticText;
}
// Uses depth-first pre-order traversal.
@@ -3578,9 +4425,13 @@ class AXPosition {
if (parent_position->IsNullPosition())
return parent_position;
- // If there is no previous sibling, move up to the parent.
+ // If there is no previous sibling, or the parent itself is a leaf, move up
+ // to the parent. The parent can be a leaf if we start with a tree position
+ // that is a descendant of a node that is an empty control represented by
+ // an "object replacement character" (see
+ // `IsEmptyObjectReplacedByCharacter()`).
const int index_in_parent = current_position->AnchorIndexInParent();
- if (index_in_parent <= 0) {
+ if (index_in_parent <= 0 || parent_position->IsLeaf()) {
if (abort_predicate.Run(*current_position, *parent_position,
AXMoveType::kAncestor,
AXMoveDirection::kPreviousInTree)) {
@@ -3600,6 +4451,7 @@ class AXPosition {
return CreateNullPosition();
}
+ CHECK(!rightmost_leaf->IsNullPosition());
while (!rightmost_leaf->IsLeaf()) {
parent_position = std::move(rightmost_leaf);
rightmost_leaf = parent_position->CreateChildPositionAt(
@@ -3611,13 +4463,15 @@ class AXPosition {
AXMoveDirection::kPreviousInTree)) {
return CreateNullPosition();
}
+ CHECK(!rightmost_leaf->IsNullPosition());
}
return rightmost_leaf;
}
- // Creates a position using the next text-only node as its anchor.
- // Assumes that text-only nodes are leaf nodes.
- AXPositionInstance CreateNextTextAnchorPosition(
+ // Creates a text position using the next leaf node as its anchor.
+ // Nearly all of the text in the accessibility tree is contained in leaf
+ // nodes, so this method is mostly used to move through text nodes.
+ AXPositionInstance CreateNextLeafTextPosition(
const AbortMovePredicate& abort_predicate) const {
// If this is an ancestor text position, resolve to its leaf text position.
if (IsTextPosition() && !IsLeaf())
@@ -3631,9 +4485,10 @@ class AXPosition {
return next_leaf->AsLeafTextPosition();
}
- // Creates a position using the previous text-only node as its anchor.
- // Assumes that text-only nodes are leaf nodes.
- AXPositionInstance CreatePreviousTextAnchorPosition(
+ // Creates a text position using the previous leaf node as its anchor.
+ // Nearly all of the text in the accessibility tree is contained in leaf
+ // nodes, so this method is mostly used to move through text nodes.
+ AXPositionInstance CreatePreviousLeafTextPosition(
const AbortMovePredicate& abort_predicate) const {
// If this is an ancestor text position, resolve to its leaf text position.
if (IsTextPosition() && !IsLeaf())
@@ -3650,8 +4505,9 @@ class AXPosition {
return previous_leaf->AsLeafTextPosition();
}
- // Creates a tree position using the next text-only node as its anchor.
- // Assumes that text-only nodes are leaf nodes.
+ // Creates a tree position using the next leaf node as its anchor.
+ // Nearly all of the text in the accessibility tree is contained in leaf
+ // nodes, so this method is mostly used to move through text nodes.
AXPositionInstance CreateNextLeafTreePosition(
const AbortMovePredicate& abort_predicate) const {
AXPositionInstance next_leaf =
@@ -3663,8 +4519,9 @@ class AXPosition {
return next_leaf;
}
- // Creates a tree position using the previous text-only node as its anchor.
- // Assumes that text-only nodes are leaf nodes.
+ // Creates a tree position using the previous leaf node as its anchor.
+ // Nearly all of the text in the accessibility tree is contained in leaf
+ // nodes, so this method is mostly used to move through text nodes.
AXPositionInstance CreatePreviousLeafTreePosition(
const AbortMovePredicate& abort_predicate) const {
AXPositionInstance previous_leaf =
@@ -3837,6 +4694,9 @@ class AXPosition {
}
// AbortMovePredicate function used to detect page boundaries.
+ //
+ // Depending on the type of content, it might be separated into a number of
+ // pages. For example, a PDF document may expose multiple pages.
static bool AbortMoveAtPageBoundary(const AXPosition& move_from,
const AXPosition& move_to,
const AXMoveType move_type,
@@ -3861,12 +4721,51 @@ class AXPosition {
// since the descendant is contained by it.
return move_to_break;
case AXMoveType::kSibling:
- // For Sibling moves, abort if at both of the siblings are a page
- // break, because that would mean exiting and/or entering a page break.
+ // For Sibling moves, abort if both of the siblings are a page break,
+ // because that would mean exiting and/or entering a page break.
return move_from_break && move_to_break;
}
- NOTREACHED();
- return false;
+ }
+
+ // AbortMovePredicate function used to detect crossing through the boundaries
+ // of a window-like container, such as a webpage, a PDF, a dialog, the
+ // browser's UI (AKA Views), or the whole desktop.
+ static bool AbortMoveAtRootBoundary(const AXPosition& move_from,
+ const AXPosition& move_to,
+ const AXMoveType move_type,
+ const AXMoveDirection direction) {
+ // Positions are null when moving past the whole content, therefore the root
+ // of a window-like container has certainly been crossed.
+ if (move_from.IsNullPosition() || move_to.IsNullPosition())
+ return true;
+
+ const ax::mojom::Role move_from_role = move_from.GetAnchorRole();
+ const ax::mojom::Role move_to_role = move_to.GetAnchorRole();
+ switch (move_type) {
+ case AXMoveType::kAncestor:
+ // For Ancestor moves, only abort when exiting a window-like container.
+ // We don't care if the ancestor is the root of a window-like container
+ // or not, since the descendant is contained by it. However, we do care
+ // if the ancestor is an iframe because a webpage should be navigated as
+ // a single document together with all its iframes, (out-of-process or
+ // otherwise).
+ return IsRootLike(move_from_role) && !IsIframe(move_to_role);
+ case AXMoveType::kDescendant:
+ // For Descendant moves, only abort when entering a window-like
+ // container. We don't care if the ancestor is the root of a window-like
+ // container or not, since the descendant is contained by it. However,
+ // we do care if the ancestor is an iframe because a webpage should be
+ // navigated as a single document together with all its iframes,
+ // (out-of-process or otherwise).
+ return IsRootLike(move_to_role) && !IsIframe(move_from_role);
+ case AXMoveType::kSibling:
+ // For Sibling moves, abort if both of the siblings are at the root of
+ // window-like containers because that would mean exiting and/or
+ // entering a new window-like container. Iframes should not be present
+ // in this case because an iframe should never contain more than one
+ // kRootWebArea as its immediate child.
+ return IsRootLike(move_from_role) && IsRootLike(move_to_role);
+ }
}
static bool AbortMoveAtStartOfInlineBlock(const AXPosition& move_from,
@@ -3933,16 +4832,74 @@ class AXPosition {
return position->GetWordEndOffsets();
}
- AXPositionInstance CreateDocumentAncestorPosition() const {
- AXPositionInstance iterator = Clone();
- while (!iterator->IsNullPosition()) {
- if (IsDocument(iterator->GetAnchorRole()) &&
- iterator->CreateParentPosition()->IsNullPosition()) {
+ // Creates an ancestor equivalent position at the root node of this position's
+ // accessibility tree, e.g. at the root of the current iframe (out-of-process
+ // or not), PDF plugin, Views tree, dialog (native, ARIA or HTML), window, or
+ // the whole desktop.
+ //
+ // For a similar method that does not stop at all iframe boundaries, see
+ // `CreateRootAncestorPosition`.
+ //
+ // See `CreateParentPosition` for an explanation of the use of
+ // |move_direction|.
+ AXPositionInstance CreateAXTreeRootAncestorPosition(
+ ax::mojom::MoveDirection move_direction) const {
+ if (IsNullPosition())
+ return Clone();
+
+ AXPositionInstance root_position = Clone();
+ while (!IsRootLike(root_position->GetAnchorRole())) {
+ AXPositionInstance parent_position =
+ root_position->CreateParentPosition(move_direction);
+ if (parent_position->IsNullPosition())
break;
+ root_position = std::move(parent_position);
+ }
+
+ return root_position;
+ }
+
+ // Creates an ancestor equivalent position at the root node of all content,
+ // e.g. at the root of the whole webpage, PDF plugin, Views tree, dialog
+ // (native, ARIA or HTML), window, or the whole desktop.
+ //
+ // Note that this method will break out of an out-of-process iframe and return
+ // a position at the root of the top-level document, but it will not break
+ // into the Views tree if present. For a similar method that stops at all
+ // iframe boundaries, see `CreateAXTreeRootAncestorPosition`.
+ //
+ // See `CreateParentPosition` for an explanation of the use of
+ // |move_direction|.
+ AXPositionInstance CreateRootAncestorPosition(
+ ax::mojom::MoveDirection move_direction) const {
+ AXPositionInstance root_position =
+ CreateAXTreeRootAncestorPosition(move_direction);
+ AXPositionInstance web_root_position = CreateNullPosition();
+ for (; !root_position->IsNullPosition();
+ root_position =
+ root_position->CreateAXTreeRootAncestorPosition(move_direction)) {
+ // An "ax::mojom::Role::kRootWebArea" could also be present at the root of
+ // iframes or embedded objects, so we need to check that for that specific
+ // role the position is also at the top of the forest of accessibility
+ // trees making up the webpage. Note that the forest of accessibility
+ // trees would include Views and on Chrome OS the whole desktop, so in the
+ // case of a web root, checking if the parent position is the null
+ // position will not work.
+ if (root_position->GetAnchorRole() != ax::mojom::Role::kRootWebArea) {
+ if (web_root_position->IsNullPosition())
+ return root_position; // Original position is not in web contents.
+
+ // The previously saved web root is the shallowest in the forest of
+ // accessibility trees.
+ return web_root_position;
}
- iterator = iterator->CreateParentPosition();
+
+ // Save this web root position and check if it is the shallowest in the
+ // forest of accessibility trees.
+ web_root_position = root_position->Clone();
+ root_position = root_position->CreateParentPosition(move_direction);
}
- return iterator;
+ return web_root_position;
}
// Creates a text position that is in the same anchor as the current
@@ -4046,7 +5003,7 @@ class AXPosition {
// than StopIfAlreadyAtBoundary is not equivalent to the initial position.
//
// Note that using CompareTo with text positions does not take into account
- // position affinity or tree pre-order, two text positions are considered
+ // position affinity or tree pre-order: two text positions are considered
// equivalent if their offsets in the text representation of the entire AXTree
// are the same. As such, using Create[Next|Previous]LeafTextPosition is not
// enough to create adjacent positions, e.g. the end of an anchor and the
@@ -4073,7 +5030,9 @@ class AXPosition {
// Same as the comment above, using AtStartOfAnchor is enough to skip
// empty text nodes that are equivalent to the initial position.
while (text_position->AtStartOfAnchor()) {
- text_position = text_position->CreatePreviousLeafTextPosition()
+ text_position = text_position
+ ->CreatePreviousLeafTextPosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary))
->CreatePositionAtEndOfAnchor();
}
if (!text_position->IsNullPosition())
@@ -4090,7 +5049,8 @@ class AXPosition {
// since those positions are equivalent to both, the previous non-empty
// leaf node's end and the next non-empty leaf node's start.
while (text_position->AtEndOfAnchor()) {
- text_position = text_position->CreateNextLeafTextPosition();
+ text_position = text_position->CreateNextLeafTextPosition(
+ base::BindRepeating(&AbortMoveAtRootBoundary));
}
if (!text_position->IsNullPosition())
++text_position->text_offset_;
@@ -4103,7 +5063,7 @@ class AXPosition {
AXPositionKind kind_;
AXTreeID tree_id_;
- AXNode::AXID anchor_id_;
+ AXNodeID anchor_id_;
// For text positions, |child_index_| is initially set to |-1| and only
// computed on demand. The same with tree positions and |text_offset_|.
@@ -4133,7 +5093,7 @@ class AXPosition {
// Cached members that should be lazily created on first use.
//
- // In the case of a leaf position, the name of its anchor used for
+ // In the case of a leaf position, its inner text (in UTF16 format). Used for
// initializing a grapheme break iterator.
mutable base::string16 name_;
};
diff --git a/chromium/ui/accessibility/ax_range.h b/chromium/ui/accessibility/ax_range.h
index 2d263e1c7ea..0376ee7829d 100644
--- a/chromium/ui/accessibility/ax_range.h
+++ b/chromium/ui/accessibility/ax_range.h
@@ -33,12 +33,12 @@ class AXRangeRectDelegate {
public:
virtual gfx::Rect GetInnerTextRangeBoundsRect(
AXTreeID tree_id,
- AXNode::AXID node_id,
+ AXNodeID node_id,
int start_offset,
int end_offset,
AXOffscreenResult* offscreen_result) = 0;
virtual gfx::Rect GetBoundsRect(AXTreeID tree_id,
- AXNode::AXID node_id,
+ AXNodeID node_id,
AXOffscreenResult* offscreen_result) = 0;
};
diff --git a/chromium/ui/accessibility/ax_range_unittest.cc b/chromium/ui/accessibility/ax_range_unittest.cc
index ea2af606d1d..48ac880e7b0 100644
--- a/chromium/ui/accessibility/ax_range_unittest.cc
+++ b/chromium/ui/accessibility/ax_range_unittest.cc
@@ -28,22 +28,22 @@ using TestPositionRange = AXRange<AXPosition<AXNodePosition, AXNode>>;
namespace {
-constexpr AXNode::AXID ROOT_ID = 1;
-constexpr AXNode::AXID DIV1_ID = 2;
-constexpr AXNode::AXID BUTTON_ID = 3;
-constexpr AXNode::AXID DIV2_ID = 4;
-constexpr AXNode::AXID CHECK_BOX1_ID = 5;
-constexpr AXNode::AXID CHECK_BOX2_ID = 6;
-constexpr AXNode::AXID TEXT_FIELD_ID = 7;
-constexpr AXNode::AXID STATIC_TEXT1_ID = 8;
-constexpr AXNode::AXID INLINE_BOX1_ID = 9;
-constexpr AXNode::AXID LINE_BREAK1_ID = 10;
-constexpr AXNode::AXID STATIC_TEXT2_ID = 11;
-constexpr AXNode::AXID INLINE_BOX2_ID = 12;
-constexpr AXNode::AXID LINE_BREAK2_ID = 13;
-constexpr AXNode::AXID PARAGRAPH_ID = 14;
-constexpr AXNode::AXID STATIC_TEXT3_ID = 15;
-constexpr AXNode::AXID INLINE_BOX3_ID = 16;
+constexpr AXNodeID ROOT_ID = 1;
+constexpr AXNodeID DIV1_ID = 2;
+constexpr AXNodeID BUTTON_ID = 3;
+constexpr AXNodeID DIV2_ID = 4;
+constexpr AXNodeID CHECK_BOX1_ID = 5;
+constexpr AXNodeID CHECK_BOX2_ID = 6;
+constexpr AXNodeID TEXT_FIELD_ID = 7;
+constexpr AXNodeID STATIC_TEXT1_ID = 8;
+constexpr AXNodeID INLINE_BOX1_ID = 9;
+constexpr AXNodeID LINE_BREAK1_ID = 10;
+constexpr AXNodeID STATIC_TEXT2_ID = 11;
+constexpr AXNodeID INLINE_BOX2_ID = 12;
+constexpr AXNodeID LINE_BREAK2_ID = 13;
+constexpr AXNodeID PARAGRAPH_ID = 14;
+constexpr AXNodeID STATIC_TEXT3_ID = 15;
+constexpr AXNodeID INLINE_BOX3_ID = 16;
class TestAXRangeScreenRectDelegate : public AXRangeRectDelegate {
public:
@@ -57,7 +57,7 @@ class TestAXRangeScreenRectDelegate : public AXRangeRectDelegate {
gfx::Rect GetInnerTextRangeBoundsRect(
AXTreeID tree_id,
- AXNode::AXID node_id,
+ AXNodeID node_id,
int start_offset,
int end_offset,
AXOffscreenResult* offscreen_result) override {
@@ -76,7 +76,7 @@ class TestAXRangeScreenRectDelegate : public AXRangeRectDelegate {
}
gfx::Rect GetBoundsRect(AXTreeID tree_id,
- AXNode::AXID node_id,
+ AXNodeID node_id,
AXOffscreenResult* offscreen_result) override {
if (tree_manager_->GetTreeID() != tree_id)
return gfx::Rect();
@@ -170,8 +170,9 @@ void AXRangeTest::SetUp() {
button_.role = ax::mojom::Role::kButton;
button_.SetHasPopup(ax::mojom::HasPopup::kMenu);
- button_.SetName(BUTTON);
+ button_.SetName("Button");
button_.SetNameFrom(ax::mojom::NameFrom::kValue);
+ button_.SetValue("Button");
button_.relative_bounds.bounds = gfx::RectF(20, 20, 100, 30);
button_.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
check_box1_.id);
@@ -323,7 +324,7 @@ TEST_F(AXRangeTest, EqualityOperators) {
GetTreeID(), button_.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
TestPositionInstance test_position2 = AXNodePosition::CreateTextPosition(
- GetTreeID(), line_break1_.id, 1 /* text_offset */,
+ GetTreeID(), text_field_.id, 7 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
TestPositionInstance test_position3 = AXNodePosition::CreateTextPosition(
GetTreeID(), inline_box2_.id, 0 /* text_offset */,
@@ -422,7 +423,7 @@ TEST_F(AXRangeTest, IsCollapsed) {
TestPositionRange tree_to_tree_range(tree_position2->Clone(),
tree_position1->Clone());
- EXPECT_TRUE(tree_to_tree_range.IsCollapsed());
+ EXPECT_FALSE(tree_to_tree_range.IsCollapsed());
// A tree and a text position that essentially point to the same text offset
// are equivalent, even if they are anchored to a different node.
diff --git a/chromium/ui/accessibility/ax_role_properties.cc b/chromium/ui/accessibility/ax_role_properties.cc
index 471248980a2..95bf0582da8 100644
--- a/chromium/ui/accessibility/ax_role_properties.cc
+++ b/chromium/ui/accessibility/ax_role_properties.cc
@@ -5,13 +5,14 @@
#include "ui/accessibility/ax_role_properties.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/accessibility/ax_enums.mojom.h"
namespace ui {
namespace {
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
constexpr bool kExposeLayoutTableAsDataTable = true;
#else
constexpr bool kExposeLayoutTableAsDataTable = false;
@@ -19,6 +20,16 @@ constexpr bool kExposeLayoutTableAsDataTable = false;
} // namespace
+bool CanHaveInlineTextBoxChildren(ax::mojom::Role role) {
+ switch (role) {
+ case ax::mojom::Role::kLineBreak:
+ case ax::mojom::Role::kStaticText:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool HasPresentationalChildren(const ax::mojom::Role role) {
// See http://www.w3.org/TR/core-aam-1.1/#exclude_elements2.
if (IsImage(role))
@@ -204,17 +215,6 @@ bool IsControlOnAndroid(const ax::mojom::Role role, bool isFocusable) {
}
}
-bool IsDocument(const ax::mojom::Role role) {
- switch (role) {
- case ax::mojom::Role::kDocument:
- case ax::mojom::Role::kRootWebArea:
- case ax::mojom::Role::kWebArea:
- return true;
- default:
- return false;
- }
-}
-
bool IsDialog(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kAlertDialog:
@@ -303,6 +303,7 @@ bool IsItemLike(const ax::mojom::Role role) {
case ax::mojom::Role::kRadioButton:
case ax::mojom::Role::kDescriptionListTerm:
case ax::mojom::Role::kTerm:
+ DCHECK(!IsSetLike(role)) << "Role cannot be both item-like and set-like.";
return true;
default:
return false;
@@ -392,6 +393,19 @@ bool IsMenuRelated(const ax::mojom::Role role) {
}
}
+bool IsPlatformDocument(const ax::mojom::Role role) {
+ // "ax::mojom::Role::kDocument" is excluded because it refers to nodes with
+ // the ARIA document role. These are not at the root of an HTML document. They
+ // can appear anywhere within an HTML document, but never at its root.
+ switch (role) {
+ case ax::mojom::Role::kPdfRoot:
+ case ax::mojom::Role::kRootWebArea:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool IsPresentational(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kNone:
@@ -477,6 +491,19 @@ bool IsReadOnlySupported(const ax::mojom::Role role) {
}
}
+bool IsRootLike(ax::mojom::Role role) {
+ if (IsDialog(role) || IsPlatformDocument(role))
+ return true;
+
+ switch (role) {
+ case ax::mojom::Role::kDesktop:
+ case ax::mojom::Role::kWindow:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool IsRowContainer(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kGrid:
@@ -610,8 +637,8 @@ bool IsStructure(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kApplication:
- case ax::mojom::Role::kDocument:
case ax::mojom::Role::kArticle: // Subclass of kDocument.
+ case ax::mojom::Role::kDocument:
case ax::mojom::Role::kPresentational:
case ax::mojom::Role::kRowGroup:
case ax::mojom::Role::kSplitter:
@@ -706,37 +733,46 @@ bool IsText(ax::mojom::Role role) {
}
}
+bool IsComboBox(const ax::mojom::Role role) {
+ switch (role) {
+ case ax::mojom::Role::kComboBoxMenuButton:
+ case ax::mojom::Role::kComboBoxGrouping:
+ case ax::mojom::Role::kTextFieldWithComboBox:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool ShouldHaveReadonlyStateByDefault(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kArticle:
case ax::mojom::Role::kDefinition:
case ax::mojom::Role::kDescriptionList:
case ax::mojom::Role::kDescriptionListTerm:
+ case ax::mojom::Role::kDirectory:
case ax::mojom::Role::kDocument:
case ax::mojom::Role::kGraphicsDocument:
case ax::mojom::Role::kImage:
case ax::mojom::Role::kImageMap:
case ax::mojom::Role::kList:
case ax::mojom::Role::kListItem:
+ case ax::mojom::Role::kPdfRoot:
case ax::mojom::Role::kProgressIndicator:
case ax::mojom::Role::kRootWebArea:
case ax::mojom::Role::kTerm:
case ax::mojom::Role::kTimer:
case ax::mojom::Role::kToolbar:
case ax::mojom::Role::kTooltip:
- case ax::mojom::Role::kWebArea:
return true;
case ax::mojom::Role::kGrid:
- // TODO(aleventhal) this changed between ARIA 1.0 and 1.1,
- // need to determine whether grids/treegrids should really be readonly
- // or editable by default
- break;
-
+ // TODO(aleventhal) this changed between ARIA 1.0 and 1.1.
+ // We need to determine whether grids/treegrids should really be readonly
+ // or editable by default.
default:
- break;
+ return false;
}
- return false;
}
bool SupportsExpandCollapse(const ax::mojom::Role role) {
diff --git a/chromium/ui/accessibility/ax_role_properties.h b/chromium/ui/accessibility/ax_role_properties.h
index c9819bd9002..072c55e401b 100644
--- a/chromium/ui/accessibility/ax_role_properties.h
+++ b/chromium/ui/accessibility/ax_role_properties.h
@@ -15,6 +15,13 @@ namespace ui {
//
// Please keep these functions in alphabetic order.
+// When using these functions in Blink, it's necessary to add the function names
+// to third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py, in
+// order to pass presubmit.
+
+// Returns true for text parents that can have inline text box children.
+AX_BASE_EXPORT bool CanHaveInlineTextBoxChildren(ax::mojom::Role role);
+
// Returns true for object roles that have the attribute "Children
// Presentational: True" as defined in the ARIA Specification.
// https://www.w3.org/TR/wai-aria-1.1/#childrenArePresentational.
@@ -57,9 +64,6 @@ AX_BASE_EXPORT bool IsControl(const ax::mojom::Role role);
AX_BASE_EXPORT bool IsControlOnAndroid(const ax::mojom::Role role,
bool isFocusable);
-// Returns true if the provided role belongs to a document.
-AX_BASE_EXPORT bool IsDocument(const ax::mojom::Role role);
-
// Returns true if the provided role represents a dialog.
AX_BASE_EXPORT bool IsDialog(const ax::mojom::Role role);
@@ -86,7 +90,7 @@ AX_BASE_EXPORT bool IsImage(const ax::mojom::Role role);
AX_BASE_EXPORT bool IsImageOrVideo(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.
+// pos_in_set and set_size values. Roles that are item-like are not set-like.
AX_BASE_EXPORT bool IsItemLike(const ax::mojom::Role role);
// Returns true if the role is a subclass of the ARIA Landmark abstract role.
@@ -108,6 +112,11 @@ AX_BASE_EXPORT bool IsMenuItem(ax::mojom::Role role);
// Returns true if the provided role belongs to a menu or related control.
AX_BASE_EXPORT bool IsMenuRelated(const ax::mojom::Role role);
+// Returns true if the provided role belongs to a node that is at the root of
+// what most accessibility APIs consider to be a document, such as the root of a
+// webpage, an iframe, or a PDF.
+AX_BASE_EXPORT bool IsPlatformDocument(const ax::mojom::Role role);
+
// Returns true if the provided role is presentational in nature, i.e. a node
// whose implicit native role semantics will not be mapped to the accessibility
// API.
@@ -127,6 +136,11 @@ AX_BASE_EXPORT bool IsRangeValueSupported(const ax::mojom::Role role);
// ARIA-1.1+ role='grid' or 'treegrid', and not role='table'.
AX_BASE_EXPORT bool IsReadOnlySupported(const ax::mojom::Role role);
+// Returns true if the provided role is at the root of a window-like container,
+// (AKA a widget in Views terminology), such as the root of the web contents, a
+// window, a dialog or the whole desktop.
+AX_BASE_EXPORT bool IsRootLike(ax::mojom::Role role);
+
// Returns true if the provided role belongs to a widget that can contain a
// table or grid row.
AX_BASE_EXPORT bool IsRowContainer(const ax::mojom::Role role);
@@ -145,7 +159,7 @@ AX_BASE_EXPORT bool IsSelect(const ax::mojom::Role role);
AX_BASE_EXPORT bool IsSelectElement(const ax::mojom::Role role);
// Returns true if the provided role is ordered-set like, specifically if it
-// can hold set_size values.
+// can hold set_size values. Roles that are set-like are not item-like.
AX_BASE_EXPORT bool IsSetLike(const ax::mojom::Role role);
// Returns true if the provided role belongs to a non-interactive list.
@@ -172,6 +186,9 @@ AX_BASE_EXPORT bool IsTableRow(ax::mojom::Role role);
// break, or inline text box.
AX_BASE_EXPORT bool IsText(ax::mojom::Role role);
+// Returns true if the provided role is any of the combobox-related roles.
+AX_BASE_EXPORT bool IsComboBox(ax::mojom::Role role);
+
// Returns true if the node should be read only by default
AX_BASE_EXPORT bool ShouldHaveReadonlyStateByDefault(
const ax::mojom::Role role);
diff --git a/chromium/ui/accessibility/ax_serializable_tree.cc b/chromium/ui/accessibility/ax_serializable_tree.cc
index 4ad26d70d09..7a07effbbe8 100644
--- a/chromium/ui/accessibility/ax_serializable_tree.cc
+++ b/chromium/ui/accessibility/ax_serializable_tree.cc
@@ -16,11 +16,10 @@ namespace ui {
// AXTreeSource abstraction and doesn't need to actually know about
// AXTree directly. Another AXTreeSource is used to abstract the Blink
// accessibility tree.
-class AX_EXPORT AXTreeSourceAdapter
- : public AXTreeSource<const AXNode*, AXNodeData, AXTreeData> {
+class AX_EXPORT AXTreeSourceAdapter : public AXTreeSource<const AXNode*> {
public:
- AXTreeSourceAdapter(AXTree* tree) : tree_(tree) {}
- ~AXTreeSourceAdapter() override {}
+ explicit AXTreeSourceAdapter(AXTree* tree) : tree_(tree) {}
+ ~AXTreeSourceAdapter() override = default;
// AXTreeSource implementation.
bool GetTreeData(AXTreeData* data) const override {
@@ -30,9 +29,9 @@ class AX_EXPORT AXTreeSourceAdapter
AXNode* GetRoot() const override { return tree_->root(); }
- AXNode* GetFromId(int32_t id) const override { return tree_->GetFromId(id); }
+ AXNode* GetFromId(AXNodeID id) const override { return tree_->GetFromId(id); }
- int32_t GetId(const AXNode* node) const override { return node->id(); }
+ AXNodeID GetId(const AXNode* node) const override { return node->id(); }
void GetChildren(const AXNode* node,
std::vector<const AXNode*>* out_children) const override {
@@ -75,8 +74,7 @@ AXSerializableTree::AXSerializableTree(
AXSerializableTree::~AXSerializableTree() {
}
-AXTreeSource<const AXNode*, AXNodeData, AXTreeData>*
-AXSerializableTree::CreateTreeSource() {
+AXTreeSource<const AXNode*>* AXSerializableTree::CreateTreeSource() {
return new AXTreeSourceAdapter(this);
}
diff --git a/chromium/ui/accessibility/ax_serializable_tree.h b/chromium/ui/accessibility/ax_serializable_tree.h
index d8fb9c45161..3764537a336 100644
--- a/chromium/ui/accessibility/ax_serializable_tree.h
+++ b/chromium/ui/accessibility/ax_serializable_tree.h
@@ -19,10 +19,9 @@ class AX_EXPORT AXSerializableTree : public AXTree {
// Create a TreeSource adapter for this tree. The client gets ownership
// of the return value and should delete it when done.
- virtual AXTreeSource<const AXNode*, AXNodeData, AXTreeData>*
- CreateTreeSource();
+ virtual AXTreeSource<const AXNode*>* CreateTreeSource();
};
} // namespace ui
-#endif // UI_ACCESSIBILITY_AX_TREE_H_
+#endif // UI_ACCESSIBILITY_AX_SERIALIZABLE_TREE_H_
diff --git a/chromium/ui/accessibility/ax_table_fuzzer.cc b/chromium/ui/accessibility/ax_table_fuzzer.cc
index b3b42248e8b..9c921c2c991 100644
--- a/chromium/ui/accessibility/ax_table_fuzzer.cc
+++ b/chromium/ui/accessibility/ax_table_fuzzer.cc
@@ -98,19 +98,19 @@ void TestTableAPIs(const ui::AXNode* node) {
// crash. Normally |ids| is an out argument only, but
// there's no reason we shouldn't be able to pass a vector
// that was previously used by another call.
- std::vector<ui::AXNode::AXID> ids;
+ std::vector<ui::AXNodeID> ids;
for (int i = 0; i < 3; i++) {
- std::vector<ui::AXNode::AXID> col_header_node_ids =
+ std::vector<ui::AXNodeID> col_header_node_ids =
node->GetTableColHeaderNodeIds(i);
ids.insert(ids.end(), col_header_node_ids.begin(),
col_header_node_ids.end());
- std::vector<ui::AXNode::AXID> row_header_node_ids =
+ std::vector<ui::AXNodeID> row_header_node_ids =
node->GetTableRowHeaderNodeIds(i);
ids.insert(ids.end(), row_header_node_ids.begin(),
row_header_node_ids.end());
}
- std::vector<ui::AXNode::AXID> unique_cell_ids = node->GetTableUniqueCellIds();
+ std::vector<ui::AXNodeID> unique_cell_ids = node->GetTableUniqueCellIds();
ids.insert(ids.end(), unique_cell_ids.begin(), unique_cell_ids.end());
ignore_result(node->IsTableRow());
@@ -127,11 +127,11 @@ void TestTableAPIs(const ui::AXNode* node) {
ignore_result(node->GetTableCellRowSpan());
ignore_result(node->GetTableCellAriaColIndex());
ignore_result(node->GetTableCellAriaRowIndex());
- std::vector<ui::AXNode::AXID> cell_col_header_node_ids =
+ std::vector<ui::AXNodeID> cell_col_header_node_ids =
node->GetTableCellColHeaderNodeIds();
ids.insert(ids.end(), cell_col_header_node_ids.begin(),
cell_col_header_node_ids.end());
- std::vector<ui::AXNode::AXID> cell_row_header_node_ids =
+ std::vector<ui::AXNodeID> cell_row_header_node_ids =
node->GetTableCellRowHeaderNodeIds();
ids.insert(ids.end(), cell_row_header_node_ids.begin(),
cell_row_header_node_ids.end());
diff --git a/chromium/ui/accessibility/ax_table_info.cc b/chromium/ui/accessibility/ax_table_info.cc
index a861036d688..141d844a317 100644
--- a/chromium/ui/accessibility/ax_table_info.cc
+++ b/chromium/ui/accessibility/ax_table_info.cc
@@ -4,6 +4,7 @@
#include "ui/accessibility/ax_table_info.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "ui/accessibility/ax_constants.mojom.h"
#include "ui/accessibility/ax_enums.mojom.h"
@@ -47,7 +48,7 @@ void FindCellsInRow(AXNode* node, std::vector<AXNode*>* cell_nodes) {
void FindRowsAndThenCells(AXNode* node,
std::vector<AXNode*>* row_node_list,
std::vector<std::vector<AXNode*>>* cell_nodes_per_row,
- int32_t& caption_node_id) {
+ AXNodeID& caption_node_id) {
for (AXNode* child : node->children()) {
if (child->IsIgnored() ||
child->data().role == ax::mojom::Role::kGenericContainer ||
@@ -59,8 +60,9 @@ void FindRowsAndThenCells(AXNode* node,
row_node_list->push_back(child);
cell_nodes_per_row->push_back(std::vector<AXNode*>());
FindCellsInRow(child, &cell_nodes_per_row->back());
- } else if (child->data().role == ax::mojom::Role::kCaption)
+ } else if (child->data().role == ax::mojom::Role::kCaption) {
caption_node_id = child->id();
+ }
}
}
@@ -440,7 +442,7 @@ void AXTableInfo::UpdateExtraMacNodes() {
}
AXNode* AXTableInfo::CreateExtraMacColumnNode(size_t col_index) {
- int32_t id = tree_->GetNextNegativeInternalNodeId();
+ AXNodeID id = tree_->GetNextNegativeInternalNodeId();
size_t index_in_parent = col_index + table_node_->children().size();
int32_t unignored_index_in_parent =
col_index + table_node_->GetUnignoredChildCount();
@@ -456,7 +458,7 @@ AXNode* AXTableInfo::CreateExtraMacColumnNode(size_t col_index) {
}
AXNode* AXTableInfo::CreateExtraMacTableHeaderNode() {
- int32_t id = tree_->GetNextNegativeInternalNodeId();
+ AXNodeID id = tree_->GetNextNegativeInternalNodeId();
size_t index_in_parent = col_count + table_node_->children().size();
int32_t unignored_index_in_parent =
col_count + table_node_->GetUnignoredChildCount();
@@ -488,10 +490,10 @@ void AXTableInfo::UpdateExtraMacColumnNodeAttributes(size_t col_index) {
// Update the list of cells in the column.
data.intlist_attributes.clear();
- std::vector<int32_t> col_nodes;
- int32_t last = 0;
+ std::vector<AXNodeID> col_nodes;
+ AXNodeID last = 0;
for (size_t row_index = 0; row_index < row_count; row_index++) {
- int32_t cell_id = cell_ids[row_index][col_index];
+ AXNodeID cell_id = cell_ids[row_index][col_index];
if (cell_id != 0 && cell_id != last)
col_nodes.push_back(cell_id);
last = cell_id;
@@ -505,7 +507,7 @@ void AXTableInfo::ClearExtraMacNodes() {
for (AXNode* extra_mac_node : extra_mac_nodes) {
for (AXTreeObserver& observer : tree_->observers())
observer.OnNodeWillBeDeleted(tree_, extra_mac_node);
- AXNode::AXID deleted_id = extra_mac_node->id();
+ AXNodeID deleted_id = extra_mac_node->id();
delete extra_mac_node;
for (AXTreeObserver& observer : tree_->observers())
observer.OnNodeDeleted(tree_, deleted_id);
diff --git a/chromium/ui/accessibility/ax_table_info.h b/chromium/ui/accessibility/ax_table_info.h
index 3bfb246263a..d33dcb6959b 100644
--- a/chromium/ui/accessibility/ax_table_info.h
+++ b/chromium/ui/accessibility/ax_table_info.h
@@ -7,11 +7,11 @@
#include <map>
#include <set>
-#include <unordered_map>
#include <vector>
#include "base/optional.h"
#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_node_data.h"
namespace ui {
@@ -23,7 +23,7 @@ class AX_EXPORT AXTableInfo {
public:
struct CellData {
AXNode* cell;
- int32_t cell_id;
+ AXNodeID cell_id;
size_t col_index;
size_t row_index;
size_t col_span;
@@ -56,28 +56,28 @@ class AX_EXPORT AXTableInfo {
size_t col_count = 0;
// List of column header nodes IDs for each column index.
- std::vector<std::vector<int32_t>> col_headers;
+ std::vector<std::vector<AXNodeID>> col_headers;
// List of row header node IDs for each row index.
- std::vector<std::vector<int32_t>> row_headers;
+ std::vector<std::vector<AXNodeID>> row_headers;
// All header cells.
- std::vector<int32_t> all_headers;
+ std::vector<AXNodeID> all_headers;
// The id of the element with the caption tag or ARIA role.
- int32_t caption_id;
+ AXNodeID caption_id;
// 2-D array of [row][column] -> cell node ID.
// This may contain duplicates if there is a rowspan or
// colspan. The entry is empty (zero) only if the cell
// really is missing from the table.
- std::vector<std::vector<int32_t>> cell_ids;
+ std::vector<std::vector<AXNodeID>> cell_ids;
// Array of cell data for every unique cell in the table.
std::vector<CellData> cell_data_vector;
// Set of all unique cell node IDs in the table.
- std::vector<int32_t> unique_cell_ids;
+ std::vector<AXNodeID> unique_cell_ids;
// Extra computed nodes for the accessibility tree for macOS:
// one column node for each table column, followed by one
@@ -85,10 +85,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.
- std::unordered_map<int32_t, size_t> cell_id_to_index;
+ std::map<AXNodeID, size_t> cell_id_to_index;
// Map from each row's node ID to its row index.
- std::unordered_map<int32_t, size_t> row_id_to_index;
+ std::map<AXNodeID, size_t> row_id_to_index;
// List of ax nodes that represent the rows of the table.
std::vector<AXNode*> row_nodes;
@@ -122,4 +122,4 @@ class AX_EXPORT AXTableInfo {
} // namespace ui
-#endif // UI_ACCESSIBILITY_AX_TABLE_INFO
+#endif // UI_ACCESSIBILITY_AX_TABLE_INFO_H_
diff --git a/chromium/ui/accessibility/ax_table_info_unittest.cc b/chromium/ui/accessibility/ax_table_info_unittest.cc
index a3631a6dc86..fc5f07ca114 100644
--- a/chromium/ui/accessibility/ax_table_info_unittest.cc
+++ b/chromium/ui/accessibility/ax_table_info_unittest.cc
@@ -529,7 +529,7 @@ TEST_F(AXTableInfoTest, ExtraMacNodes) {
EXPECT_EQ(2U, table_info->extra_mac_nodes[0]->GetUnignoredIndexInParent());
EXPECT_EQ(0, extra_node_0.GetIntAttribute(
ax::mojom::IntAttribute::kTableColumnIndex));
- std::vector<int32_t> indirect_child_ids;
+ std::vector<AXNodeID> indirect_child_ids;
EXPECT_EQ(true, extra_node_0.GetIntListAttribute(
ax::mojom::IntListAttribute::kIndirectChildIds,
&indirect_child_ids));
@@ -982,7 +982,7 @@ TEST_F(AXTableInfoTest, ExtraMacNodesChanges) {
EXPECT_EQ(3U, table_info->extra_mac_nodes[0]->GetUnignoredIndexInParent());
EXPECT_EQ(0, extra_node_0.GetIntAttribute(
ax::mojom::IntAttribute::kTableColumnIndex));
- std::vector<int32_t> indirect_child_ids;
+ std::vector<AXNodeID> indirect_child_ids;
EXPECT_EQ(true, extra_node_0.GetIntListAttribute(
ax::mojom::IntListAttribute::kIndirectChildIds,
&indirect_child_ids));
@@ -1040,7 +1040,7 @@ TEST_F(AXTableInfoTest, ExtraMacNodesChanges) {
EXPECT_EQ(1U, table_info->extra_mac_nodes[0]->GetUnignoredIndexInParent());
EXPECT_EQ(0, extra_node_0.GetIntAttribute(
ax::mojom::IntAttribute::kTableColumnIndex));
- std::vector<int32_t> indirect_child_ids;
+ std::vector<AXNodeID> indirect_child_ids;
EXPECT_EQ(true, extra_node_0.GetIntListAttribute(
ax::mojom::IntListAttribute::kIndirectChildIds,
&indirect_child_ids));
diff --git a/chromium/ui/accessibility/ax_text_utils.cc b/chromium/ui/accessibility/ax_text_utils.cc
index c48dd616e54..3dbfdb4474e 100644
--- a/chromium/ui/accessibility/ax_text_utils.cc
+++ b/chromium/ui/accessibility/ax_text_utils.cc
@@ -211,4 +211,31 @@ std::vector<int> GetWordEndOffsets(const base::string16& text) {
return word_ends;
}
+std::vector<int> GetSentenceStartOffsets(const base::string16& text) {
+ std::vector<int> sentence_starts;
+ base::i18n::BreakIterator iter(text,
+ base::i18n::BreakIterator::BREAK_SENTENCE);
+ if (!iter.Init())
+ return sentence_starts;
+ // iter.Advance() returns false if we've run past end of the text.
+ while (iter.Advance()) {
+ sentence_starts.push_back(
+ base::checked_cast<int>(iter.prev()) /* start index */);
+ }
+ return sentence_starts;
+}
+
+std::vector<int> GetSentenceEndOffsets(const base::string16& text) {
+ std::vector<int> sentence_ends;
+ base::i18n::BreakIterator iter(text,
+ base::i18n::BreakIterator::BREAK_SENTENCE);
+ if (!iter.Init())
+ return sentence_ends;
+ // iter.Advance() returns false if we've run past end of the text.
+ while (iter.Advance()) {
+ sentence_ends.push_back(
+ base::checked_cast<int>(iter.pos()) /* end index */);
+ }
+ return sentence_ends;
+}
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_text_utils.h b/chromium/ui/accessibility/ax_text_utils.h
index 7e4d0ea1a3e..f8a9552b642 100644
--- a/chromium/ui/accessibility/ax_text_utils.h
+++ b/chromium/ui/accessibility/ax_text_utils.h
@@ -41,6 +41,10 @@ AX_EXPORT std::vector<int> GetWordStartOffsets(const base::string16& text);
// Returns indices of all word ends in |text|.
AX_EXPORT std::vector<int> GetWordEndOffsets(const base::string16& text);
+// Returns indices of all sentence starts in |text|.
+AX_EXPORT std::vector<int> GetSentenceStartOffsets(const base::string16& text);
+// Returns indices of all sentence ends in |text|.
+AX_EXPORT std::vector<int> GetSentenceEndOffsets(const base::string16& text);
} // namespace ui
#endif // UI_ACCESSIBILITY_AX_TEXT_UTILS_H_
diff --git a/chromium/ui/accessibility/ax_text_utils_unittest.cc b/chromium/ui/accessibility/ax_text_utils_unittest.cc
index 39d3f2b7702..9b8613ffb2e 100644
--- a/chromium/ui/accessibility/ax_text_utils_unittest.cc
+++ b/chromium/ui/accessibility/ax_text_utils_unittest.cc
@@ -290,4 +290,26 @@ TEST(AXTextUtils, GetWordStartOffsetsMalformedInputTest) {
testing::ElementsAre(2, 9, 16, 27, 35, 43));
}
+TEST(AXTextUtils, GetSentenceStartOffsetsBasicTest) {
+ const base::string16 text = base::UTF8ToUTF16(
+ "This is the first sentence. This is the second sentence");
+ EXPECT_THAT(GetSentenceStartOffsets(text), testing::ElementsAre(0, 28));
+}
+
+TEST(AXTextUtils, GetSentenceEndOffsetsBasicTest) {
+ const base::string16 text = base::UTF8ToUTF16(
+ "This is the first sentence. This is the second sentence");
+ EXPECT_THAT(GetSentenceEndOffsets(text), testing::ElementsAre(28, 55));
+}
+
+TEST(AXTextUtils, GetSentenceStartOffsetsMalformedInputTest) {
+ const base::string16 text = base::UTF8ToUTF16("is the first ... second.");
+ EXPECT_THAT(GetSentenceStartOffsets(text), testing::ElementsAre(0));
+}
+
+TEST(AXTextUtils, GetSentenceEndOffsetsMalformedInputTest) {
+ const base::string16 text = base::UTF8ToUTF16("is the first ... second.");
+ EXPECT_THAT(GetSentenceEndOffsets(text), testing::ElementsAre(24));
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree.cc b/chromium/ui/accessibility/ax_tree.cc
index 28e1a7a56dc..d8594752bec 100644
--- a/chromium/ui/accessibility/ax_tree.cc
+++ b/chromium/ui/accessibility/ax_tree.cc
@@ -5,18 +5,18 @@
#include "ui/accessibility/ax_tree.h"
#include <stddef.h>
-
#include <algorithm>
#include <numeric>
#include <utility>
#include "base/auto_reset.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "ui/accessibility/accessibility_switches.h"
#include "ui/accessibility/ax_enums.mojom.h"
@@ -161,7 +161,7 @@ struct PendingStructureChanges {
create_node_count(0),
node_exists(!!node),
parent_node_id((node && node->parent())
- ? base::Optional<AXNode::AXID>{node->parent()->id()}
+ ? base::Optional<AXNodeID>{node->parent()->id()}
: base::nullopt),
last_known_data(node ? &node->data() : nullptr) {}
@@ -231,7 +231,7 @@ struct PendingStructureChanges {
// Keep track of the parent id for this node as of the last pending
// update that was processed.
- base::Optional<AXNode::AXID> parent_node_id;
+ base::Optional<AXNodeID> parent_node_id;
// Keep track of the last known node data for this node.
// This will be null either when a node does not exist in the tree, or
@@ -267,7 +267,7 @@ struct AXTreeUpdateState {
}
// Returns whether this update creates a node marked by |node_id|.
- bool IsCreatedNode(AXNode::AXID node_id) const {
+ bool IsCreatedNode(AXNodeID node_id) const {
return base::Contains(new_node_ids, node_id);
}
@@ -296,7 +296,7 @@ struct AXTreeUpdateState {
// Returns true if the node should exist in the tree but doesn't have
// any node data yet.
- bool DoesPendingNodeRequireInit(AXNode::AXID node_id) const {
+ bool DoesPendingNodeRequireInit(AXNodeID node_id) const {
DCHECK_EQ(AXTreePendingStructureStatus::kComputing, pending_update_status)
<< "This method should only be called while computing pending changes, "
"before updates are made to the tree.";
@@ -305,7 +305,7 @@ struct AXTreeUpdateState {
}
// Returns the parent node id for the pending node.
- base::Optional<AXNode::AXID> GetParentIdForPendingNode(AXNode::AXID node_id) {
+ base::Optional<AXNodeID> GetParentIdForPendingNode(AXNodeID node_id) {
DCHECK_EQ(AXTreePendingStructureStatus::kComputing, pending_update_status)
<< "This method should only be called while computing pending changes, "
"before updates are made to the tree.";
@@ -316,7 +316,7 @@ struct AXTreeUpdateState {
}
// Returns true if this node should exist in the tree.
- bool ShouldPendingNodeExistInTree(AXNode::AXID node_id) {
+ bool ShouldPendingNodeExistInTree(AXNodeID node_id) {
DCHECK_EQ(AXTreePendingStructureStatus::kComputing, pending_update_status)
<< "This method should only be called while computing pending changes, "
"before updates are made to the tree.";
@@ -324,7 +324,7 @@ struct AXTreeUpdateState {
}
// Returns the last known node data for a pending node.
- const AXNodeData& GetLastKnownPendingNodeData(AXNode::AXID node_id) const {
+ const AXNodeData& GetLastKnownPendingNodeData(AXNodeID node_id) const {
DCHECK_EQ(AXTreePendingStructureStatus::kComputing, pending_update_status)
<< "This method should only be called while computing pending changes, "
"before updates are made to the tree.";
@@ -335,7 +335,7 @@ struct AXTreeUpdateState {
}
// Clear the last known pending data for |node_id|.
- void ClearLastKnownPendingNodeData(AXNode::AXID node_id) {
+ void ClearLastKnownPendingNodeData(AXNodeID node_id) {
DCHECK_EQ(AXTreePendingStructureStatus::kComputing, pending_update_status)
<< "This method should only be called while computing pending changes, "
"before updates are made to the tree.";
@@ -353,7 +353,7 @@ struct AXTreeUpdateState {
// Returns the number of times the update is expected to destroy a
// subtree rooted at |node_id|.
- int32_t GetPendingDestroySubtreeCount(AXNode::AXID node_id) const {
+ int32_t GetPendingDestroySubtreeCount(AXNodeID node_id) const {
DCHECK_EQ(AXTreePendingStructureStatus::kComplete, pending_update_status)
<< "This method should not be called before pending changes have "
"finished computing.";
@@ -365,7 +365,7 @@ struct AXTreeUpdateState {
// Increments the number of times the update is expected to
// destroy a subtree rooted at |node_id|.
// Returns true on success, false on failure when the node will not exist.
- bool IncrementPendingDestroySubtreeCount(AXNode::AXID node_id) {
+ bool IncrementPendingDestroySubtreeCount(AXNodeID node_id) {
DCHECK_EQ(AXTreePendingStructureStatus::kComputing, pending_update_status)
<< "This method should only be called while computing pending changes, "
"before updates are made to the tree.";
@@ -379,7 +379,7 @@ struct AXTreeUpdateState {
// Decrements the number of times the update is expected to
// destroy a subtree rooted at |node_id|.
- void DecrementPendingDestroySubtreeCount(AXNode::AXID node_id) {
+ void DecrementPendingDestroySubtreeCount(AXNodeID node_id) {
DCHECK_EQ(AXTreePendingStructureStatus::kComplete, pending_update_status)
<< "This method should not be called before pending changes have "
"finished computing.";
@@ -391,7 +391,7 @@ struct AXTreeUpdateState {
// Returns the number of times the update is expected to destroy
// a node with |node_id|.
- int32_t GetPendingDestroyNodeCount(AXNode::AXID node_id) const {
+ int32_t GetPendingDestroyNodeCount(AXNodeID node_id) const {
DCHECK_EQ(AXTreePendingStructureStatus::kComplete, pending_update_status)
<< "This method should not be called before pending changes have "
"finished computing.";
@@ -403,7 +403,7 @@ struct AXTreeUpdateState {
// Increments the number of times the update is expected to
// destroy a node with |node_id|.
// Returns true on success, false on failure when the node will not exist.
- bool IncrementPendingDestroyNodeCount(AXNode::AXID node_id) {
+ bool IncrementPendingDestroyNodeCount(AXNodeID node_id) {
DCHECK_EQ(AXTreePendingStructureStatus::kComputing, pending_update_status)
<< "This method should only be called while computing pending changes, "
"before updates are made to the tree.";
@@ -422,7 +422,7 @@ struct AXTreeUpdateState {
// Decrements the number of times the update is expected to
// destroy a node with |node_id|.
- void DecrementPendingDestroyNodeCount(AXNode::AXID node_id) {
+ void DecrementPendingDestroyNodeCount(AXNodeID node_id) {
DCHECK_EQ(AXTreePendingStructureStatus::kComplete, pending_update_status)
<< "This method should not be called before pending changes have "
"finished computing.";
@@ -434,7 +434,7 @@ struct AXTreeUpdateState {
// Returns the number of times the update is expected to create
// a node with |node_id|.
- int32_t GetPendingCreateNodeCount(AXNode::AXID node_id) const {
+ int32_t GetPendingCreateNodeCount(AXNodeID node_id) const {
DCHECK_EQ(AXTreePendingStructureStatus::kComplete, pending_update_status)
<< "This method should not be called before pending changes have "
"finished computing.";
@@ -447,8 +447,8 @@ struct AXTreeUpdateState {
// create a node with |node_id|.
// Returns true on success, false on failure when the node will already exist.
bool IncrementPendingCreateNodeCount(
- AXNode::AXID node_id,
- base::Optional<AXNode::AXID> parent_node_id) {
+ AXNodeID node_id,
+ base::Optional<AXNodeID> parent_node_id) {
DCHECK_EQ(AXTreePendingStructureStatus::kComputing, pending_update_status)
<< "This method should only be called while computing pending changes, "
"before updates are made to the tree.";
@@ -464,7 +464,7 @@ struct AXTreeUpdateState {
// Decrements the number of times the update is expected to
// create a node with |node_id|.
- void DecrementPendingCreateNodeCount(AXNode::AXID node_id) {
+ void DecrementPendingCreateNodeCount(AXNodeID node_id) {
DCHECK_EQ(AXTreePendingStructureStatus::kComplete, pending_update_status)
<< "This method should not be called before pending changes have "
"finished computing.";
@@ -476,17 +476,17 @@ struct AXTreeUpdateState {
// Returns whether this update must invalidate the unignored cached
// values for |node_id|.
- bool InvalidatesUnignoredCachedValues(AXNode::AXID node_id) {
+ bool InvalidatesUnignoredCachedValues(AXNodeID node_id) {
return base::Contains(invalidate_unignored_cached_values_ids, node_id);
}
// Adds the parent of |node_id| to the list of nodes to invalidate unignored
// cached values.
- void InvalidateParentNodeUnignoredCacheValues(AXNode::AXID node_id) {
+ void InvalidateParentNodeUnignoredCacheValues(AXNodeID node_id) {
DCHECK_EQ(AXTreePendingStructureStatus::kComputing, pending_update_status)
<< "This method should only be called while computing pending changes, "
"before updates are made to the tree.";
- base::Optional<AXNode::AXID> parent_node_id =
+ base::Optional<AXNodeID> parent_node_id =
GetParentIdForPendingNode(node_id);
if (parent_node_id) {
invalidate_unignored_cached_values_ids.insert(*parent_node_id);
@@ -499,7 +499,7 @@ struct AXTreeUpdateState {
// Keeps track of the root node id when calculating what changes will occur
// during an update before the update applies changes.
- base::Optional<AXNode::AXID> pending_root_id;
+ base::Optional<AXNodeID> pending_root_id;
// Keeps track of whether the root node will need to be created as a new node.
// This may occur either when the root node does not exist before applying
@@ -511,47 +511,46 @@ struct AXTreeUpdateState {
// 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::AXID> pending_nodes;
+ std::set<AXNodeID> pending_nodes;
// Keeps track of nodes whose cached unignored child count, or unignored
// index in parent may have changed, and must be updated.
- std::set<AXNode::AXID> invalidate_unignored_cached_values_ids;
+ std::set<AXNodeID> invalidate_unignored_cached_values_ids;
// Keeps track of nodes that have changed their node data.
- std::set<AXNode::AXID> node_data_changed_ids;
+ std::set<AXNodeID> node_data_changed_ids;
// Keeps track of new nodes created during this update.
- std::set<AXNode::AXID> new_node_ids;
+ std::set<AXNodeID> new_node_ids;
// Keeps track of any nodes removed. Nodes are removed when their AXID no
// longer exist in the parent |child_ids| list, or the node is part of to the
// subtree of the AXID that was explicitally cleared with |node_id_to_clear|.
// Used to identify re-parented nodes. A re-parented occurs when any AXID
// is first removed from the tree then added to the tree again.
- std::set<AXNode::AXID> removed_node_ids;
+ std::set<AXNodeID> removed_node_ids;
// Maps between a node id and its pending update information.
- std::map<AXNode::AXID, std::unique_ptr<PendingStructureChanges>>
+ std::map<AXNodeID, std::unique_ptr<PendingStructureChanges>>
node_id_to_pending_data;
// Maps between a node id and the data it owned before being updated.
// We need to keep this around in order to correctly fire post-update events.
- std::map<AXNode::AXID, AXNodeData> old_node_id_to_data;
+ std::map<AXNodeID, AXNodeData> old_node_id_to_data;
// Optional copy of the old tree data, only populated when the tree
// data has changed.
base::Optional<AXTreeData> old_tree_data;
private:
- PendingStructureChanges* GetPendingStructureChanges(
- AXNode::AXID node_id) const {
+ PendingStructureChanges* GetPendingStructureChanges(AXNodeID node_id) const {
auto iter = node_id_to_pending_data.find(node_id);
return (iter != node_id_to_pending_data.cend()) ? iter->second.get()
: nullptr;
}
PendingStructureChanges* GetOrCreatePendingStructureChanges(
- AXNode::AXID node_id) {
+ AXNodeID node_id) {
auto iter = node_id_to_pending_data.find(node_id);
if (iter == node_id_to_pending_data.cend()) {
const AXNode* node = tree.GetFromId(node_id);
@@ -642,10 +641,10 @@ struct AXTree::OrderedSetItemsMap {
AXTree::AXTree() {
AXNodeData root;
- root.id = AXNode::kInvalidAXID;
+ root.id = kInvalidAXNodeID;
AXTreeUpdate initial_state;
- initial_state.root_id = AXNode::kInvalidAXID;
+ initial_state.root_id = kInvalidAXNodeID;
initial_state.nodes.push_back(root);
CHECK(Unserialize(initial_state)) << error();
// TODO(chrishall): should language_detection_manager be a member or pointer?
@@ -683,7 +682,11 @@ AXTreeID AXTree::GetAXTreeID() const {
return data().tree_id;
}
-AXNode* AXTree::GetFromId(int32_t id) const {
+const AXTreeData& AXTree::data() const {
+ return data_;
+}
+
+AXNode* AXTree::GetFromId(AXNodeID id) const {
auto iter = id_map_.find(id);
return iter != id_map_.end() ? iter->second : nullptr;
}
@@ -877,8 +880,8 @@ gfx::RectF AXTree::GetTreeBounds(const AXNode* node,
return RelativeToTreeBounds(node, gfx::RectF(), offscreen, clip_bounds);
}
-std::set<int32_t> AXTree::GetReverseRelations(ax::mojom::IntAttribute attr,
- int32_t dst_id) const {
+std::set<AXNodeID> AXTree::GetReverseRelations(ax::mojom::IntAttribute attr,
+ AXNodeID dst_id) const {
DCHECK(IsNodeIdIntAttribute(attr));
// Conceptually, this is the "const" version of:
@@ -889,11 +892,11 @@ std::set<int32_t> AXTree::GetReverseRelations(ax::mojom::IntAttribute attr,
if (result != attr_relations->second.end())
return result->second;
}
- return std::set<int32_t>();
+ return std::set<AXNodeID>();
}
-std::set<int32_t> AXTree::GetReverseRelations(ax::mojom::IntListAttribute attr,
- int32_t dst_id) const {
+std::set<AXNodeID> AXTree::GetReverseRelations(ax::mojom::IntListAttribute attr,
+ AXNodeID dst_id) const {
DCHECK(IsNodeIdIntListAttribute(attr));
// Conceptually, this is the "const" version of:
@@ -904,17 +907,17 @@ std::set<int32_t> AXTree::GetReverseRelations(ax::mojom::IntListAttribute attr,
if (result != attr_relations->second.end())
return result->second;
}
- return std::set<int32_t>();
+ return std::set<AXNodeID>();
}
-std::set<int32_t> AXTree::GetNodeIdsForChildTreeId(
+std::set<AXNodeID> AXTree::GetNodeIdsForChildTreeId(
AXTreeID child_tree_id) const {
// Conceptually, this is the "const" version of:
// return child_tree_id_reverse_map_[child_tree_id];
const auto& result = child_tree_id_reverse_map_.find(child_tree_id);
if (result != child_tree_id_reverse_map_.end())
return result->second;
- return std::set<int32_t>();
+ return std::set<AXNodeID>();
}
const std::set<AXTreeID> AXTree::GetAllChildTreeIds() const {
@@ -931,7 +934,7 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
&event_intents_));
AXTreeUpdateState update_state(*this);
- const AXNode::AXID old_root_id = root_ ? root_->id() : AXNode::kInvalidAXID;
+ const AXNodeID old_root_id = root_ ? root_->id() : kInvalidAXNodeID;
// Accumulates the work that will be required to update the AXTree.
// This allows us to notify observers of structure changes when the
@@ -942,7 +945,7 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
// Notify observers of subtrees and nodes that are about to be destroyed or
// reparented, this must be done before applying any updates to the tree.
for (auto&& pair : update_state.node_id_to_pending_data) {
- const AXNode::AXID node_id = pair.first;
+ const AXNodeID node_id = pair.first;
const std::unique_ptr<PendingStructureChanges>& data = pair.second;
if (data->DoesNodeExpectSubtreeOrNodeWillBeDestroyed()) {
if (AXNode* node = GetFromId(node_id)) {
@@ -959,7 +962,7 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
// This is iterating in reverse order so that we only notify once per node id,
// and that we only notify the initial node data against the final node data,
// unless the node is a new root.
- std::set<int32_t> notified_node_data_will_change;
+ std::set<AXNodeID> notified_node_data_will_change;
for (size_t i = update.nodes.size(); i-- > 0;) {
const AXNodeData& new_data = update.nodes[i];
const bool is_new_root =
@@ -983,8 +986,17 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
// Otherwise if the root is being replaced, update.root_id should hold the ID
// of the new root.
bool root_updated = false;
- if (update.node_id_to_clear != AXNode::kInvalidAXID) {
- if (AXNode* cleared_node = GetFromId(update.node_id_to_clear)) {
+ if (update.node_id_to_clear != kInvalidAXNodeID) {
+ // If the incoming tree was initialized with a root with an id != 1, the
+ // update won't match the tree created by CreateEmptyDocument In this
+ // case, the update won't be able to set the right node_id_to_clear.
+ // If node_id_to_clear was set and the update's root_id doesn't match the
+ // old_root_id, we assume that the update meant to replace the root.
+ int node_id_to_clear = update.node_id_to_clear;
+ if (!GetFromId(node_id_to_clear) && update.root_id == node_id_to_clear &&
+ update.root_id != old_root_id && root_)
+ node_id_to_clear = old_root_id;
+ if (AXNode* cleared_node = GetFromId(node_id_to_clear)) {
DCHECK(root_);
if (cleared_node == root_) {
// Only destroy the root if the root was replaced and not if it's simply
@@ -1033,6 +1045,8 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
}
if (!root_) {
+ ACCESSIBILITY_TREE_UNSERIALIZE_ERROR_HISTOGRAM(
+ AXTreeUnserializeError::kNoRoot);
RecordError("Tree has no root.");
return false;
}
@@ -1044,9 +1058,9 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
// and invalidate their table info if so. We have to walk up the
// ancestry of every node that was updated potentially, so keep track of
// ids that were checked to eliminate duplicate work.
- std::set<int32_t> table_ids_checked;
- for (size_t i = 0; i < update.nodes.size(); ++i) {
- AXNode* node = GetFromId(update.nodes[i].id);
+ std::set<AXNodeID> table_ids_checked;
+ for (const AXNodeData& node_data : update.nodes) {
+ AXNode* node = GetFromId(node_data.id);
while (node) {
if (table_ids_checked.find(node->id()) != table_ids_checked.end())
break;
@@ -1064,7 +1078,7 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
std::vector<AXTreeObserver::Change> changes;
changes.reserve(update.nodes.size());
- std::set<AXNode::AXID> visited_observer_changes;
+ std::set<AXNodeID> visited_observer_changes;
for (size_t i = 0; i < update.nodes.size(); ++i) {
AXNode* node = GetFromId(update.nodes[i].id);
if (!node || !visited_observer_changes.emplace(update.nodes[i].id).second)
@@ -1104,9 +1118,8 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
// Update the unignored cached values as necessary, ensuring that we only
// update once for each unignored node.
// If the node is ignored, we must update from an unignored ancestor.
- std::set<AXNode::AXID> updated_unignored_cached_values_ids;
- for (AXNode::AXID node_id :
- update_state.invalidate_unignored_cached_values_ids) {
+ std::set<AXNodeID> updated_unignored_cached_values_ids;
+ for (AXNodeID node_id : update_state.invalidate_unignored_cached_values_ids) {
AXNode* node = GetFromId(node_id);
while (node && node->data().IsIgnored())
node = node->parent();
@@ -1127,19 +1140,19 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
// Now that the unignored cached values are up to date, update observers to
// the nodes that were deleted from the tree but not reparented.
- for (AXNode::AXID node_id : update_state.removed_node_ids) {
+ for (AXNodeID node_id : update_state.removed_node_ids) {
if (!update_state.IsCreatedNode(node_id))
NotifyNodeHasBeenDeleted(node_id);
}
// Now that the unignored cached values are up to date, update observers to
// new nodes in the tree.
- for (AXNode::AXID node_id : update_state.new_node_ids)
+ for (AXNodeID node_id : update_state.new_node_ids)
NotifyNodeHasBeenReparentedOrCreated(GetFromId(node_id), &update_state);
// Now that the unignored cached values are up to date, update observers to
// node changes.
- for (AXNode::AXID node_data_changed_id : update_state.node_data_changed_ids) {
+ for (AXNodeID node_data_changed_id : update_state.node_data_changed_ids) {
AXNode* node = GetFromId(node_data_changed_id);
DCHECK(node);
@@ -1205,7 +1218,7 @@ std::string AXTree::ToString() const {
}
AXNode* AXTree::CreateNode(AXNode* parent,
- AXNode::AXID id,
+ AXNodeID id,
size_t index_in_parent,
AXTreeUpdateState* update_state) {
DCHECK(GetTreeUpdateInProgressState());
@@ -1235,16 +1248,16 @@ bool AXTree::ComputePendingChanges(const AXTreeUpdate& update,
update_state->pending_update_status =
AXTreePendingStructureStatus::kComputing;
- base::AutoReset<base::Optional<AXNode::AXID>> pending_root_id_resetter(
+ base::AutoReset<base::Optional<AXNodeID>> pending_root_id_resetter(
&update_state->pending_root_id,
- root_ ? base::Optional<AXNode::AXID>{root_->id()} : base::nullopt);
+ root_ ? base::Optional<AXNodeID>{root_->id()} : base::nullopt);
// We distinguish between updating the root, e.g. changing its children or
// some of its attributes, or replacing the root completely. If the root is
// being updated, update.node_id_to_clear should hold the current root's ID.
// Otherwise if the root is being replaced, update.root_id should hold the ID
// of the new root.
- if (update.node_id_to_clear != AXNode::kInvalidAXID) {
+ if (update.node_id_to_clear != kInvalidAXNodeID) {
if (AXNode* cleared_node = GetFromId(update.node_id_to_clear)) {
DCHECK(root_);
if (cleared_node == root_ &&
@@ -1304,6 +1317,8 @@ bool AXTree::ComputePendingChangesToNode(const AXNodeData& new_data,
// is the new root and it can be created.
if (!update_state->ShouldPendingNodeExistInTree(new_data.id)) {
if (!is_new_root) {
+ ACCESSIBILITY_TREE_UNSERIALIZE_ERROR_HISTOGRAM(
+ AXTreeUnserializeError::kNotInTree);
RecordError(base::StringPrintf(
"%d will not be in the tree and is not the new root", new_data.id));
return false;
@@ -1313,6 +1328,8 @@ bool AXTree::ComputePendingChangesToNode(const AXNodeData& new_data,
// pending for creation, then it must be a duplicate entry in the tree.
if (!update_state->IncrementPendingCreateNodeCount(new_data.id,
base::nullopt)) {
+ ACCESSIBILITY_TREE_UNSERIALIZE_ERROR_HISTOGRAM(
+ AXTreeUnserializeError::kCreationPending);
RecordError(base::StringPrintf(
"Node %d is already pending for creation, cannot be the new root",
new_data.id));
@@ -1326,9 +1343,11 @@ bool AXTree::ComputePendingChangesToNode(const AXNodeData& new_data,
// Create a set of new child ids so we can use it to find the nodes that
// have been added and removed. Returns false if a duplicate is found.
- std::set<AXNode::AXID> new_child_id_set;
- for (AXNode::AXID new_child_id : new_data.child_ids) {
+ std::set<AXNodeID> new_child_id_set;
+ for (AXNodeID new_child_id : new_data.child_ids) {
if (base::Contains(new_child_id_set, new_child_id)) {
+ ACCESSIBILITY_TREE_UNSERIALIZE_ERROR_HISTOGRAM(
+ AXTreeUnserializeError::kDuplicateChild);
RecordError(base::StringPrintf("Node %d has duplicate child id %d",
new_data.id, new_child_id));
return false;
@@ -1346,12 +1365,14 @@ bool AXTree::ComputePendingChangesToNode(const AXNodeData& new_data,
// the last-known parent's unignored cache needs to be updated.
update_state->InvalidateParentNodeUnignoredCacheValues(new_data.id);
- for (AXNode::AXID child_id : new_child_id_set) {
+ for (AXNodeID child_id : new_child_id_set) {
// If a |child_id| is already pending for creation, then it must be a
// duplicate entry in the tree.
update_state->invalidate_unignored_cached_values_ids.insert(child_id);
if (!update_state->IncrementPendingCreateNodeCount(child_id,
new_data.id)) {
+ ACCESSIBILITY_TREE_UNSERIALIZE_ERROR_HISTOGRAM(
+ AXTreeUnserializeError::kCreationPendingForChild);
RecordError(base::StringPrintf(
"Node %d is already pending for creation, cannot be a new child",
child_id));
@@ -1368,10 +1389,10 @@ bool AXTree::ComputePendingChangesToNode(const AXNodeData& new_data,
// Create a set of old child ids so we can use it to find the nodes that
// have been added and removed.
- std::set<AXNode::AXID> old_child_id_set(old_data.child_ids.cbegin(),
- old_data.child_ids.cend());
+ std::set<AXNodeID> old_child_id_set(old_data.child_ids.cbegin(),
+ old_data.child_ids.cend());
- std::vector<AXNode::AXID> create_or_destroy_ids;
+ std::vector<AXNodeID> create_or_destroy_ids;
std::set_symmetric_difference(
old_child_id_set.cbegin(), old_child_id_set.cend(),
new_child_id_set.cbegin(), new_child_id_set.cend(),
@@ -1387,13 +1408,15 @@ bool AXTree::ComputePendingChangesToNode(const AXNodeData& new_data,
update_state->InvalidateParentNodeUnignoredCacheValues(new_data.id);
}
- for (AXNode::AXID child_id : create_or_destroy_ids) {
+ for (AXNodeID child_id : create_or_destroy_ids) {
if (base::Contains(new_child_id_set, child_id)) {
// This is a serious error - nodes should never be reparented without
// first being removed from the tree. If a node exists in the tree already
// then adding it to a new parent would mean stealing the node from its
// old parent which hadn't been updated to reflect the change.
if (update_state->ShouldPendingNodeExistInTree(child_id)) {
+ ACCESSIBILITY_TREE_UNSERIALIZE_ERROR_HISTOGRAM(
+ AXTreeUnserializeError::kReparent);
RecordError(base::StringPrintf(
"Node %d is not marked for destruction, would be reparented to %d",
child_id, new_data.id));
@@ -1405,6 +1428,8 @@ bool AXTree::ComputePendingChangesToNode(const AXNodeData& new_data,
update_state->invalidate_unignored_cached_values_ids.insert(child_id);
if (!update_state->IncrementPendingCreateNodeCount(child_id,
new_data.id)) {
+ ACCESSIBILITY_TREE_UNSERIALIZE_ERROR_HISTOGRAM(
+ AXTreeUnserializeError::kCreationPendingForChild);
RecordError(base::StringPrintf(
"Node %d is already pending for creation, cannot be a new child",
child_id));
@@ -1444,6 +1469,8 @@ bool AXTree::UpdateNode(const AXNodeData& src,
node->SetData(src);
} else {
if (!is_new_root) {
+ ACCESSIBILITY_TREE_UNSERIALIZE_ERROR_HISTOGRAM(
+ AXTreeUnserializeError::kNotInTree);
RecordError(base::StringPrintf(
"%d is not in the tree and not the new root", src.id));
return false;
@@ -1488,7 +1515,7 @@ void AXTree::NotifySubtreeWillBeReparentedOrDeleted(
AXNode* node,
const AXTreeUpdateState* update_state) {
DCHECK(!GetTreeUpdateInProgressState());
- if (node->id() == AXNode::kInvalidAXID)
+ if (node->id() == kInvalidAXNodeID)
return;
for (AXTreeObserver& observer : observers_) {
@@ -1505,8 +1532,8 @@ void AXTree::NotifyNodeWillBeReparentedOrDeleted(
const AXTreeUpdateState* update_state) {
DCHECK(!GetTreeUpdateInProgressState());
- AXNode::AXID id = node->id();
- if (id == AXNode::kInvalidAXID)
+ AXNodeID id = node->id();
+ if (id == kInvalidAXNodeID)
return;
table_info_map_.erase(id);
@@ -1525,7 +1552,7 @@ void AXTree::NotifyNodeWillBeReparentedOrDeleted(
void AXTree::RecursivelyNotifyNodeDeletedForTreeTeardown(AXNode* node) {
DCHECK(!GetTreeUpdateInProgressState());
- if (node->id() == AXNode::kInvalidAXID)
+ if (node->id() == kInvalidAXNodeID)
return;
for (AXTreeObserver& observer : observers_)
@@ -1534,10 +1561,10 @@ void AXTree::RecursivelyNotifyNodeDeletedForTreeTeardown(AXNode* node) {
RecursivelyNotifyNodeDeletedForTreeTeardown(child);
}
-void AXTree::NotifyNodeHasBeenDeleted(AXNode::AXID node_id) {
+void AXTree::NotifyNodeHasBeenDeleted(AXNodeID node_id) {
DCHECK(!GetTreeUpdateInProgressState());
- if (node_id == AXNode::kInvalidAXID)
+ if (node_id == kInvalidAXNodeID)
return;
for (AXTreeObserver& observer : observers_)
@@ -1548,7 +1575,7 @@ void AXTree::NotifyNodeHasBeenReparentedOrCreated(
AXNode* node,
const AXTreeUpdateState* update_state) {
DCHECK(!GetTreeUpdateInProgressState());
- if (node->id() == AXNode::kInvalidAXID)
+ if (node->id() == kInvalidAXNodeID)
return;
for (AXTreeObserver& observer : observers_) {
@@ -1563,7 +1590,7 @@ void AXTree::NotifyNodeHasBeenReparentedOrCreated(
void AXTree::NotifyNodeDataWillChange(const AXNodeData& old_data,
const AXNodeData& new_data) {
DCHECK(!GetTreeUpdateInProgressState());
- if (new_data.id == AXNode::kInvalidAXID)
+ if (new_data.id == kInvalidAXNodeID)
return;
for (AXTreeObserver& observer : observers_)
@@ -1574,7 +1601,7 @@ void AXTree::NotifyNodeDataHasBeenChanged(AXNode* node,
const AXNodeData& old_data,
const AXNodeData& new_data) {
DCHECK(!GetTreeUpdateInProgressState());
- if (node->id() == AXNode::kInvalidAXID)
+ if (node->id() == kInvalidAXNodeID)
return;
for (AXTreeObserver& observer : observers_)
@@ -1692,19 +1719,19 @@ void AXTree::UpdateReverseRelations(AXNode* node, const AXNodeData& new_data) {
return;
auto& map = intlist_reverse_relations_[attr];
- for (int32_t old_id : old_idlist) {
+ for (AXNodeID old_id : old_idlist) {
if (map.find(old_id) != map.end()) {
map[old_id].erase(id);
if (map[old_id].empty())
map.erase(old_id);
}
}
- for (int32_t new_id : new_idlist)
+ for (AXNodeID new_id : new_idlist)
intlist_reverse_relations_[attr][new_id].insert(id);
};
CallIfAttributeValuesChanged(old_data.intlist_attributes,
new_data.intlist_attributes,
- std::vector<int32_t>(), intlist_callback);
+ std::vector<AXNodeID>(), intlist_callback);
auto string_callback = [this, id](ax::mojom::StringAttribute attr,
const std::string& old_string,
@@ -1737,8 +1764,10 @@ void AXTree::UpdateReverseRelations(AXNode* node, const AXNodeData& new_data) {
bool AXTree::ValidatePendingChangesComplete(
const AXTreeUpdateState& update_state) {
if (!update_state.pending_nodes.empty()) {
+ ACCESSIBILITY_TREE_UNSERIALIZE_ERROR_HISTOGRAM(
+ AXTreeUnserializeError::kPendingNodes);
std::string error = "Nodes left pending by the update:";
- for (const AXNode::AXID pending_id : update_state.pending_nodes)
+ for (const AXNodeID pending_id : update_state.pending_nodes)
error += base::StringPrintf(" %d", pending_id);
RecordError(error);
return false;
@@ -1751,7 +1780,7 @@ bool AXTree::ValidatePendingChangesComplete(
bool has_pending_changes = false;
for (auto&& pair : update_state.node_id_to_pending_data) {
- const AXNode::AXID pending_id = pair.first;
+ const AXNodeID pending_id = pair.first;
const std::unique_ptr<PendingStructureChanges>& data = pair.second;
if (data->DoesNodeExpectAnyStructureChanges()) {
if (data->DoesNodeExpectSubtreeWillBeDestroyed())
@@ -1764,6 +1793,8 @@ bool AXTree::ValidatePendingChangesComplete(
}
}
if (has_pending_changes) {
+ ACCESSIBILITY_TREE_UNSERIALIZE_ERROR_HISTOGRAM(
+ AXTreeUnserializeError::kPendingChanges);
RecordError(base::StringPrintf(
"Changes left pending by the update; "
"destroy subtrees: %s, destroy nodes: %s, create nodes: %s",
@@ -1776,13 +1807,13 @@ bool AXTree::ValidatePendingChangesComplete(
return true;
}
-void AXTree::MarkSubtreeForDestruction(AXNode::AXID node_id,
+void AXTree::MarkSubtreeForDestruction(AXNodeID node_id,
AXTreeUpdateState* update_state) {
update_state->IncrementPendingDestroySubtreeCount(node_id);
MarkNodesForDestructionRecursive(node_id, update_state);
}
-void AXTree::MarkNodesForDestructionRecursive(AXNode::AXID node_id,
+void AXTree::MarkNodesForDestructionRecursive(AXNodeID node_id,
AXTreeUpdateState* update_state) {
// If this subtree has already been marked for destruction, return so
// we don't walk it again.
@@ -1793,7 +1824,7 @@ void AXTree::MarkNodesForDestructionRecursive(AXNode::AXID node_id,
update_state->GetLastKnownPendingNodeData(node_id);
update_state->IncrementPendingDestroyNodeCount(node_id);
- for (AXNode::AXID child_id : last_known_data.child_ids) {
+ for (AXNodeID child_id : last_known_data.child_ids) {
MarkNodesForDestructionRecursive(child_id, update_state);
}
}
@@ -1841,15 +1872,15 @@ void AXTree::DestroyNodeAndSubtree(AXNode* node,
}
void AXTree::DeleteOldChildren(AXNode* node,
- const std::vector<int32_t>& new_child_ids,
+ const std::vector<AXNodeID>& new_child_ids,
AXTreeUpdateState* update_state) {
DCHECK(GetTreeUpdateInProgressState());
// Create a set of child ids in |src| for fast lookup, we know the set does
// not contain duplicate entries already, because that was handled when
// populating |update_state| with information about all of the expected
// changes to be applied.
- std::set<int32_t> new_child_id_set(new_child_ids.begin(),
- new_child_ids.end());
+ std::set<AXNodeID> new_child_id_set(new_child_ids.begin(),
+ new_child_ids.end());
// Delete the old children.
for (AXNode* child : node->children()) {
@@ -1859,13 +1890,13 @@ void AXTree::DeleteOldChildren(AXNode* node,
}
bool AXTree::CreateNewChildVector(AXNode* node,
- const std::vector<int32_t>& new_child_ids,
+ const std::vector<AXNodeID>& new_child_ids,
std::vector<AXNode*>* new_children,
AXTreeUpdateState* update_state) {
DCHECK(GetTreeUpdateInProgressState());
bool success = true;
for (size_t i = 0; i < new_child_ids.size(); ++i) {
- int32_t child_id = new_child_ids[i];
+ AXNodeID child_id = new_child_ids[i];
AXNode* child = GetFromId(child_id);
if (child) {
if (child->parent() != node) {
@@ -1902,8 +1933,8 @@ void AXTree::SetEnableExtraMacNodes(bool enabled) {
enable_extra_mac_nodes_ = enabled;
}
-int32_t AXTree::GetNextNegativeInternalNodeId() {
- int32_t return_value = next_negative_internal_node_id_;
+AXNodeID AXTree::GetNextNegativeInternalNodeId() {
+ AXNodeID return_value = next_negative_internal_node_id_;
next_negative_internal_node_id_--;
if (next_negative_internal_node_id_ > 0)
next_negative_internal_node_id_ = -1;
@@ -2322,8 +2353,11 @@ AXTree::Selection AXTree::GetUnignoredSelection() const {
data().sel_is_backward ? AXPositionAdjustmentBehavior::kMoveForward
: AXPositionAdjustmentBehavior::kMoveBackward);
- // Any selection endpoint that is inside a leaf node is expressed as a text
- // position in AXTreeData.
+ // Moving to an unignored position might have placed the position on a leaf
+ // node. Any selection endpoint that is inside a leaf node is expressed as a
+ // text position in AXTreeData. (Note that in this context "leaf node" means
+ // a node with no children or with only ignored children. This does not
+ // refer to a platform leaf.)
if (anchor_position->IsLeafTreePosition())
anchor_position = anchor_position->AsTextPosition();
@@ -2340,11 +2374,11 @@ AXTree::Selection AXTree::GetUnignoredSelection() const {
case AXPositionKind::NULL_POSITION:
// If one of the selection endpoints is invalid, then both endpoints
// should be unset.
- unignored_selection.anchor_object_id = AXNode::kInvalidAXID;
+ unignored_selection.anchor_object_id = kInvalidAXNodeID;
unignored_selection.anchor_offset = -1;
unignored_selection.anchor_affinity =
ax::mojom::TextAffinity::kDownstream;
- unignored_selection.focus_object_id = AXNode::kInvalidAXID;
+ unignored_selection.focus_object_id = kInvalidAXNodeID;
unignored_selection.focus_offset = -1;
unignored_selection.focus_affinity =
ax::mojom::TextAffinity::kDownstream;
@@ -2375,8 +2409,11 @@ AXTree::Selection AXTree::GetUnignoredSelection() const {
!data().sel_is_backward ? AXPositionAdjustmentBehavior::kMoveForward
: AXPositionAdjustmentBehavior::kMoveBackward);
- // Any selection endpoint that is inside a leaf node is expressed as a text
- // position in AXTreeData.
+ // Moving to an unignored position might have placed the position on a leaf
+ // node. Any selection endpoint that is inside a leaf node is expressed as a
+ // text position in AXTreeData. (Note that in this context "leaf node" means
+ // a node with no children or with only ignored children. This does not
+ // refer to a platform leaf.)
if (focus_position->IsLeafTreePosition())
focus_position = focus_position->AsTextPosition();
@@ -2393,11 +2430,11 @@ AXTree::Selection AXTree::GetUnignoredSelection() const {
case AXPositionKind::NULL_POSITION:
// If one of the selection endpoints is invalid, then both endpoints
// should be unset.
- unignored_selection.anchor_object_id = AXNode::kInvalidAXID;
+ unignored_selection.anchor_object_id = kInvalidAXNodeID;
unignored_selection.anchor_offset = -1;
unignored_selection.anchor_affinity =
ax::mojom::TextAffinity::kDownstream;
- unignored_selection.focus_object_id = AXNode::kInvalidAXID;
+ unignored_selection.focus_object_id = kInvalidAXNodeID;
unignored_selection.focus_offset = -1;
unignored_selection.focus_affinity =
ax::mojom::TextAffinity::kDownstream;
@@ -2431,6 +2468,14 @@ bool AXTree::HasPaginationSupport() const {
return has_pagination_support_;
}
+void AXTree::NotifyTreeManagerWillBeRemoved(AXTreeID previous_tree_id) {
+ if (previous_tree_id == AXTreeIDUnknown())
+ return;
+
+ for (AXTreeObserver& observer : observers_)
+ observer.OnTreeManagerWillBeRemoved(previous_tree_id);
+}
+
void AXTree::RecordError(std::string new_error) {
if (!error_.empty())
error_ = error_ + "\n"; // Add visual separation between errors.
diff --git a/chromium/ui/accessibility/ax_tree.h b/chromium/ui/accessibility/ax_tree.h
index ae4e4b2baea..5d3836eae36 100644
--- a/chromium/ui/accessibility/ax_tree.h
+++ b/chromium/ui/accessibility/ax_tree.h
@@ -14,6 +14,7 @@
#include <unordered_map>
#include <vector>
+#include "base/metrics/histogram_functions.h"
#include "base/observer_list.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
#include "ui/accessibility/ax_export.h"
@@ -29,6 +30,34 @@ class AXTreeObserver;
struct AXTreeUpdateState;
class AXLanguageDetectionManager;
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class AXTreeUnserializeError {
+ // Tree has no root.
+ kNoRoot = 0,
+ // Node will not be in the tree and is not the new root.
+ kNotInTree = 1,
+ // Node is already pending for creation, cannot be the new root
+ kCreationPending = 2,
+ // Node has duplicate child.
+ kDuplicateChild = 3,
+ // Node is already pending for creation, cannot be a new child.
+ kCreationPendingForChild = 4,
+ // Node is not marked for destruction, would be reparented.
+ kReparent = 5,
+ // Nodes are left pending by the update.
+ kPendingNodes = 6,
+ // Changes left pending by the update;
+ kPendingChanges = 7,
+ // This must always be the last enum. It's okay for its value to
+ // increase, but none of the other enum values may change.
+ kMaxValue = kPendingChanges
+};
+
+#define ACCESSIBILITY_TREE_UNSERIALIZE_ERROR_HISTOGRAM(enum_value) \
+ base::UmaHistogramEnumeration( \
+ "Accessibility.Reliability.Tree.UnserializeError", enum_value)
+
// 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.
@@ -37,10 +66,10 @@ class AXLanguageDetectionManager;
class AX_EXPORT AXTree : public AXNode::OwnerTree {
public:
using IntReverseRelationMap =
- std::map<ax::mojom::IntAttribute, std::map<int32_t, std::set<int32_t>>>;
+ std::map<ax::mojom::IntAttribute, std::map<AXNodeID, std::set<AXNodeID>>>;
using IntListReverseRelationMap =
std::map<ax::mojom::IntListAttribute,
- std::map<int32_t, std::set<int32_t>>>;
+ std::map<AXNodeID, std::set<AXNodeID>>>;
AXTree();
explicit AXTree(const AXTreeUpdate& initial_state);
@@ -58,7 +87,7 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
AXNode* root() const { return root_; }
- const AXTreeData& data() const { return data_; }
+ const AXTreeData& data() const override;
// Destroys the tree and notifies all observers.
void Destroy();
@@ -69,7 +98,7 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// AXNode::OwnerTree override.
// Returns the AXNode with the given |id| if it is part of this AXTree.
- AXNode* GetFromId(int32_t id) const override;
+ AXNode* GetFromId(AXNodeID id) const override;
// Returns true on success. If it returns false, it's a fatal error
// and this tree should be destroyed, and the source of the tree update
@@ -103,19 +132,19 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// Given a node ID attribute (one where IsNodeIdIntAttribute is true),
// and a destination node ID, return a set of all source node IDs that
// have that relationship attribute between them and the destination.
- std::set<int32_t> GetReverseRelations(ax::mojom::IntAttribute attr,
- int32_t dst_id) const;
+ std::set<AXNodeID> GetReverseRelations(ax::mojom::IntAttribute attr,
+ AXNodeID dst_id) const;
// Given a node ID list attribute (one where
// IsNodeIdIntListAttribute is true), and a destination node ID,
// return a set of all source node IDs that have that relationship
// attribute between them and the destination.
- std::set<int32_t> GetReverseRelations(ax::mojom::IntListAttribute attr,
- int32_t dst_id) const;
+ std::set<AXNodeID> GetReverseRelations(ax::mojom::IntListAttribute attr,
+ AXNodeID dst_id) const;
// Given a child tree ID, return the node IDs of all nodes in the tree who
// have a kChildTreeId int attribute with that value.
- std::set<int32_t> GetNodeIdsForChildTreeId(AXTreeID child_tree_id) const;
+ std::set<AXNodeID> GetNodeIdsForChildTreeId(AXTreeID child_tree_id) const;
// Get all of the child tree IDs referenced by any node in this tree.
const std::set<AXTreeID> GetAllChildTreeIds() const;
@@ -145,7 +174,7 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// Return a negative number that's suitable to use for a node ID for
// internal nodes created automatically by an AXTree, so as not to
// conflict with positive-numbered node IDs from tree sources.
- int32_t GetNextNegativeInternalNodeId();
+ AXNodeID GetNextNegativeInternalNodeId();
// Returns the PosInSet of |node|. Looks in node_set_size_pos_in_set_info_map_
// for cached value. Calls |ComputeSetSizePosInSetAndCache|if no value is
@@ -175,6 +204,13 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
return event_intents_;
}
+ // Notify the delegate that the tree manager for |previous_tree_id| will be
+ // removed from the AXTreeManagerMap. Because we sometimes remove the tree
+ // manager after the tree's id has been modified, we need to pass the (old)
+ // tree id associated with the manager we are removing even though it is the
+ // same tree.
+ void NotifyTreeManagerWillBeRemoved(AXTreeID previous_tree_id);
+
private:
friend class AXTableInfoTest;
@@ -195,7 +231,7 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
AXTableInfo* GetTableInfo(const AXNode* table_node) const override;
AXNode* CreateNode(AXNode* parent,
- AXNode::AXID id,
+ AXNodeID id,
size_t index_in_parent,
AXTreeUpdateState* update_state);
@@ -237,7 +273,7 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// We are passing the node id instead of ax node is because by the time this
// function is called, the ax node in the tree will already have been
// destroyed.
- void NotifyNodeHasBeenDeleted(AXNode::AXID node_id);
+ void NotifyNodeHasBeenDeleted(AXNodeID node_id);
// Notify the delegate that |node| has been created or reparented.
void NotifyNodeHasBeenReparentedOrCreated(
@@ -263,12 +299,12 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// Modifies |update_state| so that it knows what subtree and nodes are
// going to be destroyed for the subtree rooted at |node|.
- void MarkSubtreeForDestruction(AXNode::AXID node_id,
+ void MarkSubtreeForDestruction(AXNodeID node_id,
AXTreeUpdateState* update_state);
// Modifies |update_state| so that it knows what nodes are
// going to be destroyed for the subtree rooted at |node|.
- void MarkNodesForDestructionRecursive(AXNode::AXID node_id,
+ void MarkNodesForDestructionRecursive(AXNodeID node_id,
AXTreeUpdateState* update_state);
// Validates that destroying the subtree rooted at |node| has required
@@ -282,7 +318,7 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// Iterate over the children of |node| and for each child, destroy the
// child and its subtree if its id is not in |new_child_ids|.
void DeleteOldChildren(AXNode* node,
- const std::vector<int32_t>& new_child_ids,
+ const std::vector<AXNodeID>& new_child_ids,
AXTreeUpdateState* update_state);
// Iterate over |new_child_ids| and populate |new_children| with
@@ -291,7 +327,7 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// if the id already exists as the child of another node, that's an
// error. Returns true on success, false on fatal error.
bool CreateNewChildVector(AXNode* node,
- const std::vector<int32_t>& new_child_ids,
+ const std::vector<AXNodeID>& new_child_ids,
std::vector<AXNode*>* new_children,
AXTreeUpdateState* update_state);
@@ -305,7 +341,7 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
base::ObserverList<AXTreeObserver> observers_;
AXNode* root_ = nullptr;
- std::unordered_map<int32_t, AXNode*> id_map_;
+ std::unordered_map<AXNodeID, AXNode*> id_map_;
std::string error_;
AXTreeData data_;
@@ -316,15 +352,15 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// a reverse mapping from target nodes to source nodes.
IntListReverseRelationMap intlist_reverse_relations_;
// Map from child tree ID to the set of node IDs that contain that attribute.
- std::map<AXTreeID, std::set<int32_t>> child_tree_id_reverse_map_;
+ std::map<AXTreeID, std::set<AXNodeID>> child_tree_id_reverse_map_;
// Map from node ID to cached table info, if the given node is a table.
// Invalidated every time the tree is updated.
- mutable std::unordered_map<int32_t, std::unique_ptr<AXTableInfo>>
+ mutable std::unordered_map<AXNodeID, std::unique_ptr<AXTableInfo>>
table_info_map_;
// The next negative node ID to use for internal nodes.
- int32_t next_negative_internal_node_id_ = -1;
+ AXNodeID next_negative_internal_node_id_ = -1;
// Whether we should create extra nodes that
// are only useful on macOS. Implemented using this flag to allow
@@ -385,7 +421,7 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
// objects.
// All other objects will map to default-constructed OrderedSetInfo objects.
// Invalidated every time the tree is updated.
- mutable std::unordered_map<int32_t, NodeSetSizePosInSetInfo>
+ mutable std::unordered_map<AXNodeID, NodeSetSizePosInSetInfo>
node_set_size_pos_in_set_info_map_;
// Indicates if the tree is updating.
diff --git a/chromium/ui/accessibility/ax_tree_combiner.cc b/chromium/ui/accessibility/ax_tree_combiner.cc
index 9c251d1e757..7ede67f0b33 100644
--- a/chromium/ui/accessibility/ax_tree_combiner.cc
+++ b/chromium/ui/accessibility/ax_tree_combiner.cc
@@ -78,7 +78,7 @@ bool AXTreeCombiner::Combine() {
return true;
}
-int32_t AXTreeCombiner::MapId(AXTreeID tree_id, int32_t node_id) {
+AXNodeID AXTreeCombiner::MapId(AXTreeID tree_id, AXNodeID node_id) {
auto tree_id_node_id = std::make_pair(tree_id, node_id);
if (tree_id_node_id_map_[tree_id_node_id] == 0)
tree_id_node_id_map_[tree_id_node_id] = next_id_++;
diff --git a/chromium/ui/accessibility/ax_tree_combiner.h b/chromium/ui/accessibility/ax_tree_combiner.h
index 4dc2b63f8af..3fc2b88d846 100644
--- a/chromium/ui/accessibility/ax_tree_combiner.h
+++ b/chromium/ui/accessibility/ax_tree_combiner.h
@@ -34,15 +34,15 @@ class AX_EXPORT AXTreeCombiner {
const AXTreeUpdate& combined() { return combined_; }
private:
- int32_t MapId(AXTreeID tree_id, int32_t node_id);
+ AXNodeID MapId(AXTreeID tree_id, AXNodeID node_id);
void ProcessTree(const AXTreeUpdate* tree);
std::vector<ui::AXTreeUpdate> trees_;
AXTreeID root_tree_id_;
- int32_t next_id_ = 1;
+ AXNodeID next_id_ = 1;
std::map<AXTreeID, const AXTreeUpdate*> tree_id_map_;
- std::map<std::pair<AXTreeID, int32_t>, int32_t> tree_id_node_id_map_;
+ std::map<std::pair<AXTreeID, AXNodeID>, AXNodeID> tree_id_node_id_map_;
AXTreeUpdate combined_;
};
diff --git a/chromium/ui/accessibility/ax_tree_combiner_unittest.cc b/chromium/ui/accessibility/ax_tree_combiner_unittest.cc
index 5d5a5d0edff..0bf8893aae5 100644
--- a/chromium/ui/accessibility/ax_tree_combiner_unittest.cc
+++ b/chromium/ui/accessibility/ax_tree_combiner_unittest.cc
@@ -117,7 +117,7 @@ TEST(CombineAXTreesTest, MapAllIdAttributes) {
22);
tree.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kActivedescendantId,
22);
- std::vector<int32_t> ids { 22 };
+ std::vector<AXNodeID> ids{22};
tree.nodes[0].AddIntListAttribute(
ax::mojom::IntListAttribute::kIndirectChildIds, ids);
tree.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kControlsIds,
diff --git a/chromium/ui/accessibility/ax_tree_data.cc b/chromium/ui/accessibility/ax_tree_data.cc
index 43ba38f6733..945ed6b69b6 100644
--- a/chromium/ui/accessibility/ax_tree_data.cc
+++ b/chromium/ui/accessibility/ax_tree_data.cc
@@ -47,10 +47,10 @@ std::string AXTreeData::ToString() const {
if (!title.empty())
result += " title=" + title;
- if (focus_id != AXNode::kInvalidAXID)
+ if (focus_id != kInvalidAXNodeID)
result += " focus_id=" + base::NumberToString(focus_id);
- if (sel_anchor_object_id != AXNode::kInvalidAXID) {
+ if (sel_anchor_object_id != kInvalidAXNodeID) {
result +=
(sel_is_backward ? " sel_is_backward=true" : " sel_is_backward=false");
result +=
@@ -59,7 +59,7 @@ std::string AXTreeData::ToString() const {
result += " sel_anchor_affinity=";
result += ui::ToString(sel_anchor_affinity);
}
- if (sel_focus_object_id != AXNode::kInvalidAXID) {
+ if (sel_focus_object_id != kInvalidAXNodeID) {
result +=
" sel_focus_object_id=" + base::NumberToString(sel_focus_object_id);
result += " sel_focus_offset=" + base::NumberToString(sel_focus_offset);
diff --git a/chromium/ui/accessibility/ax_tree_data.h b/chromium/ui/accessibility/ax_tree_data.h
index 4f94423ec58..e8800b092c4 100644
--- a/chromium/ui/accessibility/ax_tree_data.h
+++ b/chromium/ui/accessibility/ax_tree_data.h
@@ -14,9 +14,9 @@
#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/strings/string_split.h"
+#include "ui/accessibility/ax_base_export.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
-#include "ui/accessibility/ax_export.h"
-#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree_id_registry.h"
#include "ui/gfx/geometry/rect.h"
@@ -24,7 +24,7 @@ namespace ui {
// The data associated with an accessibility tree that's global to the
// tree and not associated with any particular node in the tree.
-struct AX_EXPORT AXTreeData {
+struct AX_BASE_EXPORT AXTreeData {
AXTreeData();
AXTreeData(const AXTreeData& other);
virtual ~AXTreeData();
@@ -54,8 +54,8 @@ struct AX_EXPORT AXTreeData {
std::string url;
// The node with keyboard focus within this tree, if any, or
- // AXNode::kInvalidAXID if no node in this tree has focus.
- AXNode::AXID focus_id = AXNode::kInvalidAXID;
+ // kInvalidAXNodeID if no node in this tree has focus.
+ AXNodeID focus_id = kInvalidAXNodeID;
// The current text selection within this tree, if any, expressed as the
// node ID and character offset of the anchor (selection start) and focus
@@ -64,21 +64,21 @@ struct AX_EXPORT AXTreeData {
// line, otherwise it's on the second line.
// Most use cases will want to use ui::OwnerTree::GetUnignoredSelection.
bool sel_is_backward = false;
- AXNode::AXID sel_anchor_object_id = AXNode::kInvalidAXID;
+ AXNodeID sel_anchor_object_id = kInvalidAXNodeID;
int32_t sel_anchor_offset = -1;
ax::mojom::TextAffinity sel_anchor_affinity;
- AXNode::AXID sel_focus_object_id = AXNode::kInvalidAXID;
+ AXNodeID sel_focus_object_id = kInvalidAXNodeID;
int32_t sel_focus_offset = -1;
ax::mojom::TextAffinity sel_focus_affinity;
// The node that's used as the root scroller. On some platforms
// like Android we need to ignore accessibility scroll offsets for
// that node and get them from the viewport instead.
- AXNode::AXID root_scroller_id = AXNode::kInvalidAXID;
+ AXNodeID root_scroller_id = kInvalidAXNodeID;
};
-AX_EXPORT bool operator==(const AXTreeData& lhs, const AXTreeData& rhs);
-AX_EXPORT bool operator!=(const AXTreeData& lhs, const AXTreeData& rhs);
+AX_BASE_EXPORT bool operator==(const AXTreeData& lhs, const AXTreeData& rhs);
+AX_BASE_EXPORT bool operator!=(const AXTreeData& lhs, const AXTreeData& rhs);
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree_id_registry.h b/chromium/ui/accessibility/ax_tree_id_registry.h
index 8ccbfee3d84..f597ed6fd37 100644
--- a/chromium/ui/accessibility/ax_tree_id_registry.h
+++ b/chromium/ui/accessibility/ax_tree_id_registry.h
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "ui/accessibility/ax_action_handler.h"
-#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_base_export.h"
#include "ui/accessibility/ax_tree_id.h"
namespace base {
@@ -31,7 +31,7 @@ class AXActionHandlerBase;
// The first form allows underlying instances to change but refer to the same
// frame.
// The second form allows this registry to track the object for later retrieval.
-class AX_EXPORT AXTreeIDRegistry {
+class AX_BASE_EXPORT AXTreeIDRegistry {
public:
using FrameID = std::pair<int, int>;
diff --git a/chromium/ui/accessibility/ax_tree_manager.h b/chromium/ui/accessibility/ax_tree_manager.h
index 2e2d4d87c1f..ba8b4b654ac 100644
--- a/chromium/ui/accessibility/ax_tree_manager.h
+++ b/chromium/ui/accessibility/ax_tree_manager.h
@@ -21,12 +21,14 @@ class AX_EXPORT AXTreeManager {
// given |tree_id|. This allows for callers to access nodes outside of their
// own tree. Returns nullptr if |tree_id| or |node_id| is not found.
virtual AXNode* GetNodeFromTree(const AXTreeID tree_id,
- const AXNode::AXID node_id) const = 0;
+ const AXNodeID node_id) const = 0;
// Returns the AXNode in the current tree that has the given |node_id|.
// Returns nullptr if |node_id| is not found.
- virtual AXNode* GetNodeFromTree(const AXNode::AXID node_id) const = 0;
+ virtual AXNode* GetNodeFromTree(const AXNodeID node_id) const = 0;
+ // Use `AddObserver` and `RemoveObserver` when you want to be notified when
+ // changes happen to an `XTree`
virtual void AddObserver(AXTreeObserver* observer) {}
virtual void RemoveObserver(AXTreeObserver* observer) {}
@@ -44,6 +46,10 @@ class AX_EXPORT AXTreeManager {
// hosts the current tree. Returns nullptr if this tree doesn't have a parent
// tree.
virtual AXNode* GetParentNodeFromParentTreeAsAXNode() const = 0;
+
+ // Called when the tree manager is about to be removed from the tree map,
+ // `AXTreeManagerMap`.
+ virtual void WillBeRemovedFromMap() {}
};
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree_manager_map.cc b/chromium/ui/accessibility/ax_tree_manager_map.cc
index 56083ca73a9..d921f0c3eef 100644
--- a/chromium/ui/accessibility/ax_tree_manager_map.cc
+++ b/chromium/ui/accessibility/ax_tree_manager_map.cc
@@ -4,15 +4,16 @@
#include "ui/accessibility/ax_tree_manager_map.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "ui/accessibility/ax_enums.mojom.h"
namespace ui {
-AXTreeManagerMap::AXTreeManagerMap() {}
+AXTreeManagerMap::AXTreeManagerMap() = default;
-AXTreeManagerMap::~AXTreeManagerMap() {}
+AXTreeManagerMap::~AXTreeManagerMap() = default;
+// static
AXTreeManagerMap& AXTreeManagerMap::GetInstance() {
static base::NoDestructor<AXTreeManagerMap> instance;
return *instance;
@@ -25,8 +26,10 @@ void AXTreeManagerMap::AddTreeManager(AXTreeID tree_id,
}
void AXTreeManagerMap::RemoveTreeManager(AXTreeID tree_id) {
- if (tree_id != AXTreeIDUnknown())
+ if (auto* manager = GetManager(tree_id)) {
+ manager->WillBeRemovedFromMap();
map_.erase(tree_id);
+ }
}
AXTreeManager* AXTreeManagerMap::GetManager(AXTreeID tree_id) {
diff --git a/chromium/ui/accessibility/ax_tree_manager_map.h b/chromium/ui/accessibility/ax_tree_manager_map.h
index 7cd92ff874e..6efd33d85d5 100644
--- a/chromium/ui/accessibility/ax_tree_manager_map.h
+++ b/chromium/ui/accessibility/ax_tree_manager_map.h
@@ -22,14 +22,16 @@ class AX_EXPORT AXTreeManagerMap {
public:
AXTreeManagerMap();
~AXTreeManagerMap();
+ AXTreeManagerMap(const AXTreeManagerMap& map) = delete;
+ AXTreeManagerMap& operator=(const AXTreeManagerMap& map) = delete;
static AXTreeManagerMap& GetInstance();
void AddTreeManager(AXTreeID tree_id, AXTreeManager* manager);
void RemoveTreeManager(AXTreeID tree_id);
AXTreeManager* GetManager(AXTreeID tree_id);
- // If the child of the provided parent node exists in a separate child tree,
- // return the tree manager for that child tree. Otherwise, return nullptr.
+ // If the child of `parent_node` exists in a separate child tree, return the
+ // tree manager for that child tree. Otherwise, return nullptr.
AXTreeManager* GetManagerForChildTree(const AXNode& parent_node);
private:
diff --git a/chromium/ui/accessibility/ax_tree_observer.h b/chromium/ui/accessibility/ax_tree_observer.h
index c9517c6a7ac..04fd20fadb9 100644
--- a/chromium/ui/accessibility/ax_tree_observer.h
+++ b/chromium/ui/accessibility/ax_tree_observer.h
@@ -8,11 +8,12 @@
#include "base/observer_list_types.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_tree_id.h"
namespace ui {
class AXNode;
-struct AXNodeData;
class AXTree;
struct AXTreeData;
@@ -115,7 +116,7 @@ class AX_EXPORT AXTreeObserver : public base::CheckedObserver {
// Called after all tree mutations have occurred or during tree teardown,
// notifying that a single node has been deleted from the tree.
- virtual void OnNodeDeleted(AXTree* tree, int32_t node_id) {}
+ virtual void OnNodeDeleted(AXTree* tree, AXNodeID node_id) {}
// Same as |OnNodeCreated|, but called for nodes that have been reparented.
virtual void OnNodeReparented(AXTree* tree, AXNode* node) {}
@@ -126,6 +127,15 @@ class AX_EXPORT AXTreeObserver : public base::CheckedObserver {
// updating.
virtual void OnNodeChanged(AXTree* tree, AXNode* node) {}
+ // Called just before a tree manager is removed from the AXTreeManagerMap.
+ //
+ // Why is this needed?
+ // In some cases, we update the tree id of an AXTree and need to update the
+ // map entry that corresponds to that tree. The observers maintained in the
+ // observers list of that AXTree might need to be notified of that change to
+ // remove themselves from the list, if needed.
+ virtual void OnTreeManagerWillBeRemoved(AXTreeID previous_tree_id) {}
+
enum ChangeType {
NODE_CREATED,
SUBTREE_CREATED,
diff --git a/chromium/ui/accessibility/ax_tree_serializer.h b/chromium/ui/accessibility/ax_tree_serializer.h
index c809aa47a8b..798170787b6 100644
--- a/chromium/ui/accessibility/ax_tree_serializer.h
+++ b/chromium/ui/accessibility/ax_tree_serializer.h
@@ -8,6 +8,7 @@
#include <stddef.h>
#include <stdint.h>
+#include <ctime>
#include <ostream>
#include <unordered_map>
#include <unordered_set>
@@ -16,6 +17,8 @@
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/logging.h"
+#include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
#include "ui/accessibility/ax_common.h"
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_tree_source.h"
@@ -60,11 +63,10 @@ struct ClientTreeNode;
// because AXTreeSerializer always keeps track of what updates it's sent,
// it will never send an invalid update and the client tree will not break,
// it just may not contain all of the changes.
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
+template <typename AXSourceNode>
class AXTreeSerializer {
public:
- explicit AXTreeSerializer(
- AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree);
+ explicit AXTreeSerializer(AXTreeSource<AXSourceNode>* tree);
~AXTreeSerializer();
// Throw out the internal state that keeps track of the nodes the client
@@ -76,17 +78,23 @@ class AXTreeSerializer {
// for no maximum. This is not a hard maximum - once it hits or
// exceeds this maximum it stops walking the children of nodes, but
// it may exceed this value a bit in order to create a consistent
- // tree.
+ // tree. This is only intended to be used for one-time tree snapshots.
void set_max_node_count(size_t max_node_count) {
max_node_count_ = max_node_count;
}
+ // Sets the maximum amount of time to be spend serializing, or zero for
+ // no maximum. This is not a hard maximum - once it hits or
+ // exceeds this timeout it stops walking the children of nodes, but
+ // it may exceed this value a bit in order to create a consistent
+ // tree. This is only intended to be used for one-time tree snapshots.
+ void set_timeout(base::TimeDelta timeout) { timeout_ = timeout; }
+
// Serialize all changes to |node| and append them to |out_update|.
// Returns true on success. On failure, returns false and calls Reset();
// this only happens when the source tree has a problem like duplicate
// ids or changing during serialization.
- bool SerializeChanges(AXSourceNode node,
- AXTreeUpdateBase<AXNodeData, AXTreeData>* out_update);
+ bool SerializeChanges(AXSourceNode node, AXTreeUpdate* out_update);
// Invalidate the subtree rooted at this node, ensuring that the whole
// subtree is re-serialized the next time any of those nodes end up
@@ -109,8 +117,7 @@ class AXTreeSerializer {
// state and then call ChangeTreeSourceForTesting and then SerializeChanges
// to simulate the changes you'd get if a tree changed from the initial
// state to the second tree's state.
- void ChangeTreeSourceForTesting(
- AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* new_tree);
+ void ChangeTreeSourceForTesting(AXTreeSource<AXSourceNode>* new_tree);
// Returns the number of nodes in the client tree. After a serialization
// operation this should be an accurate representation of the tree source
@@ -166,7 +173,7 @@ class AXTreeSerializer {
bool AnyDescendantWasReparented(AXSourceNode node,
AXSourceNode* out_lca);
- ClientTreeNode* ClientTreeNodeById(int32_t id);
+ ClientTreeNode* ClientTreeNodeById(AXNodeID id);
// Invalidate the subtree rooted at this node.
void InvalidateClientSubtree(ClientTreeNode* client_node);
@@ -178,9 +185,7 @@ class AXTreeSerializer {
void DeleteClientSubtree(ClientTreeNode* client_node);
// Helper function, called recursively with each new node to serialize.
- bool SerializeChangedNodes(
- AXSourceNode node,
- AXTreeUpdateBase<AXNodeData, AXTreeData>* out_update);
+ bool SerializeChangedNodes(AXSourceNode node, AXTreeUpdate* out_update);
// Delete the entire client subtree but don't set the did_reset_ flag
// like when Reset() is called.
@@ -189,7 +194,7 @@ class AXTreeSerializer {
ClientTreeNode* GetClientTreeNodeParent(ClientTreeNode* obj);
// The tree source.
- AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree_;
+ AXTreeSource<AXSourceNode>* tree_;
// The tree data most recently sent to the client.
AXTreeData client_tree_data_;
@@ -198,12 +203,17 @@ class AXTreeSerializer {
ClientTreeNode* client_root_ = nullptr;
// A map from IDs to nodes in the client tree.
- std::unordered_map<int32_t, ClientTreeNode*> client_id_map_;
+ std::map<AXNodeID, ClientTreeNode*> client_id_map_;
// The maximum number of nodes to serialize in a given call to
// SerializeChanges, or 0 if there's no maximum.
size_t max_node_count_ = 0;
+ // The maximum time to spend serializing before timing out, or 0
+ // if there's no maximum.
+ base::TimeDelta timeout_;
+ std::unique_ptr<base::ElapsedTimer> timer_;
+
// Keeps track of if Reset() was called. If so, we need to always
// explicitly set node_id_to_clear to ensure that the next serialized
// tree is treated as a completely new tree and not a partial update.
@@ -216,34 +226,34 @@ class AXTreeSerializer {
struct AX_EXPORT ClientTreeNode {
ClientTreeNode();
virtual ~ClientTreeNode();
- int32_t id;
+ AXNodeID id;
ClientTreeNode* parent;
std::vector<ClientTreeNode*> children;
bool ignored;
bool invalid;
};
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::AXTreeSerializer(
- AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree)
+template <typename AXSourceNode>
+AXTreeSerializer<AXSourceNode>::AXTreeSerializer(
+ AXTreeSource<AXSourceNode>* tree)
: tree_(tree) {}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::~AXTreeSerializer() {
+template <typename AXSourceNode>
+AXTreeSerializer<AXSourceNode>::~AXTreeSerializer() {
// Clear |tree_| to prevent any additional calls to the tree source
// during teardown.
tree_ = nullptr;
Reset();
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::Reset() {
+template <typename AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::Reset() {
InternalReset();
did_reset_ = true;
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::InternalReset() {
+template <typename AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::InternalReset() {
client_tree_data_ = AXTreeData();
// Normally we use DeleteClientSubtree to remove nodes from the tree,
@@ -259,23 +269,19 @@ void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::InternalReset() {
client_root_ = nullptr;
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
- ChangeTreeSourceForTesting(
- AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* new_tree) {
+template <typename AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::ChangeTreeSourceForTesting(
+ AXTreeSource<AXSourceNode>* new_tree) {
tree_ = new_tree;
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-size_t
-AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::ClientTreeNodeCount()
- const {
+template <typename AXSourceNode>
+size_t AXTreeSerializer<AXSourceNode>::ClientTreeNodeCount() const {
return client_id_map_.size();
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-AXSourceNode
-AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::LeastCommonAncestor(
+template <typename AXSourceNode>
+AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
AXSourceNode node,
ClientTreeNode* client_node) {
if (!tree_->IsValid(node) || client_node == nullptr)
@@ -311,9 +317,8 @@ AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::LeastCommonAncestor(
return lca;
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-AXSourceNode
-AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::LeastCommonAncestor(
+template <typename AXSourceNode>
+AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
AXSourceNode node) {
// Walk up the tree until the source node's id also exists in the
// client tree, whose parent is not invalid, then call LeastCommonAncestor
@@ -338,9 +343,10 @@ AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::LeastCommonAncestor(
return LeastCommonAncestor(node, client_node);
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
- AnyDescendantWasReparented(AXSourceNode node, AXSourceNode* out_lca) {
+template <typename AXSourceNode>
+bool AXTreeSerializer<AXSourceNode>::AnyDescendantWasReparented(
+ AXSourceNode node,
+ AXSourceNode* out_lca) {
bool result = false;
int id = tree_->GetId(node);
std::vector<AXSourceNode> children;
@@ -380,20 +386,17 @@ bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
return result;
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-ClientTreeNode*
-AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::ClientTreeNodeById(
- int32_t id) {
- std::unordered_map<int32_t, ClientTreeNode*>::iterator iter =
- client_id_map_.find(id);
+template <typename AXSourceNode>
+ClientTreeNode* AXTreeSerializer<AXSourceNode>::ClientTreeNodeById(
+ AXNodeID id) {
+ std::map<AXNodeID, ClientTreeNode*>::iterator iter = client_id_map_.find(id);
if (iter != client_id_map_.end())
return iter->second;
return nullptr;
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-ClientTreeNode*
-AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::GetClientTreeNodeParent(
+template <typename AXSourceNode>
+ClientTreeNode* AXTreeSerializer<AXSourceNode>::GetClientTreeNodeParent(
ClientTreeNode* obj) {
ClientTreeNode* parent = obj->parent;
if (!parent)
@@ -415,10 +418,13 @@ AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::GetClientTreeNodeParent(
return parent;
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::SerializeChanges(
+template <typename AXSourceNode>
+bool AXTreeSerializer<AXSourceNode>::SerializeChanges(
AXSourceNode node,
- AXTreeUpdateBase<AXNodeData, AXTreeData>* out_update) {
+ AXTreeUpdate* out_update) {
+ if (!timeout_.is_zero())
+ timer_ = std::make_unique<base::ElapsedTimer>();
+
// Send the tree data if it's changed since the last update, or if
// out_update->has_tree_data is already set to true.
AXTreeData new_tree_data;
@@ -486,32 +492,30 @@ bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::SerializeChanges(
return true;
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::InvalidateSubtree(
- AXSourceNode node) {
+template <typename AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::InvalidateSubtree(AXSourceNode node) {
ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
if (client_node)
InvalidateClientSubtree(client_node);
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::IsInClientTree(
- AXSourceNode node) {
+template <typename AXSourceNode>
+bool AXTreeSerializer<AXSourceNode>::IsInClientTree(AXSourceNode node) {
ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
return client_node ? !client_node->invalid : false;
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
- InvalidateClientSubtree(ClientTreeNode* client_node) {
+template <typename AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::InvalidateClientSubtree(
+ ClientTreeNode* client_node) {
client_node->invalid = true;
for (size_t i = 0; i < client_node->children.size(); ++i)
InvalidateClientSubtree(client_node->children[i]);
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
- DeleteClientSubtree(ClientTreeNode* client_node) {
+template <typename AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree(
+ ClientTreeNode* client_node) {
if (client_node == client_root_) {
Reset(); // Do not try to reuse a bad root later.
} else {
@@ -522,19 +526,18 @@ void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
}
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::DeleteDescendants(
+template <typename AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::DeleteDescendants(
ClientTreeNode* client_node) {
for (size_t i = 0; i < client_node->children.size(); ++i)
DeleteClientSubtree(client_node->children[i]);
client_node->children.clear();
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
- SerializeChangedNodes(
- AXSourceNode node,
- AXTreeUpdateBase<AXNodeData, AXTreeData>* out_update) {
+template <typename AXSourceNode>
+bool AXTreeSerializer<AXSourceNode>::SerializeChangedNodes(
+ AXSourceNode node,
+ AXTreeUpdate* out_update) {
// This method has three responsibilities:
// 1. Serialize |node| into an AXNodeData, and append it to
// the AXTreeUpdate to be sent to the client.
@@ -563,23 +566,43 @@ bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
client_node->invalid = false;
client_node->ignored = tree_->IsIgnored(node);
+ // Terminate early if a maximum number of nodes is reached.
+ // the output tree is still consistent).
+ bool should_terminate_early = false;
+ if (max_node_count_ > 0 && out_update->nodes.size() >= max_node_count_)
+ should_terminate_early = true;
+
+ // Also terminate early if a timeout is reached.
+ if (!timeout_.is_zero() && timer_->Elapsed() >= timeout_)
+ should_terminate_early = true;
+
// Iterate over the ids of the children of |node|.
// Create a set of the child ids so we can quickly look
// up which children are new and which ones were there before.
// 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.
- std::unordered_set<int32_t> new_ignored_ids;
- std::unordered_set<int32_t> new_child_ids;
+ std::set<AXNodeID> new_ignored_ids;
+ std::set<AXNodeID> new_child_ids;
std::vector<AXSourceNode> children;
- if (max_node_count_ == 0 || out_update->nodes.size() < max_node_count_) {
+ if (!should_terminate_early) {
tree_->GetChildren(node, &children);
- } else if (max_node_count_ > 0) {
+ } else {
static bool logged_once = false;
if (!logged_once) {
- LOG(WARNING) << "Warning: not serializing AX nodes after a max of "
- << max_node_count_;
logged_once = true;
+
+ LOG(WARNING) << "Warning: stopped serializing AX nodes before "
+ << "serialization was complete.";
+ if (max_node_count_) {
+ LOG(WARNING) << "Nodes serialized so far: " << out_update->nodes.size()
+ << ", max_node_count: " << max_node_count_;
+ }
+ if (!timeout_.is_zero()) {
+ LOG(WARNING) << "Elapsed time in ms: "
+ << timer_->Elapsed().InMilliseconds()
+ << ", timeout: " << timeout_.InMilliseconds();
+ }
}
}
for (size_t i = 0; i < children.size(); ++i) {
@@ -609,8 +632,14 @@ bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
base::debug::SetCrashKeyString(reparent_err, error.str().substr(0, 230));
CHECK(false) << error.str();
#endif // defined(AX_FAIL_FAST_BUILD)
- // TODO: re-add this, including crash keys above.
- // base::debug::DumpWithoutCrashing();
+ static bool has_sent_reparent_err = false;
+ if (!has_sent_reparent_err) {
+ std::srand(std::time(nullptr)); // use current time as seed.
+ if (std::rand() % 50 == 0) { // Roughly 2% of the time.
+ base::debug::DumpWithoutCrashing();
+ has_sent_reparent_err = true; // Only send once.
+ }
+ }
Reset();
return false;
}
@@ -622,7 +651,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.
- std::unordered_map<int32_t, ClientTreeNode*> client_child_id_map;
+ std::map<AXNodeID, 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) {
@@ -652,7 +681,7 @@ bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
// Iterate over the children, serialize them, and update the ClientTreeNode
// data structure to reflect the new tree.
- std::vector<int32_t> actual_serialized_node_child_ids;
+ std::vector<AXNodeID> actual_serialized_node_child_ids;
client_node->children.reserve(children.size());
for (size_t i = 0; i < children.size(); ++i) {
AXSourceNode& child = children[i];
@@ -707,7 +736,14 @@ bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
#if defined(AX_FAIL_FAST_BUILD)
CHECK(false) << error.str();
#endif // defined(AX_FAIL_FAST_BUILD)
- base::debug::DumpWithoutCrashing();
+ static bool has_sent_dupe_id_err = false;
+ if (!has_sent_dupe_id_err) {
+ std::srand(std::time(nullptr)); // use current time as seed.
+ if (std::rand() % 50 == 0) { // Roughly 2% of the time.
+ base::debug::DumpWithoutCrashing();
+ has_sent_dupe_id_err = true; // Only send once.
+ }
+ }
Reset();
return false;
}
diff --git a/chromium/ui/accessibility/ax_tree_serializer_unittest.cc b/chromium/ui/accessibility/ax_tree_serializer_unittest.cc
index 0c5f7002673..0e7a97ad726 100644
--- a/chromium/ui/accessibility/ax_tree_serializer_unittest.cc
+++ b/chromium/ui/accessibility/ax_tree_serializer_unittest.cc
@@ -21,8 +21,7 @@ using testing::UnorderedElementsAre;
namespace ui {
-using BasicAXTreeSerializer =
- AXTreeSerializer<const AXNode*, AXNodeData, AXTreeData>;
+using BasicAXTreeSerializer = AXTreeSerializer<const AXNode*>;
// The framework for these tests is that each test sets up |treedata0_|
// and |treedata1_| and then calls GetTreeSerializer, which creates a
@@ -42,10 +41,8 @@ class AXTreeSerializerTest : public testing::Test {
AXTreeUpdate treedata1_;
std::unique_ptr<AXSerializableTree> tree0_;
std::unique_ptr<AXSerializableTree> tree1_;
- std::unique_ptr<AXTreeSource<const AXNode*, AXNodeData, AXTreeData>>
- tree0_source_;
- std::unique_ptr<AXTreeSource<const AXNode*, AXNodeData, AXTreeData>>
- tree1_source_;
+ std::unique_ptr<AXTreeSource<const AXNode*>> tree0_source_;
+ std::unique_ptr<AXTreeSource<const AXNode*>> tree1_source_;
std::unique_ptr<BasicAXTreeSerializer> serializer_;
private:
@@ -241,8 +238,7 @@ TEST_F(AXTreeSerializerTest, ReparentingWithInvalidationUpdatesSubtree) {
// A variant of AXTreeSource that returns true for IsValid() for one
// particular id.
-class AXTreeSourceWithInvalidId
- : public AXTreeSource<const AXNode*, AXNodeData, AXTreeData> {
+class AXTreeSourceWithInvalidId : public AXTreeSource<const AXNode*> {
public:
AXTreeSourceWithInvalidId(AXTree* tree, int invalid_id)
: tree_(tree),
@@ -255,8 +251,8 @@ class AXTreeSourceWithInvalidId
return true;
}
AXNode* GetRoot() const override { return tree_->root(); }
- AXNode* GetFromId(int32_t id) const override { return tree_->GetFromId(id); }
- int32_t GetId(const AXNode* node) const override { return node->id(); }
+ AXNode* GetFromId(AXNodeID id) const override { return tree_->GetFromId(id); }
+ AXNodeID GetId(const AXNode* node) const override { return node->id(); }
void GetChildren(const AXNode* node,
std::vector<const AXNode*>* out_children) const override {
*out_children = std::vector<const AXNode*>(node->children().cbegin(),
@@ -471,21 +467,19 @@ TEST_F(AXTreeSerializerTest, ResetWorksWithNewRootId) {
// Wraps an AXTreeSource and provides access to the results of the
// SerializerClearedNode callback.
-class AXTreeSourceTestWrapper
- : public AXTreeSource<const AXNode*, AXNodeData, AXTreeData> {
+class AXTreeSourceTestWrapper : public AXTreeSource<const AXNode*> {
public:
- explicit AXTreeSourceTestWrapper(
- AXTreeSource<const AXNode*, AXNodeData, AXTreeData>* tree_source)
+ explicit AXTreeSourceTestWrapper(AXTreeSource<const AXNode*>* tree_source)
: tree_source_(tree_source) {}
~AXTreeSourceTestWrapper() override = default;
// Override SerializerClearedNode and provide a way to access it.
- void SerializerClearedNode(int32_t node_id) override {
+ void SerializerClearedNode(AXNodeID node_id) override {
cleared_node_ids_.insert(node_id);
}
void ClearClearedNodeIds() { cleared_node_ids_.clear(); }
- std::set<int32_t>& cleared_node_ids() { return cleared_node_ids_; }
+ std::set<AXNodeID>& cleared_node_ids() { return cleared_node_ids_; }
// The rest of the AXTreeSource implementation just calls through to
// tree_source_.
@@ -493,10 +487,10 @@ class AXTreeSourceTestWrapper
return tree_source_->GetTreeData(data);
}
const AXNode* GetRoot() const override { return tree_source_->GetRoot(); }
- const AXNode* GetFromId(int32_t id) const override {
+ const AXNode* GetFromId(AXNodeID id) const override {
return tree_source_->GetFromId(id);
}
- int32_t GetId(const AXNode* node) const override {
+ AXNodeID GetId(const AXNode* node) const override {
return tree_source_->GetId(node);
}
void GetChildren(const AXNode* node,
@@ -521,8 +515,8 @@ class AXTreeSourceTestWrapper
}
private:
- AXTreeSource<const AXNode*, AXNodeData, AXTreeData>* tree_source_;
- std::set<int32_t> cleared_node_ids_;
+ AXTreeSource<const AXNode*>* tree_source_;
+ std::set<AXNodeID> cleared_node_ids_;
};
TEST_F(AXTreeSerializerTest, TestClearedNodesWhenUpdatingRoot) {
diff --git a/chromium/ui/accessibility/ax_tree_source.h b/chromium/ui/accessibility/ax_tree_source.h
index 357bfccf6f4..057441e6bc0 100644
--- a/chromium/ui/accessibility/ax_tree_source.h
+++ b/chromium/ui/accessibility/ax_tree_source.h
@@ -9,6 +9,9 @@
#include <vector>
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_tree_data.h"
+
namespace ui {
// An AXTreeSource is an abstract interface for a serializable
@@ -19,7 +22,7 @@ namespace ui {
// as an AXNodeData. This is the primary interface to use when
// an accessibility tree will be sent over an IPC before being
// consumed.
-template<typename AXNodeSource, typename AXNodeData, typename AXTreeData>
+template <typename AXNodeSource>
class AXTreeSource {
public:
virtual ~AXTreeSource() {}
@@ -32,10 +35,10 @@ class AXTreeSource {
// Get a node by its id. If no node by that id exists in the tree, return a
// null node, i.e. one that will return false if you call IsValid on it.
- virtual AXNodeSource GetFromId(int32_t id) const = 0;
+ virtual AXNodeSource GetFromId(AXNodeID id) const = 0;
// Return the id of a node. All ids must be positive integers.
- virtual int32_t GetId(AXNodeSource node) const = 0;
+ virtual AXNodeID GetId(AXNodeSource node) const = 0;
// Append all children of |node| to |out_children|.
virtual void GetChildren(AXNodeSource node,
@@ -72,7 +75,7 @@ class AXTreeSource {
// discovers that a node previously in the tree is no longer part of
// the tree. It can be used to allow an AXTreeSource to keep a cache
// indexed by node ID and delete nodes when they're no longer needed.
- virtual void SerializerClearedNode(int32_t node_id) {}
+ virtual void SerializerClearedNode(AXNodeID node_id) {}
protected:
AXTreeSource() {}
diff --git a/chromium/ui/accessibility/ax_tree_source_checker.h b/chromium/ui/accessibility/ax_tree_source_checker.h
index 748b334f623..82ee727b6a4 100644
--- a/chromium/ui/accessibility/ax_tree_source_checker.h
+++ b/chromium/ui/accessibility/ax_tree_source_checker.h
@@ -13,11 +13,10 @@
namespace ui {
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
+template <typename AXSourceNode>
class AXTreeSourceChecker {
public:
- explicit AXTreeSourceChecker(
- AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree);
+ explicit AXTreeSourceChecker(AXTreeSource<AXSourceNode>* tree);
~AXTreeSourceChecker();
// Returns true if everything reachable from the root of the tree is
@@ -29,25 +28,24 @@ class AXTreeSourceChecker {
bool Check(AXSourceNode node, std::string indent, std::string* output);
std::string NodeToString(AXSourceNode node);
- AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree_;
+ AXTreeSource<AXSourceNode>* tree_;
- std::map<int32_t, int32_t> node_id_to_parent_id_map_;
+ std::map<AXNodeID, AXNodeID> 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)
+template <typename AXSourceNode>
+AXTreeSourceChecker<AXSourceNode>::AXTreeSourceChecker(
+ AXTreeSource<AXSourceNode>* tree)
: tree_(tree) {}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::
- ~AXTreeSourceChecker() = default;
+template <typename AXSourceNode>
+AXTreeSourceChecker<AXSourceNode>::~AXTreeSourceChecker() = default;
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-bool AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::
- CheckAndGetErrorString(std::string* error_string) {
+template <typename AXSourceNode>
+bool AXTreeSourceChecker<AXSourceNode>::CheckAndGetErrorString(
+ std::string* error_string) {
node_id_to_parent_id_map_.clear();
AXSourceNode root = tree_->GetRoot();
@@ -56,28 +54,27 @@ bool AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::
return false;
}
- int32_t root_id = tree_->GetId(root);
- node_id_to_parent_id_map_[root_id] = -1;
+ AXNodeID root_id = tree_->GetId(root);
+ node_id_to_parent_id_map_[root_id] = kInvalidAXNodeID;
return Check(root, "", error_string);
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-std::string
-AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::NodeToString(
- AXSourceNode node) {
+template <typename AXSourceNode>
+std::string AXTreeSourceChecker<AXSourceNode>::NodeToString(AXSourceNode node) {
AXNodeData node_data;
tree_->SerializeNode(node, &node_data);
std::vector<AXSourceNode> children;
tree_->GetChildren(node, &children);
std::string children_str;
- if (children.size() == 0) {
+ if (children.empty()) {
children_str = "(no children)";
} else {
for (size_t i = 0; i < children.size(); i++) {
auto& child = children[i];
- int32_t child_id = tree_->IsValid(child) ? tree_->GetId(child) : -1;
+ AXNodeID child_id =
+ tree_->IsValid(child) ? tree_->GetId(child) : kInvalidAXNodeID;
if (i == 0)
children_str += "child_ids=" + base::NumberToString(child_id);
else
@@ -85,23 +82,22 @@ AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::NodeToString(
}
}
- int32_t parent_id = tree_->IsValid(tree_->GetParent(node))
- ? tree_->GetId(tree_->GetParent(node))
- : -1;
+ AXNodeID parent_id = tree_->IsValid(tree_->GetParent(node))
+ ? tree_->GetId(tree_->GetParent(node))
+ : kInvalidAXNodeID;
return base::StringPrintf("%s %s parent_id=%d", node_data.ToString().c_str(),
children_str.c_str(), parent_id);
}
-template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
-bool AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::Check(
- AXSourceNode node,
- std::string indent,
- std::string* output) {
+template <typename AXSourceNode>
+bool AXTreeSourceChecker<AXSourceNode>::Check(AXSourceNode node,
+ std::string indent,
+ std::string* output) {
*output += indent + NodeToString(node);
- int32_t node_id = tree_->GetId(node);
- if (node_id <= 0) {
+ AXNodeID node_id = tree_->GetId(node);
+ if (node_id <= kInvalidAXNodeID) {
std::string msg = base::StringPrintf(
"Got a node with id %d, but all node IDs should be >= 1:\n%s\n",
node_id, NodeToString(node).c_str());
@@ -110,9 +106,9 @@ bool AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::Check(
}
// Check parent.
- int32_t expected_parent_id = node_id_to_parent_id_map_[node_id];
+ AXNodeID expected_parent_id = node_id_to_parent_id_map_[node_id];
AXSourceNode parent = tree_->GetParent(node);
- if (expected_parent_id == -1) {
+ if (expected_parent_id == kInvalidAXNodeID) {
if (tree_->IsValid(parent)) {
std::string msg = base::StringPrintf(
"Node %d is the root, so its parent should be invalid, but we "
@@ -132,7 +128,7 @@ bool AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::Check(
*output = msg + *output;
return false;
}
- int32_t parent_id = tree_->GetId(parent);
+ AXNodeID parent_id = tree_->GetId(parent);
if (parent_id != expected_parent_id) {
AXSourceNode expected_parent = tree_->GetFromId(expected_parent_id);
std::string msg = base::StringPrintf(
@@ -161,7 +157,7 @@ bool AXTreeSourceChecker<AXSourceNode, AXNodeData, AXTreeData>::Check(
return false;
}
- int32_t child_id = tree_->GetId(child);
+ AXNodeID child_id = tree_->GetId(child);
if (node_id_to_parent_id_map_.find(child_id) !=
node_id_to_parent_id_map_.end()) {
*output += "\n" + indent + " ";
diff --git a/chromium/ui/accessibility/ax_tree_source_checker_unittest.cc b/chromium/ui/accessibility/ax_tree_source_checker_unittest.cc
index 85e315038c5..92eaabfd9c3 100644
--- a/chromium/ui/accessibility/ax_tree_source_checker_unittest.cc
+++ b/chromium/ui/accessibility/ax_tree_source_checker_unittest.cc
@@ -13,13 +13,11 @@
namespace ui {
namespace {
-struct FakeAXTreeData {};
-
struct FakeAXNode {
- int32_t id;
+ AXNodeID id;
ax::mojom::Role role;
- std::vector<int32_t> child_ids;
- int32_t parent_id;
+ std::vector<AXNodeID> child_ids;
+ AXNodeID parent_id;
};
// It's distracting to see an empty bounding box from every node, so do a
@@ -33,28 +31,27 @@ void CleanAXNodeDataString(std::string* error_str) {
// explicit. This allows us to test that AXTreeSourceChecker properly warns
// about errors in accessibility trees that have inconsistent parent/child
// links.
-class FakeAXTreeSource
- : public AXTreeSource<const FakeAXNode*, ui::AXNodeData, FakeAXTreeData> {
+class FakeAXTreeSource : public AXTreeSource<const FakeAXNode*> {
public:
- FakeAXTreeSource(std::vector<FakeAXNode> nodes, int32_t root_id)
+ FakeAXTreeSource(std::vector<FakeAXNode> nodes, AXNodeID root_id)
: nodes_(nodes), root_id_(root_id) {
for (size_t i = 0; i < nodes_.size(); ++i)
id_to_node_[nodes_[i].id] = &nodes_[i];
}
// AXTreeSource overrides.
- bool GetTreeData(FakeAXTreeData* data) const override { return true; }
+ bool GetTreeData(AXTreeData* data) const override { return true; }
const FakeAXNode* GetRoot() const override { return GetFromId(root_id_); }
- const FakeAXNode* GetFromId(int32_t id) const override {
+ const FakeAXNode* GetFromId(AXNodeID id) const override {
const auto& iter = id_to_node_.find(id);
if (iter != id_to_node_.end())
return iter->second;
return nullptr;
}
- int32_t GetId(const FakeAXNode* node) const override { return node->id; }
+ AXNodeID GetId(const FakeAXNode* node) const override { return node->id; }
void GetChildren(
const FakeAXNode* node,
@@ -88,18 +85,17 @@ class FakeAXTreeSource
private:
std::vector<FakeAXNode> nodes_;
- std::map<int32_t, FakeAXNode*> id_to_node_;
- int32_t root_id_;
+ std::map<AXNodeID, FakeAXNode*> id_to_node_;
+ AXNodeID root_id_;
};
} // namespace
-using FakeAXTreeSourceChecker =
- AXTreeSourceChecker<const FakeAXNode*, ui::AXNodeData, FakeAXTreeData>;
+using FakeAXTreeSourceChecker = AXTreeSourceChecker<const FakeAXNode*>;
TEST(AXTreeSourceCheckerTest, SimpleValidTree) {
std::vector<FakeAXNode> nodes = {
- {1, ax::mojom::Role::kRootWebArea, {2}, -1},
+ {1, ax::mojom::Role::kRootWebArea, {2}, kInvalidAXNodeID},
{2, ax::mojom::Role::kRootWebArea, {}, 1},
};
FakeAXTreeSource node_source(nodes, 1);
@@ -110,7 +106,7 @@ TEST(AXTreeSourceCheckerTest, SimpleValidTree) {
TEST(AXTreeSourceCheckerTest, BadRoot) {
std::vector<FakeAXNode> nodes = {
- {1, ax::mojom::Role::kRootWebArea, {2}, -1},
+ {1, ax::mojom::Role::kRootWebArea, {2}, kInvalidAXNodeID},
{2, ax::mojom::Role::kRootWebArea, {}, 1},
};
FakeAXTreeSource node_source(nodes, 3);
@@ -123,7 +119,7 @@ TEST(AXTreeSourceCheckerTest, BadRoot) {
TEST(AXTreeSourceCheckerTest, BadNodeIdOfRoot) {
std::vector<FakeAXNode> nodes = {
- {0, ax::mojom::Role::kRootWebArea, {2}, -1},
+ {0, ax::mojom::Role::kRootWebArea, {2}, kInvalidAXNodeID},
{2, ax::mojom::Role::kRootWebArea, {}, 0},
};
FakeAXTreeSource node_source(nodes, 0);
@@ -133,14 +129,14 @@ TEST(AXTreeSourceCheckerTest, BadNodeIdOfRoot) {
CleanAXNodeDataString(&error_string);
EXPECT_EQ(
"Got a node with id 0, but all node IDs should be >= 1:\n"
- "id=0 rootWebArea child_ids=2 parent_id=-1\n"
- "id=0 rootWebArea child_ids=2 parent_id=-1",
+ "id=0 rootWebArea child_ids=2 parent_id=0\n"
+ "id=0 rootWebArea child_ids=2 parent_id=0",
error_string);
}
TEST(AXTreeSourceCheckerTest, BadNodeIdOfChild) {
std::vector<FakeAXNode> nodes = {
- {1, ax::mojom::Role::kRootWebArea, {-5}, -1},
+ {1, ax::mojom::Role::kRootWebArea, {-5}, kInvalidAXNodeID},
{-5, ax::mojom::Role::kRootWebArea, {}, 1},
};
FakeAXTreeSource node_source(nodes, -5);
@@ -157,7 +153,7 @@ TEST(AXTreeSourceCheckerTest, BadNodeIdOfChild) {
TEST(AXTreeSourceCheckerTest, RootShouldNotBeNodeWithParent) {
std::vector<FakeAXNode> nodes = {
- {1, ax::mojom::Role::kRootWebArea, {2}, -1},
+ {1, ax::mojom::Role::kRootWebArea, {2}, kInvalidAXNodeID},
{2, ax::mojom::Role::kRootWebArea, {}, 1},
};
FakeAXTreeSource node_source(nodes, 2);
@@ -169,15 +165,15 @@ TEST(AXTreeSourceCheckerTest, RootShouldNotBeNodeWithParent) {
"Node 2 is the root, so its parent should be invalid, "
"but we got a node with id 1.\n"
"Node: id=2 rootWebArea (no children) parent_id=1\n"
- "Parent: id=1 rootWebArea child_ids=2 parent_id=-1\n"
+ "Parent: id=1 rootWebArea child_ids=2 parent_id=0\n"
"id=2 rootWebArea (no children) parent_id=1",
error_string);
}
TEST(AXTreeSourceCheckerTest, MissingParent) {
std::vector<FakeAXNode> nodes = {
- {1, ax::mojom::Role::kRootWebArea, {2}, -1},
- {2, ax::mojom::Role::kRootWebArea, {}, -1},
+ {1, ax::mojom::Role::kRootWebArea, {2}, kInvalidAXNodeID},
+ {2, ax::mojom::Role::kRootWebArea, {}, kInvalidAXNodeID},
};
FakeAXTreeSource node_source(nodes, 1);
FakeAXTreeSourceChecker checker(&node_source);
@@ -186,15 +182,15 @@ TEST(AXTreeSourceCheckerTest, MissingParent) {
CleanAXNodeDataString(&error_string);
EXPECT_EQ(
"Node 2 is not the root, but its parent was invalid:\n"
- "id=2 rootWebArea (no children) parent_id=-1\n"
- "id=1 rootWebArea child_ids=2 parent_id=-1\n"
- " id=2 rootWebArea (no children) parent_id=-1",
+ "id=2 rootWebArea (no children) parent_id=0\n"
+ "id=1 rootWebArea child_ids=2 parent_id=0\n"
+ " id=2 rootWebArea (no children) parent_id=0",
error_string);
}
TEST(AXTreeSourceCheckerTest, InvalidParent) {
std::vector<FakeAXNode> nodes = {
- {1, ax::mojom::Role::kRootWebArea, {2, 3}, -1},
+ {1, ax::mojom::Role::kRootWebArea, {2, 3}, kInvalidAXNodeID},
{2, ax::mojom::Role::kButton, {}, 1},
{3, ax::mojom::Role::kParagraph, {}, 2},
};
@@ -207,8 +203,8 @@ TEST(AXTreeSourceCheckerTest, InvalidParent) {
"Expected node 3 to have a parent of 1, but found a parent of 2.\n"
"Node: id=3 paragraph (no children) parent_id=2\n"
"Parent: id=2 button (no children) parent_id=1\n"
- "Expected parent: id=1 rootWebArea child_ids=2,3 parent_id=-1\n"
- "id=1 rootWebArea child_ids=2,3 parent_id=-1\n"
+ "Expected parent: id=1 rootWebArea child_ids=2,3 parent_id=0\n"
+ "id=1 rootWebArea child_ids=2,3 parent_id=0\n"
" id=2 button (no children) parent_id=1\n"
" id=3 paragraph (no children) parent_id=2",
error_string);
diff --git a/chromium/ui/accessibility/ax_tree_unittest.cc b/chromium/ui/accessibility/ax_tree_unittest.cc
index 0adce655607..22f87bfafa2 100644
--- a/chromium/ui/accessibility/ax_tree_unittest.cc
+++ b/chromium/ui/accessibility/ax_tree_unittest.cc
@@ -9,9 +9,10 @@
#include <memory>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
+#include "base/test/metrics/histogram_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_enum_util.h"
#include "ui/accessibility/ax_node.h"
@@ -78,7 +79,7 @@ bool IsNodeOffscreen(const AXTree& tree, int32_t id) {
class TestAXTreeObserver : public AXTreeObserver {
public:
- TestAXTreeObserver(AXTree* tree)
+ explicit TestAXTreeObserver(AXTree* tree)
: tree_(tree), tree_data_changed_(false), root_changed_(false) {
tree_->AddObserver(this);
}
@@ -96,7 +97,7 @@ class TestAXTreeObserver : public AXTreeObserver {
tree_data_changed_ = true;
}
- base::Optional<AXNode::AXID> unignored_parent_id_before_node_deleted;
+ base::Optional<AXNodeID> unignored_parent_id_before_node_deleted;
void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) override {
// When this observer function is called in an update, the actual node
// deletion has not happened yet. Verify that node still exists in the tree.
@@ -330,10 +331,9 @@ TEST(AXTreeTest, SerializeSimpleAXTree) {
initial_state.tree_data.title = "Title";
AXSerializableTree src_tree(initial_state);
- std::unique_ptr<AXTreeSource<const AXNode*, AXNodeData, AXTreeData>>
- tree_source(src_tree.CreateTreeSource());
- AXTreeSerializer<const AXNode*, AXNodeData, AXTreeData> serializer(
- tree_source.get());
+ std::unique_ptr<AXTreeSource<const AXNode*>> tree_source(
+ src_tree.CreateTreeSource());
+ AXTreeSerializer<const AXNode*> serializer(tree_source.get());
AXTreeUpdate update;
serializer.SerializeChanges(src_tree.root(), &update);
@@ -400,6 +400,7 @@ TEST(AXTreeTest, SerializeAXTreeUpdate) {
}
TEST(AXTreeTest, LeaveOrphanedDeletedSubtreeFails) {
+ base::HistogramTester histogram_tester;
AXTreeUpdate initial_state;
initial_state.root_id = 1;
initial_state.nodes.resize(3);
@@ -418,9 +419,13 @@ TEST(AXTreeTest, LeaveOrphanedDeletedSubtreeFails) {
update.nodes[0].id = 3;
EXPECT_FALSE(tree.Unserialize(update));
ASSERT_EQ("Nodes left pending by the update: 2", tree.error());
+ histogram_tester.ExpectUniqueSample(
+ "Accessibility.Reliability.Tree.UnserializeError",
+ AXTreeUnserializeError::kPendingNodes, 1);
}
TEST(AXTreeTest, LeaveOrphanedNewChildFails) {
+ base::HistogramTester histogram_tester;
AXTreeUpdate initial_state;
initial_state.root_id = 1;
initial_state.nodes.resize(1);
@@ -435,9 +440,13 @@ TEST(AXTreeTest, LeaveOrphanedNewChildFails) {
update.nodes[0].child_ids.push_back(2);
EXPECT_FALSE(tree.Unserialize(update));
ASSERT_EQ("Nodes left pending by the update: 2", tree.error());
+ histogram_tester.ExpectUniqueSample(
+ "Accessibility.Reliability.Tree.UnserializeError",
+ AXTreeUnserializeError::kPendingNodes, 1);
}
TEST(AXTreeTest, DuplicateChildIdFails) {
+ base::HistogramTester histogram_tester;
AXTreeUpdate initial_state;
initial_state.root_id = 1;
initial_state.nodes.resize(1);
@@ -453,9 +462,13 @@ TEST(AXTreeTest, DuplicateChildIdFails) {
update.nodes[1].id = 2;
EXPECT_FALSE(tree.Unserialize(update));
ASSERT_EQ("Node 1 has duplicate child id 2", tree.error());
+ histogram_tester.ExpectUniqueSample(
+ "Accessibility.Reliability.Tree.UnserializeError",
+ AXTreeUnserializeError::kDuplicateChild, 1);
}
TEST(AXTreeTest, InvalidReparentingFails) {
+ base::HistogramTester histogram_tester;
AXTreeUpdate initial_state;
initial_state.root_id = 1;
initial_state.nodes.resize(3);
@@ -479,6 +492,9 @@ TEST(AXTreeTest, InvalidReparentingFails) {
EXPECT_FALSE(tree.Unserialize(update));
ASSERT_EQ("Node 3 is not marked for destruction, would be reparented to 1",
tree.error());
+ histogram_tester.ExpectUniqueSample(
+ "Accessibility.Reliability.Tree.UnserializeError",
+ AXTreeUnserializeError::kReparent, 1);
}
TEST(AXTreeTest, NoReparentingOfRootIfNoNewRoot) {
@@ -2056,7 +2072,7 @@ TEST(AXTreeTest, UnignoredChildIteratorIncrementDecrementPastEnd) {
tree_update.nodes.resize(2);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].role = ax::mojom::Role::kWebArea;
+ tree_update.nodes[0].role = ax::mojom::Role::kRootWebArea;
tree_update.nodes[0].child_ids = {2};
tree_update.nodes[1].id = 2;
@@ -2131,7 +2147,7 @@ TEST(AXTreeTest, UnignoredChildIteratorIgnoredContainerSiblings) {
tree_update.nodes.resize(7);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].role = ax::mojom::Role::kWebArea;
+ tree_update.nodes[0].role = ax::mojom::Role::kRootWebArea;
tree_update.nodes[0].child_ids = {2, 4, 6};
tree_update.nodes[1].id = 2;
@@ -2961,9 +2977,9 @@ TEST(AXTreeTest, UnignoredSelection) {
AXTree::Selection unignored_selection =
test_ax_tree_manager.GetTree()->GetUnignoredSelection();
- EXPECT_EQ(AXNode::kInvalidAXID, unignored_selection.anchor_object_id);
+ EXPECT_EQ(kInvalidAXNodeID, unignored_selection.anchor_object_id);
EXPECT_EQ(-1, unignored_selection.anchor_offset);
- EXPECT_EQ(AXNode::kInvalidAXID, unignored_selection.focus_object_id);
+ EXPECT_EQ(kInvalidAXNodeID, unignored_selection.focus_object_id);
EXPECT_EQ(-1, unignored_selection.focus_offset);
struct SelectionData {
int32_t anchor_id;
@@ -4843,4 +4859,55 @@ TEST(AXTreeTest, TestIsInListMarker) {
ASSERT_EQ(false, inline_node2->IsInListMarker());
}
+TEST(AXTreeTest, UpdateFromOutOfSyncTree) {
+ ui::AXNodeData empty_document;
+ empty_document.id = 1;
+ empty_document.role = ax::mojom::Role::kRootWebArea;
+ ui::AXTreeUpdate empty_document_initial_update;
+ empty_document_initial_update.root_id = empty_document.id;
+ empty_document_initial_update.nodes.push_back(empty_document);
+
+ AXTree tree;
+ EXPECT_TRUE(tree.Unserialize(empty_document_initial_update));
+
+ ui::AXNodeData root;
+ root.id = 3;
+ root.role = ax::mojom::Role::kRootWebArea;
+ root.child_ids = {1};
+
+ ui::AXNodeData div;
+ div.id = 1;
+ div.role = ax::mojom::Role::kGenericContainer;
+
+ ui::AXTreeUpdate first_update;
+ first_update.root_id = root.id;
+ first_update.node_id_to_clear = root.id;
+ first_update.nodes = {root, div};
+
+ EXPECT_TRUE(tree.Unserialize(first_update));
+}
+
+TEST(AXTreeTest, UnserializeErrors) {
+ base::HistogramTester histogram_tester;
+ ui::AXNodeData empty_document;
+ empty_document.id = 1;
+ empty_document.role = ax::mojom::Role::kRootWebArea;
+ ui::AXTreeUpdate tree_update;
+ tree_update.root_id = empty_document.id;
+ tree_update.nodes.push_back(empty_document);
+
+ AXTree tree;
+ EXPECT_TRUE(tree.Unserialize(tree_update));
+
+ ui::AXTreeUpdate tree_update_3;
+ tree_update_3.root_id = empty_document.id;
+ ui::AXNodeData disconnected_node;
+ disconnected_node.id = 2;
+ tree_update_3.nodes.push_back(disconnected_node);
+ EXPECT_FALSE(tree.Unserialize(tree_update_3));
+ histogram_tester.ExpectUniqueSample(
+ "Accessibility.Reliability.Tree.UnserializeError",
+ AXTreeUnserializeError::kNotInTree, 1);
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree_update.cc b/chromium/ui/accessibility/ax_tree_update.cc
new file mode 100644
index 00000000000..b47132c1c17
--- /dev/null
+++ b/chromium/ui/accessibility/ax_tree_update.cc
@@ -0,0 +1,81 @@
+// Copyright 2021 The Chromium 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_update.h"
+
+#include "ui/accessibility/ax_tree_data.h"
+#include "base/strings/string_number_conversions.h"
+#include "ui/accessibility/ax_enum_util.h"
+
+namespace ui {
+
+AXTreeUpdate::AXTreeUpdate() = default;
+
+AXTreeUpdate::AXTreeUpdate(const ui::AXTreeUpdate& other) = default;
+
+AXTreeUpdate::~AXTreeUpdate() = default;
+
+std::string AXTreeUpdate::ToString() const {
+ std::string result;
+
+ if (has_tree_data) {
+ result += "AXTreeUpdate tree data:" + tree_data.ToString() + "\n";
+ }
+
+ if (node_id_to_clear != kInvalidAXNodeID) {
+ result += "AXTreeUpdate: clear node " +
+ base::NumberToString(node_id_to_clear) + "\n";
+ }
+
+ if (root_id != kInvalidAXNodeID) {
+ result += "AXTreeUpdate: root id " + base::NumberToString(root_id) + "\n";
+ }
+
+ if (event_from != ax::mojom::EventFrom::kNone)
+ result += "event_from=" + std::string(ui::ToString(event_from)) + "\n";
+ if (event_from_action != ax::mojom::Action::kNone)
+ result +=
+ "event_from_action=" + std::string(ui::ToString(event_from_action)) +
+ "\n";
+
+ if (!event_intents.empty()) {
+ result += "event_intents=[\n";
+ for (const auto& event_intent : event_intents)
+ result += " " + event_intent.ToString() + "\n";
+ result += "]\n";
+ }
+
+ // The challenge here is that we want to indent the nodes being updated
+ // so that parent/child relationships are clear, but we don't have access
+ // 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.
+ std::map<AXNodeID, int> id_to_indentation;
+ for (const AXNodeData& node_data : nodes) {
+ int indent = id_to_indentation[node_data.id];
+ result += std::string(2 * indent, ' ');
+ result += node_data.ToString() + "\n";
+ for (AXNodeID child_id : node_data.child_ids)
+ id_to_indentation[child_id] = indent + 1;
+ }
+
+ return result;
+}
+
+bool TreeUpdatesCanBeMerged(
+ const AXTreeUpdate& u1,
+ const AXTreeUpdate& u2) {
+ if (u2.node_id_to_clear)
+ return false;
+
+ if (u2.has_tree_data && u2.tree_data != u1.tree_data)
+ return false;
+
+ if (u2.root_id != u1.root_id)
+ return false;
+
+ return true;
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree_update.h b/chromium/ui/accessibility/ax_tree_update.h
index a27fc3b2377..3c69827d17f 100644
--- a/chromium/ui/accessibility/ax_tree_update.h
+++ b/chromium/ui/accessibility/ax_tree_update.h
@@ -12,8 +12,7 @@
#include <unordered_map>
#include <vector>
-#include "base/strings/string_number_conversions.h"
-#include "ui/accessibility/ax_enum_util.h"
+#include "ui/accessibility/ax_base_export.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_event_intent.h"
#include "ui/accessibility/ax_node_data.h"
@@ -49,9 +48,10 @@ namespace ui {
// placeholder must be updated within the same AXTreeUpdate, otherwise
// it's a fatal error. This guarantees the tree is always complete
// before or after an AXTreeUpdate.
-template<typename AXNodeData, typename AXTreeData> struct AXTreeUpdateBase {
- AXTreeUpdateBase() = default;
- ~AXTreeUpdateBase() = default;
+struct AX_BASE_EXPORT AXTreeUpdate {
+ AXTreeUpdate();
+ AXTreeUpdate(const AXTreeUpdate& other);
+ ~AXTreeUpdate();
// If |has_tree_data| is true, the value of |tree_data| should be used
// to update the tree data, otherwise it should be ignored.
@@ -63,13 +63,13 @@ template<typename AXNodeData, typename AXTreeData> struct AXTreeUpdateBase {
// all of its children and their descendants, but leaving that node in
// the tree. It's an error to clear a node but not subsequently update it
// as part of the tree update.
- int node_id_to_clear = 0;
+ AXNodeID node_id_to_clear = kInvalidAXNodeID;
// The id of the root of the tree, if the root is changing. This is
// required to be set if the root of the tree is changing or Unserialize
// will fail. If the root of the tree is not changing this is optional
// and it is allowed to pass 0.
- int root_id = 0;
+ AXNodeID root_id = kInvalidAXNodeID;
// A vector of nodes to update, according to the rules above.
std::vector<AXNodeData> nodes;
@@ -77,6 +77,9 @@ template<typename AXNodeData, typename AXTreeData> struct AXTreeUpdateBase {
// The source of the event which generated this tree update.
ax::mojom::EventFrom event_from = ax::mojom::EventFrom::kNone;
+ // The accessibility action that caused this tree update.
+ ax::mojom::Action event_from_action = ax::mojom::Action::kNone;
+
// The event intents associated with this tree update.
std::vector<AXEventIntent> event_intents;
@@ -86,71 +89,12 @@ template<typename AXNodeData, typename AXTreeData> struct AXTreeUpdateBase {
// TODO(dmazzoni): location changes
};
-using AXTreeUpdate = AXTreeUpdateBase<AXNodeData, AXTreeData>;
-
-template<typename AXNodeData, typename AXTreeData>
-std::string AXTreeUpdateBase<AXNodeData, AXTreeData>::ToString() const {
- std::string result;
-
- if (has_tree_data) {
- result += "AXTreeUpdate tree data:" + tree_data.ToString() + "\n";
- }
-
- if (node_id_to_clear != 0) {
- result += "AXTreeUpdate: clear node " +
- base::NumberToString(node_id_to_clear) + "\n";
- }
-
- if (root_id != 0) {
- result += "AXTreeUpdate: root id " + base::NumberToString(root_id) + "\n";
- }
-
- if (event_from != ax::mojom::EventFrom::kNone)
- result += "event_from=" + std::string(ui::ToString(event_from)) + "\n";
-
- if (!event_intents.empty()) {
- result += "event_intents=[\n";
- for (const auto& event_intent : event_intents)
- result += " " + event_intent.ToString() + "\n";
- result += "]\n";
- }
-
- // The challenge here is that we want to indent the nodes being updated
- // so that parent/child relationships are clear, but we don't have access
- // 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.
- 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, ' ');
- result += nodes[i].ToString() + "\n";
- for (size_t j = 0; j < nodes[i].child_ids.size(); ++j)
- id_to_indentation[nodes[i].child_ids[j]] = indent + 1;
- }
-
- return result;
-}
-
// Two tree updates can be merged into one if the second one
// doesn't clear a subtree, doesn't have new tree data, and
// doesn't have a new root id - in other words the second tree
// update consists of only changes to nodes.
-template <typename AXNodeData, typename AXTreeData>
-bool TreeUpdatesCanBeMerged(
- const AXTreeUpdateBase<AXNodeData, AXTreeData>& u1,
- const AXTreeUpdateBase<AXNodeData, AXTreeData>& u2) {
- if (u2.node_id_to_clear)
- return false;
-
- if (u2.has_tree_data && u2.tree_data != u1.tree_data)
- return false;
-
- if (u2.root_id != u1.root_id)
- return false;
-
- return true;
-}
+bool AX_BASE_EXPORT TreeUpdatesCanBeMerged(const AXTreeUpdate& u1,
+ const AXTreeUpdate& u2);
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree_update_forward.h b/chromium/ui/accessibility/ax_tree_update_forward.h
index c59dfaaad73..61b9557153b 100644
--- a/chromium/ui/accessibility/ax_tree_update_forward.h
+++ b/chromium/ui/accessibility/ax_tree_update_forward.h
@@ -7,11 +7,7 @@
namespace ui {
-struct AXNodeData;
-struct AXTreeData;
-template <typename A, typename B>
-struct AXTreeUpdateBase;
-using AXTreeUpdate = AXTreeUpdateBase<AXNodeData, AXTreeData>;
+struct AXTreeUpdate;
} // namespace ui
diff --git a/chromium/ui/accessibility/extensions/BUILD.gn b/chromium/ui/accessibility/extensions/BUILD.gn
index d824a5bb55c..c290728ea4b 100644
--- a/chromium/ui/accessibility/extensions/BUILD.gn
+++ b/chromium/ui/accessibility/extensions/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//tools/grit/grit_rule.gni")
group("extensions") {
@@ -9,14 +10,14 @@ group("extensions") {
":caretbrowsing",
":colorenhancer",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "chromevoxclassic:chromevox" ]
}
}
group("extension_tests") {
testonly = true
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps = [ "chromevoxclassic:chromevox_tests" ]
}
}
@@ -75,6 +76,10 @@ locale_files = [
"_locales/vi/messages.json",
"_locales/zh_CN/messages.json",
"_locales/zh_TW/messages.json",
+
+ # Pseudolocales
+ "_locales/ar_XB/messages.json",
+ "_locales/en_XA/messages.json",
]
#
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/BUILD.gn b/chromium/ui/accessibility/extensions/chromevoxclassic/BUILD.gn
index dfecb666555..8975eaecaaf 100644
--- a/chromium/ui/accessibility/extensions/chromevoxclassic/BUILD.gn
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/BUILD.gn
@@ -225,7 +225,6 @@ chromevox_out_dir = "$root_out_dir/chromevoxclassic"
group("chromevox") {
deps = [
- ":accessibility_strings",
":chromevox_background_script",
":chromevox_content_script",
":chromevox_copied_files",
@@ -316,6 +315,7 @@ run_jsbundler("chromevox_copied_files") {
"chromevox/injected/api_util.js",
"chromevox/injected/mathjax.js",
"chromevox/injected/mathjax_external_util.js",
+ "chromevox/injected/shadydom_loader.js",
"cvox2/background/background.html",
"cvox2/background/earcons/control.wav",
"cvox2/background/earcons/selection.wav",
@@ -519,9 +519,11 @@ test("chromevox_tests") {
deps = [
":chromevox_unitjs_tests",
+ "//ash/constants",
"//base",
"//base:i18n",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//chrome:browser_tests_pak",
"//chrome:packed_resources",
"//chrome:resources",
@@ -533,7 +535,7 @@ test("chromevox_tests") {
"//chrome/test:test_support",
"//chrome/test:test_support_ui",
"//chrome/test/data:web_ui_test_bindings",
- "//chromeos/constants:constants",
+ "//components/webapps/browser",
"//content/test:test_support",
"//extensions/browser:test_support",
"//testing/gmock",
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/README b/chromium/ui/accessibility/extensions/chromevoxclassic/README
index 586478df3c5..baf5f73aac7 100644
--- a/chromium/ui/accessibility/extensions/chromevoxclassic/README
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/README
@@ -21,6 +21,11 @@ assets, gets placed in
out/Release/chromevoxclassic.
+The one exception is ./_locales. You must copy this directory manually to
+out/Release/chromevoxclassic.
+
+These translations are no longer part of mainline ChromeVox.
+
#Loading and Testing
Go to chrome://extensions, and click "Load
Unpacked". Select out/Release/chromevoxclassic.
@@ -46,3 +51,21 @@ paths are verbalized using entirely different code paths.
Once confirmed, the entire directory can be uploaded once zipped to the Chrome
webstore.
+
+### Third party files
+
+The extension currently depends on a shim to polyfill shadow DOM. This file is located at:
+./shadydom.js.
+
+It is not checked into the repository, but can be obtained by building:
+https://github.com/webcomponents/polyfills/
+(packages/shadydom).
+
+You can test things work by visiting any polymer app e.g.
+chrome://settings
+
+## A final note on branding
+
+In order to further differentiate ChromeVox from ChromeVox Classic, the Classic
+extension is now simply known as "Screen Reader" and scrubbed of the ChromeVox
+brand. \ No newline at end of file
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/background/tabs_api_handler.js b/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/background/tabs_api_handler.js
index 000462fae0e..350ce628a9e 100644
--- a/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/background/tabs_api_handler.js
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/background/tabs_api_handler.js
@@ -208,15 +208,6 @@ cvox.TabsApiHandler.prototype = {
* @private
*/
refreshAutomationHandler_: function(tabId) {
- if (!cvox.ChromeVox.isMac)
- return;
-
- chrome.automation.getTree(tabId, function(node) {
- if (this.handler_)
- this.handler_.removeAllListeners();
-
- this.handler_ = new TabsAutomationHandler(node);
- }.bind(this));
},
/**
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/api.js b/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/api.js
index 30947603953..9c05e4c1ea3 100644
--- a/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/api.js
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/api.js
@@ -80,7 +80,9 @@ if (typeof(goog) != 'undefined' && goog.require) {
}
channel = new MessageChannel();
- window.postMessage(PORT_SETUP_MSG, [channel.port2], '*');
+ window.postMessage(
+ PORT_SETUP_MSG, '*' /* target origin */,
+ [channel.port2] /* transfer */);
channel.port1.onmessage = function(event) {
if (event.data == DISCONNECT_MSG) {
channel = null;
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/mathjax.js b/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/mathjax.js
index 1b926721519..50c99fa0659 100644
--- a/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/mathjax.js
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/mathjax.js
@@ -38,7 +38,9 @@ if (typeof(goog) != 'undefined' && goog.require) {
channel_.port1.onmessage = function(evt) {
cvox.MathJax.execMessage(evt.data);
};
- window.postMessage('cvox.MathJaxPortSetup', '*', [channel_.port2]);
+ window.postMessage(
+ 'cvox.MathJaxPortSetup', '*' /* target origin */,
+ [channel_.port2] /* transfer */);
};
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/pdf_processor.js b/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/pdf_processor.js
index 5b232946476..b443fa1398a 100644
--- a/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/pdf_processor.js
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/pdf_processor.js
@@ -73,7 +73,7 @@ cvox.PdfProcessor.processEmbeddedPdfs = function() {
cvox.PdfProcessor.process = function() {
cvox.PdfProcessor.pageCount = null;
cvox.PdfProcessor.pageIndex = null;
- window.postMessage({'type': 'getAccessibilityJSON'}, '*');
+ window.postMessage({'type': 'getAccessibilityJSON'}, '*' /* target origin */);
};
/**
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/shadydom_loader.js b/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/shadydom_loader.js
new file mode 100644
index 00000000000..15a1c8ab80e
--- /dev/null
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/chromevox/injected/shadydom_loader.js
@@ -0,0 +1,22 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Load the Shady DOM polyfill as soon as possible.
+(function() {
+ function loadScripts() {
+ if (!document.head) {
+ setTimeout(loadScripts, 0);
+ return;
+ }
+ var script1 = document.createElement('script');
+ script1.innerHTML = `
+ window.ShadyDOM = {force: true, noPatch: true};
+ `;
+ var script2 = document.createElement('script');
+ script2.src = chrome.extension.getURL('/shadydom.js');
+ document.head.prepend(script1);
+ document.head.prepend(script2);
+ }
+ loadScripts();
+}());
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/common/interframe.js b/chromium/ui/accessibility/extensions/chromevoxclassic/common/interframe.js
index 8d7b7fc117f..d13165e4894 100644
--- a/chromium/ui/accessibility/extensions/chromevoxclassic/common/interframe.js
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/common/interframe.js
@@ -132,7 +132,7 @@ cvox.Interframe.addListener = function(listener) {
cvox.Interframe.sendMessageToWindow = function(message, window) {
var encodedMessage = cvox.Interframe.IF_MSG_PREFIX +
cvox.ChromeVoxJSON.stringify(message, null, null);
- window.postMessage(encodedMessage, '*');
+ window.postMessage(encodedMessage, '*' /* target origin */);
};
/**
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/cvox2/background/desktop_automation_handler.js b/chromium/ui/accessibility/extensions/chromevoxclassic/cvox2/background/desktop_automation_handler.js
index 0b2ac9ba18c..0c0cd11c856 100644
--- a/chromium/ui/accessibility/extensions/chromevoxclassic/cvox2/background/desktop_automation_handler.js
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/cvox2/background/desktop_automation_handler.js
@@ -42,7 +42,8 @@ DesktopAutomationHandler = function(node) {
this.lastValueChanged_ = new Date(0);
var e = EventType;
- this.addListener_(e.ACTIVEDESCENDANTCHANGED, this.onActiveDescendantChanged);
+ this.addListener_(
+ e.ACTIVE_DESCENDANT_CHANGED, this.onActiveDescendantChanged);
this.addListener_(e.ALERT, this.onAlert);
this.addListener_(e.ARIA_ATTRIBUTE_CHANGED, this.onEventIfInRange);
this.addListener_(e.CHECKED_STATE_CHANGED, this.onEventIfInRange);
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/host/chrome/braille_background.js b/chromium/ui/accessibility/extensions/chromevoxclassic/host/chrome/braille_background.js
index 7ac49299d29..8dd3ab3a7b9 100644
--- a/chromium/ui/accessibility/extensions/chromevoxclassic/host/chrome/braille_background.js
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/host/chrome/braille_background.js
@@ -63,7 +63,7 @@ cvox.BrailleBackground = function(opt_displayManagerForTest,
/** @override */
cvox.BrailleBackground.prototype.write = function(params) {
- this.setContent_(params, null);
+ // Stubbed out.
};
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/manifest.json.jinja2 b/chromium/ui/accessibility/extensions/chromevoxclassic/manifest.json.jinja2
index c0bb2af6b6e..3bbbfa01e98 100644
--- a/chromium/ui/accessibility/extensions/chromevoxclassic/manifest.json.jinja2
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/manifest.json.jinja2
@@ -5,46 +5,15 @@
"background": {
"page": "cvox2/background/background.html"
},
- "commands": {
- "nextObject": {
- "description": "__MSG_CHROMEVOX_NEXT_OBJECT__",
- "suggested_key": {
- "default": "Alt+Shift+Right"
- }
- },
- "performDefaultAction": {
- "description": "__MSG_CHROMEVOX_PERFORM_DEFAULT_ACTION__",
- "suggested_key": {
- "default": "Alt+Shift+Space"
- }
- },
- "previousObject": {
- "description": "__MSG_CHROMEVOX_PREVIOUS_OBJECT__",
- "suggested_key": {
- "default": "Alt+Shift+Left"
- }
- },
- "readFromHere": {
- "description": "__MSG_CHROMEVOX_READ_FROM_HERE__",
- "suggested_key": {
- "default": "Alt+Shift+R"
- }
- },
- "toggleChromeVoxVersion": {
- "description": "__MSG_CHROMEVOX_TOGGLE_CHROMEVOX__",
- "suggested_key": {
- "default": "Alt+Shift+Q"
- }
- }
- },
"content_scripts": [ {
"all_frames": true,
- "exclude_globs": [ ],
- "js": [ "chromeVoxChromePageScript.js" ],
- "matches": [ "\u003Call_urls>" ]
+ "exclude_globs": [ "devtools://*" ],
+ "run_at": "document_start",
+ "js": [ "chromevox/injected/shadydom_loader.js", "chromeVoxChromePageScript.js" ],
+ "matches": [ "<all_urls>" ]
} ],
"default_locale": "en",
- "description": "__MSG_CHROMEVOX_DESCRIPTION__",
+ "description": "A web-powered screen reader",
"icons": {
"128": "images/chromevox-128.png",
"16": "images/chromevox-16.png",
@@ -52,10 +21,10 @@
},
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEGBi/oD7Yl/Y16w3+gee/95/EUpRZ2U6c+8orV5ei+3CRsBsoXI/DPGBauZ3rWQ47aQnfoG00sXigFdJA2NhNK9OgmRA2evnsRRbjYm2BG1twpaLsgQPPus3PyczbDCvhFu8k24wzFyEtxLrfxAGBseBPb9QrCz7B4k2QgxD/CwIDAQAB",
"manifest_version": 2,
- "name": "__MSG_CHROMEVOX_NAME__",
+ "name": "Screen Reader",
"options_page": "chromevox/background/options.html",
- "permissions": [ "accessibilityPrivate", "bookmarks", "brailleDisplayPrivate", "commands.accessibility", "commandLinePrivate", "experimental", "history", "notifications", "storage", "tabs", "tts", "virtualKeyboardPrivate", "\u003Call_urls>" ],
+ "permissions": [ "accessibilityPrivate", "bookmarks", "history", "notifications", "storage", "tabs", "tts", "<all_urls>" ],
"update_url": "https://clients2.google.com/service/update2/crx",
- "version": "53.0.2784.6",
- "web_accessible_resources": [ "chromevox/background/keymaps/next_keymap.json", "chromevox/injected/api.js", "chromevox/injected/api_util.js", "chromevox/injected/mathjax.js", "chromevox/injected/mathjax_external_util.js" ]
+ "version": "53.0.2784.11",
+ "web_accessible_resources": [ "chromevox/background/keymaps/next_keymap.json", "chromevox/injected/api.js", "chromevox/injected/api_util.js", "chromevox/injected/mathjax.js", "chromevox/injected/mathjax_external_util.js", "shadydom.js" ]
}
diff --git a/chromium/ui/accessibility/extensions/chromevoxclassic/testing/chromevox_unittest_base.js b/chromium/ui/accessibility/extensions/chromevoxclassic/testing/chromevox_unittest_base.js
index 01fcc5b6bdb..884d376cce2 100644
--- a/chromium/ui/accessibility/extensions/chromevoxclassic/testing/chromevox_unittest_base.js
+++ b/chromium/ui/accessibility/extensions/chromevoxclassic/testing/chromevox_unittest_base.js
@@ -10,7 +10,9 @@ GEN_INCLUDE([
'//chrome/browser/resources/chromeos/accessibility/chromevox/testing/' +
'common.js',
'//chrome/browser/resources/chromeos/accessibility/common/testing/' +
- 'callback_helper.js'
+ 'callback_helper.js',
+ '//chrome/browser/resources/chromeos/accessibility/common/testing/' +
+ 'common.js'
]);
/**
diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings.grd b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings.grd
index 0f59ced5340..84148eb533b 100644
--- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings.grd
+++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings.grd
@@ -59,6 +59,10 @@
<output filename="_locales/vi/messages.json" type="chrome_messages_json" lang="vi"/>
<output filename="_locales/zh_CN/messages.json" type="chrome_messages_json" lang="zh-CN"/>
<output filename="_locales/zh_TW/messages.json" type="chrome_messages_json" lang="zh-TW"/>
+
+ <!-- Pseudolocales -->
+ <output filename="_locales/ar_XB/messages.json" type="chrome_messages_json" lang="ar-XB"/>
+ <output filename="_locales/en_XA/messages.json" type="chrome_messages_json" lang="en-XA"/>
</outputs>
<translations>
<file path="accessibility_extensions_strings_af.xtb" lang="af" />
@@ -143,7 +147,7 @@
<file path="accessibility_extensions_strings_zh-TW.xtb" lang="zh-TW" />
<file path="accessibility_extensions_strings_zu.xtb" lang="zu" />
</translations>
- <release allow_pseudo="false" seq="1">
+ <release seq="1">
<messages fallback_to_english="true">
<!-- Alt extension -->
diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_be.xtb b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_be.xtb
index 15d89fb8156..e91b12632b1 100644
--- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_be.xtb
+++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_be.xtb
@@ -30,7 +30,7 @@
<translation id="4394049700291259645">Выключыць</translation>
<translation id="4769065380738716500">Відарысы заменены на альтэрнатыўны тэкст.</translation>
<translation id="4896660567607030658">Не трэба зваротнай сувязі, проста паказаць курсор.</translation>
-<translation id="4937901943818762779">Дазволіць аніміраваныя відарысы, але толькі аднойчы.</translation>
+<translation id="4937901943818762779">Дазволіць анімаваныя відарысы, але толькі аднойчы.</translation>
<translation id="4949131196216960195">Каб уключыць навігацыю клавішамі, націсніце &lt;span class='key'&gt;клавішу пошуку&lt;/span&gt; + &lt;img src='increase_brightness.png'&gt; (клавіша павелічэння яркасці, або F7). Каб выключыць функцыю, націсніце гэту клавішу яшчэ раз.</translation>
<translation id="4954450790315188152">Калі навігацыя клавішамі ўключана:</translation>
<translation id="5041932793799765940">Рэгуліроўка колеру</translation>
diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_fi.xtb b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_fi.xtb
index 03a3c76e854..165a7cd8ee4 100644
--- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_fi.xtb
+++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_fi.xtb
@@ -58,7 +58,7 @@
<translation id="7384431257964758081">Korkea kontrasti on käytössä</translation>
<translation id="7586636300921797327">Vaihe 2: liikuta liukusäädintä, kunnes kaikki tähdet ovat näkyvissä
valitulla rivillä.</translation>
-<translation id="7658239707568436148">Peruuta</translation>
+<translation id="7658239707568436148">Peru</translation>
<translation id="786423340267544509">Lisää reunus elementteihin, joissa on aria-describedat- tai longdesc-attribuutteja.</translation>
<translation id="7942349550061667556">Punainen</translation>
<translation id="8260673944985561857">Näppäimistöselaamisen asetukset</translation>
diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_nl.xtb b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_nl.xtb
index f1a75fc460c..ba3f67ef04c 100644
--- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_nl.xtb
+++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_nl.xtb
@@ -6,14 +6,14 @@
<translation id="145360476452865422">Beleid ten aanzien van animatie:</translation>
<translation id="1555130319947370107">Blauw</translation>
<translation id="1588438908519853928">Normaal</translation>
-<translation id="1591070050619849194">Alle afbeeldingsanimatie uitschakelen.</translation>
+<translation id="1591070050619849194">Alle afbeeldingsanimatie uitzetten.</translation>
<translation id="1703735871906654364">Bladeren met navigatietoetsen</translation>
<translation id="1791496371305830581">Alle afbeeldingen met animaties toestaan.</translation>
-<translation id="1996252509865389616">Inschakelen?</translation>
+<translation id="1996252509865389616">Aanzetten?</translation>
<translation id="2079545284768500474">Ongedaan maken</translation>
<translation id="2179565792157161713">Lange beschrijving openen in nieuw tabblad</translation>
<translation id="2223143012868735942">Een aanpasbaar kleurenfilter dat wordt toegepast op webpagina's om de kleurperceptie te verbeteren.</translation>
-<translation id="2394933097471027016">Nu uitproberen - Bladeren met navigatietoetsen is altijd ingeschakeld op deze pagina!</translation>
+<translation id="2394933097471027016">Probeer het nu: Bladeren met navigatietoetsen staat altijd aan op deze pagina!</translation>
<translation id="2471847333270902538">Kleurenschema voor <ph name="SITE" />:</translation>
<translation id="2648340354586434750">Houd de toets &lt;span class='key'&gt;Option&lt;/span&gt; ingedrukt om van woord naar woord te springen.</translation>
<translation id="2795227192542594043">Deze extensie biedt je een verplaatsbare muisaanwijzer in de webpagina, zodat je tekst kunt selecteren met het toetsenbord.</translation>
@@ -21,26 +21,26 @@
<translation id="2965611304828530558">&lt;p&gt;Wanneer je een link of bedieningselement bereikt, wordt het betreffende item automatisch gemarkeerd. Druk op &lt;span class='key'&gt;Enter&lt;/span&gt; om op een link of knop te klikken. &lt;/p&gt; &lt;p&gt; Wanneer een gemarkeerd bedieningselement (zoals een tekstvak of een lijstvak) invoer met pijltoetsen registreert, druk je op &lt;span class='key'&gt;Esc&lt;/span&gt; gevolgd door de pijl-links of -rechts om door te gaan met Bladeren met navigatietoetsen. &lt;/p&gt; &lt;p&gt; Je kunt eventueel ook op &lt;span class='key'&gt;Tab&lt;/span&gt; drukken om naar het volgende markeerbare bedieningselement te springen. &lt;/p&gt;</translation>
<translation id="3252573918265662711">Instellen</translation>
<translation id="3410969471888629217">Aanpassingen voor site negeren</translation>
-<translation id="3435896845095436175">Inschakelen</translation>
+<translation id="3435896845095436175">Aanzetten</translation>
<translation id="3622586652998721735">Instellen als standaardschema</translation>
<translation id="3812541808639806898">Alt-tekstviewer voor afbeelding</translation>
<translation id="381767806621926835">Klik op een item met een kenmerk 'longdesc' of 'aria-describedat' om de lange beschrijving te openen.</translation>
<translation id="4023902424053835668">Door de tekst van webpagina's bladeren met de pijltoetsen.</translation>
<translation id="4388820049312272371">De positie van de muisaanwijzer markeren met een snelle knippering.</translation>
-<translation id="4394049700291259645">Uitschakelen</translation>
+<translation id="4394049700291259645">Uitzetten</translation>
<translation id="4769065380738716500">Afbeeldingen zijn vervangen door de alt-tekst.</translation>
-<translation id="4896660567607030658">Geen feedback, alleen de muisaanwijzer weergeven</translation>
+<translation id="4896660567607030658">Geen feedback, alleen de muisaanwijzer tonen</translation>
<translation id="4937901943818762779">Afbeeldingen met animaties toestaan, maar slechts één keer.</translation>
-<translation id="4949131196216960195">Druk op &lt;span class='key'&gt;Zoeken&lt;/span&gt; + &lt;img src='increase_brightness.png'&gt; (de toets voor het verhogen van de helderheid of F7) om 'Bladeren met navigatietoetsen' in te schakelen. Druk hier nogmaals op om dit weer uit te schakelen.</translation>
-<translation id="4954450790315188152">Wanneer Bladeren met navigatietoetsen is ingeschakeld:</translation>
+<translation id="4949131196216960195">Druk op &lt;span class='key'&gt;Zoeken&lt;/span&gt; + &lt;img src='increase_brightness.png'&gt; (de toets voor het verhogen van de helderheid of F7) om Bladeren met navigatietoetsen aan te zetten. Druk hier nogmaals op om dit weer uit te zetten.</translation>
+<translation id="4954450790315188152">Als Bladeren met navigatietoetsen aanstaat:</translation>
<translation id="5041932793799765940">Kleuraanpassing</translation>
<translation id="5094574508723441140">Verhoogd contrast</translation>
<translation id="5173942593318174089">De positie van de muisaanwijzer markeren met een animatie.</translation>
<translation id="5287723860611749454">&lt;p&gt;Gebruik de pijltoetsen om door het document te navigeren. &lt;/p&gt;&lt;p&gt;Klik ergens om de muisaanwijzer naar de desbetreffende locatie te verplaatsten. &lt;/p&gt; &lt;p&gt; Gebruik de toets &lt;span class='key'&gt;Shift&lt;/span&gt; in combinatie met de pijltoetsen om tekst te selecteren.&lt;/p&gt;</translation>
<translation id="5331422999063554397">Omgekeerde kleur</translation>
-<translation id="5555153510860501336">Hoog contrast is uitgeschakeld</translation>
+<translation id="5555153510860501336">Hoog contrast staat uit</translation>
<translation id="5558600050691192317">Toetsenbordopdrachten</translation>
-<translation id="5594989420907487559">Animaties slechts één keer uitvoeren of animatie volledig uitschakelen.</translation>
+<translation id="5594989420907487559">Animaties slechts één keer uitvoeren of animatie volledig uitzetten.</translation>
<translation id="5631241868147802353">Standaardkleurenschema:</translation>
<translation id="5650358096585648000">Visuele feedback</translation>
<translation id="5710185147685935461">Het kleurenschema van de webpagina's wijzigen om omkeren zodat ze beter leesbaar zijn.</translation>
@@ -55,7 +55,7 @@
<translation id="690628312087070417">Wanneer het caret-teken een grote afstand overbrugt:</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="7379645913608427028">Mate</translation>
-<translation id="7384431257964758081">Hoog contrast is ingeschakeld</translation>
+<translation id="7384431257964758081">Hoog contrast staat aan</translation>
<translation id="7586636300921797327">Stap 2: pas de schuifregelaar aan totdat alle sterren op de geselecteerde rij zichtbaar zijn</translation>
<translation id="7658239707568436148">Annuleren</translation>
<translation id="786423340267544509">Een kader toevoegen aan elementen met een kenmerk 'aria-describedat' of 'longdesc'.</translation>
@@ -63,6 +63,6 @@
<translation id="8260673944985561857">Opties voor het bladeren met navigatietoetsen</translation>
<translation id="8321034316479930120">Beleid ten aanzien van animatie</translation>
<translation id="8480209185614411573">Hoog contrast</translation>
-<translation id="8609925175482059018">Druk op &lt;span class='key'&gt;F7&lt;/span&gt; om Bladeren met navigatietoetsen in te schakelen. Druk nogmaals op de toets om de functie uit te schakelen.</translation>
+<translation id="8609925175482059018">Druk op &lt;span class='key'&gt;F7&lt;/span&gt; om Bladeren met navigatietoetsen aan te zetten. Druk nogmaals op de toets om de functie uit te zetten.</translation>
<translation id="894241283505723656">Lange beschrijvingen in contextmenu</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/accessibility/mojom/BUILD.gn b/chromium/ui/accessibility/mojom/BUILD.gn
index 654241c270b..b934284cf27 100644
--- a/chromium/ui/accessibility/mojom/BUILD.gn
+++ b/chromium/ui/accessibility/mojom/BUILD.gn
@@ -37,7 +37,7 @@ mojom("mojom") {
]
traits_sources = [ "ax_action_data_mojom_traits.cc" ]
traits_headers = [ "ax_action_data_mojom_traits.h" ]
- traits_public_deps = [ "//ui/accessibility" ]
+ traits_public_deps = [ "//ui/accessibility:ax_base" ]
},
{
types = [
@@ -72,7 +72,7 @@ mojom("mojom") {
]
traits_sources = [ "ax_event_intent_mojom_traits.cc" ]
traits_headers = [ "ax_event_intent_mojom_traits.h" ]
- traits_public_deps = [ "//ui/accessibility" ]
+ traits_public_deps = [ "//ui/accessibility:ax_base" ]
},
{
types = [
@@ -83,7 +83,7 @@ mojom("mojom") {
]
traits_sources = [ "ax_event_mojom_traits.cc" ]
traits_headers = [ "ax_event_mojom_traits.h" ]
- traits_public_deps = [ "//ui/accessibility" ]
+ traits_public_deps = [ "//ui/accessibility:ax_base" ]
},
{
types = [
@@ -94,7 +94,7 @@ mojom("mojom") {
]
traits_sources = [ "ax_node_data_mojom_traits.cc" ]
traits_headers = [ "ax_node_data_mojom_traits.h" ]
- traits_public_deps = [ "//ui/accessibility" ]
+ traits_public_deps = [ "//ui/accessibility:ax_base" ]
},
{
types = [
@@ -121,7 +121,7 @@ mojom("mojom") {
]
traits_sources = [ "ax_tree_data_mojom_traits.cc" ]
traits_headers = [ "ax_tree_data_mojom_traits.h" ]
- traits_public_deps = [ "//ui/accessibility" ]
+ traits_public_deps = [ "//ui/accessibility:ax_base" ]
},
{
types = [
@@ -132,7 +132,7 @@ mojom("mojom") {
]
traits_sources = [ "ax_tree_id_mojom_traits.cc" ]
traits_headers = [ "ax_tree_id_mojom_traits.h" ]
- traits_public_deps = [ "//ui/accessibility" ]
+ traits_public_deps = [ "//ui/accessibility:ax_base" ]
},
{
types = [
@@ -143,7 +143,7 @@ mojom("mojom") {
]
traits_sources = [ "ax_tree_update_mojom_traits.cc" ]
traits_headers = [ "ax_tree_update_mojom_traits.h" ]
- traits_public_deps = [ "//ui/accessibility" ]
+ traits_public_deps = [ "//ui/accessibility:ax_base" ]
},
]
}
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 e8f9364a1f8..6dd7d58eb2c 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
@@ -34,8 +34,7 @@ TEST(AXActionDataMojomTraitsTest, RoundTrip) {
input.hit_test_event_to_fire = ax::mojom::Event::kFocus;
ui::AXActionData output;
- EXPECT_TRUE(
- SerializeAndDeserialize<ax::mojom::AXActionData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXActionData>(input, output));
EXPECT_EQ(output.action, ax::mojom::Action::kBlur);
EXPECT_EQ(output.target_tree_id, input.target_tree_id);
diff --git a/chromium/ui/accessibility/mojom/ax_event.mojom b/chromium/ui/accessibility/mojom/ax_event.mojom
index 857af93c03c..5a42cf087b5 100644
--- a/chromium/ui/accessibility/mojom/ax_event.mojom
+++ b/chromium/ui/accessibility/mojom/ax_event.mojom
@@ -12,6 +12,7 @@ struct AXEvent {
Event event_type;
int32 id;
EventFrom event_from;
+ Action event_from_action;
array<EventIntent> event_intents;
int32 action_request_id;
};
diff --git a/chromium/ui/accessibility/mojom/ax_event_intent_mojom_traits_unittest.cc b/chromium/ui/accessibility/mojom/ax_event_intent_mojom_traits_unittest.cc
index f089744d886..a9544670a04 100644
--- a/chromium/ui/accessibility/mojom/ax_event_intent_mojom_traits_unittest.cc
+++ b/chromium/ui/accessibility/mojom/ax_event_intent_mojom_traits_unittest.cc
@@ -18,7 +18,7 @@ TEST(AXEventIntentMojomTraitsTest, RoundTripWithEditingIntent) {
input.input_event_type = ax::mojom::InputEventType::kInsertLineBreak;
ui::AXEventIntent output;
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::EventIntent>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::EventIntent>(input, output));
EXPECT_EQ(ax::mojom::Command::kInsert, output.command);
EXPECT_EQ(ax::mojom::InputEventType::kInsertLineBreak,
output.input_event_type);
@@ -33,7 +33,7 @@ TEST(AXEventIntentMojomTraitsTest, RoundTripWithSelectionIntent) {
input.move_direction = ax::mojom::MoveDirection::kForward;
ui::AXEventIntent output;
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::EventIntent>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::EventIntent>(input, output));
EXPECT_EQ(ax::mojom::Command::kMoveSelection, output.command);
EXPECT_EQ(ax::mojom::InputEventType::kNone, output.input_event_type);
EXPECT_EQ(ax::mojom::TextBoundary::kWordEnd, output.text_boundary);
diff --git a/chromium/ui/accessibility/mojom/ax_event_mojom_traits.cc b/chromium/ui/accessibility/mojom/ax_event_mojom_traits.cc
index 1b927eab4a6..f364ccca62b 100644
--- a/chromium/ui/accessibility/mojom/ax_event_mojom_traits.cc
+++ b/chromium/ui/accessibility/mojom/ax_event_mojom_traits.cc
@@ -13,6 +13,7 @@ bool StructTraits<ax::mojom::AXEventDataView, ui::AXEvent>::Read(
out->event_type = data.event_type();
out->id = data.id();
out->event_from = data.event_from();
+ out->event_from_action = data.event_from_action();
out->action_request_id = data.action_request_id();
return data.ReadEventIntents(&out->event_intents);
}
diff --git a/chromium/ui/accessibility/mojom/ax_event_mojom_traits.h b/chromium/ui/accessibility/mojom/ax_event_mojom_traits.h
index c1922345251..e1a900e4e27 100644
--- a/chromium/ui/accessibility/mojom/ax_event_mojom_traits.h
+++ b/chromium/ui/accessibility/mojom/ax_event_mojom_traits.h
@@ -24,6 +24,9 @@ struct StructTraits<ax::mojom::AXEventDataView, ui::AXEvent> {
static ax::mojom::EventFrom event_from(const ui::AXEvent& p) {
return p.event_from;
}
+ static ax::mojom::Action event_from_action(const ui::AXEvent& p) {
+ return p.event_from_action;
+ }
static std::vector<ui::AXEventIntent> event_intents(const ui::AXEvent& p) {
return p.event_intents;
}
diff --git a/chromium/ui/accessibility/mojom/ax_event_mojom_traits_unittest.cc b/chromium/ui/accessibility/mojom/ax_event_mojom_traits_unittest.cc
index f9223d96476..edd0a8b0339 100644
--- a/chromium/ui/accessibility/mojom/ax_event_mojom_traits_unittest.cc
+++ b/chromium/ui/accessibility/mojom/ax_event_mojom_traits_unittest.cc
@@ -22,6 +22,7 @@ TEST(AXEventMojomTraitsTest, RoundTrip) {
input.event_type = ax::mojom::Event::kTextChanged;
input.id = 111;
input.event_from = ax::mojom::EventFrom::kUser;
+ input.event_from_action = ax::mojom::Action::kDoDefault;
ui::AXEventIntent editing_intent;
editing_intent.command = ax::mojom::Command::kDelete;
editing_intent.input_event_type =
@@ -36,10 +37,11 @@ TEST(AXEventMojomTraitsTest, RoundTrip) {
input.action_request_id = 222;
ui::AXEvent output;
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXEvent>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXEvent>(input, output));
EXPECT_EQ(ax::mojom::Event::kTextChanged, output.event_type);
EXPECT_EQ(111, output.id);
EXPECT_EQ(ax::mojom::EventFrom::kUser, output.event_from);
+ EXPECT_EQ(ax::mojom::Action::kDoDefault, output.event_from_action);
EXPECT_THAT(output.event_intents, testing::ContainerEq(event_intents));
EXPECT_EQ(222, output.action_request_id);
}
diff --git a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc
index f8c84a97b1d..7dda1070571 100644
--- a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc
+++ b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc
@@ -3,83 +3,14 @@
// found in the LICENSE file.
#include "ui/accessibility/mojom/ax_node_data_mojom_traits.h"
+
+#include "base/containers/flat_map.h"
#include "ui/accessibility/mojom/ax_relative_bounds.mojom-shared.h"
#include "ui/accessibility/mojom/ax_relative_bounds_mojom_traits.h"
namespace mojo {
// static
-std::unordered_map<ax::mojom::StringAttribute, std::string>
-StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::string_attributes(
- const ui::AXNodeData& p) {
- std::unordered_map<ax::mojom::StringAttribute, std::string> result;
- for (const auto& iter : p.string_attributes)
- result[iter.first] = iter.second;
- return result;
-}
-
-// static
-std::unordered_map<ax::mojom::IntAttribute, int32_t>
-StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::int_attributes(
- const ui::AXNodeData& p) {
- std::unordered_map<ax::mojom::IntAttribute, int32_t> result;
- for (const auto& iter : p.int_attributes)
- result[iter.first] = iter.second;
- return result;
-}
-
-// static
-std::unordered_map<ax::mojom::FloatAttribute, float>
-StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::float_attributes(
- const ui::AXNodeData& p) {
- std::unordered_map<ax::mojom::FloatAttribute, float> result;
- for (const auto& iter : p.float_attributes)
- result[iter.first] = iter.second;
- return result;
-}
-
-// static
-std::unordered_map<ax::mojom::BoolAttribute, bool>
-StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::bool_attributes(
- const ui::AXNodeData& p) {
- std::unordered_map<ax::mojom::BoolAttribute, bool> result;
- for (const auto& iter : p.bool_attributes)
- result[iter.first] = iter.second;
- return result;
-}
-
-// static
-std::unordered_map<ax::mojom::IntListAttribute, std::vector<int32_t>>
-StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::intlist_attributes(
- const ui::AXNodeData& p) {
- std::unordered_map<ax::mojom::IntListAttribute, std::vector<int32_t>> result;
- for (const auto& iter : p.intlist_attributes)
- result[iter.first] = iter.second;
- return result;
-}
-
-// static
-std::unordered_map<ax::mojom::StringListAttribute, std::vector<std::string>>
-StructTraits<ax::mojom::AXNodeDataDataView,
- ui::AXNodeData>::stringlist_attributes(const ui::AXNodeData& p) {
- std::unordered_map<ax::mojom::StringListAttribute, std::vector<std::string>>
- result;
- for (const auto& iter : p.stringlist_attributes)
- result[iter.first] = iter.second;
- return result;
-}
-
-// static
-std::unordered_map<std::string, std::string>
-StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::html_attributes(
- const ui::AXNodeData& p) {
- std::unordered_map<std::string, std::string> result;
- for (const auto& iter : p.html_attributes)
- result[iter.first] = iter.second;
- return result;
-}
-
-// static
bool StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::Read(
ax::mojom::AXNodeDataDataView data,
ui::AXNodeData* out) {
@@ -88,49 +19,44 @@ bool StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::Read(
out->state = data.state();
out->actions = data.actions();
- std::unordered_map<ax::mojom::StringAttribute, std::string> string_attributes;
+ // TODO(dcheng): AXNodeData should probably just switch over to absl's
+ // flat_hash_map for simplicity at some point.
+ base::flat_map<ax::mojom::StringAttribute, std::string> string_attributes;
if (!data.ReadStringAttributes(&string_attributes))
return false;
- for (const auto& iter : string_attributes)
- out->AddStringAttribute(iter.first, iter.second);
+ out->string_attributes = std::move(string_attributes).extract();
- std::unordered_map<ax::mojom::IntAttribute, int32_t> int_attributes;
+ base::flat_map<ax::mojom::IntAttribute, int32_t> int_attributes;
if (!data.ReadIntAttributes(&int_attributes))
return false;
- for (const auto& iter : int_attributes)
- out->AddIntAttribute(iter.first, iter.second);
+ out->int_attributes = std::move(int_attributes).extract();
- std::unordered_map<ax::mojom::FloatAttribute, float> float_attributes;
+ base::flat_map<ax::mojom::FloatAttribute, float> float_attributes;
if (!data.ReadFloatAttributes(&float_attributes))
return false;
- for (const auto& iter : float_attributes)
- out->AddFloatAttribute(iter.first, iter.second);
+ out->float_attributes = std::move(float_attributes).extract();
- std::unordered_map<ax::mojom::BoolAttribute, bool> bool_attributes;
+ base::flat_map<ax::mojom::BoolAttribute, bool> bool_attributes;
if (!data.ReadBoolAttributes(&bool_attributes))
return false;
- for (const auto& iter : bool_attributes)
- out->AddBoolAttribute(iter.first, iter.second);
+ out->bool_attributes = std::move(bool_attributes).extract();
- std::unordered_map<ax::mojom::IntListAttribute, std::vector<int32_t>>
+ base::flat_map<ax::mojom::IntListAttribute, std::vector<int32_t>>
intlist_attributes;
if (!data.ReadIntlistAttributes(&intlist_attributes))
return false;
- for (const auto& iter : intlist_attributes)
- out->AddIntListAttribute(iter.first, iter.second);
+ out->intlist_attributes = std::move(intlist_attributes).extract();
- std::unordered_map<ax::mojom::StringListAttribute, std::vector<std::string>>
+ base::flat_map<ax::mojom::StringListAttribute, std::vector<std::string>>
stringlist_attributes;
if (!data.ReadStringlistAttributes(&stringlist_attributes))
return false;
- for (const auto& iter : stringlist_attributes)
- out->AddStringListAttribute(iter.first, iter.second);
+ out->stringlist_attributes = std::move(stringlist_attributes).extract();
- std::unordered_map<std::string, std::string> html_attributes;
+ base::flat_map<std::string, std::string> html_attributes;
if (!data.ReadHtmlAttributes(&html_attributes))
return false;
- for (const auto& iter : html_attributes)
- out->html_attributes.push_back(std::make_pair(iter.first, iter.second));
+ out->html_attributes = std::move(html_attributes).extract();
if (!data.ReadChildIds(&out->child_ids))
return false;
diff --git a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h
index 1149d619527..7952a2ac666 100644
--- a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h
+++ b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h
@@ -17,22 +17,37 @@ struct StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData> {
static ax::mojom::Role role(const ui::AXNodeData& p) { return p.role; }
static uint32_t state(const ui::AXNodeData& p) { return p.state; }
static uint64_t actions(const ui::AXNodeData& p) { return p.actions; }
- static std::unordered_map<ax::mojom::StringAttribute, std::string>
- string_attributes(const ui::AXNodeData& p);
- static std::unordered_map<ax::mojom::IntAttribute, int32_t> int_attributes(
- const ui::AXNodeData& p);
- static std::unordered_map<ax::mojom::FloatAttribute, float> float_attributes(
- const ui::AXNodeData& p);
- static std::unordered_map<ax::mojom::BoolAttribute, bool> bool_attributes(
- const ui::AXNodeData& p);
- static std::unordered_map<ax::mojom::IntListAttribute, std::vector<int32_t>>
- intlist_attributes(const ui::AXNodeData& p);
- static std::unordered_map<ax::mojom::StringListAttribute,
- std::vector<std::string>>
- stringlist_attributes(const ui::AXNodeData& p);
- static std::unordered_map<std::string, std::string> html_attributes(
- const ui::AXNodeData& p);
- static std::vector<int32_t> child_ids(const ui::AXNodeData& p) {
+ static const std::vector<std::pair<ax::mojom::StringAttribute, std::string>>&
+ string_attributes(const ui::AXNodeData& p) {
+ return p.string_attributes;
+ }
+ static const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
+ int_attributes(const ui::AXNodeData& p) {
+ return p.int_attributes;
+ }
+ static const std::vector<std::pair<ax::mojom::FloatAttribute, float>>&
+ float_attributes(const ui::AXNodeData& p) {
+ return p.float_attributes;
+ }
+ static const std::vector<std::pair<ax::mojom::BoolAttribute, bool>>&
+ bool_attributes(const ui::AXNodeData& p) {
+ return p.bool_attributes;
+ }
+ static const std::vector<
+ std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
+ intlist_attributes(const ui::AXNodeData& p) {
+ return p.intlist_attributes;
+ }
+ static const std::vector<
+ std::pair<ax::mojom::StringListAttribute, std::vector<std::string>>>&
+ stringlist_attributes(const ui::AXNodeData& p) {
+ return p.stringlist_attributes;
+ }
+ static const std::vector<std::pair<std::string, std::string>>&
+ html_attributes(const ui::AXNodeData& p) {
+ return p.html_attributes;
+ }
+ static const std::vector<int32_t>& child_ids(const ui::AXNodeData& p) {
return p.child_ids;
}
static ui::AXRelativeBounds relative_bounds(const ui::AXNodeData& p) {
diff --git a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc
index 5b11af90538..1fc6771721b 100644
--- a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc
+++ b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc
@@ -14,14 +14,14 @@ using mojo::test::SerializeAndDeserialize;
TEST(AXNodeDataMojomTraitsTest, ID) {
ui::AXNodeData input, output;
input.id = 42;
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_EQ(42, output.id);
}
TEST(AXNodeDataMojomTraitsTest, Role) {
ui::AXNodeData input, output;
input.role = ax::mojom::Role::kButton;
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_EQ(ax::mojom::Role::kButton, output.role);
}
@@ -31,7 +31,7 @@ TEST(AXNodeDataMojomTraitsTest, State) {
input.AddState(ax::mojom::State::kCollapsed);
input.AddState(ax::mojom::State::kHorizontal);
input.AddState(ax::mojom::State::kMaxValue);
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_TRUE(output.HasState(ax::mojom::State::kCollapsed));
EXPECT_TRUE(output.HasState(ax::mojom::State::kHorizontal));
EXPECT_TRUE(output.HasState(ax::mojom::State::kMaxValue));
@@ -45,7 +45,7 @@ TEST(AXNodeDataMojomTraitsTest, Actions) {
input.AddAction(ax::mojom::Action::kDoDefault);
input.AddAction(ax::mojom::Action::kDecrement);
input.AddAction(ax::mojom::Action::kMaxValue);
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_TRUE(output.HasAction(ax::mojom::Action::kDoDefault));
EXPECT_TRUE(output.HasAction(ax::mojom::Action::kDecrement));
EXPECT_TRUE(output.HasAction(ax::mojom::Action::kMaxValue));
@@ -56,7 +56,7 @@ TEST(AXNodeDataMojomTraitsTest, Actions) {
TEST(AXNodeDataMojomTraitsTest, StringAttributes) {
ui::AXNodeData input, output;
input.AddStringAttribute(ax::mojom::StringAttribute::kName, "Mojo");
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_EQ("Mojo",
output.GetStringAttribute(ax::mojom::StringAttribute::kName));
}
@@ -64,7 +64,7 @@ TEST(AXNodeDataMojomTraitsTest, StringAttributes) {
TEST(AXNodeDataMojomTraitsTest, IntAttributes) {
ui::AXNodeData input, output;
input.AddIntAttribute(ax::mojom::IntAttribute::kScrollX, 42);
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_EQ(42, output.GetIntAttribute(ax::mojom::IntAttribute::kScrollX));
}
@@ -72,7 +72,7 @@ TEST(AXNodeDataMojomTraitsTest, FloatAttributes) {
ui::AXNodeData input, output;
input.AddFloatAttribute(ax::mojom::FloatAttribute::kFontSize, 42);
input.AddFloatAttribute(ax::mojom::FloatAttribute::kFontWeight, 100);
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_EQ(42, output.GetFloatAttribute(ax::mojom::FloatAttribute::kFontSize));
EXPECT_EQ(100,
output.GetFloatAttribute(ax::mojom::FloatAttribute::kFontWeight));
@@ -81,14 +81,14 @@ TEST(AXNodeDataMojomTraitsTest, FloatAttributes) {
TEST(AXNodeDataMojomTraitsTest, BoolAttributes) {
ui::AXNodeData input, output;
input.AddBoolAttribute(ax::mojom::BoolAttribute::kBusy, true);
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_TRUE(output.GetBoolAttribute(ax::mojom::BoolAttribute::kBusy));
}
TEST(AXNodeDataMojomTraitsTest, IntListAttributes) {
ui::AXNodeData input, output;
input.AddIntListAttribute(ax::mojom::IntListAttribute::kControlsIds, {1, 2});
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_EQ(
std::vector<int32_t>({1, 2}),
output.GetIntListAttribute(ax::mojom::IntListAttribute::kControlsIds));
@@ -99,7 +99,7 @@ TEST(AXNodeDataMojomTraitsTest, StringListAttributes) {
input.AddStringListAttribute(
ax::mojom::StringListAttribute::kCustomActionDescriptions,
{"foo", "bar"});
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_EQ(std::vector<std::string>({"foo", "bar"}),
output.GetStringListAttribute(
ax::mojom::StringListAttribute::kCustomActionDescriptions));
@@ -108,21 +108,21 @@ TEST(AXNodeDataMojomTraitsTest, StringListAttributes) {
TEST(AXNodeDataMojomTraitsTest, ChildIds) {
ui::AXNodeData input, output;
input.child_ids = {3, 4};
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_EQ(std::vector<int32_t>({3, 4}), output.child_ids);
}
TEST(AXNodeDataMojomTraitsTest, OffsetContainerID) {
ui::AXNodeData input, output;
input.relative_bounds.offset_container_id = 10;
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_EQ(10, output.relative_bounds.offset_container_id);
}
TEST(AXNodeDataMojomTraitsTest, RelativeBounds) {
ui::AXNodeData input, output;
input.relative_bounds.bounds = gfx::RectF(1, 2, 3, 4);
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_EQ(1, output.relative_bounds.bounds.x());
EXPECT_EQ(2, output.relative_bounds.bounds.y());
EXPECT_EQ(3, output.relative_bounds.bounds.width());
@@ -131,12 +131,12 @@ TEST(AXNodeDataMojomTraitsTest, RelativeBounds) {
TEST(AXNodeDataMojomTraitsTest, Transform) {
ui::AXNodeData input, output;
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_FALSE(output.relative_bounds.transform);
input.relative_bounds.transform = std::make_unique<gfx::Transform>();
input.relative_bounds.transform->Scale(2.0, 2.0);
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(input, output));
EXPECT_TRUE(output.relative_bounds.transform);
EXPECT_FALSE(output.relative_bounds.transform->IsIdentity());
}
diff --git a/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits_unittest.cc b/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits_unittest.cc
index 761c6439f2a..0c867700166 100644
--- a/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits_unittest.cc
+++ b/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits_unittest.cc
@@ -20,7 +20,7 @@ TEST(AXRelativeBoundsMojomTraitsTest, RoundTrip) {
ui::AXRelativeBounds output;
EXPECT_TRUE(
- SerializeAndDeserialize<ax::mojom::AXRelativeBounds>(&input, &output));
+ SerializeAndDeserialize<ax::mojom::AXRelativeBounds>(input, output));
EXPECT_EQ(111, output.offset_container_id);
EXPECT_EQ(1, output.bounds.x());
EXPECT_EQ(2, output.bounds.y());
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 e36061e8772..d3685734dc3 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
@@ -35,7 +35,7 @@ TEST(AXTreeDataMojomTraitsTest, TestSerializeAndDeserializeAXTreeData) {
input.sel_focus_affinity = ax::mojom::TextAffinity::kDownstream;
input.root_scroller_id = 14;
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXTreeData>(&input, &output));
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXTreeData>(input, output));
EXPECT_EQ(tree_id_1, output.tree_id);
EXPECT_EQ(tree_id_2, output.parent_tree_id);
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 fadf6cc54c3..477eed476d5 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
@@ -13,22 +13,22 @@ using mojo::test::SerializeAndDeserialize;
TEST(AXTreeIDMojomTraitsTest, TestSerializeAndDeserializeAXTreeID) {
ui::AXTreeID empty_input = ui::AXTreeID();
ui::AXTreeID empty_output;
- EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXTreeID>(&empty_input,
- &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_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_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/mojom/ax_tree_update.mojom b/chromium/ui/accessibility/mojom/ax_tree_update.mojom
index 957edd556c0..493f56f0788 100644
--- a/chromium/ui/accessibility/mojom/ax_tree_update.mojom
+++ b/chromium/ui/accessibility/mojom/ax_tree_update.mojom
@@ -17,5 +17,6 @@ struct AXTreeUpdate {
int32 root_id;
array<AXNodeData> nodes;
ax.mojom.EventFrom event_from;
+ ax.mojom.Action event_from_action;
array<EventIntent> event_intents;
};
diff --git a/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.cc b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.cc
index e429ce978d3..6dcfe1d8c8f 100644
--- a/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.cc
+++ b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.cc
@@ -18,6 +18,7 @@ bool StructTraits<ax::mojom::AXTreeUpdateDataView, ui::AXTreeUpdate>::Read(
if (!data.ReadNodes(&out->nodes))
return false;
out->event_from = data.event_from();
+ out->event_from_action = data.event_from_action();
return data.ReadEventIntents(&out->event_intents);
}
diff --git a/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.h b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.h
index 480c07aca8f..8077a0d5b06 100644
--- a/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.h
+++ b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits.h
@@ -33,7 +33,10 @@ struct StructTraits<ax::mojom::AXTreeUpdateDataView, ui::AXTreeUpdate> {
static ax::mojom::EventFrom event_from(const ui::AXTreeUpdate& p) {
return p.event_from;
}
- static std::vector<ui::AXEventIntent> event_intents(
+ static ax::mojom::Action event_from_action(const ui::AXTreeUpdate& p) {
+ return p.event_from_action;
+ }
+ static const std::vector<ui::AXEventIntent>& event_intents(
const ui::AXTreeUpdate& p) {
return p.event_intents;
}
diff --git a/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc
index 18a83b49bc2..cb5d42393c6 100644
--- a/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc
+++ b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc
@@ -21,8 +21,8 @@ TEST(AXTreeUpdateMojomTraitsTest, TestSerializeAndDeserializeAXTreeUpdate) {
input.nodes[0].role = ax::mojom::Role::kButton;
input.nodes[1].id = 4;
input.event_from = ax::mojom::EventFrom::kUser;
- EXPECT_TRUE(
- SerializeAndDeserialize<ax::mojom::AXTreeUpdate>(&input, &output));
+ input.event_from_action = ax::mojom::Action::kDoDefault;
+ EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXTreeUpdate>(input, output));
EXPECT_EQ(true, output.has_tree_data);
EXPECT_EQ(1, output.tree_data.focus_id);
EXPECT_EQ(2, output.node_id_to_clear);
@@ -31,4 +31,5 @@ TEST(AXTreeUpdateMojomTraitsTest, TestSerializeAndDeserializeAXTreeUpdate) {
EXPECT_EQ(ax::mojom::Role::kButton, output.nodes[0].role);
EXPECT_EQ(4, output.nodes[1].id);
EXPECT_EQ(ax::mojom::EventFrom::kUser, output.event_from);
+ EXPECT_EQ(ax::mojom::Action::kDoDefault, output.event_from_action);
}
diff --git a/chromium/ui/accessibility/null_ax_action_target.cc b/chromium/ui/accessibility/null_ax_action_target.cc
index 239f37472ea..65f3b46f340 100644
--- a/chromium/ui/accessibility/null_ax_action_target.cc
+++ b/chromium/ui/accessibility/null_ax_action_target.cc
@@ -10,23 +10,8 @@ AXActionTarget::Type NullAXActionTarget::GetType() const {
return AXActionTarget::Type::kNull;
}
-bool NullAXActionTarget::ClearAccessibilityFocus() const {
- return false;
-}
-
-bool NullAXActionTarget::Click() const {
- return false;
-}
-
-bool NullAXActionTarget::Decrement() const {
- return false;
-}
-
-bool NullAXActionTarget::Increment() const {
- return false;
-}
-
-bool NullAXActionTarget::Focus() const {
+bool NullAXActionTarget::PerformAction(
+ const ui::AXActionData& action_data) const {
return false;
}
@@ -46,10 +31,6 @@ gfx::Point NullAXActionTarget::MaximumScrollOffset() const {
return gfx::Point();
}
-bool NullAXActionTarget::SetAccessibilityFocus() const {
- return false;
-}
-
void NullAXActionTarget::SetScrollOffset(const gfx::Point& point) const {}
bool NullAXActionTarget::SetSelected(bool selected) const {
@@ -63,18 +44,6 @@ bool NullAXActionTarget::SetSelection(const AXActionTarget* anchor_object,
return false;
}
-bool NullAXActionTarget::SetSequentialFocusNavigationStartingPoint() const {
- return false;
-}
-
-bool NullAXActionTarget::SetValue(const std::string& value) const {
- return false;
-}
-
-bool NullAXActionTarget::ShowContextMenu() const {
- return false;
-}
-
bool NullAXActionTarget::ScrollToMakeVisible() const {
return false;
}
@@ -87,8 +56,4 @@ bool NullAXActionTarget::ScrollToMakeVisibleWithSubFocus(
return false;
}
-bool NullAXActionTarget::ScrollToGlobalPoint(const gfx::Point& point) const {
- return false;
-}
-
} // namespace ui
diff --git a/chromium/ui/accessibility/null_ax_action_target.h b/chromium/ui/accessibility/null_ax_action_target.h
index fd55809745a..d95868341e0 100644
--- a/chromium/ui/accessibility/null_ax_action_target.h
+++ b/chromium/ui/accessibility/null_ax_action_target.h
@@ -19,32 +19,23 @@ class AX_EXPORT NullAXActionTarget : public AXActionTarget {
protected:
// AXActionTarget overrides.
Type GetType() const override;
- bool ClearAccessibilityFocus() const override;
- bool Click() const override;
- bool Decrement() const override;
- bool Increment() const override;
- bool Focus() const override;
+ bool PerformAction(const AXActionData& action_data) const override;
gfx::Rect GetRelativeBounds() const override;
gfx::Point GetScrollOffset() const override;
gfx::Point MinimumScrollOffset() const override;
gfx::Point MaximumScrollOffset() const override;
- bool SetAccessibilityFocus() const override;
void SetScrollOffset(const gfx::Point& point) const override;
bool SetSelected(bool selected) const override;
bool SetSelection(const AXActionTarget* anchor_object,
int anchor_offset,
const AXActionTarget* focus_object,
int focus_offset) const override;
- bool SetSequentialFocusNavigationStartingPoint() const override;
- bool SetValue(const std::string& value) const override;
- bool ShowContextMenu() const override;
bool ScrollToMakeVisible() const override;
bool ScrollToMakeVisibleWithSubFocus(
const gfx::Rect& rect,
ax::mojom::ScrollAlignment horizontal_scroll_alignment,
ax::mojom::ScrollAlignment vertical_scroll_alignment,
ax::mojom::ScrollBehavior scroll_behavior) const override;
- bool ScrollToGlobalPoint(const gfx::Point& point) const override;
};
} // namespace ui
diff --git a/chromium/ui/accessibility/null_ax_action_target_unittest.cc b/chromium/ui/accessibility/null_ax_action_target_unittest.cc
index 13a51f9df75..0cc184db970 100644
--- a/chromium/ui/accessibility/null_ax_action_target_unittest.cc
+++ b/chromium/ui/accessibility/null_ax_action_target_unittest.cc
@@ -5,6 +5,7 @@
#include "ui/accessibility/null_ax_action_target.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
namespace ui {
@@ -14,27 +15,20 @@ TEST(NullAXActionTargetTest, TestMethods) {
std::make_unique<NullAXActionTarget>();
EXPECT_EQ(AXActionTarget::Type::kNull, action_target->GetType());
- EXPECT_FALSE(action_target->ClearAccessibilityFocus());
- EXPECT_FALSE(action_target->Click());
- EXPECT_FALSE(action_target->Decrement());
- EXPECT_FALSE(action_target->Increment());
- EXPECT_FALSE(action_target->Focus());
+ ui::AXActionData action_data;
+ action_data.action = ax::mojom::Action::kFocus;
+ EXPECT_FALSE(action_target->PerformAction(action_data));
EXPECT_EQ(gfx::Rect(), action_target->GetRelativeBounds());
EXPECT_EQ(gfx::Point(), action_target->GetScrollOffset());
EXPECT_EQ(gfx::Point(), action_target->MinimumScrollOffset());
EXPECT_EQ(gfx::Point(), action_target->MaximumScrollOffset());
- EXPECT_FALSE(action_target->SetAccessibilityFocus());
EXPECT_FALSE(action_target->SetSelected(false));
EXPECT_FALSE(action_target->SetSelection(nullptr, 0, nullptr, 0));
- EXPECT_FALSE(action_target->SetSequentialFocusNavigationStartingPoint());
- EXPECT_FALSE(action_target->SetValue(""));
- EXPECT_FALSE(action_target->ShowContextMenu());
EXPECT_FALSE(action_target->ScrollToMakeVisible());
EXPECT_FALSE(action_target->ScrollToMakeVisibleWithSubFocus(
gfx::Rect(), ax::mojom::ScrollAlignment::kScrollAlignmentCenter,
ax::mojom::ScrollAlignment::kScrollAlignmentCenter,
ax::mojom::ScrollBehavior::kDoNotScrollIfVisible));
- EXPECT_FALSE(action_target->ScrollToGlobalPoint(gfx::Point()));
}
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/BUILD.gn b/chromium/ui/accessibility/platform/BUILD.gn
index 99df759347f..c65c091356d 100644
--- a/chromium/ui/accessibility/platform/BUILD.gn
+++ b/chromium/ui/accessibility/platform/BUILD.gn
@@ -59,12 +59,16 @@ source_set("platform") {
"ax_platform_node_test_helper.h",
# Used by DumpAccTree testsuite and a11y tools
- "inspect/inspect.cc",
- "inspect/inspect.h",
- "inspect/property_node.cc",
- "inspect/property_node.h",
- "inspect/tree_formatter.cc",
- "inspect/tree_formatter.h",
+ "inspect/ax_event_recorder.cc",
+ "inspect/ax_event_recorder.h",
+ "inspect/ax_inspect.cc",
+ "inspect/ax_inspect.h",
+ "inspect/ax_property_node.cc",
+ "inspect/ax_property_node.h",
+ "inspect/ax_tree_formatter.cc",
+ "inspect/ax_tree_formatter.h",
+ "inspect/ax_tree_formatter_base.cc",
+ "inspect/ax_tree_formatter_base.h",
]
public_deps = [
@@ -97,6 +101,8 @@ source_set("platform") {
"ax_platform_relation_win.h",
"ax_system_caret_win.cc",
"ax_system_caret_win.h",
+ "inspect/ax_inspect_utils_win.cc",
+ "inspect/ax_inspect_utils_win.h",
"uia_registrar_win.cc",
"uia_registrar_win.h",
]
@@ -118,6 +124,8 @@ source_set("platform") {
"ax_event_intent_mac.mm",
"ax_platform_node_mac.h",
"ax_platform_node_mac.mm",
+ "ax_private_webkit_constants_mac.h",
+ "ax_private_webkit_constants_mac.mm",
]
frameworks = [
@@ -135,8 +143,12 @@ source_set("platform") {
"ax_platform_atk_hyperlink.h",
"ax_platform_node_auralinux.cc",
"ax_platform_node_auralinux.h",
+ "inspect/ax_inspect_utils_auralinux.cc",
+ "inspect/ax_inspect_utils_auralinux.h",
]
+ configs += [ "//build/config/linux/atspi2" ]
+
# ax_platform_text_boundary.h includes atk.h, so ATK is needed
# as a public config to ensure anything that includes this is
# able to find atk.h.
diff --git a/chromium/ui/accessibility/platform/ax_android_constants.cc b/chromium/ui/accessibility/platform/ax_android_constants.cc
index f3f350c5ab4..926818cc483 100644
--- a/chromium/ui/accessibility/platform/ax_android_constants.cc
+++ b/chromium/ui/accessibility/platform/ax_android_constants.cc
@@ -6,6 +6,8 @@
namespace ui {
+const char kAXAutoCompleteTextViewClassname[] =
+ "android.widget.AutoCompleteTextView";
const char kAXAbsListViewClassname[] = "android.widget.AbsListView";
const char kAXButtonClassname[] = "android.widget.Button";
const char kAXCheckBoxClassname[] = "android.widget.CheckBox";
@@ -21,6 +23,8 @@ const char kAXImageButtonClassname[] = "android.widget.ImageButton";
const char kAXImageViewClassname[] = "android.widget.ImageView";
const char kAXListViewClassname[] = "android.widget.ListView";
const char kAXMenuItemClassname[] = "android.view.MenuItem";
+const char kAXMultiAutoCompleteTextViewClassname[] =
+ "android.widget.MultiAutoCompleteTextView";
const char kAXPagerClassname[] = "android.support.v4.view.ViewPager";
const char kAXProgressBarClassname[] = "android.widget.ProgressBar";
const char kAXRadioButtonClassname[] = "android.widget.RadioButton";
diff --git a/chromium/ui/accessibility/platform/ax_android_constants.h b/chromium/ui/accessibility/platform/ax_android_constants.h
index a224e22ec98..6892b280f9a 100644
--- a/chromium/ui/accessibility/platform/ax_android_constants.h
+++ b/chromium/ui/accessibility/platform/ax_android_constants.h
@@ -12,6 +12,7 @@ namespace ui {
// Classnames.
+AX_EXPORT extern const char kAXAutoCompleteTextViewClassname[];
AX_EXPORT extern const char kAXAbsListViewClassname[];
AX_EXPORT extern const char kAXButtonClassname[];
AX_EXPORT extern const char kAXCheckBoxClassname[];
@@ -26,6 +27,7 @@ AX_EXPORT extern const char kAXImageButtonClassname[];
AX_EXPORT extern const char kAXImageViewClassname[];
AX_EXPORT extern const char kAXListViewClassname[];
AX_EXPORT extern const char kAXMenuItemClassname[];
+AX_EXPORT extern const char kAXMultiAutoCompleteTextViewClassname[];
AX_EXPORT extern const char kAXPagerClassname[];
AX_EXPORT extern const char kAXProgressBarClassname[];
AX_EXPORT extern const char kAXRadioButtonClassname[];
diff --git a/chromium/ui/accessibility/platform/ax_fragment_root_win.cc b/chromium/ui/accessibility/platform/ax_fragment_root_win.cc
index ea4544e8a7b..7a180e4be9f 100644
--- a/chromium/ui/accessibility/platform/ax_fragment_root_win.cc
+++ b/chromium/ui/accessibility/platform/ax_fragment_root_win.cc
@@ -54,8 +54,7 @@ class AXFragmentRootPlatformNodeWin : public AXPlatformNodeWin,
*result = nullptr;
// We currently only support the custom UIA property ID for unique id.
- if (property_id ==
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId() &&
+ if (property_id == UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId() &&
value.vt == VT_BSTR) {
int32_t ax_unique_id;
if (!base::StringToInt(value.bstrVal, &ax_unique_id))
@@ -379,7 +378,7 @@ gfx::NativeViewAccessible AXFragmentRootWin::HitTestSync(int x, int y) const {
return nullptr;
}
-gfx::NativeViewAccessible AXFragmentRootWin::GetFocus() {
+gfx::NativeViewAccessible AXFragmentRootWin::GetFocus() const {
AXPlatformNodeDelegate* child_delegate = GetChildNodeDelegate();
if (child_delegate)
return child_delegate->GetFocus();
diff --git a/chromium/ui/accessibility/platform/ax_fragment_root_win.h b/chromium/ui/accessibility/platform/ax_fragment_root_win.h
index f8cb803dc9a..6c8ec09b8e2 100644
--- a/chromium/ui/accessibility/platform/ax_fragment_root_win.h
+++ b/chromium/ui/accessibility/platform/ax_fragment_root_win.h
@@ -63,7 +63,7 @@ class AX_EXPORT AXFragmentRootWin : public ui::AXPlatformNodeDelegateBase {
gfx::NativeViewAccessible GetNextSibling() override;
gfx::NativeViewAccessible GetPreviousSibling() override;
gfx::NativeViewAccessible HitTestSync(int x, int y) const override;
- gfx::NativeViewAccessible GetFocus() override;
+ gfx::NativeViewAccessible GetFocus() const override;
const ui::AXUniqueId& GetUniqueId() const override;
gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override;
AXPlatformNode* GetFromTreeIDAndNodeID(const ui::AXTreeID& ax_tree_id,
diff --git a/chromium/ui/accessibility/platform/ax_fragment_root_win_unittest.cc b/chromium/ui/accessibility/platform/ax_fragment_root_win_unittest.cc
index e0e03afa16c..4c7283c81e1 100644
--- a/chromium/ui/accessibility/platform/ax_fragment_root_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_fragment_root_win_unittest.cc
@@ -3,10 +3,6 @@
// found in the LICENSE file.
#include "ui/accessibility/platform/ax_fragment_root_win.h"
-#include "ui/accessibility/accessibility_switches.h"
-#include "ui/accessibility/platform/ax_platform_node_win.h"
-#include "ui/accessibility/platform/ax_platform_node_win_unittest.h"
-#include "ui/accessibility/platform/test_ax_node_wrapper.h"
#include <UIAutomationClient.h>
#include <UIAutomationCoreApi.h>
@@ -15,6 +11,10 @@
#include "base/win/scoped_safearray.h"
#include "base/win/scoped_variant.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/accessibility_switches.h"
+#include "ui/accessibility/platform/ax_platform_node_win.h"
+#include "ui/accessibility/platform/ax_platform_node_win_unittest.h"
+#include "ui/accessibility/platform/test_ax_node_wrapper.h"
#include "ui/accessibility/platform/uia_registrar_win.h"
using base::win::ScopedVariant;
@@ -94,7 +94,7 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
{
unique_id = AXPlatformNodeFromNode(GetRootAsAXNode())->GetUniqueId();
unique_id_variant.Set(
- SysAllocString(base::NumberToString16(-unique_id).c_str()));
+ SysAllocString(base::NumberToWString(-unique_id).c_str()));
ComPtr<IRawElementProviderSimple> invalid_element_provider_simple;
EXPECT_HRESULT_SUCCEEDED(
@@ -103,7 +103,7 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
EXPECT_HRESULT_FAILED(item_container_provider->FindItemByProperty(
invalid_element_provider_simple.Get(),
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
result.Reset();
unique_id_variant.Release();
@@ -114,12 +114,12 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
{
unique_id = AXPlatformNodeFromNode(GetRootAsAXNode())->GetUniqueId();
unique_id_variant.Set(
- SysAllocString(base::NumberToString16(-unique_id).c_str()));
+ SysAllocString(base::NumberToWString(-unique_id).c_str()));
// When |start_after_element| of FindItemByProperty() is nullptr, we should
// be able to find "text1".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
- nullptr, UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ nullptr, UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"root");
result.Reset();
@@ -129,7 +129,7 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
// looking for.
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
text1_raw_element_provider_simple.Get(),
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_EQ(nullptr, result.Get());
result.Reset();
@@ -139,7 +139,7 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
// looking for.
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
button_raw_element_provider_simple.Get(),
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_EQ(nullptr, result.Get());
@@ -152,12 +152,12 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
{
unique_id = AXPlatformNodeFromNode(text1_node)->GetUniqueId();
unique_id_variant.Set(
- SysAllocString(base::NumberToString16(-unique_id).c_str()));
+ SysAllocString(base::NumberToWString(-unique_id).c_str()));
// When |start_after_element| of FindItemByProperty() is nullptr, we should
// be able to find "text1".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
- nullptr, UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ nullptr, UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"text1");
result.Reset();
@@ -167,7 +167,7 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
// looking for.
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
text1_raw_element_provider_simple.Get(),
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_EQ(nullptr, result.Get());
result.Reset();
@@ -177,7 +177,7 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
// looking for.
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
button_raw_element_provider_simple.Get(),
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_EQ(nullptr, result.Get());
result.Reset();
@@ -189,12 +189,12 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
{
unique_id = AXPlatformNodeFromNode(button_node)->GetUniqueId();
unique_id_variant.Set(
- SysAllocString(base::NumberToString16(-unique_id).c_str()));
+ SysAllocString(base::NumberToWString(-unique_id).c_str()));
// When |start_after_element| of FindItemByProperty() is nullptr, we should
// be able to find "button".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
- nullptr, UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ nullptr, UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"button");
result.Reset();
@@ -203,7 +203,7 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
// be able to find "button".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
text1_raw_element_provider_simple.Get(),
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"button");
result.Reset();
@@ -213,7 +213,7 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
// looking for.
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
button_raw_element_provider_simple.Get(),
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_EQ(nullptr, result.Get());
result.Reset();
@@ -226,12 +226,12 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
unique_id =
AXPlatformNodeFromNode(button_node->children()[0])->GetUniqueId();
unique_id_variant.Set(
- SysAllocString(base::NumberToString16(-unique_id).c_str()));
+ SysAllocString(base::NumberToWString(-unique_id).c_str()));
// When |start_after_element| of FindItemByProperty() is nullptr, we should
// be able to find "text2".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
- nullptr, UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ nullptr, UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"text2");
@@ -239,7 +239,7 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
// be able to find "text2".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
root_raw_element_provider_simple.Get(),
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"text2");
@@ -247,7 +247,7 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
// be able to find "text2".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
text1_raw_element_provider_simple.Get(),
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"text2");
@@ -255,7 +255,7 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
// be able to find "text2".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
button_raw_element_provider_simple.Get(),
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId(),
+ UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"text2");
}
@@ -263,6 +263,8 @@ TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
TEST_F(AXFragmentRootTest, TestUIAGetFragmentRoot) {
AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
@@ -371,6 +373,8 @@ TEST_F(AXFragmentRootTest, TestUIAGetFocus) {
TEST_F(AXFragmentRootTest, TestUIAErrorHandling) {
AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
@@ -410,6 +414,8 @@ TEST_F(AXFragmentRootTest, TestUIAErrorHandling) {
TEST_F(AXFragmentRootTest, TestGetChildCount) {
AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
@@ -422,6 +428,8 @@ TEST_F(AXFragmentRootTest, TestGetChildCount) {
TEST_F(AXFragmentRootTest, TestChildAtIndex) {
AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
@@ -437,6 +445,8 @@ TEST_F(AXFragmentRootTest, TestChildAtIndex) {
TEST_F(AXFragmentRootTest, TestGetParent) {
AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
@@ -451,6 +461,8 @@ TEST_F(AXFragmentRootTest, TestGetParent) {
TEST_F(AXFragmentRootTest, TestGetPropertyValue) {
AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
@@ -666,6 +678,8 @@ TEST_F(AXFragmentRootTest, TestUIAMultipleFragmentRoots) {
TEST_F(AXFragmentRootTest, TestFragmentRootMap) {
AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
Init(root);
// There should be nothing in the map before we create a fragment root.
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
index 900fe8d2fff..b1d16d65633 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -2380,7 +2380,7 @@ ImplementedAtkInterfaces AXPlatformNodeAuraLinux::GetGTypeInterfaceMask(
if (data.IsRangeValueSupported())
interface_mask.Add(ImplementedAtkInterfaces::Value::kValue);
- if (ui::IsDocument(data.role))
+ if (ui::IsPlatformDocument(data.role))
interface_mask.Add(ImplementedAtkInterfaces::Value::kDocument);
if (IsImage(data.role))
@@ -2545,8 +2545,9 @@ bool AXPlatformNodeAuraLinux::IsWebDocumentForRelations() {
AtkObject* AXPlatformNodeAuraLinux::CreateAtkObject() {
if (GetData().role != ax::mojom::Role::kApplication &&
!GetDelegate()->IsToplevelBrowserWindow() &&
- !GetAccessibilityMode().has_mode(AXMode::kNativeAPIs))
+ !GetAccessibilityMode().has_mode(AXMode::kNativeAPIs)) {
return nullptr;
+ }
if (GetDelegate()->IsChildOfLeaf())
return nullptr;
EnsureGTypeInit();
@@ -2782,6 +2783,7 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() const {
case ax::mojom::Role::kGenericContainer:
case ax::mojom::Role::kFooterAsNonLandmark:
case ax::mojom::Role::kHeaderAsNonLandmark:
+ case ax::mojom::Role::kRuby:
return ATK_ROLE_SECTION;
case ax::mojom::Role::kGraphicsDocument:
return ATK_ROLE_DOCUMENT_FRAME;
@@ -2883,6 +2885,8 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() const {
return ATK_ROLE_PARAGRAPH;
case ax::mojom::Role::kPdfActionableHighlight:
return ATK_ROLE_PUSH_BUTTON;
+ case ax::mojom::Role::kPdfRoot:
+ return ATK_ROLE_DOCUMENT_FRAME;
case ax::mojom::Role::kPluginObject:
return ATK_ROLE_EMBEDDED;
case ax::mojom::Role::kPopUpButton: {
@@ -2912,12 +2916,15 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() const {
return ATK_ROLE_PANEL;
case ax::mojom::Role::kRowHeader:
return ATK_ROLE_ROW_HEADER;
- case ax::mojom::Role::kRuby:
- return kStaticRole;
case ax::mojom::Role::kRubyAnnotation:
- // TODO(accessibility) Panels are generally for containers of widgets.
- // This should probably be a section (if a container) or static if text.
- return ATK_ROLE_PANEL;
+ // Generally exposed as description on <ruby> (Role::kRuby) element, not
+ // as its own object in the tree.
+ // However, it's possible to make a kRubyAnnotation element show up in the
+ // AX tree, for example by adding tabindex="0" to the source <rp> or <rt>
+ // element or making the source element the target of an aria-owns.
+ // Therefore, browser side needs to gracefully handle it if it actually
+ // shows up in the tree.
+ return kStaticRole;
case ax::mojom::Role::kSection: {
if (GetName().empty()) {
// Do not use ARIA mapping for nameless <section>.
@@ -2932,7 +2939,6 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() const {
case ax::mojom::Role::kSearch:
return ATK_ROLE_LANDMARK;
case ax::mojom::Role::kSlider:
- case ax::mojom::Role::kSliderThumb:
return ATK_ROLE_SLIDER;
case ax::mojom::Role::kSpinButton:
return ATK_ROLE_SPIN_BUTTON;
@@ -3002,9 +3008,6 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() const {
return ATK_ROLE_TREE_TABLE;
case ax::mojom::Role::kVideo:
return ATK_ROLE_VIDEO;
- case ax::mojom::Role::kWebArea:
- case ax::mojom::Role::kWebView:
- return ATK_ROLE_DOCUMENT_WEB;
case ax::mojom::Role::kWindow:
// In ATK elements with ATK_ROLE_FRAME are windows with titles and
// buttons, while those with ATK_ROLE_WINDOW are windows without those
@@ -3012,6 +3015,7 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() const {
return ATK_ROLE_FRAME;
case ax::mojom::Role::kClient:
case ax::mojom::Role::kDesktop:
+ case ax::mojom::Role::kWebView:
return ATK_ROLE_PANEL;
case ax::mojom::Role::kFigcaption:
return ATK_ROLE_CAPTION;
@@ -3062,7 +3066,7 @@ void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) {
atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSABLE);
if (data.HasState(ax::mojom::State::kHorizontal))
atk_state_set_add_state(atk_state_set, ATK_STATE_HORIZONTAL);
- if (!data.HasState(ax::mojom::State::kInvisible)) {
+ if (!IsInvisibleOrIgnored()) {
atk_state_set_add_state(atk_state_set, ATK_STATE_VISIBLE);
if (!delegate_->IsOffscreen() && !is_minimized)
atk_state_set_add_state(atk_state_set, ATK_STATE_SHOWING);
@@ -3079,6 +3083,11 @@ void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) {
data.GetIntAttribute(ax::mojom::IntAttribute::kInvalidState) !=
static_cast<int32_t>(ax::mojom::InvalidState::kFalse))
atk_state_set_add_state(atk_state_set, ATK_STATE_INVALID_ENTRY);
+ if (data.HasIntAttribute(ax::mojom::IntAttribute::kAriaCurrentState) &&
+ data.GetIntAttribute(ax::mojom::IntAttribute::kAriaCurrentState) !=
+ static_cast<int32_t>(ax::mojom::AriaCurrentState::kFalse)) {
+ atk_state_set_add_state(atk_state_set, ATK_STATE_ACTIVE);
+ }
#if defined(ATK_216)
if (IsPlatformCheckable())
atk_state_set_add_state(atk_state_set, ATK_STATE_CHECKABLE);
@@ -3693,7 +3702,7 @@ bool AXPlatformNodeAuraLinux::SelectionAndFocusAreTheSame() {
// on the select element and not the newly-selected descendant.
if (AXPlatformNodeBase* parent = FromAtkObject(GetParent())) {
if (parent->GetData().role == ax::mojom::Role::kMenuListPopup)
- return !parent->GetData().HasState(ax::mojom::State::kInvisible);
+ return !parent->IsInvisibleOrIgnored();
}
return false;
@@ -3800,7 +3809,12 @@ void AXPlatformNodeAuraLinux::EmitCaretChangedSignal() {
return;
}
- DCHECK(HasCaret());
+#if DCHECK_IS_ON()
+ AXTree::Selection unignored_selection =
+ GetDelegate()->GetUnignoredSelection();
+ DCHECK(HasCaret(&unignored_selection));
+#endif
+
std::pair<int, int> selection = GetSelectionOffsetsForAtk();
AtkObject* atk_object = GetOrCreateAtkObject();
@@ -4006,6 +4020,20 @@ void AXPlatformNodeAuraLinux::OnInvalidStatusChanged() {
GetData().GetInvalidState() != ax::mojom::InvalidState::kFalse);
}
+void AXPlatformNodeAuraLinux::OnAriaCurrentChanged() {
+ AtkObject* atk_object = GetOrCreateAtkObject();
+ if (!atk_object)
+ return;
+
+ ax::mojom::AriaCurrentState aria_current =
+ static_cast<ax::mojom::AriaCurrentState>(GetData().GetIntAttribute(
+ ax::mojom::IntAttribute::kAriaCurrentState));
+ atk_object_notify_state_change(
+ ATK_OBJECT(atk_object), ATK_STATE_ACTIVE,
+ aria_current != ax::mojom::AriaCurrentState::kNone &&
+ aria_current != ax::mojom::AriaCurrentState::kFalse);
+}
+
void AXPlatformNodeAuraLinux::OnAlertShown() {
DCHECK(ui::IsAlert(GetData().role));
atk_object_notify_state_change(ATK_OBJECT(GetOrCreateAtkObject()),
@@ -4590,7 +4618,9 @@ bool AXPlatformNodeAuraLinux::IsNameExposed() {
}
int AXPlatformNodeAuraLinux::GetCaretOffset() {
- if (!HasCaret()) {
+ AXTree::Selection unignored_selection =
+ GetDelegate()->GetUnignoredSelection();
+ if (!HasCaret(&unignored_selection)) {
base::Optional<FindInPageResultInfo> result =
GetSelectionOffsetsFromFindInPage();
AtkObject* atk_object = GetOrCreateAtkObject();
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h
index 75110c58c31..493fcfdcbb3 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -218,6 +218,7 @@ class AX_EXPORT AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
void OnDescriptionChanged();
void OnSortDirectionChanged();
void OnInvalidStatusChanged();
+ void OnAriaCurrentChanged();
void OnDocumentTitleChanged();
void OnSubtreeCreated();
void OnSubtreeWillBeDeleted();
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_base.cc b/chromium/ui/accessibility/platform/ax_platform_node_base.cc
index 6472dae7e08..9d256299be8 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_base.cc
@@ -63,7 +63,8 @@ bool FindDescendantRoleWithMaxDepth(AXPlatformNodeBase* node,
} // namespace
-const base::char16 AXPlatformNodeBase::kEmbeddedCharacter = L'\xfffc';
+const base::char16 AXPlatformNodeBase::kEmbeddedCharacter =
+ STRING16_LITERAL('\xfffc');
// Map from each AXPlatformNode's unique id to its instance.
using UniqueIdMap = std::unordered_map<int32_t, AXPlatformNode*>;
@@ -119,7 +120,7 @@ const AXNodeData& AXPlatformNodeBase::GetData() const {
return *empty_data;
}
-gfx::NativeViewAccessible AXPlatformNodeBase::GetFocus() {
+gfx::NativeViewAccessible AXPlatformNodeBase::GetFocus() const {
if (delegate_)
return delegate_->GetFocus();
return nullptr;
@@ -149,18 +150,19 @@ std::string AXPlatformNodeBase::GetName() const {
return std::string();
}
-base::string16 AXPlatformNodeBase::GetNameAsString16() const {
- std::string name = GetName();
- if (name.empty())
- return base::string16();
- return base::UTF8ToUTF16(name);
-}
-
base::Optional<int> AXPlatformNodeBase::GetIndexInParent() {
AXPlatformNodeBase* parent = FromNativeViewAccessible(GetParent());
if (!parent)
return base::nullopt;
+ // If this is the webview, it is not in the child in the list of its parent's
+ // child.
+ // TODO(jkim): Check if we could remove this after making WebView ignored.
+ if (delegate_ &&
+ delegate_->GetNativeViewAccessible() != GetNativeViewAccessible()) {
+ return base::nullopt;
+ }
+
int child_count = parent->GetChildCount();
if (child_count == 0) {
// |child_count| could be 0 if the parent is IsLeaf.
@@ -591,8 +593,8 @@ bool AXPlatformNodeBase::SetHypertextSelection(int start_offset,
return delegate_->SetHypertextSelection(start_offset, end_offset);
}
-bool AXPlatformNodeBase::IsDocument() const {
- return ui::IsDocument(GetData().role);
+bool AXPlatformNodeBase::IsPlatformDocument() const {
+ return ui::IsPlatformDocument(GetData().role);
}
bool AXPlatformNodeBase::IsSelectionItemSupported() const {
@@ -881,11 +883,7 @@ base::Optional<float> AXPlatformNodeBase::GetFontSizeInPoints() const {
return base::nullopt;
}
-bool AXPlatformNodeBase::HasCaret(
- const AXTree::Selection* unignored_selection) {
- if (IsInvisibleOrIgnored())
- return false;
-
+bool AXPlatformNodeBase::HasCaret(const AXTree::Selection* selection) {
if (IsPlainTextField() &&
HasIntAttribute(ax::mojom::IntAttribute::kTextSelStart) &&
HasIntAttribute(ax::mojom::IntAttribute::kTextSelEnd)) {
@@ -894,10 +892,10 @@ bool AXPlatformNodeBase::HasCaret(
// The caret is always at the focus of the selection.
int32_t focus_id;
- if (unignored_selection)
- focus_id = unignored_selection->focus_object_id;
+ if (selection)
+ focus_id = selection->focus_object_id;
else
- focus_id = delegate_->GetUnignoredSelection().focus_object_id;
+ focus_id = delegate_->GetTreeData().sel_focus_object_id;
AXPlatformNodeBase* focus_object =
static_cast<AXPlatformNodeBase*>(delegate_->GetFromNodeID(focus_id));
@@ -917,7 +915,17 @@ bool AXPlatformNodeBase::IsChildOfLeaf() const {
}
bool AXPlatformNodeBase::IsInvisibleOrIgnored() const {
- return GetData().IsInvisibleOrIgnored();
+ if (!GetData().IsInvisibleOrIgnored())
+ return false;
+
+ if (GetData().HasState(ax::mojom::State::kFocusable))
+ return !IsFocused();
+
+ return !const_cast<AXPlatformNodeBase*>(this)->HasCaret();
+}
+
+bool AXPlatformNodeBase::IsFocused() const {
+ return delegate_ && FromNativeViewAccessible(delegate_->GetFocus()) == this;
}
bool AXPlatformNodeBase::IsScrollable() const {
@@ -1079,9 +1087,6 @@ void AXPlatformNodeBase::ComputeAttributes(PlatformAttributeList* attributes) {
case ax::mojom::AriaCurrentState::kLocation:
AddAttributeToList("current", "location", attributes);
break;
- case ax::mojom::AriaCurrentState::kUnclippedLocation:
- AddAttributeToList("current", "unclippedLocation", attributes);
- break;
case ax::mojom::AriaCurrentState::kDate:
AddAttributeToList("current", "date", attributes);
break;
@@ -1323,6 +1328,7 @@ AXHypertext::~AXHypertext() = default;
AXHypertext::AXHypertext(const AXHypertext& other) = default;
AXHypertext& AXHypertext::operator=(const AXHypertext& other) = default;
+// TODO(nektar): To be able to use AXNode in Views, move this logic to AXNode.
void AXPlatformNodeBase::UpdateComputedHypertext() const {
if (!delegate_)
return;
@@ -1335,18 +1341,18 @@ void AXPlatformNodeBase::UpdateComputedHypertext() const {
}
// Construct the hypertext for this node, which contains the concatenation
- // of all of the static text and widespace of this node's children and an
+ // of all of the static text and whitespace from this node's children, and an
// embedded object character for all the other children. Build up a map from
// the character index of each embedded object character to the id of the
// child object it points to.
base::string16 hypertext;
for (AXPlatformNodeChildIterator child_iter = AXPlatformNodeChildrenBegin();
child_iter != AXPlatformNodeChildrenEnd(); ++child_iter) {
- // Similar to Firefox, we don't expose text-only objects in IA2 and ATK
+ // Similar to Firefox, we don't expose text nodes in IAccessible2 and ATK
// hypertext with the embedded object character. We copy all of their text
// instead.
if (child_iter->IsText()) {
- hypertext_.hypertext += child_iter->GetNameAsString16();
+ hypertext_.hypertext += child_iter->GetInnerText();
} else {
int32_t char_offset = static_cast<int32_t>(hypertext_.hypertext.size());
int32_t child_unique_id = child_iter->GetUniqueId();
@@ -1992,22 +1998,18 @@ ui::TextAttributeList AXPlatformNodeBase::ComputeTextAttributes() const {
attributes.push_back(std::make_pair("auto-generated", "true"));
int color;
- if (GetIntAttribute(ax::mojom::IntAttribute::kBackgroundColor, &color)) {
- unsigned int alpha = SkColorGetA(color);
+ if ((color = delegate_->GetBackgroundColor())) {
unsigned int red = SkColorGetR(color);
unsigned int green = SkColorGetG(color);
unsigned int blue = SkColorGetB(color);
- // Don't expose default value of pure white.
- if (alpha && (red != 255 || green != 255 || blue != 255)) {
- std::string color_value = "rgb(" + base::NumberToString(red) + ',' +
- base::NumberToString(green) + ',' +
- base::NumberToString(blue) + ')';
- SanitizeTextAttributeValue(color_value, &color_value);
- attributes.push_back(std::make_pair("background-color", color_value));
- }
+ std::string color_value = "rgb(" + base::NumberToString(red) + ',' +
+ base::NumberToString(green) + ',' +
+ base::NumberToString(blue) + ')';
+ SanitizeTextAttributeValue(color_value, &color_value);
+ attributes.push_back(std::make_pair("background-color", color_value));
}
- if (GetIntAttribute(ax::mojom::IntAttribute::kColor, &color)) {
+ if ((color = delegate_->GetColor())) {
unsigned int red = SkColorGetR(color);
unsigned int green = SkColorGetG(color);
unsigned int blue = SkColorGetB(color);
@@ -2219,9 +2221,6 @@ std::string AXPlatformNodeBase::ComputeDetailsRoles() const {
}
int AXPlatformNodeBase::GetMaxSelectableItems() const {
- if (!GetData().HasState(ax::mojom::State::kFocusable))
- return 0;
-
if (IsLeaf())
return 0;
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_base.h b/chromium/ui/accessibility/platform/ax_platform_node_base.h
index 23d8794a157..f8e7dccdd2a 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_base.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_base.h
@@ -28,6 +28,8 @@ namespace ui {
struct AXNodeData;
+// TODO(nektar): Move this struct over to AXNode so that it can be accessed by
+// AXPosition.
struct AX_EXPORT AXHypertext {
AXHypertext();
~AXHypertext();
@@ -62,13 +64,12 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
// These are simple wrappers to our delegate.
const AXNodeData& GetData() const;
- gfx::NativeViewAccessible GetFocus();
+ gfx::NativeViewAccessible GetFocus() const;
gfx::NativeViewAccessible GetParent() const;
int GetChildCount() const;
gfx::NativeViewAccessible ChildAtIndex(int index) const;
std::string GetName() const;
- base::string16 GetNameAsString16() const;
// This returns nullopt if there's no parent, it's unable to find the child in
// the list of its parent's children, or its parent doesn't have children.
@@ -225,8 +226,11 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
// Returns true if either a descendant has selection (sel_focus_object_id) or
// if this node is a simple text element and has text selection attributes.
- // Optionally accepts an unignored selection to avoid redundant computation.
- bool HasCaret(const AXTree::Selection* unignored_selection = nullptr);
+ // Optionally accepts a selection, which can be useful if checking the
+ // unignored selection is required. If not provided, uses the selection from
+ // the tree data, which is safe and fast but does not take ignored nodes into
+ // account.
+ bool HasCaret(const AXTree::Selection* selection = nullptr);
// See AXPlatformNodeDelegate::IsChildOfLeaf().
bool IsChildOfLeaf() const;
@@ -237,6 +241,9 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
// See AXPlatformNodeDelegate::IsInvisibleOrIgnored().
bool IsInvisibleOrIgnored() const;
+ // Returns true if this node is currently focused.
+ bool IsFocused() const;
+
// Returns true if this node can be scrolled either in the horizontal or the
// vertical direction.
bool IsScrollable() const;
@@ -269,14 +276,14 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
bool HasFocus();
// If this node is a leaf, returns the visible accessible name of this node.
- // Otherwise represents every non-leaf child node with a special "embedded
- // object character", and every leaf child node with its visible accessible
+ // Otherwise represents every non-textual child node with a special "embedded
+ // object character", and every textual child node with its visible accessible
// name. This is how displayed text and embedded objects are represented in
// ATK and IA2 APIs.
base::string16 GetHypertext() const;
- // Returns the text of this node and all descendant nodes; including text
- // found in embedded objects.
+ // Returns the text that is found inside this node and all its descendants;
+ // including text found in embedded objects.
//
// Only text displayed on screen is included. Text from ARIA and HTML
// attributes that is either not displayed on screen, or outside this node,
@@ -340,8 +347,8 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
ui::TextAttributeList ComputeTextAttributes() const;
- // Get the number of items selected. It checks kMultiselectable and
- // kFocusable. and uses GetSelectedItems to get the selected number.
+ // Get the number of items selected. It checks kMultiselectable and uses
+ // GetSelectedItems to get the selected number.
int GetSelectionCount() const;
// If this object is a container that supports selectable children, returns
@@ -363,7 +370,16 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
//
AXPlatformNodeDelegate* delegate_ = nullptr;
- bool IsDocument() const;
+ // Uses the delegate to calculate this node's PosInSet.
+ base::Optional<int> GetPosInSet() const;
+
+ // Uses the delegate to calculate this node's SetSize.
+ base::Optional<int> GetSetSize() const;
+
+ // Returns true if this object is at the root of what most accessibility APIs
+ // consider to be a document, such as the root of a webpage, an iframe, or a
+ // PDF.
+ bool IsPlatformDocument() const;
protected:
bool IsSelectionItemSupported() const;
@@ -387,7 +403,7 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
#if BUILDFLAG(USE_ATK)
using PlatformAttributeList = AtkAttributeSet*;
#else
- using PlatformAttributeList = std::vector<base::string16>;
+ using PlatformAttributeList = std::vector<std::wstring>;
#endif
// Compute the attributes exposed via platform accessibility objects and put
@@ -490,9 +506,6 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
size_t* old_len,
size_t* new_len);
- base::Optional<int> GetPosInSet() const;
- base::Optional<int> GetSetSize() const;
-
std::string GetInvalidValue() const;
// Based on the characteristics of this object, such as its role and the
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_base_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_base_unittest.cc
index 54991d0b866..a88b1036d0d 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_base_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_base_unittest.cc
@@ -55,7 +55,7 @@ TEST(AXPlatformNodeBaseTest, GetHypertext) {
update.nodes.resize(4);
update.nodes[0].id = 1;
- update.nodes[0].role = ax::mojom::Role::kWebArea;
+ update.nodes[0].role = ax::mojom::Role::kRootWebArea;
update.nodes[0].child_ids = {2, 3, 4};
MakeStaticText(&update.nodes[1], 2, "text1");
@@ -101,7 +101,7 @@ TEST(AXPlatformNodeBaseTest, GetHypertextIgnoredContainerSiblings) {
update.nodes.resize(7);
update.nodes[0].id = 1;
- update.nodes[0].role = ax::mojom::Role::kWebArea;
+ update.nodes[0].role = ax::mojom::Role::kRootWebArea;
update.nodes[0].child_ids = {2, 4, 6};
update.nodes[1].id = 2;
@@ -204,6 +204,41 @@ TEST(AXPlatformNodeBaseTest, InnerTextIgnoresInvisibleAndIgnored) {
}
}
+TEST(AXPlatformNodeBaseTest, TestMenuSelectedItems) {
+ AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+
+ AXNodeData root_data;
+ root_data.id = 1;
+ root_data.role = ax::mojom::Role::kMenu;
+
+ AXNodeData item_1_data;
+ item_1_data.id = 2;
+ item_1_data.role = ax::mojom::Role::kMenuItem;
+ item_1_data.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+
+ AXNodeData item_2_data;
+ item_2_data.id = 3;
+ item_2_data.role = ax::mojom::Role::kMenuItem;
+
+ root_data.child_ids = {item_1_data.id, item_2_data.id};
+
+ AXTreeUpdate update;
+ update.root_id = 1;
+ update.nodes = {root_data, item_1_data, item_2_data};
+ AXTree tree(update);
+
+ auto* root = static_cast<AXPlatformNodeBase*>(
+ TestAXNodeWrapper::GetOrCreate(&tree, tree.root())->ax_platform_node());
+
+ int num = root->GetSelectionCount();
+ EXPECT_EQ(num, 1);
+
+ gfx::NativeViewAccessible first_child = root->ChildAtIndex(0);
+ AXPlatformNodeBase* first_selected_node = root->GetSelectedItem(0);
+ EXPECT_EQ(first_child, first_selected_node->GetNativeViewAccessible());
+ EXPECT_EQ(nullptr, root->GetSelectedItem(1));
+}
+
TEST(AXPlatformNodeBaseTest, TestSelectedChildren) {
AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
@@ -417,7 +452,7 @@ TEST(AXPlatformNodeBaseTest, CompareTo) {
AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
AXNodeData node1;
node1.id = 1;
- node1.role = ax::mojom::Role::kWebArea;
+ node1.role = ax::mojom::Role::kRootWebArea;
node1.child_ids = {2};
AXNodeData node2;
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_delegate.h b/chromium/ui/accessibility/platform/ax_platform_node_delegate.h
index acbf7f2e34f..eb1ea1bd9db 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -17,6 +17,7 @@
#include <vector>
#include "base/optional.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/accessibility/ax_clipping_behavior.h"
#include "ui/accessibility/ax_coordinate_system.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
@@ -93,7 +94,9 @@ class AX_EXPORT AXPlatformNodeDelegate {
// field.
virtual base::string16 GetValueForControl() const = 0;
- // Get the unignored selection from the tree
+ // Get the unignored selection from the tree, meaning the selection whose
+ // endpoints are on unignored nodes. (An ignored node means that the node
+ // should not be exposed to platform APIs: See `IsInvisibleOrIgnored`.)
virtual const AXTree::Selection GetUnignoredSelection() const = 0;
// Creates a text position rooted at this object.
@@ -117,9 +120,20 @@ class AX_EXPORT AXPlatformNodeDelegate {
virtual int GetIndexInParent() = 0;
// Get the number of children of this node.
+ //
+ // Note that for accessibility trees that have ignored nodes, this method
+ // should return the number of unignored children. All ignored nodes are
+ // recursively removed from the children count. (An ignored node means that
+ // the node should not be exposed to platform APIs: See
+ // `IsInvisibleOrIgnored`.)
virtual int GetChildCount() const = 0;
- // Get the child of a node given a 0-based index.
+ // Get a child of a node given a 0-based index.
+ //
+ // Note that for accessibility trees that have ignored nodes, this method
+ // returns only unignored children. All ignored nodes are recursively removed.
+ // (An ignored node means that the node should not be exposed to platform
+ // APIs: See `IsInvisibleOrIgnored`.)
virtual gfx::NativeViewAccessible ChildAtIndex(int index) = 0;
// Returns true if it has a modal dialog.
@@ -143,8 +157,8 @@ class AX_EXPORT AXPlatformNodeDelegate {
// platform's accessibility layer.
virtual bool IsChildOfLeaf() const = 0;
- // Returns true if this current node is editable and the root editable node is
- // a plain text field.
+ // Returns true if this node is either a plain text field , or one of its
+ // ancestors is.
virtual bool IsDescendantOfPlainTextField() const = 0;
// Returns true if this is a leaf node, meaning all its
@@ -152,15 +166,25 @@ class AX_EXPORT AXPlatformNodeDelegate {
// layer.
virtual bool IsLeaf() const = 0;
+ // Returns true if this node is invisible or ignored. (Only relevant for
+ // accessibility trees that support ignored nodes.)
+ virtual bool IsInvisibleOrIgnored() const = 0;
+
+ // Returns true if this node is focused.
+ virtual bool IsFocused() const = 0;
+
// Returns true if this is a top-level browser window that doesn't have a
// parent accessible node, or its parent is the application accessible node on
// platforms that have one.
virtual bool IsToplevelBrowserWindow() = 0;
// If this object is exposed to the platform's accessibility layer, returns
- // this object. Otherwise, returns the platform leaf under which this object
- // is found.
- virtual gfx::NativeViewAccessible GetClosestPlatformObject() const = 0;
+ // this object. Otherwise, returns the platform leaf or lowest unignored
+ // ancestor under which this object is found.
+ //
+ // (An ignored node means that the node should not be exposed to platform
+ // APIs: See `IsInvisibleOrIgnored`.)
+ virtual gfx::NativeViewAccessible GetLowestPlatformAncestor() const = 0;
class ChildIterator {
public:
@@ -259,7 +283,7 @@ class AX_EXPORT AXPlatformNodeDelegate {
// Return the node within this node's subtree (inclusive) that currently has
// focus, or return nullptr if this subtree is not connected to the top
// document through its ancestry chain.
- virtual gfx::NativeViewAccessible GetFocus() = 0;
+ virtual gfx::NativeViewAccessible GetFocus() const = 0;
// Get whether this node is offscreen.
virtual bool IsOffscreen() const = 0;
@@ -393,6 +417,10 @@ class AX_EXPORT AXPlatformNodeDelegate {
virtual base::Optional<int> GetPosInSet() const = 0;
virtual base::Optional<int> GetSetSize() const = 0;
+ // Computed colors, taking blending into account.
+ virtual SkColor GetColor() const = 0;
+ virtual SkColor GetBackgroundColor() 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 ba49fe98b82..cbc3c5ce561 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -160,6 +160,14 @@ bool AXPlatformNodeDelegateBase::IsLeaf() const {
return !GetChildCount();
}
+bool AXPlatformNodeDelegateBase::IsFocused() const {
+ return false;
+}
+
+bool AXPlatformNodeDelegateBase::IsInvisibleOrIgnored() const {
+ return false;
+}
+
bool AXPlatformNodeDelegateBase::IsToplevelBrowserWindow() {
return false;
}
@@ -168,9 +176,38 @@ bool AXPlatformNodeDelegateBase::IsDescendantOfPlainTextField() const {
return false;
}
-gfx::NativeViewAccessible AXPlatformNodeDelegateBase::GetClosestPlatformObject()
- const {
- return nullptr;
+gfx::NativeViewAccessible
+AXPlatformNodeDelegateBase::GetLowestPlatformAncestor() const {
+ AXPlatformNodeDelegateBase* current_delegate =
+ const_cast<AXPlatformNodeDelegateBase*>(this);
+ AXPlatformNodeDelegateBase* lowest_unignored_delegate = current_delegate;
+ if (lowest_unignored_delegate->IsInvisibleOrIgnored()) {
+ lowest_unignored_delegate = static_cast<AXPlatformNodeDelegateBase*>(
+ lowest_unignored_delegate->GetParentDelegate());
+ }
+ DCHECK(!lowest_unignored_delegate ||
+ !lowest_unignored_delegate->IsInvisibleOrIgnored())
+ << "`AXPlatformNodeDelegateBase::GetParentDelegate()` should return "
+ "either an unignored object or nullptr.";
+
+ // `highest_leaf_delegate` could be nullptr.
+ AXPlatformNodeDelegateBase* highest_leaf_delegate = lowest_unignored_delegate;
+ // For the purposes of this method, a leaf node does not include leaves in the
+ // internal accessibility tree, only in the platform exposed tree.
+ for (AXPlatformNodeDelegateBase* ancestor_delegate =
+ lowest_unignored_delegate;
+ ancestor_delegate;
+ ancestor_delegate = static_cast<AXPlatformNodeDelegateBase*>(
+ ancestor_delegate->GetParentDelegate())) {
+ if (ancestor_delegate->IsLeaf())
+ highest_leaf_delegate = ancestor_delegate;
+ }
+ if (highest_leaf_delegate)
+ return highest_leaf_delegate->GetNativeViewAccessible();
+
+ if (lowest_unignored_delegate)
+ return lowest_unignored_delegate->GetNativeViewAccessible();
+ return current_delegate->GetNativeViewAccessible();
}
AXPlatformNodeDelegateBase::ChildIteratorBase::ChildIteratorBase(
@@ -313,7 +350,7 @@ gfx::NativeViewAccessible AXPlatformNodeDelegateBase::HitTestSync(
return nullptr;
}
-gfx::NativeViewAccessible AXPlatformNodeDelegateBase::GetFocus() {
+gfx::NativeViewAccessible AXPlatformNodeDelegateBase::GetFocus() const {
return nullptr;
}
@@ -439,13 +476,23 @@ base::Optional<int> AXPlatformNodeDelegateBase::GetTableCellRowSpan() const {
base::Optional<int> AXPlatformNodeDelegateBase::GetTableCellAriaColIndex()
const {
- return GetData().GetIntAttribute(
- ax::mojom::IntAttribute::kAriaCellColumnIndex);
+ if (GetData().HasIntAttribute(
+ ax::mojom::IntAttribute::kAriaCellColumnIndex)) {
+ return GetData().GetIntAttribute(
+ ax::mojom::IntAttribute::kAriaCellColumnIndex);
+ }
+
+ return base::nullopt;
}
base::Optional<int> AXPlatformNodeDelegateBase::GetTableCellAriaRowIndex()
const {
- return GetData().GetIntAttribute(ax::mojom::IntAttribute::kAriaCellRowIndex);
+ if (GetData().HasIntAttribute(ax::mojom::IntAttribute::kAriaCellRowIndex)) {
+ return GetData().GetIntAttribute(
+ ax::mojom::IntAttribute::kAriaCellRowIndex);
+ }
+
+ return base::nullopt;
}
base::Optional<int32_t> AXPlatformNodeDelegateBase::GetCellId(
@@ -487,6 +534,14 @@ base::Optional<int> AXPlatformNodeDelegateBase::GetSetSize() const {
return base::nullopt;
}
+SkColor AXPlatformNodeDelegateBase::GetColor() const {
+ return SK_ColorBLACK;
+}
+
+SkColor AXPlatformNodeDelegateBase::GetBackgroundColor() const {
+ return SK_ColorWHITE;
+}
+
bool AXPlatformNodeDelegateBase::AccessibilityPerformAction(
const ui::AXActionData& data) {
return false;
@@ -553,7 +608,7 @@ bool AXPlatformNodeDelegateBase::IsWebContent() const {
}
bool AXPlatformNodeDelegateBase::HasVisibleCaretOrSelection() const {
- return false;
+ return IsDescendantOfPlainTextField();
}
AXPlatformNode* AXPlatformNodeDelegateBase::GetTargetNodeForRelation(
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 43459f18b43..46f1e9a3222 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -74,8 +74,9 @@ class AX_EXPORT AXPlatformNodeDelegateBase : public AXPlatformNodeDelegate {
bool IsChildOfLeaf() const override;
bool IsDescendantOfPlainTextField() const override;
bool IsLeaf() const override;
+ bool IsFocused() const override;
bool IsToplevelBrowserWindow() override;
- gfx::NativeViewAccessible GetClosestPlatformObject() const override;
+ gfx::NativeViewAccessible GetLowestPlatformAncestor() const override;
class ChildIteratorBase : public ChildIterator {
public:
@@ -149,11 +150,14 @@ class AX_EXPORT AXPlatformNodeDelegateBase : public AXPlatformNodeDelegate {
// Return the node within this node's subtree (inclusive) that currently
// has focus.
- gfx::NativeViewAccessible GetFocus() override;
+ gfx::NativeViewAccessible GetFocus() const override;
// Get whether this node is offscreen.
bool IsOffscreen() const override;
+ // Returns true if this node is invisible or ignored.
+ bool IsInvisibleOrIgnored() const override;
+
// Get whether this node is a minimized window.
bool IsMinimized() const override;
bool IsText() const override;
@@ -256,6 +260,10 @@ class AX_EXPORT AXPlatformNodeDelegateBase : public AXPlatformNodeDelegate {
base::Optional<int> GetPosInSet() const override;
base::Optional<int> GetSetSize() const override;
+ // Computed colors, taking blending into account.
+ SkColor GetColor() const override;
+ SkColor GetBackgroundColor() const override;
+
//
// Events.
//
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
index afd130143d7..3ef8956d61f 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
+++ b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -36,6 +36,8 @@ struct AnnouncementSpec {
};
RoleMap BuildRoleMap() {
+ // TODO(accessibility) Are any missing? Consider switch statement so that
+ // compiler doesn't allow missing roles;
const RoleMap::value_type roles[] = {
{ax::mojom::Role::kAbbr, NSAccessibilityGroupRole},
{ax::mojom::Role::kAlert, NSAccessibilityGroupRole},
@@ -55,8 +57,8 @@ RoleMap BuildRoleMap() {
{ax::mojom::Role::kColorWell, NSAccessibilityColorWellRole},
{ax::mojom::Role::kColumn, NSAccessibilityColumnRole},
{ax::mojom::Role::kColumnHeader, @"AXCell"},
- {ax::mojom::Role::kComboBoxGrouping, NSAccessibilityGroupRole},
- {ax::mojom::Role::kComboBoxMenuButton, NSAccessibilityPopUpButtonRole},
+ {ax::mojom::Role::kComboBoxGrouping, NSAccessibilityComboBoxRole},
+ {ax::mojom::Role::kComboBoxMenuButton, NSAccessibilityComboBoxRole},
{ax::mojom::Role::kComment, NSAccessibilityGroupRole},
{ax::mojom::Role::kComplementary, NSAccessibilityGroupRole},
{ax::mojom::Role::kContentDeletion, NSAccessibilityGroupRole},
@@ -172,6 +174,7 @@ RoleMap BuildRoleMap() {
{ax::mojom::Role::kNote, NSAccessibilityGroupRole},
{ax::mojom::Role::kParagraph, NSAccessibilityGroupRole},
{ax::mojom::Role::kPdfActionableHighlight, NSAccessibilityButtonRole},
+ {ax::mojom::Role::kPdfRoot, NSAccessibilityGroupRole},
{ax::mojom::Role::kPluginObject, NSAccessibilityGroupRole},
{ax::mojom::Role::kPopUpButton, NSAccessibilityPopUpButtonRole},
{ax::mojom::Role::kPortal, NSAccessibilityButtonRole},
@@ -186,16 +189,13 @@ RoleMap BuildRoleMap() {
{ax::mojom::Role::kRow, NSAccessibilityRowRole},
{ax::mojom::Role::kRowGroup, NSAccessibilityGroupRole},
{ax::mojom::Role::kRowHeader, @"AXCell"},
- // TODO(accessibility) What should kRuby be? It's not listed? Any others
- // missing? Maybe use switch statement so that compiler doesn't allow us
- // to miss any.
+ {ax::mojom::Role::kRuby, NSAccessibilityGroupRole},
{ax::mojom::Role::kRubyAnnotation, NSAccessibilityUnknownRole},
{ax::mojom::Role::kScrollBar, NSAccessibilityScrollBarRole},
{ax::mojom::Role::kSearch, NSAccessibilityGroupRole},
{ax::mojom::Role::kSearchBox, NSAccessibilityTextFieldRole},
{ax::mojom::Role::kSection, NSAccessibilityGroupRole},
{ax::mojom::Role::kSlider, NSAccessibilitySliderRole},
- {ax::mojom::Role::kSliderThumb, NSAccessibilityValueIndicatorRole},
{ax::mojom::Role::kSpinButton, NSAccessibilityIncrementorRole},
{ax::mojom::Role::kSplitter, NSAccessibilitySplitterRole},
{ax::mojom::Role::kStaticText, NSAccessibilityStaticTextRole},
@@ -222,7 +222,6 @@ RoleMap BuildRoleMap() {
{ax::mojom::Role::kTreeGrid, NSAccessibilityTableRole},
{ax::mojom::Role::kTreeItem, NSAccessibilityRowRole},
{ax::mojom::Role::kVideo, NSAccessibilityGroupRole},
- {ax::mojom::Role::kWebArea, @"AXWebArea"},
// Use the group role as the BrowserNativeWidgetWindow already provides
// a kWindow role, and having extra window roles, which are treated
// specially by screen readers, can break their ability to find the
@@ -288,6 +287,10 @@ EventMap BuildEventMap() {
NSAccessibilityFocusedUIElementChangedNotification},
{ax::mojom::Event::kFocusContext,
NSAccessibilityFocusedUIElementChangedNotification},
+ {ax::mojom::Event::kMenuStart, (id)kAXMenuOpenedNotification},
+ {ax::mojom::Event::kMenuEnd, (id)kAXMenuClosedNotification},
+ {ax::mojom::Event::kMenuPopupStart, (id)kAXMenuOpenedNotification},
+ {ax::mojom::Event::kMenuPopupEnd, (id)kAXMenuClosedNotification},
{ax::mojom::Event::kTextChanged, NSAccessibilityTitleChangedNotification},
{ax::mojom::Event::kValueChanged,
NSAccessibilityValueChangedNotification},
@@ -351,6 +354,12 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
data.role == ax::mojom::Role::kPopUpButton;
}
+// Check whether |selector| is an accessibility setter. This is a heuristic but
+// seems to be a pretty good one.
+bool IsAXSetter(SEL selector) {
+ return [NSStringFromSelector(selector) hasPrefix:@"setAccessibility"];
+}
+
} // namespace
@interface AXPlatformNodeCocoa (Private)
@@ -490,7 +499,7 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
return YES;
return [[self AXRole] isEqualToString:NSAccessibilityUnknownRole] ||
- _node->GetData().HasState(ax::mojom::State::kInvisible);
+ _node->IsInvisibleOrIgnored();
}
- (id)accessibilityHitTest:(NSPoint)point {
@@ -623,7 +632,6 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
case ax::mojom::Role::kRadioButton:
case ax::mojom::Role::kSearchBox:
case ax::mojom::Role::kSlider:
- case ax::mojom::Role::kSliderThumb:
case ax::mojom::Role::kToggleButton:
[axAttributes addObjectsFromArray:kValueAttributes];
break;
@@ -631,12 +639,14 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
default:
break;
}
- if (_node->GetData().HasBoolAttribute(ax::mojom::BoolAttribute::kSelected)) {
- [axAttributes addObjectsFromArray:@[ NSAccessibilitySelectedAttribute ]];
- }
- if (ui::IsMenuItem(_node->GetData().role)) {
- [axAttributes addObjectsFromArray:@[ @"AXMenuItemMarkChar" ]];
- }
+ if (_node->GetData().HasBoolAttribute(ax::mojom::BoolAttribute::kSelected))
+ [axAttributes addObject:NSAccessibilitySelectedAttribute];
+ if (ui::IsMenuItem(_node->GetData().role))
+ [axAttributes addObject:@"AXMenuItemMarkChar"];
+ if (ui::IsItemLike(_node->GetData().role))
+ [axAttributes addObjectsFromArray:@[ @"AXARIAPosInSet", @"AXARIASetSize" ]];
+ if (ui::IsSetLike(_node->GetData().role))
+ [axAttributes addObject:@"AXARIASetSize"];
return axAttributes.autorelease();
}
@@ -696,6 +706,10 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
}
- (NSString*)AXRoleDescription {
+ if (_node->HasStringAttribute(ax::mojom::StringAttribute::kRoleDescription)) {
+ return [base::SysUTF8ToNSString(_node->GetStringAttribute(
+ ax::mojom::StringAttribute::kRoleDescription)) lowercaseString];
+ }
switch (_node->GetData().role) {
case ax::mojom::Role::kTab:
// There is no NSAccessibilityTabRole or similar (AXRadioButton is used
@@ -836,6 +850,20 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
return @"";
}
+- (NSNumber*)AXARIAPosInSet {
+ base::Optional<int> posInSet = _node->GetPosInSet();
+ if (!posInSet)
+ return nil;
+ return @(*posInSet);
+}
+
+- (NSNumber*)AXARIASetSize {
+ base::Optional<int> setSize = _node->GetSetSize();
+ if (!setSize)
+ return nil;
+ return @(*setSize);
+}
+
// Text-specific attributes.
- (NSString*)AXSelectedText {
@@ -955,7 +983,7 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
return NO;
return (![[self AXRole] isEqualToString:NSAccessibilityUnknownRole] &&
- !_node->GetData().HasState(ax::mojom::State::kInvisible));
+ !_node->IsInvisibleOrIgnored());
}
- (BOOL)isAccessibilityEnabled {
if (!_node)
@@ -991,37 +1019,34 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
return [self AXSubrole];
}
+- (NSString*)accessibilityRoleDescription {
+ return [self AXRoleDescription];
+}
+
- (BOOL)isAccessibilitySelectorAllowed:(SEL)selector {
if (!_node)
return NO;
- const ax::mojom::Restriction restriction = _node->GetData().GetRestriction();
- if (restriction == ax::mojom::Restriction::kDisabled)
- return NO;
+ if (selector == @selector(setAccessibilityFocused:))
+ return _node->GetData().HasState(ax::mojom::State::kFocusable);
- if (selector == @selector(setAccessibilityValue:)) {
+ if (selector == @selector(setAccessibilityValue:) &&
+ _node->GetData().role == ax::mojom::Role::kTab) {
// Tabs use the radio button role on Mac, so they are selected by calling
// setSelected on an individual tab, rather than by setting the selected
// element on the tabstrip as a whole.
- if (_node->GetData().role == ax::mojom::Role::kTab) {
- return !_node->GetData().GetBoolAttribute(
- ax::mojom::BoolAttribute::kSelected);
- }
- return restriction != ax::mojom::Restriction::kReadOnly;
+ return !_node->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected);
}
+ // Don't allow calling AX setters on disabled elements.
// TODO(https://crbug.com/692362): Once the underlying bug in
// views::Textfield::SetSelectionRange() described in that bug is fixed,
- // remove the check here; right now, this check serves to prevent
- // accessibility clients from trying to set the selection range, which won't
- // work because of 692362.
- if (selector == @selector(setAccessibilitySelectedText:) ||
- selector == @selector(setAccessibilitySelectedTextRange:)) {
- return restriction != ax::mojom::Restriction::kReadOnly;
- }
-
- if (selector == @selector(setAccessibilityFocused:))
- return _node->GetData().HasState(ax::mojom::State::kFocusable);
+ // remove the check here when the selector is setAccessibilitySelectedText*;
+ // right now, this check serves to prevent accessibility clients from trying
+ // to set the selection range, which won't work because of 692362.
+ if (_node->GetData().IsReadOnlyOrDisabled() && IsAXSetter(selector))
+ return NO;
// TODO(https://crbug.com/386671): What about role-specific selectors?
return [super isAccessibilitySelectorAllowed:selector];
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
index ec5adb620d6..60bb50c0395 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
@@ -272,9 +272,8 @@ TEST_F(AXPlatformNodeTextChildProviderTest,
EXPECT_HRESULT_SUCCEEDED(
text_range_provider->GetText(-1, text_content.Receive()));
EXPECT_EQ(
- 0,
- wcscmp(text_content.Get(),
- (kEmbeddedCharacterAsString + L"text child of nontext.").c_str()));
+ base::WideToUTF16(text_content.Get()),
+ kEmbeddedCharacterAsString + STRING16_LITERAL("text child of nontext."));
ComPtr<IRawElementProviderSimple> enclosing_element;
text_range_provider->GetEnclosingElement(&enclosing_element);
@@ -311,7 +310,7 @@ TEST_F(AXPlatformNodeTextChildProviderTest,
base::win::ScopedBstr text_content;
EXPECT_HRESULT_SUCCEEDED(
text_range_provider->GetText(-1, text_content.Receive()));
- EXPECT_EQ(0, wcscmp(text_content.Get(), kEmbeddedCharacterAsString.c_str()));
+ EXPECT_EQ(base::WideToUTF16(text_content.Get()), kEmbeddedCharacterAsString);
ComPtr<IRawElementProviderSimple> enclosing_element;
text_range_provider->GetEnclosingElement(&enclosing_element);
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win.cc b/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
index f5ecd975918..71b3a8847ad 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
@@ -300,9 +300,9 @@ ITextRangeProvider* AXPlatformNodeTextProviderWin::GetRangeFromChild(
descendant->GetDelegate()->CreateTextPositionAt(0)->AsLeafTextPosition();
AXNodePosition::AXPositionInstance end;
- if (descendant->IsDocument()) {
- // Fast path for getting the range of the web root.
- end = start->CreatePositionAtEndOfDocument();
+ if (descendant->IsPlatformDocument()) {
+ // Fast path for getting the range of the web or PDF root.
+ end = start->CreatePositionAtEndOfContent();
} else if (descendant->GetChildCount() == 0) {
end = descendant->GetDelegate()
->CreateTextPositionAt(0)
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win.h b/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win.h
index 92af71111f0..d216815bd57 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win.h
@@ -12,6 +12,7 @@
#include "ui/accessibility/platform/ax_platform_node_win.h"
namespace ui {
+
class __declspec(uuid("3e1c192b-4348-45ac-8eb6-4b58eeb3dcca"))
AXPlatformNodeTextProviderWin
: public CComObjectRootEx<CComMultiThreadModel>,
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
index 3d375fb06f5..82171aac0ee 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
@@ -38,7 +38,7 @@ class AXPlatformNodeTextProviderTest : public AXPlatformNodeWinTest {
const AXPlatformNodeTextProviderTest&) = delete;
protected:
- ui::AXPlatformNodeWin* GetOwner(
+ AXPlatformNodeWin* GetOwner(
const AXPlatformNodeTextProviderWin* text_provider) {
return text_provider->owner_.Get();
}
@@ -54,25 +54,25 @@ class AXPlatformNodeTextProviderTest : public AXPlatformNodeWinTest {
TEST_F(AXPlatformNodeTextProviderTest, ITextProviderRangeFromChild) {
- ui::AXNodeData text_data;
+ AXNodeData text_data;
text_data.id = 2;
text_data.role = ax::mojom::Role::kStaticText;
text_data.SetName("some text");
- ui::AXNodeData empty_text_data;
+ AXNodeData empty_text_data;
empty_text_data.id = 3;
empty_text_data.role = ax::mojom::Role::kStaticText;
- ui::AXNodeData root_data;
+ AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
root_data.SetName("Document");
root_data.child_ids.push_back(2);
root_data.child_ids.push_back(3);
- ui::AXTreeUpdate update;
- ui::AXTreeData tree_data;
- tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+ AXTreeUpdate update;
+ AXTreeData tree_data;
+ tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
update.tree_data = tree_data;
update.has_tree_data = true;
update.root_id = root_data.id;
@@ -152,50 +152,50 @@ TEST_F(AXPlatformNodeTextProviderTest,
const int BUTTON_TEXT_ID = 7;
const int DIALOG_DETAIL_ID = 8;
- ui::AXNodeData root;
+ AXNodeData root;
root.id = ROOT_ID;
root.role = ax::mojom::Role::kRootWebArea;
root.SetName("Document");
root.child_ids = {DIALOG_ID};
- ui::AXNodeData dialog;
+ AXNodeData dialog;
dialog.id = DIALOG_ID;
dialog.role = ax::mojom::Role::kDialog;
dialog.child_ids = {DIALOG_LABEL_ID, DIALOG_DESCRIPTION_ID, BUTTON_ID,
DIALOG_DETAIL_ID};
- ui::AXNodeData dialog_label;
+ AXNodeData dialog_label;
dialog_label.id = DIALOG_LABEL_ID;
dialog_label.role = ax::mojom::Role::kStaticText;
dialog_label.SetName("Dialog label.");
- ui::AXNodeData dialog_description;
+ AXNodeData dialog_description;
dialog_description.id = DIALOG_DESCRIPTION_ID;
dialog_description.role = ax::mojom::Role::kStaticText;
dialog_description.SetName("Dialog description.");
- ui::AXNodeData button;
+ AXNodeData button;
button.id = BUTTON_ID;
button.role = ax::mojom::Role::kButton;
button.child_ids = {BUTTON_IMG_ID, BUTTON_TEXT_ID};
- ui::AXNodeData button_img;
+ AXNodeData button_img;
button_img.id = BUTTON_IMG_ID;
button_img.role = ax::mojom::Role::kImage;
- ui::AXNodeData button_text;
+ AXNodeData button_text;
button_text.id = BUTTON_TEXT_ID;
button_text.role = ax::mojom::Role::kStaticText;
button_text.SetName("ok.");
- ui::AXNodeData dialog_detail;
+ AXNodeData dialog_detail;
dialog_detail.id = DIALOG_DETAIL_ID;
dialog_detail.role = ax::mojom::Role::kStaticText;
dialog_detail.SetName("Some more detail about dialog.");
- ui::AXTreeUpdate update;
- ui::AXTreeData tree_data;
- tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+ AXTreeUpdate update;
+ AXTreeData tree_data;
+ tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
update.tree_data = tree_data;
update.has_tree_data = true;
update.root_id = ROOT_ID;
@@ -224,11 +224,11 @@ TEST_F(AXPlatformNodeTextProviderTest,
base::win::ScopedBstr text_content;
EXPECT_HRESULT_SUCCEEDED(
text_range_provider->GetText(-1, text_content.Receive()));
- EXPECT_EQ(0, wcscmp(text_content.Get(), (L"Dialog label.Dialog description." +
- kEmbeddedCharacterAsString +
- "ok.Some more detail "
- L"about dialog.")
- .c_str()));
+ EXPECT_EQ(base::WideToUTF16(text_content.Get()),
+ STRING16_LITERAL("Dialog label.Dialog description.") +
+ kEmbeddedCharacterAsString +
+ STRING16_LITERAL("ok.Some more detail ") +
+ STRING16_LITERAL("about dialog."));
// Check the reverse relationship that GetEnclosingElement on the text range
// gives back the dialog.
@@ -239,7 +239,7 @@ TEST_F(AXPlatformNodeTextProviderTest,
}
TEST_F(AXPlatformNodeTextProviderTest, NearestTextIndexToPoint) {
- ui::AXNodeData text_data;
+ AXNodeData text_data;
text_data.id = 2;
text_data.role = ax::mojom::Role::kInlineTextBox;
text_data.SetName("text");
@@ -247,7 +247,7 @@ TEST_F(AXPlatformNodeTextProviderTest, NearestTextIndexToPoint) {
text_data.AddIntListAttribute(ax::mojom::IntListAttribute::kCharacterOffsets,
{2, 4, 8, 10});
- ui::AXNodeData root_data;
+ AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
root_data.relative_bounds.bounds = gfx::RectF(1, 1, 2, 2);
@@ -294,12 +294,12 @@ TEST_F(AXPlatformNodeTextProviderTest, NearestTextIndexToPoint) {
}
TEST_F(AXPlatformNodeTextProviderTest, ITextProviderDocumentRange) {
- ui::AXNodeData text_data;
+ AXNodeData text_data;
text_data.id = 2;
text_data.role = ax::mojom::Role::kStaticText;
text_data.SetName("some text");
- ui::AXNodeData root_data;
+ AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
root_data.SetName("Document");
@@ -320,17 +320,17 @@ TEST_F(AXPlatformNodeTextProviderTest, ITextProviderDocumentRange) {
}
TEST_F(AXPlatformNodeTextProviderTest, ITextProviderDocumentRangeNested) {
- ui::AXNodeData text_data;
+ AXNodeData text_data;
text_data.id = 3;
text_data.role = ax::mojom::Role::kStaticText;
text_data.SetName("some text");
- ui::AXNodeData paragraph_data;
+ AXNodeData paragraph_data;
paragraph_data.id = 2;
paragraph_data.role = ax::mojom::Role::kParagraph;
paragraph_data.child_ids.push_back(3);
- ui::AXNodeData root_data;
+ AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
root_data.SetName("Document");
@@ -351,12 +351,12 @@ TEST_F(AXPlatformNodeTextProviderTest, ITextProviderDocumentRangeNested) {
}
TEST_F(AXPlatformNodeTextProviderTest, ITextProviderSupportedSelection) {
- ui::AXNodeData text_data;
+ AXNodeData text_data;
text_data.id = 2;
text_data.role = ax::mojom::Role::kStaticText;
text_data.SetName("some text");
- ui::AXNodeData root_data;
+ AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
root_data.SetName("Document");
@@ -378,27 +378,27 @@ TEST_F(AXPlatformNodeTextProviderTest, ITextProviderSupportedSelection) {
}
TEST_F(AXPlatformNodeTextProviderTest, ITextProviderGetSelection) {
- ui::AXNodeData text_data;
+ AXNodeData text_data;
text_data.id = 2;
text_data.role = ax::mojom::Role::kStaticText;
text_data.SetName("some text");
- ui::AXNodeData textbox_data;
+ AXNodeData textbox_data;
textbox_data.id = 3;
textbox_data.role = ax::mojom::Role::kInlineTextBox;
textbox_data.SetName("textbox text");
textbox_data.AddState(ax::mojom::State::kEditable);
- ui::AXNodeData root_data;
+ AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
root_data.SetName("Document");
root_data.child_ids.push_back(2);
root_data.child_ids.push_back(3);
- ui::AXTreeUpdate update;
- ui::AXTreeData tree_data;
- tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+ AXTreeUpdate update;
+ AXTreeData tree_data;
+ tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
update.tree_data = tree_data;
update.has_tree_data = true;
update.root_id = root_data.id;
@@ -573,20 +573,20 @@ TEST_F(AXPlatformNodeTextProviderTest, ITextProviderGetSelection) {
}
TEST_F(AXPlatformNodeTextProviderTest, ITextProviderGetActiveComposition) {
- ui::AXNodeData text_data;
+ AXNodeData text_data;
text_data.id = 2;
text_data.role = ax::mojom::Role::kStaticText;
text_data.SetName("some text");
- ui::AXNodeData root_data;
+ AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
root_data.SetName("Document");
root_data.child_ids.push_back(2);
- ui::AXTreeUpdate update;
- ui::AXTreeData tree_data;
- tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+ AXTreeUpdate update;
+ AXTreeData tree_data;
+ tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
update.tree_data = tree_data;
update.has_tree_data = true;
update.root_id = root_data.id;
@@ -612,12 +612,12 @@ TEST_F(AXPlatformNodeTextProviderTest, ITextProviderGetActiveComposition) {
ComPtr<AXPlatformNodeTextProviderWin> root_platform_node;
root_text_provider->QueryInterface(IID_PPV_ARGS(&root_platform_node));
- ui::AXActionData action_data;
+ AXActionData action_data;
action_data.action = ax::mojom::Action::kFocus;
action_data.target_node_id = 1;
AXPlatformNodeWin* owner = GetOwner(root_platform_node.Get());
owner->GetDelegate()->AccessibilityPerformAction(action_data);
- const base::string16 active_composition_text = L"a";
+ const base::string16 active_composition_text = STRING16_LITERAL("a");
owner->OnActiveComposition(gfx::Range(0, 1), active_composition_text, false);
root_text_edit_provider->GetActiveComposition(&text_range_provider);
@@ -633,20 +633,20 @@ TEST_F(AXPlatformNodeTextProviderTest, ITextProviderGetActiveComposition) {
}
TEST_F(AXPlatformNodeTextProviderTest, ITextProviderGetConversionTarget) {
- ui::AXNodeData text_data;
+ AXNodeData text_data;
text_data.id = 2;
text_data.role = ax::mojom::Role::kStaticText;
text_data.SetName("some text");
- ui::AXNodeData root_data;
+ AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
root_data.SetName("Document");
root_data.child_ids.push_back(2);
- ui::AXTreeUpdate update;
- ui::AXTreeData tree_data;
- tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+ AXTreeUpdate update;
+ AXTreeData tree_data;
+ tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
update.tree_data = tree_data;
update.has_tree_data = true;
update.root_id = root_data.id;
@@ -672,12 +672,12 @@ TEST_F(AXPlatformNodeTextProviderTest, ITextProviderGetConversionTarget) {
ComPtr<AXPlatformNodeTextProviderWin> root_platform_node;
root_text_provider->QueryInterface(IID_PPV_ARGS(&root_platform_node));
- ui::AXActionData action_data;
+ AXActionData action_data;
action_data.action = ax::mojom::Action::kFocus;
action_data.target_node_id = 1;
AXPlatformNodeWin* owner = GetOwner(root_platform_node.Get());
owner->GetDelegate()->AccessibilityPerformAction(action_data);
- const base::string16 active_composition_text = L"a";
+ const base::string16 active_composition_text = STRING16_LITERAL("a");
owner->OnActiveComposition(gfx::Range(0, 1), active_composition_text, false);
root_text_edit_provider->GetConversionTarget(&text_range_provider);
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
index f8410f3b3c6..b5d734ed27a 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -56,12 +56,13 @@ namespace ui {
class AXRangePhysicalPixelRectDelegate : public AXRangeRectDelegate {
public:
- AXRangePhysicalPixelRectDelegate(AXPlatformNodeTextRangeProviderWin* host)
+ explicit AXRangePhysicalPixelRectDelegate(
+ AXPlatformNodeTextRangeProviderWin* host)
: host_(host) {}
gfx::Rect GetInnerTextRangeBoundsRect(
AXTreeID tree_id,
- AXNode::AXID node_id,
+ AXNodeID node_id,
int start_offset,
int end_offset,
AXOffscreenResult* offscreen_result) override {
@@ -73,7 +74,7 @@ class AXRangePhysicalPixelRectDelegate : public AXRangeRectDelegate {
}
gfx::Rect GetBoundsRect(AXTreeID tree_id,
- AXNode::AXID node_id,
+ AXNodeID node_id,
AXOffscreenResult* offscreen_result) override {
AXPlatformNodeDelegate* delegate = host_->GetDelegate(tree_id, node_id);
DCHECK(delegate);
@@ -242,7 +243,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::ExpandToEnclosingUnitImpl(
// no word boundaries, like whitespaces and punctuation. When it happens,
// move the position back to the start of the document.
if (start()->IsNullPosition())
- SetStart(start_backup->CreatePositionAtStartOfDocument());
+ SetStart(start_backup->CreatePositionAtStartOfContent());
// Since start_ is already located at a word boundary, we need to cross it
// in order to move to the next one. Because Windows ATs behave
@@ -284,9 +285,8 @@ HRESULT AXPlatformNodeTextRangeProviderWin::ExpandToEnclosingUnitImpl(
}
FALLTHROUGH;
case TextUnit_Document:
- SetStart(
- start()->CreatePositionAtStartOfDocument()->AsLeafTextPosition());
- SetEnd(start()->CreatePositionAtEndOfDocument());
+ SetStart(start()->CreatePositionAtStartOfContent()->AsLeafTextPosition());
+ SetEnd(start()->CreatePositionAtEndOfContent());
break;
default:
return UIA_E_NOTSUPPORTED;
@@ -436,7 +436,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::FindText(
WIN_ACCESSIBILITY_API_PERF_HISTOGRAM(UMA_API_TEXTRANGE_FINDTEXT);
UIA_VALIDATE_TEXTRANGEPROVIDER_CALL_1_IN_1_OUT(string, result);
- base::string16 search_string(string);
+ base::string16 search_string = base::WideToUTF16(string);
if (search_string.length() <= 0)
return E_INVALIDARG;
@@ -455,13 +455,14 @@ HRESULT AXPlatformNodeTextRangeProviderWin::FindText(
// someday, and if so, we'll have to address this issue.
const AXNode* common_anchor = start()->LowestCommonAnchor(*end());
AXPositionInstance start_ancestor_position =
- start()->CreateAncestorPosition(common_anchor);
+ start()->CreateAncestorPosition(common_anchor,
+ ax::mojom::MoveDirection::kForward);
DCHECK(!start_ancestor_position->IsNullPosition());
- AXPositionInstance end_ancestor_position =
- end()->CreateAncestorPosition(common_anchor);
+ AXPositionInstance end_ancestor_position = end()->CreateAncestorPosition(
+ common_anchor, ax::mojom::MoveDirection::kForward);
DCHECK(!end_ancestor_position->IsNullPosition());
AXTreeID tree_id = start_ancestor_position->tree_id();
- AXNode::AXID anchor_id = start_ancestor_position->anchor_id();
+ AXNodeID anchor_id = start_ancestor_position->anchor_id();
const int start_offset =
start_ancestor_position->text_offset() + find_start;
const int end_offset = start_offset + find_length - appended_newlines_count;
@@ -519,13 +520,12 @@ HRESULT AXPlatformNodeTextRangeProviderWin::GetAttributeValue(
delegate->GetFromNodeID(it->anchor_id()));
DCHECK(platform_node);
- // Only get attributes for nodes in the tree
- if (platform_node->GetDelegate()->IsChildOfLeaf()) {
- platform_node = static_cast<AXPlatformNodeWin*>(
- AXPlatformNode::FromNativeViewAccessible(
- platform_node->GetDelegate()->GetClosestPlatformObject()));
- DCHECK(platform_node);
- }
+ // Only get attributes for nodes in the tree. Exclude descendants of leaves
+ // and ignored objects.
+ platform_node = static_cast<AXPlatformNodeWin*>(
+ AXPlatformNode::FromNativeViewAccessible(
+ platform_node->GetDelegate()->GetLowestPlatformAncestor()));
+ DCHECK(platform_node);
base::win::VariantVector current_value;
const bool at_end_leaf_text_anchor =
@@ -639,7 +639,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::GetText(int max_count, BSTR* text) {
if (max_count < -1)
return E_INVALIDARG;
- base::string16 full_text = GetString(max_count);
+ std::wstring full_text = base::UTF16ToWide(GetString(max_count));
if (!full_text.empty()) {
size_t length = full_text.length();
@@ -680,7 +680,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::Move(TextUnit unit,
SetEnd(start()->Clone());
if (!is_degenerate_range) {
bool forwards = count > 0;
- if (forwards && start()->AtEndOfDocument()) {
+ if (forwards && start()->AtEndOfContent()) {
// The start is at the end of the document, so move the start backward
// by one text unit to expand the text range from the degenerate range
// state.
@@ -896,12 +896,14 @@ HRESULT AXPlatformNodeTextRangeProviderWin::ScrollIntoView(BOOL align_to_top) {
UIA_VALIDATE_TEXTRANGEPROVIDER_CALL();
const AXPositionInstance start_common_ancestor =
- start()->LowestCommonAncestor(*end());
+ start()->LowestCommonAncestor(*end(),
+ ax::mojom::MoveDirection::kBackward);
const AXPositionInstance end_common_ancestor =
- end()->LowestCommonAncestor(*start());
+ end()->LowestCommonAncestor(*start(), ax::mojom::MoveDirection::kForward);
if (start_common_ancestor->IsNullPosition() ||
- end_common_ancestor->IsNullPosition())
+ end_common_ancestor->IsNullPosition()) {
return E_INVALIDARG;
+ }
const AXNode* common_ancestor_anchor = start_common_ancestor->GetAnchor();
DCHECK(common_ancestor_anchor == end_common_ancestor->GetAnchor());
@@ -979,7 +981,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::GetChildren(SAFEARRAY** children) {
if (!common_anchor)
return UIA_E_ELEMENTNOTAVAILABLE;
const AXTreeID tree_id = common_anchor->tree()->GetAXTreeID();
- const AXNode::AXID node_id = common_anchor->id();
+ const AXNodeID node_id = common_anchor->id();
AXPlatformNodeDelegate* delegate = GetDelegate(tree_id, node_id);
DCHECK(delegate);
while (delegate->GetData().IsIgnored()) {
@@ -1074,7 +1076,7 @@ AXPlatformNodeDelegate* AXPlatformNodeTextRangeProviderWin::GetDelegate(
AXPlatformNodeDelegate* AXPlatformNodeTextRangeProviderWin::GetDelegate(
const AXTreeID tree_id,
- const AXNode::AXID node_id) const {
+ const AXNodeID node_id) const {
AXPlatformNode* platform_node =
owner_->GetDelegate()->GetFromTreeIDAndNodeID(tree_id, node_id);
if (!platform_node)
@@ -1147,7 +1149,12 @@ AXPlatformNodeTextRangeProviderWin::MoveEndpointByPage(
int* units_moved) {
// Per UIA spec, if the document containing the current endpoint doesn't
// support pagination, default to document navigation.
- AXPositionInstance common_ancestor = start()->LowestCommonAncestor(*end());
+ //
+ // Note that the "ax::mojom::MoveDirection" should not matter when calculating
+ // the ancestor position for use when navigating by page or document, so we
+ // use a backward direction as the default.
+ AXPositionInstance common_ancestor = start()->LowestCommonAncestor(
+ *end(), ax::mojom::MoveDirection::kBackward);
if (!common_ancestor->GetAnchor()->tree()->HasPaginationSupport())
return MoveEndpointByDocument(std::move(endpoint), count, units_moved);
@@ -1166,11 +1173,11 @@ AXPlatformNodeTextRangeProviderWin::MoveEndpointByDocument(
DCHECK_NE(count, 0);
if (count < 0) {
- *units_moved = !endpoint->AtStartOfDocument() ? -1 : 0;
- return endpoint->CreatePositionAtStartOfDocument();
+ *units_moved = !endpoint->AtStartOfContent() ? -1 : 0;
+ return endpoint->CreatePositionAtStartOfContent();
}
- *units_moved = !endpoint->AtEndOfDocument() ? 1 : 0;
- return endpoint->CreatePositionAtEndOfDocument();
+ *units_moved = !endpoint->AtEndOfContent() ? 1 : 0;
+ return endpoint->CreatePositionAtEndOfContent();
}
AXPlatformNodeTextRangeProviderWin::AXPositionInstance
@@ -1190,21 +1197,30 @@ AXPlatformNodeTextRangeProviderWin::MoveEndpointByUnitHelper(
AXPositionInstance current_endpoint = endpoint->AsLeafTextPosition();
for (int iteration = 0; iteration < std::abs(count); ++iteration) {
- AXPositionInstance next_endpoint = GetNextTextBoundaryPosition(
- current_endpoint, boundary_type,
- AXBoundaryBehavior::StopAtLastAnchorBoundary, boundary_direction);
- DCHECK(next_endpoint->IsLeafTextPosition());
-
- // Since AXBoundaryBehavior::StopAtLastAnchorBoundary forces the next text
- // boundary position to be different than the input position, the only case
- // where these are equal is when they're already located at the last anchor
- // boundary. In such case, there is no next position to move to.
- if (next_endpoint->GetAnchor() == current_endpoint->GetAnchor() &&
- *next_endpoint == *current_endpoint) {
- *units_moved = (count > 0) ? iteration : -iteration;
- return current_endpoint;
- }
- current_endpoint = std::move(next_endpoint);
+ do {
+ AXPositionInstance next_endpoint = GetNextTextBoundaryPosition(
+ current_endpoint, boundary_type,
+ AXBoundaryBehavior::StopAtLastAnchorBoundary, boundary_direction);
+ DCHECK(next_endpoint->IsLeafTextPosition());
+
+ // Since AXBoundaryBehavior::StopAtLastAnchorBoundary forces the next text
+ // boundary position to be different than the input position, the only
+ // case where these are equal is when they're already located at the last
+ // anchor boundary. In such case, there is no next position to move to.
+ if (next_endpoint->GetAnchor() == current_endpoint->GetAnchor() &&
+ *next_endpoint == *current_endpoint) {
+ *units_moved = (count > 0) ? iteration : -iteration;
+ return current_endpoint;
+ }
+ current_endpoint = std::move(next_endpoint);
+ // Loop until we're not on a position that is ignored for text navigation.
+ // There is one exception for character navigation - since the ignored
+ // anchor is represented by an embedded object character, we allow
+ // navigation by character for consistency (i.e. you should be able to
+ // move by character the same number of characters that are represented by
+ // the ranges flat string buffer).
+ } while (boundary_type != ax::mojom::TextBoundary::kCharacter &&
+ current_endpoint->GetAnchor()->IsIgnoredForTextNavigation());
}
*units_moved = count;
@@ -1254,6 +1270,26 @@ void AXPlatformNodeTextRangeProviderWin::NormalizeTextRange(
}
// static
+void AXPlatformNodeTextRangeProviderWin::NormalizeAsUnignoredPosition(
+ AXPositionInstance& position) {
+ if (!position->IsValid())
+ return;
+
+ if (position->IsIgnored()) {
+ AXPositionInstance normalized_position = position->AsUnignoredPosition(
+ AXPositionAdjustmentBehavior::kMoveForward);
+ if (normalized_position->IsNullPosition()) {
+ normalized_position = position->AsUnignoredPosition(
+ AXPositionAdjustmentBehavior::kMoveBackward);
+ }
+
+ if (!normalized_position->IsNullPosition())
+ position = std::move(normalized_position);
+ }
+ DCHECK(!position->IsNullPosition());
+}
+
+// static
void AXPlatformNodeTextRangeProviderWin::NormalizeAsUnignoredTextRange(
AXPositionInstance& start,
AXPositionInstance& end) {
@@ -1262,29 +1298,8 @@ void AXPlatformNodeTextRangeProviderWin::NormalizeAsUnignoredTextRange(
if (!start->IsIgnored() && !end->IsIgnored())
return;
-
- if (start->IsIgnored()) {
- AXPositionInstance normalized_start =
- start->AsUnignoredPosition(AXPositionAdjustmentBehavior::kMoveForward);
- if (normalized_start->IsNullPosition()) {
- normalized_start = start->AsUnignoredPosition(
- AXPositionAdjustmentBehavior::kMoveBackward);
- }
- if (!normalized_start->IsNullPosition())
- start = std::move(normalized_start);
- }
-
- if (end->IsIgnored()) {
- AXPositionInstance normalized_end =
- end->AsUnignoredPosition(AXPositionAdjustmentBehavior::kMoveForward);
- if (normalized_end->IsNullPosition()) {
- normalized_end =
- end->AsUnignoredPosition(AXPositionAdjustmentBehavior::kMoveBackward);
- }
- if (!normalized_end->IsNullPosition())
- end = std::move(normalized_end);
- }
-
+ NormalizeAsUnignoredPosition(start);
+ NormalizeAsUnignoredPosition(end);
DCHECK_LE(*start, *end);
}
@@ -1370,7 +1385,7 @@ AXPlatformNodeTextRangeProviderWin::GetLowestAccessibleCommonPlatformNode()
return nullptr;
const AXTreeID tree_id = common_anchor->tree()->GetAXTreeID();
- const AXNode::AXID node_id = common_anchor->id();
+ const AXNodeID node_id = common_anchor->id();
AXPlatformNodeWin* platform_node =
static_cast<AXPlatformNodeWin*>(AXPlatformNode::FromNativeViewAccessible(
GetDelegate(tree_id, node_id)->GetNativeViewAccessible()));
@@ -1386,15 +1401,14 @@ bool AXPlatformNodeTextRangeProviderWin::HasCaretOrSelectionInPlainTextField(
// reason, if we have a caret or a selection inside of an editable node,
// restrict this to a plain text field as we gain nothing from using it in a
// rich text field.
+ //
+ // Note that "AXPlatformNodeDelegate::IsDescendantOfPlainTextField()" also
+ // returns true when this node is at the root of a plain text field, i.e. the
+ // node could either be a descendant or it could be equivalent to the field's
+ // root node.
AXPlatformNodeDelegate* delegate = GetDelegate(position.get());
- if (delegate && delegate->HasVisibleCaretOrSelection()) {
- if (!delegate->GetData().HasState(ax::mojom::State::kEditable) ||
- (delegate->GetData().IsPlainTextField() ||
- delegate->IsDescendantOfPlainTextField())) {
- return true;
- }
- }
- return false;
+ return delegate && delegate->HasVisibleCaretOrSelection() &&
+ delegate->IsDescendantOfPlainTextField();
}
// static
@@ -1455,7 +1469,10 @@ AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::~TextRangeEndpoints() {
void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::SetStart(
AXPositionInstance new_start) {
bool did_tree_change = start_->tree_id() != new_start->tree_id();
- if (did_tree_change && !start_->IsNullPosition() &&
+ // TODO(bebeaudr): We can't use IsNullPosition() here because of
+ // https://crbug.com/1152939. Once this is fixed, we can go back to
+ // IsNullPosition().
+ if (did_tree_change && start_->kind() != AXPositionKind::NULL_POSITION &&
start_->tree_id() != end_->tree_id()) {
RemoveObserver(start_->tree_id());
}
@@ -1471,7 +1488,10 @@ void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::SetStart(
void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::SetEnd(
AXPositionInstance new_end) {
bool did_tree_change = end_->tree_id() != new_end->tree_id();
- if (did_tree_change && !end_->IsNullPosition() &&
+ // TODO(bebeaudr): We can't use IsNullPosition() here because of
+ // https://crbug.com/1152939. Once this is fixed, we can go back to
+ // IsNullPosition().
+ if (did_tree_change && end_->kind() != AXPositionKind::NULL_POSITION &&
end_->tree_id() != start_->tree_id()) {
RemoveObserver(end_->tree_id());
}
@@ -1512,23 +1532,49 @@ void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::
if (tree->GetAXTreeID() == start_->tree_id() &&
node->id() == start_->anchor_id()) {
AXPositionInstance new_start = start_->CreateParentPosition();
+ AXPositionInstance end_for_comparison = end_->Clone();
+
+ // Convert |new_start| and |end_for_comparison| to unignored positions to
+ // avoid AXPosition::SlowCompareTo in the < operator below.
+ NormalizeAsUnignoredPosition(new_start);
+ NormalizeAsUnignoredPosition(end_for_comparison);
+ DCHECK(!new_start->IsIgnored());
+ DCHECK(!end_for_comparison->IsIgnored());
+
// Create a degenerate range at |end_| if we have an inverted range -
// which occurs when the |end_| comes before the |start_|. However, if the
// |end_| is positioned on the deleted node, don't create a degenerate range
// yet as that position will be updated below.
- if (node->id() != end_->anchor_id() && *end_ < *new_start)
+ if (node->id() != end_->anchor_id() && *end_for_comparison < *new_start)
new_start = end_->Clone();
SetStart(std::move(new_start));
}
if (tree->GetAXTreeID() == end_->tree_id() &&
node->id() == end_->anchor_id()) {
AXPositionInstance new_end = end_->CreateParentPosition();
+ AXPositionInstance start_for_comparison = start_->Clone();
+
+ // Convert |new_end| and |start_for_comparison| to unignored positions to
+ // avoid AXPosition::SlowCompareTo in the < operator below.
+ NormalizeAsUnignoredPosition(new_end);
+ NormalizeAsUnignoredPosition(start_for_comparison);
+ DCHECK(!new_end->IsIgnored());
+ DCHECK(!start_for_comparison->IsIgnored());
+
// Create a degenerate range at |start_| if we have an inverted range -
// which occurs when the |end_| comes before the |start_|.
- if (*new_end < *start_)
+ if (*new_end < *start_for_comparison)
new_end = start_->Clone();
SetEnd(std::move(new_end));
}
}
+void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::
+ OnTreeManagerWillBeRemoved(AXTreeID previous_tree_id) {
+ if (start_->tree_id() == previous_tree_id ||
+ end_->tree_id() == previous_tree_id) {
+ RemoveObserver(previous_tree_id);
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h b/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
index 0d960715d9e..e7f3f15419a 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
@@ -117,7 +117,7 @@ class AX_EXPORT __declspec(uuid("3071e40d-a10d-45ff-a59f-6e8e1138e2c1"))
AXPlatformNodeDelegate* GetDelegate(
const AXPositionInstanceType* position) const;
AXPlatformNodeDelegate* GetDelegate(const AXTreeID tree_id,
- const AXNode::AXID node_id) const;
+ const AXNodeID node_id) const;
template <typename AnchorIterator, typename ExpandMatchLambda>
HRESULT FindAttributeRange(const TEXTATTRIBUTEID text_attribute_id,
@@ -169,6 +169,7 @@ class AX_EXPORT __declspec(uuid("3071e40d-a10d-45ff-a59f-6e8e1138e2c1"))
// normalizes the endpoints passed by parameter.
// TODO(vicfei): Make static.
void NormalizeTextRange(AXPositionInstance& start, AXPositionInstance& end);
+ static void NormalizeAsUnignoredPosition(AXPositionInstance& position);
static void NormalizeAsUnignoredTextRange(AXPositionInstance& start,
AXPositionInstance& end);
@@ -211,6 +212,7 @@ class AX_EXPORT __declspec(uuid("3071e40d-a10d-45ff-a59f-6e8e1138e2c1"))
void AddObserver(const AXTreeID tree_id);
void RemoveObserver(const AXTreeID tree_id);
void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) override;
+ void OnTreeManagerWillBeRemoved(AXTreeID previous_tree_id) override;
private:
AXPositionInstance start_;
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
index d36a8cc9d81..6c04f783f68 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -216,10 +216,10 @@ class AXPlatformNodeTextRangeProviderTest : public ui::AXPlatformNodeWinTest {
ComPtr<AXPlatformNodeTextRangeProviderWin>& text_range_provider_win,
AXPlatformNodeWin* owner,
AXTreeID tree_id,
- AXNode::AXID start_anchor_id,
+ AXNodeID start_anchor_id,
int start_offset,
ax::mojom::TextAffinity start_affinity,
- AXNode::AXID end_anchor_id,
+ AXNodeID end_anchor_id,
int end_offset,
ax::mojom::TextAffinity end_affinity) {
AXNodePosition::AXPositionInstance range_start =
@@ -257,37 +257,57 @@ class AXPlatformNodeTextRangeProviderTest : public ui::AXPlatformNodeWinTest {
std::reverse(word_end_offsets.begin(), word_end_offsets.end());
}
- ui::AXTreeUpdate BuildTextDocument(
+ AXTreeUpdate BuildTextDocument(
const std::vector<std::string>& text_nodes_content,
- bool build_word_boundaries_offsets = false) {
+ bool build_word_boundaries_offsets = false,
+ bool place_text_on_one_line = false) {
int current_id = 0;
- ui::AXNodeData root_data;
+ AXNodeData root_data;
root_data.id = ++current_id;
root_data.role = ax::mojom::Role::kRootWebArea;
- ui::AXTreeUpdate update;
+ AXTreeUpdate update;
update.tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
update.has_tree_data = true;
for (const std::string& text_content : text_nodes_content) {
- ui::AXNodeData text_data;
- text_data.id = ++current_id;
- text_data.role = ax::mojom::Role::kStaticText;
- text_data.SetName(text_content);
+ AXNodeData static_text_data;
+ static_text_data.id = ++current_id;
+ static_text_data.role = ax::mojom::Role::kStaticText;
+ static_text_data.SetName(text_content);
+ root_data.child_ids.push_back(static_text_data.id);
+
+ AXNodeData inline_box_data;
+ inline_box_data.id = ++current_id;
+ inline_box_data.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_data.SetName(text_content);
+ static_text_data.child_ids = {inline_box_data.id};
if (build_word_boundaries_offsets) {
std::vector<int> word_end_offsets;
std::vector<int> word_start_offsets;
ComputeWordBoundariesOffsets(text_content, word_start_offsets,
word_end_offsets);
- text_data.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts,
- word_start_offsets);
- text_data.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
- word_end_offsets);
+ inline_box_data.AddIntListAttribute(
+ ax::mojom::IntListAttribute::kWordStarts, word_start_offsets);
+ inline_box_data.AddIntListAttribute(
+ ax::mojom::IntListAttribute::kWordEnds, word_end_offsets);
+ }
+
+ if (place_text_on_one_line && !update.nodes.empty()) {
+ AXNodeData* previous_inline_box_data = &update.nodes.back();
+ static_text_data.AddIntAttribute(
+ ax::mojom::IntAttribute::kPreviousOnLineId,
+ previous_inline_box_data->id);
+ inline_box_data.AddIntAttribute(
+ ax::mojom::IntAttribute::kPreviousOnLineId,
+ previous_inline_box_data->id);
+ previous_inline_box_data->AddIntAttribute(
+ ax::mojom::IntAttribute::kNextOnLineId, inline_box_data.id);
}
- root_data.child_ids.push_back(text_data.id);
- update.nodes.push_back(text_data);
+ update.nodes.push_back(static_text_data);
+ update.nodes.push_back(inline_box_data);
}
update.nodes.insert(update.nodes.begin(), root_data);
@@ -356,6 +376,7 @@ class AXPlatformNodeTextRangeProviderTest : public ui::AXPlatformNodeWinTest {
text_field.role = ax::mojom::Role::kTextField;
text_field.AddState(ax::mojom::State::kEditable);
+ text_field.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot, true);
text_field.SetValue(ALL_TEXT);
text_field.AddIntListAttribute(
ax::mojom::IntListAttribute::kCachedLineStarts,
@@ -431,7 +452,7 @@ class AXPlatformNodeTextRangeProviderTest : public ui::AXPlatformNodeWinTest {
return update;
}
- const base::string16 tree_for_move_full_text =
+ const std::wstring tree_for_move_full_text =
L"First line of text\nStandalone line\n"
L"bold text\nParagraph 1\nParagraph 2";
@@ -577,7 +598,7 @@ class AXPlatformNodeTextRangeProviderTest : public ui::AXPlatformNodeWinTest {
return update;
}
- ui::AXTreeUpdate BuildAXTreeForMoveByFormat() {
+ AXTreeUpdate BuildAXTreeForMoveByFormat() {
// 1
// |
// -------------------------------------
@@ -588,120 +609,133 @@ class AXPlatformNodeTextRangeProviderTest : public ui::AXPlatformNodeWinTest {
// | | | | | | | | |
// 3 5 6 7 9 11 13 15 17
- ui::AXNodeData group1_data;
+ AXNodeData group1_data;
group1_data.id = 2;
group1_data.role = ax::mojom::Role::kGenericContainer;
group1_data.AddStringAttribute(ax::mojom::StringAttribute::kFontFamily,
"test font");
+ group1_data.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
- ui::AXNodeData text_data;
+ AXNodeData text_data;
text_data.id = 3;
text_data.role = ax::mojom::Role::kStaticText;
- std::string text_content = "Text with formatting";
- text_data.SetName(text_content);
- group1_data.child_ids = {3};
+ text_data.SetName("Text with formatting");
+ group1_data.child_ids = {text_data.id};
- ui::AXNodeData group2_data;
+ AXNodeData group2_data;
group2_data.id = 4;
group2_data.role = ax::mojom::Role::kGenericContainer;
+ group2_data.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
- ui::AXNodeData line_break1_data;
+ AXNodeData line_break1_data;
line_break1_data.id = 5;
line_break1_data.role = ax::mojom::Role::kLineBreak;
+ line_break1_data.SetName("\n");
- ui::AXNodeData standalone_text_data;
+ AXNodeData standalone_text_data;
standalone_text_data.id = 6;
standalone_text_data.role = ax::mojom::Role::kStaticText;
- text_content = "Standalone line with no formatting";
- standalone_text_data.SetName(text_content);
+ standalone_text_data.SetName("Standalone line with no formatting");
- ui::AXNodeData line_break2_data;
+ AXNodeData line_break2_data;
line_break2_data.id = 7;
line_break2_data.role = ax::mojom::Role::kLineBreak;
+ line_break2_data.SetName("\n");
- group2_data.child_ids = {5, 6, 7};
+ group2_data.child_ids = {line_break1_data.id, standalone_text_data.id,
+ line_break2_data.id};
- ui::AXNodeData group3_data;
+ AXNodeData group3_data;
group3_data.id = 8;
group3_data.role = ax::mojom::Role::kGenericContainer;
group3_data.AddIntAttribute(
ax::mojom::IntAttribute::kTextStyle,
static_cast<int32_t>(ax::mojom::TextStyle::kBold));
+ group3_data.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
- ui::AXNodeData bold_text_data;
+ AXNodeData bold_text_data;
bold_text_data.id = 9;
bold_text_data.role = ax::mojom::Role::kStaticText;
- text_content = "bold text";
- bold_text_data.SetName(text_content);
- group3_data.child_ids = {9};
+ bold_text_data.SetName("bold text");
+ group3_data.child_ids = {bold_text_data.id};
- ui::AXNodeData paragraph1_data;
+ AXNodeData paragraph1_data;
paragraph1_data.id = 10;
paragraph1_data.role = ax::mojom::Role::kParagraph;
paragraph1_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 100);
+ paragraph1_data.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
- ui::AXNodeData paragraph1_text_data;
+ AXNodeData paragraph1_text_data;
paragraph1_text_data.id = 11;
paragraph1_text_data.role = ax::mojom::Role::kStaticText;
- text_content = "Paragraph 1";
- paragraph1_text_data.SetName(text_content);
- paragraph1_data.child_ids = {11};
+ paragraph1_text_data.SetName("Paragraph 1");
+ paragraph1_data.child_ids = {paragraph1_text_data.id};
- ui::AXNodeData paragraph2_data;
+ AXNodeData paragraph2_data;
paragraph2_data.id = 12;
paragraph2_data.role = ax::mojom::Role::kParagraph;
paragraph2_data.AddFloatAttribute(ax::mojom::FloatAttribute::kFontSize,
1.0f);
+ paragraph2_data.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
- ui::AXNodeData paragraph2_text_data;
+ AXNodeData paragraph2_text_data;
paragraph2_text_data.id = 13;
paragraph2_text_data.role = ax::mojom::Role::kStaticText;
- text_content = "Paragraph 2";
- paragraph2_text_data.SetName(text_content);
- paragraph2_data.child_ids = {13};
+ paragraph2_text_data.SetName("Paragraph 2");
+ paragraph2_data.child_ids = {paragraph2_text_data.id};
- ui::AXNodeData paragraph3_data;
+ AXNodeData paragraph3_data;
paragraph3_data.id = 14;
paragraph3_data.role = ax::mojom::Role::kParagraph;
paragraph3_data.AddFloatAttribute(ax::mojom::FloatAttribute::kFontSize,
1.0f);
+ paragraph3_data.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
- ui::AXNodeData paragraph3_text_data;
+ AXNodeData paragraph3_text_data;
paragraph3_text_data.id = 15;
paragraph3_text_data.role = ax::mojom::Role::kStaticText;
- text_content = "Paragraph 3";
- paragraph3_text_data.SetName(text_content);
- paragraph3_data.child_ids = {15};
+ paragraph3_text_data.SetName("Paragraph 3");
+ paragraph3_data.child_ids = {paragraph3_text_data.id};
- ui::AXNodeData paragraph4_data;
+ AXNodeData paragraph4_data;
paragraph4_data.id = 16;
paragraph4_data.role = ax::mojom::Role::kParagraph;
paragraph4_data.AddFloatAttribute(ax::mojom::FloatAttribute::kFontSize,
2.0f);
+ paragraph4_data.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
- ui::AXNodeData paragraph4_text_data;
+ AXNodeData paragraph4_text_data;
paragraph4_text_data.id = 17;
paragraph4_text_data.role = ax::mojom::Role::kStaticText;
- text_content = "Paragraph 4";
- paragraph4_text_data.SetName(text_content);
- paragraph4_data.child_ids = {17};
+ paragraph4_text_data.SetName("Paragraph 4");
+ paragraph4_data.child_ids = {paragraph4_text_data.id};
- ui::AXNodeData root_data;
+ AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
- root_data.child_ids = {2, 4, 8, 10, 12, 14, 16};
+ root_data.child_ids = {group1_data.id, group2_data.id,
+ group3_data.id, paragraph1_data.id,
+ paragraph2_data.id, paragraph3_data.id,
+ paragraph4_data.id};
- ui::AXTreeUpdate update;
+ AXTreeUpdate update;
update.has_tree_data = true;
update.root_id = root_data.id;
update.nodes = {root_data,
group1_data,
text_data,
group2_data,
- group3_data,
line_break1_data,
standalone_text_data,
line_break2_data,
+ group3_data,
bold_text_data,
paragraph1_data,
paragraph1_text_data,
@@ -718,7 +752,7 @@ class AXPlatformNodeTextRangeProviderTest : public ui::AXPlatformNodeWinTest {
ui::AXTreeUpdate BuildAXTreeForMoveByPage() {
ui::AXNodeData root_data;
root_data.id = 1;
- root_data.role = ax::mojom::Role::kDocument;
+ root_data.role = ax::mojom::Role::kPdfRoot;
ui::AXNodeData page_1_data;
page_1_data.id = 2;
@@ -923,7 +957,9 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderClone) {
TEST_F(AXPlatformNodeTextRangeProviderTest,
TestITextRangeProviderCompareEndpoints) {
- Init(BuildTextDocument({"some text", "more text"}));
+ Init(BuildTextDocument({"some text", "more text"},
+ false /* build_word_boundaries_offsets */,
+ true /* place_text_on_one_line */));
AXNode* root_node = GetRootAsAXNode();
@@ -1244,8 +1280,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
EXPECT_UIA_TEXTRANGE_EQ(
text_range_provider,
- L"Text with formattingStandalone line with no formattingbold "
- L"textParagraph 1Paragraph 2Paragraph 3Paragraph 4");
+ L"Text with formatting\nStandalone line with no formatting\nbold "
+ L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParagraph 4");
// https://docs.microsoft.com/en-us/windows/win32/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-expandtoenclosingunit
// Consider two consecutive text units A and B.
@@ -1258,22 +1294,21 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
ASSERT_HRESULT_SUCCEEDED(text_range_provider->Clone(&units_a_b_provider));
int count;
ASSERT_HRESULT_SUCCEEDED(units_a_b_provider->MoveEndpointByUnit(
- TextPatternRangeEndpoint_Start, TextUnit_Character, /*count*/ 63,
- &count));
- ASSERT_EQ(63, count);
+ TextPatternRangeEndpoint_Start, TextUnit_Line, /*count*/ 5, &count));
+ ASSERT_EQ(5, count);
ASSERT_HRESULT_SUCCEEDED(units_a_b_provider->MoveEndpointByUnit(
- TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ -11, &count));
- ASSERT_EQ(-11, count);
+ TextPatternRangeEndpoint_End, TextUnit_Line, /*count*/ -1, &count));
+ ASSERT_EQ(-1, count);
EXPECT_UIA_TEXTRANGE_EQ(units_a_b_provider,
- L"Paragraph 1Paragraph 2Paragraph 3");
+ L"Paragraph 1\nParagraph 2\nParagraph 3");
// Create a range encompassing node 11 which will serve as our expected
// value of a range from start of A to end of A.
ComPtr<ITextRangeProvider> unit_a_provider;
ASSERT_HRESULT_SUCCEEDED(units_a_b_provider->Clone(&unit_a_provider));
ASSERT_HRESULT_SUCCEEDED(unit_a_provider->MoveEndpointByUnit(
- TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ -22, &count));
- ASSERT_EQ(-22, count);
+ TextPatternRangeEndpoint_End, TextUnit_Line, /*count*/ -2, &count));
+ ASSERT_EQ(-2, count);
EXPECT_UIA_TEXTRANGE_EQ(unit_a_provider, L"Paragraph 1");
// Case 1: Degenerate range at start of A.
@@ -1336,7 +1371,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
ASSERT_HRESULT_SUCCEEDED(test_case_provider->MoveEndpointByUnit(
TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ 4, &count));
ASSERT_EQ(4, count);
- EXPECT_UIA_TEXTRANGE_EQ(test_case_provider, L"Paragraph 1Para");
+ EXPECT_UIA_TEXTRANGE_EQ(test_case_provider, L"Paragraph 1\nPara");
ASSERT_HRESULT_SUCCEEDED(
test_case_provider->ExpandToEnclosingUnit(TextUnit_Format));
@@ -1422,7 +1457,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
ASSERT_HRESULT_SUCCEEDED(test_case_provider->MoveEndpointByUnit(
TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ 4, &count));
ASSERT_EQ(4, count);
- EXPECT_UIA_TEXTRANGE_EQ(test_case_provider, L"graph 1Para");
+ EXPECT_UIA_TEXTRANGE_EQ(test_case_provider, L"graph 1\nPara");
ASSERT_HRESULT_SUCCEEDED(
test_case_provider->ExpandToEnclosingUnit(TextUnit_Format));
@@ -1454,24 +1489,23 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
// ++++++3 kStaticText
// ++++++++4 kInlineTextBox
// ++++5 kGenericContainer ignored
- // ++++6 kGenericContainer
+ // ++++6 kButton
ui::AXNodeData root_1;
ui::AXNodeData heading_2;
ui::AXNodeData static_text_3;
ui::AXNodeData inline_box_4;
ui::AXNodeData generic_container_5;
- ui::AXNodeData generic_container_6;
+ ui::AXNodeData button_6;
root_1.id = 1;
heading_2.id = 2;
static_text_3.id = 3;
inline_box_4.id = 4;
generic_container_5.id = 5;
- generic_container_6.id = 6;
+ button_6.id = 6;
root_1.role = ax::mojom::Role::kRootWebArea;
- root_1.child_ids = {heading_2.id, generic_container_5.id,
- generic_container_6.id};
+ root_1.child_ids = {heading_2.id, generic_container_5.id, button_6.id};
heading_2.role = ax::mojom::Role::kHeading;
heading_2.child_ids = {static_text_3.id};
@@ -1488,9 +1522,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
generic_container_5.AddState(ax::mojom::State::kIgnored);
- generic_container_6.role = ax::mojom::Role::kGenericContainer;
- generic_container_6.AddBoolAttribute(
- ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+ button_6.role = ax::mojom::Role::kButton;
ui::AXTreeUpdate update;
ui::AXTreeData tree_data;
@@ -1503,7 +1535,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
update.nodes.push_back(static_text_3);
update.nodes.push_back(inline_box_4);
update.nodes.push_back(generic_container_5);
- update.nodes.push_back(generic_container_6);
+ update.nodes.push_back(button_6);
Init(update);
@@ -1567,6 +1599,102 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
}
TEST_F(AXPlatformNodeTextRangeProviderTest,
+ TestITextRangeProviderIgnoredForTextNavigation) {
+ // ++1 kRootWebArea
+ // ++++2 kStaticText
+ // ++++++3 kInlineTextBox foo
+ // ++++4 kSplitter
+ // ++++5 kStaticText
+ // ++++++6 kInlineTextBox bar
+ // ++++7 genericContainer
+ // ++++8 kStaticText
+ // ++++++9 kInlineTextBox baz
+ ui::AXNodeData root_1;
+ ui::AXNodeData static_text_2;
+ ui::AXNodeData inline_box_3;
+ ui::AXNodeData splitter_4;
+ ui::AXNodeData static_text_5;
+ ui::AXNodeData inline_box_6;
+ ui::AXNodeData generic_container_7;
+ ui::AXNodeData static_text_8;
+ ui::AXNodeData inline_box_9;
+
+ root_1.id = 1;
+ static_text_2.id = 2;
+ inline_box_3.id = 3;
+ splitter_4.id = 4;
+ static_text_5.id = 5;
+ inline_box_6.id = 6;
+ generic_container_7.id = 7;
+ static_text_8.id = 8;
+ inline_box_9.id = 9;
+
+ root_1.role = ax::mojom::Role::kRootWebArea;
+ root_1.child_ids = {static_text_2.id, splitter_4.id, static_text_5.id,
+ generic_container_7.id, static_text_8.id};
+
+ static_text_2.role = ax::mojom::Role::kStaticText;
+ static_text_2.child_ids = {inline_box_3.id};
+ static_text_2.SetName("foo");
+
+ inline_box_3.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_3.SetName("foo");
+
+ splitter_4.role = ax::mojom::Role::kSplitter;
+ splitter_4.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+ true);
+
+ static_text_5.role = ax::mojom::Role::kStaticText;
+ static_text_5.child_ids = {inline_box_6.id};
+ static_text_5.SetName("bar");
+
+ inline_box_6.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_6.SetName("bar");
+
+ generic_container_7.role = ax::mojom::Role::kGenericContainer;
+ generic_container_7.AddBoolAttribute(
+ ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
+
+ static_text_8.role = ax::mojom::Role::kStaticText;
+ static_text_8.child_ids = {inline_box_9.id};
+ static_text_8.SetName("bar");
+
+ inline_box_9.role = ax::mojom::Role::kInlineTextBox;
+ inline_box_9.SetName("baz");
+
+ ui::AXTreeUpdate update;
+ ui::AXTreeData tree_data;
+ tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+ update.tree_data = tree_data;
+ update.has_tree_data = true;
+ update.root_id = root_1.id;
+ update.nodes = {
+ root_1, static_text_2, inline_box_3, splitter_4,
+ static_text_5, inline_box_6, generic_container_7, static_text_8,
+ inline_box_9};
+
+ Init(update);
+
+ AXNode* root_node = GetRootAsAXNode();
+ ComPtr<ITextRangeProvider> text_range_provider;
+ GetTextRangeProviderFromTextNode(text_range_provider, root_node);
+
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider,
+ L"foo\n\xFFFC\nbar\n\xFFFC\nbaz");
+
+ int count;
+ ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+ TextPatternRangeEndpoint_Start, TextUnit_Paragraph, /*count*/ 1, &count));
+ ASSERT_EQ(1, count);
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"bar\n\xFFFC\nbaz");
+
+ ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+ TextPatternRangeEndpoint_Start, TextUnit_Paragraph, /*count*/ 1, &count));
+ ASSERT_EQ(1, count);
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"baz");
+}
+
+TEST_F(AXPlatformNodeTextRangeProviderTest,
TestITextRangeProviderInvalidCalls) {
// Test for when a text range provider is invalid. Because no ax tree is
// available, the anchor is invalid, so the text range provider fails the
@@ -1776,35 +1904,36 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveFormat) {
GetTextRangeProviderFromTextNode(text_range_provider, root_node);
// Moving by 0 should have no effect.
- EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
- /*count*/ 0,
- /*expected_text*/
- L"Text with formattingStandalone line with no formattingbold "
- L"textParagraph 1Paragraph 2Paragraph 3Paragraph 4",
- /*expected_count*/ 0);
+ EXPECT_UIA_MOVE(
+ text_range_provider, TextUnit_Format,
+ /*count*/ 0,
+ /*expected_text*/
+ L"Text with formatting\nStandalone line with no formatting\nbold "
+ L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParagraph 4",
+ /*expected_count*/ 0);
// Move forward.
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 1,
- /*expected_text*/ L"Standalone line with no formatting",
+ /*expected_text*/ L"\nStandalone line with no formatting\n",
/*expected_count*/ 1);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 2,
- /*expected_text*/ L"Paragraph 1",
+ /*expected_text*/ L"\nParagraph 1",
/*expected_count*/ 2);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 1,
- /*expected_text*/ L"Paragraph 2Paragraph 3",
+ /*expected_text*/ L"\nParagraph 2\nParagraph 3",
/*expected_count*/ 1);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 1,
- /*expected_text*/ L"Paragraph 4",
+ /*expected_text*/ L"\nParagraph 4",
/*expected_count*/ 1);
// Trying to move past the last format should have no effect.
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 1,
- /*expected_text*/ L"Paragraph 4",
+ /*expected_text*/ L"\nParagraph 4",
/*expected_count*/ 0);
// Move backward.
@@ -1814,7 +1943,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveFormat) {
/*expected_count*/ -3);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ -1,
- /*expected_text*/ L"Standalone line with no formatting",
+ /*expected_text*/ L"\nStandalone line with no formatting\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ -1,
@@ -1844,7 +1973,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveFormat) {
// Test degenerate range creation at the end of the document.
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 5,
- /*expected_text*/ L"Paragraph 4",
+ /*expected_text*/ L"\nParagraph 4",
/*expected_count*/ 5);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Format,
@@ -1912,7 +2041,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMovePage) {
L"some text on page 1\nsome text on page 2some more text on page 3",
/*expected_count*/ 0);
- // Backwards endpoint moves
+ // Backwards endpoint moves.
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Page,
/*count*/ -1,
@@ -1925,7 +2054,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMovePage) {
/*expected_text*/ L"",
/*expected_count*/ -2);
- // Forwards endpoint move
+ // Forwards endpoint move.
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Page,
/*count*/ 5,
@@ -1933,7 +2062,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMovePage) {
L"some text on page 1\nsome text on page 2some more text on page 3",
/*expected_count*/ 3);
- // Range moves
+ // Range moves.
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Page,
/*count*/ 1,
/*expected_text*/ L"some text on page 2",
@@ -1950,7 +2079,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMovePage) {
/*expected_count*/ -1);
// ExpandToEnclosingUnit - first move by character so it's not on a
- // page boundary before calling ExpandToEnclosingUnit
+ // page boundary before calling ExpandToEnclosingUnit.
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Character,
/*count*/ -2,
@@ -2283,7 +2412,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Document, /*count*/ -1,
/*expected_text*/ tree_for_move_full_text.data(),
- /*expected_count*/ -1);
+ /*expected_count*/ 0);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Document, /*count*/ 2,
/*expected_text*/ tree_for_move_full_text.data(),
/*expected_count*/ 0);
@@ -2403,13 +2532,13 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
// The Hindi string has two characters, the first one 32 bits and the second
// 64 bits in length. It is formatted in UTF16.
- const std::string hindi =
- base::UTF16ToUTF8(L"\x0939\x093F\x0928\x094D\x0926\x0940");
+ const std::string hindi = base::UTF16ToUTF8(
+ STRING16_LITERAL("\x0939\x093F\x0928\x094D\x0926\x0940"));
// The Thai string has three characters, the first one 48, the second 32 and
// the last one 16 bits in length. It is formatted in UTF16.
- const std::string thai =
- base::UTF16ToUTF8(L"\x0E23\x0E39\x0E49\x0E2A\x0E36\x0E01");
+ const std::string thai = base::UTF16ToUTF8(
+ STRING16_LITERAL("\x0E23\x0E39\x0E49\x0E2A\x0E36\x0E01"));
Init(BuildTextDocument({english, hindi, thai}));
@@ -2691,6 +2820,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
// Verify that the endpoint can move past an empty text field.
TEST_F(AXPlatformNodeTextRangeProviderTest,
TestITextRangeProviderMoveEndpointByUnitTextField) {
+ // An empty text field should also be a character, word, and line boundary.
ui::AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
@@ -2770,33 +2900,63 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text");
int count;
- // Tests for TextUnit_Character
+ // Tests for TextUnit_Character.
+ ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+ TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ 1, &count));
+ ASSERT_EQ(1, count);
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text\xFFFc");
+
ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ 1, &count));
ASSERT_EQ(1, count);
- EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some textm");
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text\xFFFcm");
+
+ ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+ TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ -1, &count));
+ ASSERT_EQ(-1, count);
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text\xFFFC");
ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ -1, &count));
ASSERT_EQ(-1, count);
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text");
- // Tests for TextUnit_Word
+ // Tests for TextUnit_Word.
+ ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+ TextPatternRangeEndpoint_End, TextUnit_Word, /*count*/ 1, &count));
+ ASSERT_EQ(1, count);
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text\xFFFC");
+
ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
TextPatternRangeEndpoint_End, TextUnit_Word, /*count*/ 1, &count));
ASSERT_EQ(1, count);
- EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some textmore ");
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text\xFFFCmore ");
+
+ ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+ TextPatternRangeEndpoint_End, TextUnit_Word, /*count*/ -1, &count));
+ ASSERT_EQ(-1, count);
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text\xFFFC");
ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
TextPatternRangeEndpoint_End, TextUnit_Word, /*count*/ -1, &count));
ASSERT_EQ(-1, count);
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text");
- // Tests for TextUnit_Line
+ // Tests for TextUnit_Line.
+ ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+ TextPatternRangeEndpoint_End, TextUnit_Line, /*count*/ 1, &count));
+ ASSERT_EQ(1, count);
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text\xFFFC");
+
ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
TextPatternRangeEndpoint_End, TextUnit_Line, /*count*/ 1, &count));
ASSERT_EQ(1, count);
- EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some textmore text");
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text\xFFFCmore text");
+
+ ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
+ TextPatternRangeEndpoint_End, TextUnit_Line, /*count*/ -1, &count));
+ ASSERT_EQ(-1, count);
+ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text\xFFFC");
ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
TextPatternRangeEndpoint_End, TextUnit_Line, /*count*/ -1, &count));
@@ -2814,29 +2974,28 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
EXPECT_UIA_TEXTRANGE_EQ(
text_range_provider,
- L"Text with formattingStandalone line with no formattingbold "
- L"textParagraph 1Paragraph 2Paragraph 3Paragraph 4");
+ L"Text with formatting\nStandalone line with no formatting\nbold "
+ L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParagraph 4");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -2,
/*expected_text*/
- L"Text with formattingStandalone line with no formattingbold "
- L"textParagraph 1",
+ L"Text with formatting\nStandalone line with no formatting\nbold "
+ L"text\nParagraph 1\n",
/*expected_count*/ -2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/
- L"Text with formattingStandalone line with no formattingbold text",
-
+ L"Text with formatting\nStandalone line with no formatting\nbold text\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/
- L"Text with formattingStandalone line with no formatting",
+ L"Text with formatting\nStandalone line with no formatting\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
@@ -2855,8 +3014,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 7,
/*expected_text*/
- L"Text with formattingStandalone line with no formattingbold "
- L"textParagraph 1Paragraph 2Paragraph 3Paragraph 4",
+ L"Text with formatting\nStandalone line with no formatting\nbold "
+ L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParagraph 4",
/*expected_count*/ 6);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
@@ -3419,7 +3578,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetChildren) {
// Set up ax tree with the following structure:
//
// ++1 kRootWebArea
- // ++++2 kDocument ignored
+ // ++++2 kGenericContainer editable richlyEditable
// ++++++3 kStaticText
// ++++++++4 kInlineTextBox
// ++++++++5 kInlineTextBox
@@ -3430,7 +3589,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetChildren) {
// ++++++++10 kStaticText
AXNodeData root_1;
- AXNodeData document_2;
+ AXNodeData generic_container_2;
AXNodeData static_text_3;
AXNodeData inline_box_4;
AXNodeData inline_box_5;
@@ -3441,7 +3600,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetChildren) {
AXNodeData static_text_10;
root_1.id = 1;
- document_2.id = 2;
+ generic_container_2.id = 2;
static_text_3.id = 3;
inline_box_4.id = 4;
inline_box_5.id = 5;
@@ -3452,12 +3611,15 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetChildren) {
static_text_10.id = 10;
root_1.role = ax::mojom::Role::kRootWebArea;
- root_1.child_ids = {document_2.id};
+ root_1.child_ids = {generic_container_2.id};
- document_2.role = ax::mojom::Role::kDocument;
- document_2.AddState(ax::mojom::State::kIgnored);
- document_2.child_ids = {static_text_3.id, static_text_6.id, static_text_7.id,
- button_8.id};
+ generic_container_2.role = ax::mojom::Role::kGenericContainer;
+ generic_container_2.AddState(ax::mojom::State::kEditable);
+ generic_container_2.AddState(ax::mojom::State::kRichlyEditable);
+ generic_container_2.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot,
+ true);
+ generic_container_2.child_ids = {static_text_3.id, static_text_6.id,
+ static_text_7.id, button_8.id};
static_text_3.role = ax::mojom::Role::kStaticText;
static_text_3.child_ids = {inline_box_4.id, inline_box_5.id};
@@ -3472,9 +3634,11 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetChildren) {
static_text_7.AddState(ax::mojom::State::kIgnored);
button_8.role = ax::mojom::Role::kButton;
- // Hack: This attribute is needed to be able to get a text range provider
+ // Hack: The kEditableRoot attribute is needed to get a text range provider
// located on this element (see AXPlatformNodeWin::GetPatternProvider).
button_8.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot, true);
+ // When kEditableRoot is set, kEditable is also expected.
+ button_8.AddState(ax::mojom::State::kEditable);
button_8.child_ids = {image_9.id, static_text_10.id};
image_9.role = ax::mojom::Role::kImage;
@@ -3487,29 +3651,24 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetChildren) {
update.tree_data = tree_data;
update.has_tree_data = true;
update.root_id = root_1.id;
- update.nodes.push_back(root_1);
- update.nodes.push_back(document_2);
- update.nodes.push_back(static_text_3);
- update.nodes.push_back(inline_box_4);
- update.nodes.push_back(inline_box_5);
- update.nodes.push_back(static_text_6);
- update.nodes.push_back(static_text_7);
- update.nodes.push_back(button_8);
- update.nodes.push_back(image_9);
- update.nodes.push_back(static_text_10);
+ update.nodes = {
+ root_1, generic_container_2, static_text_3, inline_box_4,
+ inline_box_5, static_text_6, static_text_7, button_8,
+ image_9, static_text_10};
Init(update);
// Set up variables from the tree for testing.
- AXNode* document_2_node = GetRootAsAXNode()->children()[0];
- AXNode* static_text_3_node = document_2_node->children()[0];
+ AXNode* generic_container_2_node = GetRootAsAXNode()->children()[0];
+ AXNode* static_text_3_node = generic_container_2_node->children()[0];
AXNode* inline_box_4_node = static_text_3_node->children()[0];
AXNode* inline_box_5_node = static_text_3_node->children()[1];
- AXNode* static_text_6_node = document_2_node->children()[1];
- AXNode* button_8_node = document_2_node->children()[3];
+ AXNode* static_text_6_node = generic_container_2_node->children()[1];
+ AXNode* button_8_node = generic_container_2_node->children()[3];
- ComPtr<IRawElementProviderSimple> document_2_raw =
- QueryInterfaceFromNode<IRawElementProviderSimple>(document_2_node);
+ ComPtr<IRawElementProviderSimple> generic_container_2_raw =
+ QueryInterfaceFromNode<IRawElementProviderSimple>(
+ generic_container_2_node);
ComPtr<IRawElementProviderSimple> static_text_3_raw =
QueryInterfaceFromNode<IRawElementProviderSimple>(static_text_3_node);
ComPtr<IRawElementProviderSimple> inline_box_4_raw =
@@ -3593,8 +3752,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetChildren) {
// Test document_2 - children should not include ignored nodes and nodes under
// a node that should hide its children.
{
- EXPECT_HRESULT_SUCCEEDED(
- document_2_raw->GetPatternProvider(UIA_TextPatternId, &text_provider));
+ EXPECT_HRESULT_SUCCEEDED(generic_container_2_raw->GetPatternProvider(
+ UIA_TextPatternId, &text_provider));
EXPECT_HRESULT_SUCCEEDED(
text_provider->get_DocumentRange(&text_range_provider));
@@ -3624,8 +3783,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
2);
text_data.AddIntAttribute(ax::mojom::IntAttribute::kTextUnderlineStyle, 3);
text_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
- text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
+ 0xFFADBEEFU);
+ text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xFFADC0DEU);
text_data.AddStringAttribute(ax::mojom::StringAttribute::kLanguage, "fr-CA");
text_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
text_data.AddTextStyle(ax::mojom::TextStyle::kItalic);
@@ -3646,8 +3805,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
heading_data.role = ax::mojom::Role::kHeading;
heading_data.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 6);
heading_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
- heading_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
+ 0xFFADBEEFU);
+ heading_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xFFADC0DEU);
heading_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
heading_data.SetTextPosition(ax::mojom::TextPosition::kSuperscript);
heading_data.AddState(ax::mojom::State::kEditable);
@@ -3658,9 +3817,9 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
heading_text_data.role = ax::mojom::Role::kStaticText;
heading_text_data.AddState(ax::mojom::State::kInvisible);
heading_text_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
+ 0xFFADBEEFU);
heading_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor,
- 0xDEADC0DEU);
+ 0xFFADC0DEU);
heading_text_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
heading_text_data.SetTextPosition(ax::mojom::TextPosition::kSuperscript);
heading_text_data.AddState(ax::mojom::State::kEditable);
@@ -3678,8 +3837,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
mark_data.id = 5;
mark_data.role = ax::mojom::Role::kMark;
mark_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
- mark_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
+ 0xFFADBEEFU);
+ mark_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xFFADC0DEU);
mark_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
mark_data.child_ids = {6};
@@ -3687,8 +3846,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
mark_text_data.id = 6;
mark_text_data.role = ax::mojom::Role::kStaticText;
mark_text_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
- mark_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
+ 0xFFADBEEFU);
+ mark_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xFFADC0DEU);
mark_text_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
mark_text_data.SetTextAlign(ax::mojom::TextAlign::kNone);
mark_text_data.SetName("marked text");
@@ -3698,8 +3857,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
list_data.role = ax::mojom::Role::kList;
list_data.child_ids = {8, 10};
list_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
- list_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
+ 0xFFADBEEFU);
+ list_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xFFADC0DEU);
ui::AXNodeData list_item_data;
list_item_data.id = 8;
@@ -3709,16 +3868,16 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
ax::mojom::IntAttribute::kListStyle,
static_cast<int>(ax::mojom::ListStyle::kOther));
list_item_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
- list_item_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
+ 0xFFADBEEFU);
+ list_item_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xFFADC0DEU);
ui::AXNodeData list_item_text_data;
list_item_text_data.id = 9;
list_item_text_data.role = ax::mojom::Role::kStaticText;
list_item_text_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
+ 0xFFADBEEFU);
list_item_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor,
- 0xDEADC0DEU);
+ 0xFFADC0DEU);
list_item_text_data.SetName("list item");
ui::AXNodeData list_item2_data;
@@ -3729,16 +3888,16 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
ax::mojom::IntAttribute::kListStyle,
static_cast<int>(ax::mojom::ListStyle::kDisc));
list_item2_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
- list_item2_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
+ 0xFFADBEEFU);
+ list_item2_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xFFADC0DEU);
ui::AXNodeData list_item2_text_data;
list_item2_text_data.id = 11;
list_item2_text_data.role = ax::mojom::Role::kStaticText;
list_item2_text_data.AddIntAttribute(
- ax::mojom::IntAttribute::kBackgroundColor, 0xDEADBEEFU);
+ ax::mojom::IntAttribute::kBackgroundColor, 0xFFADBEEFU);
list_item2_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor,
- 0xDEADC0DEU);
+ 0xFFADC0DEU);
list_item2_text_data.SetName("list item 2");
ui::AXNodeData input_text_data;
@@ -3751,8 +3910,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
input_text_data.AddStringAttribute(ax::mojom::StringAttribute::kPlaceholder,
"placeholder2");
input_text_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
- input_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
+ 0xFFADBEEFU);
+ input_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xFFADC0DEU);
input_text_data.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot,
true);
input_text_data.SetName("placeholder");
@@ -3762,9 +3921,9 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
placeholder_text_data.id = 13;
placeholder_text_data.role = ax::mojom::Role::kStaticText;
placeholder_text_data.AddIntAttribute(
- ax::mojom::IntAttribute::kBackgroundColor, 0xDEADBEEFU);
+ ax::mojom::IntAttribute::kBackgroundColor, 0xFFADBEEFU);
placeholder_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor,
- 0xDEADC0DEU);
+ 0xFFADC0DEU);
placeholder_text_data.SetName("placeholder");
ui::AXNodeData input_text_data2;
@@ -3774,9 +3933,9 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
input_text_data2.AddStringAttribute(ax::mojom::StringAttribute::kPlaceholder,
"placeholder2");
input_text_data2.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
+ 0xFFADBEEFU);
input_text_data2.AddIntAttribute(ax::mojom::IntAttribute::kColor,
- 0xDEADC0DEU);
+ 0xFFADC0DEU);
input_text_data2.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot,
true);
input_text_data2.SetName("foo");
@@ -3786,24 +3945,24 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
placeholder_text_data2.id = 15;
placeholder_text_data2.role = ax::mojom::Role::kStaticText;
placeholder_text_data2.AddIntAttribute(
- ax::mojom::IntAttribute::kBackgroundColor, 0xDEADBEEFU);
+ ax::mojom::IntAttribute::kBackgroundColor, 0xFFADBEEFU);
placeholder_text_data2.AddIntAttribute(ax::mojom::IntAttribute::kColor,
- 0xDEADC0DEU);
+ 0xFFADC0DEU);
placeholder_text_data2.SetName("placeholder2");
ui::AXNodeData link_data;
link_data.id = 16;
link_data.role = ax::mojom::Role::kLink;
link_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
- link_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
+ 0xFFADBEEFU);
+ link_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xFFADC0DEU);
ui::AXNodeData link_text_data;
link_text_data.id = 17;
link_text_data.role = ax::mojom::Role::kStaticText;
link_text_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
- 0xDEADBEEFU);
- link_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
+ 0xFFADBEEFU);
+ link_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xFFADC0DEU);
link_data.child_ids = {17};
ui::AXNodeData root_data;
@@ -3917,7 +4076,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
EXPECT_EQ(SORT_DEFAULT, SORTIDFROMLCID(lcid));
}
- base::string16 font_name = base::UTF8ToUTF16("sans");
+ std::wstring font_name = L"sans";
expected_variant.Set(SysAllocString(font_name.c_str()));
EXPECT_UIA_TEXTATTRIBUTE_EQ(text_range_provider, UIA_FontNameAttributeId,
expected_variant);
@@ -4031,7 +4190,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
UIA_UnderlineStyleAttributeId, expected_variant);
expected_variant.Reset();
- base::string16 style_name = base::UTF8ToUTF16("");
+ std::wstring style_name;
expected_variant.Set(SysAllocString(style_name.c_str()));
EXPECT_UIA_TEXTATTRIBUTE_EQ(text_range_provider, UIA_StyleNameAttributeId,
expected_variant);
@@ -4042,7 +4201,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
UIA_StyleIdAttributeId, expected_variant);
expected_variant.Reset();
- style_name = base::UTF8ToUTF16("mark");
+ style_name = L"mark";
expected_variant.Set(SysAllocString(style_name.c_str()));
EXPECT_UIA_TEXTATTRIBUTE_EQ(mark_text_range_provider,
UIA_StyleNameAttributeId, expected_variant);
@@ -4276,12 +4435,12 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
initial_state.nodes[3].role = ax::mojom::Role::kStaticText;
initial_state.nodes[3].SetName("some text");
initial_state.nodes[3].AddIntAttribute(
- ax::mojom::IntAttribute::kBackgroundColor, 0xDEADBEEFU);
+ ax::mojom::IntAttribute::kBackgroundColor, 0xFFADBEEFU);
initial_state.nodes[4].id = 5;
initial_state.nodes[4].role = ax::mojom::Role::kStaticText;
initial_state.nodes[4].SetName("more text");
initial_state.nodes[4].AddIntAttribute(
- ax::mojom::IntAttribute::kBackgroundColor, 0xDEADBEEFU);
+ ax::mojom::IntAttribute::kBackgroundColor, 0xFFADBEEFU);
Init(initial_state);
@@ -4291,22 +4450,22 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
AXPlatformNodeFromNode(GetNodeFromTree(tree_id, 2)));
// start: TextPosition, anchor_id=4, text_offset=0, annotated_text=<s>ome text
- // end : TextPosition, anchor_id=2, text_offset=17,
- // annotated_text=some textmore tex<t>
+ // end : TextPosition, anchor_id=5, text_offset=8,
+ // annotated_text=more tex<t>
ComPtr<AXPlatformNodeTextRangeProviderWin> text_range_provider_win;
CreateTextRangeProviderWin(
text_range_provider_win, owner, tree_id,
/*start_anchor_id=*/4, /*start_offset=*/0,
/*start_affinity*/ ax::mojom::TextAffinity::kDownstream,
- /*end_anchor_id=*/2, /*end_offset=*/17,
+ /*end_anchor_id=*/5, /*end_offset=*/8,
/*end_affinity*/ ax::mojom::TextAffinity::kDownstream);
ASSERT_TRUE(GetStart(text_range_provider_win.Get())->IsTextPosition());
ASSERT_EQ(4, GetStart(text_range_provider_win.Get())->anchor_id());
ASSERT_EQ(0, GetStart(text_range_provider_win.Get())->text_offset());
ASSERT_TRUE(GetEnd(text_range_provider_win.Get())->IsTextPosition());
- ASSERT_EQ(2, GetEnd(text_range_provider_win.Get())->anchor_id());
- ASSERT_EQ(17, GetEnd(text_range_provider_win.Get())->text_offset());
+ ASSERT_EQ(5, GetEnd(text_range_provider_win.Get())->anchor_id());
+ ASSERT_EQ(8, GetEnd(text_range_provider_win.Get())->text_offset());
base::win::ScopedVariant expected_variant;
// SkColor is ARGB, COLORREF is 0BGR
@@ -4361,8 +4520,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderSelect) {
// Verify selection.
AXTree::Selection unignored_selection = delegate->GetUnignoredSelection();
- EXPECT_EQ(2, unignored_selection.anchor_object_id);
- EXPECT_EQ(2, unignored_selection.focus_object_id);
+ EXPECT_EQ(3, unignored_selection.anchor_object_id);
+ EXPECT_EQ(3, unignored_selection.focus_object_id);
EXPECT_EQ(0, unignored_selection.anchor_offset);
EXPECT_EQ(9, unignored_selection.focus_offset);
@@ -4389,8 +4548,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderSelect) {
// Verify selection
AXTree::Selection unignored_selection = delegate->GetUnignoredSelection();
- EXPECT_EQ(3, unignored_selection.anchor_object_id);
- EXPECT_EQ(3, unignored_selection.focus_object_id);
+ EXPECT_EQ(5, unignored_selection.anchor_object_id);
+ EXPECT_EQ(5, unignored_selection.focus_object_id);
EXPECT_EQ(0, unignored_selection.anchor_offset);
EXPECT_EQ(10, unignored_selection.focus_offset);
@@ -4417,8 +4576,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderSelect) {
// Verify selection.
AXTree::Selection unignored_selection = delegate->GetUnignoredSelection();
- EXPECT_EQ(2, unignored_selection.anchor_object_id);
- EXPECT_EQ(3, unignored_selection.focus_object_id);
+ EXPECT_EQ(3, unignored_selection.anchor_object_id);
+ EXPECT_EQ(5, unignored_selection.focus_object_id);
EXPECT_EQ(0, unignored_selection.anchor_offset);
EXPECT_EQ(10, unignored_selection.focus_offset);
@@ -4448,8 +4607,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderSelect) {
// Verify selection.
AXTree::Selection unignored_selection = delegate->GetUnignoredSelection();
- EXPECT_EQ(2, unignored_selection.anchor_object_id);
- EXPECT_EQ(2, unignored_selection.focus_object_id);
+ EXPECT_EQ(3, unignored_selection.anchor_object_id);
+ EXPECT_EQ(3, unignored_selection.focus_object_id);
EXPECT_EQ(9, unignored_selection.anchor_offset);
EXPECT_EQ(9, unignored_selection.focus_offset);
@@ -4541,7 +4700,9 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
}
TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderFindText) {
- Init(BuildTextDocument({"some text", "more text"}));
+ Init(BuildTextDocument({"some text", "more text"},
+ false /* build_word_boundaries_offsets */,
+ true /* place_text_on_one_line */));
AXNode* root_node = GetRootAsAXNode();
ComPtr<ITextRangeProvider> range;
@@ -4577,16 +4738,18 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderFindText) {
text_range_provider_found->QueryInterface(
IID_PPV_ARGS(&text_range_provider_win));
ASSERT_TRUE(GetStart(text_range_provider_win.Get())->IsTextPosition());
- ASSERT_EQ(3, GetStart(text_range_provider_win.Get())->anchor_id());
- ASSERT_EQ(0, GetStart(text_range_provider_win.Get())->text_offset());
+ EXPECT_EQ(5, GetStart(text_range_provider_win.Get())->anchor_id());
+ EXPECT_EQ(0, GetStart(text_range_provider_win.Get())->text_offset());
ASSERT_TRUE(GetEnd(text_range_provider_win.Get())->IsTextPosition());
- ASSERT_EQ(3, GetEnd(text_range_provider_win.Get())->anchor_id());
- ASSERT_EQ(9, GetEnd(text_range_provider_win.Get())->text_offset());
+ EXPECT_EQ(5, GetEnd(text_range_provider_win.Get())->anchor_id());
+ EXPECT_EQ(9, GetEnd(text_range_provider_win.Get())->text_offset());
}
TEST_F(AXPlatformNodeTextRangeProviderTest,
TestITextRangeProviderFindTextBackwards) {
- Init(BuildTextDocument({"text", "some", "text"}));
+ Init(BuildTextDocument({"text", "some", "text"},
+ false /* build_word_boundaries_offsets */,
+ true /* place_text_on_one_line */));
AXNode* root_node = GetRootAsAXNode();
ComPtr<ITextRangeProvider> root_range_provider;
@@ -4600,7 +4763,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
base::win::ScopedBstr find_string(L"text");
BOOL range_equal;
- // Forward search finds the text_node1
+ // Forward search finds the text_node1.
EXPECT_HRESULT_SUCCEEDED(root_range_provider->FindText(
find_string.Get(), false, false, &text_range_provider_found));
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider_found, find_string.Get());
@@ -4610,7 +4773,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
text_range_provider_found->Compare(text_node1_range.Get(), &range_equal));
EXPECT_TRUE(range_equal);
- // Backwards search finds the text_node3
+ // Backwards search finds the text_node3.
EXPECT_HRESULT_SUCCEEDED(root_range_provider->FindText(
find_string.Get(), true, false, &text_range_provider_found));
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider_found, find_string.Get());
@@ -5150,8 +5313,14 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
tree_update.nodes[1].id = 2;
tree_update.nodes[1].child_ids = {3, 4, 5, 6, 7, 8};
+ // According to the existing Blink code, editable roots are never ignored.
+ // However, we can still create this tree structure only for test purposes.
tree_update.nodes[1].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[1].role = ax::mojom::Role::kDocument;
+ tree_update.nodes[1].AddState(ax::mojom::State::kEditable);
+ tree_update.nodes[1].AddState(ax::mojom::State::kRichlyEditable);
+ tree_update.nodes[1].AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot,
+ true);
+ tree_update.nodes[1].role = ax::mojom::Role::kGenericContainer;
tree_update.nodes[2].id = 3;
tree_update.nodes[2].role = ax::mojom::Role::kStaticText;
@@ -5166,7 +5335,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
tree_update.nodes[4].SetName(".5.");
tree_update.nodes[5].id = 6;
- tree_update.nodes[5].role = ax::mojom::Role::kGenericContainer;
+ tree_update.nodes[5].role = ax::mojom::Role::kButton;
tree_update.nodes[5].child_ids = {9};
tree_update.nodes[6].id = 7;
@@ -5422,9 +5591,9 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
ComPtr<AXPlatformNodeTextRangeProviderWin> ignored_range_win;
CreateTextRangeProviderWin(
ignored_range_win, owner, tree_id,
- /*start_anchor_id=*/3, /*start_offset=*/1,
+ /*start_anchor_id=*/3, /*start_offset=*/0,
/*start_affinity*/ ax::mojom::TextAffinity::kDownstream,
- /*end_anchor_id=*/3, /*end_offset=*/6,
+ /*end_anchor_id=*/3, /*end_offset=*/0,
/*end_affinity*/ ax::mojom::TextAffinity::kDownstream);
EXPECT_TRUE(GetStart(ignored_range_win.Get())->IsIgnored());
@@ -5596,6 +5765,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
image_3.role = ax::mojom::Role::kImage;
text_field_4.role = ax::mojom::Role::kTextField;
+ text_field_4.AddState(ax::mojom::State::kEditable);
+ text_field_4.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot, true);
text_field_4.child_ids = {generic_container_5.id};
text_field_4.SetValue("3.14");
@@ -5790,43 +5961,50 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
// thus generating a tree update.
//
// ++1 kRootWebArea
- // ++++2 kStaticText/++++3 kStaticText (replacement node)
- // ++++4 kStaticText/++++5 kStaticText (replacement node)
+ // ++++2 kGroup (ignored)
+ // ++++++3 kStaticText/++++4 kStaticText (replacement node)
+ // ++++5 kStaticText/++++6 kStaticText (replacement node)
AXNodeData root_1;
- AXNodeData text_2;
+ AXNodeData group_2;
AXNodeData text_3;
AXNodeData text_4;
AXNodeData text_5;
+ AXNodeData text_6;
root_1.id = 1;
- text_2.id = 2;
+ group_2.id = 2;
text_3.id = 3;
text_4.id = 4;
text_5.id = 5;
+ text_6.id = 6;
root_1.role = ax::mojom::Role::kRootWebArea;
- root_1.child_ids = {text_2.id, text_4.id};
+ root_1.child_ids = {text_3.id, text_5.id};
- text_2.role = ax::mojom::Role::kStaticText;
- text_2.SetName("some text");
+ group_2.role = ax::mojom::Role::kGroup;
+ group_2.AddState(ax::mojom::State::kIgnored);
+ group_2.child_ids = {text_3.id};
- // Replacement node of |text_2|.
text_3.role = ax::mojom::Role::kStaticText;
text_3.SetName("some text");
+ // Replacement node of |text_3|.
text_4.role = ax::mojom::Role::kStaticText;
- text_4.SetName("more text");
+ text_4.SetName("some text");
- // Replacement node of |text_4|.
text_5.role = ax::mojom::Role::kStaticText;
text_5.SetName("more text");
+ // Replacement node of |text_5|.
+ text_6.role = ax::mojom::Role::kStaticText;
+ text_6.SetName("more text");
+
ui::AXTreeUpdate update;
ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
update.root_id = root_1.id;
update.tree_data.tree_id = tree_id;
update.has_tree_data = true;
- update.nodes = {root_1, text_2, text_4};
+ update.nodes = {root_1, text_3, text_5};
Init(update);
// Create a position at MaxTextOffset.
@@ -5835,14 +6013,14 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
AXPlatformNodeWin* owner = static_cast<AXPlatformNodeWin*>(
AXPlatformNodeFromNode(GetNodeFromTree(tree_id, 1)));
- // start: TextPosition, anchor_id=2, text_offset=0, annotated_text=<s>ome text
- // end : TextPosition, anchor_id=4, text_offset=9, annotated_text=more text<>
+ // start: TextPosition, anchor_id=3, text_offset=0, annotated_text=<s>ome text
+ // end : TextPosition, anchor_id=5, text_offset=9, annotated_text=more text<>
ComPtr<AXPlatformNodeTextRangeProviderWin> range;
CreateTextRangeProviderWin(
range, owner, tree_id,
- /*start_anchor_id*/ 2, /*start_offset*/ 0,
+ /*start_anchor_id*/ text_3.id, /*start_offset*/ 0,
/*start_affinity*/ ax::mojom::TextAffinity::kDownstream,
- /*end_anchor_id*/ 4, /*end_offset*/ 9,
+ /*end_anchor_id*/ text_5.id, /*end_offset*/ 9,
/*end_affinity*/ ax::mojom::TextAffinity::kDownstream);
EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"some textmore text");
@@ -5850,9 +6028,9 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
// 1. Replace the node on which |start_| is.
{
// Replace node |text_2| with |text_3|.
- root_1.child_ids = {text_3.id, text_4.id};
+ root_1.child_ids = {text_4.id, text_5.id};
AXTreeUpdate test_update;
- test_update.nodes = {root_1, text_3};
+ test_update.nodes = {root_1, text_4};
ASSERT_TRUE(GetTree()->Unserialize(test_update));
// Replacing that node shouldn't impact the range.
@@ -5860,21 +6038,22 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
range->GetChildren(children.Receive());
EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"some textmore text");
- // The |start_| endpoint should have moved to its parent.
- EXPECT_EQ(1, GetStart(range.Get())->anchor_id());
+ // The |start_| endpoint should have moved to the root, skipping its ignored
+ // parent.
+ EXPECT_EQ(root_1.id, GetStart(range.Get())->anchor_id());
EXPECT_EQ(0, GetStart(range.Get())->text_offset());
// The |end_| endpoint should not have moved.
- EXPECT_EQ(4, GetEnd(range.Get())->anchor_id());
+ EXPECT_EQ(text_5.id, GetEnd(range.Get())->anchor_id());
EXPECT_EQ(9, GetEnd(range.Get())->text_offset());
}
// 2. Replace the node on which |end_| is.
{
// Replace node |text_4| with |text_5|.
- root_1.child_ids = {text_3.id, text_5.id};
+ root_1.child_ids = {text_4.id, text_6.id};
AXTreeUpdate test_update;
- test_update.nodes = {root_1, text_5};
+ test_update.nodes = {root_1, text_6};
ASSERT_TRUE(GetTree()->Unserialize(test_update));
// Replacing that node shouldn't impact the range.
@@ -5883,32 +6062,32 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"some textmore text");
// The |start_| endpoint should still be on its parent.
- EXPECT_EQ(1, GetStart(range.Get())->anchor_id());
+ EXPECT_EQ(root_1.id, GetStart(range.Get())->anchor_id());
EXPECT_EQ(0, GetStart(range.Get())->text_offset());
// The |end_| endpoint should have moved to its parent.
- EXPECT_EQ(1, GetEnd(range.Get())->anchor_id());
+ EXPECT_EQ(root_1.id, GetEnd(range.Get())->anchor_id());
EXPECT_EQ(18, GetEnd(range.Get())->text_offset());
}
// 3. Replace the node on which |end_| is.
{
- // start: TextPosition, anchor_id=3, text_offset=0, annotated_text=<s>ome
- // end : TextPosition, anchor_id=3, text_offset=4, annotated_text=some<>
+ // start: TextPosition, anchor_id=4, text_offset=0, annotated_text=<s>ome
+ // end : TextPosition, anchor_id=4, text_offset=4, annotated_text=some<>
ComPtr<AXPlatformNodeTextRangeProviderWin> range_2;
CreateTextRangeProviderWin(
range_2, owner, tree_id,
- /*start_anchor_id*/ 3, /*start_offset*/ 0,
+ /*start_anchor_id*/ text_4.id, /*start_offset*/ 0,
/*start_affinity*/ ax::mojom::TextAffinity::kDownstream,
- /*end_anchor_id*/ 3, /*end_offset*/ 4,
+ /*end_anchor_id*/ text_4.id, /*end_offset*/ 4,
/*end_affinity*/ ax::mojom::TextAffinity::kDownstream);
EXPECT_UIA_TEXTRANGE_EQ(range_2, /*expected_text*/ L"some");
- // Replace node |text_3| with |text_2|.
- root_1.child_ids = {text_2.id, text_5.id};
+ // Replace node |text_4| with |text_3|.
+ root_1.child_ids = {text_3.id, text_6.id};
AXTreeUpdate test_update;
- test_update.nodes = {root_1, text_2};
+ test_update.nodes = {root_1, text_3};
ASSERT_TRUE(GetTree()->Unserialize(test_update));
// Replacing that node shouldn't impact the range.
@@ -5917,13 +6096,117 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
EXPECT_UIA_TEXTRANGE_EQ(range_2, /*expected_text*/ L"some");
// The |start_| endpoint should have moved to its parent.
- EXPECT_EQ(1, GetStart(range_2.Get())->anchor_id());
+ EXPECT_EQ(root_1.id, GetStart(range_2.Get())->anchor_id());
EXPECT_EQ(0, GetStart(range_2.Get())->text_offset());
// The |end_| endpoint should have moved to its parent.
- EXPECT_EQ(1, GetEnd(range_2.Get())->anchor_id());
+ EXPECT_EQ(root_1.id, GetEnd(range_2.Get())->anchor_id());
EXPECT_EQ(4, GetEnd(range_2.Get())->text_offset());
}
}
+TEST_F(AXPlatformNodeTextRangeProviderTest,
+ TestReplaceStartAndEndEndpointRepeatRemoval) {
+ // This test updates the tree structure to ensure that the text range is still
+ // valid after text nodes get removed repeatedly.
+ //
+ // ++1 kRootWebArea
+ // ++++2 kStaticText
+ // ++++3 kGroup (ignored)
+ // ++++++4 kStaticText
+ // ++++5 kStaticText
+ AXNodeData root_1;
+ AXNodeData text_2;
+ AXNodeData group_3;
+ AXNodeData text_4;
+ AXNodeData text_5;
+
+ root_1.id = 1;
+ text_2.id = 2;
+ group_3.id = 3;
+ text_4.id = 4;
+ text_5.id = 5;
+
+ root_1.role = ax::mojom::Role::kRootWebArea;
+ root_1.child_ids = {text_2.id, group_3.id, text_5.id};
+
+ text_2.role = ax::mojom::Role::kStaticText;
+ text_2.SetName("text 2");
+
+ group_3.role = ax::mojom::Role::kGroup;
+ group_3.AddState(ax::mojom::State::kIgnored);
+ group_3.child_ids = {text_4.id};
+
+ text_4.role = ax::mojom::Role::kStaticText;
+ text_4.SetName("text 4");
+
+ text_5.role = ax::mojom::Role::kStaticText;
+ text_5.SetName("text 5");
+
+ ui::AXTreeUpdate update;
+ ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
+ update.root_id = root_1.id;
+ update.tree_data.tree_id = tree_id;
+ update.has_tree_data = true;
+ update.nodes = {root_1, text_2, group_3, text_4, text_5};
+ Init(update);
+
+ // Making |owner| AXID:1 so that |TestAXNodeWrapper::BuildAllWrappers|
+ // will build the entire tree.
+ AXPlatformNodeWin* owner = static_cast<AXPlatformNodeWin*>(
+ AXPlatformNodeFromNode(GetNodeFromTree(tree_id, 1)));
+
+ ComPtr<AXPlatformNodeTextRangeProviderWin> range;
+ CreateTextRangeProviderWin(
+ range, owner, tree_id,
+ /*start_anchor_id*/ text_2.id, /*start_offset*/ 0,
+ /*start_affinity*/ ax::mojom::TextAffinity::kDownstream,
+ /*end_anchor_id*/ text_4.id, /*end_offset*/ 0,
+ /*end_affinity*/ ax::mojom::TextAffinity::kDownstream);
+
+ EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"text 2");
+
+ // start: TextPosition, anchor_id=2, text_offset=0, annotated_text=<t>ext2
+ // end : TextPosition, anchor_id=4, text_offset=0, annotated_text=<>text4
+ // 1. Remove |text_4| which |end_| is anchored on.
+ {
+ // Remove node |text_4|.
+ group_3.child_ids = {};
+ AXTreeUpdate test_update;
+ test_update.nodes = {root_1, group_3};
+ ASSERT_TRUE(GetTree()->Unserialize(test_update));
+
+ // Replacing that node should not impact the range.
+ EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"text 2");
+ }
+
+ // start: TextPosition, anchor_id=2, text_offset=0, annotated_text=<>text2
+ // end : TextPosition, anchor_id=2, text_offset=5, annotated_text=text2<>
+ // 2. Remove |text_2|, which both |start_| and |end_| are anchored to and
+ // replace with |text_5|.
+ {
+ root_1.child_ids = {group_3.id, text_5.id};
+ AXTreeUpdate test_update;
+ test_update.nodes = {root_1, group_3};
+ ASSERT_TRUE(GetTree()->Unserialize(test_update));
+
+ // Removing that node should adjust the range to the |text_5|, as it took
+ // |text_2|'s position.
+ EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"text 5");
+ }
+
+ // start: TextPosition, anchor_id=5, text_offset=0, annotated_text=<>text5
+ // end : TextPosition, anchor_id=5, text_offset=5, annotated_text=text5<>
+ // 3. Remove |text_5|, which both |start_| and |end_| are pointing to.
+ {
+ root_1.child_ids = {group_3.id};
+ AXTreeUpdate test_update;
+ test_update.nodes = {root_1, group_3};
+ ASSERT_TRUE(GetTree()->Unserialize(test_update));
+
+ // Removing the last text node should leave a degenerate range.
+ EXPECT_UIA_TEXTRANGE_EQ(range, /*expected_text*/ L"");
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.cc b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
index cee747eaa87..44d49b91ad9 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
@@ -20,7 +20,9 @@
#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_number_conversions_win.h"
#include "base/strings/string_util.h"
+#include "base/strings/string_util_win.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
@@ -42,12 +44,14 @@
#include "ui/accessibility/ax_node_position.h"
#include "ui/accessibility/ax_role_properties.h"
#include "ui/accessibility/ax_tree_data.h"
+#include "ui/accessibility/ax_tree_id_registry.h"
#include "ui/accessibility/platform/ax_fragment_root_win.h"
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
#include "ui/accessibility/platform/ax_platform_node_delegate_utils_win.h"
#include "ui/accessibility/platform/ax_platform_node_textchildprovider_win.h"
#include "ui/accessibility/platform/ax_platform_node_textprovider_win.h"
#include "ui/accessibility/platform/ax_platform_relation_win.h"
+#include "ui/accessibility/platform/compute_attributes.h"
#include "ui/accessibility/platform/uia_registrar_win.h"
#include "ui/base/win/atl_module.h"
#include "ui/display/win/screen_win.h"
@@ -215,12 +219,20 @@ base::LazyInstance<
// greater than small changes.
constexpr int kLargeChangeScaleFactor = 10;
+// Sets the default small change amount for a RangeValueProvider when no
+// step was set on the element. Note: This should be in-sync with the native
+// default value, defined by the default constructor of:
+//
+// third_party/blink/renderer/core/html/forms/step_range.cc
+//
+constexpr float kDefaultSmallChangeValue = 1.0f;
+
// The amount to scroll when UI Automation asks to scroll by a small increment.
// Value is in device independent pixels and is the same used by Blink when
// cursor keys are used to scroll a webpage.
constexpr float kSmallScrollIncrement = 40.0f;
-void AppendTextToString(base::string16 extra_text, base::string16* string) {
+void AppendTextToString(const std::wstring& extra_text, std::wstring* string) {
if (extra_text.empty())
return;
@@ -229,7 +241,7 @@ void AppendTextToString(base::string16 extra_text, base::string16* string) {
return;
}
- *string += base::string16(L". ") + extra_text;
+ *string += L". " + extra_text;
}
// Helper function to GetPatternProviderFactoryMethod that, given a node,
@@ -247,8 +259,8 @@ void AXPlatformNodeWin::AddAttributeToList(const char* name,
PlatformAttributeList* attributes) {
std::string str_value = value;
SanitizeStringAttribute(str_value, &str_value);
- attributes->push_back(base::UTF8ToUTF16(name) + L":" +
- base::UTF8ToUTF16(str_value));
+ attributes->push_back(base::UTF8ToWide(name) + L":" +
+ base::UTF8ToWide(str_value));
}
// There is no easy way to decouple |kScreenReader| and |kHTML| accessibility
@@ -320,8 +332,8 @@ void AXPlatformNodeWin::ClearOwnRelations() {
// Static
void AXPlatformNodeWin::SanitizeStringAttributeForUIAAriaProperty(
- const base::string16& input,
- base::string16* output) {
+ const std::wstring& input,
+ std::wstring* output) {
DCHECK(output);
// According to the UIA Spec, these characters need to be escaped with a
// backslash in an AriaProperties string: backslash, equals and semicolon.
@@ -332,69 +344,71 @@ void AXPlatformNodeWin::SanitizeStringAttributeForUIAAriaProperty(
}
void AXPlatformNodeWin::StringAttributeToUIAAriaProperty(
- std::vector<base::string16>& properties,
+ std::vector<std::wstring>& properties,
ax::mojom::StringAttribute attribute,
const char* uia_aria_property) {
- base::string16 value;
- if (GetString16Attribute(attribute, &value)) {
- SanitizeStringAttributeForUIAAriaProperty(value, &value);
- properties.push_back(base::ASCIIToUTF16(uia_aria_property) + L"=" + value);
+ std::string value;
+ if (GetStringAttribute(attribute, &value)) {
+ std::wstring wide_value = base::UTF8ToWide(value);
+ SanitizeStringAttributeForUIAAriaProperty(wide_value, &wide_value);
+ properties.push_back(base::ASCIIToWide(uia_aria_property) + L"=" +
+ wide_value);
}
}
void AXPlatformNodeWin::BoolAttributeToUIAAriaProperty(
- std::vector<base::string16>& properties,
+ std::vector<std::wstring>& properties,
ax::mojom::BoolAttribute attribute,
const char* uia_aria_property) {
bool value;
if (GetBoolAttribute(attribute, &value)) {
- properties.push_back((base::ASCIIToUTF16(uia_aria_property) + L"=") +
+ properties.push_back(base::ASCIIToWide(uia_aria_property) + L"=" +
(value ? L"true" : L"false"));
}
}
void AXPlatformNodeWin::IntAttributeToUIAAriaProperty(
- std::vector<base::string16>& properties,
+ std::vector<std::wstring>& properties,
ax::mojom::IntAttribute attribute,
const char* uia_aria_property) {
int value;
if (GetIntAttribute(attribute, &value)) {
- properties.push_back(base::ASCIIToUTF16(uia_aria_property) + L"=" +
- base::NumberToString16(value));
+ properties.push_back(base::ASCIIToWide(uia_aria_property) + L"=" +
+ base::NumberToWString(value));
}
}
void AXPlatformNodeWin::FloatAttributeToUIAAriaProperty(
- std::vector<base::string16>& properties,
+ std::vector<std::wstring>& properties,
ax::mojom::FloatAttribute attribute,
const char* uia_aria_property) {
float value;
if (GetFloatAttribute(attribute, &value)) {
- properties.push_back(base::ASCIIToUTF16(uia_aria_property) + L"=" +
- base::NumberToString16(value));
+ properties.push_back(base::ASCIIToWide(uia_aria_property) + L"=" +
+ base::NumberToWString(value));
}
}
void AXPlatformNodeWin::StateToUIAAriaProperty(
- std::vector<base::string16>& properties,
+ std::vector<std::wstring>& properties,
ax::mojom::State state,
const char* uia_aria_property) {
const AXNodeData& data = GetData();
bool value = data.HasState(state);
- properties.push_back((base::ASCIIToUTF16(uia_aria_property) + L"=") +
+ properties.push_back(base::ASCIIToWide(uia_aria_property) + L"=" +
(value ? L"true" : L"false"));
}
void AXPlatformNodeWin::HtmlAttributeToUIAAriaProperty(
- std::vector<base::string16>& properties,
+ std::vector<std::wstring>& properties,
const char* html_attribute_name,
const char* uia_aria_property) {
base::string16 html_attribute_value;
if (GetData().GetHtmlAttribute(html_attribute_name, &html_attribute_value)) {
- SanitizeStringAttributeForUIAAriaProperty(html_attribute_value,
- &html_attribute_value);
- properties.push_back(base::ASCIIToUTF16(uia_aria_property) + L"=" +
- html_attribute_value);
+ std::wstring wide_value = base::UTF16ToWide(html_attribute_value);
+ SanitizeStringAttributeForUIAAriaProperty(wide_value, &wide_value);
+ properties.push_back(base::ASCIIToWide(uia_aria_property) + L"=" +
+ wide_value);
}
}
@@ -675,13 +689,14 @@ void AXPlatformNodeWin::OnActiveComposition(
// AXPlatformNodeTextProviderWin
active_composition_range_ = range;
// Fire the UiaTextEditTextChangedEvent
- FireUiaTextEditTextChangedEvent(range, active_composition_text,
+ FireUiaTextEditTextChangedEvent(range,
+ base::UTF16ToWide(active_composition_text),
is_composition_committed);
}
void AXPlatformNodeWin::FireUiaTextEditTextChangedEvent(
const gfx::Range& range,
- const base::string16& active_composition_text,
+ const std::wstring& active_composition_text,
bool is_composition_committed) {
if (!::switches::IsExperimentalAccessibilityPlatformUIAEnabled()) {
return;
@@ -998,7 +1013,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accDefaultAction(VARIANT var_id,
return S_FALSE;
}
- base::string16 action_verb = base::UTF8ToUTF16(
+ std::wstring action_verb = base::UTF8ToWide(
ui::ToLocalizedString(static_cast<ax::mojom::DefaultActionVerb>(action)));
if (action_verb.empty()) {
*def_action = nullptr;
@@ -1068,7 +1083,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accName(VARIANT var_id, BSTR* name_bstr) {
return S_FALSE;
bool has_name = target->HasStringAttribute(ax::mojom::StringAttribute::kName);
- base::string16 name = target->GetNameAsString16();
+ std::wstring name = base::UTF8ToWide(target->GetName());
auto status = GetData().GetImageAnnotationStatus();
switch (status) {
case ax::mojom::ImageAnnotationStatus::kNone:
@@ -1083,14 +1098,16 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accName(VARIANT var_id, BSTR* name_bstr) {
case ax::mojom::ImageAnnotationStatus::kAnnotationAdult:
case ax::mojom::ImageAnnotationStatus::kAnnotationProcessFailed:
AppendTextToString(
- GetDelegate()->GetLocalizedStringForImageAnnotationStatus(status),
+ base::UTF16ToWide(
+ GetDelegate()->GetLocalizedStringForImageAnnotationStatus(
+ status)),
&name);
break;
case ax::mojom::ImageAnnotationStatus::kAnnotationSucceeded:
- AppendTextToString(
- GetString16Attribute(ax::mojom::StringAttribute::kImageAnnotation),
- &name);
+ AppendTextToString(base::UTF8ToWide(GetStringAttribute(
+ ax::mojom::StringAttribute::kImageAnnotation)),
+ &name);
break;
}
@@ -1294,7 +1311,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_relationTargetsOfType(BSTR type_bstr,
*targets = nullptr;
// Special case for relations of type "alerts".
- base::string16 type(type_bstr);
+ std::wstring type(type_bstr);
if (type == L"alerts") {
// Collect all of the objects that have had an alert fired on them that
// are a descendant of this object.
@@ -1328,7 +1345,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_relationTargetsOfType(BSTR type_bstr,
return S_OK;
}
- base::string16 relation_type;
+ std::wstring relation_type;
std::set<AXPlatformNode*> enumerated_targets;
int found = AXPlatformRelationWin::EnumerateRelationships(
this, 0, type, &relation_type, &enumerated_targets);
@@ -1363,9 +1380,9 @@ IFACEMETHODIMP AXPlatformNodeWin::get_attributes(BSTR* attributes) {
AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
*attributes = nullptr;
- base::string16 attributes_str;
- std::vector<base::string16> computed_attributes = ComputeIA2Attributes();
- for (const base::string16& attribute : computed_attributes)
+ std::wstring attributes_str;
+ std::vector<std::wstring> computed_attributes = ComputeIA2Attributes();
+ for (const std::wstring& attribute : computed_attributes)
attributes_str += attribute + L';';
if (attributes_str.empty())
@@ -1393,7 +1410,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_nRelations(LONG* n_relations) {
AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
int count = AXPlatformRelationWin::EnumerateRelationships(
- this, -1, base::string16(), nullptr, nullptr);
+ this, -1, std::wstring(), nullptr, nullptr);
*n_relations = count;
return S_OK;
}
@@ -1404,10 +1421,10 @@ IFACEMETHODIMP AXPlatformNodeWin::get_relation(LONG relation_index,
COM_OBJECT_VALIDATE_1_ARG(relation);
AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
- base::string16 relation_type;
+ std::wstring relation_type;
std::set<AXPlatformNode*> targets;
int found = AXPlatformRelationWin::EnumerateRelationships(
- this, relation_index, base::string16(), &relation_type, &targets);
+ this, relation_index, std::wstring(), &relation_type, &targets);
if (found == 0)
return E_INVALIDARG;
@@ -1479,7 +1496,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_localizedExtendedRole(
if (base::ContainsOnlyChars(role_description, base::kWhitespaceUTF16))
return S_FALSE;
- *localized_extended_role = SysAllocString(role_description.c_str());
+ *localized_extended_role = SysAllocString(base::as_wcstr(role_description));
return S_OK;
}
@@ -1487,21 +1504,20 @@ IFACEMETHODIMP AXPlatformNodeWin::get_attribute(BSTR name, VARIANT* attribute) {
COM_OBJECT_VALIDATE_1_ARG(attribute);
AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
- base::string16 desired_attribute(name);
+ std::wstring desired_attribute(name);
// Each computed attribute from ComputeIA2Attributes is a string of
// the form "key:value". Search for strings that start with the
// attribute name plus a colon.
- base::string16 prefix = desired_attribute + L":";
+ std::wstring prefix = desired_attribute + L":";
// Let's accept any case.
const auto compare_case = base::CompareCase::INSENSITIVE_ASCII;
- const std::vector<base::string16> computed_attributes =
- ComputeIA2Attributes();
- for (const base::string16& computed_attribute : computed_attributes) {
+ const std::vector<std::wstring> computed_attributes = ComputeIA2Attributes();
+ for (const std::wstring& computed_attribute : computed_attributes) {
if (base::StartsWith(computed_attribute, prefix, compare_case)) {
- base::string16 value = computed_attribute.substr(prefix.size());
+ std::wstring value = computed_attribute.substr(prefix.size());
attribute->vt = VT_BSTR;
attribute->bstrVal = SysAllocString(value.c_str());
return S_OK;
@@ -1682,8 +1698,9 @@ IFACEMETHODIMP AXPlatformNodeWin::setSelectionRanges(LONG nRanges,
return E_INVALIDARG;
// Blink only supports selections within a single tree.
- if (anchor_node->GetDelegate()->GetTreeData().tree_id !=
- focus_node->GetDelegate()->GetTreeData().tree_id) {
+ AXTreeID anchor_tree_id = anchor_node->GetDelegate()->GetTreeData().tree_id;
+ AXTreeID focus_tree_id = focus_node->GetDelegate()->GetTreeData().tree_id;
+ if (anchor_tree_id != focus_tree_id) {
return E_INVALIDARG;
}
@@ -1710,6 +1727,7 @@ IFACEMETHODIMP AXPlatformNodeWin::setSelectionRanges(LONG nRanges,
AXActionData action_data;
action_data.action = ax::mojom::Action::kSetSelection;
action_data.anchor_node_id = anchor_node->GetData().id;
+ action_data.target_tree_id = anchor_tree_id;
action_data.anchor_offset = int32_t{ranges->anchorOffset};
action_data.focus_node_id = focus_node->GetData().id;
action_data.focus_offset = int32_t{ranges->activeOffset};
@@ -2441,6 +2459,16 @@ IFACEMETHODIMP AXPlatformNodeWin::get_LargeChange(double* result) {
&attribute)) {
*result = attribute * kLargeChangeScaleFactor;
return S_OK;
+ } else {
+ // For native sliders and spin buttons, when no explicit step value was
+ // set, use the default value instead.
+ std::string html_input_type =
+ GetStringAttribute(ax::mojom::StringAttribute::kInputType);
+ if (html_input_type == "range" || html_input_type == "number") {
+ *result = kDefaultSmallChangeValue * kLargeChangeScaleFactor;
+ return S_OK;
+ }
+ return E_FAIL;
}
return E_FAIL;
}
@@ -2477,6 +2505,16 @@ IFACEMETHODIMP AXPlatformNodeWin::get_SmallChange(double* result) {
&attribute)) {
*result = attribute;
return S_OK;
+ } else {
+ // For native sliders and spin buttons, when no explicit step value was
+ // set, use the default value instead.
+ std::string html_input_type =
+ GetStringAttribute(ax::mojom::StringAttribute::kInputType);
+ if (html_input_type == "range" || html_input_type == "number") {
+ *result = kDefaultSmallChangeValue;
+ return S_OK;
+ }
+ return E_FAIL;
}
return E_FAIL;
}
@@ -2573,14 +2611,14 @@ IFACEMETHODIMP AXPlatformNodeWin::get_columnDescription(LONG column,
if (!cell)
continue;
- base::string16 cell_name = cell->GetNameAsString16();
+ std::wstring cell_name = base::UTF8ToWide(cell->GetName());
if (!cell_name.empty()) {
*description = SysAllocString(cell_name.c_str());
return S_OK;
}
- cell_name =
- cell->GetString16Attribute(ax::mojom::StringAttribute::kDescription);
+ cell_name = base::UTF8ToWide(
+ cell->GetStringAttribute(ax::mojom::StringAttribute::kDescription));
if (!cell_name.empty()) {
*description = SysAllocString(cell_name.c_str());
return S_OK;
@@ -2758,14 +2796,14 @@ IFACEMETHODIMP AXPlatformNodeWin::get_rowDescription(LONG row,
if (!cell)
continue;
- base::string16 cell_name = cell->GetNameAsString16();
+ std::wstring cell_name = base::UTF8ToWide(cell->GetName());
if (!cell_name.empty()) {
*description = SysAllocString(cell_name.c_str());
return S_OK;
}
- cell_name =
- cell->GetString16Attribute(ax::mojom::StringAttribute::kDescription);
+ cell_name = base::UTF8ToWide(
+ cell->GetStringAttribute(ax::mojom::StringAttribute::kDescription));
if (!cell_name.empty()) {
*description = SysAllocString(cell_name.c_str());
return S_OK;
@@ -3426,7 +3464,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_text(LONG start_offset,
if (substr.empty())
return S_FALSE;
- *text = SysAllocString(substr.c_str());
+ *text = SysAllocString(base::as_wcstr(substr));
DCHECK(*text);
return S_OK;
}
@@ -3912,8 +3950,26 @@ IFACEMETHODIMP AXPlatformNodeWin::Navigate(
void AXPlatformNodeWin::GetRuntimeIdArray(
AXPlatformNodeWin::RuntimeIdArray& runtime_id) {
+ const AXNodeData& data = GetData();
+ int dom_id;
runtime_id[0] = UiaAppendRuntimeId;
- runtime_id[1] = GetUniqueId();
+
+ // The combination of tree/frame id and Blink (DOM) id is unique and gives
+ // nodes stable ids across layouts/tree movement. If there's a valid tree
+ // id, use that, otherwise fall back to the globally unique id.
+ AXTreeID tree_id = GetDelegate()->GetTreeData().tree_id;
+ if (data.GetIntAttribute(ax::mojom::IntAttribute::kDOMNodeId, &dom_id) &&
+ tree_id != AXTreeIDUnknown()) {
+ AXTreeIDRegistry::FrameID frame_id =
+ AXTreeIDRegistry::GetInstance()->GetFrameID(tree_id);
+ runtime_id[1] = frame_id.first;
+ runtime_id[2] = frame_id.second;
+ runtime_id[3] = dom_id;
+ } else {
+ runtime_id[1] = 0;
+ runtime_id[2] = 0;
+ runtime_id[3] = GetUniqueId();
+ }
}
IFACEMETHODIMP AXPlatformNodeWin::GetRuntimeId(SAFEARRAY** runtime_id) {
@@ -4061,7 +4117,7 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id,
case UIA_AutomationIdPropertyId:
V_VT(result) = VT_BSTR;
V_BSTR(result) =
- SysAllocString(GetDelegate()->GetAuthorUniqueId().c_str());
+ SysAllocString(base::as_wcstr(GetDelegate()->GetAuthorUniqueId()));
break;
case UIA_ClassNamePropertyId:
@@ -4230,7 +4286,8 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id,
base::string16 localized_control_type = GetRoleDescription();
if (!localized_control_type.empty()) {
result->vt = VT_BSTR;
- result->bstrVal = SysAllocString(localized_control_type.c_str());
+ result->bstrVal =
+ SysAllocString(base::as_wcstr(localized_control_type));
}
// If a role description has not been provided, leave as VT_EMPTY.
// UIA core handles Localized Control type for some built-in types and
@@ -4241,7 +4298,15 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id,
case UIA_NamePropertyId:
if (IsNameExposed()) {
result->vt = VT_BSTR;
- GetNameAsBstr(&result->bstrVal);
+
+ // We need to handle listitems name property differently because UIA
+ // expects a name for listitems, whereas other APIs do not.
+ if (GetData().role == ax::mojom::Role::kListItem &&
+ !HasStringAttribute(ax::mojom::StringAttribute::kName)) {
+ ComputeListItemNameAsBstr(&result->bstrVal);
+ } else {
+ GetNameAsBstr(&result->bstrVal);
+ }
}
break;
@@ -4379,7 +4444,8 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id,
GetDelegate()->GetLocalizedStringForLandmarkType();
if (!localized_landmark_type.empty()) {
result->vt = VT_BSTR;
- result->bstrVal = SysAllocString(localized_landmark_type.c_str());
+ result->bstrVal =
+ SysAllocString(base::as_wcstr(localized_landmark_type));
}
break;
}
@@ -4411,21 +4477,34 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id,
case UIA_ProviderDescriptionPropertyId:
case UIA_RuntimeIdPropertyId:
break;
- } // End of default UIA property ids.
-
- // Custom UIA Property Ids.
- if (property_id ==
- UiaRegistrarWin::GetInstance().GetUiaUniqueIdPropertyId()) {
- // We want to negate the unique id for it to be consistent across different
- // Windows accessiblity APIs. The negative unique id convention originated
- // from ::NotifyWinEvent() takes an hwnd and a child id. A 0 child id means
- // self, and a positive child id means child #n. In order to fire an event
- // for an arbitrary descendant of the window, Firefox started the practice
- // of using a negative unique id. We follow the same negative unique id
- // convention here and when we fire events via ::NotifyWinEvent().
- result->vt = VT_BSTR;
- result->bstrVal =
- SysAllocString(base::NumberToString16(-GetUniqueId()).c_str());
+ default:
+ // We can't simply add these custom properties ids to the switch case
+ // because they are not constant expressions.
+ //
+ // Custom UIA Property Ids.
+ if (property_id ==
+ UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId()) {
+ // We want to negate the unique id for it to be consistent across
+ // different Windows accessiblity APIs. The negative unique id
+ // convention originated from ::NotifyWinEvent() takes an hwnd and a
+ // child id. A 0 child id means self, and a positive child id means
+ // child #n. In order to fire an event for an arbitrary descendant of
+ // the window, Firefox started the practice of using a negative unique
+ // id. We follow the same negative unique id convention here and when we
+ // fire events via ::NotifyWinEvent().
+ result->vt = VT_BSTR;
+ result->bstrVal =
+ SysAllocString(base::NumberToWString(-GetUniqueId()).c_str());
+ } else if (features::IsAccessibilityAriaVirtualContentEnabled() &&
+ property_id == UiaRegistrarWin::GetInstance()
+ .GetVirtualContentPropertyId()) {
+ if (HasStringAttribute(ax::mojom::StringAttribute::kVirtualContent)) {
+ V_VT(result) = VT_BSTR;
+ GetStringAttributeAsBstr(ax::mojom::StringAttribute::kVirtualContent,
+ &V_BSTR(result));
+ }
+ }
+ break;
}
return S_OK;
@@ -4472,9 +4551,9 @@ void SendBulkFetchResponse(
Microsoft::WRL::ComPtr<IChromeAccessibleDelegate> delegate,
LONG request_id,
std::string json_result) {
- base::string16 json_result_utf16 = base::UTF8ToUTF16(json_result);
+ std::wstring json_result_wide = base::UTF8ToWide(json_result);
delegate->put_bulkFetchResult(request_id,
- SysAllocString(json_result_utf16.c_str()));
+ SysAllocString(json_result_wide.c_str()));
}
IFACEMETHODIMP AXPlatformNodeWin::get_bulkFetch(
@@ -4756,7 +4835,7 @@ base::Optional<LCID> AXPlatformNodeWin::GetCultureAttributeAsLCID() const {
const base::string16 language =
GetInheritedString16Attribute(ax::mojom::StringAttribute::kLanguage);
const LCID lcid =
- LocaleNameToLCID(language.c_str(), LOCALE_ALLOW_NEUTRAL_NAMES);
+ LocaleNameToLCID(base::as_wcstr(language), LOCALE_ALLOW_NEUTRAL_NAMES);
if (!lcid)
return base::nullopt;
@@ -4765,7 +4844,12 @@ base::Optional<LCID> AXPlatformNodeWin::GetCultureAttributeAsLCID() const {
COLORREF AXPlatformNodeWin::GetIntAttributeAsCOLORREF(
ax::mojom::IntAttribute attribute) const {
- const SkColor color = GetIntAttribute(attribute);
+ SkColor color;
+ auto maybe_value = ComputeAttribute(delegate_, attribute);
+ if (maybe_value.has_value())
+ color = maybe_value.value();
+ else
+ color = GetIntAttribute(attribute);
return skia::SkColorToCOLORREF(color);
}
@@ -5186,8 +5270,8 @@ int AXPlatformNodeWin::MSAARole() {
return ROLE_SYSTEM_GROUPING;
case ax::mojom::Role::kDocument:
+ case ax::mojom::Role::kPdfRoot:
case ax::mojom::Role::kRootWebArea:
- case ax::mojom::Role::kWebArea:
return ROLE_SYSTEM_DOCUMENT;
case ax::mojom::Role::kEmbeddedObject:
@@ -5291,14 +5375,11 @@ int AXPlatformNodeWin::MSAARole() {
return ROLE_SYSTEM_LISTITEM;
case ax::mojom::Role::kListMarker:
- if (!GetDelegate()->GetChildCount()) {
- // There's only a name attribute when using Legacy layout. With Legacy
- // layout, list markers have no child and are considered as StaticText.
- // We consider a list marker as a group in LayoutNG since it has
- // a text child node.
- return ROLE_SYSTEM_STATICTEXT;
- }
- return ROLE_SYSTEM_GROUPING;
+ // If a name is exposed, it's legacy layout, and this will be a leaf.
+ // Otherwise, it's LayoutNG, and the text will be exposed in children.
+ // In this case use an MSAA role of group, but IA2_ROLE_REDUNDANT_OBJECT
+ // in order to avoid having the object be announced in JAWS/NVDA.
+ return IsNameExposed() ? ROLE_SYSTEM_STATICTEXT : ROLE_SYSTEM_GROUPING;
case ax::mojom::Role::kLog:
return ROLE_SYSTEM_GROUPING;
@@ -5394,10 +5475,20 @@ int AXPlatformNodeWin::MSAARole() {
return ROLE_SYSTEM_ROWHEADER;
case ax::mojom::Role::kRuby:
- return ROLE_SYSTEM_TEXT;
+ return ROLE_SYSTEM_GROUPING;
+
+ case ax::mojom::Role::kRubyAnnotation:
+ // Generally exposed as description on <ruby> (Role::kRuby) element, not
+ // as its own object in the tree.
+ // However, it's possible to make a kRubyAnnotation element show up in the
+ // AX tree, for example by adding tabindex="0" to the source <rp> or <rt>
+ // element or making the source element the target of an aria-owns.
+ // Therefore, browser side needs to gracefully handle it if it actually
+ // shows up in the tree.
+ return ROLE_SYSTEM_STATICTEXT;
case ax::mojom::Role::kSection: {
- if (GetNameAsString16().empty()) {
+ if (GetName().empty()) {
// Do not use ARIA mapping for nameless <section>.
return ROLE_SYSTEM_GROUPING;
}
@@ -5417,16 +5508,12 @@ int AXPlatformNodeWin::MSAARole() {
case ax::mojom::Role::kSlider:
return ROLE_SYSTEM_SLIDER;
- case ax::mojom::Role::kSliderThumb:
- return ROLE_SYSTEM_SLIDER;
-
case ax::mojom::Role::kSpinButton:
return ROLE_SYSTEM_SPINBUTTON;
case ax::mojom::Role::kSwitch:
return ROLE_SYSTEM_CHECKBUTTON;
- case ax::mojom::Role::kRubyAnnotation:
case ax::mojom::Role::kStaticText:
return ROLE_SYSTEM_STATICTEXT;
@@ -5526,10 +5613,8 @@ int AXPlatformNodeWin::MSAARole() {
}
bool AXPlatformNodeWin::IsWebAreaForPresentationalIframe() {
- if (GetData().role != ax::mojom::Role::kWebArea &&
- GetData().role != ax::mojom::Role::kRootWebArea) {
+ if (!IsPlatformDocument())
return false;
- }
AXPlatformNodeBase* parent = FromNativeViewAccessible(GetParent());
if (!parent)
@@ -5757,6 +5842,13 @@ int32_t AXPlatformNodeWin::ComputeIA2Role() {
case ax::mojom::Role::kLegend:
ia2_role = IA2_ROLE_LABEL;
break;
+ case ax::mojom::Role::kListMarker:
+ if (!IsNameExposed()) {
+ // This role causes JAWS and NVDA to ignore the object.
+ // Otherwise, they speak "group" before each bullet or item number.
+ ia2_role = IA2_ROLE_REDUNDANT_OBJECT;
+ }
+ break;
case ax::mojom::Role::kMain:
ia2_role = IA2_ROLE_LANDMARK;
break;
@@ -5799,13 +5891,13 @@ int32_t AXPlatformNodeWin::ComputeIA2Role() {
ia2_role = IA2_ROLE_LANDMARK;
break;
case ax::mojom::Role::kRuby:
- ia2_role = IA2_ROLE_TEXT_FRAME;
+ ia2_role = IA2_ROLE_SECTION;
break;
case ax::mojom::Role::kSearch:
ia2_role = IA2_ROLE_LANDMARK;
break;
case ax::mojom::Role::kSection: {
- if (GetNameAsString16().empty()) {
+ if (GetName().empty()) {
// Do not use ARIA mapping for nameless <section>.
ia2_role = IA2_ROLE_SECTION;
} else {
@@ -5836,13 +5928,13 @@ int32_t AXPlatformNodeWin::ComputeIA2Role() {
return ia2_role;
}
-std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() {
- std::vector<base::string16> attribute_list;
+std::vector<std::wstring> AXPlatformNodeWin::ComputeIA2Attributes() {
+ std::vector<std::wstring> attribute_list;
ComputeAttributes(&attribute_list);
return attribute_list;
}
-base::string16 AXPlatformNodeWin::UIAAriaRole() {
+std::wstring AXPlatformNodeWin::UIAAriaRole() {
// If this is a web area for a presentational iframe, give it a role of
// something other than document so that the fact that it's a separate doc
// is not exposed to AT.
@@ -6014,8 +6106,8 @@ base::string16 AXPlatformNodeWin::UIAAriaRole() {
return L"group";
case ax::mojom::Role::kDocument:
+ case ax::mojom::Role::kPdfRoot:
case ax::mojom::Role::kRootWebArea:
- case ax::mojom::Role::kWebArea:
return L"document";
case ax::mojom::Role::kEmbeddedObject:
@@ -6228,10 +6320,20 @@ base::string16 AXPlatformNodeWin::UIAAriaRole() {
return L"rowheader";
case ax::mojom::Role::kRuby:
- return L"region";
+ return L"group";
+
+ case ax::mojom::Role::kRubyAnnotation:
+ // Generally exposed as description on <ruby> (Role::kRuby) element, not
+ // as its own object in the tree.
+ // However, it's possible to make a kRubyAnnotation element show up in the
+ // AX tree, for example by adding tabindex="0" to the source <rp> or <rt>
+ // element or making the source element the target of an aria-owns.
+ // Therefore, browser side needs to gracefully handle it if it actually
+ // shows up in the tree.
+ return L"description";
case ax::mojom::Role::kSection: {
- if (GetNameAsString16().empty()) {
+ if (GetName().empty()) {
// Do not use ARIA mapping for nameless <section>.
return L"group";
}
@@ -6251,9 +6353,6 @@ base::string16 AXPlatformNodeWin::UIAAriaRole() {
case ax::mojom::Role::kSlider:
return L"slider";
- case ax::mojom::Role::kSliderThumb:
- return L"slider";
-
case ax::mojom::Role::kSpinButton:
return L"spinbutton";
@@ -6263,7 +6362,6 @@ base::string16 AXPlatformNodeWin::UIAAriaRole() {
case ax::mojom::Role::kSwitch:
return L"switch";
- case ax::mojom::Role::kRubyAnnotation:
case ax::mojom::Role::kStaticText:
return L"description";
@@ -6355,8 +6453,8 @@ base::string16 AXPlatformNodeWin::UIAAriaRole() {
return L"document";
}
-base::string16 AXPlatformNodeWin::ComputeUIAProperties() {
- std::vector<base::string16> properties;
+std::wstring AXPlatformNodeWin::ComputeUIAProperties() {
+ std::vector<std::wstring> properties;
const AXNodeData& data = GetData();
BoolAttributeToUIAAriaProperty(
@@ -6421,7 +6519,7 @@ base::string16 AXPlatformNodeWin::ComputeUIAProperties() {
// aria-dropeffect is deprecated in WAI-ARIA 1.1.
if (data.HasIntAttribute(ax::mojom::IntAttribute::kDropeffect)) {
properties.push_back(L"dropeffect=" +
- base::UTF8ToUTF16(data.DropeffectBitfieldToString()));
+ base::UTF8ToWide(data.DropeffectBitfieldToString()));
}
StateToUIAAriaProperty(properties, ax::mojom::State::kExpanded, "expanded");
BoolAttributeToUIAAriaProperty(properties, ax::mojom::BoolAttribute::kGrabbed,
@@ -6507,13 +6605,13 @@ base::string16 AXPlatformNodeWin::ComputeUIAProperties() {
StringAttributeToUIAAriaProperty(
properties, ax::mojom::StringAttribute::kValue, "valuetext");
- base::string16 value_now = GetValueForControl();
+ std::wstring value_now = base::UTF16ToWide(GetValueForControl());
SanitizeStringAttributeForUIAAriaProperty(value_now, &value_now);
if (!value_now.empty())
properties.push_back(L"valuenow=" + value_now);
}
- base::string16 result = base::JoinString(properties, L";");
+ std::wstring result = base::JoinString(properties, L";");
return result;
}
@@ -6689,8 +6787,8 @@ LONG AXPlatformNodeWin::ComputeUIAControlType() { // NOLINT(runtime/int)
return UIA_GroupControlTypeId;
case ax::mojom::Role::kDocument:
+ case ax::mojom::Role::kPdfRoot:
case ax::mojom::Role::kRootWebArea:
- case ax::mojom::Role::kWebArea:
return UIA_DocumentControlTypeId;
case ax::mojom::Role::kEmbeddedObject:
@@ -6893,7 +6991,17 @@ LONG AXPlatformNodeWin::ComputeUIAControlType() { // NOLINT(runtime/int)
return UIA_DataItemControlTypeId;
case ax::mojom::Role::kRuby:
- return UIA_PaneControlTypeId;
+ return UIA_GroupControlTypeId;
+
+ case ax::mojom::Role::kRubyAnnotation:
+ // Generally exposed as description on <ruby> (Role::kRuby) element, not
+ // as its own object in the tree.
+ // However, it's possible to make a kRubyAnnotation element show up in the
+ // AX tree, for example by adding tabindex="0" to the source <rp> or <rt>
+ // element or making the source element the target of an aria-owns.
+ // Therefore, browser side needs to gracefully handle it if it actually
+ // shows up in the tree.
+ return UIA_TextControlTypeId;
case ax::mojom::Role::kSection:
return UIA_GroupControlTypeId;
@@ -6910,16 +7018,12 @@ LONG AXPlatformNodeWin::ComputeUIAControlType() { // NOLINT(runtime/int)
case ax::mojom::Role::kSlider:
return UIA_SliderControlTypeId;
- case ax::mojom::Role::kSliderThumb:
- return UIA_SliderControlTypeId;
-
case ax::mojom::Role::kSpinButton:
return UIA_SpinnerControlTypeId;
case ax::mojom::Role::kSwitch:
return UIA_ButtonControlTypeId;
- case ax::mojom::Role::kRubyAnnotation:
case ax::mojom::Role::kStaticText:
return UIA_TextControlTypeId;
@@ -7180,7 +7284,7 @@ bool AXPlatformNodeWin::IsUIAControl() const {
// Doing so helps Narrator find all the content of live regions.
if (!data.GetBoolAttribute(ax::mojom::BoolAttribute::kHasAriaAttribute) &&
!data.GetBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot) &&
- GetNameAsString16().empty() &&
+ GetName().empty() &&
data.GetStringAttribute(ax::mojom::StringAttribute::kDescription)
.empty() &&
!data.HasState(ax::mojom::State::kFocusable) && !data.IsClickable()) {
@@ -7191,8 +7295,8 @@ bool AXPlatformNodeWin::IsUIAControl() const {
} // end of web-content only case.
const AXNodeData& data = GetData();
- return !(data.HasState(ax::mojom::State::kInvisible) ||
- (data.IsIgnored() && !data.HasState(ax::mojom::State::kFocusable)));
+ return !(IsInvisibleOrIgnored() &&
+ !data.HasState(ax::mojom::State::kFocusable));
}
base::Optional<LONG> AXPlatformNodeWin::ComputeUIALandmarkType() const {
@@ -7294,31 +7398,20 @@ bool AXPlatformNodeWin::IsPlatformCheckable() const {
bool AXPlatformNodeWin::ShouldNodeHaveFocusableState(
const AXNodeData& data) const {
- switch (data.role) {
- case ax::mojom::Role::kDocument:
- case ax::mojom::Role::kGraphicsDocument:
- case ax::mojom::Role::kWebArea:
- return true;
-
- case ax::mojom::Role::kRootWebArea: {
- AXPlatformNodeBase* parent = FromNativeViewAccessible(GetParent());
- return !parent || parent->GetData().role != ax::mojom::Role::kPortal;
- }
-
- case ax::mojom::Role::kIframe:
- return false;
+ if (IsIframe(data.role))
+ return false;
+ if (IsPlatformDocument()) {
+ const AXPlatformNodeBase* parent = FromNativeViewAccessible(GetParent());
+ return !parent || parent->GetData().role != ax::mojom::Role::kPortal;
+ }
+ switch (data.role) {
case ax::mojom::Role::kListBoxOption:
case ax::mojom::Role::kMenuListOption:
- if (data.HasBoolAttribute(ax::mojom::BoolAttribute::kSelected))
- return true;
- break;
-
+ return data.HasBoolAttribute(ax::mojom::BoolAttribute::kSelected);
default:
- break;
+ return data.HasState(ax::mojom::State::kFocusable);
}
-
- return data.HasState(ax::mojom::State::kFocusable);
}
int AXPlatformNodeWin::MSAAState() const {
@@ -7359,8 +7452,8 @@ int AXPlatformNodeWin::MSAAState() const {
msaa_state |= STATE_SYSTEM_HOTTRACKED;
}
- // If the role is IGNORED, we want these elements to be invisible so that
- // these nodes are hidden from the screen reader.
+ // If the node is ignored, we want these elements to be invisible so that
+ // they are hidden from the screen reader.
if (IsInvisibleOrIgnored())
msaa_state |= STATE_SYSTEM_INVISIBLE;
@@ -7476,10 +7569,8 @@ int AXPlatformNodeWin::MSAAState() const {
// TODO(dmazzoni): this should probably check if focus is actually inside
// the menu bar, but we don't currently track focus inside menu pop-ups,
// and Chrome only has one menu visible at a time so this works for now.
- if (data.role == ax::mojom::Role::kMenuBar &&
- !(data.HasState(ax::mojom::State::kInvisible))) {
+ if (data.role == ax::mojom::Role::kMenuBar && !IsInvisibleOrIgnored())
msaa_state |= STATE_SYSTEM_FOCUSED;
- }
// Handle STATE_SYSTEM_LINKED
if (GetData().role == ax::mojom::Role::kLink)
@@ -7594,23 +7685,23 @@ base::Optional<PROPERTYID> AXPlatformNodeWin::MojoEventToUIAProperty(
// static
BSTR AXPlatformNodeWin::GetValueAttributeAsBstr(AXPlatformNodeWin* target) {
- if (target->IsDocument()) {
- base::string16 url =
- base::UTF8ToUTF16(target->GetDelegate()->GetTreeData().url);
+ if (target->IsPlatformDocument()) {
+ std::wstring url =
+ base::UTF8ToWide(target->GetDelegate()->GetTreeData().url);
BSTR value = SysAllocString(url.c_str());
DCHECK(value);
return value;
}
if (IsLink(target->GetData().role)) {
- base::string16 url =
- target->GetString16Attribute(ax::mojom::StringAttribute::kUrl);
+ std::wstring url = base::UTF8ToWide(
+ target->GetStringAttribute(ax::mojom::StringAttribute::kUrl));
BSTR value = SysAllocString(url.c_str());
DCHECK(value);
return value;
}
- BSTR value = SysAllocString(target->GetValueForControl().c_str());
+ BSTR value = SysAllocString(base::as_wcstr(target->GetValueForControl()));
DCHECK(value);
return value;
}
@@ -7623,14 +7714,31 @@ HRESULT AXPlatformNodeWin::GetStringAttributeAsBstr(
if (!GetString16Attribute(attribute, &str))
return S_FALSE;
- *value_bstr = SysAllocString(str.c_str());
+ *value_bstr = SysAllocString(base::as_wcstr(str));
DCHECK(*value_bstr);
return S_OK;
}
HRESULT AXPlatformNodeWin::GetNameAsBstr(BSTR* value_bstr) const {
- base::string16 str = GetNameAsString16();
+ std::wstring str = base::UTF8ToWide(GetName());
+ *value_bstr = SysAllocString(str.c_str());
+ DCHECK(*value_bstr);
+ return S_OK;
+}
+
+HRESULT AXPlatformNodeWin::ComputeListItemNameAsBstr(BSTR* value_bstr) const {
+ DCHECK_EQ(GetData().role, ax::mojom::Role::kListItem);
+ DCHECK(!HasStringAttribute(ax::mojom::StringAttribute::kName));
+ std::wstring str;
+ // The list item name will result in the concatenation of its children's
+ // accessible names, excluding the list item marker.
+ for (int i = 0; i < GetChildCount(); ++i) {
+ auto* child = static_cast<AXPlatformNodeWin*>(
+ FromNativeViewAccessible(ChildAtIndex(i)));
+ if (child->GetDelegate()->IsText())
+ str += base::UTF8ToWide(child->GetName());
+ }
*value_bstr = SysAllocString(str.c_str());
DCHECK(*value_bstr);
return S_OK;
@@ -7794,8 +7902,8 @@ double AXPlatformNodeWin::GetVerticalScrollPercent() {
}
BSTR AXPlatformNodeWin::GetFontNameAttributeAsBSTR() const {
- const base::string16 string =
- GetInheritedString16Attribute(ax::mojom::StringAttribute::kFontFamily);
+ const std::wstring string = base::UTF8ToWide(
+ GetInheritedStringAttribute(ax::mojom::StringAttribute::kFontFamily));
return SysAllocString(string.c_str());
}
@@ -7804,7 +7912,7 @@ BSTR AXPlatformNodeWin::GetStyleNameAttributeAsBSTR() const {
base::string16 style_name =
GetDelegate()->GetStyleNameAttributeAsLocalizedString();
- return SysAllocString(style_name.c_str());
+ return SysAllocString(base::as_wcstr(style_name));
}
TextDecorationLineStyle AXPlatformNodeWin::GetUIATextDecorationStyle(
@@ -7925,10 +8033,8 @@ AXPlatformNodeWin::GetPatternProviderFactoryMethod(PATTERNID pattern_id) {
case UIA_TextEditPatternId:
case UIA_TextPatternId:
- if (IsText() || IsDocument() ||
- HasBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot)) {
+ if (IsPlatformDocument() || IsTextField() || IsText())
return &AXPlatformNodeTextProviderWin::CreateIUnknown;
- }
break;
case UIA_TogglePatternId:
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.h b/chromium/ui/accessibility/platform/ax_platform_node_win.h
index 64b1819c9d8..852ecc6954e 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win.h
@@ -1091,7 +1091,7 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
HRESULT GetPropertyValueImpl(PROPERTYID property_id, VARIANT* result);
// Helper to return the runtime id (without going through a SAFEARRAY)
- using RuntimeIdArray = std::array<int, 2>;
+ using RuntimeIdArray = std::array<int, 4>;
void GetRuntimeIdArray(RuntimeIdArray& runtime_id);
// Updates the active composition range and fires UIA text edit event about
@@ -1128,7 +1128,7 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
// This is hard-coded; all products based on the Chromium engine will have the
// same framework name, so that assistive technology can detect any
// Chromium-based product.
- static constexpr const base::char16* FRAMEWORK_ID = L"Chrome";
+ static constexpr const wchar_t* FRAMEWORK_ID = L"Chrome";
AXPlatformNodeWin();
@@ -1140,11 +1140,11 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
int32_t ComputeIA2Role();
- std::vector<base::string16> ComputeIA2Attributes();
+ std::vector<std::wstring> ComputeIA2Attributes();
- base::string16 UIAAriaRole();
+ std::wstring UIAAriaRole();
- base::string16 ComputeUIAProperties();
+ std::wstring ComputeUIAProperties();
LONG ComputeUIAControlType();
@@ -1220,49 +1220,51 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
HRESULT GetNameAsBstr(BSTR* value_bstr) const;
+ HRESULT ComputeListItemNameAsBstr(BSTR* value_bstr) const;
+
// Sets the selection given a start and end offset in IA2 Hypertext.
void SetIA2HypertextSelection(LONG start_offset, LONG end_offset);
// Escapes characters in string attributes as required by the UIA Aria
// Property Spec. It's okay for input to be the same as output.
static void SanitizeStringAttributeForUIAAriaProperty(
- const base::string16& input,
- base::string16* output);
+ const std::wstring& input,
+ std::wstring* output);
// If the string attribute |attribute| is present, add its value as a
// UIA AriaProperties Property with the name |uia_aria_property|.
- void StringAttributeToUIAAriaProperty(std::vector<base::string16>& properties,
+ void StringAttributeToUIAAriaProperty(std::vector<std::wstring>& properties,
ax::mojom::StringAttribute attribute,
const char* uia_aria_property);
// If the bool attribute |attribute| is present, add its value as a
// UIA AriaProperties Property with the name |uia_aria_property|.
- void BoolAttributeToUIAAriaProperty(std::vector<base::string16>& properties,
+ void BoolAttributeToUIAAriaProperty(std::vector<std::wstring>& properties,
ax::mojom::BoolAttribute attribute,
const char* uia_aria_property);
// If the int attribute |attribute| is present, add its value as a
// UIA AriaProperties Property with the name |uia_aria_property|.
- void IntAttributeToUIAAriaProperty(std::vector<base::string16>& properties,
+ void IntAttributeToUIAAriaProperty(std::vector<std::wstring>& properties,
ax::mojom::IntAttribute attribute,
const char* uia_aria_property);
// If the float attribute |attribute| is present, add its value as a
// UIA AriaProperties Property with the name |uia_aria_property|.
- void FloatAttributeToUIAAriaProperty(std::vector<base::string16>& properties,
+ void FloatAttributeToUIAAriaProperty(std::vector<std::wstring>& properties,
ax::mojom::FloatAttribute attribute,
const char* uia_aria_property);
// If the state |state| exists, set the
// UIA AriaProperties Property with the name |uia_aria_property| to "true".
// Otherwise set the AriaProperties Property to "false".
- void StateToUIAAriaProperty(std::vector<base::string16>& properties,
+ void StateToUIAAriaProperty(std::vector<std::wstring>& properties,
ax::mojom::State state,
const char* uia_aria_property);
// If the Html attribute |html_attribute_name| is present, add its value as a
// UIA AriaProperties Property with the name |uia_aria_property|.
- void HtmlAttributeToUIAAriaProperty(std::vector<base::string16>& properties,
+ void HtmlAttributeToUIAAriaProperty(std::vector<std::wstring>& properties,
const char* html_attribute_name,
const char* uia_aria_property);
@@ -1435,7 +1437,7 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
// Fires UIA text edit event about composition (active or committed)
void FireUiaTextEditTextChangedEvent(
const gfx::Range& range,
- const base::string16& active_composition_text,
+ const std::wstring& active_composition_text,
bool is_composition_committed);
// Return true if the given element is valid enough to be returned as a value
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 e7b450ed9b4..d309f18e006 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -11,9 +11,9 @@
#include <memory>
#include "base/auto_reset.h"
+#include "base/containers/contains.h"
#include "base/json/json_reader.h"
#include "base/run_loop.h"
-#include "base/stl_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/win/atl.h"
@@ -289,7 +289,7 @@ AXPlatformNode* AXPlatformNodeWinTest::AXPlatformNodeFromNode(AXNode* node) {
}
template <typename T>
-ComPtr<T> AXPlatformNodeWinTest::QueryInterfaceFromNodeId(AXNode::AXID id) {
+ComPtr<T> AXPlatformNodeWinTest::QueryInterfaceFromNodeId(AXNodeID id) {
return QueryInterfaceFromNode<T>(GetNodeFromTree(id));
}
@@ -325,7 +325,7 @@ AXPlatformNodeWinTest::GetIRawElementProviderSimpleFromChildIndex(
Microsoft::WRL::ComPtr<IRawElementProviderSimple>
AXPlatformNodeWinTest::GetIRawElementProviderSimpleFromTree(
const ui::AXTreeID tree_id,
- const AXNode::AXID node_id) {
+ const AXNodeID node_id) {
return QueryInterfaceFromNode<IRawElementProviderSimple>(
GetNodeFromTree(tree_id, node_id));
}
@@ -453,7 +453,7 @@ AXPlatformNodeWinTest::GetFragmentRoot() {
}
AXPlatformNodeWinTest::PatternSet
-AXPlatformNodeWinTest::GetSupportedPatternsFromNodeId(AXNode::AXID id) {
+AXPlatformNodeWinTest::GetSupportedPatternsFromNodeId(AXNodeID id) {
ComPtr<IRawElementProviderSimple> raw_element_provider_simple =
QueryInterfaceFromNodeId<IRawElementProviderSimple>(id);
PatternSet supported_patterns;
@@ -517,6 +517,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessibleDetachedObject) {
TEST_F(AXPlatformNodeWinTest, IAccessibleHitTest) {
AXNodeData root;
root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
root.relative_bounds.bounds = gfx::RectF(0, 0, 40, 40);
AXNodeData node1;
@@ -559,6 +560,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessibleHitTest) {
TEST_F(AXPlatformNodeWinTest, IAccessibleHitTestDoesNotLoopForever) {
AXNodeData root;
root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
root.relative_bounds.bounds = gfx::RectF(0, 0, 40, 40);
AXNodeData node1;
@@ -605,6 +607,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessibleName) {
TEST_F(AXPlatformNodeWinTest, IAccessibleDescription) {
AXNodeData root;
root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
root.AddStringAttribute(ax::mojom::StringAttribute::kDescription,
"Description");
Init(root);
@@ -641,6 +644,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessibleAccValue) {
TEST_F(AXPlatformNodeWinTest, IAccessibleShortcut) {
AXNodeData root;
root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
root.AddStringAttribute(ax::mojom::StringAttribute::kKeyShortcuts,
"Shortcut");
Init(root);
@@ -994,6 +998,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessibleSelectionTableCellMultipleSelected) {
TEST_F(AXPlatformNodeWinTest, IAccessibleRole) {
AXNodeData root;
root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
root.child_ids.push_back(2);
AXNodeData child;
@@ -1029,6 +1034,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessibleRole) {
TEST_F(AXPlatformNodeWinTest, IAccessibleLocation) {
AXNodeData root;
root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
root.relative_bounds.bounds = gfx::RectF(10, 40, 800, 600);
Init(root);
@@ -1061,6 +1067,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessibleLocation) {
TEST_F(AXPlatformNodeWinTest, IAccessibleChildAndParent) {
AXNodeData root;
root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
root.child_ids.push_back(2);
root.child_ids.push_back(3);
@@ -1162,6 +1169,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessible2IndexInParent) {
AXNodeData root;
root.id = 1;
root.child_ids.push_back(2);
+ root.role = ax::mojom::Role::kRootWebArea;
root.child_ids.push_back(3);
AXNodeData left;
@@ -1394,7 +1402,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessibleTableQueryInterfaceOnNonTable) {
AXNodeData root;
root.id = 1;
- root.role = ax::mojom::Role::kWebArea;
+ root.role = ax::mojom::Role::kRootWebArea;
Init(root);
ComPtr<IAccessible> root_obj = GetRootIAccessible();
@@ -1853,7 +1861,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessible2GetNRelations) {
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
- std::vector<AXNode::AXID> describedby_ids = {1, 2, 3};
+ std::vector<AXNodeID> describedby_ids = {1, 2, 3};
root.AddIntListAttribute(ax::mojom::IntListAttribute::kDescribedbyIds,
describedby_ids);
@@ -1899,7 +1907,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessible2GetNRelations) {
EXPECT_HRESULT_SUCCEEDED(
describedby_relation->get_relationType(relation_type.Receive()));
- EXPECT_EQ(L"describedBy", base::string16(relation_type.Get()));
+ EXPECT_EQ(L"describedBy", std::wstring(relation_type.Get()));
relation_type.Reset();
@@ -1922,7 +1930,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessible2GetNRelations) {
ax_child1->get_relation(0, &description_for_relation));
EXPECT_HRESULT_SUCCEEDED(
description_for_relation->get_relationType(relation_type.Receive()));
- EXPECT_EQ(L"descriptionFor", base::string16(relation_type.Get()));
+ EXPECT_EQ(L"descriptionFor", std::wstring(relation_type.Get()));
relation_type.Reset();
EXPECT_HRESULT_SUCCEEDED(description_for_relation->get_nTargets(&n_targets));
@@ -1939,7 +1947,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessible2GetNRelations) {
ax_child2->get_relation(0, &description_for_relation));
EXPECT_HRESULT_SUCCEEDED(
description_for_relation->get_relationType(relation_type.Receive()));
- EXPECT_EQ(L"descriptionFor", base::string16(relation_type.Get()));
+ EXPECT_EQ(L"descriptionFor", std::wstring(relation_type.Get()));
relation_type.Reset();
EXPECT_HRESULT_SUCCEEDED(description_for_relation->get_nTargets(&n_targets));
@@ -1999,7 +2007,7 @@ TEST_F(AXPlatformNodeWinTest,
EXPECT_HRESULT_SUCCEEDED(
controls_relation->get_relationType(relation_type.Receive()));
- EXPECT_EQ(L"controllerFor", base::string16(relation_type.Get()));
+ EXPECT_EQ(L"controllerFor", std::wstring(relation_type.Get()));
relation_type.Reset();
@@ -2024,7 +2032,7 @@ TEST_F(AXPlatformNodeWinTest,
EXPECT_HRESULT_SUCCEEDED(ax_child2->get_relation(0, &controlled_by_relation));
EXPECT_HRESULT_SUCCEEDED(
controlled_by_relation->get_relationType(relation_type.Receive()));
- EXPECT_EQ(L"controlledBy", base::string16(relation_type.Get()));
+ EXPECT_EQ(L"controlledBy", std::wstring(relation_type.Get()));
relation_type.Reset();
EXPECT_HRESULT_SUCCEEDED(controlled_by_relation->get_nTargets(&n_targets));
@@ -2038,7 +2046,7 @@ TEST_F(AXPlatformNodeWinTest,
EXPECT_HRESULT_SUCCEEDED(ax_child2->get_relation(1, &controlled_by_relation));
EXPECT_HRESULT_SUCCEEDED(
controlled_by_relation->get_relationType(relation_type.Receive()));
- EXPECT_EQ(L"controlledBy", base::string16(relation_type.Get()));
+ EXPECT_EQ(L"controlledBy", std::wstring(relation_type.Get()));
relation_type.Reset();
EXPECT_HRESULT_SUCCEEDED(controlled_by_relation->get_nTargets(&n_targets));
@@ -2063,7 +2071,7 @@ TEST_F(AXPlatformNodeWinTest, DISABLED_TestRelationTargetsOfType) {
AXNodeData child2;
child2.id = 3;
child2.role = ax::mojom::Role::kStaticText;
- std::vector<AXNode::AXID> labelledby_ids = {1, 4};
+ std::vector<AXNodeID> labelledby_ids = {1, 4};
child2.AddIntListAttribute(ax::mojom::IntListAttribute::kLabelledbyIds,
labelledby_ids);
@@ -2869,9 +2877,9 @@ TEST_F(AXPlatformNodeWinTest, UnlabeledImageAttributes) {
ScopedBstr attributes_bstr;
ASSERT_EQ(S_OK, ia2_child->get_attributes(attributes_bstr.Receive()));
- base::string16 attributes(attributes_bstr.Get());
+ std::wstring attributes(attributes_bstr.Get());
- std::vector<base::string16> attribute_vector = base::SplitString(
+ std::vector<std::wstring> attribute_vector = base::SplitString(
attributes, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
EXPECT_TRUE(
base::Contains(attribute_vector, L"roledescription:Unlabeled image"));
@@ -3048,7 +3056,7 @@ TEST_F(AXPlatformNodeWinTest, IAccessibleTextGetNCharacters) {
TEST_F(AXPlatformNodeWinTest, IAccessibleTextGetOffsetAtPoint) {
AXNodeData root;
root.id = 1;
- root.role = ax::mojom::Role::kWebArea;
+ root.role = ax::mojom::Role::kRootWebArea;
root.relative_bounds.bounds = gfx::RectF(0, 0, 300, 200);
root.child_ids = {2, 3};
@@ -3556,13 +3564,13 @@ TEST_F(AXPlatformNodeWinTest, ITableProviderGetColumnHeaders) {
AXNodeData column_header;
column_header.id = 3;
column_header.role = ax::mojom::Role::kColumnHeader;
- column_header.SetName(L"column_header");
+ column_header.SetName(STRING16_LITERAL("column_header"));
row1.child_ids.push_back(column_header.id);
AXNodeData row_header;
row_header.id = 4;
row_header.role = ax::mojom::Role::kRowHeader;
- row_header.SetName(L"row_header");
+ row_header.SetName(STRING16_LITERAL("row_header"));
row1.child_ids.push_back(row_header.id);
Init(root, row1, column_header, row_header);
@@ -3639,19 +3647,19 @@ TEST_F(AXPlatformNodeWinTest, ITableProviderGetColumnHeadersMultipleHeaders) {
AXNodeData header_r1c1;
header_r1c1.id = 5;
header_r1c1.role = ax::mojom::Role::kColumnHeader;
- header_r1c1.SetName(L"header_r1c1");
+ header_r1c1.SetName(STRING16_LITERAL("header_r1c1"));
row1.child_ids.push_back(header_r1c1.id);
AXNodeData header_r1c2;
header_r1c2.id = 6;
header_r1c2.role = ax::mojom::Role::kColumnHeader;
- header_r1c2.SetName(L"header_r1c2");
+ header_r1c2.SetName(STRING16_LITERAL("header_r1c2"));
row1.child_ids.push_back(header_r1c2.id);
AXNodeData header_r1c3;
header_r1c3.id = 7;
header_r1c3.role = ax::mojom::Role::kColumnHeader;
- header_r1c3.SetName(L"header_r1c3");
+ header_r1c3.SetName(STRING16_LITERAL("header_r1c3"));
row1.child_ids.push_back(header_r1c3.id);
// <tr aria-label="row2">
@@ -3660,19 +3668,19 @@ TEST_F(AXPlatformNodeWinTest, ITableProviderGetColumnHeadersMultipleHeaders) {
AXNodeData cell_r2c1;
cell_r2c1.id = 8;
cell_r2c1.role = ax::mojom::Role::kCell;
- cell_r2c1.SetName(L"cell_r2c1");
+ cell_r2c1.SetName(STRING16_LITERAL("cell_r2c1"));
row2.child_ids.push_back(cell_r2c1.id);
AXNodeData cell_r2c2;
cell_r2c2.id = 9;
cell_r2c2.role = ax::mojom::Role::kCell;
- cell_r2c2.SetName(L"cell_r2c2");
+ cell_r2c2.SetName(STRING16_LITERAL("cell_r2c2"));
row2.child_ids.push_back(cell_r2c2.id);
AXNodeData cell_r2c3;
cell_r2c3.id = 10;
cell_r2c3.role = ax::mojom::Role::kCell;
- cell_r2c3.SetName(L"cell_r2c3");
+ cell_r2c3.SetName(STRING16_LITERAL("cell_r2c3"));
row2.child_ids.push_back(cell_r2c3.id);
// <tr aria-label="row3">
@@ -3681,13 +3689,13 @@ TEST_F(AXPlatformNodeWinTest, ITableProviderGetColumnHeadersMultipleHeaders) {
AXNodeData cell_r3c1;
cell_r3c1.id = 11;
cell_r3c1.role = ax::mojom::Role::kCell;
- cell_r3c1.SetName(L"cell_r3c1");
+ cell_r3c1.SetName(STRING16_LITERAL("cell_r3c1"));
row3.child_ids.push_back(cell_r3c1.id);
AXNodeData header_r3c2;
header_r3c2.id = 12;
header_r3c2.role = ax::mojom::Role::kColumnHeader;
- header_r3c2.SetName(L"header_r3c2");
+ header_r3c2.SetName(STRING16_LITERAL("header_r3c2"));
row3.child_ids.push_back(header_r3c2.id);
Init(root, row1, row2, row3, header_r1c1, header_r1c2, header_r1c3, cell_r2c1,
@@ -3722,13 +3730,13 @@ TEST_F(AXPlatformNodeWinTest, ITableProviderGetRowHeaders) {
AXNodeData column_header;
column_header.id = 3;
column_header.role = ax::mojom::Role::kColumnHeader;
- column_header.SetName(L"column_header");
+ column_header.SetName(STRING16_LITERAL("column_header"));
row1.child_ids.push_back(column_header.id);
AXNodeData row_header;
row_header.id = 4;
row_header.role = ax::mojom::Role::kRowHeader;
- row_header.SetName(L"row_header");
+ row_header.SetName(STRING16_LITERAL("row_header"));
row1.child_ids.push_back(row_header.id);
Init(root, row1, column_header, row_header);
@@ -3784,13 +3792,13 @@ TEST_F(AXPlatformNodeWinTest, ITableItemProviderGetColumnHeaderItems) {
AXNodeData column_header_1;
column_header_1.id = 3;
column_header_1.role = ax::mojom::Role::kColumnHeader;
- column_header_1.SetName(L"column_header_1");
+ column_header_1.SetName(STRING16_LITERAL("column_header_1"));
row1.child_ids.push_back(column_header_1.id);
AXNodeData column_header_2;
column_header_2.id = 4;
column_header_2.role = ax::mojom::Role::kColumnHeader;
- column_header_2.SetName(L"column_header_2");
+ column_header_2.SetName(STRING16_LITERAL("column_header_2"));
row1.child_ids.push_back(column_header_2.id);
AXNodeData row2;
@@ -3847,7 +3855,7 @@ TEST_F(AXPlatformNodeWinTest, ITableItemProviderGetRowHeaderItems) {
AXNodeData row_header_1;
row_header_1.id = 3;
row_header_1.role = ax::mojom::Role::kRowHeader;
- row_header_1.SetName(L"row_header_1");
+ row_header_1.SetName(STRING16_LITERAL("row_header_1"));
row1.child_ids.push_back(row_header_1.id);
AXNodeData cell;
@@ -3863,7 +3871,7 @@ TEST_F(AXPlatformNodeWinTest, ITableItemProviderGetRowHeaderItems) {
AXNodeData row_header_2;
row_header_2.id = 6;
row_header_2.role = ax::mojom::Role::kRowHeader;
- row_header_2.SetName(L"row_header_2");
+ row_header_2.SetName(STRING16_LITERAL("row_header_2"));
row2.child_ids.push_back(row_header_2.id);
Init(root, row1, row_header_1, cell, row2, row_header_2);
@@ -4151,7 +4159,7 @@ TEST_F(AXPlatformNodeWinTest, UIAGetControllerForPropertyId) {
tab.id = 2;
tab.role = ax::mojom::Role::kTab;
tab.SetName("tab");
- std::vector<AXNode::AXID> controller_ids = {3, 4};
+ std::vector<AXNodeID> controller_ids = {3, 4};
tab.AddIntListAttribute(ax::mojom::IntListAttribute::kControlsIds,
controller_ids);
@@ -4191,7 +4199,7 @@ TEST_F(AXPlatformNodeWinTest, UIAGetControllerForPropertyId) {
TEST_F(AXPlatformNodeWinTest, UIAGetDescribedByPropertyId) {
AXNodeData root;
- std::vector<AXNode::AXID> describedby_ids = {2, 3, 4};
+ std::vector<AXNodeID> describedby_ids = {2, 3, 4};
root.AddIntListAttribute(ax::mojom::IntListAttribute::kDescribedbyIds,
describedby_ids);
root.id = 1;
@@ -4292,7 +4300,7 @@ TEST_F(AXPlatformNodeWinTest, UIAItemStatusPropertyId) {
TEST_F(AXPlatformNodeWinTest, UIAGetFlowsToPropertyId) {
AXNodeData root;
- std::vector<AXNode::AXID> flowto_ids = {2, 3, 4};
+ std::vector<AXNodeID> flowto_ids = {2, 3, 4};
root.AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds, flowto_ids);
root.id = 1;
root.role = ax::mojom::Role::kMarquee;
@@ -4749,6 +4757,8 @@ TEST_F(AXPlatformNodeWinTest, GetPropertyValue_IsControlElement) {
TEST_F(AXPlatformNodeWinTest, UIAGetProviderOptions) {
AXNodeData root_data;
+ root_data.id = 1;
+ root_data.role = ax::mojom::Role::kRootWebArea;
Init(root_data);
ComPtr<IRawElementProviderSimple> root_node =
@@ -4765,6 +4775,8 @@ TEST_F(AXPlatformNodeWinTest, UIAGetProviderOptions) {
TEST_F(AXPlatformNodeWinTest, UIAGetHostRawElementProvider) {
AXNodeData root_data;
+ root_data.id = 1;
+ root_data.role = ax::mojom::Role::kRootWebArea;
Init(root_data);
ComPtr<IRawElementProviderSimple> root_node =
@@ -4779,6 +4791,7 @@ TEST_F(AXPlatformNodeWinTest, UIAGetHostRawElementProvider) {
TEST_F(AXPlatformNodeWinTest, UIAGetBoundingRectangle) {
AXNodeData root_data;
root_data.id = 1;
+ root_data.role = ax::mojom::Role::kRootWebArea;
root_data.relative_bounds.bounds = gfx::RectF(10, 20, 30, 50);
Init(root_data);
@@ -4799,6 +4812,7 @@ TEST_F(AXPlatformNodeWinTest, UIAGetFragmentRoot) {
// overrides the method.
AXNodeData root_data;
root_data.id = 1;
+ root_data.role = ax::mojom::Role::kRootWebArea;
AXNodeData element1_data;
element1_data.id = 2;
@@ -4837,6 +4851,7 @@ TEST_F(AXPlatformNodeWinTest, UIAGetFragmentRoot) {
TEST_F(AXPlatformNodeWinTest, UIAGetEmbeddedFragmentRoots) {
AXNodeData root_data;
root_data.id = 1;
+ root_data.role = ax::mojom::Role::kRootWebArea;
Init(root_data);
ComPtr<IRawElementProviderFragment> root_provider =
@@ -4851,6 +4866,7 @@ TEST_F(AXPlatformNodeWinTest, UIAGetEmbeddedFragmentRoots) {
TEST_F(AXPlatformNodeWinTest, UIAGetRuntimeId) {
AXNodeData root_data;
root_data.id = 1;
+ root_data.role = ax::mojom::Role::kRootWebArea;
Init(root_data);
ComPtr<IRawElementProviderFragment> root_provider =
@@ -4867,13 +4883,15 @@ TEST_F(AXPlatformNodeWinTest, UIAGetRuntimeId) {
LONG array_upper_bound;
EXPECT_HRESULT_SUCCEEDED(
::SafeArrayGetUBound(runtime_id.Get(), 1, &array_upper_bound));
- EXPECT_EQ(1, array_upper_bound);
+ EXPECT_EQ(3, array_upper_bound);
int* array_data;
EXPECT_HRESULT_SUCCEEDED(::SafeArrayAccessData(
runtime_id.Get(), reinterpret_cast<void**>(&array_data)));
EXPECT_EQ(UiaAppendRuntimeId, array_data[0]);
EXPECT_NE(-1, array_data[1]);
+ EXPECT_NE(-1, array_data[2]);
+ EXPECT_NE(-1, array_data[3]);
EXPECT_HRESULT_SUCCEEDED(::SafeArrayUnaccessData(runtime_id.Get()));
}
@@ -4994,6 +5012,7 @@ TEST_F(AXPlatformNodeWinTest, UIAIWindowProviderNotSupported) {
TEST_F(AXPlatformNodeWinTest, UIANavigate) {
AXNodeData root_data;
root_data.id = 1;
+ root_data.role = ax::mojom::Role::kRootWebArea;
AXNodeData element1_data;
element1_data.id = 2;
@@ -5228,25 +5247,25 @@ TEST_F(AXPlatformNodeWinTest, ComputeUIAControlType) {
root.role = ax::mojom::Role::kRootWebArea;
AXNodeData child1;
- AXNode::AXID child1_id = 2;
+ AXNodeID child1_id = 2;
child1.id = child1_id;
child1.role = ax::mojom::Role::kTable;
root.child_ids.push_back(child1_id);
AXNodeData child2;
- AXNode::AXID child2_id = 3;
+ AXNodeID child2_id = 3;
child2.id = child2_id;
child2.role = ax::mojom::Role::kLayoutTable;
root.child_ids.push_back(child2_id);
AXNodeData child3;
- AXNode::AXID child3_id = 4;
+ AXNodeID child3_id = 4;
child3.id = child3_id;
child3.role = ax::mojom::Role::kTextField;
root.child_ids.push_back(child3_id);
AXNodeData child4;
- AXNode::AXID child4_id = 5;
+ AXNodeID child4_id = 5;
child4.id = child4_id;
child4.role = ax::mojom::Role::kSearchBox;
root.child_ids.push_back(child4_id);
@@ -5357,6 +5376,7 @@ TEST_F(AXPlatformNodeWinTest, UIALocalizedLandmarkType) {
TEST_F(AXPlatformNodeWinTest, IRawElementProviderSimple2ShowContextMenu) {
AXNodeData root_data;
root_data.id = 1;
+ root_data.role = ax::mojom::Role::kRootWebArea;
AXNodeData element1_data;
element1_data.id = 2;
@@ -5389,6 +5409,8 @@ TEST_F(AXPlatformNodeWinTest, IRawElementProviderSimple2ShowContextMenu) {
TEST_F(AXPlatformNodeWinTest, UIAErrorHandling) {
AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
Init(root);
ComPtr<IRawElementProviderSimple> simple_provider =
@@ -5605,26 +5627,26 @@ TEST_F(AXPlatformNodeWinTest, UIAErrorHandling) {
}
TEST_F(AXPlatformNodeWinTest, GetPatternProviderSupportedPatterns) {
- constexpr AXNode::AXID root_id = 1;
- constexpr AXNode::AXID text_field_with_combo_box_id = 2;
- constexpr AXNode::AXID meter_id = 3;
- constexpr AXNode::AXID group_with_scroll_id = 4;
- constexpr AXNode::AXID checkbox_id = 5;
- constexpr AXNode::AXID link_id = 6;
- constexpr AXNode::AXID table_without_header_id = 7;
- constexpr AXNode::AXID table_without_header_cell_id = 8;
- constexpr AXNode::AXID table_with_header_id = 9;
- constexpr AXNode::AXID table_with_header_row_1_id = 10;
- constexpr AXNode::AXID table_with_header_column_header_id = 11;
- constexpr AXNode::AXID table_with_header_row_2_id = 12;
- constexpr AXNode::AXID table_with_header_cell_id = 13;
- constexpr AXNode::AXID grid_without_header_id = 14;
- constexpr AXNode::AXID grid_without_header_cell_id = 15;
- constexpr AXNode::AXID grid_with_header_id = 16;
- constexpr AXNode::AXID grid_with_header_row_1_id = 17;
- constexpr AXNode::AXID grid_with_header_column_header_id = 18;
- constexpr AXNode::AXID grid_with_header_row_2_id = 19;
- constexpr AXNode::AXID grid_with_header_cell_id = 20;
+ constexpr AXNodeID root_id = 1;
+ constexpr AXNodeID text_field_with_combo_box_id = 2;
+ constexpr AXNodeID meter_id = 3;
+ constexpr AXNodeID group_with_scroll_id = 4;
+ constexpr AXNodeID checkbox_id = 5;
+ constexpr AXNodeID link_id = 6;
+ constexpr AXNodeID table_without_header_id = 7;
+ constexpr AXNodeID table_without_header_cell_id = 8;
+ constexpr AXNodeID table_with_header_id = 9;
+ constexpr AXNodeID table_with_header_row_1_id = 10;
+ constexpr AXNodeID table_with_header_column_header_id = 11;
+ constexpr AXNodeID table_with_header_row_2_id = 12;
+ constexpr AXNodeID table_with_header_cell_id = 13;
+ constexpr AXNodeID grid_without_header_id = 14;
+ constexpr AXNodeID grid_without_header_cell_id = 15;
+ constexpr AXNodeID grid_with_header_id = 16;
+ constexpr AXNodeID grid_with_header_row_1_id = 17;
+ constexpr AXNodeID grid_with_header_column_header_id = 18;
+ constexpr AXNodeID grid_with_header_row_2_id = 19;
+ constexpr AXNodeID grid_with_header_cell_id = 20;
AXTreeUpdate update;
update.tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
@@ -5644,6 +5666,9 @@ TEST_F(AXPlatformNodeWinTest, GetPatternProviderSupportedPatterns) {
grid_with_header_id};
update.nodes[1].id = text_field_with_combo_box_id;
update.nodes[1].role = ax::mojom::Role::kTextFieldWithComboBox;
+ update.nodes[1].AddState(ax::mojom::State::kEditable);
+ update.nodes[1].AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot,
+ true);
update.nodes[2].id = meter_id;
update.nodes[2].role = ax::mojom::Role::kMeter;
update.nodes[3].id = group_with_scroll_id;
@@ -5704,7 +5729,8 @@ TEST_F(AXPlatformNodeWinTest, GetPatternProviderSupportedPatterns) {
GetSupportedPatternsFromNodeId(root_id));
EXPECT_EQ(PatternSet({UIA_ScrollItemPatternId, UIA_ValuePatternId,
- UIA_ExpandCollapsePatternId, UIA_TextChildPatternId}),
+ UIA_ExpandCollapsePatternId, UIA_TextChildPatternId,
+ UIA_TextEditPatternId, UIA_TextPatternId}),
GetSupportedPatternsFromNodeId(text_field_with_combo_box_id));
EXPECT_EQ(PatternSet({UIA_ScrollItemPatternId, UIA_ValuePatternId,
@@ -5772,6 +5798,7 @@ TEST_F(AXPlatformNodeWinTest, GetPatternProviderSupportedPatterns) {
TEST_F(AXPlatformNodeWinTest, GetPatternProviderExpandCollapsePattern) {
ui::AXNodeData root;
root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
ui::AXNodeData list_box;
ui::AXNodeData list_item;
@@ -5890,6 +5917,7 @@ TEST_F(AXPlatformNodeWinTest, GetPatternProviderExpandCollapsePattern) {
TEST_F(AXPlatformNodeWinTest, GetPatternProviderInvokePattern) {
ui::AXNodeData root;
root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
ui::AXNodeData link;
ui::AXNodeData generic_container;
@@ -5956,6 +5984,7 @@ TEST_F(AXPlatformNodeWinTest, GetPatternProviderInvokePattern) {
TEST_F(AXPlatformNodeWinTest, IExpandCollapsePatternProviderAction) {
ui::AXNodeData root;
root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
ui::AXNodeData combo_box_grouping_has_popup;
ui::AXNodeData combo_box_grouping_expanded;
@@ -6125,6 +6154,7 @@ TEST_F(AXPlatformNodeWinTest, IExpandCollapsePatternProviderAction) {
TEST_F(AXPlatformNodeWinTest, IInvokeProviderInvoke) {
ui::AXNodeData root;
root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
ui::AXNodeData button;
ui::AXNodeData button_disabled;
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.h b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.h
index 2d272715747..85a66de654b 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.h
@@ -90,7 +90,7 @@ class AXPlatformNodeWinTest : public AXPlatformNodeTest {
AXPlatformNode* AXPlatformNodeFromNode(AXNode* node);
template <typename T>
- Microsoft::WRL::ComPtr<T> QueryInterfaceFromNodeId(AXNode::AXID id);
+ Microsoft::WRL::ComPtr<T> QueryInterfaceFromNodeId(AXNodeID id);
template <typename T>
Microsoft::WRL::ComPtr<T> QueryInterfaceFromNode(AXNode* node);
Microsoft::WRL::ComPtr<IRawElementProviderSimple>
@@ -99,7 +99,7 @@ class AXPlatformNodeWinTest : public AXPlatformNodeTest {
GetIRawElementProviderSimpleFromChildIndex(int child_index);
Microsoft::WRL::ComPtr<IRawElementProviderSimple>
GetIRawElementProviderSimpleFromTree(const ui::AXTreeID tree_id,
- const AXNode::AXID node_id);
+ const AXNodeID node_id);
Microsoft::WRL::ComPtr<IRawElementProviderFragment>
GetRootIRawElementProviderFragment();
Microsoft::WRL::ComPtr<IRawElementProviderFragment>
@@ -124,7 +124,7 @@ class AXPlatformNodeWinTest : public AXPlatformNodeTest {
Microsoft::WRL::ComPtr<IRawElementProviderFragmentRoot> GetFragmentRoot();
using PatternSet = std::unordered_set<LONG>;
- PatternSet GetSupportedPatternsFromNodeId(AXNode::AXID id);
+ PatternSet GetSupportedPatternsFromNodeId(AXNodeID id);
std::unique_ptr<AXFragmentRootWin> ax_fragment_root_;
diff --git a/chromium/ui/accessibility/platform/ax_platform_relation_win.cc b/chromium/ui/accessibility/platform/ax_platform_relation_win.cc
index eee92e3b9cb..c50ac0ceda9 100644
--- a/chromium/ui/accessibility/platform/ax_platform_relation_win.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_relation_win.cc
@@ -37,7 +37,7 @@ AXPlatformRelationWin::AXPlatformRelationWin() {
AXPlatformRelationWin::~AXPlatformRelationWin() {}
-base::string16 GetIA2RelationFromIntAttr(ax::mojom::IntAttribute attribute) {
+std::wstring GetIA2RelationFromIntAttr(ax::mojom::IntAttribute attribute) {
switch (attribute) {
case ax::mojom::IntAttribute::kMemberOfId:
return IA2_RELATION_MEMBER_OF;
@@ -50,12 +50,11 @@ base::string16 GetIA2RelationFromIntAttr(ax::mojom::IntAttribute attribute) {
// content as the reverse of the controls relationship.
return IA2_RELATION_CONTROLLED_BY;
default:
- break;
+ return std::wstring();
}
- return base::string16();
}
-base::string16 GetIA2RelationFromIntListAttr(
+std::wstring GetIA2RelationFromIntListAttr(
ax::mojom::IntListAttribute attribute) {
switch (attribute) {
case ax::mojom::IntListAttribute::kControlsIds:
@@ -69,23 +68,21 @@ base::string16 GetIA2RelationFromIntListAttr(
case ax::mojom::IntListAttribute::kLabelledbyIds:
return IA2_RELATION_LABELLED_BY;
default:
- break;
+ return std::wstring();
}
- return base::string16();
}
-base::string16 GetIA2ReverseRelationFromIntAttr(
+std::wstring GetIA2ReverseRelationFromIntAttr(
ax::mojom::IntAttribute attribute) {
switch (attribute) {
case ax::mojom::IntAttribute::kErrormessageId:
return IA2_RELATION_ERROR_FOR;
default:
- break;
+ return std::wstring();
}
- return base::string16();
}
-base::string16 GetIA2ReverseRelationFromIntListAttr(
+std::wstring GetIA2ReverseRelationFromIntListAttr(
ax::mojom::IntListAttribute attribute) {
switch (attribute) {
case ax::mojom::IntListAttribute::kControlsIds:
@@ -99,17 +96,16 @@ base::string16 GetIA2ReverseRelationFromIntListAttr(
case ax::mojom::IntListAttribute::kLabelledbyIds:
return IA2_RELATION_LABEL_FOR;
default:
- break;
+ return std::wstring();
}
- return base::string16();
}
// static
int AXPlatformRelationWin::EnumerateRelationships(
AXPlatformNodeBase* node,
int desired_index,
- const base::string16& desired_ia2_relation,
- base::string16* out_ia2_relation,
+ const std::wstring& desired_ia2_relation,
+ std::wstring* out_ia2_relation,
std::set<AXPlatformNode*>* out_targets) {
const AXNodeData& node_data = node->GetData();
AXPlatformNodeDelegate* delegate = node->GetDelegate();
@@ -157,7 +153,7 @@ int AXPlatformRelationWin::EnumerateRelationships(
// that correspond to IAccessible2 relations.
for (size_t i = 0; i < node_data.int_attributes.size(); ++i) {
ax::mojom::IntAttribute int_attribute = node_data.int_attributes[i].first;
- base::string16 relation = GetIA2RelationFromIntAttr(int_attribute);
+ std::wstring relation = GetIA2RelationFromIntAttr(int_attribute);
if (!relation.empty() &&
(desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
// Skip reflexive relations
@@ -177,7 +173,7 @@ int AXPlatformRelationWin::EnumerateRelationships(
// in IAccessible2, and query AXTree to see if the reverse relation exists.
for (ax::mojom::IntAttribute int_attribute :
int_attributes_with_reverse_relations) {
- base::string16 relation = GetIA2ReverseRelationFromIntAttr(int_attribute);
+ std::wstring relation = GetIA2ReverseRelationFromIntAttr(int_attribute);
std::set<AXPlatformNode*> targets =
delegate->GetReverseRelations(int_attribute);
// Erase reflexive relations.
@@ -200,7 +196,7 @@ int AXPlatformRelationWin::EnumerateRelationships(
for (size_t i = 0; i < node_data.intlist_attributes.size(); ++i) {
ax::mojom::IntListAttribute intlist_attribute =
node_data.intlist_attributes[i].first;
- base::string16 relation = GetIA2RelationFromIntListAttr(intlist_attribute);
+ std::wstring relation = GetIA2RelationFromIntListAttr(intlist_attribute);
if (!relation.empty() &&
(desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
if (desired_index == total_count) {
@@ -223,7 +219,7 @@ int AXPlatformRelationWin::EnumerateRelationships(
// in IAccessible2, and query AXTree to see if the reverse relation exists.
for (ax::mojom::IntListAttribute intlist_attribute :
intlist_attributes_with_reverse_relations) {
- base::string16 relation =
+ std::wstring relation =
GetIA2ReverseRelationFromIntListAttr(intlist_attribute);
std::set<AXPlatformNode*> targets =
delegate->GetReverseRelations(intlist_attribute);
@@ -245,7 +241,7 @@ int AXPlatformRelationWin::EnumerateRelationships(
return total_count;
}
-void AXPlatformRelationWin::Initialize(const base::string16& type) {
+void AXPlatformRelationWin::Initialize(const std::wstring& type) {
type_ = type;
}
diff --git a/chromium/ui/accessibility/platform/ax_platform_relation_win.h b/chromium/ui/accessibility/platform/ax_platform_relation_win.h
index dd8426fdb53..76f2721e7a9 100644
--- a/chromium/ui/accessibility/platform/ax_platform_relation_win.h
+++ b/chromium/ui/accessibility/platform/ax_platform_relation_win.h
@@ -55,11 +55,11 @@ class AXPlatformRelationWin : public CComObjectRootEx<CComMultiThreadModel>,
// criteria.
static int EnumerateRelationships(AXPlatformNodeBase* node,
int desired_index,
- const base::string16& desired_ia2_relation,
- base::string16* out_ia2_relation,
+ const std::wstring& desired_ia2_relation,
+ std::wstring* out_ia2_relation,
std::set<AXPlatformNode*>* out_targets);
- void Initialize(const base::string16& type);
+ void Initialize(const std::wstring& type);
void Invalidate();
void AddTarget(AXPlatformNodeWin* target);
@@ -73,7 +73,7 @@ class AXPlatformRelationWin : public CComObjectRootEx<CComMultiThreadModel>,
IFACEMETHODIMP get_localizedRelationType(BSTR* relation_type) override;
private:
- base::string16 type_;
+ std::wstring type_;
std::vector<Microsoft::WRL::ComPtr<AXPlatformNodeWin>> targets_;
};
diff --git a/chromium/ui/accessibility/platform/ax_private_webkit_constants_mac.h b/chromium/ui/accessibility/platform/ax_private_webkit_constants_mac.h
new file mode 100644
index 00000000000..5f1776a3aea
--- /dev/null
+++ b/chromium/ui/accessibility/platform/ax_private_webkit_constants_mac.h
@@ -0,0 +1,96 @@
+// Copyright 2020 The Chromium 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_AX_PRIVATE_WEBKIT_CONSTANTS_MAC_H_
+#define UI_ACCESSIBILITY_PLATFORM_AX_PRIVATE_WEBKIT_CONSTANTS_MAC_H_
+
+#import <Cocoa/Cocoa.h>
+#include "ui/accessibility/ax_export.h"
+
+namespace ui {
+
+enum AXTextStateChangeType {
+ AXTextStateChangeTypeUnknown,
+ AXTextStateChangeTypeEdit,
+ AXTextStateChangeTypeSelectionMove,
+ AXTextStateChangeTypeSelectionExtend
+};
+
+enum AXTextSelectionDirection {
+ AXTextSelectionDirectionUnknown,
+ AXTextSelectionDirectionBeginning,
+ AXTextSelectionDirectionEnd,
+ AXTextSelectionDirectionPrevious,
+ AXTextSelectionDirectionNext,
+ AXTextSelectionDirectionDiscontiguous
+};
+
+enum AXTextSelectionGranularity {
+ AXTextSelectionGranularityUnknown,
+ AXTextSelectionGranularityCharacter,
+ AXTextSelectionGranularityWord,
+ AXTextSelectionGranularityLine,
+ AXTextSelectionGranularitySentence,
+ AXTextSelectionGranularityParagraph,
+ AXTextSelectionGranularityPage,
+ AXTextSelectionGranularityDocument,
+ AXTextSelectionGranularityAll
+};
+
+enum AXTextEditType {
+ AXTextEditTypeUnknown,
+ AXTextEditTypeDelete,
+ AXTextEditTypeInsert,
+ AXTextEditTypeTyping,
+ AXTextEditTypeDictation,
+ AXTextEditTypeCut,
+ AXTextEditTypePaste,
+ AXTextEditTypeAttributesChange
+};
+
+// Native mac notifications fired.
+NSString* const NSAccessibilityAutocorrectionOccurredNotification =
+ @"AXAutocorrectionOccurred";
+NSString* const NSAccessibilityLoadCompleteNotification = @"AXLoadComplete";
+NSString* const NSAccessibilityInvalidStatusChangedNotification =
+ @"AXInvalidStatusChanged";
+NSString* const NSAccessibilityLiveRegionCreatedNotification =
+ @"AXLiveRegionCreated";
+NSString* const NSAccessibilityLiveRegionChangedNotification =
+ @"AXLiveRegionChanged";
+NSString* const NSAccessibilityExpandedChanged = @"AXExpandedChanged";
+NSString* const NSAccessibilityMenuItemSelectedNotification =
+ @"AXMenuItemSelected";
+
+// The following native mac notifications are not fired:
+// AXLayoutComplete: Voiceover does not use this, it is considered too spammy.
+
+// Attributes used for NSAccessibilitySelectedTextChangedNotification and
+// NSAccessibilityValueChangedNotification.
+NSString* const NSAccessibilityTextStateChangeTypeKey =
+ @"AXTextStateChangeType";
+NSString* const NSAccessibilityTextStateSyncKey = @"AXTextStateSync";
+NSString* const NSAccessibilityTextSelectionDirection =
+ @"AXTextSelectionDirection";
+NSString* const NSAccessibilityTextSelectionGranularity =
+ @"AXTextSelectionGranularity";
+NSString* const NSAccessibilityTextSelectionChangedFocus =
+ @"AXTextSelectionChangedFocus";
+NSString* const NSAccessibilityTextChangeElement = @"AXTextChangeElement";
+NSString* const NSAccessibilityTextEditType = @"AXTextEditType";
+NSString* const NSAccessibilityTextChangeValue = @"AXTextChangeValue";
+NSString* const NSAccessibilityChangeValueStartMarker =
+ @"AXTextChangeValueStartMarker";
+NSString* const NSAccessibilityTextChangeValueLength =
+ @"AXTextChangeValueLength";
+NSString* const NSAccessibilityTextChangeValues = @"AXTextChangeValues";
+
+AX_EXPORT const char* ToString(AXTextStateChangeType);
+AX_EXPORT const char* ToString(AXTextSelectionDirection);
+AX_EXPORT const char* ToString(AXTextSelectionGranularity);
+AX_EXPORT const char* ToString(AXTextEditType);
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_PLATFORM_AX_PRIVATE_WEBKIT_CONSTANTS_MAC_H_
diff --git a/chromium/ui/accessibility/platform/ax_private_webkit_constants_mac.mm b/chromium/ui/accessibility/platform/ax_private_webkit_constants_mac.mm
new file mode 100644
index 00000000000..7de31a487dd
--- /dev/null
+++ b/chromium/ui/accessibility/platform/ax_private_webkit_constants_mac.mm
@@ -0,0 +1,91 @@
+// Copyright 2020 The Chromium 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/ax_private_webkit_constants_mac.h"
+
+namespace ui {
+
+const char* ToString(AXTextStateChangeType type) {
+ switch (type) {
+ case AXTextStateChangeTypeUnknown:
+ return "AXTextStateChangeTypeUnknown";
+ case AXTextStateChangeTypeEdit:
+ return "AXTextStateChangeTypeEdit";
+ case AXTextStateChangeTypeSelectionMove:
+ return "AXTextStateChangeTypeSelectionMove";
+ case AXTextStateChangeTypeSelectionExtend:
+ return "AXTextStateChangeTypeSelectionExtend";
+ }
+
+ return "";
+}
+
+const char* ToString(AXTextSelectionDirection direction) {
+ switch (direction) {
+ case AXTextSelectionDirectionUnknown:
+ return "AXTextSelectionDirectionUnknown";
+ case AXTextSelectionDirectionBeginning:
+ return "AXTextSelectionDirectionBeginning";
+ case AXTextSelectionDirectionEnd:
+ return "AXTextSelectionDirectionEnd";
+ case AXTextSelectionDirectionPrevious:
+ return "AXTextSelectionDirectionPrevious";
+ case AXTextSelectionDirectionNext:
+ return "AXTextSelectionDirectionNext";
+ case AXTextSelectionDirectionDiscontiguous:
+ return "AXTextSelectionDirectionDiscontiguous";
+ }
+
+ return "";
+}
+
+const char* ToString(AXTextSelectionGranularity granularity) {
+ switch (granularity) {
+ case AXTextSelectionGranularityUnknown:
+ return "AXTextSelectionGranularityUnknown";
+ case AXTextSelectionGranularityCharacter:
+ return "AXTextSelectionGranularityCharacter";
+ case AXTextSelectionGranularityWord:
+ return "AXTextSelectionGranularityWord";
+ case AXTextSelectionGranularityLine:
+ return "AXTextSelectionGranularityLine";
+ case AXTextSelectionGranularitySentence:
+ return "AXTextSelectionGranularitySentence";
+ case AXTextSelectionGranularityParagraph:
+ return "AXTextSelectionGranularityParagraph";
+ case AXTextSelectionGranularityPage:
+ return "AXTextSelectionGranularityPage";
+ case AXTextSelectionGranularityDocument:
+ return "AXTextSelectionGranularityDocument";
+ case AXTextSelectionGranularityAll:
+ return "AXTextSelectionGranularityAll";
+ }
+
+ return "";
+}
+
+const char* ToString(AXTextEditType type) {
+ switch (type) {
+ case AXTextEditTypeUnknown:
+ return "AXTextEditTypeUnknown";
+ case AXTextEditTypeDelete:
+ return "AXTextEditTypeDelete";
+ case AXTextEditTypeInsert:
+ return "AXTextEditTypeInsert";
+ case AXTextEditTypeTyping:
+ return "AXTextEditTypeTyping";
+ case AXTextEditTypeDictation:
+ return "AXTextEditTypeDictation";
+ case AXTextEditTypeCut:
+ return "AXTextEditTypeCut";
+ case AXTextEditTypePaste:
+ return "AXTextEditTypePaste";
+ case AXTextEditTypeAttributesChange:
+ return "AXTextEditTypeAttributesChange";
+ }
+
+ return "";
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_system_caret_win.cc b/chromium/ui/accessibility/platform/ax_system_caret_win.cc
index 4b7356abeef..39c8fa17ba6 100644
--- a/chromium/ui/accessibility/platform/ax_system_caret_win.cc
+++ b/chromium/ui/accessibility/platform/ax_system_caret_win.cc
@@ -28,7 +28,7 @@ AXSystemCaretWin::AXSystemCaretWin(gfx::AcceleratedWidget event_target)
data_.state = 0;
data_.AddState(ax::mojom::State::kInvisible);
// According to MSDN, "Edit" should be the name of the caret object.
- data_.SetName(L"Edit");
+ data_.SetName(STRING16_LITERAL("Edit"));
data_.relative_bounds.offset_container_id = -1;
if (event_target_) {
diff --git a/chromium/ui/accessibility/platform/ax_unique_id.cc b/chromium/ui/accessibility/platform/ax_unique_id.cc
index 163fcdc39e0..cfb433a1280 100644
--- a/chromium/ui/accessibility/platform/ax_unique_id.cc
+++ b/chromium/ui/accessibility/platform/ax_unique_id.cc
@@ -7,9 +7,9 @@
#include <memory>
#include <unordered_set>
+#include "base/containers/contains.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/stl_util.h"
namespace ui {
@@ -46,7 +46,7 @@ int32_t AXUniqueId::GetNextAXUniqueId(const int32_t max_id) {
const int32_t prev_id = current_id;
do {
- if (current_id == max_id) {
+ if (current_id >= max_id) {
current_id = 1;
has_wrapped = true;
} else {
diff --git a/chromium/ui/accessibility/platform/ax_unique_id_unittest.cc b/chromium/ui/accessibility/platform/ax_unique_id_unittest.cc
index d6fdb5886ed..42a722b200e 100644
--- a/chromium/ui/accessibility/platform/ax_unique_id_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_unique_id_unittest.cc
@@ -53,4 +53,22 @@ TEST(AXPlatformUniqueIdTest, UnassignedIdsAreReused) {
EXPECT_EQ(ids[kIdToReplace]->Get(), expected_id);
}
+TEST(AXPlatformUniqueIdTest, DoesCreateCorrectId) {
+ int kLargerThanMaxId = kMaxId * 2;
+ std::unique_ptr<AXUniqueId> ids[kLargerThanMaxId];
+ // Creates and releases to fill up the internal static counter.
+ for (int i = 0; i < kLargerThanMaxId; i++) {
+ ids[i] = std::make_unique<AXUniqueId>();
+ }
+ for (int i = 0; i < kLargerThanMaxId; i++) {
+ ids[i].reset(nullptr);
+ }
+ // Creates an unique id whose max value is less than the internal
+ // static counter.
+ std::unique_ptr<AXTestSmallBankUniqueId> unique_id =
+ std::make_unique<AXTestSmallBankUniqueId>();
+
+ EXPECT_LE(unique_id->Get(), kMaxId);
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/compute_attributes.cc b/chromium/ui/accessibility/platform/compute_attributes.cc
index b5adf3d3dad..63280ae9445 100644
--- a/chromium/ui/accessibility/platform/compute_attributes.cc
+++ b/chromium/ui/accessibility/platform/compute_attributes.cc
@@ -100,6 +100,13 @@ base::Optional<int32_t> ComputeAttribute(
const ui::AXPlatformNodeDelegate* delegate,
ax::mojom::IntAttribute attribute) {
base::Optional<int32_t> maybe_value = base::nullopt;
+
+ // Color-related attributes.
+ if (attribute == ax::mojom::IntAttribute::kColor)
+ return delegate->GetColor();
+ else if (attribute == ax::mojom::IntAttribute::kBackgroundColor)
+ return delegate->GetBackgroundColor();
+
// Table-related nodes.
if (delegate->IsTableCellOrHeader())
maybe_value = GetCellAttribute(delegate, attribute);
diff --git a/chromium/ui/accessibility/platform/inspect/ax_event_recorder.cc b/chromium/ui/accessibility/platform/inspect/ax_event_recorder.cc
new file mode 100644
index 00000000000..779652b39c0
--- /dev/null
+++ b/chromium/ui/accessibility/platform/inspect/ax_event_recorder.cc
@@ -0,0 +1,24 @@
+// Copyright 2021 The Chromium 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/inspect/ax_event_recorder.h"
+
+#include "base/callback_helpers.h"
+
+namespace ui {
+
+AXEventRecorder::AXEventRecorder() = default;
+AXEventRecorder::~AXEventRecorder() = default;
+
+void AXEventRecorder::StopListeningToEvents() {
+ callback_ = base::NullCallback();
+}
+
+void AXEventRecorder::OnEvent(const std::string& event) {
+ event_logs_.push_back(event);
+ if (callback_)
+ callback_.Run(event);
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/platform/inspect/ax_event_recorder.h b/chromium/ui/accessibility/platform/inspect/ax_event_recorder.h
new file mode 100644
index 00000000000..a398cf85d3d
--- /dev/null
+++ b/chromium/ui/accessibility/platform/inspect/ax_event_recorder.h
@@ -0,0 +1,73 @@
+// Copyright 2021 The Chromium 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_INSPECT_AX_EVENT_RECORDER_H_
+#define UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_EVENT_RECORDER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "ui/accessibility/ax_export.h"
+
+namespace ui {
+
+using AXEventCallback = base::RepeatingCallback<void(const std::string&)>;
+
+// Listens for native accessibility events fired by a given
+// BrowserAccessibilityManager and saves human-readable log strings for
+// each event fired to a vector. Construct an instance of this class to
+// begin listening, call GetEventLogs() to get all of the logs so far, and
+// destroy it to stop listening.
+//
+// A log string should be of the form "<event> on <node>" where <event> is
+// the name of the event fired (platform-specific) and <node> is information
+// about the accessibility node on which the event was fired, for example its
+// role and name.
+//
+// The implementation is highly platform-specific; a subclass is needed for
+// each platform does most of the work.
+//
+// As currently designed, there should only be one instance of this class.
+class AX_EXPORT AXEventRecorder {
+ public:
+ AXEventRecorder();
+ virtual ~AXEventRecorder();
+
+ // Scopes/unscopes events to a web area.
+ void SetOnlyWebEvents(bool only_web_events) {
+ only_web_events_ = only_web_events;
+ }
+
+ // Sets a callback which will be called on every event fired.
+ void ListenToEvents(AXEventCallback callback) {
+ callback_ = std::move(callback);
+ }
+
+ // Stop listenting to events.
+ void StopListeningToEvents();
+
+ // Called to ensure the event recorder has finished recording async events.
+ virtual void FlushAsyncEvents() {}
+
+ // Access the vector of human-readable event logs, one string per event.
+ const std::vector<std::string>& EventLogs() { return event_logs_; }
+
+ protected:
+ // Called by a derived class which implements platform event handling on
+ // every fired event.
+ void OnEvent(const std::string& event);
+
+ bool only_web_events_ = false;
+
+ private:
+ std::vector<std::string> event_logs_;
+ AXEventCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(AXEventRecorder);
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_EVENT_RECORDER_H_
diff --git a/chromium/ui/accessibility/platform/inspect/inspect.cc b/chromium/ui/accessibility/platform/inspect/ax_inspect.cc
index 85b9627c1e8..eaa64d20645 100644
--- a/chromium/ui/accessibility/platform/inspect/inspect.cc
+++ b/chromium/ui/accessibility/platform/inspect/ax_inspect.cc
@@ -2,10 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/accessibility/platform/inspect/inspect.h"
+#include "ui/accessibility/platform/inspect/ax_inspect.h"
namespace ui {
+std::string AXTreeSelector::AppName() const {
+ if (types & Chrome)
+ return "Chrome";
+ if (types & Chromium)
+ return "Chromium";
+ if (types & Edge)
+ return "Edge";
+ if (types & Firefox)
+ return "Firefox";
+ if (types & Safari)
+ return "Safari";
+ return "Unknown";
+}
+
AXPropertyFilter::AXPropertyFilter(const AXPropertyFilter&) = default;
AXPropertyFilter::AXPropertyFilter(const std::string& str, Type type)
diff --git a/chromium/ui/accessibility/platform/inspect/inspect.h b/chromium/ui/accessibility/platform/inspect/ax_inspect.h
index dcbb36ee4d0..a7550792c56 100644
--- a/chromium/ui/accessibility/platform/inspect/inspect.h
+++ b/chromium/ui/accessibility/platform/inspect/ax_inspect.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_INSPECT_INSPECT_H_
-#define UI_ACCESSIBILITY_PLATFORM_INSPECT_INSPECT_H_
+#ifndef UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_INSPECT_H_
+#define UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_INSPECT_H_
#include <string>
@@ -21,8 +21,9 @@ struct AX_EXPORT AXTreeSelector {
ActiveTab = 1 << 0,
Chrome = 1 << 1,
Chromium = 1 << 2,
- Firefox = 1 << 3,
- Safari = 1 << 4,
+ Edge = 1 << 3,
+ Firefox = 1 << 4,
+ Safari = 1 << 5,
};
int types{None};
std::string pattern;
@@ -32,6 +33,10 @@ struct AX_EXPORT AXTreeSelector {
: types(types), pattern(pattern) {}
bool empty() const { return types == None && pattern.empty(); }
+
+ // Returns an application name for a type if the type specifies an
+ // application.
+ std::string AppName() const;
};
// A single property filter specification. Represents a parsed string of the
@@ -51,7 +56,7 @@ struct AX_EXPORT AXTreeSelector {
// DumpAccessibilityTestBase::ParseHtmlForExtraDirectives() for more
// information.
struct AX_EXPORT AXPropertyFilter {
- enum Type { ALLOW, ALLOW_EMPTY, DENY };
+ enum Type { ALLOW, ALLOW_EMPTY, DENY, SCRIPT };
std::string match_str;
std::string property_str;
@@ -79,4 +84,4 @@ struct AX_EXPORT AXNodeFilter {
} // namespace ui
-#endif // UI_ACCESSIBILITY_PLATFORM_INSPECT_INSPECT_H_
+#endif // UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_INSPECT_H_
diff --git a/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_auralinux.cc b/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_auralinux.cc
new file mode 100644
index 00000000000..95576e9c5f1
--- /dev/null
+++ b/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_auralinux.cc
@@ -0,0 +1,443 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/platform/inspect/ax_inspect_utils_auralinux.h"
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/pattern.h"
+#include "ui/accessibility/platform/inspect/ax_inspect.h"
+
+namespace ui {
+namespace {
+
+const char kChromeTitle[] = "Google Chrome";
+const char kChromiumTitle[] = "Chromium";
+const char kFirefoxTitle[] = "Firefox";
+
+struct PlatformConstantToNameEntry {
+ int32_t value;
+ const char* name;
+};
+
+const char* GetNameForPlatformConstant(
+ const PlatformConstantToNameEntry table[],
+ size_t table_size,
+ int32_t value) {
+ for (size_t i = 0; i < table_size; ++i) {
+ auto& entry = table[i];
+ if (entry.value == value)
+ return entry.name;
+ }
+ return "<unknown>";
+}
+} // namespace
+
+#define QUOTE(X) \
+ { X, #X }
+
+#define ATSPI_CHECK_VERSION(major, minor, micro) \
+ (major) < ATSPI_MAJOR_VERSION || \
+ ((major) == ATSPI_MAJOR_VERSION && (minor) < ATSPI_MINOR_VERSION) || \
+ ((major) == ATSPI_MAJOR_VERSION && (minor) == ATSPI_MINOR_VERSION && \
+ (micro) <= ATSPI_MICRO_VERSION)
+
+#define CHECK_ATSPI_ERROR_NULLPTR(error) \
+ if (error) { \
+ LOG(ERROR) << error->message; \
+ g_clear_error(&error); \
+ return nullptr; \
+ }
+
+const char* ATSPIStateToString(AtspiStateType state) {
+ // These roles are listed in the order they are defined in the enum so that
+ // we can more easily discard ones that are too new for the version of
+ // atspi2 that we are compiling against.
+ static const PlatformConstantToNameEntry state_table[] = {
+ QUOTE(ATSPI_STATE_INVALID),
+ QUOTE(ATSPI_STATE_ACTIVE),
+ QUOTE(ATSPI_STATE_ARMED),
+ QUOTE(ATSPI_STATE_BUSY),
+ QUOTE(ATSPI_STATE_CHECKED),
+ QUOTE(ATSPI_STATE_COLLAPSED),
+ QUOTE(ATSPI_STATE_DEFUNCT),
+ QUOTE(ATSPI_STATE_EDITABLE),
+ QUOTE(ATSPI_STATE_ENABLED),
+ QUOTE(ATSPI_STATE_EXPANDABLE),
+ QUOTE(ATSPI_STATE_EXPANDED),
+ QUOTE(ATSPI_STATE_FOCUSABLE),
+ QUOTE(ATSPI_STATE_FOCUSED),
+ QUOTE(ATSPI_STATE_HAS_TOOLTIP),
+ QUOTE(ATSPI_STATE_HORIZONTAL),
+ QUOTE(ATSPI_STATE_ICONIFIED),
+ QUOTE(ATSPI_STATE_MODAL),
+ QUOTE(ATSPI_STATE_MULTI_LINE),
+ QUOTE(ATSPI_STATE_MULTISELECTABLE),
+ QUOTE(ATSPI_STATE_OPAQUE),
+ QUOTE(ATSPI_STATE_PRESSED),
+ QUOTE(ATSPI_STATE_RESIZABLE),
+ QUOTE(ATSPI_STATE_SELECTABLE),
+ QUOTE(ATSPI_STATE_SELECTED),
+ QUOTE(ATSPI_STATE_SENSITIVE),
+ QUOTE(ATSPI_STATE_SHOWING),
+ QUOTE(ATSPI_STATE_SINGLE_LINE),
+ QUOTE(ATSPI_STATE_STALE),
+ QUOTE(ATSPI_STATE_TRANSIENT),
+ QUOTE(ATSPI_STATE_VERTICAL),
+ QUOTE(ATSPI_STATE_VISIBLE),
+ QUOTE(ATSPI_STATE_MANAGES_DESCENDANTS),
+ QUOTE(ATSPI_STATE_INDETERMINATE),
+ QUOTE(ATSPI_STATE_REQUIRED),
+ QUOTE(ATSPI_STATE_TRUNCATED),
+ QUOTE(ATSPI_STATE_ANIMATED),
+ QUOTE(ATSPI_STATE_INVALID_ENTRY),
+ QUOTE(ATSPI_STATE_SUPPORTS_AUTOCOMPLETION),
+ QUOTE(ATSPI_STATE_SELECTABLE_TEXT),
+ QUOTE(ATSPI_STATE_IS_DEFAULT),
+ QUOTE(ATSPI_STATE_VISITED),
+#if ATSPI_CHECK_VERSION(2, 12, 0)
+ QUOTE(ATSPI_STATE_CHECKABLE),
+ QUOTE(ATSPI_STATE_HAS_POPUP),
+#endif
+#if ATSPI_CHECK_VERSION(2, 16, 0)
+ QUOTE(ATSPI_STATE_READ_ONLY),
+#endif
+ };
+
+ return GetNameForPlatformConstant(state_table, base::size(state_table),
+ state);
+}
+
+const char* ATSPIRoleToString(AtspiRole role) {
+ // These roles are listed in the order they are defined in the enum so that
+ // we can more easily discard ones that are too new for the version of
+ // atspi2 that we are compiling against.
+ static const PlatformConstantToNameEntry role_table[] = {
+ QUOTE(ATSPI_ROLE_INVALID),
+ QUOTE(ATSPI_ROLE_ACCELERATOR_LABEL),
+ QUOTE(ATSPI_ROLE_ALERT),
+ QUOTE(ATSPI_ROLE_ANIMATION),
+ QUOTE(ATSPI_ROLE_ARROW),
+ QUOTE(ATSPI_ROLE_CALENDAR),
+ QUOTE(ATSPI_ROLE_CANVAS),
+ QUOTE(ATSPI_ROLE_CHECK_BOX),
+ QUOTE(ATSPI_ROLE_CHECK_MENU_ITEM),
+ QUOTE(ATSPI_ROLE_COLOR_CHOOSER),
+ QUOTE(ATSPI_ROLE_COLUMN_HEADER),
+ QUOTE(ATSPI_ROLE_COMBO_BOX),
+ QUOTE(ATSPI_ROLE_DATE_EDITOR),
+ QUOTE(ATSPI_ROLE_DESKTOP_ICON),
+ QUOTE(ATSPI_ROLE_DESKTOP_FRAME),
+ QUOTE(ATSPI_ROLE_DIAL),
+ QUOTE(ATSPI_ROLE_DIALOG),
+ QUOTE(ATSPI_ROLE_DIRECTORY_PANE),
+ QUOTE(ATSPI_ROLE_DRAWING_AREA),
+ QUOTE(ATSPI_ROLE_FILE_CHOOSER),
+ QUOTE(ATSPI_ROLE_FILLER),
+ QUOTE(ATSPI_ROLE_FOCUS_TRAVERSABLE),
+ QUOTE(ATSPI_ROLE_FONT_CHOOSER),
+ QUOTE(ATSPI_ROLE_FRAME),
+ QUOTE(ATSPI_ROLE_GLASS_PANE),
+ QUOTE(ATSPI_ROLE_HTML_CONTAINER),
+ QUOTE(ATSPI_ROLE_ICON),
+ QUOTE(ATSPI_ROLE_IMAGE),
+ QUOTE(ATSPI_ROLE_INTERNAL_FRAME),
+ QUOTE(ATSPI_ROLE_LABEL),
+ QUOTE(ATSPI_ROLE_LAYERED_PANE),
+ QUOTE(ATSPI_ROLE_LIST),
+ QUOTE(ATSPI_ROLE_LIST_ITEM),
+ QUOTE(ATSPI_ROLE_MENU),
+ QUOTE(ATSPI_ROLE_MENU_BAR),
+ QUOTE(ATSPI_ROLE_MENU_ITEM),
+ QUOTE(ATSPI_ROLE_OPTION_PANE),
+ QUOTE(ATSPI_ROLE_PAGE_TAB),
+ QUOTE(ATSPI_ROLE_PAGE_TAB_LIST),
+ QUOTE(ATSPI_ROLE_PANEL),
+ QUOTE(ATSPI_ROLE_PASSWORD_TEXT),
+ QUOTE(ATSPI_ROLE_POPUP_MENU),
+ QUOTE(ATSPI_ROLE_PROGRESS_BAR),
+ QUOTE(ATSPI_ROLE_PUSH_BUTTON),
+ QUOTE(ATSPI_ROLE_RADIO_BUTTON),
+ QUOTE(ATSPI_ROLE_RADIO_MENU_ITEM),
+ QUOTE(ATSPI_ROLE_ROOT_PANE),
+ QUOTE(ATSPI_ROLE_ROW_HEADER),
+ QUOTE(ATSPI_ROLE_SCROLL_BAR),
+ QUOTE(ATSPI_ROLE_SCROLL_PANE),
+ QUOTE(ATSPI_ROLE_SEPARATOR),
+ QUOTE(ATSPI_ROLE_SLIDER),
+ QUOTE(ATSPI_ROLE_SPIN_BUTTON),
+ QUOTE(ATSPI_ROLE_SPLIT_PANE),
+ QUOTE(ATSPI_ROLE_STATUS_BAR),
+ QUOTE(ATSPI_ROLE_TABLE),
+ QUOTE(ATSPI_ROLE_TABLE_CELL),
+ QUOTE(ATSPI_ROLE_TABLE_COLUMN_HEADER),
+ QUOTE(ATSPI_ROLE_TABLE_ROW_HEADER),
+ QUOTE(ATSPI_ROLE_TEAROFF_MENU_ITEM),
+ QUOTE(ATSPI_ROLE_TERMINAL),
+ QUOTE(ATSPI_ROLE_TEXT),
+ QUOTE(ATSPI_ROLE_TOGGLE_BUTTON),
+ QUOTE(ATSPI_ROLE_TOOL_BAR),
+ QUOTE(ATSPI_ROLE_TOOL_TIP),
+ QUOTE(ATSPI_ROLE_TREE),
+ QUOTE(ATSPI_ROLE_TREE_TABLE),
+ QUOTE(ATSPI_ROLE_UNKNOWN),
+ QUOTE(ATSPI_ROLE_VIEWPORT),
+ QUOTE(ATSPI_ROLE_WINDOW),
+ QUOTE(ATSPI_ROLE_EXTENDED),
+ QUOTE(ATSPI_ROLE_HEADER),
+ QUOTE(ATSPI_ROLE_FOOTER),
+ QUOTE(ATSPI_ROLE_PARAGRAPH),
+ QUOTE(ATSPI_ROLE_RULER),
+ QUOTE(ATSPI_ROLE_APPLICATION),
+ QUOTE(ATSPI_ROLE_AUTOCOMPLETE),
+ QUOTE(ATSPI_ROLE_EDITBAR),
+ QUOTE(ATSPI_ROLE_EMBEDDED),
+ QUOTE(ATSPI_ROLE_ENTRY),
+ QUOTE(ATSPI_ROLE_CHART),
+ QUOTE(ATSPI_ROLE_CAPTION),
+ QUOTE(ATSPI_ROLE_DOCUMENT_FRAME),
+ QUOTE(ATSPI_ROLE_HEADING),
+ QUOTE(ATSPI_ROLE_PAGE),
+ QUOTE(ATSPI_ROLE_SECTION),
+ QUOTE(ATSPI_ROLE_REDUNDANT_OBJECT),
+ QUOTE(ATSPI_ROLE_FORM),
+ QUOTE(ATSPI_ROLE_LINK),
+ QUOTE(ATSPI_ROLE_INPUT_METHOD_WINDOW),
+ QUOTE(ATSPI_ROLE_TABLE_ROW),
+ QUOTE(ATSPI_ROLE_TREE_ITEM),
+ QUOTE(ATSPI_ROLE_DOCUMENT_SPREADSHEET),
+ QUOTE(ATSPI_ROLE_DOCUMENT_PRESENTATION),
+ QUOTE(ATSPI_ROLE_DOCUMENT_TEXT),
+ QUOTE(ATSPI_ROLE_DOCUMENT_WEB),
+ QUOTE(ATSPI_ROLE_DOCUMENT_EMAIL),
+ QUOTE(ATSPI_ROLE_COMMENT),
+ QUOTE(ATSPI_ROLE_LIST_BOX),
+ QUOTE(ATSPI_ROLE_GROUPING),
+ QUOTE(ATSPI_ROLE_IMAGE_MAP),
+ QUOTE(ATSPI_ROLE_NOTIFICATION),
+ QUOTE(ATSPI_ROLE_INFO_BAR),
+ QUOTE(ATSPI_ROLE_LEVEL_BAR),
+#if ATSPI_CHECK_VERSION(2, 12, 0)
+ QUOTE(ATSPI_ROLE_TITLE_BAR),
+ QUOTE(ATSPI_ROLE_BLOCK_QUOTE),
+ QUOTE(ATSPI_ROLE_AUDIO),
+ QUOTE(ATSPI_ROLE_VIDEO),
+ QUOTE(ATSPI_ROLE_DEFINITION),
+ QUOTE(ATSPI_ROLE_ARTICLE),
+ QUOTE(ATSPI_ROLE_LANDMARK),
+ QUOTE(ATSPI_ROLE_LOG),
+ QUOTE(ATSPI_ROLE_MARQUEE),
+ QUOTE(ATSPI_ROLE_MATH),
+ QUOTE(ATSPI_ROLE_RATING),
+ QUOTE(ATSPI_ROLE_TIMER),
+#endif
+#if ATSPI_CHECK_VERSION(2, 16, 0)
+ QUOTE(ATSPI_ROLE_STATIC),
+ QUOTE(ATSPI_ROLE_MATH_FRACTION),
+ QUOTE(ATSPI_ROLE_MATH_ROOT),
+ QUOTE(ATSPI_ROLE_SUBSCRIPT),
+ QUOTE(ATSPI_ROLE_SUPERSCRIPT),
+#endif
+#if ATSPI_CHECK_VERSION(2, 26, 0)
+ QUOTE(ATSPI_ROLE_DESCRIPTION_LIST),
+ QUOTE(ATSPI_ROLE_DESCRIPTION_TERM),
+ QUOTE(ATSPI_ROLE_DESCRIPTION_VALUE),
+ QUOTE(ATSPI_ROLE_FOOTNOTE),
+#endif
+ };
+
+ return GetNameForPlatformConstant(role_table, base::size(role_table), role);
+}
+
+// This is used to ensure a standard set of AtkRole name conversions between
+// different versions of ATK. Older versions may not have an implementation of
+// a new role and newer versions may have changed the name returned by
+// atk_role_get_name. This table should be kept up to date with newer ATK
+// releases.
+const char* const kRoleNames[] = {
+ "invalid", // ATK_ROLE_INVALID.
+ "accelerator label",
+ "alert",
+ "animation",
+ "arrow",
+ "calendar",
+ "canvas",
+ "check box",
+ "check menu item",
+ "color chooser",
+ "column header",
+ "combo box",
+ "dateeditor",
+ "desktop icon",
+ "desktop frame",
+ "dial",
+ "dialog",
+ "directory pane",
+ "drawing area",
+ "file chooser",
+ "filler",
+ "fontchooser",
+ "frame",
+ "glass pane",
+ "html container",
+ "icon",
+ "image",
+ "internal frame",
+ "label",
+ "layered pane",
+ "list",
+ "list item",
+ "menu",
+ "menu bar",
+ "menu item",
+ "option pane",
+ "page tab",
+ "page tab list",
+ "panel",
+ "password text",
+ "popup menu",
+ "progress bar",
+ "push button",
+ "radio button",
+ "radio menu item",
+ "root pane",
+ "row header",
+ "scroll bar",
+ "scroll pane",
+ "separator",
+ "slider",
+ "split pane",
+ "spin button",
+ "statusbar",
+ "table",
+ "table cell",
+ "table column header",
+ "table row header",
+ "tear off menu item",
+ "terminal",
+ "text",
+ "toggle button",
+ "tool bar",
+ "tool tip",
+ "tree",
+ "tree table",
+ "unknown",
+ "viewport",
+ "window",
+ "header",
+ "footer",
+ "paragraph",
+ "ruler",
+ "application",
+ "autocomplete",
+ "edit bar",
+ "embedded component",
+ "entry",
+ "chart",
+ "caption",
+ "document frame",
+ "heading",
+ "page",
+ "section",
+ "redundant object",
+ "form",
+ "link",
+ "input method window",
+ "table row",
+ "tree item",
+ "document spreadsheet",
+ "document presentation",
+ "document text",
+ "document web",
+ "document email",
+ "comment",
+ "list box",
+ "grouping",
+ "image map",
+ "notification",
+ "info bar",
+ "level bar",
+ "title bar",
+ "block quote",
+ "audio",
+ "video",
+ "definition",
+ "article",
+ "landmark",
+ "log",
+ "marquee",
+ "math",
+ "rating",
+ "timer",
+ "description list",
+ "description term",
+ "description value",
+ "static",
+ "math fraction",
+ "math root",
+ "subscript",
+ "superscript",
+ "footnote", // ATK_ROLE_FOOTNOTE = 122.
+ "content deletion", // ATK_ROLE_CONTENT_DELETION = 123.
+ "content insertion", // ATK_ROLE_CONTENT_DELETION = 124.
+};
+
+const char* AtkRoleToString(AtkRole role) {
+ if (role < G_N_ELEMENTS(kRoleNames))
+ return kRoleNames[role];
+ return "<unknown AtkRole>";
+}
+
+AtspiAccessible* FindAccessible(const AXTreeSelector& selector) {
+ std::string title;
+ if (selector.types & AXTreeSelector::Chrome) {
+ title = kChromeTitle;
+ } else if (selector.types & AXTreeSelector::Chromium) {
+ title = kChromiumTitle;
+ } else if (selector.types & AXTreeSelector::Firefox) {
+ title = kFirefoxTitle;
+ }
+
+ // AT-SPI2 always expects the first parameter to this call to be zero.
+ AtspiAccessible* desktop = atspi_get_desktop(0);
+ CHECK(desktop);
+
+ GError* error = nullptr;
+ int child_count = atspi_accessible_get_child_count(desktop, &error);
+ CHECK_ATSPI_ERROR_NULLPTR(error)
+
+ std::vector<std::pair<std::string, AtspiAccessible*>> matched_children;
+ for (int i = 0; i < child_count; i++) {
+ AtspiAccessible* child =
+ atspi_accessible_get_child_at_index(desktop, i, &error);
+ CHECK_ATSPI_ERROR_NULLPTR(error)
+
+ char* name = atspi_accessible_get_name(child, &error);
+ if (!error && name) {
+ if ((!title.empty() && title == name) ||
+ base::MatchPattern(name, selector.pattern)) {
+ matched_children.emplace_back(name, child);
+ }
+ }
+ free(name);
+ }
+
+ if (matched_children.size() == 0) {
+ LOG(ERROR) << "No application matched.";
+ return nullptr;
+ }
+
+ if (matched_children.size() > 1) {
+ LOG(ERROR) << "Matched more than one application. "
+ << "Try to make a more specific pattern.";
+ for (auto& match : matched_children) {
+ LOG(ERROR) << " * " << match.first;
+ }
+ return nullptr;
+ }
+
+ return matched_children[0].second;
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_auralinux.h b/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_auralinux.h
new file mode 100644
index 00000000000..90e678f51e8
--- /dev/null
+++ b/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_auralinux.h
@@ -0,0 +1,23 @@
+// 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_ACCESSIBILITY_PLATFORM_INSPECT_AX_INSPECT_UTILS_AURALINUX_H_
+#define UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_INSPECT_UTILS_AURALINUX_H_
+
+#include <atk/atk.h>
+#include <atspi/atspi.h>
+
+#include "ui/accessibility/ax_export.h"
+
+namespace ui {
+struct AXTreeSelector;
+
+AX_EXPORT const char* ATSPIStateToString(AtspiStateType state);
+AX_EXPORT const char* ATSPIRoleToString(AtspiRole role);
+AX_EXPORT const char* AtkRoleToString(AtkRole role);
+AX_EXPORT AtspiAccessible* FindAccessible(const AXTreeSelector&);
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_INSPECT_UTILS_AURALINUX_H_
diff --git a/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_win.cc b/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_win.cc
new file mode 100644
index 00000000000..6d74b176c90
--- /dev/null
+++ b/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_win.cc
@@ -0,0 +1,748 @@
+// 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/accessibility/platform/inspect/ax_inspect_utils_win.h"
+
+#include <oleacc.h>
+#include <uiautomation.h>
+
+#include <map>
+#include <string>
+
+#include "base/memory/singleton.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/iaccessible2/ia2_api_all.h"
+#include "ui/accessibility/platform/inspect/ax_inspect.h"
+
+namespace ui {
+namespace {
+
+const wchar_t kChromeTitle[] = L"Google Chrome";
+const wchar_t kChromiumTitle[] = L"Chromium";
+const wchar_t kEdgeTitle[] = L"Edge";
+const wchar_t kFirefoxTitle[] = L"Firefox";
+
+struct PlatformConstantToNameEntry {
+ int32_t value;
+ const char* name;
+};
+
+std::wstring GetNameForPlatformConstant(
+ const PlatformConstantToNameEntry table[],
+ size_t table_size,
+ int32_t value) {
+ for (size_t i = 0; i < table_size; ++i) {
+ auto& entry = table[i];
+ if (entry.value == value)
+ return base::ASCIIToWide(entry.name);
+ }
+ return std::wstring();
+}
+
+struct HwndWithProcId {
+ HwndWithProcId(const base::ProcessId id) : pid(id), hwnd(nullptr) {}
+ const base::ProcessId pid;
+ HWND hwnd;
+};
+
+BOOL CALLBACK EnumWindowsProcPid(HWND hwnd, LPARAM lParam) {
+ DWORD process_id;
+ GetWindowThreadProcessId(hwnd, &process_id);
+ HwndWithProcId* hwnd_with_proc_id = (HwndWithProcId*)lParam;
+ if (process_id == static_cast<DWORD>(hwnd_with_proc_id->pid)) {
+ hwnd_with_proc_id->hwnd = hwnd;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+} // namespace
+
+#define QUOTE(X) \
+ { X, #X }
+
+AX_EXPORT std::wstring IAccessibleRoleToString(int32_t ia_role) {
+ // MSAA / IAccessible roles. Each one of these is also a valid
+ // IAccessible2 role.
+ static const PlatformConstantToNameEntry ia_table[] = {
+ QUOTE(ROLE_SYSTEM_ALERT), QUOTE(ROLE_SYSTEM_ANIMATION),
+ QUOTE(ROLE_SYSTEM_APPLICATION), QUOTE(ROLE_SYSTEM_BORDER),
+ QUOTE(ROLE_SYSTEM_BUTTONDROPDOWN), QUOTE(ROLE_SYSTEM_BUTTONDROPDOWNGRID),
+ QUOTE(ROLE_SYSTEM_BUTTONMENU), QUOTE(ROLE_SYSTEM_CARET),
+ QUOTE(ROLE_SYSTEM_CELL), QUOTE(ROLE_SYSTEM_CHARACTER),
+ QUOTE(ROLE_SYSTEM_CHART), QUOTE(ROLE_SYSTEM_CHECKBUTTON),
+ QUOTE(ROLE_SYSTEM_CLIENT), QUOTE(ROLE_SYSTEM_CLOCK),
+ QUOTE(ROLE_SYSTEM_COLUMN), QUOTE(ROLE_SYSTEM_COLUMNHEADER),
+ QUOTE(ROLE_SYSTEM_COMBOBOX), QUOTE(ROLE_SYSTEM_CURSOR),
+ QUOTE(ROLE_SYSTEM_DIAGRAM), QUOTE(ROLE_SYSTEM_DIAL),
+ QUOTE(ROLE_SYSTEM_DIALOG), QUOTE(ROLE_SYSTEM_DOCUMENT),
+ QUOTE(ROLE_SYSTEM_DROPLIST), QUOTE(ROLE_SYSTEM_EQUATION),
+ QUOTE(ROLE_SYSTEM_GRAPHIC), QUOTE(ROLE_SYSTEM_GRIP),
+ QUOTE(ROLE_SYSTEM_GROUPING), QUOTE(ROLE_SYSTEM_HELPBALLOON),
+ QUOTE(ROLE_SYSTEM_HOTKEYFIELD), QUOTE(ROLE_SYSTEM_INDICATOR),
+ QUOTE(ROLE_SYSTEM_IPADDRESS), QUOTE(ROLE_SYSTEM_LINK),
+ QUOTE(ROLE_SYSTEM_LIST), QUOTE(ROLE_SYSTEM_LISTITEM),
+ QUOTE(ROLE_SYSTEM_MENUBAR), QUOTE(ROLE_SYSTEM_MENUITEM),
+ QUOTE(ROLE_SYSTEM_MENUPOPUP), QUOTE(ROLE_SYSTEM_OUTLINE),
+ QUOTE(ROLE_SYSTEM_OUTLINEBUTTON), QUOTE(ROLE_SYSTEM_OUTLINEITEM),
+ QUOTE(ROLE_SYSTEM_PAGETAB), QUOTE(ROLE_SYSTEM_PAGETABLIST),
+ QUOTE(ROLE_SYSTEM_PANE), QUOTE(ROLE_SYSTEM_PROGRESSBAR),
+ QUOTE(ROLE_SYSTEM_PROPERTYPAGE), QUOTE(ROLE_SYSTEM_PUSHBUTTON),
+ QUOTE(ROLE_SYSTEM_RADIOBUTTON), QUOTE(ROLE_SYSTEM_ROW),
+ QUOTE(ROLE_SYSTEM_ROWHEADER), QUOTE(ROLE_SYSTEM_SCROLLBAR),
+ QUOTE(ROLE_SYSTEM_SEPARATOR), QUOTE(ROLE_SYSTEM_SLIDER),
+ QUOTE(ROLE_SYSTEM_SOUND), QUOTE(ROLE_SYSTEM_SPINBUTTON),
+ QUOTE(ROLE_SYSTEM_SPLITBUTTON), QUOTE(ROLE_SYSTEM_STATICTEXT),
+ QUOTE(ROLE_SYSTEM_STATUSBAR), QUOTE(ROLE_SYSTEM_TABLE),
+ QUOTE(ROLE_SYSTEM_TEXT), QUOTE(ROLE_SYSTEM_TITLEBAR),
+ QUOTE(ROLE_SYSTEM_TOOLBAR), QUOTE(ROLE_SYSTEM_TOOLTIP),
+ QUOTE(ROLE_SYSTEM_WHITESPACE), QUOTE(ROLE_SYSTEM_WINDOW),
+ };
+
+ return GetNameForPlatformConstant(ia_table, base::size(ia_table), ia_role);
+}
+
+AX_EXPORT std::wstring IAccessible2RoleToString(int32_t ia2_role) {
+ std::wstring result = IAccessibleRoleToString(ia2_role);
+ if (!result.empty())
+ return result;
+
+ static const PlatformConstantToNameEntry ia2_table[] = {
+ QUOTE(IA2_ROLE_CANVAS),
+ QUOTE(IA2_ROLE_CAPTION),
+ QUOTE(IA2_ROLE_CHECK_MENU_ITEM),
+ QUOTE(IA2_ROLE_COLOR_CHOOSER),
+ QUOTE(IA2_ROLE_DATE_EDITOR),
+ QUOTE(IA2_ROLE_DESKTOP_ICON),
+ QUOTE(IA2_ROLE_DESKTOP_PANE),
+ QUOTE(IA2_ROLE_DIRECTORY_PANE),
+ QUOTE(IA2_ROLE_EDITBAR),
+ QUOTE(IA2_ROLE_EMBEDDED_OBJECT),
+ QUOTE(IA2_ROLE_ENDNOTE),
+ QUOTE(IA2_ROLE_FILE_CHOOSER),
+ QUOTE(IA2_ROLE_FONT_CHOOSER),
+ QUOTE(IA2_ROLE_FOOTER),
+ QUOTE(IA2_ROLE_FOOTNOTE),
+ QUOTE(IA2_ROLE_FORM),
+ QUOTE(IA2_ROLE_FRAME),
+ QUOTE(IA2_ROLE_GLASS_PANE),
+ QUOTE(IA2_ROLE_HEADER),
+ QUOTE(IA2_ROLE_HEADING),
+ QUOTE(IA2_ROLE_ICON),
+ QUOTE(IA2_ROLE_IMAGE_MAP),
+ QUOTE(IA2_ROLE_INPUT_METHOD_WINDOW),
+ QUOTE(IA2_ROLE_INTERNAL_FRAME),
+ QUOTE(IA2_ROLE_LABEL),
+ QUOTE(IA2_ROLE_LAYERED_PANE),
+ QUOTE(IA2_ROLE_NOTE),
+ QUOTE(IA2_ROLE_OPTION_PANE),
+ QUOTE(IA2_ROLE_PAGE),
+ QUOTE(IA2_ROLE_PARAGRAPH),
+ QUOTE(IA2_ROLE_RADIO_MENU_ITEM),
+ QUOTE(IA2_ROLE_REDUNDANT_OBJECT),
+ QUOTE(IA2_ROLE_ROOT_PANE),
+ QUOTE(IA2_ROLE_RULER),
+ QUOTE(IA2_ROLE_SCROLL_PANE),
+ QUOTE(IA2_ROLE_SECTION),
+ QUOTE(IA2_ROLE_SHAPE),
+ QUOTE(IA2_ROLE_SPLIT_PANE),
+ QUOTE(IA2_ROLE_TEAR_OFF_MENU),
+ QUOTE(IA2_ROLE_TERMINAL),
+ QUOTE(IA2_ROLE_TEXT_FRAME),
+ QUOTE(IA2_ROLE_TOGGLE_BUTTON),
+ QUOTE(IA2_ROLE_UNKNOWN),
+ QUOTE(IA2_ROLE_VIEW_PORT),
+ QUOTE(IA2_ROLE_COMPLEMENTARY_CONTENT),
+ QUOTE(IA2_ROLE_LANDMARK),
+ QUOTE(IA2_ROLE_LEVEL_BAR),
+ QUOTE(IA2_ROLE_CONTENT_DELETION),
+ QUOTE(IA2_ROLE_CONTENT_INSERTION),
+ QUOTE(IA2_ROLE_BLOCK_QUOTE),
+ QUOTE(IA2_ROLE_MARK),
+ QUOTE(IA2_ROLE_SUGGESTION),
+ QUOTE(IA2_ROLE_COMMENT),
+ };
+
+ return GetNameForPlatformConstant(ia2_table, base::size(ia2_table), ia2_role);
+}
+
+AX_EXPORT std::wstring AccessibilityEventToString(int32_t event) {
+ static const PlatformConstantToNameEntry event_table[] = {
+ QUOTE(EVENT_OBJECT_CREATE),
+ QUOTE(EVENT_OBJECT_DESTROY),
+ QUOTE(EVENT_OBJECT_SHOW),
+ QUOTE(EVENT_OBJECT_HIDE),
+ QUOTE(EVENT_OBJECT_REORDER),
+ QUOTE(EVENT_OBJECT_FOCUS),
+ QUOTE(EVENT_OBJECT_SELECTION),
+ QUOTE(EVENT_OBJECT_SELECTIONADD),
+ QUOTE(EVENT_OBJECT_SELECTIONREMOVE),
+ QUOTE(EVENT_OBJECT_SELECTIONWITHIN),
+ QUOTE(EVENT_OBJECT_STATECHANGE),
+ QUOTE(EVENT_OBJECT_LOCATIONCHANGE),
+ QUOTE(EVENT_OBJECT_NAMECHANGE),
+ QUOTE(EVENT_OBJECT_DESCRIPTIONCHANGE),
+ QUOTE(EVENT_OBJECT_VALUECHANGE),
+ QUOTE(EVENT_OBJECT_PARENTCHANGE),
+ QUOTE(EVENT_OBJECT_HELPCHANGE),
+ QUOTE(EVENT_OBJECT_DEFACTIONCHANGE),
+ QUOTE(EVENT_OBJECT_ACCELERATORCHANGE),
+ QUOTE(EVENT_OBJECT_INVOKED),
+ QUOTE(EVENT_OBJECT_TEXTSELECTIONCHANGED),
+ QUOTE(EVENT_OBJECT_CONTENTSCROLLED),
+ QUOTE(EVENT_OBJECT_LIVEREGIONCHANGED),
+ QUOTE(EVENT_OBJECT_HOSTEDOBJECTSINVALIDATED),
+ QUOTE(EVENT_OBJECT_DRAGSTART),
+ QUOTE(EVENT_OBJECT_DRAGCANCEL),
+ QUOTE(EVENT_OBJECT_DRAGCOMPLETE),
+ QUOTE(EVENT_OBJECT_DRAGENTER),
+ QUOTE(EVENT_OBJECT_DRAGLEAVE),
+ QUOTE(EVENT_OBJECT_DRAGDROPPED),
+ QUOTE(EVENT_SYSTEM_ALERT),
+ QUOTE(EVENT_SYSTEM_MENUPOPUPSTART),
+ QUOTE(EVENT_SYSTEM_MENUPOPUPEND),
+ QUOTE(EVENT_SYSTEM_SCROLLINGSTART),
+ QUOTE(EVENT_SYSTEM_SCROLLINGEND),
+ QUOTE(IA2_EVENT_ACTION_CHANGED),
+ QUOTE(IA2_EVENT_ACTIVE_DESCENDANT_CHANGED),
+ QUOTE(IA2_EVENT_DOCUMENT_ATTRIBUTE_CHANGED),
+ QUOTE(IA2_EVENT_DOCUMENT_CONTENT_CHANGED),
+ QUOTE(IA2_EVENT_DOCUMENT_LOAD_COMPLETE),
+ QUOTE(IA2_EVENT_DOCUMENT_LOAD_STOPPED),
+ QUOTE(IA2_EVENT_DOCUMENT_RELOAD),
+ QUOTE(IA2_EVENT_HYPERLINK_END_INDEX_CHANGED),
+ QUOTE(IA2_EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED),
+ QUOTE(IA2_EVENT_HYPERLINK_SELECTED_LINK_CHANGED),
+ QUOTE(IA2_EVENT_HYPERTEXT_LINK_ACTIVATED),
+ QUOTE(IA2_EVENT_HYPERTEXT_LINK_SELECTED),
+ QUOTE(IA2_EVENT_HYPERLINK_START_INDEX_CHANGED),
+ QUOTE(IA2_EVENT_HYPERTEXT_CHANGED),
+ QUOTE(IA2_EVENT_HYPERTEXT_NLINKS_CHANGED),
+ QUOTE(IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED),
+ QUOTE(IA2_EVENT_PAGE_CHANGED),
+ QUOTE(IA2_EVENT_SECTION_CHANGED),
+ QUOTE(IA2_EVENT_TABLE_CAPTION_CHANGED),
+ QUOTE(IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED),
+ QUOTE(IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED),
+ QUOTE(IA2_EVENT_TABLE_MODEL_CHANGED),
+ QUOTE(IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED),
+ QUOTE(IA2_EVENT_TABLE_ROW_HEADER_CHANGED),
+ QUOTE(IA2_EVENT_TABLE_SUMMARY_CHANGED),
+ QUOTE(IA2_EVENT_TEXT_ATTRIBUTE_CHANGED),
+ QUOTE(IA2_EVENT_TEXT_CARET_MOVED),
+ QUOTE(IA2_EVENT_TEXT_CHANGED),
+ QUOTE(IA2_EVENT_TEXT_COLUMN_CHANGED),
+ QUOTE(IA2_EVENT_TEXT_INSERTED),
+ QUOTE(IA2_EVENT_TEXT_REMOVED),
+ QUOTE(IA2_EVENT_TEXT_UPDATED),
+ QUOTE(IA2_EVENT_TEXT_SELECTION_CHANGED),
+ QUOTE(IA2_EVENT_VISIBLE_DATA_CHANGED),
+ QUOTE(IA2_EVENT_ROLE_CHANGED),
+ };
+
+ return GetNameForPlatformConstant(event_table, base::size(event_table),
+ event);
+}
+
+void IAccessibleStateToStringVector(int32_t ia_state,
+ std::vector<std::wstring>* result) {
+#define QUOTE_STATE(X) \
+ { STATE_SYSTEM_##X, #X }
+ // MSAA / IAccessible states. Unlike roles, these are not also IA2 states.
+ //
+ // Note: for historical reasons these are in numerical order rather than
+ // alphabetical order. Changing the order would change the order in which
+ // the states are printed, which would affect a bunch of tests.
+ static const PlatformConstantToNameEntry ia_table[] = {
+ QUOTE_STATE(UNAVAILABLE), QUOTE_STATE(SELECTED),
+ QUOTE_STATE(FOCUSED), QUOTE_STATE(PRESSED),
+ QUOTE_STATE(CHECKED), QUOTE_STATE(MIXED),
+ QUOTE_STATE(READONLY), QUOTE_STATE(HOTTRACKED),
+ QUOTE_STATE(DEFAULT), QUOTE_STATE(EXPANDED),
+ QUOTE_STATE(COLLAPSED), QUOTE_STATE(BUSY),
+ QUOTE_STATE(FLOATING), QUOTE_STATE(MARQUEED),
+ QUOTE_STATE(ANIMATED), QUOTE_STATE(INVISIBLE),
+ QUOTE_STATE(OFFSCREEN), QUOTE_STATE(SIZEABLE),
+ QUOTE_STATE(MOVEABLE), QUOTE_STATE(SELFVOICING),
+ QUOTE_STATE(FOCUSABLE), QUOTE_STATE(SELECTABLE),
+ QUOTE_STATE(LINKED), QUOTE_STATE(TRAVERSED),
+ QUOTE_STATE(MULTISELECTABLE), QUOTE_STATE(EXTSELECTABLE),
+ QUOTE_STATE(ALERT_LOW), QUOTE_STATE(ALERT_MEDIUM),
+ QUOTE_STATE(ALERT_HIGH), QUOTE_STATE(PROTECTED),
+ QUOTE_STATE(HASPOPUP),
+ };
+ for (auto& entry : ia_table) {
+ if (entry.value & ia_state)
+ result->push_back(base::ASCIIToWide(entry.name));
+ }
+}
+
+std::wstring IAccessibleStateToString(int32_t ia_state) {
+ std::vector<std::wstring> strings;
+ IAccessibleStateToStringVector(ia_state, &strings);
+ return base::JoinString(strings, L",");
+}
+
+void IAccessible2StateToStringVector(int32_t ia2_state,
+ std::vector<std::wstring>* result) {
+ // Note: for historical reasons these are in numerical order rather than
+ // alphabetical order. Changing the order would change the order in which
+ // the states are printed, which would affect a bunch of tests.
+ static const PlatformConstantToNameEntry ia2_table[] = {
+ QUOTE(IA2_STATE_ACTIVE),
+ QUOTE(IA2_STATE_ARMED),
+ QUOTE(IA2_STATE_CHECKABLE),
+ QUOTE(IA2_STATE_DEFUNCT),
+ QUOTE(IA2_STATE_EDITABLE),
+ QUOTE(IA2_STATE_HORIZONTAL),
+ QUOTE(IA2_STATE_ICONIFIED),
+ QUOTE(IA2_STATE_INVALID_ENTRY),
+ QUOTE(IA2_STATE_MANAGES_DESCENDANTS),
+ QUOTE(IA2_STATE_MODAL),
+ QUOTE(IA2_STATE_MULTI_LINE),
+ QUOTE(IA2_STATE_REQUIRED),
+ QUOTE(IA2_STATE_SELECTABLE_TEXT),
+ QUOTE(IA2_STATE_SINGLE_LINE),
+ QUOTE(IA2_STATE_STALE),
+ QUOTE(IA2_STATE_SUPPORTS_AUTOCOMPLETION),
+ QUOTE(IA2_STATE_TRANSIENT),
+ QUOTE(IA2_STATE_VERTICAL),
+ // Untested states include those that would be repeated on nearly
+ // every node or would vary based on window size.
+ // QUOTE(IA2_STATE_OPAQUE) // Untested.
+ };
+
+ for (auto& entry : ia2_table) {
+ if (entry.value & ia2_state)
+ result->push_back(base::ASCIIToWide(entry.name));
+ }
+}
+
+std::wstring IAccessible2StateToString(int32_t ia2_state) {
+ std::vector<std::wstring> strings;
+ IAccessible2StateToStringVector(ia2_state, &strings);
+ return base::JoinString(strings, L",");
+}
+
+AX_EXPORT std::wstring UiaIdentifierToString(int32_t identifier) {
+ static const PlatformConstantToNameEntry id_table[] = {
+ // Patterns
+ QUOTE(UIA_InvokePatternId),
+ QUOTE(UIA_SelectionPatternId),
+ QUOTE(UIA_ValuePatternId),
+ QUOTE(UIA_RangeValuePatternId),
+ QUOTE(UIA_ScrollPatternId),
+ QUOTE(UIA_ExpandCollapsePatternId),
+ QUOTE(UIA_GridPatternId),
+ QUOTE(UIA_GridItemPatternId),
+ QUOTE(UIA_MultipleViewPatternId),
+ QUOTE(UIA_WindowPatternId),
+ QUOTE(UIA_SelectionItemPatternId),
+ QUOTE(UIA_DockPatternId),
+ QUOTE(UIA_TablePatternId),
+ QUOTE(UIA_TableItemPatternId),
+ QUOTE(UIA_TextPatternId),
+ QUOTE(UIA_TogglePatternId),
+ QUOTE(UIA_TransformPatternId),
+ QUOTE(UIA_ScrollItemPatternId),
+ QUOTE(UIA_LegacyIAccessiblePatternId),
+ QUOTE(UIA_ItemContainerPatternId),
+ QUOTE(UIA_VirtualizedItemPatternId),
+ QUOTE(UIA_SynchronizedInputPatternId),
+ QUOTE(UIA_ObjectModelPatternId),
+ QUOTE(UIA_AnnotationPatternId),
+ QUOTE(UIA_TextPattern2Id),
+ QUOTE(UIA_StylesPatternId),
+ QUOTE(UIA_SpreadsheetPatternId),
+ QUOTE(UIA_SpreadsheetItemPatternId),
+ QUOTE(UIA_TransformPattern2Id),
+ QUOTE(UIA_TextChildPatternId),
+ QUOTE(UIA_DragPatternId),
+ QUOTE(UIA_DropTargetPatternId),
+ QUOTE(UIA_TextEditPatternId),
+ QUOTE(UIA_CustomNavigationPatternId),
+ QUOTE(UIA_SelectionPattern2Id),
+ // Events
+ QUOTE(UIA_ToolTipOpenedEventId),
+ QUOTE(UIA_ToolTipClosedEventId),
+ QUOTE(UIA_StructureChangedEventId),
+ QUOTE(UIA_MenuOpenedEventId),
+ QUOTE(UIA_AutomationPropertyChangedEventId),
+ QUOTE(UIA_AutomationFocusChangedEventId),
+ QUOTE(UIA_AsyncContentLoadedEventId),
+ QUOTE(UIA_MenuClosedEventId),
+ QUOTE(UIA_LayoutInvalidatedEventId),
+ QUOTE(UIA_Invoke_InvokedEventId),
+ QUOTE(UIA_SelectionItem_ElementAddedToSelectionEventId),
+ QUOTE(UIA_SelectionItem_ElementRemovedFromSelectionEventId),
+ QUOTE(UIA_SelectionItem_ElementSelectedEventId),
+ QUOTE(UIA_Selection_InvalidatedEventId),
+ QUOTE(UIA_Text_TextSelectionChangedEventId),
+ QUOTE(UIA_Text_TextChangedEventId),
+ QUOTE(UIA_Window_WindowOpenedEventId),
+ QUOTE(UIA_Window_WindowClosedEventId),
+ QUOTE(UIA_MenuModeStartEventId),
+ QUOTE(UIA_MenuModeEndEventId),
+ QUOTE(UIA_InputReachedTargetEventId),
+ QUOTE(UIA_InputReachedOtherElementEventId),
+ QUOTE(UIA_InputDiscardedEventId),
+ QUOTE(UIA_SystemAlertEventId),
+ QUOTE(UIA_LiveRegionChangedEventId),
+ QUOTE(UIA_HostedFragmentRootsInvalidatedEventId),
+ QUOTE(UIA_Drag_DragStartEventId),
+ QUOTE(UIA_Drag_DragCancelEventId),
+ QUOTE(UIA_Drag_DragCompleteEventId),
+ QUOTE(UIA_DropTarget_DragEnterEventId),
+ QUOTE(UIA_DropTarget_DragLeaveEventId),
+ QUOTE(UIA_DropTarget_DroppedEventId),
+ QUOTE(UIA_TextEdit_TextChangedEventId),
+ QUOTE(UIA_TextEdit_ConversionTargetChangedEventId),
+ QUOTE(UIA_ChangesEventId),
+ QUOTE(UIA_NotificationEventId),
+ // Properties
+ QUOTE(UIA_RuntimeIdPropertyId),
+ QUOTE(UIA_BoundingRectanglePropertyId),
+ QUOTE(UIA_ProcessIdPropertyId),
+ QUOTE(UIA_ControlTypePropertyId),
+ QUOTE(UIA_LocalizedControlTypePropertyId),
+ QUOTE(UIA_NamePropertyId),
+ QUOTE(UIA_AcceleratorKeyPropertyId),
+ QUOTE(UIA_AccessKeyPropertyId),
+ QUOTE(UIA_HasKeyboardFocusPropertyId),
+ QUOTE(UIA_IsKeyboardFocusablePropertyId),
+ QUOTE(UIA_IsEnabledPropertyId),
+ QUOTE(UIA_AutomationIdPropertyId),
+ QUOTE(UIA_ClassNamePropertyId),
+ QUOTE(UIA_HelpTextPropertyId),
+ QUOTE(UIA_ClickablePointPropertyId),
+ QUOTE(UIA_CulturePropertyId),
+ QUOTE(UIA_IsControlElementPropertyId),
+ QUOTE(UIA_IsContentElementPropertyId),
+ QUOTE(UIA_LabeledByPropertyId),
+ QUOTE(UIA_IsPasswordPropertyId),
+ QUOTE(UIA_NativeWindowHandlePropertyId),
+ QUOTE(UIA_ItemTypePropertyId),
+ QUOTE(UIA_IsOffscreenPropertyId),
+ QUOTE(UIA_OrientationPropertyId),
+ QUOTE(UIA_FrameworkIdPropertyId),
+ QUOTE(UIA_IsRequiredForFormPropertyId),
+ QUOTE(UIA_ItemStatusPropertyId),
+ QUOTE(UIA_IsDockPatternAvailablePropertyId),
+ QUOTE(UIA_IsExpandCollapsePatternAvailablePropertyId),
+ QUOTE(UIA_IsGridItemPatternAvailablePropertyId),
+ QUOTE(UIA_IsGridPatternAvailablePropertyId),
+ QUOTE(UIA_IsInvokePatternAvailablePropertyId),
+ QUOTE(UIA_IsMultipleViewPatternAvailablePropertyId),
+ QUOTE(UIA_IsRangeValuePatternAvailablePropertyId),
+ QUOTE(UIA_IsScrollPatternAvailablePropertyId),
+ QUOTE(UIA_IsScrollItemPatternAvailablePropertyId),
+ QUOTE(UIA_IsSelectionItemPatternAvailablePropertyId),
+ QUOTE(UIA_IsSelectionPatternAvailablePropertyId),
+ QUOTE(UIA_IsTablePatternAvailablePropertyId),
+ QUOTE(UIA_IsTableItemPatternAvailablePropertyId),
+ QUOTE(UIA_IsTextPatternAvailablePropertyId),
+ QUOTE(UIA_IsTogglePatternAvailablePropertyId),
+ QUOTE(UIA_IsTransformPatternAvailablePropertyId),
+ QUOTE(UIA_IsValuePatternAvailablePropertyId),
+ QUOTE(UIA_IsWindowPatternAvailablePropertyId),
+ QUOTE(UIA_ValueValuePropertyId),
+ QUOTE(UIA_ValueIsReadOnlyPropertyId),
+ QUOTE(UIA_RangeValueValuePropertyId),
+ QUOTE(UIA_RangeValueIsReadOnlyPropertyId),
+ QUOTE(UIA_RangeValueMinimumPropertyId),
+ QUOTE(UIA_RangeValueMaximumPropertyId),
+ QUOTE(UIA_RangeValueLargeChangePropertyId),
+ QUOTE(UIA_RangeValueSmallChangePropertyId),
+ QUOTE(UIA_ScrollHorizontalScrollPercentPropertyId),
+ QUOTE(UIA_ScrollHorizontalViewSizePropertyId),
+ QUOTE(UIA_ScrollVerticalScrollPercentPropertyId),
+ QUOTE(UIA_ScrollVerticalViewSizePropertyId),
+ QUOTE(UIA_ScrollHorizontallyScrollablePropertyId),
+ QUOTE(UIA_ScrollVerticallyScrollablePropertyId),
+ QUOTE(UIA_SelectionSelectionPropertyId),
+ QUOTE(UIA_SelectionCanSelectMultiplePropertyId),
+ QUOTE(UIA_SelectionIsSelectionRequiredPropertyId),
+ QUOTE(UIA_GridRowCountPropertyId),
+ QUOTE(UIA_GridColumnCountPropertyId),
+ QUOTE(UIA_GridItemRowPropertyId),
+ QUOTE(UIA_GridItemColumnPropertyId),
+ QUOTE(UIA_GridItemRowSpanPropertyId),
+ QUOTE(UIA_GridItemColumnSpanPropertyId),
+ QUOTE(UIA_GridItemContainingGridPropertyId),
+ QUOTE(UIA_DockDockPositionPropertyId),
+ QUOTE(UIA_ExpandCollapseExpandCollapseStatePropertyId),
+ QUOTE(UIA_MultipleViewCurrentViewPropertyId),
+ QUOTE(UIA_MultipleViewSupportedViewsPropertyId),
+ QUOTE(UIA_WindowCanMaximizePropertyId),
+ QUOTE(UIA_WindowCanMinimizePropertyId),
+ QUOTE(UIA_WindowWindowVisualStatePropertyId),
+ QUOTE(UIA_WindowWindowInteractionStatePropertyId),
+ QUOTE(UIA_WindowIsModalPropertyId),
+ QUOTE(UIA_WindowIsTopmostPropertyId),
+ QUOTE(UIA_SelectionItemIsSelectedPropertyId),
+ QUOTE(UIA_SelectionItemSelectionContainerPropertyId),
+ QUOTE(UIA_TableRowHeadersPropertyId),
+ QUOTE(UIA_TableColumnHeadersPropertyId),
+ QUOTE(UIA_TableRowOrColumnMajorPropertyId),
+ QUOTE(UIA_TableItemRowHeaderItemsPropertyId),
+ QUOTE(UIA_TableItemColumnHeaderItemsPropertyId),
+ QUOTE(UIA_ToggleToggleStatePropertyId),
+ QUOTE(UIA_TransformCanMovePropertyId),
+ QUOTE(UIA_TransformCanResizePropertyId),
+ QUOTE(UIA_TransformCanRotatePropertyId),
+ QUOTE(UIA_IsLegacyIAccessiblePatternAvailablePropertyId),
+ QUOTE(UIA_LegacyIAccessibleChildIdPropertyId),
+ QUOTE(UIA_LegacyIAccessibleNamePropertyId),
+ QUOTE(UIA_LegacyIAccessibleValuePropertyId),
+ QUOTE(UIA_LegacyIAccessibleDescriptionPropertyId),
+ QUOTE(UIA_LegacyIAccessibleRolePropertyId),
+ QUOTE(UIA_LegacyIAccessibleStatePropertyId),
+ QUOTE(UIA_LegacyIAccessibleHelpPropertyId),
+ QUOTE(UIA_LegacyIAccessibleKeyboardShortcutPropertyId),
+ QUOTE(UIA_LegacyIAccessibleSelectionPropertyId),
+ QUOTE(UIA_LegacyIAccessibleDefaultActionPropertyId),
+ QUOTE(UIA_AriaRolePropertyId),
+ QUOTE(UIA_AriaPropertiesPropertyId),
+ QUOTE(UIA_IsDataValidForFormPropertyId),
+ QUOTE(UIA_ControllerForPropertyId),
+ QUOTE(UIA_DescribedByPropertyId),
+ QUOTE(UIA_FlowsToPropertyId),
+ QUOTE(UIA_ProviderDescriptionPropertyId),
+ QUOTE(UIA_IsItemContainerPatternAvailablePropertyId),
+ QUOTE(UIA_IsVirtualizedItemPatternAvailablePropertyId),
+ QUOTE(UIA_IsSynchronizedInputPatternAvailablePropertyId),
+ QUOTE(UIA_OptimizeForVisualContentPropertyId),
+ QUOTE(UIA_IsObjectModelPatternAvailablePropertyId),
+ QUOTE(UIA_AnnotationAnnotationTypeIdPropertyId),
+ QUOTE(UIA_AnnotationAnnotationTypeNamePropertyId),
+ QUOTE(UIA_AnnotationAuthorPropertyId),
+ QUOTE(UIA_AnnotationDateTimePropertyId),
+ QUOTE(UIA_AnnotationTargetPropertyId),
+ QUOTE(UIA_IsAnnotationPatternAvailablePropertyId),
+ QUOTE(UIA_IsTextPattern2AvailablePropertyId),
+ QUOTE(UIA_StylesStyleIdPropertyId),
+ QUOTE(UIA_StylesStyleNamePropertyId),
+ QUOTE(UIA_StylesFillColorPropertyId),
+ QUOTE(UIA_StylesFillPatternStylePropertyId),
+ QUOTE(UIA_StylesShapePropertyId),
+ QUOTE(UIA_StylesFillPatternColorPropertyId),
+ QUOTE(UIA_StylesExtendedPropertiesPropertyId),
+ QUOTE(UIA_IsStylesPatternAvailablePropertyId),
+ QUOTE(UIA_IsSpreadsheetPatternAvailablePropertyId),
+ QUOTE(UIA_SpreadsheetItemFormulaPropertyId),
+ QUOTE(UIA_SpreadsheetItemAnnotationObjectsPropertyId),
+ QUOTE(UIA_SpreadsheetItemAnnotationTypesPropertyId),
+ QUOTE(UIA_IsSpreadsheetItemPatternAvailablePropertyId),
+ QUOTE(UIA_Transform2CanZoomPropertyId),
+ QUOTE(UIA_IsTransformPattern2AvailablePropertyId),
+ QUOTE(UIA_LiveSettingPropertyId),
+ QUOTE(UIA_IsTextChildPatternAvailablePropertyId),
+ QUOTE(UIA_IsDragPatternAvailablePropertyId),
+ QUOTE(UIA_DragIsGrabbedPropertyId),
+ QUOTE(UIA_DragDropEffectPropertyId),
+ QUOTE(UIA_DragDropEffectsPropertyId),
+ QUOTE(UIA_IsDropTargetPatternAvailablePropertyId),
+ QUOTE(UIA_DropTargetDropTargetEffectPropertyId),
+ QUOTE(UIA_DropTargetDropTargetEffectsPropertyId),
+ QUOTE(UIA_DragGrabbedItemsPropertyId),
+ QUOTE(UIA_Transform2ZoomLevelPropertyId),
+ QUOTE(UIA_Transform2ZoomMinimumPropertyId),
+ QUOTE(UIA_Transform2ZoomMaximumPropertyId),
+ QUOTE(UIA_FlowsFromPropertyId),
+ QUOTE(UIA_IsTextEditPatternAvailablePropertyId),
+ QUOTE(UIA_IsPeripheralPropertyId),
+ QUOTE(UIA_IsCustomNavigationPatternAvailablePropertyId),
+ QUOTE(UIA_PositionInSetPropertyId),
+ QUOTE(UIA_SizeOfSetPropertyId),
+ QUOTE(UIA_LevelPropertyId),
+ QUOTE(UIA_AnnotationTypesPropertyId),
+ QUOTE(UIA_AnnotationObjectsPropertyId),
+ QUOTE(UIA_LandmarkTypePropertyId),
+ QUOTE(UIA_LocalizedLandmarkTypePropertyId),
+ QUOTE(UIA_FullDescriptionPropertyId),
+ QUOTE(UIA_FillColorPropertyId),
+ QUOTE(UIA_OutlineColorPropertyId),
+ QUOTE(UIA_FillTypePropertyId),
+ QUOTE(UIA_VisualEffectsPropertyId),
+ QUOTE(UIA_OutlineThicknessPropertyId),
+ QUOTE(UIA_CenterPointPropertyId),
+ QUOTE(UIA_RotationPropertyId),
+ QUOTE(UIA_SizePropertyId),
+ QUOTE(UIA_IsSelectionPattern2AvailablePropertyId),
+ QUOTE(UIA_Selection2FirstSelectedItemPropertyId),
+ QUOTE(UIA_Selection2LastSelectedItemPropertyId),
+ QUOTE(UIA_Selection2CurrentSelectedItemPropertyId),
+ QUOTE(UIA_Selection2ItemCountPropertyId),
+ QUOTE(UIA_HeadingLevelPropertyId),
+ // Attributes
+ QUOTE(UIA_AnimationStyleAttributeId),
+ QUOTE(UIA_BackgroundColorAttributeId),
+ QUOTE(UIA_BulletStyleAttributeId),
+ QUOTE(UIA_CapStyleAttributeId),
+ QUOTE(UIA_CultureAttributeId),
+ QUOTE(UIA_FontNameAttributeId),
+ QUOTE(UIA_FontSizeAttributeId),
+ QUOTE(UIA_FontWeightAttributeId),
+ QUOTE(UIA_ForegroundColorAttributeId),
+ QUOTE(UIA_HorizontalTextAlignmentAttributeId),
+ QUOTE(UIA_IndentationFirstLineAttributeId),
+ QUOTE(UIA_IndentationLeadingAttributeId),
+ QUOTE(UIA_IndentationTrailingAttributeId),
+ QUOTE(UIA_IsHiddenAttributeId),
+ QUOTE(UIA_IsItalicAttributeId),
+ QUOTE(UIA_IsReadOnlyAttributeId),
+ QUOTE(UIA_IsSubscriptAttributeId),
+ QUOTE(UIA_IsSuperscriptAttributeId),
+ QUOTE(UIA_MarginBottomAttributeId),
+ QUOTE(UIA_MarginLeadingAttributeId),
+ QUOTE(UIA_MarginTopAttributeId),
+ QUOTE(UIA_MarginTrailingAttributeId),
+ QUOTE(UIA_OutlineStylesAttributeId),
+ QUOTE(UIA_OverlineColorAttributeId),
+ QUOTE(UIA_OverlineStyleAttributeId),
+ QUOTE(UIA_StrikethroughColorAttributeId),
+ QUOTE(UIA_StrikethroughStyleAttributeId),
+ QUOTE(UIA_TabsAttributeId),
+ QUOTE(UIA_TextFlowDirectionsAttributeId),
+ QUOTE(UIA_UnderlineColorAttributeId),
+ QUOTE(UIA_UnderlineStyleAttributeId),
+ QUOTE(UIA_AnnotationTypesAttributeId),
+ QUOTE(UIA_AnnotationObjectsAttributeId),
+ QUOTE(UIA_StyleNameAttributeId),
+ QUOTE(UIA_StyleIdAttributeId),
+ QUOTE(UIA_LinkAttributeId),
+ QUOTE(UIA_IsActiveAttributeId),
+ QUOTE(UIA_SelectionActiveEndAttributeId),
+ QUOTE(UIA_CaretPositionAttributeId),
+ QUOTE(UIA_CaretBidiModeAttributeId),
+ QUOTE(UIA_LineSpacingAttributeId),
+ QUOTE(UIA_BeforeParagraphSpacingAttributeId),
+ QUOTE(UIA_AfterParagraphSpacingAttributeId),
+ QUOTE(UIA_SayAsInterpretAsAttributeId),
+ // Control Types
+ QUOTE(UIA_ButtonControlTypeId),
+ QUOTE(UIA_CalendarControlTypeId),
+ QUOTE(UIA_CheckBoxControlTypeId),
+ QUOTE(UIA_ComboBoxControlTypeId),
+ QUOTE(UIA_EditControlTypeId),
+ QUOTE(UIA_HyperlinkControlTypeId),
+ QUOTE(UIA_ImageControlTypeId),
+ QUOTE(UIA_ListItemControlTypeId),
+ QUOTE(UIA_ListControlTypeId),
+ QUOTE(UIA_MenuControlTypeId),
+ QUOTE(UIA_MenuBarControlTypeId),
+ QUOTE(UIA_MenuItemControlTypeId),
+ QUOTE(UIA_ProgressBarControlTypeId),
+ QUOTE(UIA_RadioButtonControlTypeId),
+ QUOTE(UIA_ScrollBarControlTypeId),
+ QUOTE(UIA_SliderControlTypeId),
+ QUOTE(UIA_SpinnerControlTypeId),
+ QUOTE(UIA_StatusBarControlTypeId),
+ QUOTE(UIA_TabControlTypeId),
+ QUOTE(UIA_TabItemControlTypeId),
+ QUOTE(UIA_TextControlTypeId),
+ QUOTE(UIA_ToolBarControlTypeId),
+ QUOTE(UIA_ToolTipControlTypeId),
+ QUOTE(UIA_TreeControlTypeId),
+ QUOTE(UIA_TreeItemControlTypeId),
+ QUOTE(UIA_CustomControlTypeId),
+ QUOTE(UIA_GroupControlTypeId),
+ QUOTE(UIA_ThumbControlTypeId),
+ QUOTE(UIA_DataGridControlTypeId),
+ QUOTE(UIA_DataItemControlTypeId),
+ QUOTE(UIA_DocumentControlTypeId),
+ QUOTE(UIA_SplitButtonControlTypeId),
+ QUOTE(UIA_WindowControlTypeId),
+ QUOTE(UIA_PaneControlTypeId),
+ QUOTE(UIA_HeaderControlTypeId),
+ QUOTE(UIA_HeaderItemControlTypeId),
+ QUOTE(UIA_TableControlTypeId),
+ QUOTE(UIA_TitleBarControlTypeId),
+ QUOTE(UIA_SeparatorControlTypeId),
+ QUOTE(UIA_SemanticZoomControlTypeId),
+ QUOTE(UIA_AppBarControlTypeId),
+ };
+
+ return GetNameForPlatformConstant(id_table, base::size(id_table), identifier);
+}
+
+AX_EXPORT std::wstring UiaOrientationToString(int32_t identifier) {
+ static const PlatformConstantToNameEntry id_table[] = {
+ QUOTE(OrientationType_None), QUOTE(OrientationType_Horizontal),
+ QUOTE(OrientationType_Vertical)};
+ return GetNameForPlatformConstant(id_table, base::size(id_table), identifier);
+}
+
+AX_EXPORT std::wstring UiaLiveSettingToString(int32_t identifier) {
+ static const PlatformConstantToNameEntry id_table[] = {
+ QUOTE(LiveSetting::Off), QUOTE(LiveSetting::Polite),
+ QUOTE(LiveSetting::Assertive)};
+ return GetNameForPlatformConstant(id_table, base::size(id_table), identifier);
+}
+
+AX_EXPORT std::string BstrToUTF8(BSTR bstr) {
+ std::wstring str(bstr, SysStringLen(bstr));
+ return base::WideToUTF8(str);
+}
+
+AX_EXPORT std::string UiaIdentifierToStringUTF8(int32_t id) {
+ return base::WideToUTF8(UiaIdentifierToString(id));
+}
+
+AX_EXPORT HWND GetHwndForProcess(base::ProcessId pid) {
+ HwndWithProcId hwnd_with_proc_id(pid);
+ EnumWindows(&EnumWindowsProcPid, (LPARAM)&hwnd_with_proc_id);
+ return hwnd_with_proc_id.hwnd;
+}
+
+struct HWNDSearchInfo {
+ std::wstring title;
+ HWND hwnd;
+};
+
+BOOL CALLBACK MatchWindow(HWND hwnd, LPARAM lParam) {
+ const auto num_chars = ::GetWindowTextLength(hwnd);
+ if (!num_chars) {
+ return TRUE;
+ }
+
+ std::wstring title(num_chars + 1, '\0');
+ if (!::GetWindowText(hwnd, &title.front(), title.size())) {
+ return TRUE;
+ }
+
+ auto* info = reinterpret_cast<HWNDSearchInfo*>(lParam);
+ if (title.find(info->title) != std::wstring::npos) {
+ info->hwnd = hwnd;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+AX_EXPORT HWND GetHWNDBySelector(const AXTreeSelector& selector) {
+ HWNDSearchInfo info;
+ if (selector.types & AXTreeSelector::Chrome) {
+ info.title = kChromeTitle;
+ } else if (selector.types & AXTreeSelector::Chromium) {
+ info.title = kChromiumTitle;
+ } else if (selector.types & AXTreeSelector::Edge) {
+ info.title = kEdgeTitle;
+ } else if (selector.types & AXTreeSelector::Firefox) {
+ info.title = kFirefoxTitle;
+ } else {
+ LOG(ERROR) << selector.AppName()
+ << " application is not supported on the system";
+ return NULL;
+ }
+
+ if (::EnumWindows(MatchWindow, reinterpret_cast<LPARAM>(&info))) {
+ return NULL;
+ }
+
+ return info.hwnd;
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_win.h b/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_win.h
new file mode 100644
index 00000000000..64f6f775afc
--- /dev/null
+++ b/chromium/ui/accessibility/platform/inspect/ax_inspect_utils_win.h
@@ -0,0 +1,49 @@
+// 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_ACCESSIBILITY_PLATFORM_INSPECT_AX_INSPECT_UTILS_WIN_H_
+#define UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_INSPECT_UTILS_WIN_H_
+
+#include <stdint.h>
+#include <wtypes.h>
+
+#include <string>
+#include <vector>
+
+#include "base/process/process_handle.h"
+#include "ui/accessibility/ax_export.h"
+#include "ui/gfx/win/hwnd_util.h"
+
+namespace ui {
+struct AXTreeSelector;
+
+AX_EXPORT std::wstring IAccessibleRoleToString(int32_t ia_role);
+AX_EXPORT std::wstring IAccessible2RoleToString(int32_t ia_role);
+AX_EXPORT std::wstring IAccessibleStateToString(int32_t ia_state);
+AX_EXPORT void IAccessibleStateToStringVector(
+ int32_t ia_state,
+ std::vector<std::wstring>* result);
+AX_EXPORT std::wstring IAccessible2StateToString(int32_t ia2_state);
+AX_EXPORT void IAccessible2StateToStringVector(
+ int32_t ia_state,
+ std::vector<std::wstring>* result);
+
+// Handles both IAccessible/MSAA events and IAccessible2 events.
+AX_EXPORT std::wstring AccessibilityEventToString(int32_t event_id);
+
+AX_EXPORT std::wstring UiaIdentifierToString(int32_t identifier);
+AX_EXPORT std::wstring UiaOrientationToString(int32_t identifier);
+AX_EXPORT std::wstring UiaLiveSettingToString(int32_t identifier);
+
+AX_EXPORT std::string BstrToUTF8(BSTR bstr);
+AX_EXPORT std::string UiaIdentifierToStringUTF8(int32_t id);
+
+AX_EXPORT HWND GetHwndForProcess(base::ProcessId pid);
+
+// Returns HWND of window matching a given tree selector.
+AX_EXPORT HWND GetHWNDBySelector(const ui::AXTreeSelector& selector);
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_INSPECT_UTILS_WIN_H_
diff --git a/chromium/ui/accessibility/platform/inspect/property_node.cc b/chromium/ui/accessibility/platform/inspect/ax_property_node.cc
index 4110de2c199..74b10a1b4d5 100644
--- a/chromium/ui/accessibility/platform/inspect/property_node.cc
+++ b/chromium/ui/accessibility/platform/inspect/ax_property_node.cc
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/accessibility/platform/inspect/property_node.h"
+#include "ui/accessibility/platform/inspect/ax_property_node.h"
#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
-#include "ui/accessibility/platform/inspect/inspect.h"
+#include "ui/accessibility/platform/inspect/ax_inspect.h"
namespace ui {
diff --git a/chromium/ui/accessibility/platform/inspect/property_node.h b/chromium/ui/accessibility/platform/inspect/ax_property_node.h
index 2da2819b67a..e9033b8fdda 100644
--- a/chromium/ui/accessibility/platform/inspect/property_node.h
+++ b/chromium/ui/accessibility/platform/inspect/ax_property_node.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_INSPECT_PROPERTY_NODE_H_
-#define UI_ACCESSIBILITY_PLATFORM_INSPECT_PROPERTY_NODE_H_
+#ifndef UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_PROPERTY_NODE_H_
+#define UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_PROPERTY_NODE_H_
#include <string>
#include <vector>
@@ -95,4 +95,4 @@ class AX_EXPORT AXPropertyNode final {
} // namespace ui
-#endif // UI_ACCESSIBILITY_PLATFORM_INSPECT_PROPERTY_NODE_H_
+#endif // UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_PROPERTY_NODE_H_
diff --git a/chromium/ui/accessibility/platform/inspect/property_node_unittest.cc b/chromium/ui/accessibility/platform/inspect/ax_property_node_unittest.cc
index 1b676b97a76..17cde27a2df 100644
--- a/chromium/ui/accessibility/platform/inspect/property_node_unittest.cc
+++ b/chromium/ui/accessibility/platform/inspect/ax_property_node_unittest.cc
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/accessibility/platform/inspect/property_node.h"
+#include "ui/accessibility/platform/inspect/ax_property_node.h"
+
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_enums.mojom.h"
-#include "ui/accessibility/platform/inspect/inspect.h"
+#include "ui/accessibility/platform/inspect/ax_inspect.h"
using ui::AXPropertyFilter;
using ui::AXPropertyNode;
diff --git a/chromium/ui/accessibility/platform/inspect/tree_formatter.cc b/chromium/ui/accessibility/platform/inspect/ax_tree_formatter.cc
index e2a1e222a15..2cbf9ebfa2c 100644
--- a/chromium/ui/accessibility/platform/inspect/tree_formatter.cc
+++ b/chromium/ui/accessibility/platform/inspect/ax_tree_formatter.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/accessibility/platform/inspect/tree_formatter.h"
+#include "ui/accessibility/platform/inspect/ax_tree_formatter.h"
#include <ostream>
@@ -33,6 +33,7 @@ bool AXTreeFormatter::MatchesPropertyFilters(
base::MatchPattern(text, filter.match_str + "=*"))) {
switch (filter.type) {
case AXPropertyFilter::ALLOW_EMPTY:
+ case AXPropertyFilter::SCRIPT:
allow = true;
break;
case AXPropertyFilter::ALLOW:
@@ -50,13 +51,13 @@ bool AXTreeFormatter::MatchesPropertyFilters(
// static
bool AXTreeFormatter::MatchesNodeFilters(
const std::vector<AXNodeFilter>& node_filters,
- const base::DictionaryValue& dict) {
+ const base::Value& dict) {
for (const auto& filter : node_filters) {
- std::string value;
- if (!dict.GetString(filter.property, &value)) {
- continue;
+ if (filter.property == "*") {
+ return true;
}
- if (base::MatchPattern(value, filter.pattern)) {
+ const std::string* value = dict.FindStringKey(filter.property);
+ if (value && base::MatchPattern(*value, filter.pattern)) {
return true;
}
}
diff --git a/chromium/ui/accessibility/platform/inspect/ax_tree_formatter.h b/chromium/ui/accessibility/platform/inspect/ax_tree_formatter.h
new file mode 100644
index 00000000000..f8f6dbde568
--- /dev/null
+++ b/chromium/ui/accessibility/platform/inspect/ax_tree_formatter.h
@@ -0,0 +1,120 @@
+// Copyright 2020 The Chromium 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_INSPECT_AX_TREE_FORMATTER_H_
+#define UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_TREE_FORMATTER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "ui/accessibility/platform/inspect/ax_inspect.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace base {
+class Value;
+}
+
+namespace ui {
+
+class AXNode;
+class AXTreeID;
+class AXPlatformNodeDelegate;
+
+// A utility class for formatting platform-specific accessibility information,
+// for use in testing, debugging, and developer tools.
+// This is extended by a subclass for each platform where accessibility is
+// implemented.
+class AX_EXPORT AXTreeFormatter {
+ public:
+ using AXTreeSelector = ui::AXTreeSelector;
+ using AXPropertyFilter = ui::AXPropertyFilter;
+ using AXNodeFilter = ui::AXNodeFilter;
+
+ virtual ~AXTreeFormatter() = default;
+
+ // Returns true if the given text matches |allow| property filters, or false
+ // if matches |deny| filter. Returns default value if doesn't match any
+ // property filters.
+ static bool MatchesPropertyFilters(
+ const std::vector<AXPropertyFilter>& property_filters,
+ const std::string& text,
+ bool default_result);
+
+ // Check if the given dictionary matches any of the supplied AXNodeFilter(s).
+ static bool MatchesNodeFilters(const std::vector<AXNodeFilter>& node_filters,
+ const base::Value& dict);
+
+ // Formats a given web content accessible tree.
+ // |root| must be non-null and must be in web content.
+ virtual std::string Format(AXPlatformNodeDelegate* root) const = 0;
+
+ // Build an accessibility tree for any window.
+ //
+ // Returns a dictionary value with the accessibility tree populated.
+ // The dictionary contains a key/value pair for each attribute of a node,
+ // plus a "children" attribute containing a list of all child nodes.
+ // {
+ // "AXName": "node", /* actual attributes will vary by platform */
+ // "position": { /* some attributes may be dictionaries */
+ // "x": 0,
+ // "y": 0
+ // },
+ // /* ... more attributes of |node| */
+ // "children": [ { /* list of children created recursively */
+ // "AXName": "child node 1",
+ // /* ... more attributes */
+ // "children": [ ]
+ // }, {
+ // "AXName": "child name 2",
+ // /* ... more attributes */
+ // "children": [ ]
+ // } ]
+ // }
+ virtual base::Value BuildTreeForWindow(
+ gfx::AcceleratedWidget widget) const = 0;
+
+ // Build an accessibility tree for an application with a name matching the
+ // given pattern.
+ virtual base::Value BuildTreeForSelector(const AXTreeSelector&) const = 0;
+
+ // Build an accessibility tree for an application with |node| as the root.
+ virtual base::Value BuildTreeForNode(ui::AXNode* node) const = 0;
+
+ // Returns a string representing the internal tree represented by |tree_id|.
+ virtual std::string DumpInternalAccessibilityTree(
+ ui::AXTreeID tree_id,
+ const std::vector<AXPropertyFilter>& property_filters) = 0;
+
+ // Dumps accessibility tree.
+ virtual std::string FormatTree(const base::Value& tree_node) const = 0;
+
+ // Propery filter predefined sets.
+ enum PropertyFilterSet {
+ // Empty set.
+ kFiltersEmptySet,
+
+ // Default filters set, defined by a formatter.
+ kFiltersDefaultSet,
+ };
+
+ // Set regular expression filters that apply to each property of every node
+ // before it's output. If a default filter set is given, then filters defined
+ // by the set are preappended to the given property filters.
+ virtual void SetPropertyFilters(
+ const std::vector<AXPropertyFilter>& property_filters,
+ PropertyFilterSet default_filters_set = kFiltersEmptySet) = 0;
+
+ // Set regular expression filters that apply to every node before output.
+ virtual void SetNodeFilters(
+ const std::vector<AXNodeFilter>& node_filters) = 0;
+
+ // If true, the internal accessibility id of each node will be included
+ // in its output.
+ virtual void set_show_ids(bool show_ids) = 0;
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_TREE_FORMATTER_H_
diff --git a/chromium/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc b/chromium/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc
new file mode 100644
index 00000000000..f3dd6709288
--- /dev/null
+++ b/chromium/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc
@@ -0,0 +1,228 @@
+// 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/accessibility/platform/inspect/ax_tree_formatter_base.h"
+
+#include "base/notreached.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "ui/accessibility/ax_tree_id.h"
+#include "ui/accessibility/platform/inspect/ax_property_node.h"
+
+namespace ui {
+
+namespace {
+
+const char kIndentSymbol = '+';
+const int kIndentSymbolCount = 2;
+const char kSkipString[] = "@NO_DUMP";
+const char kSkipChildren[] = "@NO_CHILDREN_DUMP";
+
+} // namespace
+
+AXTreeFormatterBase::AXTreeFormatterBase() = default;
+
+AXTreeFormatterBase::~AXTreeFormatterBase() = default;
+
+// static
+const char AXTreeFormatterBase::kChildrenDictAttr[] = "children";
+const char AXTreeFormatterBase::kScriptsDictAttr[] = "scripts";
+
+std::string AXTreeFormatterBase::Format(AXPlatformNodeDelegate* root) const {
+ DCHECK(root);
+ return FormatTree(BuildTree(root));
+}
+
+std::string AXTreeFormatterBase::FormatTree(const base::Value& dict) const {
+ std::string contents;
+
+ // Format the tree.
+ RecursiveFormatTree(dict, &contents);
+
+ // Format scripts.
+ const base::Value* scripts = dict.FindListKey(kScriptsDictAttr);
+ if (!scripts)
+ return contents;
+
+ for (const base::Value& script : scripts->GetList()) {
+ WriteAttribute(false, script.GetString(), &contents);
+ contents += "\n";
+ }
+
+ return contents;
+}
+
+base::Value AXTreeFormatterBase::BuildTreeForNode(ui::AXNode* root) const {
+ NOTREACHED()
+ << "Only supported when called on AccessibilityTreeFormatterBlink.";
+ return base::Value();
+}
+
+void AXTreeFormatterBase::RecursiveFormatTree(const base::Value& dict,
+ std::string* contents,
+ int depth) const {
+ // Check dictionary against node filters, may require us to skip this node
+ // and its children.
+ if (MatchesNodeFilters(dict))
+ return;
+
+ std::string indent = std::string(depth * kIndentSymbolCount, kIndentSymbol);
+ std::string line =
+ indent + ProcessTreeForOutput(base::Value::AsDictionaryValue(dict));
+ if (line.find(kSkipString) != std::string::npos)
+ return;
+
+ // Normalize any Windows-style line endings by removing \r.
+ base::RemoveChars(line, "\r", &line);
+
+ // Replace literal newlines with "<newline>"
+ base::ReplaceChars(line, "\n", "<newline>", &line);
+
+ *contents += line + "\n";
+ if (line.find(kSkipChildren) != std::string::npos)
+ return;
+
+ const base::Value* children = dict.FindListPath(kChildrenDictAttr);
+ if (children && !children->GetList().empty()) {
+ for (const auto& child_dict : children->GetList()) {
+ RecursiveFormatTree(child_dict, contents, depth + 1);
+ }
+ }
+}
+
+void AXTreeFormatterBase::SetPropertyFilters(
+ const std::vector<AXPropertyFilter>& property_filters,
+ PropertyFilterSet default_filter_set) {
+ property_filters_.clear();
+ if (default_filter_set == kFiltersDefaultSet) {
+ AddDefaultFilters(&property_filters_);
+ }
+ property_filters_.insert(property_filters_.end(), property_filters.begin(),
+ property_filters.end());
+}
+
+void AXTreeFormatterBase::SetNodeFilters(
+ const std::vector<AXNodeFilter>& node_filters) {
+ node_filters_ = node_filters;
+}
+
+void AXTreeFormatterBase::set_show_ids(bool show_ids) {
+ show_ids_ = show_ids;
+}
+
+std::string AXTreeFormatterBase::DumpInternalAccessibilityTree(
+ ui::AXTreeID tree_id,
+ const std::vector<AXPropertyFilter>& property_filters) {
+ NOTREACHED()
+ << "Only supported when called on AccessibilityTreeFormatterBlink.";
+ return std::string("");
+}
+
+std::vector<AXPropertyNode> AXTreeFormatterBase::PropertyFilterNodesFor(
+ const std::string& line_index) const {
+ std::vector<AXPropertyNode> list;
+ for (const auto& filter : property_filters_) {
+ AXPropertyNode property_node = AXPropertyNode::From(filter);
+
+ // Filter out if doesn't match line index (if specified).
+ if (!property_node.line_indexes.empty() &&
+ std::find(property_node.line_indexes.begin(),
+ property_node.line_indexes.end(),
+ line_index) == property_node.line_indexes.end()) {
+ continue;
+ }
+
+ switch (filter.type) {
+ case AXPropertyFilter::ALLOW_EMPTY:
+ case AXPropertyFilter::ALLOW:
+ list.push_back(std::move(property_node));
+ break;
+ case AXPropertyFilter::SCRIPT:
+ case AXPropertyFilter::DENY:
+ break;
+ default:
+ break;
+ }
+ }
+ return list;
+}
+
+std::vector<AXPropertyNode> AXTreeFormatterBase::ScriptPropertyNodes() const {
+ std::vector<AXPropertyNode> list;
+ for (const auto& filter : property_filters_) {
+ if (filter.type == AXPropertyFilter::SCRIPT) {
+ list.push_back(AXPropertyNode::From(filter));
+ }
+ }
+ return list;
+}
+
+bool AXTreeFormatterBase::HasMatchAllPropertyFilter() const {
+ for (const auto& filter : property_filters_) {
+ if (filter.type == AXPropertyFilter::ALLOW && filter.match_str == "*") {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AXTreeFormatterBase::MatchesPropertyFilters(const std::string& text,
+ bool default_result) const {
+ return ui::AXTreeFormatter::MatchesPropertyFilters(property_filters_, text,
+ default_result);
+}
+
+bool AXTreeFormatterBase::MatchesNodeFilters(const base::Value& dict) const {
+ return ui::AXTreeFormatter::MatchesNodeFilters(node_filters_, dict);
+}
+
+std::string AXTreeFormatterBase::FormatCoordinates(
+ const base::Value& dict,
+ const std::string& name,
+ const std::string& x_name,
+ const std::string& y_name) const {
+ int x = dict.FindIntPath(x_name).value_or(0);
+ int y = dict.FindIntPath(y_name).value_or(0);
+ return base::StringPrintf("%s=(%d, %d)", name.c_str(), x, y);
+}
+
+std::string AXTreeFormatterBase::FormatRectangle(
+ const base::Value& dict,
+ const std::string& name,
+ const std::string& left_name,
+ const std::string& top_name,
+ const std::string& width_name,
+ const std::string& height_name) const {
+ int left = dict.FindIntPath(left_name).value_or(0);
+ int top = dict.FindIntPath(top_name).value_or(0);
+ int width = dict.FindIntPath(width_name).value_or(0);
+ int height = dict.FindIntPath(height_name).value_or(0);
+ return base::StringPrintf("%s=(%d, %d, %d, %d)", name.c_str(), left, top,
+ width, height);
+}
+
+bool AXTreeFormatterBase::WriteAttribute(bool include_by_default,
+ const std::string& attr,
+ std::string* line) const {
+ if (attr.empty())
+ return false;
+ if (!MatchesPropertyFilters(attr, include_by_default))
+ return false;
+ if (!line->empty())
+ *line += " ";
+ *line += attr;
+ return true;
+}
+
+void AXTreeFormatterBase::AddPropertyFilter(
+ std::vector<AXPropertyFilter>* property_filters,
+ std::string filter,
+ AXPropertyFilter::Type type) {
+ property_filters->push_back(AXPropertyFilter(filter, type));
+}
+
+void AXTreeFormatterBase::AddDefaultFilters(
+ std::vector<AXPropertyFilter>* property_filters) {}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/platform/inspect/ax_tree_formatter_base.h b/chromium/ui/accessibility/platform/inspect/ax_tree_formatter_base.h
new file mode 100644
index 00000000000..e5704194822
--- /dev/null
+++ b/chromium/ui/accessibility/platform/inspect/ax_tree_formatter_base.h
@@ -0,0 +1,129 @@
+// 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_ACCESSIBILITY_PLATFORM_INSPECT_AX_TREE_FORMATTER_BASE_H_
+#define UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_TREE_FORMATTER_BASE_H_
+
+#include <vector>
+
+#include "base/values.h"
+#include "ui/accessibility/platform/inspect/ax_tree_formatter.h"
+
+namespace ui {
+
+class AXPropertyNode;
+
+// A utility class for formatting platform-specific accessibility information,
+// for use in testing, debugging, and developer tools.
+// This is extended by a subclass for each platform where accessibility is
+// implemented.
+class AX_EXPORT AXTreeFormatterBase : public AXTreeFormatter {
+ public:
+ AXTreeFormatterBase();
+ ~AXTreeFormatterBase() override;
+
+ // Dumps formatted the given accessibility tree into a string.
+ std::string Format(AXPlatformNodeDelegate* root) const override;
+
+ // Build an accessibility tree for the current Chrome app.
+ virtual base::Value BuildTree(AXPlatformNodeDelegate* root) const = 0;
+
+ // AXTreeFormatter overrides.
+ std::string FormatTree(const base::Value& tree_node) const override;
+ base::Value BuildTreeForNode(ui::AXNode* root) const override;
+ void SetPropertyFilters(const std::vector<AXPropertyFilter>& property_filters,
+ PropertyFilterSet default_filters_set) override;
+ void SetNodeFilters(const std::vector<AXNodeFilter>& node_filters) override;
+ void set_show_ids(bool show_ids) override;
+ std::string DumpInternalAccessibilityTree(
+ ui::AXTreeID tree_id,
+ const std::vector<AXPropertyFilter>& property_filters) override;
+
+ protected:
+ static const char kChildrenDictAttr[];
+ static const char kScriptsDictAttr[];
+
+ //
+ // Overridden by platform subclasses.
+ //
+
+ // Appends default filters of the formatter.
+ virtual void AddDefaultFilters(
+ std::vector<AXPropertyFilter>* property_filters);
+
+ // Returns property nodes complying to the line index filter for all
+ // allow/allow_empty property filters.
+ std::vector<AXPropertyNode> PropertyFilterNodesFor(
+ const std::string& line_index) const;
+
+ // Returns a list of script property nodes.
+ std::vector<ui::AXPropertyNode> ScriptPropertyNodes() const;
+
+ // Return true if match-all filter is present.
+ bool HasMatchAllPropertyFilter() const;
+
+ // Process accessibility tree with filters for output.
+ // Given a dictionary that contains a platform-specific dictionary
+ // representing an accessibility tree, and utilizing property_filters_ and
+ // node_filters_:
+ // - Returns a filtered text view as one large string.
+ // - Provides a filtered version of the dictionary in an out param,
+ // (only if the out param is provided).
+ virtual std::string ProcessTreeForOutput(
+ const base::DictionaryValue& node) const = 0;
+
+ //
+ // Utility functions to be used by each platform.
+ //
+
+ std::string FormatCoordinates(const base::Value& dict,
+ const std::string& name,
+ const std::string& x_name,
+ const std::string& y_name) const;
+
+ std::string FormatRectangle(const base::Value& dict,
+ const std::string& name,
+ const std::string& left_name,
+ const std::string& top_name,
+ const std::string& width_name,
+ const std::string& height_name) const;
+
+ // Writes the given attribute string out to |line| if it matches the property
+ // filters.
+ // Returns false if the attribute was filtered out.
+ bool WriteAttribute(bool include_by_default,
+ const std::string& attr,
+ std::string* line) const;
+ void AddPropertyFilter(std::vector<AXPropertyFilter>* property_filters,
+ std::string filter,
+ AXPropertyFilter::Type type = AXPropertyFilter::ALLOW);
+ bool show_ids() const { return show_ids_; }
+
+ private:
+ void RecursiveFormatTree(const base::Value& tree_node,
+ std::string* contents,
+ int depth = 0) const;
+
+ bool MatchesPropertyFilters(const std::string& text,
+ bool default_result) const;
+ bool MatchesNodeFilters(const base::Value& dict) const;
+
+ // Property filters used when formatting the accessibility tree as text.
+ // Any property which matches a property filter will be skipped.
+ std::vector<AXPropertyFilter> property_filters_;
+
+ // Node filters used when formatting the accessibility tree as text.
+ // Any node which matches a node wilder will be skipped, along with all its
+ // children.
+ std::vector<AXNodeFilter> node_filters_;
+
+ // Whether or not node ids should be included in the dump.
+ bool show_ids_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(AXTreeFormatterBase);
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_TREE_FORMATTER_BASE_H_
diff --git a/chromium/ui/accessibility/platform/inspect/tree_formatter.h b/chromium/ui/accessibility/platform/inspect/tree_formatter.h
deleted file mode 100644
index 4a70a4d5439..00000000000
--- a/chromium/ui/accessibility/platform/inspect/tree_formatter.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2020 The Chromium 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_INSPECT_TREE_FORMATTER_H_
-#define UI_ACCESSIBILITY_PLATFORM_INSPECT_TREE_FORMATTER_H_
-
-#include "ui/accessibility/platform/inspect/inspect.h"
-
-#include "ui/gfx/native_widget_types.h"
-
-namespace base {
-class Value;
-class DictionaryValue;
-}
-
-namespace ui {
-
-class AXPlatformNodeDelegate;
-
-// A utility class for formatting platform-specific accessibility information,
-// for use in testing, debugging, and developer tools.
-// This is extended by a subclass for each platform where accessibility is
-// implemented.
-class AX_EXPORT AXTreeFormatter {
- public:
- using AXTreeSelector = ui::AXTreeSelector;
- using AXPropertyFilter = ui::AXPropertyFilter;
- using AXNodeFilter = ui::AXNodeFilter;
-
- virtual ~AXTreeFormatter() = default;
-
- // Appends default filters of the formatter.
- virtual void AddDefaultFilters(
- std::vector<AXPropertyFilter>* property_filters) = 0;
-
- // Returns true if the given text matches |allow| property filters, or false
- // if matches |deny| filter. Returns default value if doesn't match any
- // property filters.
- static bool MatchesPropertyFilters(
- const std::vector<AXPropertyFilter>& property_filters,
- const std::string& text,
- bool default_result);
-
- // Check if the given dictionary matches any of the supplied AXNodeFilter(s).
- static bool MatchesNodeFilters(const std::vector<AXNodeFilter>& node_filters,
- const base::DictionaryValue& dict);
-
- // Build an accessibility tree for any window.
- virtual base::Value BuildTreeForWindow(
- gfx::AcceleratedWidget widget) const = 0;
-
- // Build an accessibility tree for an application with a name matching the
- // given pattern.
- virtual base::Value BuildTreeForSelector(const AXTreeSelector&) const = 0;
-
- // Returns a filtered accessibility tree using the current property and node
- // filters.
- virtual std::unique_ptr<base::DictionaryValue> FilterAccessibilityTree(
- const base::DictionaryValue& dict) = 0;
-
- // Dumps a BrowserAccessibility tree into a string.
- virtual void FormatAccessibilityTree(const base::DictionaryValue& tree_node,
- std::string* contents) = 0;
-
- // Test version of FormatAccessibilityTree().
- // |root| must be non-null and must be in web content.
- virtual void FormatAccessibilityTreeForTesting(AXPlatformNodeDelegate* root,
- std::string* contents) = 0;
-
- // Set regular expression filters that apply to each property of every node
- // before it's output.
- virtual void SetPropertyFilters(
- const std::vector<AXPropertyFilter>& property_filters) = 0;
-
- // Set regular expression filters that apply to every node before output.
- virtual void SetNodeFilters(
- const std::vector<AXNodeFilter>& node_filters) = 0;
-
- // If true, the internal accessibility id of each node will be included
- // in its output.
- virtual void set_show_ids(bool show_ids) = 0;
-};
-
-} // namespace ui
-
-#endif // UI_ACCESSIBILITY_PLATFORM_INSPECT_TREE_FORMATTER_H_
diff --git a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
index 45d3274a5ea..00f48c746b8 100644
--- a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -21,7 +21,7 @@ namespace ui {
namespace {
// A global map from AXNodes to TestAXNodeWrappers.
-std::map<AXNode::AXID, TestAXNodeWrapper*> g_node_id_to_wrapper_map;
+std::map<AXNodeID, TestAXNodeWrapper*> g_node_id_to_wrapper_map;
// A global coordinate offset.
gfx::Vector2d g_offset;
@@ -48,7 +48,7 @@ bool g_is_web_content = false;
// A map of hit test results - a map from source node ID to destination node
// ID.
-std::map<AXNode::AXID, AXNode::AXID> g_hit_test_result;
+std::map<AXNodeID, AXNodeID> g_hit_test_result;
// A simple implementation of AXTreeObserver to catch when AXNodes are
// deleted so we can delete their wrappers.
@@ -115,8 +115,8 @@ void TestAXNodeWrapper::SetGlobalIsWebContent(bool is_web_content) {
}
// static
-void TestAXNodeWrapper::SetHitTestResult(AXNode::AXID src_node_id,
- AXNode::AXID dst_node_id) {
+void TestAXNodeWrapper::SetHitTestResult(AXNodeID src_node_id,
+ AXNodeID dst_node_id) {
g_hit_test_result[src_node_id] = dst_node_id;
}
@@ -301,7 +301,7 @@ gfx::NativeViewAccessible TestAXNodeWrapper::HitTestSync(
: nullptr;
}
-gfx::NativeViewAccessible TestAXNodeWrapper::GetFocus() {
+gfx::NativeViewAccessible TestAXNodeWrapper::GetFocus() const {
auto focused = g_focused_node_in_tree.find(tree_);
if (focused != g_focused_node_in_tree.end() &&
focused->second->IsDescendantOf(node_)) {
@@ -464,20 +464,20 @@ base::Optional<bool> TestAXNodeWrapper::GetTableHasColumnOrRowHeaderNode()
return node_->GetTableHasColumnOrRowHeaderNode();
}
-std::vector<AXNode::AXID> TestAXNodeWrapper::GetColHeaderNodeIds() const {
+std::vector<AXNodeID> TestAXNodeWrapper::GetColHeaderNodeIds() const {
return node_->GetTableColHeaderNodeIds();
}
-std::vector<AXNode::AXID> TestAXNodeWrapper::GetColHeaderNodeIds(
+std::vector<AXNodeID> TestAXNodeWrapper::GetColHeaderNodeIds(
int col_index) const {
return node_->GetTableColHeaderNodeIds(col_index);
}
-std::vector<AXNode::AXID> TestAXNodeWrapper::GetRowHeaderNodeIds() const {
+std::vector<AXNodeID> TestAXNodeWrapper::GetRowHeaderNodeIds() const {
return node_->GetTableCellRowHeaderNodeIds();
}
-std::vector<AXNode::AXID> TestAXNodeWrapper::GetRowHeaderNodeIds(
+std::vector<AXNodeID> TestAXNodeWrapper::GetRowHeaderNodeIds(
int row_index) const {
return node_->GetTableRowHeaderNodeIds(row_index);
}
@@ -899,6 +899,14 @@ base::Optional<int> TestAXNodeWrapper::GetSetSize() const {
return node_->GetSetSize();
}
+SkColor TestAXNodeWrapper::GetColor() const {
+ return node_->ComputeColor();
+}
+
+SkColor TestAXNodeWrapper::GetBackgroundColor() const {
+ return node_->ComputeBackgroundColor();
+}
+
gfx::RectF TestAXNodeWrapper::GetLocation() const {
return GetData().relative_bounds.bounds;
}
diff --git a/chromium/ui/accessibility/platform/test_ax_node_wrapper.h b/chromium/ui/accessibility/platform/test_ax_node_wrapper.h
index 4cd51d5874c..506906c0cb8 100644
--- a/chromium/ui/accessibility/platform/test_ax_node_wrapper.h
+++ b/chromium/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -53,8 +53,7 @@ class TestAXNodeWrapper : public AXPlatformNodeDelegateBase {
// When a hit test is called on |src_node_id|, return |dst_node_id| as
// the result.
- static void SetHitTestResult(AXNode::AXID src_node_id,
- AXNode::AXID dst_node_id);
+ static void SetHitTestResult(AXNodeID src_node_id, AXNodeID dst_node_id);
~TestAXNodeWrapper() override;
@@ -93,7 +92,7 @@ class TestAXNodeWrapper : public AXPlatformNodeDelegateBase {
gfx::NativeViewAccessible HitTestSync(
int screen_physical_pixel_x,
int screen_physical_pixel_y) const override;
- gfx::NativeViewAccessible GetFocus() override;
+ gfx::NativeViewAccessible GetFocus() const override;
bool IsMinimized() const override;
bool IsWebContent() const override;
AXPlatformNode* GetFromNodeID(int32_t id) override;
@@ -145,6 +144,9 @@ class TestAXNodeWrapper : public AXPlatformNodeDelegateBase {
bool IsOrderedSet() const override;
base::Optional<int> GetPosInSet() const override;
base::Optional<int> GetSetSize() const override;
+ SkColor GetColor() const override;
+ SkColor GetBackgroundColor() const override;
+
const std::vector<gfx::NativeViewAccessible> GetUIADescendants()
const override;
gfx::RectF GetLocation() const;
diff --git a/chromium/ui/accessibility/platform/uia_registrar_win.cc b/chromium/ui/accessibility/platform/uia_registrar_win.cc
index bd6ca8f56aa..8a249afb485 100644
--- a/chromium/ui/accessibility/platform/uia_registrar_win.cc
+++ b/chromium/ui/accessibility/platform/uia_registrar_win.cc
@@ -5,6 +5,7 @@
#include "ui/accessibility/platform/uia_registrar_win.h"
#include <wrl/implements.h>
#include "base/stl_util.h"
+#include "ui/accessibility/accessibility_features.h"
namespace ui {
@@ -17,29 +18,46 @@ UiaRegistrarWin::UiaRegistrarWin() {
&registrar)))
return;
+ // Register the custom UIA event that represents the test end event for the
+ // UIA test suite.
+ UIAutomationEventInfo test_complete_event_info = {
+ kUiaEventTestCompleteSentinelGuid, L"kUiaTestCompleteSentinel"};
+ registrar->RegisterEvent(&test_complete_event_info, &test_complete_event_id_);
+
// Register the custom UIA property that represents the unique id of an UIA
// element which also matches its corresponding IA2 element's unique id.
UIAutomationPropertyInfo unique_id_property_info = {
kUiaPropertyUniqueIdGuid, L"UniqueId", UIAutomationType_String};
registrar->RegisterProperty(&unique_id_property_info,
- &uia_unique_id_property_id_);
+ &unique_id_property_id_);
- // Register the custom UIA event that represents the test end event for the
- // UIA test suite.
- UIAutomationEventInfo test_complete_event_info = {
- kUiaEventTestCompleteSentinelGuid, L"kUiaTestCompleteSentinel"};
- registrar->RegisterEvent(&test_complete_event_info,
- &uia_test_complete_event_id_);
+ if (features::IsAccessibilityAriaVirtualContentEnabled()) {
+ // Register the custom UIA property that represents the value for the
+ // 'aria-virtualcontent' attribute.
+ UIAutomationPropertyInfo virtual_content_property_info = {
+ kUiaPropertyVirtualContentGuid, L"VirtualContent",
+ UIAutomationType_String};
+ registrar->RegisterProperty(&virtual_content_property_info,
+ &virtual_content_property_id_);
+ }
}
UiaRegistrarWin::~UiaRegistrarWin() = default;
-PROPERTYID UiaRegistrarWin::GetUiaUniqueIdPropertyId() const {
- return uia_unique_id_property_id_;
+// UIA custom events.
+EVENTID UiaRegistrarWin::GetTestCompleteEventId() const {
+ return test_complete_event_id_;
+}
+
+// UIA custom properties.
+PROPERTYID UiaRegistrarWin::GetUniqueIdPropertyId() const {
+ return unique_id_property_id_;
}
-EVENTID UiaRegistrarWin::GetUiaTestCompleteEventId() const {
- return uia_test_complete_event_id_;
+PROPERTYID UiaRegistrarWin::GetVirtualContentPropertyId() const {
+ if (!features::IsAccessibilityAriaVirtualContentEnabled())
+ return 0;
+ return virtual_content_property_id_;
}
const UiaRegistrarWin& UiaRegistrarWin::GetInstance() {
diff --git a/chromium/ui/accessibility/platform/uia_registrar_win.h b/chromium/ui/accessibility/platform/uia_registrar_win.h
index 53c8da4fe37..a477ef3e799 100644
--- a/chromium/ui/accessibility/platform/uia_registrar_win.h
+++ b/chromium/ui/accessibility/platform/uia_registrar_win.h
@@ -12,6 +12,9 @@
#include "ui/accessibility/ax_export.h"
namespace ui {
+
+// UIA custom events.
+
// {3761326A-34B2-465A-835D-7A3D8F4EFB92}
static const GUID kUiaEventTestCompleteSentinelGuid = {
0x3761326a,
@@ -19,6 +22,8 @@ static const GUID kUiaEventTestCompleteSentinelGuid = {
0x465a,
{0x83, 0x5d, 0x7a, 0x3d, 0x8f, 0x4e, 0xfb, 0x92}};
+// UIA custom properties.
+
// {cc7eeb32-4b62-4f4c-aff6-1c2e5752ad8e}
static const GUID kUiaPropertyUniqueIdGuid = {
0xcc7eeb32,
@@ -26,18 +31,34 @@ static const GUID kUiaPropertyUniqueIdGuid = {
0x4f4c,
{0xaf, 0xf6, 0x1c, 0x2e, 0x57, 0x52, 0xad, 0x8e}};
+// {28A68D78-3EA6-4FE4-B7C6-1E0F089A72A5}
+static const GUID kUiaPropertyVirtualContentGuid = {
+ 0x28A68D78,
+ 0x3EA6,
+ 0x4FE4,
+ {0xB7, 0xC6, 0x1E, 0x0F, 0x08, 0x9A, 0x72, 0xA5}};
+
class AX_EXPORT UiaRegistrarWin {
public:
UiaRegistrarWin();
~UiaRegistrarWin();
- PROPERTYID GetUiaUniqueIdPropertyId() const;
- EVENTID GetUiaTestCompleteEventId() const;
+
+ // UIA custom events.
+ EVENTID GetTestCompleteEventId() const;
+
+ // UIA custom properties.
+ PROPERTYID GetUniqueIdPropertyId() const;
+ PROPERTYID GetVirtualContentPropertyId() const;
static const UiaRegistrarWin& GetInstance();
private:
- PROPERTYID uia_unique_id_property_id_ = 0;
- EVENTID uia_test_complete_event_id_ = 0;
+ // UIA custom events.
+ EVENTID test_complete_event_id_ = 0;
+
+ // UIA custom properties.
+ PROPERTYID unique_id_property_id_ = 0;
+ PROPERTYID virtual_content_property_id_ = 0;
};
} // namespace ui
diff --git a/chromium/ui/accessibility/test_ax_node_helper.cc b/chromium/ui/accessibility/test_ax_node_helper.cc
index a2cfcf0f114..b7e85af537a 100644
--- a/chromium/ui/accessibility/test_ax_node_helper.cc
+++ b/chromium/ui/accessibility/test_ax_node_helper.cc
@@ -21,13 +21,13 @@ namespace ui {
namespace {
// A global map from AXNodes to TestAXNodeHelpers.
-std::map<AXNode::AXID, TestAXNodeHelper*> g_node_id_to_helper_map;
+std::map<AXNodeID, TestAXNodeHelper*> g_node_id_to_helper_map;
// A simple implementation of AXTreeObserver to catch when AXNodes are
// deleted so we can delete their helpers.
class TestAXTreeObserver : public AXTreeObserver {
private:
- void OnNodeDeleted(AXTree* tree, int32_t node_id) override {
+ void OnNodeDeleted(AXTree* tree, AXNodeID node_id) override {
const auto iter = g_node_id_to_helper_map.find(node_id);
if (iter != g_node_id_to_helper_map.end()) {
TestAXNodeHelper* helper = iter->second;
diff --git a/chromium/ui/accessibility/test_ax_tree_manager.cc b/chromium/ui/accessibility/test_ax_tree_manager.cc
index 70d872d8efc..15627a47248 100644
--- a/chromium/ui/accessibility/test_ax_tree_manager.cc
+++ b/chromium/ui/accessibility/test_ax_tree_manager.cc
@@ -14,7 +14,27 @@ TestAXTreeManager::TestAXTreeManager() = default;
TestAXTreeManager::TestAXTreeManager(std::unique_ptr<AXTree> tree)
: tree_(std::move(tree)) {
- AXTreeManagerMap::GetInstance().AddTreeManager(GetTreeID(), this);
+ if (tree_)
+ AXTreeManagerMap::GetInstance().AddTreeManager(GetTreeID(), this);
+}
+
+TestAXTreeManager::TestAXTreeManager(TestAXTreeManager&& manager)
+ : tree_(std::move(manager.tree_)) {
+ if (tree_) {
+ AXTreeManagerMap::GetInstance().RemoveTreeManager(GetTreeID());
+ AXTreeManagerMap::GetInstance().AddTreeManager(GetTreeID(), this);
+ }
+}
+
+TestAXTreeManager& TestAXTreeManager::operator=(TestAXTreeManager&& manager) {
+ if (this == &manager)
+ return *this;
+ if (manager.tree_)
+ AXTreeManagerMap::GetInstance().RemoveTreeManager(manager.GetTreeID());
+ // std::move(nullptr) == nullptr, so no need to check if `manager.tree_` is
+ // assigned.
+ SetTree(std::move(manager.tree_));
+ return *this;
}
TestAXTreeManager::~TestAXTreeManager() {
@@ -40,16 +60,17 @@ void TestAXTreeManager::SetTree(std::unique_ptr<AXTree> tree) {
AXTreeManagerMap::GetInstance().RemoveTreeManager(GetTreeID());
tree_ = std::move(tree);
- AXTreeManagerMap::GetInstance().AddTreeManager(GetTreeID(), this);
+ if (tree_)
+ AXTreeManagerMap::GetInstance().AddTreeManager(GetTreeID(), this);
}
AXNode* TestAXTreeManager::GetNodeFromTree(const AXTreeID tree_id,
- const AXNode::AXID node_id) const {
+ const AXNodeID node_id) const {
return (tree_ && GetTreeID() == tree_id) ? tree_->GetFromId(node_id)
: nullptr;
}
-AXNode* TestAXTreeManager::GetNodeFromTree(const AXNode::AXID node_id) const {
+AXNode* TestAXTreeManager::GetNodeFromTree(const AXNodeID node_id) const {
return tree_ ? tree_->GetFromId(node_id) : nullptr;
}
@@ -76,17 +97,17 @@ AXNode* TestAXTreeManager::GetRootAsAXNode() const {
}
AXNode* TestAXTreeManager::GetParentNodeFromParentTreeAsAXNode() const {
- ui::AXTreeID parent_tree_id = GetParentTreeID();
+ AXTreeID parent_tree_id = GetParentTreeID();
TestAXTreeManager* parent_manager = static_cast<TestAXTreeManager*>(
- ui::AXTreeManagerMap::GetInstance().GetManager(parent_tree_id));
+ AXTreeManagerMap::GetInstance().GetManager(parent_tree_id));
if (!parent_manager)
return nullptr;
- std::set<int32_t> host_node_ids =
+ std::set<AXNodeID> host_node_ids =
parent_manager->GetTree()->GetNodeIdsForChildTreeId(GetTreeID());
- for (int32_t host_node_id : host_node_ids) {
- ui::AXNode* parent_node =
+ for (AXNodeID host_node_id : host_node_ids) {
+ AXNode* parent_node =
parent_manager->GetNodeFromTree(parent_tree_id, host_node_id);
if (parent_node)
return parent_node;
diff --git a/chromium/ui/accessibility/test_ax_tree_manager.h b/chromium/ui/accessibility/test_ax_tree_manager.h
index 117f020d062..36690c45301 100644
--- a/chromium/ui/accessibility/test_ax_tree_manager.h
+++ b/chromium/ui/accessibility/test_ax_tree_manager.h
@@ -34,6 +34,9 @@ class TestAXTreeManager : public AXTreeManager {
TestAXTreeManager(const TestAXTreeManager& manager) = delete;
TestAXTreeManager& operator=(const TestAXTreeManager& manager) = delete;
+ TestAXTreeManager(TestAXTreeManager&& manager);
+ TestAXTreeManager& operator=(TestAXTreeManager&& manager);
+
void DestroyTree();
AXTree* GetTree() const;
// Takes ownership of |tree|.
@@ -41,8 +44,8 @@ class TestAXTreeManager : public AXTreeManager {
// AXTreeManager implementation.
AXNode* GetNodeFromTree(const AXTreeID tree_id,
- const AXNode::AXID node_id) const override;
- AXNode* GetNodeFromTree(const AXNode::AXID node_id) const override;
+ const AXNodeID node_id) const override;
+ AXNode* GetNodeFromTree(const AXNodeID node_id) const override;
void AddObserver(AXTreeObserver* observer) override;
void RemoveObserver(AXTreeObserver* observer) override;
AXTreeID GetTreeID() const override;
diff --git a/chromium/ui/android/BUILD.gn b/chromium/ui/android/BUILD.gn
index 780d7d57605..ad00a4dc7e1 100644
--- a/chromium/ui/android/BUILD.gn
+++ b/chromium/ui/android/BUILD.gn
@@ -13,6 +13,8 @@ component("android") {
output_name = "ui_android"
sources = [
"animation_utils.h",
+ "color_helpers.cc",
+ "color_helpers.h",
"delegated_frame_host_android.cc",
"delegated_frame_host_android.h",
"display_android_manager.cc",
@@ -145,6 +147,7 @@ android_resources("ui_java_resources") {
"java/res/color/chip_stroke_color.xml",
"java/res/color/chip_text_color.xml",
"java/res/color/chip_text_color_secondary.xml",
+ "java/res/color/default_text_color_hint_list.xml",
"java/res/color/default_text_color_inverse_list.xml",
"java/res/color/default_text_color_light_list.xml",
"java/res/color/default_text_color_list.xml",
@@ -225,10 +228,10 @@ android_library("ui_utils_java") {
]
deps = [
"//base:base_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
- "//third_party/android_deps:androidx_appcompat_appcompat_java",
- "//third_party/android_deps:androidx_appcompat_appcompat_resources_java",
- "//third_party/android_deps:androidx_core_core_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ "//third_party/androidx:androidx_appcompat_appcompat_java",
+ "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
+ "//third_party/androidx:androidx_core_core_java",
]
}
@@ -276,6 +279,7 @@ android_library("ui_no_recycler_view_java") {
"java/src/org/chromium/ui/base/ViewAndroidDelegate.java",
"java/src/org/chromium/ui/base/ViewUtils.java",
"java/src/org/chromium/ui/base/WindowAndroid.java",
+ "java/src/org/chromium/ui/base/WindowDelegate.java",
"java/src/org/chromium/ui/display/DisplayAndroid.java",
"java/src/org/chromium/ui/display/DisplayAndroidManager.java",
"java/src/org/chromium/ui/display/DisplaySwitches.java",
@@ -316,7 +320,6 @@ android_library("ui_no_recycler_view_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",
- "java/src/org/chromium/ui/resources/ResourceExtractor.java",
"java/src/org/chromium/ui/resources/ResourceFactory.java",
"java/src/org/chromium/ui/resources/ResourceLoader.java",
"java/src/org/chromium/ui/resources/ResourceManager.java",
@@ -359,13 +362,14 @@ android_library("ui_no_recycler_view_java") {
":ui_utils_java",
"//base:base_java",
"//base:jni_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
- "//third_party/android_deps:androidx_appcompat_appcompat_java",
- "//third_party/android_deps:androidx_appcompat_appcompat_resources_java",
- "//third_party/android_deps:androidx_asynclayoutinflater_asynclayoutinflater_java",
- "//third_party/android_deps:androidx_core_core_java",
- "//third_party/android_deps:androidx_vectordrawable_vectordrawable_animated_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ "//third_party/androidx:androidx_appcompat_appcompat_java",
+ "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
+ "//third_party/androidx:androidx_asynclayoutinflater_asynclayoutinflater_java",
+ "//third_party/androidx:androidx_core_core_java",
+ "//third_party/androidx:androidx_vectordrawable_vectordrawable_animated_java",
"//ui/base/cursor/mojom:cursor_type_java",
+ "//url:gurl_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
srcjar_deps = [ ":java_enums_srcjar" ]
@@ -382,8 +386,8 @@ android_library("ui_recycler_view_java") {
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
deps = [
":ui_no_recycler_view_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
- "//third_party/android_deps:androidx_recyclerview_recyclerview_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ "//third_party/androidx:androidx_recyclerview_recyclerview_java",
]
}
@@ -414,8 +418,9 @@ android_library("ui_java_test_support") {
"//base:base_java",
"//base:base_java_test_support",
"//third_party/android_deps:android_support_v7_appcompat_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
"//third_party/android_support_test_runner:rules_java",
+ "//third_party/android_support_test_runner:runner_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
"//third_party/junit",
]
}
@@ -469,15 +474,17 @@ junit_binary("ui_junit_tests") {
"//base:base_java_test_support",
"//base:base_junit_test_support",
"//base/test:test_support_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
- "//third_party/android_deps:androidx_appcompat_appcompat_java",
- "//third_party/android_deps:androidx_appcompat_appcompat_resources_java",
- "//third_party/android_deps:androidx_asynclayoutinflater_asynclayoutinflater_java",
- "//third_party/android_deps:androidx_test_core_java",
- "//third_party/android_deps:androidx_test_ext_junit_java",
- "//third_party/android_deps:androidx_test_runner_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ "//third_party/androidx:androidx_appcompat_appcompat_java",
+ "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
+ "//third_party/androidx:androidx_asynclayoutinflater_asynclayoutinflater_java",
+ "//third_party/androidx:androidx_test_core_java",
+ "//third_party/androidx:androidx_test_ext_junit_java",
+ "//third_party/androidx:androidx_test_runner_java",
"//third_party/hamcrest:hamcrest_java",
"//third_party/mockito:mockito_java",
+ "//url:gurl_java",
+ "//url:gurl_junit_test_support",
]
android_manifest = "junit/AndroidManifest.xml"
}
@@ -487,6 +494,7 @@ test("ui_android_unittests") {
# Clipboard unittests are run here for Android as gtests on Android are not
# sharded. On other OSs these are run as part of interactive_ui_tests.
"//ui/base/clipboard/clipboard_unittest.cc",
+ "color_helpers_unittest.cc",
"overscroll_refresh_unittest.cc",
"resources/resource_manager_impl_unittest.cc",
"run_all_unittests.cc",
@@ -542,7 +550,7 @@ android_library("ui_javatests") {
"//base:base_java_test_support",
"//base:jni_java",
"//content/public/test/android:content_java_test_support",
- "//third_party/android_deps:androidx_test_runner_java",
+ "//third_party/androidx:androidx_test_runner_java",
"//third_party/junit",
]
}
diff --git a/chromium/ui/android/OWNERS b/chromium/ui/android/OWNERS
index 3dce3d6e3fc..2d96ba4cb79 100644
--- a/chromium/ui/android/OWNERS
+++ b/chromium/ui/android/OWNERS
@@ -8,6 +8,3 @@ jaekyun@chromium.org
# for display/window/view_android
boliu@chromium.org
jinsukkim@chromium.org
-
-# for CC and Viz integration
-khushalsagar@chromium.org
diff --git a/chromium/ui/android/color_helpers.cc b/chromium/ui/android/color_helpers.cc
new file mode 100644
index 00000000000..e110e6a8389
--- /dev/null
+++ b/chromium/ui/android/color_helpers.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/android/color_helpers.h"
+
+#include "base/check.h"
+#include "base/numerics/safe_math.h"
+#include "ui/gfx/color_utils.h"
+
+namespace ui {
+
+std::string OptionalSkColorToString(const base::Optional<SkColor>& color) {
+ if (!color)
+ return std::string();
+ return color_utils::SkColorToRgbaString(*color);
+}
+
+int64_t OptionalSkColorToJavaColor(const base::Optional<SkColor>& skcolor) {
+ if (!skcolor)
+ return kInvalidJavaColor;
+ return static_cast<int32_t>(*skcolor);
+}
+
+base::Optional<SkColor> JavaColorToOptionalSkColor(int64_t java_color) {
+ if (java_color == kInvalidJavaColor)
+ return base::nullopt;
+ DCHECK(base::IsValueInRangeForNumericType<int32_t>(java_color));
+ return static_cast<SkColor>(java_color);
+}
+
+} // namespace ui
diff --git a/chromium/ui/android/color_helpers.h b/chromium/ui/android/color_helpers.h
new file mode 100644
index 00000000000..6b12d90abf6
--- /dev/null
+++ b/chromium/ui/android/color_helpers.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ANDROID_COLOR_HELPERS_H_
+#define UI_ANDROID_COLOR_HELPERS_H_
+
+#include <stdint.h>
+
+#include <limits>
+#include <string>
+
+#include "base/optional.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/android/ui_android_export.h"
+
+namespace ui {
+
+UI_ANDROID_EXPORT constexpr int64_t kInvalidJavaColor =
+ static_cast<int64_t>(std::numeric_limits<int32_t>::max()) + 1;
+
+// Converts |color| to a CSS color string. If |color| is null, the empty string
+// is returned.
+UI_ANDROID_EXPORT std::string OptionalSkColorToString(
+ const base::Optional<SkColor>& color);
+
+// Conversions between a Java color and an Optional<SkColor>. Java colors are
+// represented as 64-bit signed integers. Valid colors are in the range
+// [std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max()].
+// while |kInvalidJavaColor| is reserved for representing a null/unset color.
+UI_ANDROID_EXPORT int64_t
+OptionalSkColorToJavaColor(const base::Optional<SkColor>& skcolor);
+UI_ANDROID_EXPORT base::Optional<SkColor> JavaColorToOptionalSkColor(
+ int64_t java_color);
+
+} // namespace ui
+
+#endif // UI_ANDROID_COLOR_HELPERS_H_
diff --git a/chromium/ui/android/color_helpers_unittest.cc b/chromium/ui/android/color_helpers_unittest.cc
new file mode 100644
index 00000000000..4ad4e1e69c3
--- /dev/null
+++ b/chromium/ui/android/color_helpers_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/android/color_helpers.h"
+
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/optional.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace ui {
+
+namespace {
+
+// Intentionally avoids reusing the constant defined in color_helpers.h to catch
+// mistakes that accidentally change the value.
+constexpr int64_t kAndroidInvalidColor =
+ static_cast<int64_t>(std::numeric_limits<int32_t>::max()) + 1;
+
+// https://developer.android.com/reference/android/graphics/Color.html defines
+// the various color constants.
+constexpr int kAndroidBlack = -16777216;
+constexpr int kAndroidWhite = -1;
+constexpr int kAndroidRed = -65536;
+constexpr int kAndroidDkgray = -12303292;
+constexpr int kAndroidTransparent = 0;
+
+} // namespace
+
+TEST(ColorHelpersTest, Null) {
+ EXPECT_EQ(kAndroidInvalidColor, OptionalSkColorToJavaColor(base::nullopt));
+ EXPECT_FALSE(JavaColorToOptionalSkColor(kAndroidInvalidColor).has_value());
+}
+
+TEST(ColorHelpersTest, Roundtrip) {
+ EXPECT_EQ(kAndroidBlack, OptionalSkColorToJavaColor(SK_ColorBLACK));
+ EXPECT_EQ(SK_ColorBLACK, JavaColorToOptionalSkColor(kAndroidBlack));
+
+ EXPECT_EQ(kAndroidWhite, OptionalSkColorToJavaColor(SK_ColorWHITE));
+ EXPECT_EQ(SK_ColorWHITE, JavaColorToOptionalSkColor(kAndroidWhite));
+
+ EXPECT_EQ(kAndroidRed, OptionalSkColorToJavaColor(SK_ColorRED));
+ EXPECT_EQ(SK_ColorRED, JavaColorToOptionalSkColor(kAndroidRed));
+
+ EXPECT_EQ(kAndroidDkgray, OptionalSkColorToJavaColor(SK_ColorDKGRAY));
+ EXPECT_EQ(SK_ColorDKGRAY, JavaColorToOptionalSkColor(kAndroidDkgray));
+
+ EXPECT_EQ(kAndroidTransparent,
+ OptionalSkColorToJavaColor(SK_ColorTRANSPARENT));
+ EXPECT_EQ(SK_ColorTRANSPARENT,
+ JavaColorToOptionalSkColor(kAndroidTransparent));
+}
+
+} // namespace ui
diff --git a/chromium/ui/android/delegated_frame_host_android.cc b/chromium/ui/android/delegated_frame_host_android.cc
index cb488cb8593..856c0f56933 100644
--- a/chromium/ui/android/delegated_frame_host_android.cc
+++ b/chromium/ui/android/delegated_frame_host_android.cc
@@ -158,10 +158,24 @@ bool DelegatedFrameHostAndroid::CanCopyFromCompositingSurface() const {
void DelegatedFrameHostAndroid::EvictDelegatedFrame() {
content_layer_->SetSurfaceId(viz::SurfaceId(),
cc::DeadlinePolicy::UseDefaultDeadline());
- if (!HasSavedFrame() || frame_evictor_->visible())
+ std::vector<viz::SurfaceId> surface_ids;
+ // If we have a surface from before a navigation, evict it, regardless of
+ // visibility state.
+ if (pre_navigation_local_surface_id_.is_valid()) {
+ viz::SurfaceId pre_nav =
+ viz::SurfaceId(frame_sink_id_, pre_navigation_local_surface_id_);
+ surface_ids.push_back(pre_nav);
+ } else if (!HasSavedFrame() || frame_evictor_->visible()) {
+ return;
+ }
+
+ if (local_surface_id_.is_valid()) {
+ viz::SurfaceId current = viz::SurfaceId(frame_sink_id_, local_surface_id_);
+ surface_ids.push_back(current);
+ }
+
+ if (surface_ids.empty())
return;
- std::vector<viz::SurfaceId> surface_ids = {
- viz::SurfaceId(frame_sink_id_, local_surface_id_)};
host_frame_sink_manager_->EvictSurfaces(surface_ids);
frame_evictor_->OnSurfaceDiscarded();
// When surface sync is on, this call will force |client_| to allocate a new
@@ -183,6 +197,14 @@ void DelegatedFrameHostAndroid::ResetFallbackToFirstNavigationSurface() {
.IsSameOrNewerThan(first_local_surface_id_after_navigation_)) {
return;
}
+
+ // If we have a surface from before a navigation, evict it as well.
+ if (pre_navigation_local_surface_id_.is_valid() &&
+ !first_local_surface_id_after_navigation_.is_valid()) {
+ EvictDelegatedFrame();
+ content_layer_->SetBackgroundColor(SK_ColorTRANSPARENT);
+ }
+
content_layer_->SetOldestAcceptableFallback(
viz::SurfaceId(frame_sink_id_, first_local_surface_id_after_navigation_));
}
@@ -246,7 +268,20 @@ void DelegatedFrameHostAndroid::EmbedSurface(
// at serialization time.
CHECK(new_local_surface_id.is_valid());
+ // Confirm that there is a valid fallback surface on, otherwise we need to
+ // adjust deadline times. To avoid displaying invalid content.
+ bool has_fallback_surface =
+ (content_layer_->oldest_acceptable_fallback() &&
+ content_layer_->oldest_acceptable_fallback()->is_valid());
local_surface_id_ = new_local_surface_id;
+ // The embedding of a new surface completes the navigation process.
+ pre_navigation_local_surface_id_ = viz::LocalSurfaceId();
+ // Navigations performed while hidden delay embedding until transitioning to
+ // becoming visible. So we may not have a valid surace when DidNavigate is
+ // called. Cache the first surface here so we have the correct oldest surface
+ // to fallback to.
+ if (!first_local_surface_id_after_navigation_.is_valid())
+ first_local_surface_id_after_navigation_ = local_surface_id_;
surface_size_in_pixels_ = new_size_in_pixels;
viz::SurfaceId current_primary_surface_id = content_layer_->surface_id();
@@ -258,8 +293,7 @@ void DelegatedFrameHostAndroid::EmbedSurface(
// screen if renderer won't submit frame in time. See
// https://crbug.com/1088369 and https://crbug.com/813157
if (surface_size_in_pixels_ != content_layer_->bounds() &&
- content_layer_->oldest_acceptable_fallback() &&
- content_layer_->oldest_acceptable_fallback()->is_valid()) {
+ has_fallback_surface) {
content_layer_->SetOldestAcceptableFallback(new_primary_surface_id);
// We default to black background for fullscreen case.
@@ -293,6 +327,11 @@ void DelegatedFrameHostAndroid::EmbedSurface(
deadline_policy = cc::DeadlinePolicy::UseSpecifiedDeadline(0u);
}
}
+ // If there is not a valid current surface, nor a valid fallback, we want to
+ // produce new content as soon as possible. To avoid displaying invalide
+ // content, such as surfaces from before a navigation.
+ if (!has_fallback_surface)
+ deadline_policy = cc::DeadlinePolicy::UseSpecifiedDeadline(0u);
content_layer_->SetSurfaceId(new_primary_surface_id, deadline_policy);
content_layer_->SetBounds(new_size_in_pixels);
}
@@ -303,8 +342,10 @@ void DelegatedFrameHostAndroid::OnFirstSurfaceActivation(
NOTREACHED();
}
-void DelegatedFrameHostAndroid::OnFrameTokenChanged(uint32_t frame_token) {
- client_->OnFrameTokenChanged(frame_token);
+void DelegatedFrameHostAndroid::OnFrameTokenChanged(
+ uint32_t frame_token,
+ base::TimeTicks activation_time) {
+ client_->OnFrameTokenChanged(frame_token, activation_time);
}
viz::SurfaceId DelegatedFrameHostAndroid::SurfaceId() const {
@@ -343,6 +384,18 @@ void DelegatedFrameHostAndroid::DidNavigate() {
first_local_surface_id_after_navigation_ = local_surface_id_;
}
+void DelegatedFrameHostAndroid::OnNavigateToNewPage() {
+ // We are navigating to a different page, so the current |local_surface_id_|
+ // and the fallback option of |first_local_surface_id_after_navigation_| are
+ // no longer valid, as they represent older content from a different source.
+ //
+ // Cache the current |local_surface_id_| so that if navigation fails we can
+ // evict it when transitioning to becoming visible.
+ pre_navigation_local_surface_id_ = local_surface_id_;
+ first_local_surface_id_after_navigation_ = viz::LocalSurfaceId();
+ local_surface_id_ = viz::LocalSurfaceId();
+}
+
void DelegatedFrameHostAndroid::SetTopControlsVisibleHeight(float height) {
if (top_controls_visible_height_ == height)
return;
diff --git a/chromium/ui/android/delegated_frame_host_android.h b/chromium/ui/android/delegated_frame_host_android.h
index fcea61c10b7..b8ae91290ac 100644
--- a/chromium/ui/android/delegated_frame_host_android.h
+++ b/chromium/ui/android/delegated_frame_host_android.h
@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/numerics/safe_conversions.h"
+#include "base/time/time.h"
#include "cc/layers/deadline_policy.h"
#include "components/viz/client/frame_evictor.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
@@ -38,7 +39,8 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
class Client {
public:
virtual ~Client() {}
- virtual void OnFrameTokenChanged(uint32_t frame_token) = 0;
+ virtual void OnFrameTokenChanged(uint32_t frame_token,
+ base::TimeTicks activation_time) = 0;
virtual void WasEvicted() = 0;
};
@@ -121,7 +123,15 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
void TakeFallbackContentFrom(DelegatedFrameHostAndroid* other);
+ // Called when navigation has completed, and this DelegatedFrameHost is
+ // visible. A new Surface will have been embedded at this point. If navigation
+ // is done while hidden, this will be called upon becoming visible.
void DidNavigate();
+ // Navigation to a different page than the current one has begun. This is
+ // called regardless of the visibility of the page. Caches the current
+ // LocalSurfaceId information so that old content can be evicted if
+ // navigation fails to complete.
+ void OnNavigateToNewPage();
void SetTopControlsVisibleHeight(float height);
@@ -131,7 +141,8 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
// viz::HostFrameSinkClient implementation.
void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
- void OnFrameTokenChanged(uint32_t frame_token) override;
+ void OnFrameTokenChanged(uint32_t frame_token,
+ base::TimeTicks activation_time) override;
void ProcessCopyOutputRequest(
std::unique_ptr<viz::CopyOutputRequest> request);
@@ -151,6 +162,10 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
// Whether we've received a frame from the renderer since navigating.
// Only used when surface synchronization is on.
viz::LocalSurfaceId first_local_surface_id_after_navigation_;
+ // While navigating we have no active |local_surface_id_|. Track the one from
+ // before a navigation, because if the navigation fails to complete, we will
+ // need to evict its surface.
+ viz::LocalSurfaceId pre_navigation_local_surface_id_;
// The LocalSurfaceId of the currently embedded surface. If surface sync is
// on, this surface is not necessarily active.
diff --git a/chromium/ui/android/junit/src/org/chromium/ui/base/ActivityAndroidPermissionDelegateTest.java b/chromium/ui/android/junit/src/org/chromium/ui/base/ActivityAndroidPermissionDelegateTest.java
index 1df70151bcb..fe8bd9e38ad 100644
--- a/chromium/ui/android/junit/src/org/chromium/ui/base/ActivityAndroidPermissionDelegateTest.java
+++ b/chromium/ui/android/junit/src/org/chromium/ui/base/ActivityAndroidPermissionDelegateTest.java
@@ -12,6 +12,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.content.pm.PackageManager;
+import android.os.Build;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
@@ -170,23 +171,63 @@ public class ActivityAndroidPermissionDelegateTest {
}
@Test
- public void testCanRequestPermissionAfterRequestDenied() {
+ public void
+ testCanRequestPermissionRequestDenied_shouldNotShowRationale_prevShouldShowRationale() {
mActivityScenarios.getScenario().onActivity(activity -> {
AndroidPermissionDelegate permissionDelegate =
new ActivityAndroidPermissionDelegate(new WeakReference(activity));
+ Shadows.shadowOf(activity.getPackageManager())
+ .setShouldShowRequestPermissionRationale(
+ android.Manifest.permission.INTERNET, true);
performRequestPermission(permissionDelegate, Shadows.shadowOf(activity),
android.Manifest.permission.INTERNET, PackageManager.PERMISSION_DENIED);
-
+ Shadows.shadowOf(activity.getPackageManager())
+ .setShouldShowRequestPermissionRationale(
+ android.Manifest.permission.INTERNET, false);
boolean canRequest =
permissionDelegate.canRequestPermission(android.Manifest.permission.INTERNET);
assertFalse(
- "After a denied permission request canRequestPermission should return false",
+ "After a denied permission request canRequestPermission should return false "
+ + "if shouldShowRequestPermissionRationale returns false after "
+ + "previously returning true",
canRequest);
});
}
@Test
+ public void
+ testCanRequestPermissionRequestDenied_shouldNotShowRationale_prevShouldNotShowRationale() {
+ mActivityScenarios.getScenario().onActivity(activity -> {
+ AndroidPermissionDelegate permissionDelegate =
+ new ActivityAndroidPermissionDelegate(new WeakReference(activity));
+ Shadows.shadowOf(activity.getPackageManager())
+ .setShouldShowRequestPermissionRationale(
+ android.Manifest.permission.INTERNET, false);
+ performRequestPermission(permissionDelegate, Shadows.shadowOf(activity),
+ android.Manifest.permission.INTERNET, PackageManager.PERMISSION_DENIED);
+ Shadows.shadowOf(activity.getPackageManager())
+ .setShouldShowRequestPermissionRationale(
+ android.Manifest.permission.INTERNET, false);
+ boolean canRequest =
+ permissionDelegate.canRequestPermission(android.Manifest.permission.INTERNET);
+
+ if (Build.VERSION.SDK_INT < 30 /*Build.VERSION_CODES.R*/) {
+ assertFalse("After a denied permission request canRequestPermission should return "
+ + "false if shouldShowRequestPermissionRationale returns false",
+ canRequest);
+ } else {
+ // This can happen in Android.R>= when a user dismissed permission dialog before
+ // taking any action.
+ assertTrue("After a denied permission request canRequestPermission should return "
+ + "true if shouldShowRequestPermissionRationale returns false "
+ + "after previously returning false",
+ canRequest);
+ }
+ });
+ }
+
+ @Test
public void testCanRequestPermissionWithShowRequestRationale() {
mActivityScenarios.getScenario().onActivity(activity -> {
AndroidPermissionDelegate permissionDelegate =
diff --git a/chromium/ui/android/junit/src/org/chromium/ui/base/ClipboardTest.java b/chromium/ui/android/junit/src/org/chromium/ui/base/ClipboardTest.java
index 22e430bd774..19c278826da 100644
--- a/chromium/ui/android/junit/src/org/chromium/ui/base/ClipboardTest.java
+++ b/chromium/ui/android/junit/src/org/chromium/ui/base/ClipboardTest.java
@@ -28,6 +28,7 @@ import org.chromium.base.ContentUriUtils;
import org.chromium.base.StreamUtil;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.UrlUtils;
+import org.chromium.url.JUnitTestGURLs;
import java.io.File;
import java.io.FileOutputStream;
@@ -111,8 +112,8 @@ public class ClipboardTest {
ClipboardManager clipboardManager = Mockito.mock(ClipboardManager.class);
clipboard.overrideClipboardManagerForTesting(clipboardManager);
- String url = "https://google.com";
- clipboard.copyUrlToClipboard(url);
+ String url = JUnitTestGURLs.SEARCH_URL;
+ clipboard.copyUrlToClipboard(JUnitTestGURLs.getGURL(url));
ArgumentCaptor<ClipData> clipCaptor = ArgumentCaptor.forClass(ClipData.class);
verify(clipboardManager).setPrimaryClip(clipCaptor.capture());
@@ -127,8 +128,8 @@ public class ClipboardTest {
clipboard.overrideClipboardManagerForTesting(clipboardManager);
doThrow(SecurityException.class).when(clipboardManager).setPrimaryClip(any(ClipData.class));
- String url = "https://google.com";
- clipboard.copyUrlToClipboard(url);
+ String url = JUnitTestGURLs.SEARCH_URL;
+ clipboard.copyUrlToClipboard(JUnitTestGURLs.getGURL(url));
ArgumentCaptor<ClipData> clipCaptor = ArgumentCaptor.forClass(ClipData.class);
verify(clipboardManager).setPrimaryClip(clipCaptor.capture());
diff --git a/chromium/ui/android/overscroll_glow.cc b/chromium/ui/android/overscroll_glow.cc
index b20b433bb63..3b6d9b7d3ad 100644
--- a/chromium/ui/android/overscroll_glow.cc
+++ b/chromium/ui/android/overscroll_glow.cc
@@ -44,6 +44,7 @@ OverscrollGlow::OverscrollGlow(OverscrollGlowClient* client)
OverscrollGlow::~OverscrollGlow() {
Detach();
+ client_ = nullptr;
}
void OverscrollGlow::Reset() {
@@ -193,6 +194,9 @@ bool OverscrollGlow::InitializeIfNecessary() {
if (initialized_)
return true;
+ if (client_ == nullptr)
+ return false;
+
DCHECK(!root_layer_.get());
root_layer_ = cc::Layer::Create();
for (size_t i = 0; i < EDGE_COUNT; ++i) {
diff --git a/chromium/ui/android/overscroll_glow.h b/chromium/ui/android/overscroll_glow.h
index e00d4fc1eee..665dc9ee643 100644
--- a/chromium/ui/android/overscroll_glow.h
+++ b/chromium/ui/android/overscroll_glow.h
@@ -95,7 +95,7 @@ class UI_ANDROID_EXPORT OverscrollGlow {
EdgeEffect* GetOppositeEdge(int edge_index);
- OverscrollGlowClient* const client_;
+ OverscrollGlowClient* client_;
std::unique_ptr<EdgeEffect> edge_effects_[EDGE_COUNT];
gfx::SizeF viewport_size_;
diff --git a/chromium/ui/android/view_android.cc b/chromium/ui/android/view_android.cc
index 90b6b8c1f4f..e89265babbf 100644
--- a/chromium/ui/android/view_android.cc
+++ b/chromium/ui/android/view_android.cc
@@ -11,7 +11,7 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/containers/adapters.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "cc/layers/layer.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chromium/ui/android/window_android.cc b/chromium/ui/android/window_android.cc
index b1aa28f4428..ae0f86f9c5c 100644
--- a/chromium/ui/android/window_android.cc
+++ b/chromium/ui/android/window_android.cc
@@ -147,9 +147,6 @@ std::vector<float> WindowAndroid::GetSupportedRefreshRates() {
}
void WindowAndroid::SetPreferredRefreshRate(float refresh_rate) {
- if (force_60hz_refresh_rate_)
- return;
-
if (test_hooks_) {
test_hooks_->SetPreferredRate(refresh_rate);
return;
@@ -204,7 +201,6 @@ void WindowAndroid::OnUpdateRefreshRate(
float refresh_rate) {
if (compositor_)
compositor_->OnUpdateRefreshRate(refresh_rate);
- Force60HzRefreshRateIfNeeded();
}
void WindowAndroid::OnSupportedRefreshRatesUpdated(
@@ -218,8 +214,6 @@ void WindowAndroid::OnSupportedRefreshRatesUpdated(
}
if (compositor_)
compositor_->OnUpdateSupportedRefreshRates(supported_refresh_rates);
-
- Force60HzRefreshRateIfNeeded();
}
void WindowAndroid::SetWideColorEnabled(bool enabled) {
@@ -227,28 +221,6 @@ void WindowAndroid::SetWideColorEnabled(bool enabled) {
Java_WindowAndroid_setWideColorEnabled(env, GetJavaObject(), enabled);
}
-void WindowAndroid::SetForce60HzRefreshRate() {
- if (force_60hz_refresh_rate_)
- return;
-
- force_60hz_refresh_rate_ = true;
- Force60HzRefreshRateIfNeeded();
-}
-
-void WindowAndroid::Force60HzRefreshRateIfNeeded() {
- if (!force_60hz_refresh_rate_)
- return;
-
- JNIEnv* env = AttachCurrentThread();
- Java_WindowAndroid_setPreferredRefreshRate(env, GetJavaObject(), 60.f);
-}
-
-bool WindowAndroid::ApplyDisableSurfaceControlWorkaround() {
- JNIEnv* env = AttachCurrentThread();
- return Java_WindowAndroid_applyDisableSurfaceControlWorkaround(
- env, GetJavaObject());
-}
-
bool WindowAndroid::HasPermission(const std::string& permission) {
JNIEnv* env = AttachCurrentThread();
return Java_WindowAndroid_hasPermission(
diff --git a/chromium/ui/android/window_android.h b/chromium/ui/android/window_android.h
index d6d0ac73706..658e85f2aa9 100644
--- a/chromium/ui/android/window_android.h
+++ b/chromium/ui/android/window_android.h
@@ -104,10 +104,6 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid {
void SetWideColorEnabled(bool enabled);
- void SetForce60HzRefreshRate();
-
- bool ApplyDisableSurfaceControlWorkaround();
-
class TestHooks {
public:
virtual ~TestHooks() = default;
@@ -150,7 +146,6 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid {
bool vsync_paused_ = false;
TestHooks* test_hooks_ = nullptr;
- bool force_60hz_refresh_rate_ = false;
int selection_handles_active_count_ = 0;
diff --git a/chromium/ui/aura/BUILD.gn b/chromium/ui/aura/BUILD.gn
index 193de1bb5ca..22d0ec9dd4d 100644
--- a/chromium/ui/aura/BUILD.gn
+++ b/chromium/ui/aura/BUILD.gn
@@ -37,6 +37,7 @@ component("aura") {
"scoped_enable_unadjusted_mouse_events.h",
"scoped_keyboard_hook.h",
"scoped_simple_keyboard_hook.h",
+ "scoped_window_capture_request.h",
"scoped_window_event_targeting_blocker.h",
"scoped_window_targeter.h",
"window.h",
@@ -79,6 +80,7 @@ component("aura") {
"null_window_targeter.cc",
"scoped_keyboard_hook.cc",
"scoped_simple_keyboard_hook.cc",
+ "scoped_window_capture_request.cc",
"scoped_window_event_targeting_blocker.cc",
"scoped_window_targeter.cc",
"window.cc",
@@ -101,6 +103,7 @@ component("aura") {
"//base",
"//base:i18n",
"//base/third_party/dynamic_annotations",
+ "//build:chromeos_buildflags",
"//cc",
"//cc/mojo_embedder",
"//components/discardable_memory/client",
@@ -228,6 +231,7 @@ static_library("test_support") {
deps = [
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//cc:test_support",
"//components/viz/test:test_support",
"//skia",
@@ -343,6 +347,7 @@ test("aura_unittests") {
deps = [
":test_support",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//cc/mojo_embedder",
"//components/viz/client",
"//mojo/core/embedder",
diff --git a/chromium/ui/aura/DIR_METADATA b/chromium/ui/aura/DIR_METADATA
new file mode 100644
index 00000000000..b6a63317f30
--- /dev/null
+++ b/chromium/ui/aura/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI>Aura"
+}
diff --git a/chromium/ui/aura/OWNERS b/chromium/ui/aura/OWNERS
index 8225922dda1..5b124f5fd28 100644
--- a/chromium/ui/aura/OWNERS
+++ b/chromium/ui/aura/OWNERS
@@ -5,4 +5,3 @@ per-file *x11.cc=thomasanderson@chromium.org
per-file *x11.h=thomasanderson@chromium.org
per-file *occlusion*=fdoray@chromium.org
per-file native_window_occlusion_tracker_win*=davidbienvenu@chromium.org
-# COMPONENT: UI>Aura
diff --git a/chromium/ui/aura/client/aura_constants.cc b/chromium/ui/aura/client/aura_constants.cc
index 3fa9141b582..ac740522a77 100644
--- a/chromium/ui/aura/client/aura_constants.cc
+++ b/chromium/ui/aura/client/aura_constants.cc
@@ -49,9 +49,6 @@ DEFINE_UI_CLASS_PROPERTY_KEY(bool, kWindowLayerDrawn, false)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kConstrainedWindowKey, false)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kCreatedByUserGesture, false)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kDrawAttentionKey, false)
-DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Rect,
- kEmbeddedWindowEnsureNotInRect,
- nullptr)
DEFINE_UI_CLASS_PROPERTY_KEY(FocusClient*, kFocusClientKey, nullptr)
DEFINE_UI_CLASS_PROPERTY_KEY(Window*, kHostWindowKey, nullptr)
DEFINE_UI_CLASS_PROPERTY_KEY(Window*, kChildModalParentKey, nullptr)
@@ -75,8 +72,10 @@ DEFINE_UI_CLASS_PROPERTY_KEY(ui::WindowShowState,
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSkipImeProcessing, false)
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(base::string16, kTitleKey, nullptr)
DEFINE_UI_CLASS_PROPERTY_KEY(int, kTopViewInset, 0)
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kVisibleOnAllWorkspacesKey, false)
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::ImageSkia, kWindowIconKey, nullptr)
DEFINE_UI_CLASS_PROPERTY_KEY(int, kWindowCornerRadiusKey, -1)
+DEFINE_UI_CLASS_PROPERTY_KEY(int, kWindowWorkspaceKey, kUnassignedWorkspace)
DEFINE_UI_CLASS_PROPERTY_KEY(ui::ZOrderLevel,
kZOrderingKey,
ui::ZOrderLevel::kNormal)
diff --git a/chromium/ui/aura/client/aura_constants.h b/chromium/ui/aura/client/aura_constants.h
index 138069130a8..ac15d1b3519 100644
--- a/chromium/ui/aura/client/aura_constants.h
+++ b/chromium/ui/aura/client/aura_constants.h
@@ -18,7 +18,7 @@ namespace ws {
namespace mojom {
enum class WindowType;
}
-}
+} // namespace ws
namespace aura {
namespace client {
@@ -30,6 +30,9 @@ constexpr int kResizeBehaviorCanResize = 1 << 0;
constexpr int kResizeBehaviorCanMaximize = 1 << 1;
constexpr int kResizeBehaviorCanMinimize = 1 << 2;
+// A value used to represent an unassigned workspace for kWindowWorkspaceKey.
+constexpr int kUnassignedWorkspace = -1;
+
// Alphabetical sort.
// A property key to store whether accessibility focus falls back to widget or
@@ -81,12 +84,6 @@ AURA_EXPORT extern const WindowProperty<bool>* const kCreatedByUserGesture;
// attention.
AURA_EXPORT extern const WindowProperty<bool>* const kDrawAttentionKey;
-// A property key to store a bounds in screen coordinates that an embedded
-// window wants to be moved out of. This is only used in MUS to move the
-// embedding top-level window at the other side.
-AURA_EXPORT extern const WindowProperty<gfx::Rect*>* const
- kEmbeddedWindowEnsureNotInRect;
-
// A property key to store the focus client on the window.
AURA_EXPORT extern const WindowProperty<FocusClient*>* const kFocusClientKey;
@@ -151,6 +148,9 @@ AURA_EXPORT extern const WindowProperty<base::string16*>* const kTitleKey;
// the web contents for app windows and varies for fullscreen windows.
AURA_EXPORT extern const WindowProperty<int>* const kTopViewInset;
+// A property key to store whether this window is visible on all workspaces.
+AURA_EXPORT extern const WindowProperty<bool>* const kVisibleOnAllWorkspacesKey;
+
// A property key to store the window icon, typically 16x16 for title bars.
AURA_EXPORT extern const WindowProperty<gfx::ImageSkia*>* const kWindowIconKey;
@@ -158,6 +158,10 @@ AURA_EXPORT extern const WindowProperty<gfx::ImageSkia*>* const kWindowIconKey;
// Default is -1, meaning "unspecified". 0 Ensures corners are square.
AURA_EXPORT extern const WindowProperty<int>* const kWindowCornerRadiusKey;
+// A property key to indicate a desk index of a workspace this window belongs
+// to. The default value is kUnassignedWorkspace.
+AURA_EXPORT extern const WindowProperty<int>* const kWindowWorkspaceKey;
+
// A property key to store the z-ordering.
AURA_EXPORT extern const WindowProperty<ui::ZOrderLevel>* const kZOrderingKey;
diff --git a/chromium/ui/aura/client/drag_drop_client_observer.h b/chromium/ui/aura/client/drag_drop_client_observer.h
index aca9bda44bc..f668f77cb86 100644
--- a/chromium/ui/aura/client/drag_drop_client_observer.h
+++ b/chromium/ui/aura/client/drag_drop_client_observer.h
@@ -5,6 +5,7 @@
#ifndef UI_AURA_CLIENT_DRAG_DROP_CLIENT_OBSERVER_H_
#define UI_AURA_CLIENT_DRAG_DROP_CLIENT_OBSERVER_H_
+#include "build/chromeos_buildflags.h"
#include "ui/aura/aura_export.h"
namespace aura {
@@ -18,7 +19,7 @@ class AURA_EXPORT DragDropClientObserver {
// Called when dragging ended.
virtual void OnDragEnded() = 0;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Called when the set of currently selected drag operation changes during the
// drag. |action| is a bitmask of the actions selected by the client. This is
// to provide feedback during the operation, it does not take precedence over
diff --git a/chromium/ui/aura/client/drag_drop_delegate.cc b/chromium/ui/aura/client/drag_drop_delegate.cc
index 37529f956d4..2e250bcb17c 100644
--- a/chromium/ui/aura/client/drag_drop_delegate.cc
+++ b/chromium/ui/aura/client/drag_drop_delegate.cc
@@ -12,6 +12,14 @@ DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AURA_EXPORT,
namespace aura {
namespace client {
+DragUpdateInfo::DragUpdateInfo() = default;
+
+DragUpdateInfo::DragUpdateInfo(int op, ui::DataTransferEndpoint endpoint)
+ : drag_operation(op), data_endpoint(endpoint) {}
+
+DragUpdateInfo& DragUpdateInfo::operator=(const DragUpdateInfo& update_info) =
+ default;
+
DEFINE_UI_CLASS_PROPERTY_KEY(DragDropDelegate*, kDragDropDelegateKey, nullptr)
void SetDragDropDelegate(Window* window, DragDropDelegate* delegate) {
diff --git a/chromium/ui/aura/client/drag_drop_delegate.h b/chromium/ui/aura/client/drag_drop_delegate.h
index 82a2dc665d6..009f91445bc 100644
--- a/chromium/ui/aura/client/drag_drop_delegate.h
+++ b/chromium/ui/aura/client/drag_drop_delegate.h
@@ -9,6 +9,9 @@
#include "ui/aura/aura_export.h"
#include "ui/aura/window.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"
#include "ui/base/dragdrop/os_exchange_data.h"
namespace ui {
@@ -19,6 +22,18 @@ namespace aura {
class Window;
namespace client {
+struct AURA_EXPORT DragUpdateInfo {
+ DragUpdateInfo();
+ DragUpdateInfo(int op, ui::DataTransferEndpoint endpoint);
+
+ DragUpdateInfo& operator=(const DragUpdateInfo& update_info);
+
+ // A bitmask of the DragDropTypes::DragOperation supported.
+ int drag_operation = ui::DragDropTypes::DRAG_NONE;
+ // An object representing the destination window.
+ ui::DataTransferEndpoint data_endpoint{ui::EndpointType::kDefault};
+};
+
// Delegate interface for drag and drop actions on aura::Window.
class AURA_EXPORT DragDropDelegate {
public:
@@ -28,10 +43,9 @@ class AURA_EXPORT DragDropDelegate {
virtual void OnDragEntered(const ui::DropTargetEvent& event) = 0;
// Invoked during a drag and drop session while the mouse is over the window.
- // This should return a bitmask of the DragDropTypes::DragOperation supported
- // based on the location of the event. Return 0 to indicate the drop should
- // not be accepted.
- virtual int OnDragUpdated(const ui::DropTargetEvent& event) = 0;
+ // This should return DragUpdateInfo object based on the location of the
+ // event.
+ virtual DragUpdateInfo OnDragUpdated(const ui::DropTargetEvent& event) = 0;
// Invoked during a drag and drop session when the mouse exits the window, or
// when the drag session was canceled and the mouse was over the window.
@@ -43,8 +57,9 @@ class AURA_EXPORT DragDropDelegate {
// also stored in the DropTargetEvent. Implementor of this function should be
// aware of keeping the OSExchageData alive until it wants to access it
// through the parameter or the stored reference in DropTargetEvent.
- virtual int OnPerformDrop(const ui::DropTargetEvent& event,
- std::unique_ptr<ui::OSExchangeData> data) = 0;
+ virtual ui::mojom::DragOperation OnPerformDrop(
+ const ui::DropTargetEvent& event,
+ std::unique_ptr<ui::OSExchangeData> data) = 0;
protected:
virtual ~DragDropDelegate() {}
diff --git a/chromium/ui/aura/env.cc b/chromium/ui/aura/env.cc
index ae56d8fcb85..1aa181ecd8d 100644
--- a/chromium/ui/aura/env.cc
+++ b/chromium/ui/aura/env.cc
@@ -8,6 +8,7 @@
#include "base/lazy_instance.h"
#include "base/memory/ptr_util.h"
#include "base/observer_list_types.h"
+#include "build/build_config.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env_input_state_controller.h"
#include "ui/aura/env_observer.h"
@@ -21,11 +22,19 @@
#include "ui/events/gestures/gesture_recognizer_impl.h"
#include "ui/events/platform/platform_event_source.h"
+#if defined(OS_WIN)
+#include "ui/base/cursor/win/win_cursor_factory.h"
+#endif
+
#if defined(USE_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#endif
#if defined(USE_X11)
+#include "ui/base/x/x11_cursor_factory.h"
+#endif
+
+#if defined(OS_WIN) || defined(USE_X11)
#include "ui/gfx/switches.h"
#endif
@@ -210,12 +219,17 @@ Env::Env()
: env_controller_(std::make_unique<EnvInputStateController>(this)),
gesture_recognizer_(std::make_unique<ui::GestureRecognizerImpl>()),
input_state_lookup_(InputStateLookup::Create()) {
+#if defined(OS_WIN) || defined(USE_X11)
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless)) {
#if defined(USE_X11)
- // In Ozone/X11, the cursor factory is initialized by the platform
- // initialization code.
- if (!features::IsUsingOzonePlatform() &&
- !base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
- cursor_factory_ = std::make_unique<ui::X11CursorFactory>();
+ // In Ozone/X11, the cursor factory is initialized by the platform
+ // initialization code.
+ if (!features::IsUsingOzonePlatform())
+ cursor_factory_ = std::make_unique<ui::X11CursorFactory>();
+#else
+ cursor_factory_ = std::make_unique<ui::WinCursorFactory>();
+#endif
+ }
#endif
}
@@ -244,10 +258,17 @@ void Env::NotifyWindowInitialized(Window* window) {
}
void Env::NotifyHostInitialized(WindowTreeHost* host) {
+ window_tree_hosts_.push_back(host);
for (EnvObserver& observer : observers_)
observer.OnHostInitialized(host);
}
+void Env::NotifyHostDestroyed(WindowTreeHost* host) {
+ base::Erase(window_tree_hosts_, host);
+ for (EnvObserver& observer : observers_)
+ observer.OnHostDestroyed(host);
+}
+
////////////////////////////////////////////////////////////////////////////////
// Env, ui::EventTarget implementation:
diff --git a/chromium/ui/aura/env.h b/chromium/ui/aura/env.h
index 12f91827271..2baf5a54175 100644
--- a/chromium/ui/aura/env.h
+++ b/chromium/ui/aura/env.h
@@ -19,15 +19,15 @@
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/point.h"
-#if defined(USE_X11)
-#include "ui/base/x/x11_cursor_factory.h" // nogncheck
-#endif
-
namespace ui {
class ContextFactory;
class EventObserver;
class GestureRecognizer;
class PlatformEventSource;
+
+#if defined(OS_WIN) || defined(USE_X11)
+class CursorFactory;
+#endif
} // namespace ui
namespace aura {
@@ -133,6 +133,10 @@ class AURA_EXPORT Env : public ui::EventTarget,
void RemoveEventObserver(ui::EventObserver* observer);
void NotifyEventObservers(const ui::Event& event);
+ const std::vector<aura::WindowTreeHost*>& window_tree_hosts() const {
+ return window_tree_hosts_;
+ }
+
private:
friend class test::EnvTestHelper;
friend class EventInjector;
@@ -149,6 +153,9 @@ class AURA_EXPORT Env : public ui::EventTarget,
// Called by the WindowTreeHost when it is initialized. Notifies observers.
void NotifyHostInitialized(WindowTreeHost* host);
+ // Called by the WindowTreeHost before it is destroyed. Notifies observers.
+ void NotifyHostDestroyed(WindowTreeHost* host);
+
// Overridden from ui::EventTarget:
bool CanAcceptEvent(const ui::Event& event) override;
ui::EventTarget* GetParentTarget() override;
@@ -175,8 +182,8 @@ class AURA_EXPORT Env : public ui::EventTarget,
std::unique_ptr<ui::GestureRecognizer> gesture_recognizer_;
-#if defined(USE_X11)
- std::unique_ptr<ui::X11CursorFactory> cursor_factory_;
+#if defined(OS_WIN) || defined(USE_X11)
+ std::unique_ptr<ui::CursorFactory> cursor_factory_;
#endif
std::unique_ptr<InputStateLookup> input_state_lookup_;
@@ -189,6 +196,8 @@ class AURA_EXPORT Env : public ui::EventTarget,
std::unique_ptr<WindowOcclusionTracker> window_occlusion_tracker_;
+ std::vector<aura::WindowTreeHost*> window_tree_hosts_;
+
DISALLOW_COPY_AND_ASSIGN(Env);
};
diff --git a/chromium/ui/aura/env_observer.h b/chromium/ui/aura/env_observer.h
index dcb3080a061..e9a3e7870aa 100644
--- a/chromium/ui/aura/env_observer.h
+++ b/chromium/ui/aura/env_observer.h
@@ -20,6 +20,9 @@ class AURA_EXPORT EnvObserver {
// Called when a WindowTreeHost is initialized.
virtual void OnHostInitialized(WindowTreeHost* host) {}
+ // Called before WindowTreeHost is destroyed.
+ virtual void OnHostDestroyed(WindowTreeHost* host) {}
+
// Called right before Env is destroyed.
virtual void OnWillDestroyEnv() {}
diff --git a/chromium/ui/aura/event_injector.cc b/chromium/ui/aura/event_injector.cc
index 6598c5f8f3c..5e7ebe692b0 100644
--- a/chromium/ui/aura/event_injector.cc
+++ b/chromium/ui/aura/event_injector.cc
@@ -31,7 +31,7 @@ ui::EventDispatchDetails EventInjector::Inject(WindowTreeHost* host,
host->GetRootTransformForLocalEventCoordinates());
}
- return host->event_sink()->OnEventFromSource(event);
+ return host->GetEventSink()->OnEventFromSource(event);
}
} // namespace aura
diff --git a/chromium/ui/aura/gestures/DIR_METADATA b/chromium/ui/aura/gestures/DIR_METADATA
new file mode 100644
index 00000000000..016423996f7
--- /dev/null
+++ b/chromium/ui/aura/gestures/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+ component: "UI>Input"
+}
+team_email: "input-dev@chromium.org"
diff --git a/chromium/ui/aura/gestures/OWNERS b/chromium/ui/aura/gestures/OWNERS
index 4b27ef7648b..854bbfa6ab0 100644
--- a/chromium/ui/aura/gestures/OWNERS
+++ b/chromium/ui/aura/gestures/OWNERS
@@ -1,7 +1,3 @@
rjkroege@chromium.org
sadrul@chromium.org
-tdresser@chromium.org
-nzolghadr@chromium.org
-
-# TEAM: input-dev@chromium.org
-# COMPONENT: UI>Input
+flackr@chromium.org
diff --git a/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc b/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
index 9d582844a33..40ad0466075 100644
--- a/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -1020,7 +1020,7 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) {
// should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures.
// The first movement is diagonal, to ensure that we have a free scroll,
// and not a rail scroll.
- tes.SendScrollEvent(event_sink(), 111.5, 211.5, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 111.5, 211.5, kTouchId, delegate.get());
EXPECT_3_EVENTS(delegate->events(),
ui::ET_GESTURE_TAP_CANCEL,
ui::ET_GESTURE_SCROLL_BEGIN,
@@ -1037,13 +1037,13 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) {
// Move some more to generate a few more scroll updates. Make sure that we get
// out of the snap channel for the unified GR.
- tes.SendScrollEvent(event_sink(), 20, 120, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 20, 120, kTouchId, delegate.get());
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
EXPECT_FLOAT_EQ(-91.5, delegate->scroll_x());
EXPECT_FLOAT_EQ(-91.5, delegate->scroll_y());
EXPECT_TRUE(delegate->bounding_box().IsEmpty());
- tes.SendScrollEvent(event_sink(), 50, 124, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 50, 124, kTouchId, delegate.get());
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
EXPECT_EQ(30, delegate->scroll_x());
EXPECT_EQ(4, delegate->scroll_y());
@@ -1109,7 +1109,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollPrediction) {
// The first movement is diagonal, to ensure that we have a free scroll,
// and not a rail scroll.
tes.LeapForward(30);
- tes.SendScrollEvent(event_sink(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 130, 230, kTouchId, delegate.get());
EXPECT_1_EVENT(delegate->events(),
ui::ET_GESTURE_SCROLL_UPDATE);
total_scroll.set_x(total_scroll.x() + delegate->scroll_x());
@@ -1117,13 +1117,13 @@ TEST_F(GestureRecognizerTest, GestureEventScrollPrediction) {
// Move some more to generate a few more scroll updates.
tes.LeapForward(30);
- tes.SendScrollEvent(event_sink(), 110, 211, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 110, 211, kTouchId, delegate.get());
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
total_scroll.set_x(total_scroll.x() + delegate->scroll_x());
total_scroll.set_y(total_scroll.y() + delegate->scroll_y());
tes.LeapForward(30);
- tes.SendScrollEvent(event_sink(), 140, 215, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 140, 215, kTouchId, delegate.get());
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
total_scroll.set_x(total_scroll.x() + delegate->scroll_x());
total_scroll.set_y(total_scroll.y() + delegate->scroll_y());
@@ -1162,7 +1162,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox) {
delegate->bounding_box());
const int kScrollAmount = 50;
- tes.SendScrollEvents(event_sink(), kPositionX, kPositionY, 1, 1, kTouchId,
+ tes.SendScrollEvents(GetEventSink(), kPositionX, kPositionY, 1, 1, kTouchId,
1, kScrollAmount, delegate.get());
EXPECT_EQ(gfx::Point(1, 1).ToString(),
delegate->scroll_begin_position().ToString());
@@ -1213,14 +1213,14 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailFling) {
// Move the touch-point horizontally enough that it is considered a
// horizontal scroll.
- tes.SendScrollEvent(event_sink(), 30, 1, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 30, 1, kTouchId, delegate.get());
EXPECT_FLOAT_EQ(0, delegate->scroll_y());
EXPECT_FLOAT_EQ(20, delegate->scroll_x());
// Get a high x velocity, while still staying on the rail
const int kScrollAmount = 8;
- tes.SendScrollEvents(event_sink(), 1, 1, 100, 10, kTouchId, 1, kScrollAmount,
- delegate.get());
+ tes.SendScrollEvents(GetEventSink(), 1, 1, 100, 10, kTouchId, 1,
+ kScrollAmount, delegate.get());
delegate->Reset();
ui::TouchEvent release(
@@ -1259,15 +1259,15 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailFling) {
// Move the touch-point vertically enough that it is considered a
// vertical scroll.
- tes.SendScrollEvent(event_sink(), 1, 30, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 1, 30, kTouchId, delegate.get());
EXPECT_EQ(20, delegate->scroll_y());
EXPECT_EQ(0, delegate->scroll_x());
EXPECT_EQ(0, delegate->scroll_velocity_x());
// Get a high y velocity, while still staying on the rail
const int kScrollAmount = 8;
- tes.SendScrollEvents(event_sink(), 1, 6, 10, 100, kTouchId, 1, kScrollAmount,
- delegate.get());
+ tes.SendScrollEvents(GetEventSink(), 1, 6, 10, 100, kTouchId, 1,
+ kScrollAmount, delegate.get());
EXPECT_EQ(0, delegate->scroll_velocity_x());
delegate->Reset();
@@ -1302,13 +1302,13 @@ TEST_F(GestureRecognizerTest, GestureEventNonRailFling) {
// Move the touch-point such that a non-rail scroll begins, and we're outside
// the snap channel for the unified GR.
- tes.SendScrollEvent(event_sink(), 50, 50, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 50, 50, kTouchId, delegate.get());
EXPECT_EQ(50, delegate->scroll_y());
EXPECT_EQ(50, delegate->scroll_x());
const int kScrollAmount = 8;
- tes.SendScrollEvents(event_sink(), 1, 1, 10, 100, kTouchId, 1, kScrollAmount,
- delegate.get());
+ tes.SendScrollEvents(GetEventSink(), 1, 1, 10, 100, kTouchId, 1,
+ kScrollAmount, delegate.get());
delegate->Reset();
ui::TouchEvent release(
@@ -1388,7 +1388,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) {
EXPECT_FALSE(delegate->tap_cancel());
// Scroll around, to cancel the long press
- tes.SendScrollEvent(event_sink(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 130, 230, kTouchId, delegate.get());
// Wait until a long press event would have fired, if it hadn't been
// cancelled.
@@ -1526,11 +1526,11 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll) {
// Move the touch-point horizontally enough that it is considered a
// horizontal scroll.
- tes.SendScrollEvent(event_sink(), 25, 0, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 25, 0, kTouchId, delegate.get());
EXPECT_EQ(0, delegate->scroll_y());
EXPECT_EQ(20, delegate->scroll_x());
- tes.SendScrollEvent(event_sink(), 30, 6, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 30, 6, kTouchId, delegate.get());
EXPECT_TRUE(delegate->scroll_update());
EXPECT_EQ(5, delegate->scroll_x());
// y shouldn't change, as we're on a horizontal rail.
@@ -1539,11 +1539,11 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll) {
// Send enough information that a velocity can be calculated for the gesture,
// and we can break the rail
const int kScrollAmount = 8;
- tes.SendScrollEvents(event_sink(), 1, 1, 6, 100, kTouchId, 1, kScrollAmount,
+ tes.SendScrollEvents(GetEventSink(), 1, 1, 6, 100, kTouchId, 1, kScrollAmount,
delegate.get());
- tes.SendScrollEvent(event_sink(), 5, 0, kTouchId, delegate.get());
- tes.SendScrollEvent(event_sink(), 10, 5, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 5, 0, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 10, 5, kTouchId, delegate.get());
// The rail should be broken
EXPECT_TRUE(delegate->scroll_update());
@@ -1576,11 +1576,11 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll) {
// Move the touch-point vertically enough that it is considered a
// vertical scroll.
- tes.SendScrollEvent(event_sink(), 0, 25, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 0, 25, kTouchId, delegate.get());
EXPECT_EQ(0, delegate->scroll_x());
EXPECT_EQ(20, delegate->scroll_y());
- tes.SendScrollEvent(event_sink(), 6, 30, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 6, 30, kTouchId, delegate.get());
EXPECT_TRUE(delegate->scroll_update());
EXPECT_EQ(5, delegate->scroll_y());
// x shouldn't change, as we're on a vertical rail.
@@ -1590,11 +1590,11 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll) {
// Send enough information that a velocity can be calculated for the gesture,
// and we can break the rail
const int kScrollAmount = 8;
- tes.SendScrollEvents(event_sink(), 1, 6, 100, 1, kTouchId, 1, kScrollAmount,
+ tes.SendScrollEvents(GetEventSink(), 1, 6, 100, 1, kTouchId, 1, kScrollAmount,
delegate.get());
- tes.SendScrollEvent(event_sink(), 0, 5, kTouchId, delegate.get());
- tes.SendScrollEvent(event_sink(), 5, 10, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 0, 5, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 5, 10, kTouchId, delegate.get());
// The rail should be broken
EXPECT_TRUE(delegate->scroll_update());
@@ -2053,12 +2053,12 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScrollFromPinch) {
EXPECT_FALSE(delegate->pinch_begin());
// Touch move triggers pinch begin and update.
- tes.SendScrollEvent(event_sink(), 130, 230, kTouchId1, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 130, 230, kTouchId1, delegate.get());
EXPECT_TRUE(delegate->pinch_begin());
EXPECT_TRUE(delegate->pinch_update());
// Touch move triggers pinch update.
- tes.SendScrollEvent(event_sink(), 160, 200, kTouchId1, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 160, 200, kTouchId1, delegate.get());
EXPECT_FALSE(delegate->pinch_begin());
EXPECT_TRUE(delegate->pinch_update());
@@ -2070,7 +2070,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScrollFromPinch) {
DispatchEventUsingWindowDispatcher(&release);
EXPECT_TRUE(delegate->pinch_end());
- tes.SendScrollEvent(event_sink(), 130, 230, kTouchId2, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 130, 230, kTouchId2, delegate.get());
EXPECT_TRUE(delegate->scroll_update());
// Pinch again
@@ -2087,7 +2087,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScrollFromPinch) {
DispatchEventUsingWindowDispatcher(&move2);
EXPECT_TRUE(delegate->pinch_begin());
- tes.SendScrollEvent(event_sink(), 350, 350, kTouchId1, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 350, 350, kTouchId1, delegate.get());
EXPECT_TRUE(delegate->pinch_update());
}
@@ -2751,7 +2751,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) {
ui::PointerDetails(ui::EventPointerType::kTouch, kTouchId2));
DispatchEventUsingWindowDispatcher(&press2);
- tes.SendScrollEvent(event_sink(), 230, 330, kTouchId1, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 230, 330, kTouchId1, delegate.get());
EXPECT_FALSE(delegate->two_finger_tap());
EXPECT_TRUE(delegate->pinch_begin());
@@ -2785,7 +2785,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) {
ui::PointerDetails(ui::EventPointerType::kTouch, kTouchId2));
DispatchEventUsingWindowDispatcher(&press2);
- tes.SendScrollEvent(event_sink(), 301, 230, kTouchId2, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 301, 230, kTouchId2, delegate.get());
EXPECT_FALSE(delegate->two_finger_tap());
EXPECT_TRUE(delegate->pinch_begin());
@@ -2820,7 +2820,7 @@ TEST_F(GestureRecognizerTest, NoTwoFingerTapWhenFirstFingerHasScrolled) {
ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), tes.Now(),
ui::PointerDetails(ui::EventPointerType::kTouch, kTouchId1));
DispatchEventUsingWindowDispatcher(&press1);
- tes.SendScrollEvent(event_sink(), 130, 230, kTouchId1, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 130, 230, kTouchId1, delegate.get());
delegate->Reset();
ui::TouchEvent press2(
@@ -3091,7 +3091,7 @@ TEST_F(GestureRecognizerTest, LongPressTimerStopsOnPreventDefaultedTouchMoves) {
ui::PointerDetails(ui::EventPointerType::kTouch, kTouchId));
DispatchEventUsingWindowDispatcher(&press);
// Scroll around, to cancel the long press
- tes.SendScrollEvent(event_sink(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 130, 230, kTouchId, delegate.get());
delegate->Reset();
delegate->ReceivedAck();
@@ -3156,7 +3156,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) {
// Move the touch-point enough so that it would normally be considered a
// scroll. But since the touch-moves will be consumed, the scroll should not
// start.
- tes.SendScrollEvent(event_sink(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 130, 230, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_TRUE(delegate->tap_cancel());
@@ -3204,7 +3204,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), tes.Now(),
ui::PointerDetails(ui::EventPointerType::kTouch, kTouchId1));
DispatchEventUsingWindowDispatcher(&press1);
- tes.SendScrollEvent(event_sink(), 131, 231, kTouchId1, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 131, 231, kTouchId1, delegate.get());
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_TAP_CANCEL,
@@ -3216,12 +3216,12 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
ui::ET_TOUCH_PRESSED, gfx::Point(130, 201), tes.LeapForward(50),
ui::PointerDetails(ui::EventPointerType::kTouch, kTouchId2));
DispatchEventUsingWindowDispatcher(&press2);
- tes.SendScrollEvent(event_sink(), 161, 231, kTouchId2, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 161, 231, kTouchId2, delegate.get());
EXPECT_0_EVENTS(delegate->events());
delegate->Reset();
// Move first finger again, no PinchUpdate & ScrollUpdate.
- tes.SendScrollEvent(event_sink(), 161, 261, kTouchId1, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 161, 261, kTouchId1, delegate.get());
EXPECT_0_EVENTS(delegate->events());
// Stops consuming touch-move.
@@ -3229,11 +3229,11 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
delegate->Reset();
// Making a pinch gesture.
- tes.SendScrollEvent(event_sink(), 161, 260, kTouchId1, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 161, 260, kTouchId1, delegate.get());
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
delegate->Reset();
- tes.SendScrollEvent(event_sink(), 161, 261, kTouchId2, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 161, 261, kTouchId2, delegate.get());
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
delegate->Reset();
@@ -3282,7 +3282,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
// Move the touch-point enough so that it would normally be considered a
// scroll. But since the touch-moves will be consumed, the scroll should not
// start.
- tes.SendScrollEvent(event_sink(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 130, 230, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_TRUE(delegate->tap_cancel());
@@ -3295,7 +3295,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
// Now, stop consuming touch-move events, and move the touch-point again.
delegate->set_consume_touch_move(false);
- tes.SendScrollEvent(event_sink(), 159, 259, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 159, 259, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -3314,7 +3314,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
delegate->set_consume_touch_move(true);
// Move some more to generate a few more scroll updates.
- tes.SendScrollEvent(event_sink(), 110, 211, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 110, 211, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -3325,7 +3325,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
EXPECT_EQ(0, delegate->scroll_x());
EXPECT_EQ(0, delegate->scroll_y());
- tes.SendScrollEvent(event_sink(), 140, 215, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 140, 215, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -3707,7 +3707,7 @@ TEST_F(GestureRecognizerTest, GestureEventConsumedTouchMoveCanFireTapCancel) {
// occur.
// With the unified gesture detector, we will receive a scroll begin gesture,
// whereas with the aura gesture recognizer we won't.
- tes.SendScrollEvent(event_sink(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 130, 230, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_TRUE(delegate->tap_cancel());
@@ -3846,7 +3846,7 @@ TEST_F(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) {
EXPECT_FALSE(delegate->tap_cancel());
// Scroll around, to cancel the show press
- tes.SendScrollEvent(event_sink(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(GetEventSink(), 130, 230, kTouchId, delegate.get());
// Wait until the timer runs out
DelayByShowPressTimeout();
EXPECT_FALSE(delegate->show_press());
diff --git a/chromium/ui/aura/native_window_occlusion_tracker_unittest.cc b/chromium/ui/aura/native_window_occlusion_tracker_unittest.cc
index da4af6cf485..deaa10679d4 100644
--- a/chromium/ui/aura/native_window_occlusion_tracker_unittest.cc
+++ b/chromium/ui/aura/native_window_occlusion_tracker_unittest.cc
@@ -43,6 +43,41 @@ TestNativeWindow::~TestNativeWindow() {
DestroyWindow(hwnd());
}
+// Test wrapper around native window HWND.
+class TestWin32Window {
+ public:
+ TestWin32Window() {}
+ ~TestWin32Window();
+
+ HWND Create(DWORD style);
+
+ DISALLOW_COPY_AND_ASSIGN(TestWin32Window);
+
+ private:
+ HWND hwnd_ = NULL;
+};
+
+TestWin32Window::~TestWin32Window() {
+ if (hwnd_)
+ DestroyWindow(hwnd_);
+}
+
+HWND TestWin32Window::Create(DWORD style) {
+ const wchar_t class_name[] = L"TestWin32Window";
+ WNDCLASSEX wcex = {sizeof(wcex)};
+ wcex.lpfnWndProc = DefWindowProc;
+ wcex.hInstance = ::GetModuleHandle(nullptr);
+ wcex.lpszClassName = class_name;
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ RegisterClassEx(&wcex);
+ HWND hwnd_ =
+ CreateWindowEx(0, class_name, class_name, style, 0, 0, 100, 100, nullptr,
+ nullptr, GetModuleHandle(nullptr), nullptr);
+ ShowWindow(hwnd_, SW_SHOWNORMAL);
+ EXPECT_TRUE(UpdateWindow(hwnd_));
+ return hwnd_;
+}
+
// This class currently tests the behavior of
// NativeWindowOcclusionTrackerWin::IsWindowVisibleAndFullyOpaque with hwnds
// with various attributes (e.g., minimized, transparent, etc).
@@ -52,9 +87,10 @@ class NativeWindowOcclusionTrackerTest : public test::AuraTestBase {
TestNativeWindow* native_win() { return native_win_.get(); }
- HWND CreateNativeWindow(DWORD ex_style) {
+ HWND CreateNativeWindow(DWORD style, DWORD ex_style) {
native_win_ = std::make_unique<TestNativeWindow>();
- native_win_->set_window_style(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN);
+ native_win_->set_window_style(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN |
+ style);
native_win_->set_window_ex_style(ex_style);
gfx::Rect bounds(0, 0, 100, 100);
native_win_->Init(nullptr, bounds);
@@ -94,7 +130,7 @@ class NativeWindowOcclusionTrackerTest : public test::AuraTestBase {
};
TEST_F(NativeWindowOcclusionTrackerTest, VisibleOpaqueWindow) {
- HWND hwnd = CreateNativeWindow(/*ex_style=*/0);
+ HWND hwnd = CreateNativeWindow(/*style=*/0, /*ex_style=*/0);
gfx::Rect returned_rect;
// Normal windows should be visible.
EXPECT_TRUE(CheckWindowVisibleAndFullyOpaque(hwnd, &returned_rect));
@@ -106,7 +142,7 @@ TEST_F(NativeWindowOcclusionTrackerTest, VisibleOpaqueWindow) {
}
TEST_F(NativeWindowOcclusionTrackerTest, MinimizedWindow) {
- HWND hwnd = CreateNativeWindow(/*ex_style=*/0);
+ HWND hwnd = CreateNativeWindow(/*style=*/0, /*ex_style=*/0);
gfx::Rect win_rect;
ShowWindow(hwnd, SW_MINIMIZE);
// Minimized windows are not considered visible.
@@ -114,21 +150,21 @@ TEST_F(NativeWindowOcclusionTrackerTest, MinimizedWindow) {
}
TEST_F(NativeWindowOcclusionTrackerTest, TransparentWindow) {
- HWND hwnd = CreateNativeWindow(WS_EX_TRANSPARENT);
+ HWND hwnd = CreateNativeWindow(/*style=*/0, WS_EX_TRANSPARENT);
gfx::Rect win_rect;
// Transparent windows are not considered visible and opaque.
EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
}
TEST_F(NativeWindowOcclusionTrackerTest, ToolWindow) {
- HWND hwnd = CreateNativeWindow(WS_EX_TOOLWINDOW);
+ HWND hwnd = CreateNativeWindow(/*style=*/0, WS_EX_TOOLWINDOW);
gfx::Rect win_rect;
// Tool windows are not considered visible and opaque.
EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
}
TEST_F(NativeWindowOcclusionTrackerTest, LayeredAlphaWindow) {
- HWND hwnd = CreateNativeWindow(WS_EX_LAYERED);
+ HWND hwnd = CreateNativeWindow(/*style=*/0, WS_EX_LAYERED);
gfx::Rect win_rect;
BYTE alpha = 1;
DWORD flags = LWA_ALPHA;
@@ -139,7 +175,7 @@ TEST_F(NativeWindowOcclusionTrackerTest, LayeredAlphaWindow) {
}
TEST_F(NativeWindowOcclusionTrackerTest, UpdatedLayeredAlphaWindow) {
- HWND hwnd = CreateNativeWindow(WS_EX_LAYERED);
+ HWND hwnd = CreateNativeWindow(/*style=*/0, WS_EX_LAYERED);
gfx::Rect win_rect;
base::win::ScopedCreateDC hdc(::CreateCompatibleDC(nullptr));
BLENDFUNCTION blend = {AC_SRC_OVER, 0x00, 0xFF, AC_SRC_ALPHA};
@@ -152,7 +188,7 @@ TEST_F(NativeWindowOcclusionTrackerTest, UpdatedLayeredAlphaWindow) {
}
TEST_F(NativeWindowOcclusionTrackerTest, LayeredNonAlphaWindow) {
- HWND hwnd = CreateNativeWindow(WS_EX_LAYERED);
+ HWND hwnd = CreateNativeWindow(/*style=*/0, WS_EX_LAYERED);
gfx::Rect win_rect;
BYTE alpha = 1;
DWORD flags = 0;
@@ -163,7 +199,7 @@ TEST_F(NativeWindowOcclusionTrackerTest, LayeredNonAlphaWindow) {
}
TEST_F(NativeWindowOcclusionTrackerTest, ComplexRegionWindow) {
- HWND hwnd = CreateNativeWindow(/*ex_style=*/0);
+ HWND hwnd = CreateNativeWindow(/*style=*/0, /*ex_style=*/0);
gfx::Rect win_rect;
// Create a region with rounded corners, which should be a complex region.
base::win::ScopedRegion region(CreateRoundRectRgn(1, 1, 100, 100, 5, 5));
@@ -172,11 +208,26 @@ TEST_F(NativeWindowOcclusionTrackerTest, ComplexRegionWindow) {
EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
}
+TEST_F(NativeWindowOcclusionTrackerTest, PopupChromeWindow) {
+ HWND hwnd = CreateNativeWindow(WS_POPUP, /*ex_style=*/0);
+ gfx::Rect win_rect;
+ // Chrome Popup Windows of class Chrome_WidgetWin_ are considered visible.
+ EXPECT_TRUE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
+}
+
+TEST_F(NativeWindowOcclusionTrackerTest, PopupWindow) {
+ TestWin32Window test_window;
+ HWND hwnd = test_window.Create(WS_POPUPWINDOW);
+ gfx::Rect win_rect;
+ // Normal Popup Windows are not considered visible.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
+}
+
TEST_F(NativeWindowOcclusionTrackerTest, CloakedWindow) {
// Cloaking is only supported in Windows 8 and above.
if (base::win::GetVersion() < base::win::Version::WIN8)
return;
- HWND hwnd = CreateNativeWindow(/*ex_style=*/0);
+ HWND hwnd = CreateNativeWindow(/*style=*/0, /*ex_style=*/0);
gfx::Rect win_rect;
BOOL cloak = TRUE;
DwmSetWindowAttribute(hwnd, DWMWA_CLOAK, &cloak, sizeof(cloak));
diff --git a/chromium/ui/aura/native_window_occlusion_tracker_win.cc b/chromium/ui/aura/native_window_occlusion_tracker_win.cc
index 9b7e1e3fa9d..ac50a5b093f 100644
--- a/chromium/ui/aura/native_window_occlusion_tracker_win.cc
+++ b/chromium/ui/aura/native_window_occlusion_tracker_win.cc
@@ -12,6 +12,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/scoped_refptr.h"
+#include "base/strings/string_util_win.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/post_task.h"
@@ -22,59 +23,8 @@
#include "base/win/scoped_gdi_object.h"
#include "base/win/windows_version.h"
#include "ui/aura/window_tree_host.h"
-#include "ui/base/ui_base_features.h"
#include "ui/gfx/win/hwnd_util.h"
-const CLSID CLSID_ImmersiveShell = {
- 0xC2F03A33,
- 0x21F5,
- 0x47FA,
- {0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39}};
-
-const CLSID CLSID_VirtualDesktopAPI_Unknown = {
- 0xC5E0CDCA,
- 0x7B6E,
- 0x41B2,
- {0x9F, 0xC4, 0xD9, 0x39, 0x75, 0xCC, 0x46, 0x7B}};
-
-struct IApplicationView : public IUnknown {
- public:
-};
-
-MIDL_INTERFACE("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4")
-IVirtualDesktop : public IUnknown {
- public:
- virtual HRESULT STDMETHODCALLTYPE IsViewVisible(IApplicationView * pView,
- int* pfVisible) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetID(GUID * pGuid) = 0;
-};
-
-enum AdjacentDesktop { LeftDirection = 3, RightDirection = 4 };
-
-MIDL_INTERFACE("F31574D6-B682-4cdc-BD56-1827860ABEC6")
-IVirtualDesktopManagerInternal : public IUnknown {
- public:
- virtual HRESULT STDMETHODCALLTYPE GetCount(UINT * pCount) = 0;
- virtual HRESULT STDMETHODCALLTYPE MoveViewToDesktop(
- IApplicationView * pView, IVirtualDesktop * pDesktop) = 0;
- virtual HRESULT STDMETHODCALLTYPE CanViewMoveDesktops(
- IApplicationView * pView, int* pfCanViewMoveDesktops) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCurrentDesktop(IVirtualDesktop *
- *desktop) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetDesktops(IObjectArray * *ppDesktops) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetAdjacentDesktop(
- IVirtualDesktop * pDesktopReference, AdjacentDesktop uDirection,
- IVirtualDesktop * *ppAdjacentDesktop) = 0;
- virtual HRESULT STDMETHODCALLTYPE SwitchDesktop(IVirtualDesktop *
- pDesktop) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateDesktopW(IVirtualDesktop *
- *ppNewDesktop) = 0;
- virtual HRESULT STDMETHODCALLTYPE RemoveDesktop(
- IVirtualDesktop * pRemove, IVirtualDesktop * pFallbackDesktop) = 0;
- virtual HRESULT STDMETHODCALLTYPE FindDesktop(
- GUID * desktopId, IVirtualDesktop * *ppDesktop) = 0;
-};
-
namespace aura {
namespace {
@@ -83,9 +33,6 @@ namespace {
const base::TimeDelta kUpdateOcclusionDelay =
base::TimeDelta::FromMilliseconds(16);
-const base::TimeDelta kUpdateVirtualDesktopDelay =
- base::TimeDelta::FromMilliseconds(1000);
-
// This global variable can be accessed only on main thread.
NativeWindowOcclusionTrackerWin* g_tracker = nullptr;
@@ -221,7 +168,7 @@ bool NativeWindowOcclusionTrackerWin::IsWindowVisibleAndFullyOpaque(
if (IsIconic(hwnd))
return false;
- LONG ex_styles = GetWindowLong(hwnd, GWL_EXSTYLE);
+ LONG ex_styles = ::GetWindowLong(hwnd, GWL_EXSTYLE);
// Filter out "transparent" windows, windows where the mouse clicks fall
// through them.
if (ex_styles & WS_EX_TRANSPARENT)
@@ -278,7 +225,17 @@ bool NativeWindowOcclusionTrackerWin::IsWindowVisibleAndFullyOpaque(
return false;
if (IsRectEmpty(&win_rect))
return false;
+
+ // Ignore popup windows since they're transient unless it is a Chrome Widget
+ // Window.
+ if (::GetWindowLong(hwnd, GWL_STYLE) & WS_POPUP) {
+ if (!base::StartsWith(gfx::GetClassName(hwnd), L"Chrome_WidgetWin_")) {
+ return false;
+ }
+ }
+
*window_rect = gfx::Rect(win_rect);
+
return true;
}
@@ -362,19 +319,6 @@ NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
if (base::win::GetVersion() >= base::win::Version::WIN10) {
::CoCreateInstance(__uuidof(VirtualDesktopManager), nullptr, CLSCTX_ALL,
IID_PPV_ARGS(&virtual_desktop_manager_));
-
- Microsoft::WRL::ComPtr<IServiceProvider> service_provider;
- if (base::FeatureList::IsEnabled(
- features::kCalculateNativeWinOcclusionCheckVirtualDesktopUsed) &&
- SUCCEEDED(::CoCreateInstance(CLSID_ImmersiveShell, NULL,
- CLSCTX_LOCAL_SERVER,
- IID_PPV_ARGS(&service_provider)))) {
- service_provider->QueryService(
- CLSID_VirtualDesktopAPI_Unknown,
- IID_PPV_ARGS(&virtual_desktop_manager_internal_));
- if (virtual_desktop_manager_internal_)
- ComputeVirtualDesktopUsed();
- }
}
DETACH_FROM_SEQUENCE(sequence_checker_);
}
@@ -418,12 +362,12 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
DisableOcclusionTrackingForWindow(HWND hwnd) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
root_window_hwnds_occlusion_state_.erase(hwnd);
+ if (moving_window_ == hwnd)
+ moving_window_ = 0;
if (root_window_hwnds_occlusion_state_.empty()) {
UnregisterEventHooks();
if (occlusion_update_timer_.IsRunning())
occlusion_update_timer_.Stop();
- if (virtual_desktop_update_timer_.IsRunning())
- virtual_desktop_update_timer_.Stop();
}
}
@@ -570,25 +514,12 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
}
void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
- ComputeVirtualDesktopUsed() {
- UINT count = 0;
- if (SUCCEEDED(virtual_desktop_manager_internal_->GetCount(&count)))
- virtual_desktops_used_ = count > 1;
-}
-
-void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
ScheduleOcclusionCalculationIfNeeded() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!occlusion_update_timer_.IsRunning()) {
+ if (!occlusion_update_timer_.IsRunning())
occlusion_update_timer_.Start(
FROM_HERE, kUpdateOcclusionDelay, this,
&WindowOcclusionCalculator::ComputeNativeWindowOcclusionStatus);
- if (virtual_desktop_manager_internal_) {
- virtual_desktop_update_timer_.Start(
- FROM_HERE, kUpdateVirtualDesktopDelay, this,
- &WindowOcclusionCalculator::ComputeVirtualDesktopUsed);
- }
- }
}
void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
@@ -694,6 +625,10 @@ bool NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
return true;
}
+ // Ignore moving windows when deciding if windows under it are occluded.
+ if (hwnd == moving_window_)
+ return true;
+
// Check if |hwnd| is a root window; if so, we're done figuring out
// if it's occluded because we've seen all the windows "over" it.
auto it = root_window_hwnds_occlusion_state_.find(hwnd);
@@ -739,6 +674,15 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
if (id_object != OBJID_WINDOW)
return;
+ // We generally ignore events for popup windows, except for when the taskbar
+ // is hidden or when the popup is a Chrome Widget, in which case we
+ // recalculate occlusion.
+ bool calculate_occlusion = true;
+ if (::GetWindowLong(hwnd, GWL_STYLE) & WS_POPUP) {
+ calculate_occlusion =
+ base::StartsWith(gfx::GetClassName(hwnd), L"Chrome_WidgetWin_");
+ }
+
// Detect if either the alt tab view or the task list thumbnail is being
// shown. If so, mark all non-hidden windows as occluded, and remember that
// we're in the showing_thumbnails state. This lasts until we get told that
@@ -748,7 +692,7 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
// needed.
if (showing_thumbnails_)
return;
- std::string hwnd_class_name = base::UTF16ToUTF8(gfx::GetClassName(hwnd));
+ std::string hwnd_class_name = base::WideToUTF8(gfx::GetClassName(hwnd));
if ((hwnd_class_name == "MultitaskingViewFrame" ||
hwnd_class_name == "TaskListThumbnailWnd")) {
showing_thumbnails_ = true;
@@ -763,31 +707,45 @@ void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
// needed.
if (!showing_thumbnails_)
return;
- std::string hwnd_class_name = base::UTF16ToUTF8(gfx::GetClassName(hwnd));
+ std::string hwnd_class_name = base::WideToUTF8(gfx::GetClassName(hwnd));
if (hwnd_class_name == "MultitaskingViewFrame" ||
hwnd_class_name == "TaskListThumbnailWnd") {
showing_thumbnails_ = false;
- // Let occlusion calculation fix occlusion state.
+ // Let occlusion calculation fix occlusion state, even though hwnd might
+ // be a popup window.
+ calculate_occlusion = true;
}
}
-
- // Don't continually calculate occlusion while a window is moving, but rather
- // once at the beginning and once at the end.
- if (event == EVENT_SYSTEM_MOVESIZESTART) {
- window_is_moving_ = true;
+ // Don't continually calculate occlusion while a window is moving (unless it's
+ // a root window), but instead once at the beginning and once at the end.
+ // Remember the window being moved so if it's a root window, we can ignore
+ // it when deciding if windows under it are occluded.
+ else if (event == EVENT_SYSTEM_MOVESIZESTART) {
+ moving_window_ = hwnd;
} else if (event == EVENT_SYSTEM_MOVESIZEEND) {
- window_is_moving_ = false;
- } else if (window_is_moving_) {
+ moving_window_ = 0;
+ } else if (moving_window_ != 0) {
if (event == EVENT_OBJECT_LOCATIONCHANGE ||
event == EVENT_OBJECT_STATECHANGE) {
- return;
+ // Ignore move events if it's not a root window that's being moved. If it
+ // is a root window, we want to calculate occlusion to support tab
+ // dragging to windows that were occluded when the drag was started but
+ // are no longer occluded.
+ if (root_window_hwnds_occlusion_state_.find(hwnd) ==
+ root_window_hwnds_occlusion_state_.end()) {
+ return;
+ }
+ } else {
+ // If we get an event that isn't a location/state change, then we probably
+ // missed the movesizeend notification, or got events out of order. In
+ // that case, we want to go back to normal occlusion calculation.
+ moving_window_ = 0;
}
- // If we get an event that isn't a location/state change, then we probably
- // missed the movesizeend notification, or got events out of order. In
- // that case, we want to go back to calculating occlusion.
- window_is_moving_ = false;
}
+ if (!calculate_occlusion)
+ return;
+
// ProcessEventHookCallback is called from the task_runner's PeekMessage
// call, on the task runner's thread, but before the task_tracker thread sets
// up the thread sequence. In order to prevent DCHECK failures with the
@@ -822,7 +780,7 @@ bool NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
base::Optional<bool> NativeWindowOcclusionTrackerWin::
WindowOcclusionCalculator::IsWindowOnCurrentVirtualDesktop(HWND hwnd) {
- if (!virtual_desktop_manager_ || !virtual_desktops_used_)
+ if (!virtual_desktop_manager_)
return true;
BOOL on_current_desktop;
diff --git a/chromium/ui/aura/native_window_occlusion_tracker_win.h b/chromium/ui/aura/native_window_occlusion_tracker_win.h
index 8fe2f6f3348..4934e8b3175 100644
--- a/chromium/ui/aura/native_window_occlusion_tracker_win.h
+++ b/chromium/ui/aura/native_window_occlusion_tracker_win.h
@@ -34,8 +34,6 @@ namespace gfx {
class Rect;
}
-struct IVirtualDesktopManagerInternal;
-
namespace aura {
// This class keeps track of whether any HWNDs are occluding any app windows.
@@ -136,10 +134,6 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin
// their occlusion status has changed.
void ComputeNativeWindowOcclusionStatus();
- // Computes if virtual desktops are used. This is used as an optimization
- // since IsWindowOnCurrentVirtualDesktop is a slow call.
- void ComputeVirtualDesktopUsed();
-
// Schedules an occlusion calculation |update_occlusion_delay_| time in the
// future, if one isn't already scheduled.
void ScheduleOcclusionCalculationIfNeeded();
@@ -223,9 +217,6 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin
// Timer to delay occlusion update.
base::OneShotTimer occlusion_update_timer_;
- // Timer to check how many virtual desktops are present.
- base::OneShotTimer virtual_desktop_update_timer_;
-
// Used to keep track of whether we're in the middle of getting window move
// events, in order to wait until the window move is complete before
// calculating window occlusion.
@@ -248,18 +239,14 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin
// showing.
bool showing_thumbnails_ = false;
- // By caching if virtual desktops are in use or not we can avoid calling
- // IsWindowOnCurrentVirtualDesktop which is slow. Start with an initial
- // value of true so that we only optimize after we get confirmation that
- // there are no virtual desktops.
- bool virtual_desktops_used_ = true;
+ // Used to keep track of the window that's currently moving. That window
+ // is ignored for calculation occlusion so that tab dragging won't
+ // ignore windows occluded by the dragged window.
+ HWND moving_window_ = 0;
// Only used on Win10+.
Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager_;
- Microsoft::WRL::ComPtr<IVirtualDesktopManagerInternal>
- virtual_desktop_manager_internal_;
-
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<WindowOcclusionCalculator> weak_factory_{this};
@@ -272,8 +259,8 @@ class AURA_EXPORT NativeWindowOcclusionTrackerWin
// Returns true if we are interested in |hwnd| for purposes of occlusion
// calculation. We are interested in |hwnd| if it is a window that is
- // visible, opaque, and bounded. If we are interested in |hwnd|, stores the
- // window rectangle in |window_rect|.
+ // visible, opaque, bounded, and not a popup or floating window. If we are
+ // interested in |hwnd|, stores the window rectangle in |window_rect|.
static bool IsWindowVisibleAndFullyOpaque(HWND hwnd, gfx::Rect* window_rect);
// Updates root windows occclusion state. If |show_all_windows| is true,
diff --git a/chromium/ui/aura/scoped_simple_keyboard_hook.cc b/chromium/ui/aura/scoped_simple_keyboard_hook.cc
index 53f4c45c8c5..c39f0a1cf4c 100644
--- a/chromium/ui/aura/scoped_simple_keyboard_hook.cc
+++ b/chromium/ui/aura/scoped_simple_keyboard_hook.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "ui/events/keycodes/dom/dom_code.h"
namespace aura {
diff --git a/chromium/ui/aura/scoped_window_capture_request.cc b/chromium/ui/aura/scoped_window_capture_request.cc
new file mode 100644
index 00000000000..0d7c3f2ff17
--- /dev/null
+++ b/chromium/ui/aura/scoped_window_capture_request.cc
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium 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/scoped_window_capture_request.h"
+
+#include "ui/aura/window.h"
+
+namespace aura {
+
+ScopedWindowCaptureRequest::ScopedWindowCaptureRequest(
+ ScopedWindowCaptureRequest&& other)
+ : window_(other.window_) {
+ other.window_ = nullptr;
+}
+
+ScopedWindowCaptureRequest& ScopedWindowCaptureRequest::operator=(
+ ScopedWindowCaptureRequest&& rhs) {
+ if (window_)
+ window_->OnScopedWindowCaptureRequestRemoved();
+ window_ = rhs.window_;
+ rhs.window_ = nullptr;
+ return *this;
+}
+
+ScopedWindowCaptureRequest::~ScopedWindowCaptureRequest() {
+ if (window_)
+ window_->OnScopedWindowCaptureRequestRemoved();
+}
+
+viz::SubtreeCaptureId ScopedWindowCaptureRequest::GetCaptureId() const {
+ return window_ ? window_->subtree_capture_id() : viz::SubtreeCaptureId();
+}
+
+ScopedWindowCaptureRequest::ScopedWindowCaptureRequest(Window* window)
+ : window_(window) {
+ DCHECK(window_);
+ DCHECK(!window_->IsRootWindow());
+ window_->OnScopedWindowCaptureRequestAdded();
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/scoped_window_capture_request.h b/chromium/ui/aura/scoped_window_capture_request.h
new file mode 100644
index 00000000000..ee7e4f95637
--- /dev/null
+++ b/chromium/ui/aura/scoped_window_capture_request.h
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium 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_SCOPED_WINDOW_CAPTURE_REQUEST_H_
+#define UI_AURA_SCOPED_WINDOW_CAPTURE_REQUEST_H_
+
+#include "components/viz/common/surfaces/subtree_capture_id.h"
+#include "ui/aura/aura_export.h"
+
+namespace aura {
+
+class Window;
+
+// A scoped move-only object which is associated with a request to make a
+// non-root window individually capturable by a FrameSinkVideoCapturer. This
+// request is tracked as long as this object lives. Once all requests are
+// destroyed, the window will no longer be uniquely identifiable by a
+// viz::SubtreeCaptureId, and can no longer be individually capturable by the
+// FrameSinkVideoCapturer.
+// Note that making a window capturable forces the layer tree root at its layer
+// to be promoted to a render surface that draw into a render pass.
+// See https://crbug.com/1143930 for more details.
+class AURA_EXPORT ScopedWindowCaptureRequest {
+ public:
+ // Creates an empty request that doesn't affect any window.
+ ScopedWindowCaptureRequest() = default;
+ ScopedWindowCaptureRequest(ScopedWindowCaptureRequest&& other);
+ ScopedWindowCaptureRequest& operator=(ScopedWindowCaptureRequest&& rhs);
+ ~ScopedWindowCaptureRequest();
+
+ Window* window() const { return window_; }
+
+ viz::SubtreeCaptureId GetCaptureId() const;
+
+ private:
+ friend class Window;
+
+ // Private so it can only be called through Window::MakeWindowCapturable().
+ explicit ScopedWindowCaptureRequest(Window* window);
+
+ // The window on which this request has been made. Can be |nullptr| if this is
+ // an empty request (created by the default ctor), or if this object was
+ // std::move()'d from.
+ Window* window_ = nullptr;
+};
+
+} // namespace aura
+
+#endif // UI_AURA_SCOPED_WINDOW_CAPTURE_REQUEST_H_
diff --git a/chromium/ui/aura/test/ui_controls_ozone.cc b/chromium/ui/aura/test/ui_controls_ozone.cc
index 43a7a07ada7..2572a3c2f14 100644
--- a/chromium/ui/aura/test/ui_controls_ozone.cc
+++ b/chromium/ui/aura/test/ui_controls_ozone.cc
@@ -5,6 +5,7 @@
#include "ui/aura/test/ui_controls_ozone.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
namespace aura {
namespace test {
@@ -203,7 +204,7 @@ bool UIControlsOzone::SendMouseClick(ui_controls::MouseButton type) {
ui_controls::kNoAccelerator);
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
bool UIControlsOzone::SendTouchEvents(int action, int id, int x, int y) {
return SendTouchEventsNotifyWhenDone(action, id, x, y, base::OnceClosure());
}
diff --git a/chromium/ui/aura/test/ui_controls_ozone.h b/chromium/ui/aura/test/ui_controls_ozone.h
index e85844fba15..325017400a9 100644
--- a/chromium/ui/aura/test/ui_controls_ozone.h
+++ b/chromium/ui/aura/test/ui_controls_ozone.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/chromeos_buildflags.h"
#include "ui/aura/env.h"
#include "ui/aura/test/aura_test_utils.h"
#include "ui/aura/test/env_test_helper.h"
@@ -60,7 +61,7 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
base::OnceClosure closure,
int accelerator_state) override;
bool SendMouseClick(ui_controls::MouseButton type) override;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
bool SendTouchEvents(int action, int id, int x, int y) override;
bool SendTouchEventsNotifyWhenDone(int action,
int id,
diff --git a/chromium/ui/aura/window.cc b/chromium/ui/aura/window.cc
index a752e293658..283092e62f2 100644
--- a/chromium/ui/aura/window.cc
+++ b/chromium/ui/aura/window.cc
@@ -13,9 +13,9 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -283,6 +283,13 @@ bool Window::IsVisible() const {
return visible_ ? layer()->IsDrawn() : false;
}
+ScopedWindowCaptureRequest Window::MakeWindowCapturable() {
+ DCHECK(!IsRootWindow()) << "Root windows can already be captured using their "
+ "FrameSinkId; no need to call this.";
+
+ return ScopedWindowCaptureRequest(this);
+}
+
gfx::Rect Window::GetBoundsInRootWindow() const {
// TODO(beng): There may be a better way to handle this, and the existing code
// is likely wrong anyway in a multi-display world, but this will
@@ -1413,6 +1420,18 @@ gfx::PointF Window::GetScreenLocationF(const ui::LocatedEvent& event) const {
return screen_location;
}
+std::unique_ptr<ui::Layer> Window::ReleaseLayer() {
+ if (number_of_capture_requests_) {
+ // Before we release our own layer, if this window was marked for capture,
+ // we need to reset the SubtreeCaptureId on that layer as it will no longer
+ // be associated with us.
+ DCHECK(subtree_capture_id_.is_valid());
+ if (layer())
+ layer()->SetSubtreeCaptureId(viz::SubtreeCaptureId());
+ }
+ return LayerOwner::ReleaseLayer();
+}
+
std::unique_ptr<ui::Layer> Window::RecreateLayer() {
WindowOcclusionTracker::ScopedPause pause_occlusion_tracking;
@@ -1430,6 +1449,12 @@ std::unique_ptr<ui::Layer> Window::RecreateLayer() {
if (GetFrameSinkId().is_valid() && old_layer)
AllocateLocalSurfaceId();
+ // The old layer subtree must no longer be capturable.
+ // Note that we don't need to worry about the newly recreated layer since
+ // Window::SetLayer() will have taken care of it already.
+ if (number_of_capture_requests_ && old_layer)
+ old_layer->SetSubtreeCaptureId(viz::SubtreeCaptureId());
+
// Observers are guaranteed to be notified when an opacity or transform
// animation ends.
if (was_animating_opacity) {
@@ -1451,6 +1476,17 @@ std::unique_ptr<ui::Layer> Window::RecreateLayer() {
return old_layer;
}
+void Window::SetLayer(std::unique_ptr<ui::Layer> alayer) {
+ LayerOwner::SetLayer(std::move(alayer));
+ if (number_of_capture_requests_) {
+ // If this window was marked for capture before, then the new layer that we
+ // own now should be given the current SubtreeCaptureId that we have.
+ DCHECK(subtree_capture_id_.is_valid());
+ if (layer())
+ layer()->SetSubtreeCaptureId(subtree_capture_id_);
+ }
+}
+
void Window::OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) {
DCHECK_EQ(surface_info.id().frame_sink_id(), GetFrameSinkId());
layer()->SetShowSurface(surface_info.id(), bounds().size(), SK_ColorWHITE,
@@ -1458,7 +1494,8 @@ void Window::OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) {
false /* stretch_content_to_fill_bounds */);
}
-void Window::OnFrameTokenChanged(uint32_t frame_token) {}
+void Window::OnFrameTokenChanged(uint32_t frame_token,
+ base::TimeTicks activation_time) {}
void Window::UpdateLayerName() {
#if DCHECK_IS_ON()
@@ -1508,4 +1545,32 @@ bool Window::IsEmbeddingExternalContent() const {
return parent_local_surface_id_allocator_.get() != nullptr;
}
+void Window::OnScopedWindowCaptureRequestAdded() {
+ if (++number_of_capture_requests_ == 1) {
+ DCHECK(!subtree_capture_id_.is_valid());
+ DCHECK(!layer() || !layer()->GetSubtreeCaptureId().is_valid());
+
+ subtree_capture_id_ =
+ Env::GetInstance()->context_factory()->AllocateSubtreeCaptureId();
+ if (layer())
+ layer()->SetSubtreeCaptureId(subtree_capture_id_);
+ }
+
+ DCHECK(subtree_capture_id_.is_valid());
+}
+
+void Window::OnScopedWindowCaptureRequestRemoved() {
+ DCHECK(subtree_capture_id_.is_valid());
+ DCHECK(number_of_capture_requests_);
+
+ --number_of_capture_requests_;
+ DCHECK_GE(number_of_capture_requests_, 0);
+
+ if (number_of_capture_requests_ == 0) {
+ subtree_capture_id_ = viz::SubtreeCaptureId();
+ if (layer())
+ layer()->SetSubtreeCaptureId(subtree_capture_id_);
+ }
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/window.h b/chromium/ui/aura/window.h
index 2dfa559ca07..b422c18d087 100644
--- a/chromium/ui/aura/window.h
+++ b/chromium/ui/aura/window.h
@@ -26,9 +26,11 @@
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "components/viz/common/surfaces/scoped_surface_id_allocator.h"
+#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "components/viz/host/host_frame_sink_client.h"
#include "ui/aura/aura_export.h"
#include "ui/aura/client/window_types.h"
+#include "ui/aura/scoped_window_capture_request.h"
#include "ui/aura/window_observer.h"
#include "ui/base/class_property.h"
#include "ui/compositor/layer_animator.h"
@@ -233,6 +235,28 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
return occluded_region_in_root_;
}
+ // Makes this *non-root* window individually capturable by the
+ // |FrameSinkVideoCapturer| by tagging its layer with a unique
+ // |viz::SubtreeCaptureId| which will force the layer tree root at this
+ // window's layer to a render surface that draws into a render pass that is
+ // identifiable by the capturer using that ID.
+ //
+ // Note that this should only be called for non-root windows. Root windows are
+ // already capturable by the capturer as they're identifiable by their
+ // |viz::FrameSinkId| and thei associated root render pass, so there's no need
+ // to call this.
+ //
+ // This returns a scoped object associated with this request to make the
+ // window capturable, since multiple capturers can capture the same window at
+ // the same time. Once all requests are destroyed, this window will no longer
+ // be individually capturable, and its layer won't be tagged with a valid
+ // |viz::SubtreeCaptureId|.
+ // See https://crbug.com/1143930 for more details.
+ ScopedWindowCaptureRequest MakeWindowCapturable() WARN_UNUSED_RESULT;
+ const viz::SubtreeCaptureId& subtree_capture_id() const {
+ return subtree_capture_id_;
+ }
+
// Returns the window's bounds in root window's coordinates.
gfx::Rect GetBoundsInRootWindow() const;
@@ -400,8 +424,10 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
float new_device_scale_factor) override;
void UpdateVisualState() override;
- // Overridden from ui::LayerOwner:
+ // ui::LayerOwner:
+ std::unique_ptr<ui::Layer> ReleaseLayer() override;
std::unique_ptr<ui::Layer> RecreateLayer() override;
+ void SetLayer(std::unique_ptr<ui::Layer> layer) override;
#if DCHECK_IS_ON()
// These methods are useful when debugging.
@@ -508,6 +534,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
friend class HitTestDataProviderAura;
friend class LayoutManager;
friend class PropertyConverter;
+ friend class ScopedWindowCaptureRequest;
friend class ScopedWindowEventTargetingBlocker;
friend class WindowTargeter;
friend class test::WindowTestApi;
@@ -617,7 +644,8 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// viz::HostFrameSinkClient:
void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
- void OnFrameTokenChanged(uint32_t frame_token) override;
+ void OnFrameTokenChanged(uint32_t frame_token,
+ base::TimeTicks activation_time) override;
// Updates the layer name based on the window's name and id.
void UpdateLayerName();
@@ -628,6 +656,14 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
const viz::LocalSurfaceId& GetCurrentLocalSurfaceId() const;
bool IsEmbeddingExternalContent() const;
+ // Called by the constructor of ScopedWindowCaptureRequest to add a request to
+ // make this non-root window capturable by the FrameSinkVideoCapturer.
+ void OnScopedWindowCaptureRequestAdded();
+
+ // Called by the destructor of ScopedWindowCaptureRequest to remove a request
+ // to make this non-root window capturable by the FrameSinkVideoCapturer.
+ void OnScopedWindowCaptureRequestRemoved();
+
// Bounds of this window relative to the parent. This is cached as the bounds
// of the Layer and Window are not necessarily the same. In particular bounds
// of the Layer are relative to the first ancestor with a Layer, where as this
@@ -688,6 +724,22 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
base::ReentrantObserverList<WindowObserver, true> observers_;
+ // Video capturing support ---------------------------------------------------
+
+ // A non-root window must be marked with a viz::SubtreeCaptureId so that it
+ // can be captured by a FrameSinkVideoCapturer. Multiple clients can request
+ // to capture the same window at the same time. This is the number of those
+ // requests, which once it goes to zero, we well clear the
+ // viz::SubtreeCaptureId from the layer associated with this window.
+ int number_of_capture_requests_ = 0;
+
+ // The ID allocated for the layer tree rooted at this window's layer, so that
+ // it can be uniquely identified by the FrameSinkVideoCapturer. This can only
+ // be set for non-root windows. Root windows can be captured normally by the
+ // capturer using their frame sink ID, since those root windows are already
+ // associated with a root compositor render pass.
+ viz::SubtreeCaptureId subtree_capture_id_;
+
// Embedding support ---------------------------------------------------------
// Used to detect changes in device scale factor that require generating a
diff --git a/chromium/ui/aura/window_event_dispatcher.cc b/chromium/ui/aura/window_event_dispatcher.cc
index af90753ae70..9eddddd0499 100644
--- a/chromium/ui/aura/window_event_dispatcher.cc
+++ b/chromium/ui/aura/window_event_dispatcher.cc
@@ -89,7 +89,6 @@ WindowEventDispatcher::ObserverNotifier::~ObserverNotifier() {
WindowEventDispatcher::WindowEventDispatcher(WindowTreeHost* host)
: host_(host),
- observer_manager_(this),
event_targeter_(std::make_unique<WindowTargeter>()) {
Env::GetInstance()->gesture_recognizer()->AddGestureEventHelper(this);
Env::GetInstance()->AddObserver(this);
@@ -519,6 +518,8 @@ ui::EventDispatchDetails WindowEventDispatcher::PreDispatchEvent(
event->time_stamp());
}
+ WindowTracker target_window_tracker;
+ target_window_tracker.Add(target_window);
if (!dispatching_held_event_) {
bool can_be_held = IsEventCandidateForHold(*event);
if (!move_hold_count_ || !can_be_held) {
@@ -529,6 +530,12 @@ ui::EventDispatchDetails WindowEventDispatcher::PreDispatchEvent(
return details;
}
}
+ if (target_window_tracker.windows().empty()) {
+ // The event target is destroyed while processing the held event.
+ DispatchDetails details;
+ details.target_destroyed = true;
+ return details;
+ }
DispatchDetails details;
if (event->IsMouseEvent()) {
@@ -620,7 +627,7 @@ void WindowEventDispatcher::OnWindowDestroying(Window* window) {
void WindowEventDispatcher::OnWindowDestroyed(Window* window) {
// We observe all windows regardless of what root Window (if any) they're
// attached to.
- observer_manager_.Remove(window);
+ observation_manager_.RemoveObservation(window);
// In theory this should be cleaned up by other checks, but we are getting
// crashes that seem to indicate otherwise. See https://crbug.com/942552 for
@@ -630,8 +637,8 @@ void WindowEventDispatcher::OnWindowDestroyed(Window* window) {
}
void WindowEventDispatcher::OnWindowAddedToRootWindow(Window* attached) {
- if (!observer_manager_.IsObserving(attached))
- observer_manager_.Add(attached);
+ if (!observation_manager_.IsObservingSource(attached))
+ observation_manager_.AddObservation(attached);
if (!host_->window()->Contains(attached))
return;
@@ -738,7 +745,7 @@ void WindowEventDispatcher::OnWindowTransformed(
// WindowEventDispatcher, EnvObserver implementation:
void WindowEventDispatcher::OnWindowInitialized(Window* window) {
- observer_manager_.Add(window);
+ observation_manager_.AddObservation(window);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/ui/aura/window_event_dispatcher.h b/chromium/ui/aura/window_event_dispatcher.h
index 573cec8f5ca..102d162f0d4 100644
--- a/chromium/ui/aura/window_event_dispatcher.h
+++ b/chromium/ui/aura/window_event_dispatcher.h
@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_multi_source_observation.h"
#include "ui/aura/aura_export.h"
#include "ui/aura/client/capture_delegate.h"
#include "ui/aura/env_observer.h"
@@ -313,7 +313,8 @@ class AURA_EXPORT WindowEventDispatcher : public ui::EventProcessor,
// Set when dispatching a held event.
ui::LocatedEvent* dispatching_held_event_ = nullptr;
- ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
+ base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
+ observation_manager_{this};
// The default EventTargeter for WindowEventDispatcher generated events.
std::unique_ptr<WindowTargeter> event_targeter_;
diff --git a/chromium/ui/aura/window_event_dispatcher_unittest.cc b/chromium/ui/aura/window_event_dispatcher_unittest.cc
index 35fd78d0632..8b05ebc4c55 100644
--- a/chromium/ui/aura/window_event_dispatcher_unittest.cc
+++ b/chromium/ui/aura/window_event_dispatcher_unittest.cc
@@ -10,10 +10,10 @@
#include <vector>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -3108,4 +3108,84 @@ TEST_F(WindowEventDispatcherTest, TouchEventWithScaledWindow) {
root_window()->RemovePreTargetHandler(&root_recorder);
}
+// A test case for crbug.com/1099985
+TEST_F(WindowEventDispatcherTest, TargetIsDestroyedByHeldEvent) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+
+ // Create a window which should be a target of all MouseEvent in this tests.
+ test::TestWindowDelegate delegate;
+ std::unique_ptr<aura::Window> mouse_target(CreateTestWindowWithDelegate(
+ &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
+
+ // Create a window which has a focus, so should receive all KeyEvents.
+ ConsumeKeyHandler key_handler;
+ // Not using std::unique_ptr<> intentionally
+ aura::Window* focused(test::CreateTestWindowWithBounds(
+ gfx::Rect(200, 200, 100, 100), root_window()));
+ focused->SetProperty(client::kSkipImeProcessing, true);
+ focused->AddPostTargetHandler(&key_handler);
+ focused->Show();
+ focused->Focus();
+
+ // Make sure that the key event goes to the |focused| window.
+ ui::KeyEvent key_press(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
+ DispatchEventUsingWindowDispatcher(&key_press);
+ EXPECT_EQ(1, key_handler.num_key_events());
+ key_handler.Reset();
+
+ ui::MouseEvent mouse_move_event(ui::ET_MOUSE_MOVED, gfx::Point(1, 1),
+ gfx::Point(1, 1), ui::EventTimeForNow(), 0,
+ 0);
+ DispatchEventUsingWindowDispatcher(&mouse_move_event);
+ // Discard MOUSE_ENTER.
+ recorder.Reset();
+
+ host()->dispatcher()->HoldPointerMoves();
+
+ // The dragged event should not be sent to the |target| window because
+ // WindowEventDispatcher is holding it now.
+ ui::MouseEvent mouse_dragged_event(ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0),
+ gfx::Point(0, 0), ui::EventTimeForNow(), 0,
+ 0);
+ DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
+ EXPECT_TRUE(recorder.events().empty());
+
+ // Create a event handler which destroys the |focused| window when it sees any
+ // mouse event.
+ class Handler : public ui::test::TestEventHandler {
+ public:
+ explicit Handler(aura::Window* focused) : focused_(focused) {}
+ ~Handler() override = default;
+
+ Handler(const Handler&) = delete;
+ Handler& operator=(const Handler&) = delete;
+
+ // Overridden from ui::EventHandler:
+ void OnMouseEvent(ui::MouseEvent* event) override {
+ ui::test::TestEventHandler::OnMouseEvent(event);
+ LOG(ERROR) << "|focused_| is being deleted";
+ // !!!
+ delete focused_;
+ }
+
+ private:
+ aura::Window* focused_;
+ };
+ Handler mouse_handler(focused);
+ mouse_target->AddPostTargetHandler(&mouse_handler);
+
+ // Sending a key event should stop the hold and the mouse event goes to the
+ // |target| window.
+ // The key event should not be sent to the handler because the focused window
+ // is destroyed before the event is dispatched.
+ ui::KeyEvent key_press2(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
+ DispatchEventUsingWindowDispatcher(&key_press2);
+ EXPECT_EQ(1u, recorder.events().size());
+ EXPECT_EQ(0, key_handler.num_key_events());
+ EXPECT_EQ(1, mouse_handler.num_mouse_events());
+
+ root_window()->RemovePreTargetHandler(&recorder);
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/window_occlusion_tracker.cc b/chromium/ui/aura/window_occlusion_tracker.cc
index 8a13839bfdb..07a1f10402a 100644
--- a/chromium/ui/aura/window_occlusion_tracker.cc
+++ b/chromium/ui/aura/window_occlusion_tracker.cc
@@ -6,6 +6,7 @@
#include "base/auto_reset.h"
#include "base/containers/adapters.h"
+#include "base/containers/contains.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "third_party/skia/include/core/SkRect.h"
@@ -223,8 +224,8 @@ void WindowOcclusionTracker::Track(Window* window) {
if (!insert_result.second)
return;
- if (!window_observer_.IsObserving(window))
- window_observer_.Add(window);
+ if (!window_observations_.IsObservingSource(window))
+ window_observations_.AddObservation(window);
if (window->GetRootWindow())
TrackedWindowAddedToRoot(window);
}
@@ -722,10 +723,10 @@ void WindowOcclusionTracker::TrackedWindowRemovedFromRoot(Window* window) {
void WindowOcclusionTracker::RemoveObserverFromWindowAndDescendants(
Window* window) {
if (WindowIsTracked(window)) {
- DCHECK(window_observer_.IsObserving(window));
+ DCHECK(window_observations_.IsObservingSource(window));
} else {
- if (window_observer_.IsObserving(window))
- window_observer_.Remove(window);
+ if (window_observations_.IsObservingSource(window))
+ window_observations_.RemoveObservation(window);
window->layer()->GetAnimator()->RemoveObserver(this);
animated_windows_.erase(window);
}
@@ -735,10 +736,10 @@ void WindowOcclusionTracker::RemoveObserverFromWindowAndDescendants(
void WindowOcclusionTracker::AddObserverToWindowAndDescendants(Window* window) {
if (WindowIsTracked(window)) {
- DCHECK(window_observer_.IsObserving(window));
+ DCHECK(window_observations_.IsObservingSource(window));
} else {
- DCHECK(!window_observer_.IsObserving(window));
- window_observer_.Add(window);
+ DCHECK(!window_observations_.IsObservingSource(window));
+ window_observations_.AddObservation(window);
}
for (Window* child_window : window->children())
AddObserverToWindowAndDescendants(child_window);
@@ -818,7 +819,7 @@ void WindowOcclusionTracker::OnWindowHierarchyChanged(
Window* const window = params.target;
Window* const root_window = window->GetRootWindow();
if (root_window && base::Contains(root_windows_, root_window) &&
- !window_observer_.IsObserving(window)) {
+ !window_observations_.IsObservingSource(window)) {
AddObserverToWindowAndDescendants(window);
}
}
@@ -917,7 +918,7 @@ void WindowOcclusionTracker::OnWindowStackingChanged(Window* window) {
void WindowOcclusionTracker::OnWindowDestroyed(Window* window) {
DCHECK(!window->GetRootWindow() || (window == window->GetRootWindow()));
tracked_windows_.erase(window);
- window_observer_.Remove(window);
+ window_observations_.RemoveObservation(window);
// Animations should be completed or aborted before a window is destroyed.
DCHECK(!window->layer()->GetAnimator()->IsAnimatingOnePropertyOf(
kOcclusionCanChangeWhenPropertyAnimationEnds));
diff --git a/chromium/ui/aura/window_occlusion_tracker.h b/chromium/ui/aura/window_occlusion_tracker.h
index c41a134325d..70a6477489a 100644
--- a/chromium/ui/aura/window_occlusion_tracker.h
+++ b/chromium/ui/aura/window_occlusion_tracker.h
@@ -12,7 +12,7 @@
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_multi_source_observation.h"
#include "ui/aura/aura_export.h"
#include "ui/aura/native_window_occlusion_tracker.h"
#include "ui/aura/window.h"
@@ -381,7 +381,8 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
int num_pause_occlusion_tracking_ = 0;
// Tracks the observed windows.
- ScopedObserver<Window, WindowObserver> window_observer_{this};
+ base::ScopedMultiSourceObservation<Window, WindowObserver>
+ window_observations_{this};
// Callback to be invoked for additional window has content check.
WindowHasContentCallback window_has_content_callback_;
diff --git a/chromium/ui/aura/window_targeter.cc b/chromium/ui/aura/window_targeter.cc
index d0d68f41305..46e718a7943 100644
--- a/chromium/ui/aura/window_targeter.cc
+++ b/chromium/ui/aura/window_targeter.cc
@@ -4,6 +4,7 @@
#include "ui/aura/window_targeter.h"
+#include "build/chromeos_buildflags.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/event_client.h"
#include "ui/aura/client/focus_client.h"
@@ -122,7 +123,7 @@ Window* WindowTargeter::FindTargetInRootWindow(Window* root_window,
if (consumer)
return static_cast<Window*>(consumer);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// If the initial touch is outside the window's display, target the root.
// This is used for bezel gesture events (eg. swiping in from screen edge).
display::Display display =
@@ -171,7 +172,7 @@ bool WindowTargeter::ProcessEventIfTargetsDifferentRootWindow(
window_tree_host->GetRootTransform(),
window_tree_host->GetRootTransformForLocalEventCoordinates());
}
- ignore_result(new_root->GetHost()->event_sink()->OnEventFromSource(event));
+ ignore_result(new_root->GetHost()->GetEventSink()->OnEventFromSource(event));
return true;
}
@@ -223,7 +224,7 @@ Window* WindowTargeter::FindTargetForLocatedEvent(Window* window,
if (target) {
window->ConvertEventToTarget(target, event);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
if (window->IsRootWindow() && event->HasNativeEvent()) {
// If window is root, and the target is in a different host, we need to
// convert the native event to the target's host as well. This happens
@@ -272,35 +273,18 @@ bool WindowTargeter::SubtreeCanAcceptEvent(
bool WindowTargeter::EventLocationInsideBounds(
Window* window,
const ui::LocatedEvent& event) const {
- gfx::Rect mouse_rect;
- gfx::Rect touch_rect;
- if (!GetHitTestRects(window, &mouse_rect, &touch_rect))
- return false;
- const gfx::Vector2d offset = -window->bounds().OffsetFromOrigin();
- mouse_rect.Offset(offset);
- touch_rect.Offset(offset);
gfx::Point point = event.location();
if (window->parent())
Window::ConvertPointToTarget(window->parent(), window, &point);
- const bool point_in_rect = event.IsTouchEvent() || event.IsGestureEvent()
- ? touch_rect.Contains(point)
- : mouse_rect.Contains(point);
- if (!point_in_rect)
- return false;
-
- auto shape_rects = GetExtraHitTestShapeRects(window);
- if (!shape_rects)
- return true;
-
- for (const gfx::Rect& shape_rect : *shape_rects) {
- if (shape_rect.Contains(point)) {
- return true;
- }
- }
+ BoundsType bounds_type = BoundsType::kMouse;
+ if (event.IsTouchEvent())
+ bounds_type = BoundsType::kTouch;
+ else if (event.IsGestureEvent())
+ bounds_type = BoundsType::kGesture;
- return false;
+ return PointInsideBounds(window, bounds_type, point);
}
bool WindowTargeter::ShouldUseExtendedBounds(const aura::Window* w) const {
@@ -355,4 +339,63 @@ Window* WindowTargeter::FindTargetForLocatedEventRecursively(
return root_window->CanAcceptEvent(*event) ? root_window : nullptr;
}
+bool WindowTargeter::PointInsideBounds(Window* window,
+ BoundsType bounds_type,
+ const gfx::Point& point) const {
+ gfx::Rect mouse_rect;
+ gfx::Rect touch_rect;
+ if (!GetHitTestRects(window, &mouse_rect, &touch_rect))
+ return false;
+
+ const gfx::Vector2d offset = -window->bounds().OffsetFromOrigin();
+ mouse_rect.Offset(offset);
+ touch_rect.Offset(offset);
+
+ const bool point_in_rect =
+ bounds_type == BoundsType::kTouch || bounds_type == BoundsType::kGesture
+ ? touch_rect.Contains(point)
+ : mouse_rect.Contains(point);
+ if (point_in_rect) {
+ auto shape_rects = GetExtraHitTestShapeRects(window);
+ if (!shape_rects)
+ return true;
+
+ for (const gfx::Rect& shape_rect : *shape_rects) {
+ if (shape_rect.Contains(point)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ if (ShouldUseExtendedBounds(window) &&
+ (!mouse_extend_.IsEmpty() || !touch_extend_.IsEmpty())) {
+ // Insets take priority over child traversal, otherwise it's possible to
+ // have a window that has a non-interactable region in the middle.
+ return false;
+ }
+
+ if (window->layer()->GetMasksToBounds()) {
+ // If the layer masks to bounds, children are clipped and shouldn't receive
+ // input events.
+ return false;
+ }
+
+ // Child windows are not always fully contained in the current window.
+ std::unique_ptr<ui::EventTargetIterator> iter = window->GetChildIterator();
+ if (!iter)
+ return false;
+
+ for (ui::EventTarget* child = iter->GetNextTarget(); child;
+ child = iter->GetNextTarget()) {
+ auto* child_window = static_cast<Window*>(child);
+ gfx::Point child_point(point);
+ Window::ConvertPointToTarget(window, child_window, &child_point);
+ if (PointInsideBounds(child_window, bounds_type, child_point))
+ return true;
+ }
+ return false;
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/window_targeter.h b/chromium/ui/aura/window_targeter.h
index e0485413abd..7fdf3f46bda 100644
--- a/chromium/ui/aura/window_targeter.h
+++ b/chromium/ui/aura/window_targeter.h
@@ -14,6 +14,7 @@
#include "ui/gfx/geometry/insets.h"
namespace gfx {
+class Point;
class Rect;
}
@@ -130,10 +131,22 @@ class AURA_EXPORT WindowTargeter : public ui::EventTargeter {
// To call OnInstalled().
friend class Window;
+ enum class BoundsType {
+ kMouse,
+ kTouch,
+ kGesture,
+ };
+
Window* FindTargetForNonKeyEvent(Window* root_window, ui::Event* event);
Window* FindTargetForLocatedEventRecursively(Window* root_window,
ui::LocatedEvent* event);
+ // Whether |point| is inside |window| or its descendents using |bounds_type|
+ // as a rect source. |point| should be relative to |window|.
+ bool PointInsideBounds(Window* window,
+ BoundsType bounds_type,
+ const gfx::Point& point) const;
+
// The Window this WindowTargeter is installed on. Null if not attached to a
// Window.
aura::Window* window_ = nullptr;
diff --git a/chromium/ui/aura/window_targeter_unittest.cc b/chromium/ui/aura/window_targeter_unittest.cc
index 9ab8a23e41e..f4e6b465f59 100644
--- a/chromium/ui/aura/window_targeter_unittest.cc
+++ b/chromium/ui/aura/window_targeter_unittest.cc
@@ -288,6 +288,43 @@ TEST_F(WindowTargeterTest, Bounds) {
EXPECT_EQ(child_r, targeter->FindTargetForEvent(root_target, &third));
}
+TEST_F(WindowTargeterTest, NonFullyContainedBounds) {
+ test::TestWindowDelegate delegate;
+ std::unique_ptr<Window> parent(
+ CreateNormalWindow(1, root_window(), &delegate));
+ std::unique_ptr<Window> child(CreateNormalWindow(1, parent.get(), &delegate));
+
+ parent->SetBounds(gfx::Rect(0, 0, 30, 30));
+ child->SetBounds(gfx::Rect(15, 15, 5, 100));
+
+ auto* targeter =
+ static_cast<ui::EventTarget*>(root_window())->GetEventTargeter();
+
+ ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(17, 75),
+ gfx::Point(17, 75), ui::EventTimeForNow(), ui::EF_NONE,
+ ui::EF_NONE);
+ EXPECT_EQ(child.get(), targeter->FindTargetForEvent(root_window(), &mouse));
+}
+
+TEST_F(WindowTargeterTest, NonFullyContainedBoundsWithMasksToBounds) {
+ test::TestWindowDelegate delegate;
+ std::unique_ptr<Window> parent(
+ CreateNormalWindow(1, root_window(), &delegate));
+ std::unique_ptr<Window> child(CreateNormalWindow(1, parent.get(), &delegate));
+
+ parent->SetBounds(gfx::Rect(0, 0, 30, 30));
+ parent->layer()->SetMasksToBounds(true);
+ child->SetBounds(gfx::Rect(15, 15, 5, 100));
+
+ auto* targeter =
+ static_cast<ui::EventTarget*>(root_window())->GetEventTargeter();
+
+ ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(17, 75),
+ gfx::Point(17, 75), ui::EventTimeForNow(), ui::EF_NONE,
+ ui::EF_NONE);
+ EXPECT_EQ(root_window(), targeter->FindTargetForEvent(root_window(), &mouse));
+}
+
class IgnoreWindowTargeter : public WindowTargeter {
public:
IgnoreWindowTargeter() {}
diff --git a/chromium/ui/aura/window_tree_host.cc b/chromium/ui/aura/window_tree_host.cc
index b2521da1ba1..6faeee8d7eb 100644
--- a/chromium/ui/aura/window_tree_host.cc
+++ b/chromium/ui/aura/window_tree_host.cc
@@ -8,6 +8,7 @@
#include "base/feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
+#include "build/chromeos_buildflags.h"
#include "components/viz/common/features.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/cursor_client.h"
@@ -116,10 +117,6 @@ bool WindowTreeHost::HasObserver(const WindowTreeHostObserver* observer) const {
return observers_.HasObserver(observer);
}
-ui::EventSink* WindowTreeHost::event_sink() {
- return dispatcher_.get();
-}
-
base::WeakPtr<WindowTreeHost> WindowTreeHost::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
@@ -282,7 +279,7 @@ ui::EventDispatchDetails WindowTreeHost::DispatchKeyEventPostIME(
// We should bypass event rewriters here as they've been tried before.
ui::EventDispatchDetails dispatch_details =
- event_sink()->OnEventFromSource(event);
+ GetEventSink()->OnEventFromSource(event);
if (!dispatch_details.dispatcher_destroyed)
dispatcher_->set_skip_ime(false);
return dispatch_details;
@@ -382,6 +379,7 @@ void WindowTreeHost::DestroyCompositor() {
}
void WindowTreeHost::DestroyDispatcher() {
+ Env::GetInstance()->NotifyHostDestroyed(this);
delete window_;
window_ = nullptr;
dispatcher_.reset();
@@ -396,9 +394,11 @@ void WindowTreeHost::DestroyDispatcher() {
//window()->RemoveOrDestroyChildren();
}
-void WindowTreeHost::CreateCompositor(const viz::FrameSinkId& frame_sink_id,
- bool force_software_compositor,
- bool use_external_begin_frame_control) {
+void WindowTreeHost::CreateCompositor(
+ const viz::FrameSinkId& frame_sink_id,
+ bool force_software_compositor,
+ bool use_external_begin_frame_control,
+ bool enable_compositing_based_throttling) {
Env* env = Env::GetInstance();
ui::ContextFactory* context_factory = env->context_factory();
DCHECK(context_factory);
@@ -407,8 +407,8 @@ void WindowTreeHost::CreateCompositor(const viz::FrameSinkId& frame_sink_id,
: context_factory->AllocateFrameSinkId(),
context_factory, base::ThreadTaskRunnerHandle::Get(),
ui::IsPixelCanvasRecordingEnabled(), use_external_begin_frame_control,
- force_software_compositor);
-#if defined(OS_CHROMEOS)
+ force_software_compositor, enable_compositing_based_throttling);
+#if BUILDFLAG(IS_CHROMEOS_ASH)
compositor_->AddObserver(this);
#endif
if (!dispatcher()) {
@@ -507,7 +507,7 @@ void WindowTreeHost::OnDisplayMetricsChanged(const display::Display& display,
// Chrome OS is handled in WindowTreeHostManager::OnDisplayMetricsChanged.
// Chrome OS requires additional handling for the bounds that we do not need to
// do for other OSes.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
if (metrics & DISPLAY_METRIC_DEVICE_SCALE_FACTOR &&
display.id() == GetDisplayId())
OnHostResizedInPixels(GetBoundsInPixels().size());
@@ -559,8 +559,10 @@ void WindowTreeHost::OnCompositingChildResizing(ui::Compositor* compositor) {
holding_pointer_moves_ = true;
}
-void WindowTreeHost::OnCompositingShuttingDown(ui::Compositor* compositor) {
- compositor->RemoveObserver(this);
+void WindowTreeHost::OnFrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& ids) {
+ for (auto& observer : observers_)
+ observer.OnCompositingFrameSinksToThrottleUpdated(this, ids);
}
} // namespace aura
diff --git a/chromium/ui/aura/window_tree_host.h b/chromium/ui/aura/window_tree_host.h
index e00fb7b60ba..93c56f7ffbc 100644
--- a/chromium/ui/aura/window_tree_host.h
+++ b/chromium/ui/aura/window_tree_host.h
@@ -83,9 +83,6 @@ 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() {
return const_cast<WindowEventDispatcher*>(
const_cast<const WindowTreeHost*>(this)->dispatcher());
@@ -136,7 +133,6 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
// root window's.
virtual void ConvertPixelsToDIP(gfx::Point* point) const;
- // Cursor.
// Sets the currently-displayed cursor. If the cursor was previously hidden
// via ShowCursor(false), it will remain hidden until ShowCursor(true) is
// called, at which point the cursor that was last set via SetCursor() will be
@@ -273,7 +269,8 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
void CreateCompositor(
const viz::FrameSinkId& frame_sink_id = viz::FrameSinkId(),
bool force_software_compositor = false,
- bool use_external_begin_frame_control = false);
+ bool use_external_begin_frame_control = false,
+ bool enable_compositing_based_throttling = false);
void InitCompositor();
void OnAcceleratedWidgetAvailable();
@@ -337,10 +334,11 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
void MoveCursorToInternal(const gfx::Point& root_location,
const gfx::Point& host_location);
- // Overrided from CompositorObserver:
- void OnCompositingEnded(ui::Compositor* compositor) override;
- void OnCompositingChildResizing(ui::Compositor* compositor) override;
- void OnCompositingShuttingDown(ui::Compositor* compositor) override;
+ // Overridden from CompositorObserver:
+ void OnCompositingEnded(ui::Compositor* compositor) final;
+ void OnCompositingChildResizing(ui::Compositor* compositor) final;
+ void OnFrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& ids) final;
// We don't use a std::unique_ptr for |window_| since we need this ptr to be
// valid during its deletion. (Window's dtor notifies observers that may
diff --git a/chromium/ui/aura/window_tree_host_observer.h b/chromium/ui/aura/window_tree_host_observer.h
index 5b8da3b28da..995ada6aa5d 100644
--- a/chromium/ui/aura/window_tree_host_observer.h
+++ b/chromium/ui/aura/window_tree_host_observer.h
@@ -5,6 +5,8 @@
#ifndef UI_AURA_WINDOW_TREE_HOST_OBSERVER_H_
#define UI_AURA_WINDOW_TREE_HOST_OBSERVER_H_
+#include "base/containers/flat_set.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
#include "ui/aura/aura_export.h"
#include "ui/aura/window.h"
@@ -43,6 +45,10 @@ class AURA_EXPORT WindowTreeHostObserver {
virtual void OnHostWillProcessBoundsChange(WindowTreeHost* host) {}
virtual void OnHostDidProcessBoundsChange(WindowTreeHost* host) {}
+ virtual void OnCompositingFrameSinksToThrottleUpdated(
+ const aura::WindowTreeHost* host,
+ const base::flat_set<viz::FrameSinkId>& ids) {}
+
protected:
virtual ~WindowTreeHostObserver() {}
};
diff --git a/chromium/ui/aura/window_tree_host_platform.cc b/chromium/ui/aura/window_tree_host_platform.cc
index 01843f47b17..7589542026f 100644
--- a/chromium/ui/aura/window_tree_host_platform.cc
+++ b/chromium/ui/aura/window_tree_host_platform.cc
@@ -34,7 +34,6 @@
#endif
#if defined(OS_WIN)
-#include "ui/base/cursor/cursor_loader_win.h"
#include "ui/platform_window/win/win_window.h"
#endif
@@ -57,7 +56,8 @@ WindowTreeHostPlatform::WindowTreeHostPlatform(
std::unique_ptr<Window> window)
: WindowTreeHost(std::move(window)) {
bounds_in_pixels_ = properties.bounds;
- CreateCompositor();
+ CreateCompositor(viz::FrameSinkId(), false, false,
+ properties.enable_compositing_based_throttling);
CreateAndSetPlatformWindow(std::move(properties));
}
@@ -68,6 +68,11 @@ WindowTreeHostPlatform::WindowTreeHostPlatform(std::unique_ptr<Window> window)
void WindowTreeHostPlatform::CreateAndSetPlatformWindow(
ui::PlatformWindowInitProperties properties) {
+ // Cache initial bounds used to create |platform_window_| so that it does not
+ // end up propagating unneeded bounds change event when it is first notified
+ // through OnBoundsChanged, which may lead to unneeded re-layouts, etc.
+ bounds_in_pixels_ = properties.bounds;
+
#if defined(USE_OZONE) || defined(USE_X11)
#if defined(USE_OZONE)
if (features::IsUsingOzonePlatform()) {
@@ -185,11 +190,6 @@ void WindowTreeHostPlatform::SetCursorNative(gfx::NativeCursor cursor) {
return;
current_cursor_ = cursor;
-#if defined(OS_WIN)
- ui::CursorLoaderWin cursor_loader;
- cursor_loader.SetPlatformCursor(&cursor);
-#endif
-
platform_window_->SetCursor(cursor.platform());
}
@@ -214,13 +214,21 @@ void WindowTreeHostPlatform::OnBoundsChanged(const gfx::Rect& new_bounds) {
float current_scale = compositor()->device_scale_factor();
float new_scale = ui::GetScaleFactorForNativeView(window());
gfx::Rect old_bounds = bounds_in_pixels_;
+ auto weak_ref = GetWeakPtr();
bounds_in_pixels_ = new_bounds;
- if (bounds_in_pixels_.origin() != old_bounds.origin())
+ if (bounds_in_pixels_.origin() != old_bounds.origin()) {
OnHostMovedInPixels(bounds_in_pixels_.origin());
+ // Changing the bounds may destroy this.
+ if (!weak_ref)
+ return;
+ }
if (bounds_in_pixels_.size() != old_bounds.size() ||
current_scale != new_scale) {
pending_size_ = gfx::Size();
OnHostResizedInPixels(bounds_in_pixels_.size());
+ // Changing the size may destroy this.
+ if (!weak_ref)
+ return;
}
DCHECK_GT(on_bounds_changed_recursion_depth_, 0);
if (--on_bounds_changed_recursion_depth_ == 0) {
diff --git a/chromium/ui/aura/window_tree_host_platform_unittest.cc b/chromium/ui/aura/window_tree_host_platform_unittest.cc
index eda14e2f0cd..4de039c88af 100644
--- a/chromium/ui/aura/window_tree_host_platform_unittest.cc
+++ b/chromium/ui/aura/window_tree_host_platform_unittest.cc
@@ -34,7 +34,7 @@ class TestWindowTreeHost : public WindowTreeHostPlatform {
// OnHostWill/DidProcessBoundsChange. Additionally, this triggers a bounds
// change from within OnHostResized(). Such a scenario happens in production
// code.
-class TestWindowTreeHostObserver : public aura::WindowTreeHostObserver {
+class TestWindowTreeHostObserver : public WindowTreeHostObserver {
public:
TestWindowTreeHostObserver(WindowTreeHostPlatform* host,
ui::PlatformWindow* platform_window)
@@ -51,7 +51,7 @@ class TestWindowTreeHostObserver : public aura::WindowTreeHostObserver {
return on_host_will_process_bounds_change_count_;
}
- // aura::WindowTreeHostObserver:
+ // WindowTreeHostObserver:
void OnHostResized(WindowTreeHost* host) override {
if (!should_change_bounds_in_on_resized_)
return;
@@ -92,5 +92,41 @@ TEST_F(WindowTreeHostPlatformTest, HostWillProcessBoundsChangeRecursion) {
EXPECT_EQ(1, observer.on_host_will_process_bounds_change_count());
}
+// Deletes WindowTreeHostPlatform from OnHostMovedInPixels().
+class DeleteHostWindowTreeHostObserver : public WindowTreeHostObserver {
+ public:
+ explicit DeleteHostWindowTreeHostObserver(
+ std::unique_ptr<TestWindowTreeHost> host)
+ : host_(std::move(host)) {
+ host_->AddObserver(this);
+ }
+ ~DeleteHostWindowTreeHostObserver() override = default;
+
+ TestWindowTreeHost* host() { return host_.get(); }
+
+ // WindowTreeHostObserver:
+ void OnHostMovedInPixels(WindowTreeHost* host,
+ const gfx::Point& new_origin_in_pixels) override {
+ host_->RemoveObserver(this);
+ host_.reset();
+ }
+
+ private:
+ std::unique_ptr<TestWindowTreeHost> host_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeleteHostWindowTreeHostObserver);
+};
+
+// Verifies WindowTreeHostPlatform can be safely deleted when calling
+// OnHostMovedInPixels().
+// Regression test for https://crbug.com/1185482
+TEST_F(WindowTreeHostPlatformTest, DeleteHostFromOnHostMovedInPixels) {
+ std::unique_ptr<TestWindowTreeHost> host =
+ std::make_unique<TestWindowTreeHost>();
+ DeleteHostWindowTreeHostObserver observer(std::move(host));
+ observer.host()->SetBoundsInPixels(gfx::Rect(1, 2, 3, 4));
+ EXPECT_EQ(nullptr, observer.host());
+}
+
} // namespace
} // namespace aura
diff --git a/chromium/ui/aura/window_tree_host_unittest.cc b/chromium/ui/aura/window_tree_host_unittest.cc
index 2bf6cb83460..fbbef1cf138 100644
--- a/chromium/ui/aura/window_tree_host_unittest.cc
+++ b/chromium/ui/aura/window_tree_host_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/test_screen.h"
#include "ui/aura/test/window_event_dispatcher_test_api.h"
@@ -91,7 +92,7 @@ TEST_F(WindowTreeHostTest,
EXPECT_EQ(gfx::Rect(300, 400), host()->window()->bounds());
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(WindowTreeHostTest, HoldPointerMovesOnChildResizing) {
aura::WindowEventDispatcher* dispatcher = host()->dispatcher();
@@ -115,7 +116,7 @@ TEST_F(WindowTreeHostTest, HoldPointerMovesOnChildResizing) {
}
#endif
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
// Tests if scale factor changes take effect. Previously a scale factor change
// wouldn't take effect without a bounds change. For context see
// https://crbug.com/1087626
diff --git a/chromium/ui/aura/window_unittest.cc b/chromium/ui/aura/window_unittest.cc
index 6bf4c71aff6..a30c5ee18b0 100644
--- a/chromium/ui/aura/window_unittest.cc
+++ b/chromium/ui/aura/window_unittest.cc
@@ -6,6 +6,7 @@
#include <limits.h>
+#include <memory>
#include <string>
#include <utility>
#include <vector>
@@ -24,6 +25,7 @@
#include "ui/aura/client/visibility_client.h"
#include "ui/aura/client/window_parenting_client.h"
#include "ui/aura/layout_manager.h"
+#include "ui/aura/scoped_window_capture_request.h"
#include "ui/aura/scoped_window_event_targeting_blocker.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/aura_test_utils.h"
@@ -368,6 +370,92 @@ TEST_F(WindowTest, ContainsPoint) {
EXPECT_FALSE(w->ContainsPoint(gfx::Point(10, 10)));
}
+TEST_F(WindowTest, MakeWindowCapturable) {
+ std::unique_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
+ // Initailly the window is not capturable.
+ EXPECT_FALSE(w1->subtree_capture_id().is_valid());
+
+ // Creating requests makes the window capturable as long as those requests
+ // remain alive.
+ ScopedWindowCaptureRequest request1 = w1->MakeWindowCapturable();
+ EXPECT_TRUE(w1->subtree_capture_id().is_valid());
+ EXPECT_EQ(request1.GetCaptureId(), w1->subtree_capture_id());
+ EXPECT_EQ(request1.GetCaptureId(), w1->layer()->GetSubtreeCaptureId());
+
+ // A new request does not affect the subtree capture ID.
+ const viz::SubtreeCaptureId current_id = w1->subtree_capture_id();
+ ScopedWindowCaptureRequest request2 = w1->MakeWindowCapturable();
+ EXPECT_EQ(current_id, w1->subtree_capture_id());
+ EXPECT_EQ(request1.GetCaptureId(), request2.GetCaptureId());
+
+ // Create a new request, then move an existing request into it. This should
+ // invalidate the moved-from request.
+ ScopedWindowCaptureRequest request3 = w1->MakeWindowCapturable();
+ EXPECT_EQ(current_id, request3.GetCaptureId());
+ request3 = std::move(request2);
+ EXPECT_FALSE(request2.window());
+ EXPECT_FALSE(request2.GetCaptureId().is_valid());
+ EXPECT_TRUE(w1->subtree_capture_id().is_valid());
+
+ // Destroying |request2| does nothing.
+ auto consume_request = [](ScopedWindowCaptureRequest request) {};
+ consume_request(std::move(request2));
+ EXPECT_TRUE(w1->subtree_capture_id().is_valid());
+ EXPECT_EQ(current_id, w1->subtree_capture_id());
+
+ // Destroying |request1| won't affect the window, it will remain capturable,
+ // since |request3| is still alive.
+ consume_request(std::move(request1));
+ EXPECT_FALSE(request1.window());
+ EXPECT_FALSE(request1.GetCaptureId().is_valid());
+ EXPECT_TRUE(w1->subtree_capture_id().is_valid());
+ EXPECT_EQ(current_id, w1->subtree_capture_id());
+
+ // Once all requests are destroyed, the window no longer has a valid capture
+ // ID.
+ consume_request(std::move(request3));
+ EXPECT_FALSE(w1->subtree_capture_id().is_valid());
+ EXPECT_FALSE(w1->layer()->GetSubtreeCaptureId().is_valid());
+}
+
+TEST_F(WindowTest, LayerReleasingAndSettingOfCapturableWindow) {
+ std::unique_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
+ EXPECT_FALSE(w1->subtree_capture_id().is_valid());
+ ScopedWindowCaptureRequest request = w1->MakeWindowCapturable();
+ EXPECT_TRUE(w1->layer()->GetSubtreeCaptureId().is_valid());
+
+ // Releasing the capturable window's layer (i.e. it's no longer associated
+ // with the window) will clear its capture ID. However, the window remains
+ // marked as capturable with a valid SubtreeCaptureId even though it has no
+ // layer.
+ std::unique_ptr<ui::Layer> taken_layer = w1->ReleaseLayer();
+ EXPECT_FALSE(w1->layer());
+ EXPECT_FALSE(taken_layer->GetSubtreeCaptureId().is_valid());
+ EXPECT_TRUE(w1->subtree_capture_id().is_valid());
+
+ // Setting a new layer on the window will set the layer's capture ID.
+ auto new_layer = std::make_unique<ui::Layer>();
+ taken_layer->parent()->Add(new_layer.get());
+ w1->Reset(std::move(new_layer));
+ EXPECT_TRUE(w1->layer()->GetSubtreeCaptureId().is_valid());
+ EXPECT_EQ(request.GetCaptureId(), w1->layer()->GetSubtreeCaptureId());
+}
+
+TEST_F(WindowTest, RecreateLayerOfCapturableWindow) {
+ std::unique_ptr<Window> w1(CreateTestWindowWithId(1, root_window()));
+ EXPECT_FALSE(w1->subtree_capture_id().is_valid());
+ ScopedWindowCaptureRequest request = w1->MakeWindowCapturable();
+ EXPECT_TRUE(w1->layer()->GetSubtreeCaptureId().is_valid());
+
+ // Recreating the layer of a capturable window will preserve the capture ID
+ // on the newly recreated window, and clears it from the old layer.
+ const viz::SubtreeCaptureId current_id = w1->subtree_capture_id();
+ std::unique_ptr<ui::Layer> old_layer = w1->RecreateLayer();
+ EXPECT_FALSE(old_layer->GetSubtreeCaptureId().is_valid());
+ EXPECT_EQ(current_id, w1->subtree_capture_id());
+ EXPECT_EQ(current_id, w1->layer()->GetSubtreeCaptureId());
+}
+
TEST_F(WindowTest, ConvertPointToWindow) {
// Window::ConvertPointToWindow is mostly identical to
// Layer::ConvertPointToLayer, except NULL values for |source| are permitted,
diff --git a/chromium/ui/aura_extra/BUILD.gn b/chromium/ui/aura_extra/BUILD.gn
index cc402e9282f..70fd26f5c31 100644
--- a/chromium/ui/aura_extra/BUILD.gn
+++ b/chromium/ui/aura_extra/BUILD.gn
@@ -42,6 +42,7 @@ source_set("vector_resource") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//cc/paint",
"//third_party/zlib/google:compression_utils",
"//ui/base",
diff --git a/chromium/ui/aura_extra/DIR_METADATA b/chromium/ui/aura_extra/DIR_METADATA
new file mode 100644
index 00000000000..b6a63317f30
--- /dev/null
+++ b/chromium/ui/aura_extra/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI>Aura"
+}
diff --git a/chromium/ui/aura_extra/OWNERS b/chromium/ui/aura_extra/OWNERS
deleted file mode 100644
index 23c884fa016..00000000000
--- a/chromium/ui/aura_extra/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# COMPONENT: UI>Aura
diff --git a/chromium/ui/aura_extra/skia_vector_resource.cc b/chromium/ui/aura_extra/skia_vector_resource.cc
index 940a8e07bc6..ffa95969e23 100644
--- a/chromium/ui/aura_extra/skia_vector_resource.cc
+++ b/chromium/ui/aura_extra/skia_vector_resource.cc
@@ -10,6 +10,7 @@
#include "base/no_destructor.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "cc/paint/skottie_wrapper.h"
#include "third_party/zlib/google/compression_utils.h"
#include "ui/base/resource/resource_bundle.h"
@@ -40,7 +41,7 @@ std::unique_ptr<gfx::SkiaVectorAnimation> GetVectorAnimationNamed(
return std::make_unique<gfx::SkiaVectorAnimation>(found->second);
auto& rb = ui::ResourceBundle::GetSharedInstance();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ui::ScaleFactor scale_factor_to_load = rb.GetMaxScaleFactor();
#elif defined(OS_WIN)
ui::ScaleFactor scale_factor_to_load = display::win::GetDPIScale() > 1.25
diff --git a/chromium/ui/base/BUILD.gn b/chromium/ui/base/BUILD.gn
index df0db2e2e26..b88df58d50b 100644
--- a/chromium/ui/base/BUILD.gn
+++ b/chromium/ui/base/BUILD.gn
@@ -3,15 +3,17 @@
# found in the LICENSE file.
import("//build/buildflag_header.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/compiler/compiler.gni")
import("//build/config/dcheck_always_on.gni")
import("//build/config/linux/gtk/gtk.gni")
import("//build/config/linux/pangocairo/pangocairo.gni")
+import("//build/config/locales.gni")
import("//build/config/ozone.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//build/config/ui.gni")
import("//build/util/branding.gni")
-import("//components/system_media_controls/linux/buildflags/buildflags.gni")
+import("//testing/libfuzzer/fuzzer_test.gni")
import("//testing/test.gni")
import("//tools/grit/grit_rule.gni")
import("//ui/base/ui_features.gni")
@@ -62,6 +64,7 @@ buildflag_header("buildflags") {
"USE_ATK=$use_atk",
"USE_XKBCOMMON=$use_xkbcommon",
"HAS_NATIVE_ACCESSIBILITY=$has_native_accessibility",
+ "HAS_PLATFORM_ACCESSIBILITY_SUPPORT=$has_platform_accessibility_support",
"USE_GTK=$use_gtk",
]
}
@@ -89,6 +92,7 @@ component("base") {
"default_style.h",
"device_form_factor.h",
"device_form_factor_desktop.cc",
+ "dragdrop/drag_drop_types.cc",
"dragdrop/drag_drop_types.h",
"dragdrop/drop_target_event.cc",
"dragdrop/drop_target_event.h",
@@ -168,6 +172,7 @@ component("base") {
"webui/i18n_source_stream.h",
"webui/jstemplate_builder.cc",
"webui/jstemplate_builder.h",
+ "webui/resource_path.h",
"webui/web_ui_util.cc",
"webui/web_ui_util.h",
"window_open_disposition.cc",
@@ -274,6 +279,8 @@ component("base") {
"cocoa/focus_window_set.mm",
"cocoa/menu_controller.h",
"cocoa/menu_controller.mm",
+ "cocoa/nsmenuitem_additions.h",
+ "cocoa/nsmenuitem_additions.mm",
"cocoa/permissions_utils.h",
"cocoa/permissions_utils.mm",
"cocoa/quartz_util.h",
@@ -332,8 +339,6 @@ component("base") {
"accelerators/media_keys_util.h",
"accelerators/menu_label_accelerator_util.cc",
"accelerators/menu_label_accelerator_util.h",
- "accelerators/system_media_controls_media_keys_listener.cc",
- "accelerators/system_media_controls_media_keys_listener.h",
"base_window.cc",
"base_window.h",
"emoji/emoji_panel_helper.h",
@@ -373,7 +378,7 @@ component("base") {
sources += [ "emoji/emoji_panel_helper_mac.mm" ]
} else if (is_win) {
sources += [ "emoji/emoji_panel_helper_win.cc" ]
- } else if (is_chromeos) {
+ } else if (is_chromeos_ash) {
sources += [ "emoji/emoji_panel_helper_chromeos.cc" ]
} else {
# Empty implementation for all other platforms.
@@ -388,8 +393,6 @@ component("base") {
"accelerators/global_media_keys_listener_win.h",
"accelerators/media_keys_listener_win.cc",
]
- } else if (use_mpris) {
- sources += [ "accelerators/media_keys_listener_linux.cc" ]
} else {
sources += [ "accelerators/media_keys_listener_stub.cc" ]
}
@@ -429,10 +432,12 @@ component("base") {
]
deps = [
+ ":locales_list",
"//base:base_static",
"//base:i18n",
"//base/third_party/dynamic_annotations",
"//base/util/type_safety:type_safety",
+ "//build:chromeos_buildflags",
"//net",
"//third_party/brotli:dec",
"//third_party/icu",
@@ -441,6 +446,7 @@ component("base") {
"//third_party/zlib/google:compression_utils",
"//ui/base:data_exchange",
"//ui/base/clipboard:clipboard_types",
+ "//ui/base/dragdrop/mojom",
"//ui/display",
"//ui/events",
"//ui/events/devices",
@@ -457,7 +463,7 @@ component("base") {
if (!is_ios) {
# iOS does not use Chromium-specific code for event handling.
public_deps += [
- "//ui/base/dragdrop/file_info",
+ "//ui/base/clipboard:file_info",
"//ui/events:events_base",
"//ui/events/platform",
]
@@ -485,13 +491,11 @@ component("base") {
# X11 drag and drop wants to use common drag and drop types.
allow_circular_includes_from = [ "//ui/base/x" ]
- if (!is_chromeos) {
+ if (!is_chromeos_ash) {
deps += [ "//ui/gfx/x" ]
}
}
- deps += [ "//components/system_media_controls" ]
-
if (use_x11 && use_aura) {
sources += [
"x/selection_requestor.cc",
@@ -502,7 +506,7 @@ component("base") {
"//ui/gfx/x",
]
- if (!is_chromeos) {
+ if (!is_chromeos_ash) {
# These Aura X11 files aren't used on ChromeOS.
sources += [
"dragdrop/os_exchange_data_provider_x11.cc",
@@ -528,7 +532,7 @@ component("base") {
]
}
- if (is_chromeos || (use_aura && is_linux)) {
+ if (is_chromeos_ash || (use_aura && (is_linux || is_chromeos_lacros))) {
sources += [
"dragdrop/os_exchange_data_provider_non_backed.cc",
"dragdrop/os_exchange_data_provider_non_backed.h",
@@ -562,6 +566,7 @@ component("base") {
if (!toolkit_views && !use_aura) {
sources -= [
+ "dragdrop/drag_drop_types.cc",
"dragdrop/drag_drop_types.h",
"dragdrop/drop_target_event.cc",
"dragdrop/drop_target_event.h",
@@ -607,7 +612,7 @@ component("data_exchange") {
deps = [
"//base",
"//ui/base/clipboard:clipboard_types",
- "//ui/base/dragdrop/file_info",
+ "//ui/base/clipboard:file_info",
"//ui/gfx",
"//ui/gfx/geometry",
"//url",
@@ -631,10 +636,13 @@ component("features") {
"//base",
"//build:chromeos_buildflags",
]
+ if (!is_ios) {
+ deps += [ "//media:media_buildflags" ]
+ }
}
# TODO(crbug.com/1091985): Support CrOS.
-if (is_win || is_mac || (is_linux && !is_chromeos)) {
+if (is_win || is_mac || (is_linux || is_chromeos_lacros)) {
static_library("pixel_diff_test_support") {
testonly = true
sources = [
@@ -646,6 +654,7 @@ if (is_win || is_mac || (is_linux && !is_chromeos)) {
deps = [
"//base",
"//base/test:test_config",
+ "//build:chromeos_buildflags",
"//testing/gtest",
"//ui/gfx",
"//ui/snapshot",
@@ -719,6 +728,7 @@ static_library("test_support") {
"accelerators/test_accelerator_target.h",
"test/mock_base_window.cc",
"test/mock_base_window.h",
+ "test/test_dialog_model_host.h",
"test/ui_controls.h",
"test/view_tree_validator.h",
]
@@ -743,6 +753,7 @@ static_library("test_support") {
"//base",
"//base/test:test_config",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//skia",
"//testing/gmock",
"//testing/gtest",
@@ -767,6 +778,8 @@ static_library("test_support") {
"ime/dummy_input_method.h",
"ime/dummy_text_input_client.cc",
"ime/dummy_text_input_client.h",
+ "ime/fake_text_input_client.cc",
+ "ime/fake_text_input_client.h",
]
deps += [
@@ -779,18 +792,22 @@ static_library("test_support") {
}
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [
- "ime/chromeos/input_method_allowlist.cc",
- "ime/chromeos/input_method_allowlist.h",
+ "ime/chromeos/mock_component_extension_ime_manager.cc",
+ "ime/chromeos/mock_component_extension_ime_manager.h",
+ "ime/chromeos/mock_component_extension_ime_manager_delegate.cc",
+ "ime/chromeos/mock_component_extension_ime_manager_delegate.h",
+ "ime/chromeos/mock_ime_candidate_window_handler.cc",
+ "ime/chromeos/mock_ime_candidate_window_handler.h",
+ "ime/chromeos/mock_ime_engine_handler.cc",
+ "ime/chromeos/mock_ime_engine_handler.h",
+ "ime/chromeos/mock_ime_input_context_handler.cc",
+ "ime/chromeos/mock_ime_input_context_handler.h",
"ime/chromeos/mock_input_method_manager.cc",
"ime/chromeos/mock_input_method_manager.h",
]
- deps += [
- # Generates a header used by input_method_allowlist.cc
- "//chromeos/ime:gencode",
- "//ui/base/ime/chromeos",
- ]
+ deps += [ "//ui/base/ime/chromeos" ]
}
}
@@ -857,6 +874,7 @@ test("ui_base_unittests") {
sources = [
"class_property_unittest.cc",
+ "clipboard/file_info_unittest.cc",
"ime/utf_offset_unittest.cc",
"l10n/l10n_util_unittest.cc",
"l10n/time_format_unittest.cc",
@@ -889,7 +907,10 @@ test("ui_base_unittests") {
"webui/i18n_source_stream_unittest.cc",
]
if (is_mac) {
- sources += [ "l10n/l10n_util_mac_unittest.mm" ]
+ sources += [
+ "cocoa/nsmenuitem_additions_unittest.mm",
+ "l10n/l10n_util_mac_unittest.mm",
+ ]
}
if (!is_ios) {
sources += [ "user_activity/user_activity_detector_unittest.cc" ]
@@ -903,12 +924,13 @@ test("ui_base_unittests") {
}
data = []
- data_deps = []
+ data_deps = [ "//testing/buildbot/filters:ui_base_unittests_filters" ]
deps = [
":ui_base_test_resources_grit",
":ui_base_unittests_bundle_data",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//mojo/core/embedder",
"//net",
"//net:test_support",
@@ -924,7 +946,9 @@ test("ui_base_unittests") {
"//ui/base:ui_data_pack",
"//ui/base/clipboard:clipboard_test",
"//ui/base/clipboard:clipboard_types",
+ "//ui/base/clipboard:file_info",
"//ui/base/cursor:unittests",
+ "//ui/base/data_transfer_policy:unittests",
"//ui/base/prediction:prediction",
"//ui/display",
"//ui/events:events_base",
@@ -955,14 +979,13 @@ test("ui_base_unittests") {
"accelerators/accelerator_manager_unittest.cc",
"accelerators/accelerator_unittest.cc",
"accelerators/menu_label_accelerator_util_unittest.cc",
- "accelerators/system_media_controls_media_keys_listener_unittest.cc",
+ "models/dialog_model_unittest.cc",
"models/list_model_unittest.cc",
"models/list_selection_model_unittest.cc",
"models/tree_node_model_unittest.cc",
"text/bytes_formatting_unittest.cc",
"webui/web_ui_util_unittest.cc",
]
- deps += [ "//components/system_media_controls:test_support" ]
if (is_linux || is_chromeos) {
sources +=
@@ -986,7 +1009,7 @@ test("ui_base_unittests") {
}
# TODO(crbug.com/1091985): Support CrOS.
- if (is_win || is_mac || (is_linux && !is_chromeos)) {
+ if (is_win || is_mac || (is_linux || is_chromeos_lacros)) {
sources += [
"test/skia_gold_matching_algorithm_unittest.cc",
"test/skia_gold_pixel_diff_unittest.cc",
@@ -1005,22 +1028,28 @@ test("ui_base_unittests") {
sources += [
"ime/win/imm32_manager_unittest.cc",
"ime/win/on_screen_keyboard_display_manager_unittest.cc",
- "ime/win/tsf_input_policy_unittest.cc",
"ime/win/tsf_input_scope_unittest.cc",
"ime/win/tsf_text_store_unittest.cc",
]
deps += [ "//ui/base/ime/win" ]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [
+ "dragdrop/os_exchange_data_provider_non_backed_unittest.cc",
"ime/chromeos/extension_ime_util_unittest.cc",
"ime/chromeos/ime_keyboard_unittest.cc",
"ime/chromeos/input_method_chromeos_unittest.cc",
+ "ime/chromeos/input_method_descriptor_unittest.cc",
"ime/chromeos/input_method_util_unittest.cc",
]
- deps += [ "//ui/base/ime/chromeos" ]
+ deps += [
+ "//build:branding_buildflags",
+ "//ui/base/ime/chromeos",
+ ]
}
- if (is_linux && use_aura && !is_chromeos) {
+ if ((is_linux || is_chromeos_lacros) && use_aura) {
+ sources += [ "dragdrop/os_exchange_data_provider_non_backed_unittest.cc" ]
+
if (use_x11 || use_ozone) {
sources += [ "ime/linux/input_method_auralinux_unittest.cc" ]
deps += [
@@ -1035,7 +1064,7 @@ test("ui_base_unittests") {
if (use_x11) {
sources += [ "ime/linux/composition_text_util_pango_unittest.cc" ]
}
- if (is_chromeos || use_ozone) {
+ if (is_chromeos_ash || use_ozone) {
sources += [ "ime/character_composer_unittest.cc" ]
}
}
@@ -1119,7 +1148,7 @@ test("ui_base_unittests") {
deps += [ "//ui/gfx/x:unit_test" ]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//ui/events:dom_keycode_converter" ]
}
@@ -1200,3 +1229,33 @@ source_set("base_interactive_ui_tests") {
]
}
}
+
+fuzzer_test("file_info_fuzzer") {
+ sources = [ "clipboard/file_info_fuzzer.cc" ]
+ deps = [
+ "//base",
+ "//ui/base/clipboard:file_info",
+ ]
+}
+
+# Same as locales, but includes "en" on Apple platforms.
+# Apple platforms use "en" instead of "en-US" (see the definition of
+# |locales_as_mac_outputs| in locales.gni). However, we still want to keep
+# "en-US" in the list as the |ResourceBundle::GetLocaleFilePath| implementations
+# in ui/base/resource/resource_bundle_{mac,ios}.mm return a valid path for
+# "en-US" (as they internally rewrite it as "en" instead).
+locales_for_platform_list = locales
+if (is_apple) {
+ locales_for_platform_list += [ "en" ]
+}
+
+action("locales_list_gen") {
+ script = "//tools/l10n/generate_locales_list.py"
+ outputs = [ "$root_gen_dir/ui/base/l10n/l10n_util_locales_list.inc" ]
+ args = rebase_path(outputs, root_build_dir) + locales_for_platform_list
+}
+
+source_set("locales_list") {
+ deps = [ ":locales_list_gen" ]
+ sources = [ "$root_gen_dir/ui/base/l10n/l10n_util_locales_list.inc" ]
+}
diff --git a/chromium/ui/base/DEPS b/chromium/ui/base/DEPS
index f333c5dc19c..42711119b4c 100644
--- a/chromium/ui/base/DEPS
+++ b/chromium/ui/base/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+components/system_media_controls",
+ "+media/media_buildflags.h",
"+net",
"+skia/ext",
"+third_party/brotli",
diff --git a/chromium/ui/base/OWNERS b/chromium/ui/base/OWNERS
index 964fafc2a6c..01f524d676f 100644
--- a/chromium/ui/base/OWNERS
+++ b/chromium/ui/base/OWNERS
@@ -2,6 +2,8 @@ per-file template_expressions*=dpapad@chromium.org
per-file template_expressions*=michaelpg@chromium.org
per-file template_expressions*=rbpotter@chromium.org
+per-file class_property*=kylixrd@chromium.org
+
per-file window_open_disposition*=pkasting@chromium.org
# If you're doing structural changes get a review from one of the ui/OWNERS.
diff --git a/chromium/ui/base/accelerators/accelerator.cc b/chromium/ui/base/accelerators/accelerator.cc
index 627e077480f..17e1739c12e 100644
--- a/chromium/ui/base/accelerators/accelerator.cc
+++ b/chromium/ui/base/accelerators/accelerator.cc
@@ -14,6 +14,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
@@ -27,7 +28,7 @@
#include "ui/events/keycodes/keyboard_code_conversion.h"
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/base/ui_base_features.h"
#endif
@@ -35,7 +36,7 @@ namespace ui {
namespace {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
template <DomKey::Base T>
using DomKeyConst = typename ui::DomKey::Constant<T>;
@@ -113,7 +114,7 @@ Accelerator::Accelerator(const KeyEvent& key_event)
time_stamp_(key_event.time_stamp()),
interrupted_by_mouse_event_(false),
source_device_id_(key_event.source_device_id()) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
if (features::IsNewShortcutMappingEnabled()) {
DomKey dom_key = key_event.GetDomKey();
if (!dom_key.IsCharacter())
@@ -416,7 +417,7 @@ base::string16 Accelerator::ApplyLongFormModifiers(
if (IsCmdDown()) {
#if defined(OS_APPLE)
shortcut = ApplyModifierToAcceleratorString(shortcut, IDS_APP_COMMAND_KEY);
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
shortcut = ApplyModifierToAcceleratorString(shortcut, IDS_APP_SEARCH_KEY);
#elif defined(OS_WIN)
shortcut = ApplyModifierToAcceleratorString(shortcut, IDS_APP_WINDOWS_KEY);
diff --git a/chromium/ui/base/accelerators/accelerator_history.cc b/chromium/ui/base/accelerators/accelerator_history.cc
index e4fbc8130f0..4438093c61b 100644
--- a/chromium/ui/base/accelerators/accelerator_history.cc
+++ b/chromium/ui/base/accelerators/accelerator_history.cc
@@ -4,11 +4,49 @@
#include "ui/base/accelerators/accelerator_history.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "ui/events/event.h"
+#include "ui/events/event_target.h"
+
namespace ui {
-AcceleratorHistory::AcceleratorHistory() {}
+namespace {
+
+bool ShouldFilter(ui::KeyEvent* event) {
+ const ui::EventType type = event->type();
+ if (!event->target() ||
+ (type != ui::ET_KEY_PRESSED && type != ui::ET_KEY_RELEASED) ||
+ event->is_char() || !event->target() ||
+ // Key events with key code of VKEY_PROCESSKEY, usually created by virtual
+ // keyboard (like handwriting input), have no effect on accelerator and
+ // they may disturb the accelerator history. So filter them out. (see
+ // https://crbug.com/918317)
+ event->key_code() == ui::VKEY_PROCESSKEY) {
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
-AcceleratorHistory::~AcceleratorHistory() {}
+AcceleratorHistory::AcceleratorHistory() = default;
+
+AcceleratorHistory::~AcceleratorHistory() = default;
+
+void AcceleratorHistory::OnKeyEvent(ui::KeyEvent* event) {
+ DCHECK(event->target());
+ if (!ShouldFilter(event))
+ StoreCurrentAccelerator(ui::Accelerator(*event));
+}
+
+void AcceleratorHistory::OnMouseEvent(ui::MouseEvent* event) {
+ if (event->type() == ui::ET_MOUSE_PRESSED ||
+ event->type() == ui::ET_MOUSE_RELEASED) {
+ InterruptCurrentAccelerator();
+ }
+}
void AcceleratorHistory::StoreCurrentAccelerator(
const Accelerator& accelerator) {
@@ -22,7 +60,19 @@ void AcceleratorHistory::StoreCurrentAccelerator(
if (!currently_pressed_keys_.emplace(accelerator.key_code()).second)
return;
} else {
- currently_pressed_keys_.erase(accelerator.key_code());
+ if (!currently_pressed_keys_.erase(accelerator.key_code())) {
+ // If the released accelerator doesn't have a corresponding press stored,
+ // likely the language was changed between press and release. Clear
+ // `currently_pressed_keys_` to prevent keys being left pressed.
+ std::string pressed_keys;
+ for (auto key_code : currently_pressed_keys_)
+ pressed_keys.append(base::NumberToString(key_code).append(" "));
+ LOG(WARNING) << "Key Release (" << accelerator.key_code()
+ << ") delivered with no corresponding Press. "
+ "Clearing all pressed keys: "
+ << pressed_keys;
+ currently_pressed_keys_.clear();
+ }
}
if (accelerator != current_accelerator_) {
diff --git a/chromium/ui/base/accelerators/accelerator_history.h b/chromium/ui/base/accelerators/accelerator_history.h
index 5d5ece78516..f2600cfb3c8 100644
--- a/chromium/ui/base/accelerators/accelerator_history.h
+++ b/chromium/ui/base/accelerators/accelerator_history.h
@@ -10,15 +10,16 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "ui/base/accelerators/accelerator.h"
+#include "ui/events/event_handler.h"
namespace ui {
// Keeps track of the system-wide current and the most recent previous
// key accelerators.
-class COMPONENT_EXPORT(UI_BASE) AcceleratorHistory {
+class COMPONENT_EXPORT(UI_BASE) AcceleratorHistory : public ui::EventHandler {
public:
AcceleratorHistory();
- ~AcceleratorHistory();
+ ~AcceleratorHistory() override;
// Returns the most recent recorded accelerator.
const Accelerator& current_accelerator() const {
@@ -35,6 +36,10 @@ class COMPONENT_EXPORT(UI_BASE) AcceleratorHistory {
return currently_pressed_keys_;
}
+ // ui::EventHandler:
+ void OnKeyEvent(ui::KeyEvent* event) override;
+ void OnMouseEvent(ui::MouseEvent* event) override;
+
// Stores the given |accelerator| only if it's different than the currently
// stored one.
void StoreCurrentAccelerator(const Accelerator& accelerator);
diff --git a/chromium/ui/base/accelerators/accelerator_history_unittest.cc b/chromium/ui/base/accelerators/accelerator_history_unittest.cc
index 4fcf29a4f66..b633fe34d56 100644
--- a/chromium/ui/base/accelerators/accelerator_history_unittest.cc
+++ b/chromium/ui/base/accelerators/accelerator_history_unittest.cc
@@ -4,6 +4,7 @@
#include "ui/base/accelerators/accelerator_history.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/accelerators/accelerator.h"
namespace ui {
@@ -52,4 +53,23 @@ TEST(AcceleratorHistoryTest, SimulatePressAndHold) {
EXPECT_EQ(alt_release_search_down, history.previous_accelerator());
}
+// Tests that the record of pressed keys is cleared when language changes
+// between key press and release. Detected via a release event that arrives with
+// no corresponding press. See https://crbug.com/1184474.
+TEST(AcceleratorHistoryTest, ReleaseWithNoMatchingPressClearsPressedKeys) {
+ // Press "]" aka ui::VKEY_OEM_6 in the US keyboard.
+ AcceleratorHistory history;
+ ui::Accelerator right_bracket_press(ui::VKEY_OEM_6, ui::EF_NONE,
+ ui::Accelerator::KeyState::PRESSED);
+ history.StoreCurrentAccelerator(right_bracket_press);
+
+ // Simulate that a keyboard language change turns the release of "]" to
+ // VKEY_OEM_PLUS in a DE keyboard. So there should be a release event with no
+ // matching press. Test that the set of pressed keys is empty.
+ ui::Accelerator right_bracket_release(ui::VKEY_OEM_PLUS, ui::EF_NONE,
+ ui::Accelerator::KeyState::RELEASED);
+ history.StoreCurrentAccelerator(right_bracket_release);
+ EXPECT_TRUE(history.currently_pressed_keys().empty());
+}
+
} // namespace ui
diff --git a/chromium/ui/base/accelerators/accelerator_manager.cc b/chromium/ui/base/accelerators/accelerator_manager.cc
index c3db7cc5f2c..aed89311295 100644
--- a/chromium/ui/base/accelerators/accelerator_manager.cc
+++ b/chromium/ui/base/accelerators/accelerator_manager.cc
@@ -7,8 +7,8 @@
#include <algorithm>
#include "base/check.h"
+#include "base/containers/contains.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
namespace ui {
@@ -110,8 +110,9 @@ bool AcceleratorManager::HasPriorityHandler(
return map_iter->second.second.front()->CanHandleAccelerators();
}
-void AcceleratorManager::UnregisterImpl(AcceleratorMap::iterator map_iter,
- AcceleratorTarget* target) {
+void AcceleratorManager::UnregisterImpl(
+ AcceleratorTargetsMap::iterator map_iter,
+ AcceleratorTarget* target) {
AcceleratorTargetList* targets = &map_iter->second.second;
auto target_iter = std::find(targets->begin(), targets->end(), target);
if (target_iter == targets->end()) {
diff --git a/chromium/ui/base/accelerators/accelerator_manager.h b/chromium/ui/base/accelerators/accelerator_manager.h
index 6d7c88604a0..3a0fb79f1db 100644
--- a/chromium/ui/base/accelerators/accelerator_manager.h
+++ b/chromium/ui/base/accelerators/accelerator_manager.h
@@ -84,14 +84,14 @@ class COMPONENT_EXPORT(UI_BASE) AcceleratorManager {
// This construct pairs together a |bool| (denoting whether the list contains
// a priority_handler at the front) with the list of AcceleratorTargets.
using AcceleratorTargets = std::pair<bool, AcceleratorTargetList>;
- using AcceleratorMap = std::map<Accelerator, AcceleratorTargets>;
+ using AcceleratorTargetsMap = std::map<Accelerator, AcceleratorTargets>;
// Implementation of Unregister(). |map_iter| points to the accelerator to
// remove, and |target| the AcceleratorTarget to remove.
- void UnregisterImpl(AcceleratorMap::iterator map_iter,
+ void UnregisterImpl(AcceleratorTargetsMap::iterator map_iter,
AcceleratorTarget* target);
- AcceleratorMap accelerators_;
+ AcceleratorTargetsMap accelerators_;
DISALLOW_COPY_AND_ASSIGN(AcceleratorManager);
};
diff --git a/chromium/ui/base/accelerators/accelerator_manager_unittest.cc b/chromium/ui/base/accelerators/accelerator_manager_unittest.cc
index eae146afc8d..502d45aa40d 100644
--- a/chromium/ui/base/accelerators/accelerator_manager_unittest.cc
+++ b/chromium/ui/base/accelerators/accelerator_manager_unittest.cc
@@ -6,6 +6,7 @@
#include "base/stl_util.h"
#include "base/test/scoped_feature_list.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/accelerators/test_accelerator_target.h"
#include "ui/base/ui_base_features.h"
@@ -166,7 +167,7 @@ TEST_F(AcceleratorManagerTest, Process) {
}
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(AcceleratorManagerTest, NewMapping) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kNewShortcutMapping);
diff --git a/chromium/ui/base/accelerators/global_media_keys_listener_win.h b/chromium/ui/base/accelerators/global_media_keys_listener_win.h
index 2f20ba52397..adf4b9c9b2b 100644
--- a/chromium/ui/base/accelerators/global_media_keys_listener_win.h
+++ b/chromium/ui/base/accelerators/global_media_keys_listener_win.h
@@ -33,7 +33,6 @@ class COMPONENT_EXPORT(UI_BASE) GlobalMediaKeysListenerWin
// MediaKeysListener implementation.
bool StartWatchingMediaKey(KeyboardCode key_code) override;
void StopWatchingMediaKey(KeyboardCode key_code) override;
- void SetIsMediaPlaying(bool is_playing) override {}
private:
// Called by SingletonHwndObserver.
diff --git a/chromium/ui/base/accelerators/media_keys_listener.h b/chromium/ui/base/accelerators/media_keys_listener.h
index 6787fa39da1..c2b03328c0e 100644
--- a/chromium/ui/base/accelerators/media_keys_listener.h
+++ b/chromium/ui/base/accelerators/media_keys_listener.h
@@ -49,13 +49,6 @@ class COMPONENT_EXPORT(UI_BASE) MediaKeysListener {
virtual bool StartWatchingMediaKey(KeyboardCode key_code) = 0;
// Stop listening for a given media key.
virtual void StopWatchingMediaKey(KeyboardCode key_code) = 0;
-
- // Informs the listener whether or not media is currently playing. In some
- // implementations this will prevent us from calling PlayPause unnecessarily.
- // TODO(https://crbug.com/974035): Once the MediaKeysListenerManager has been
- // refactored to work with system media controls this should no longer be
- // needed and should be deleted.
- virtual void SetIsMediaPlaying(bool is_playing) = 0;
};
} // namespace ui
diff --git a/chromium/ui/base/accelerators/media_keys_listener_linux.cc b/chromium/ui/base/accelerators/media_keys_listener_linux.cc
deleted file mode 100644
index c74807dfae7..00000000000
--- a/chromium/ui/base/accelerators/media_keys_listener_linux.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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/accelerators/media_keys_listener.h"
-
-#include "ui/base/accelerators/system_media_controls_media_keys_listener.h"
-
-namespace ui {
-
-std::unique_ptr<MediaKeysListener> MediaKeysListener::Create(
- MediaKeysListener::Delegate* delegate,
- MediaKeysListener::Scope scope) {
- DCHECK(delegate);
-
- if (scope == Scope::kGlobal) {
- if (!SystemMediaControlsMediaKeysListener::has_instance()) {
- auto listener =
- std::make_unique<SystemMediaControlsMediaKeysListener>(delegate);
- bool success = listener->Initialize();
-
- // The Linux implementation should always initialize successfully.
- DCHECK(success);
-
- return std::move(listener);
- }
- // We shouldn't try to create more than one global MediaKeysListener
- // instance.
- NOTREACHED();
- }
- return nullptr;
-}
-
-} // 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 6052fd13ff3..60f7ad6ffb2 100644
--- a/chromium/ui/base/accelerators/media_keys_listener_mac.mm
+++ b/chromium/ui/base/accelerators/media_keys_listener_mac.mm
@@ -13,7 +13,6 @@
#include "base/containers/flat_set.h"
#include "base/logging.h"
#include "ui/base/accelerators/accelerator.h"
-#include "ui/base/accelerators/system_media_controls_media_keys_listener.h"
namespace ui {
@@ -46,7 +45,6 @@ class MediaKeysListenerImpl : public MediaKeysListener {
// MediaKeysListener:
bool StartWatchingMediaKey(KeyboardCode key_code) override;
void StopWatchingMediaKey(KeyboardCode key_code) override;
- void SetIsMediaPlaying(bool is_playing) override {}
private:
// Callback on media key event.
@@ -221,16 +219,6 @@ CGEventRef MediaKeysListenerImpl::EventTapCallback(CGEventTapProxy proxy,
std::unique_ptr<MediaKeysListener> MediaKeysListener::Create(
MediaKeysListener::Delegate* delegate,
MediaKeysListener::Scope scope) {
- // For Mac OS 10.12.2 or later, we want to use MPRemoteCommandCenter for
- // getting media keys globally if there is a RemoteCommandCenterDelegate
- // available.
- if (scope == Scope::kGlobal) {
- auto listener =
- std::make_unique<SystemMediaControlsMediaKeysListener>(delegate);
- if (listener->Initialize())
- return listener;
- }
-
return std::make_unique<MediaKeysListenerImpl>(delegate, scope);
}
diff --git a/chromium/ui/base/accelerators/media_keys_listener_win.cc b/chromium/ui/base/accelerators/media_keys_listener_win.cc
index c50ea0ca2b8..6c63a88cbb1 100644
--- a/chromium/ui/base/accelerators/media_keys_listener_win.cc
+++ b/chromium/ui/base/accelerators/media_keys_listener_win.cc
@@ -5,7 +5,6 @@
#include "ui/base/accelerators/media_keys_listener.h"
#include "ui/base/accelerators/global_media_keys_listener_win.h"
-#include "ui/base/accelerators/system_media_controls_media_keys_listener.h"
namespace ui {
@@ -16,20 +15,12 @@ std::unique_ptr<MediaKeysListener> MediaKeysListener::Create(
if (scope == Scope::kGlobal) {
// We should never have more than one global media keys listener.
- if (!SystemMediaControlsMediaKeysListener::has_instance() &&
- !GlobalMediaKeysListenerWin::has_instance()) {
- auto listener =
- std::make_unique<SystemMediaControlsMediaKeysListener>(delegate);
- if (listener->Initialize())
- return listener;
-
- // If |Initialize()| fails, then we fall back to the
- // GlobalMediaKeysListenerWin.
+ if (!GlobalMediaKeysListenerWin::has_instance())
return std::make_unique<GlobalMediaKeysListenerWin>(delegate);
- }
+
NOTREACHED();
}
return nullptr;
}
-} // namespace ui \ No newline at end of file
+} // namespace ui
diff --git a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.cc b/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.cc
deleted file mode 100644
index 9d6084ceacc..00000000000
--- a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-// 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/accelerators/system_media_controls_media_keys_listener.h"
-
-#include "components/system_media_controls/system_media_controls.h"
-#include "ui/base/accelerators/accelerator.h"
-
-namespace ui {
-
-// static
-bool SystemMediaControlsMediaKeysListener::has_instance_ = false;
-
-SystemMediaControlsMediaKeysListener::SystemMediaControlsMediaKeysListener(
- MediaKeysListener::Delegate* delegate)
- : delegate_(delegate) {
- DCHECK(delegate_);
- DCHECK(!has_instance_);
- has_instance_ = true;
-}
-
-SystemMediaControlsMediaKeysListener::~SystemMediaControlsMediaKeysListener() {
- DCHECK(has_instance_);
- has_instance_ = false;
-}
-
-bool SystemMediaControlsMediaKeysListener::Initialize() {
- // |service_| can be set for tests.
- if (!service_)
- service_ = system_media_controls::SystemMediaControls::GetInstance();
-
- // If we still don't have a service, then either System Media Controls isn't
- // supported on this platform or it failed to initialize. If that's the case,
- // return false.
- if (!service_)
- return false;
-
- service_->AddObserver(this);
- return true;
-}
-
-bool SystemMediaControlsMediaKeysListener::StartWatchingMediaKey(
- KeyboardCode key_code) {
- DCHECK(IsMediaKeycode(key_code));
-
- // If we're already listening for this key, do nothing.
- if (key_codes_.contains(key_code))
- return true;
-
- key_codes_.insert(key_code);
-
- DCHECK(service_);
-
- switch (key_code) {
- case VKEY_MEDIA_PLAY_PAUSE:
- service_->SetIsPlayPauseEnabled(true);
- break;
- case VKEY_MEDIA_NEXT_TRACK:
- service_->SetIsNextEnabled(true);
- break;
- case VKEY_MEDIA_PREV_TRACK:
- service_->SetIsPreviousEnabled(true);
- break;
- case VKEY_MEDIA_STOP:
- service_->SetIsStopEnabled(true);
- break;
- default:
- NOTREACHED();
- }
-
- return true;
-}
-
-void SystemMediaControlsMediaKeysListener::StopWatchingMediaKey(
- KeyboardCode key_code) {
- DCHECK(IsMediaKeycode(key_code));
-
- // If we're not currently listening for this key, do nothing.
- if (!key_codes_.contains(key_code))
- return;
-
- key_codes_.erase(key_code);
-
- DCHECK(service_);
-
- switch (key_code) {
- case VKEY_MEDIA_PLAY_PAUSE:
- service_->SetIsPlayPauseEnabled(false);
- break;
- case VKEY_MEDIA_NEXT_TRACK:
- service_->SetIsNextEnabled(false);
- break;
- case VKEY_MEDIA_PREV_TRACK:
- service_->SetIsPreviousEnabled(false);
- break;
- case VKEY_MEDIA_STOP:
- service_->SetIsStopEnabled(false);
- break;
- default:
- NOTREACHED();
- }
-}
-
-void SystemMediaControlsMediaKeysListener::SetIsMediaPlaying(bool is_playing) {
- is_media_playing_ = is_playing;
-}
-
-void SystemMediaControlsMediaKeysListener::OnNext() {
- MaybeSendKeyCode(VKEY_MEDIA_NEXT_TRACK);
-}
-
-void SystemMediaControlsMediaKeysListener::OnPrevious() {
- MaybeSendKeyCode(VKEY_MEDIA_PREV_TRACK);
-}
-
-void SystemMediaControlsMediaKeysListener::OnPlay() {
- if (!is_media_playing_)
- MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
-}
-
-void SystemMediaControlsMediaKeysListener::OnPause() {
- if (is_media_playing_)
- MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
-}
-
-void SystemMediaControlsMediaKeysListener::OnPlayPause() {
- MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
-}
-
-void SystemMediaControlsMediaKeysListener::OnStop() {
- MaybeSendKeyCode(VKEY_MEDIA_STOP);
-}
-
-void SystemMediaControlsMediaKeysListener::MaybeSendKeyCode(
- KeyboardCode key_code) {
- if (!key_codes_.contains(key_code))
- return;
-
- Accelerator accelerator(key_code, /*modifiers=*/0);
- delegate_->OnMediaKeysAccelerator(accelerator);
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.h b/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.h
deleted file mode 100644
index 847669a515e..00000000000
--- a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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_ACCELERATORS_SYSTEM_MEDIA_CONTROLS_MEDIA_KEYS_LISTENER_H_
-#define UI_BASE_ACCELERATORS_SYSTEM_MEDIA_CONTROLS_MEDIA_KEYS_LISTENER_H_
-
-#include "base/component_export.h"
-#include "base/containers/flat_set.h"
-#include "components/system_media_controls/system_media_controls_observer.h"
-#include "ui/base/accelerators/media_keys_listener.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-
-namespace system_media_controls {
-class SystemMediaControls;
-} // namespace system_media_controls
-
-namespace ui {
-
-// Implementation of MediaKeysListener that uses the SystemMediaControls API to
-// listen for media key presses. It only allows for a single instance to be
-// created in order to prevent conflicts from multiple listeners.
-class COMPONENT_EXPORT(UI_BASE) SystemMediaControlsMediaKeysListener
- : public MediaKeysListener,
- public system_media_controls::SystemMediaControlsObserver {
- public:
- explicit SystemMediaControlsMediaKeysListener(
- MediaKeysListener::Delegate* delegate);
- ~SystemMediaControlsMediaKeysListener() override;
-
- static bool has_instance() { return has_instance_; }
-
- bool Initialize();
-
- // MediaKeysListener implementation.
- bool StartWatchingMediaKey(KeyboardCode key_code) override;
- void StopWatchingMediaKey(KeyboardCode key_code) override;
- void SetIsMediaPlaying(bool is_playing) override;
-
- // system_media_controls::SystemMediaControlsObserver implementation.
- void OnServiceReady() override {}
- void OnNext() override;
- void OnPrevious() override;
- void OnPlay() override;
- void OnPause() override;
- void OnPlayPause() override;
- void OnStop() override;
-
- void SetSystemMediaControlsForTesting(
- system_media_controls::SystemMediaControls* service) {
- service_ = service;
- }
-
- private:
- static bool has_instance_;
-
- // Sends the key code to the delegate if the delegate has asked for it.
- void MaybeSendKeyCode(KeyboardCode key_code);
-
- MediaKeysListener::Delegate* delegate_;
-
- // Set of keys codes that we're currently listening for.
- base::flat_set<KeyboardCode> key_codes_;
-
- system_media_controls::SystemMediaControls* service_ = nullptr;
-
- bool is_media_playing_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsMediaKeysListener);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_ACCELERATORS_SYSTEM_MEDIA_CONTROLS_MEDIA_KEYS_LISTENER_H_
diff --git a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc b/chromium/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc
deleted file mode 100644
index 905f3f54ea8..00000000000
--- a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-// 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/accelerators/system_media_controls_media_keys_listener.h"
-
-#include <memory>
-
-#include "components/system_media_controls/mock_system_media_controls.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/accelerators/accelerator.h"
-
-using testing::_;
-using testing::Expectation;
-using testing::WithArg;
-
-namespace ui {
-
-namespace {
-
-class MockMediaKeysListenerDelegate : public MediaKeysListener::Delegate {
- public:
- MockMediaKeysListenerDelegate() = default;
- ~MockMediaKeysListenerDelegate() override = default;
-
- // MediaKeysListener::Delegate implementation.
- MOCK_METHOD1(OnMediaKeysAccelerator, void(const Accelerator& accelerator));
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockMediaKeysListenerDelegate);
-};
-
-} // anonymous namespace
-
-class SystemMediaControlsMediaKeysListenerTest : public testing::Test {
- public:
- SystemMediaControlsMediaKeysListenerTest() {
- listener_ =
- std::make_unique<SystemMediaControlsMediaKeysListener>(&delegate_);
- listener_->SetSystemMediaControlsForTesting(
- &mock_system_media_controls_service_);
- }
-
- ~SystemMediaControlsMediaKeysListenerTest() override = default;
-
- protected:
- system_media_controls::testing::MockSystemMediaControls&
- mock_system_media_controls_service() {
- return mock_system_media_controls_service_;
- }
- MockMediaKeysListenerDelegate& delegate() { return delegate_; }
- SystemMediaControlsMediaKeysListener* listener() { return listener_.get(); }
-
- private:
- system_media_controls::testing::MockSystemMediaControls
- mock_system_media_controls_service_;
- MockMediaKeysListenerDelegate delegate_;
- std::unique_ptr<SystemMediaControlsMediaKeysListener> listener_;
-
- DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsMediaKeysListenerTest);
-};
-
-TEST_F(SystemMediaControlsMediaKeysListenerTest, ListensToSystemMediaControls) {
- EXPECT_CALL(mock_system_media_controls_service(), AddObserver(listener()));
- listener()->Initialize();
-}
-
-TEST_F(SystemMediaControlsMediaKeysListenerTest, SimplePlayPauseTest) {
- // Should be set to true when we start listening for the key.
- EXPECT_CALL(mock_system_media_controls_service(),
- SetIsPlayPauseEnabled(true));
-
- EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_))
- .WillOnce(WithArg<0>([](const Accelerator& accelerator) {
- EXPECT_EQ(ui::VKEY_MEDIA_PLAY_PAUSE, accelerator.key_code());
- }));
-
- ASSERT_TRUE(listener()->Initialize());
- listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
-
- // Simulate media key press.
- listener()->OnPlay();
-}
-
-TEST_F(SystemMediaControlsMediaKeysListenerTest, KeyCanBeReRegistered) {
- Expectation enable_next =
- EXPECT_CALL(mock_system_media_controls_service(), SetIsNextEnabled(true));
- Expectation disable_next =
- EXPECT_CALL(mock_system_media_controls_service(), SetIsNextEnabled(false))
- .After(enable_next);
- Expectation reenable_next =
- EXPECT_CALL(mock_system_media_controls_service(), SetIsNextEnabled(true))
- .After(disable_next);
- EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_))
- .After(reenable_next)
- .WillOnce(WithArg<0>([](const Accelerator& accelerator) {
- EXPECT_EQ(ui::VKEY_MEDIA_NEXT_TRACK, accelerator.key_code());
- }));
-
- ASSERT_TRUE(listener()->Initialize());
-
- // 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);
-
- // Simulate media key press.
- listener()->OnNext();
-}
-
-TEST_F(SystemMediaControlsMediaKeysListenerTest, ListenForMultipleKeys) {
- // Should be set to true when we start listening for the key.
- EXPECT_CALL(mock_system_media_controls_service(),
- SetIsPlayPauseEnabled(true));
- EXPECT_CALL(mock_system_media_controls_service(), SetIsPreviousEnabled(true));
-
- // Should receive the key presses.
- EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(2);
-
- ASSERT_TRUE(listener()->Initialize());
- listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
- listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PREV_TRACK);
-
- // Simulate media key press.
- listener()->OnPlay();
- listener()->OnPrevious();
-}
-
-TEST_F(SystemMediaControlsMediaKeysListenerTest,
- DoesNotFirePlayPauseOnPauseEventWhenPaused) {
- // Should be set to true when we start listening for the key.
- EXPECT_CALL(mock_system_media_controls_service(),
- SetIsPlayPauseEnabled(true));
-
- EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0);
-
- ASSERT_TRUE(listener()->Initialize());
- listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
- listener()->SetIsMediaPlaying(false);
-
- // Simulate media key press.
- listener()->OnPause();
-}
-
-TEST_F(SystemMediaControlsMediaKeysListenerTest,
- DoesNotFirePlayPauseOnPlayEventWhenPlaying) {
- // Should be set to true when we start listening for the key.
- EXPECT_CALL(mock_system_media_controls_service(),
- SetIsPlayPauseEnabled(true));
-
- EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0);
-
- ASSERT_TRUE(listener()->Initialize());
- listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
- listener()->SetIsMediaPlaying(true);
-
- // Simulate media key press.
- listener()->OnPlay();
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/clipboard/BUILD.gn b/chromium/ui/base/clipboard/BUILD.gn
index a24dfe52e7c..6e806368add 100644
--- a/chromium/ui/base/clipboard/BUILD.gn
+++ b/chromium/ui/base/clipboard/BUILD.gn
@@ -4,6 +4,7 @@
import("///build/config/ozone.gni")
import("//build/config/chromeos/ui_mode.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
component("clipboard_types") {
@@ -35,7 +36,7 @@ component("clipboard_types") {
}
if (use_aura) {
- if ((use_x11 && is_linux) || !is_win) {
+ if ((use_x11 && (is_linux || is_chromeos_lacros)) || !is_win) {
sources += [ "clipboard_format_type_aura.cc" ]
}
}
@@ -53,6 +54,19 @@ component("clipboard_types") {
}
}
+component("file_info") {
+ output_name = "ui_base_file_info"
+
+ sources = [
+ "file_info.cc",
+ "file_info.h",
+ ]
+
+ defines = [ "IS_UI_BASE_FILE_INFO_IMPL" ]
+
+ deps = [ "//base" ]
+}
+
component("clipboard") {
output_name = "ui_base_clipboard"
@@ -100,6 +114,7 @@ component("clipboard") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//mojo/public/cpp/base",
"//net",
"//skia",
@@ -110,12 +125,13 @@ component("clipboard") {
public_deps = [
":clipboard_types",
+ ":file_info",
"//ui/base/data_transfer_policy",
]
if (use_aura) {
# Linux clipboard implementations.
- if (is_linux && !is_chromecast) {
+ if ((is_linux || is_chromeos_lacros) && !is_chromecast) {
sources += [ "clipboard_linux.cc" ]
if (use_ozone) {
sources += [
@@ -138,7 +154,7 @@ component("clipboard") {
"//ui/gfx/x",
]
}
- } else if (is_chromeos && ozone_platform_x11) {
+ } else if (is_chromeos_ash && ozone_platform_x11) {
# linux-chromeos uses non-backed clipboard by default, but supports ozone
# x11 with flag --use-system-clipbboard.
sources += [
@@ -227,8 +243,7 @@ source_set("clipboard_test") {
]
}
- if (use_aura && !chromeos_is_browser_only && !use_x11 && !is_win &&
- !use_ozone) {
+ if (use_aura && !is_chromeos_lacros && !use_x11 && !is_win) {
sources += [
"clipboard_data_unittest.cc",
"clipboard_non_backed_unittest.cc",
@@ -240,6 +255,7 @@ source_set("clipboard_test") {
"//base/test:test_support",
"//testing/gmock",
"//testing/gtest",
+ "//ui/base:features",
"//ui/events/platform",
"//ui/gfx:test_support",
"//url:url",
diff --git a/chromium/ui/base/clipboard/OWNERS b/chromium/ui/base/clipboard/OWNERS
index 9317fe4e188..e48dbe775ee 100644
--- a/chromium/ui/base/clipboard/OWNERS
+++ b/chromium/ui/base/clipboard/OWNERS
@@ -1,2 +1,6 @@
dcheng@chromium.org
huangdarwin@chromium.org
+
+per-file clipboard_ozone*=msisov@igalia.com
+per-file clipboard_ozone*=adunaev@igalia.com
+
diff --git a/chromium/ui/base/clipboard/README.md b/chromium/ui/base/clipboard/README.md
new file mode 100644
index 00000000000..51d1a61b624
--- /dev/null
+++ b/chromium/ui/base/clipboard/README.md
@@ -0,0 +1,18 @@
+Platform-neutral clipboard abstractions, to access platform-specific clipboards
+(copy/paste) without platform-specific code.
+
+Interfaces include:
+* `Clipboard`: reading/pasting from the clipboard.
+* `ScopedClipboardWriter`: writing/copying to the clipboard.
+* `ClipboardObserver`: notifications of clipboard events.
+* `ClipboardFormatType`: specifying clipboard formats.
+
+While most platform-specific behavior should be abstracted away, some may
+still be exposed. For some notable platform-specific behavior exposed by these
+interfaces:
+* `ClipboardAndroid` has a more limited set of supported formats.
+* `ClipboardObserver` is only supported on some platforms, as other platforms
+ may require (inefficient) polling to implement.
+* `ClipboardX11` supports both the usual clipboard buffer, as well as the
+ selection (middle-click) paste buffer.
+* `DataTransferPolicyController` is only currently exercised in ChromeOS.
diff --git a/chromium/ui/base/clipboard/clipboard.cc b/chromium/ui/base/clipboard/clipboard.cc
index 76f95800d1c..3735eff0e7a 100644
--- a/chromium/ui/base/clipboard/clipboard.cc
+++ b/chromium/ui/base/clipboard/clipboard.cc
@@ -9,9 +9,10 @@
#include <memory>
#include "base/check.h"
+#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/size.h"
@@ -27,14 +28,14 @@ bool Clipboard::IsSupportedClipboardBuffer(ClipboardBuffer buffer) {
case ClipboardBuffer::kCopyPaste:
return true;
case ClipboardBuffer::kSelection:
-#if defined(USE_OZONE) && !defined(OS_CHROMEOS)
+#if defined(USE_OZONE) && !BUILDFLAG(IS_CHROMEOS_ASH)
if (features::IsUsingOzonePlatform()) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
CHECK(clipboard);
return clipboard->IsSelectionBufferAvailable();
}
#endif
-#if !defined(OS_WIN) && !defined(OS_APPLE) && !defined(OS_CHROMEOS)
+#if !defined(OS_WIN) && !defined(OS_APPLE) && !BUILDFLAG(IS_CHROMEOS_ASH)
return true;
#else
return false;
@@ -182,6 +183,12 @@ void Clipboard::DispatchPortableRepresentation(PortableFormat format,
break;
}
+ case PortableFormat::kFilenames: {
+ std::string uri_list(&(params[0].front()), params[0].size());
+ WriteFilenames(ui::URIListToFileInfos(uri_list));
+ break;
+ }
+
case PortableFormat::kData:
WriteData(ClipboardFormatType::Deserialize(
std::string(&(params[0].front()), params[0].size())),
diff --git a/chromium/ui/base/clipboard/clipboard.h b/chromium/ui/base/clipboard/clipboard.h
index 410e2936cfb..bcd96bf03f3 100644
--- a/chromium/ui/base/clipboard/clipboard.h
+++ b/chromium/ui/base/clipboard/clipboard.h
@@ -28,6 +28,7 @@
#include "mojo/public/cpp/base/big_buffer.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
class SkBitmap;
@@ -89,6 +90,10 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) Clipboard
virtual void OnPreShutdown() = 0;
+ // Gets the source of the current clipboard buffer contents.
+ virtual const DataTransferEndpoint* GetSource(
+ ClipboardBuffer buffer) const = 0;
+
// Returns a sequence number which uniquely identifies clipboard state.
// This can be used to version the data on the clipboard and determine
// whether it has changed.
@@ -171,6 +176,11 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) Clipboard
const DataTransferEndpoint* data_dst,
base::string16* result) const = 0;
+ // Reads filenames from the clipboard, if available.
+ virtual void ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const = 0;
+
// Reads a bookmark from the clipboard, if available.
// |title| or |url| may be null.
virtual void ReadBookmark(const DataTransferEndpoint* data_dst,
@@ -213,6 +223,7 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) Clipboard
kWebkit,
kData, // Arbitrary block of bytes.
kSvg,
+ kFilenames,
};
// TODO (https://crbug.com/994928): Rename ObjectMap-related types.
@@ -223,18 +234,19 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) Clipboard
//
// Key Arguments Type
// -------------------------------------
- // kBitmap bitmap A pointer to a SkBitmap. The caller must ensure
- // the SkBitmap remains live for the duration of
- // the WritePortableRepresentations call.
- // kHtml html char array
- // url* char array
- // kRtf data byte array
- // kBookmark html char array
- // url char array
- // kText text char array
- // kWebkit none empty vector
- // kData format char array
- // data byte array
+ // kBitmap bitmap A pointer to a SkBitmap. The caller must ensure
+ // the SkBitmap remains live for the duration of
+ // the WritePortableRepresentations call.
+ // kHtml html char array
+ // url* char array
+ // kRtf data byte array
+ // kFilenames text/uri-list char array
+ // kBookmark html char array
+ // url char array
+ // kText text char array
+ // kWebkit none empty vector
+ // kData format char array
+ // data byte array
using ObjectMapParam = std::vector<char>;
using ObjectMapParams = std::vector<ObjectMapParam>;
using ObjectMap = base::flat_map<PortableFormat, ObjectMapParams>;
@@ -293,6 +305,8 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) Clipboard
virtual void WriteRTF(const char* rtf_data, size_t data_len) = 0;
+ virtual void WriteFilenames(std::vector<ui::FileInfo> filenames) = 0;
+
virtual void WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
diff --git a/chromium/ui/base/clipboard/clipboard_android.cc b/chromium/ui/base/clipboard/clipboard_android.cc
index d1f728c1992..7ad02c4c37f 100644
--- a/chromium/ui/base/clipboard/clipboard_android.cc
+++ b/chromium/ui/base/clipboard/clipboard_android.cc
@@ -15,9 +15,9 @@
#include "base/android/scoped_java_ref.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/containers/contains.h"
#include "base/lazy_instance.h"
#include "base/no_destructor.h"
-#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "base/task/post_task.h"
@@ -364,6 +364,14 @@ ClipboardAndroid::~ClipboardAndroid() {
void ClipboardAndroid::OnPreShutdown() {}
+// DataTransferEndpoint is not used on this platform.
+DataTransferEndpoint* ClipboardAndroid::GetSource(
+ ClipboardBuffer buffer) const {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
+ return nullptr;
+}
+
uint64_t ClipboardAndroid::GetSequenceNumber(
ClipboardBuffer /* buffer */) const {
DCHECK(CalledOnValidThread());
@@ -525,6 +533,15 @@ void ClipboardAndroid::ReadCustomData(ClipboardBuffer buffer,
// |data_dst| is not used. It's only passed to be consistent with other
// platforms.
+void ClipboardAndroid::ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const {
+ DCHECK(CalledOnValidThread());
+ NOTIMPLEMENTED();
+}
+
+// |data_dst| is not used. It's only passed to be consistent with other
+// platforms.
void ClipboardAndroid::ReadBookmark(const DataTransferEndpoint* data_dst,
base::string16* title,
std::string* url) const {
@@ -606,6 +623,10 @@ void ClipboardAndroid::WriteRTF(const char* rtf_data, size_t data_len) {
NOTIMPLEMENTED();
}
+void ClipboardAndroid::WriteFilenames(std::vector<ui::FileInfo> filenames) {
+ NOTIMPLEMENTED();
+}
+
// According to other platforms implementations, this really writes the
// URL spec.
void ClipboardAndroid::WriteBookmark(const char* title_data,
diff --git a/chromium/ui/base/clipboard/clipboard_android.h b/chromium/ui/base/clipboard/clipboard_android.h
index 5a262fa3595..6ad7e758d22 100644
--- a/chromium/ui/base/clipboard/clipboard_android.h
+++ b/chromium/ui/base/clipboard/clipboard_android.h
@@ -58,6 +58,7 @@ class ClipboardAndroid : public Clipboard {
// Clipboard overrides:
void OnPreShutdown() override;
+ DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardBuffer buffer,
@@ -94,6 +95,9 @@ class ClipboardAndroid : public Clipboard {
const base::string16& type,
const DataTransferEndpoint* data_dst,
base::string16* result) const override;
+ void ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const override;
void ReadBookmark(const DataTransferEndpoint* data_dst,
base::string16* title,
@@ -118,6 +122,7 @@ class ClipboardAndroid : public Clipboard {
size_t url_len) override;
void WriteSvg(const char* markup_data, size_t markup_len) override;
void WriteRTF(const char* rtf_data, size_t data_len) override;
+ void WriteFilenames(std::vector<ui::FileInfo> filenames) override;
void WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
diff --git a/chromium/ui/base/clipboard/clipboard_constants.cc b/chromium/ui/base/clipboard/clipboard_constants.cc
index a64162fdd86..df542333f6b 100644
--- a/chromium/ui/base/clipboard/clipboard_constants.cc
+++ b/chromium/ui/base/clipboard/clipboard_constants.cc
@@ -8,7 +8,9 @@ namespace ui {
const char kMimeTypeText[] = "text/plain";
const char kMimeTypeTextUtf8[] = "text/plain;charset=utf-8";
+// Used for file:// URLs.
const char kMimeTypeURIList[] = "text/uri-list";
+// Used for site URL bookmarks.
const char kMimeTypeMozillaURL[] = "text/x-moz-url";
const char kMimeTypeDownloadURL[] = "downloadurl";
const char kMimeTypeHTML[] = "text/html";
diff --git a/chromium/ui/base/clipboard/clipboard_data.cc b/chromium/ui/base/clipboard/clipboard_data.cc
index 956afe8c2fe..0f93ad7484c 100644
--- a/chromium/ui/base/clipboard/clipboard_data.cc
+++ b/chromium/ui/base/clipboard/clipboard_data.cc
@@ -29,6 +29,7 @@ ClipboardData::ClipboardData(const ClipboardData& other) {
custom_data_data_ = other.custom_data_data_;
web_smart_paste_ = other.web_smart_paste_;
svg_data_ = other.svg_data_;
+ filenames_ = other.filenames_;
src_ = other.src_ ? std::make_unique<DataTransferEndpoint>(*other.src_.get())
: nullptr;
}
@@ -46,7 +47,7 @@ bool ClipboardData::operator==(const ClipboardData& that) const {
custom_data_format_ == that.custom_data_format() &&
custom_data_data_ == that.custom_data_data() &&
web_smart_paste_ == that.web_smart_paste() &&
- svg_data_ == that.svg_data() &&
+ svg_data_ == that.svg_data() && filenames_ == that.filenames() &&
gfx::BitmapsAreEqual(bitmap_, that.bitmap()) &&
(src_.get() ? (that.source() && *src_.get() == *that.source())
: !that.source());
diff --git a/chromium/ui/base/clipboard/clipboard_data.h b/chromium/ui/base/clipboard/clipboard_data.h
index ac89e4f65f4..3c60c1f797b 100644
--- a/chromium/ui/base/clipboard/clipboard_data.h
+++ b/chromium/ui/base/clipboard/clipboard_data.h
@@ -10,6 +10,7 @@
#include "base/component_export.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
class SkBitmap;
@@ -26,6 +27,7 @@ enum class ClipboardInternalFormat {
kBitmap = 1 << 5,
kCustom = 1 << 6,
kWeb = 1 << 7,
+ kFilenames = 1 << 8,
};
// ClipboardData contains data copied to the Clipboard for a variety of formats.
@@ -100,6 +102,13 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardData {
format_ |= static_cast<int>(ClipboardInternalFormat::kWeb);
}
+ const std::vector<ui::FileInfo>& filenames() const { return filenames_; }
+ void set_filenames(std::vector<ui::FileInfo> filenames) {
+ filenames_ = std::move(filenames);
+ if (!filenames_.empty())
+ format_ |= static_cast<int>(ClipboardInternalFormat::kFilenames);
+ }
+
DataTransferEndpoint* source() const { return src_.get(); }
void set_source(std::unique_ptr<DataTransferEndpoint> src) {
@@ -134,6 +143,9 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardData {
// Svg data.
std::string svg_data_;
+ // text/uri-list filenames data.
+ std::vector<ui::FileInfo> filenames_;
+
int format_;
// The source of the data.
diff --git a/chromium/ui/base/clipboard/clipboard_format_type.h b/chromium/ui/base/clipboard/clipboard_format_type.h
index b5944b0ef7e..982209eddf7 100644
--- a/chromium/ui/base/clipboard/clipboard_format_type.h
+++ b/chromium/ui/base/clipboard/clipboard_format_type.h
@@ -54,6 +54,7 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD_TYPES) ClipboardFormatType {
static ClipboardFormatType GetType(const std::string& format_string);
// Get format identifiers for various types.
+ static const ClipboardFormatType& GetFilenamesType();
static const ClipboardFormatType& GetUrlType();
static const ClipboardFormatType& GetPlainTextType();
static const ClipboardFormatType& GetWebKitSmartPasteType();
diff --git a/chromium/ui/base/clipboard/clipboard_format_type_android.cc b/chromium/ui/base/clipboard/clipboard_format_type_android.cc
index e773978a379..2e1b66e0fbb 100644
--- a/chromium/ui/base/clipboard/clipboard_format_type_android.cc
+++ b/chromium/ui/base/clipboard/clipboard_format_type_android.cc
@@ -47,12 +47,18 @@ ClipboardFormatType ClipboardFormatType::GetType(
}
// static
-const ClipboardFormatType& ClipboardFormatType::GetUrlType() {
+const ClipboardFormatType& ClipboardFormatType::GetFilenamesType() {
static base::NoDestructor<ClipboardFormatType> type(kMimeTypeURIList);
return *type;
}
// static
+const ClipboardFormatType& ClipboardFormatType::GetUrlType() {
+ static base::NoDestructor<ClipboardFormatType> type(kMimeTypeMozillaURL);
+ return *type;
+}
+
+// static
const ClipboardFormatType& ClipboardFormatType::GetPlainTextType() {
static base::NoDestructor<ClipboardFormatType> type(kMimeTypeText);
return *type;
diff --git a/chromium/ui/base/clipboard/clipboard_format_type_aura.cc b/chromium/ui/base/clipboard/clipboard_format_type_aura.cc
index 06e2293c01a..0e182341f49 100644
--- a/chromium/ui/base/clipboard/clipboard_format_type_aura.cc
+++ b/chromium/ui/base/clipboard/clipboard_format_type_aura.cc
@@ -50,12 +50,18 @@ ClipboardFormatType ClipboardFormatType::GetType(
}
// static
-const ClipboardFormatType& ClipboardFormatType::GetUrlType() {
+const ClipboardFormatType& ClipboardFormatType::GetFilenamesType() {
static base::NoDestructor<ClipboardFormatType> type(kMimeTypeURIList);
return *type;
}
// static
+const ClipboardFormatType& ClipboardFormatType::GetUrlType() {
+ static base::NoDestructor<ClipboardFormatType> type(kMimeTypeMozillaURL);
+ return *type;
+}
+
+// static
const ClipboardFormatType& ClipboardFormatType::GetPlainTextType() {
static base::NoDestructor<ClipboardFormatType> type(kMimeTypeText);
return *type;
diff --git a/chromium/ui/base/clipboard/clipboard_format_type_mac.mm b/chromium/ui/base/clipboard/clipboard_format_type_mac.mm
index 3ee36e5bd9c..c87c9bc4cb6 100644
--- a/chromium/ui/base/clipboard/clipboard_format_type_mac.mm
+++ b/chromium/ui/base/clipboard/clipboard_format_type_mac.mm
@@ -64,6 +64,12 @@ ClipboardFormatType ClipboardFormatType::GetType(
}
// static
+const ClipboardFormatType& ClipboardFormatType::GetFilenamesType() {
+ static base::NoDestructor<ClipboardFormatType> type(NSFilenamesPboardType);
+ return *type;
+}
+
+// static
const ClipboardFormatType& ClipboardFormatType::GetUrlType() {
static base::NoDestructor<ClipboardFormatType> type(NSURLPboardType);
return *type;
diff --git a/chromium/ui/base/clipboard/clipboard_format_type_win.cc b/chromium/ui/base/clipboard/clipboard_format_type_win.cc
index 7e7516fa801..74b273b4de1 100644
--- a/chromium/ui/base/clipboard/clipboard_format_type_win.cc
+++ b/chromium/ui/base/clipboard/clipboard_format_type_win.cc
@@ -169,6 +169,11 @@ ClipboardFormatType ClipboardFormatType::GetType(
// ClipboardFormatTypes thread-safe on all platforms.
// static
+const ClipboardFormatType& ClipboardFormatType::GetFilenamesType() {
+ return GetFilenameType();
+}
+
+// static
const ClipboardFormatType& ClipboardFormatType::GetUrlType() {
static base::NoDestructor<ClipboardFormatType> format(
::RegisterClipboardFormat(CFSTR_INETURLW));
diff --git a/chromium/ui/base/clipboard/clipboard_mac.h b/chromium/ui/base/clipboard/clipboard_mac.h
index b556901af5d..fbf4e3a6583 100644
--- a/chromium/ui/base/clipboard/clipboard_mac.h
+++ b/chromium/ui/base/clipboard/clipboard_mac.h
@@ -30,6 +30,7 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardMac : public Clipboard {
// Clipboard overrides:
void OnPreShutdown() override;
+ DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardBuffer buffer,
@@ -68,6 +69,9 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardMac : public Clipboard {
const base::string16& type,
const DataTransferEndpoint* data_dst,
base::string16* result) const override;
+ void ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const override;
void ReadBookmark(const DataTransferEndpoint* data_dst,
base::string16* title,
std::string* url) const override;
@@ -89,6 +93,7 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardMac : public Clipboard {
size_t url_len) override;
void WriteSvg(const char* markup_data, size_t markup_len) override;
void WriteRTF(const char* rtf_data, size_t data_len) override;
+ void WriteFilenames(std::vector<ui::FileInfo> filenames) override;
void WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
diff --git a/chromium/ui/base/clipboard/clipboard_mac.mm b/chromium/ui/base/clipboard/clipboard_mac.mm
index 67cb135e387..d5379d8fddb 100644
--- a/chromium/ui/base/clipboard/clipboard_mac.mm
+++ b/chromium/ui/base/clipboard/clipboard_mac.mm
@@ -9,6 +9,7 @@
#include <limits>
+#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/mac/foundation_util.h"
@@ -17,8 +18,11 @@
#include "base/mac/scoped_nsobject.h"
#include "base/no_destructor.h"
#include "base/stl_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "net/base/filename_util.h"
#include "skia/ext/skia_utils_base.h"
#include "skia/ext/skia_utils_mac.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
@@ -28,9 +32,11 @@
#include "ui/base/clipboard/clipboard_util_mac.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/ui_base_features.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
+#include "url/gurl.h"
namespace ui {
@@ -62,6 +68,13 @@ ClipboardMac::~ClipboardMac() {
void ClipboardMac::OnPreShutdown() {}
+// DataTransferEndpoint is not used on this platform.
+DataTransferEndpoint* ClipboardMac::GetSource(ClipboardBuffer buffer) const {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
+ return nullptr;
+}
+
uint64_t ClipboardMac::GetSequenceNumber(ClipboardBuffer buffer) const {
DCHECK(CalledOnValidThread());
DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
@@ -79,6 +92,12 @@ bool ClipboardMac::IsFormatAvailable(
DCHECK(CalledOnValidThread());
DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
+ // Only support filenames if chrome://flags#clipboard-filenames is enabled.
+ if (format == ClipboardFormatType::GetFilenamesType() &&
+ !base::FeatureList::IsEnabled(features::kClipboardFilenames)) {
+ return false;
+ }
+
NSPasteboard* pb = GetPasteboard();
NSArray* types = [pb types];
@@ -139,6 +158,9 @@ void ClipboardMac::ReadAvailableTypes(
types->push_back(base::UTF8ToUTF16(kMimeTypeSvg));
if (IsFormatAvailable(ClipboardFormatType::GetRtfType(), buffer, data_dst))
types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
+ if (IsFormatAvailable(ClipboardFormatType::GetFilenamesType(), buffer,
+ data_dst))
+ types->push_back(base::UTF8ToUTF16(kMimeTypeURIList));
NSPasteboard* pb = GetPasteboard();
if (pb && [NSImage canInitWithPasteboard:pb])
@@ -289,6 +311,22 @@ void ClipboardMac::ReadCustomData(ClipboardBuffer buffer,
// |data_dst| is not used. It's only passed to be consistent with other
// platforms.
+void ClipboardMac::ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
+ RecordRead(ClipboardFormatMetric::kFilenames);
+
+ NSArray* paths = [GetPasteboard() propertyListForType:NSFilenamesPboardType];
+ for (NSString* path in paths) {
+ result->push_back(
+ ui::FileInfo(base::mac::NSStringToFilePath(path), base::FilePath()));
+ }
+}
+
+// |data_dst| is not used. It's only passed to be consistent with other
+// platforms.
void ClipboardMac::ReadBookmark(const DataTransferEndpoint* data_dst,
base::string16* title,
std::string* url) const {
@@ -389,6 +427,15 @@ void ClipboardMac::WriteRTF(const char* rtf_data, size_t data_len) {
WriteData(ClipboardFormatType::GetRtfType(), rtf_data, data_len);
}
+void ClipboardMac::WriteFilenames(std::vector<ui::FileInfo> filenames) {
+ NSMutableArray* paths = [NSMutableArray arrayWithCapacity:filenames.size()];
+ for (const ui::FileInfo& file : filenames) {
+ NSString* path = base::mac::FilePathToNSString(file.path);
+ [paths addObject:path];
+ }
+ [GetPasteboard() setPropertyList:paths forType:NSFilenamesPboardType];
+}
+
void ClipboardMac::WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
diff --git a/chromium/ui/base/clipboard/clipboard_metrics.h b/chromium/ui/base/clipboard/clipboard_metrics.h
index e7194491b4d..3683dd3e27d 100644
--- a/chromium/ui/base/clipboard/clipboard_metrics.h
+++ b/chromium/ui/base/clipboard/clipboard_metrics.h
@@ -20,7 +20,8 @@ enum class ClipboardFormatMetric {
kCustomData = 6,
kWebSmartPaste = 7, // Only used on write.
kSvg = 8,
- kMaxValue = kSvg,
+ kFilenames = 9,
+ kMaxValue = kFilenames,
};
void RecordRead(ClipboardFormatMetric metric);
diff --git a/chromium/ui/base/clipboard/clipboard_monitor.cc b/chromium/ui/base/clipboard/clipboard_monitor.cc
index 1d5cd5518d9..9defbce91fb 100644
--- a/chromium/ui/base/clipboard/clipboard_monitor.cc
+++ b/chromium/ui/base/clipboard/clipboard_monitor.cc
@@ -4,6 +4,7 @@
#include "ui/base/clipboard/clipboard_monitor.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_observer.h"
@@ -27,7 +28,7 @@ void ClipboardMonitor::NotifyClipboardDataChanged() {
observer.OnClipboardDataChanged();
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void ClipboardMonitor::NotifyClipboardDataRead() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
for (ClipboardObserver& observer : observers_)
diff --git a/chromium/ui/base/clipboard/clipboard_monitor.h b/chromium/ui/base/clipboard/clipboard_monitor.h
index d09aafaaec7..5ba97a41eaf 100644
--- a/chromium/ui/base/clipboard/clipboard_monitor.h
+++ b/chromium/ui/base/clipboard/clipboard_monitor.h
@@ -11,6 +11,7 @@
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
namespace ui {
@@ -31,7 +32,7 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardMonitor {
// Notifies all observers for clipboard data change.
virtual void NotifyClipboardDataChanged();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Notifies all observers for clipboard data read.
virtual void NotifyClipboardDataRead();
#endif
diff --git a/chromium/ui/base/clipboard/clipboard_non_backed.cc b/chromium/ui/base/clipboard/clipboard_non_backed.cc
index 05513ec8398..e9941077122 100644
--- a/chromium/ui/base/clipboard/clipboard_non_backed.cc
+++ b/chromium/ui/base/clipboard/clipboard_non_backed.cc
@@ -13,6 +13,7 @@
#include <utility>
#include "base/check_op.h"
+#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -20,6 +21,7 @@
#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
+#include "build/chromeos_buildflags.h"
#include "skia/ext/skia_utils_base.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard_constants.h"
@@ -30,6 +32,7 @@
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
+#include "ui/base/ui_base_features.h"
#include "ui/gfx/geometry/size.h"
#include "ui/ozone/buildflags.h"
@@ -37,12 +40,13 @@ namespace ui {
namespace {
+using InstanceRegistry = std::set<const ClipboardNonBacked*, std::less<>>;
// Returns the registry which tracks all instances of ClipboardNonBacked in
// existence. This allows us to determine if any arbitrary Clipboard pointer in
// fact points to a ClipboardNonBacked instance. Only if a pointer exists in
// this registry is it safe to cast to ClipboardNonBacked*.
-std::set<const ClipboardNonBacked*>* GetInstanceRegistry() {
- static base::NoDestructor<std::set<const ClipboardNonBacked*>> registry;
+InstanceRegistry* GetInstanceRegistry() {
+ static base::NoDestructor<InstanceRegistry> registry;
return registry.get();
}
@@ -204,6 +208,11 @@ class ClipboardInternal {
data->custom_data_data().size(), type, result);
}
+ // Reads filenames from the ClipboardData.
+ const std::vector<ui::FileInfo>& ReadFilenames() const {
+ return GetData()->filenames();
+ }
+
// Reads bookmark from the ClipboardData.
void ReadBookmark(base::string16* title, std::string* url) const {
if (title)
@@ -246,7 +255,7 @@ class ClipboardInternal {
auto* data = GetData();
if (!policy_controller || !data)
return true;
- return policy_controller->IsDataReadAllowed(data->source(), data_dst);
+ return policy_controller->IsClipboardReadAllowed(data->source(), data_dst);
}
private:
@@ -302,6 +311,11 @@ class ClipboardDataBuilder {
data->SetRTFData(std::string(rtf_data, rtf_len));
}
+ static void WriteFilenames(std::vector<ui::FileInfo> filenames) {
+ ClipboardData* data = GetCurrentData();
+ data->set_filenames(std::move(filenames));
+ }
+
static void WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
@@ -349,7 +363,7 @@ ClipboardData* ClipboardDataBuilder::current_data_ = nullptr;
// linux-chromeos uses non-backed clipboard by default, but supports ozone x11
// with flag --use-system-clipbboard.
-#if !defined(OS_CHROMEOS) || !BUILDFLAG(OZONE_PLATFORM_X11)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) || !BUILDFLAG(OZONE_PLATFORM_X11)
// Clipboard factory method.
Clipboard* Clipboard::Create() {
return new ClipboardNonBacked;
@@ -359,7 +373,11 @@ Clipboard* Clipboard::Create() {
// static
ClipboardNonBacked* ClipboardNonBacked::GetForCurrentThread() {
auto* clipboard = Clipboard::GetForCurrentThread();
- CHECK(IsRegisteredInstance(clipboard)); // Ensure type safety.
+
+ // Ensure type safety. In tests the instance may not be registered.
+ if (!IsRegisteredInstance(clipboard))
+ return nullptr;
+
return static_cast<ClipboardNonBacked*>(clipboard);
}
@@ -393,6 +411,12 @@ std::unique_ptr<ClipboardData> ClipboardNonBacked::WriteClipboardData(
void ClipboardNonBacked::OnPreShutdown() {}
+DataTransferEndpoint* ClipboardNonBacked::GetSource(
+ ClipboardBuffer buffer) const {
+ const ClipboardData* data = clipboard_internal_->GetData();
+ return data ? data->source() : nullptr;
+}
+
uint64_t ClipboardNonBacked::GetSequenceNumber(ClipboardBuffer buffer) const {
DCHECK(CalledOnValidThread());
return clipboard_internal_->sequence_number();
@@ -427,6 +451,11 @@ bool ClipboardNonBacked::IsFormatAvailable(
if (format == ClipboardFormatType::GetWebKitSmartPasteType())
return clipboard_internal_->IsFormatAvailable(
ClipboardInternalFormat::kWeb);
+ // Only support filenames if chrome://flags#clipboard-filenames is enabled.
+ if (format == ClipboardFormatType::GetFilenamesType() &&
+ base::FeatureList::IsEnabled(features::kClipboardFilenames))
+ return clipboard_internal_->IsFormatAvailable(
+ ClipboardInternalFormat::kFilenames);
const ClipboardData* data = clipboard_internal_->GetData();
return data && data->custom_data_format() == format.GetName();
}
@@ -460,6 +489,9 @@ void ClipboardNonBacked::ReadAvailableTypes(
base::UTF8ToUTF16(ClipboardFormatType::GetRtfType().GetName()));
if (IsFormatAvailable(ClipboardFormatType::GetBitmapType(), buffer, data_dst))
types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
+ if (IsFormatAvailable(ClipboardFormatType::GetFilenamesType(), buffer,
+ data_dst))
+ types->push_back(base::UTF8ToUTF16(kMimeTypeURIList));
if (clipboard_internal_->IsFormatAvailable(
ClipboardInternalFormat::kCustom) &&
@@ -514,7 +546,7 @@ void ClipboardNonBacked::ReadText(ClipboardBuffer buffer,
RecordRead(ClipboardFormatMetric::kText);
clipboard_internal_->ReadText(result);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ClipboardMonitor::GetInstance()->NotifyClipboardDataRead();
#endif
}
@@ -530,7 +562,7 @@ void ClipboardNonBacked::ReadAsciiText(ClipboardBuffer buffer,
RecordRead(ClipboardFormatMetric::kText);
clipboard_internal_->ReadAsciiText(result);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ClipboardMonitor::GetInstance()->NotifyClipboardDataRead();
#endif
}
@@ -549,7 +581,7 @@ void ClipboardNonBacked::ReadHTML(ClipboardBuffer buffer,
RecordRead(ClipboardFormatMetric::kHtml);
clipboard_internal_->ReadHTML(markup, src_url, fragment_start, fragment_end);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ClipboardMonitor::GetInstance()->NotifyClipboardDataRead();
#endif
}
@@ -577,7 +609,7 @@ void ClipboardNonBacked::ReadRTF(ClipboardBuffer buffer,
RecordRead(ClipboardFormatMetric::kRtf);
clipboard_internal_->ReadRTF(result);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ClipboardMonitor::GetInstance()->NotifyClipboardDataRead();
#endif
}
@@ -595,7 +627,7 @@ void ClipboardNonBacked::ReadImage(ClipboardBuffer buffer,
RecordRead(ClipboardFormatMetric::kImage);
std::move(callback).Run(clipboard_internal_->ReadImage());
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ClipboardMonitor::GetInstance()->NotifyClipboardDataRead();
#endif
}
@@ -612,7 +644,24 @@ void ClipboardNonBacked::ReadCustomData(ClipboardBuffer buffer,
RecordRead(ClipboardFormatMetric::kCustomData);
clipboard_internal_->ReadCustomData(type, result);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ ClipboardMonitor::GetInstance()->NotifyClipboardDataRead();
+#endif
+}
+
+void ClipboardNonBacked::ReadFilenames(
+ ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const {
+ DCHECK(CalledOnValidThread());
+
+ if (!clipboard_internal_->IsReadAllowed(data_dst))
+ return;
+
+ RecordRead(ClipboardFormatMetric::kFilenames);
+ *result = clipboard_internal_->ReadFilenames();
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ClipboardMonitor::GetInstance()->NotifyClipboardDataRead();
#endif
}
@@ -628,7 +677,7 @@ void ClipboardNonBacked::ReadBookmark(const DataTransferEndpoint* data_dst,
RecordRead(ClipboardFormatMetric::kBookmark);
clipboard_internal_->ReadBookmark(title, url);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ClipboardMonitor::GetInstance()->NotifyClipboardDataRead();
#endif
}
@@ -644,13 +693,13 @@ void ClipboardNonBacked::ReadData(const ClipboardFormatType& format,
RecordRead(ClipboardFormatMetric::kData);
clipboard_internal_->ReadData(format.GetName(), result);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ClipboardMonitor::GetInstance()->NotifyClipboardDataRead();
#endif
}
bool ClipboardNonBacked::IsSelectionBufferAvailable() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return false;
#else
return true;
@@ -701,6 +750,10 @@ void ClipboardNonBacked::WriteRTF(const char* rtf_data, size_t data_len) {
ClipboardDataBuilder::WriteRTF(rtf_data, data_len);
}
+void ClipboardNonBacked::WriteFilenames(std::vector<ui::FileInfo> filenames) {
+ ClipboardDataBuilder::WriteFilenames(std::move(filenames));
+}
+
void ClipboardNonBacked::WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
diff --git a/chromium/ui/base/clipboard/clipboard_non_backed.h b/chromium/ui/base/clipboard/clipboard_non_backed.h
index a9fa8b39c44..d14ff0ff67e 100644
--- a/chromium/ui/base/clipboard/clipboard_non_backed.h
+++ b/chromium/ui/base/clipboard/clipboard_non_backed.h
@@ -9,6 +9,7 @@
#include <stdint.h>
#include "base/component_export.h"
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "ui/base/clipboard/clipboard.h"
@@ -40,11 +41,13 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardNonBacked
std::unique_ptr<ClipboardData> data);
// Clipboard overrides:
+ DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
private:
friend class Clipboard;
friend class ClipboardNonBackedTest;
+ FRIEND_TEST_ALL_PREFIXES(ClipboardNonBackedTest, TextURIList);
ClipboardNonBacked();
~ClipboardNonBacked() override;
@@ -85,6 +88,9 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardNonBacked
const base::string16& type,
const DataTransferEndpoint* data_dst,
base::string16* result) const override;
+ void ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const override;
void ReadBookmark(const DataTransferEndpoint* data_dst,
base::string16* title,
std::string* url) const override;
@@ -107,6 +113,7 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardNonBacked
size_t url_len) override;
void WriteSvg(const char* markup_data, size_t markup_len) override;
void WriteRTF(const char* rtf_data, size_t data_len) override;
+ void WriteFilenames(std::vector<ui::FileInfo> filenames) override;
void WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
diff --git a/chromium/ui/base/clipboard/clipboard_non_backed_unittest.cc b/chromium/ui/base/clipboard/clipboard_non_backed_unittest.cc
index 4fa7c18928a..e5989209bb5 100644
--- a/chromium/ui/base/clipboard/clipboard_non_backed_unittest.cc
+++ b/chromium/ui/base/clipboard/clipboard_non_backed_unittest.cc
@@ -5,12 +5,27 @@
#include "ui/base/clipboard/clipboard_non_backed.h"
#include <memory>
+#include <vector>
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard_data.h"
+#include "ui/base/ui_base_features.h"
namespace ui {
+namespace {
+
+std::vector<std::string> UTF8Types(std::vector<base::string16> types) {
+ std::vector<std::string> result;
+ for (const base::string16& type : types)
+ result.push_back(base::UTF16ToUTF8(type));
+ return result;
+}
+
+} // namespace
class ClipboardNonBackedTest : public testing::Test {
public:
@@ -74,4 +89,42 @@ TEST_F(ClipboardNonBackedTest, AdminWriteDoesNotRecordHistograms) {
histogram_tester.ExpectTotalCount("Clipboard.Write", 0);
}
+// Tests that site bookmark URLs are accessed as text, and
+// IsFormatAvailable('text/uri-list') is only true for files.
+TEST_F(ClipboardNonBackedTest, TextURIList) {
+ base::test::ScopedFeatureList features;
+ features.InitWithFeatures({features::kClipboardFilenames}, {});
+ EXPECT_EQ("text/uri-list", ClipboardFormatType::GetFilenamesType().GetName());
+
+ auto data = std::make_unique<ClipboardData>();
+ data->set_bookmark_url("http://example.com");
+ clipboard()->WriteClipboardData(std::move(data));
+ std::vector<base::string16> types;
+ clipboard()->ReadAvailableTypes(ClipboardBuffer::kCopyPaste,
+ /*data_dst=*/nullptr, &types);
+
+ // With bookmark data, available types should be only 'text/plain'.
+ EXPECT_EQ(std::vector<std::string>({"text/plain"}), UTF8Types(types));
+ EXPECT_TRUE(clipboard()->IsFormatAvailable(ClipboardFormatType::GetUrlType(),
+ ClipboardBuffer::kCopyPaste,
+ /*data_dst=*/nullptr));
+ EXPECT_FALSE(clipboard()->IsFormatAvailable(
+ ClipboardFormatType::GetFilenamesType(), ClipboardBuffer::kCopyPaste,
+ /*data_dst=*/nullptr));
+
+ // With filenames data, available types should be 'text/uri-list'.
+ data = std::make_unique<ClipboardData>();
+ data->set_filenames({FileInfo(base::FilePath("/path"), base::FilePath())});
+ clipboard()->WriteClipboardData(std::move(data));
+ clipboard()->ReadAvailableTypes(ClipboardBuffer::kCopyPaste,
+ /*data_dst=*/nullptr, &types);
+ EXPECT_EQ(std::vector<std::string>({"text/uri-list"}), UTF8Types(types));
+ EXPECT_FALSE(clipboard()->IsFormatAvailable(ClipboardFormatType::GetUrlType(),
+ ClipboardBuffer::kCopyPaste,
+ /*data_dst=*/nullptr));
+ EXPECT_TRUE(clipboard()->IsFormatAvailable(
+ ClipboardFormatType::GetFilenamesType(), ClipboardBuffer::kCopyPaste,
+ /*data_dst=*/nullptr));
+}
+
} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_observer.cc b/chromium/ui/base/clipboard/clipboard_observer.cc
index 4adb0ac9954..00eaeae38bd 100644
--- a/chromium/ui/base/clipboard/clipboard_observer.cc
+++ b/chromium/ui/base/clipboard/clipboard_observer.cc
@@ -4,11 +4,13 @@
#include "ui/base/clipboard/clipboard_observer.h"
+#include "build/chromeos_buildflags.h"
+
namespace ui {
void ClipboardObserver::OnClipboardDataChanged() {}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void ClipboardObserver::OnClipboardDataRead() {}
#endif
diff --git a/chromium/ui/base/clipboard/clipboard_observer.h b/chromium/ui/base/clipboard/clipboard_observer.h
index 3e3a2af7c94..ebeefa921e2 100644
--- a/chromium/ui/base/clipboard/clipboard_observer.h
+++ b/chromium/ui/base/clipboard/clipboard_observer.h
@@ -8,6 +8,7 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
namespace ui {
@@ -17,7 +18,7 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardObserver {
// Override notified when clipboard data is changed.
virtual void OnClipboardDataChanged();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Override notified when clipboard data is read.
virtual void OnClipboardDataRead();
#endif
diff --git a/chromium/ui/base/clipboard/clipboard_ozone.cc b/chromium/ui/base/clipboard/clipboard_ozone.cc
index 774c8848ddf..782762a4064 100644
--- a/chromium/ui/base/clipboard/clipboard_ozone.cc
+++ b/chromium/ui/base/clipboard/clipboard_ozone.cc
@@ -4,18 +4,24 @@
#include "ui/base/clipboard/clipboard_ozone.h"
+#include <algorithm>
#include <limits>
#include <utility>
+#include <vector>
#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "base/containers/span.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/clipboard_constants.h"
@@ -28,7 +34,7 @@
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/platform_clipboard.h"
-#if defined(OS_CHROMEOS) && BUILDFLAG(OZONE_PLATFORM_X11)
+#if BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(OZONE_PLATFORM_X11)
#include "base/command_line.h"
#include "ui/base/clipboard/clipboard_non_backed.h"
#include "ui/base/ui_base_switches.h"
@@ -39,11 +45,14 @@ namespace ui {
namespace {
// The amount of time to wait for a request to complete before aborting it.
-constexpr base::TimeDelta kRequestTimeout = base::TimeDelta::FromSeconds(10);
+constexpr base::TimeDelta kRequestTimeout = base::TimeDelta::FromSeconds(1);
// Depending on the backend, the platform clipboard may or may not be
// available. Should it be absent, we provide a dummy one. It always calls
-// back immediately with empty data, and denies ownership of any buffer.
+// back immediately with empty data. It starts without ownership of any buffers
+// but will take and keep ownership after a call to OfferClipboardData(). By
+// taking ownership, we allow ClipboardOzone to return existing data in
+// ReadClipboardDataAndWait().
class StubPlatformClipboard : public PlatformClipboard {
public:
StubPlatformClipboard() = default;
@@ -54,6 +63,7 @@ class StubPlatformClipboard : public PlatformClipboard {
ClipboardBuffer buffer,
const PlatformClipboard::DataMap& data_map,
PlatformClipboard::OfferDataClosure callback) override {
+ is_owner_[buffer] = true;
std::move(callback).Run();
}
void RequestClipboardData(
@@ -68,10 +78,15 @@ class StubPlatformClipboard : public PlatformClipboard {
PlatformClipboard::GetMimeTypesClosure callback) override {
std::move(callback).Run({});
}
- bool IsSelectionOwner(ClipboardBuffer buffer) override { return false; }
+ bool IsSelectionOwner(ClipboardBuffer buffer) override {
+ return is_owner_[buffer];
+ }
void SetSequenceNumberUpdateCb(
PlatformClipboard::SequenceNumberUpdateCb cb) override {}
bool IsSelectionBufferAvailable() const override { return false; }
+
+ private:
+ base::flat_map<ClipboardBuffer, bool> is_owner_;
};
} // namespace
@@ -110,15 +125,9 @@ class ClipboardOzone::AsyncClipboardOzone {
return base::make_span(it->second->front(), it->second->size());
}
- Request request(RequestType::kRead);
- request.requested_mime_type = mime_type;
- PerformRequestAndWaitForResult(buffer, &request);
-
- offered_data_[buffer] = request.data_map;
- auto it = offered_data_[buffer].find(mime_type);
- if (it == offered_data_[buffer].end())
- return {};
- return base::make_span(it->second->front(), it->second->size());
+ if (auto data = Read(buffer, mime_type))
+ return base::make_span(data->front(), data->size());
+ return {};
}
std::vector<std::string> RequestMimeTypes(ClipboardBuffer buffer) {
@@ -130,17 +139,11 @@ class ClipboardOzone::AsyncClipboardOzone {
return mime_types;
}
- Request request(RequestType::kGetMime);
- PerformRequestAndWaitForResult(buffer, &request);
- return request.mime_types;
+ return GetMimeTypes(buffer);
}
void OfferData(ClipboardBuffer buffer) {
- Request request(RequestType::kOffer);
- request.data_map = data_to_offer_;
- offered_data_[buffer] = std::move(data_to_offer_);
- PerformRequestAndWaitForResult(buffer, &request);
-
+ Offer(buffer, std::move(data_to_offer_));
UpdateClipboardSequenceNumber(buffer);
}
@@ -166,118 +169,110 @@ class ClipboardOzone::AsyncClipboardOzone {
}
private:
- enum class RequestType {
- kRead = 0,
- kOffer = 1,
- kGetMime = 2,
- };
-
- // Holds request data to process inquiries from the ClipboardOzone.
- struct Request {
- explicit Request(RequestType request_type) : type(request_type) {}
- ~Request() = default;
-
- // Describes the type of the request.
- RequestType type;
-
- // A closure that is used to signal the request is processed.
- base::OnceClosure finish_closure;
-
- // Used for kRead and kOffer requests. It contains either data offered by
- // Chromium to a system clipboard or a read data offered by the system
- // clipboard.
- PlatformClipboard::DataMap data_map;
-
- // Identifies which mime type the client is interested to read from the
- // system clipboard during kRead requests.
- std::string requested_mime_type;
-
- // A vector of mime types returned as a result to a kGetMime request to get
- // available mime types.
- std::vector<std::string> mime_types;
- };
+ // Request<Result> encapsulates a clipboard request and provides a sync-like
+ // way to perform it, whereas Result is the operation return type. Request
+ // instances are created by factory functions (e.g: Read, Offer, GetMimeTypes,
+ // etc), which are supposed to know how to bind them to actual calls to the
+ // underlying platform clipboard instance. Factory functions usually create
+ // them as local vars (ie: stack memory), and bind them to weak references,
+ // through GetWeakPtr(), plumbing them into Finish* functions, which prevents
+ // use-after-free issues in case, for example, a platform clipboard callback
+ // would run with an already destroyed request instance.
+ template <typename Result>
+ class Request {
+ public:
+ enum class State { kStarted, kDone, kAborted };
+
+ // Blocks until the request is done or aborted. The |result_| is returned if
+ // the request succeeds, otherwise an empty value is returned.
+ Result TakeResultSync() {
+ // For a variety of reasons, it might already be done at this point,
+ // depending on the platform clipboard implementation and the specific
+ // request (e.g: cached values, sync request, etc).
+ if (state_ == State::kDone)
+ return std::move(result_);
+
+ DCHECK_EQ(state_, State::kStarted);
+
+ // TODO(crbug.com/913422): this is known to be dangerous, and may cause
+ // blocks in ui thread. But ui::Clipboard was designed with synchronous
+ // APIs rather than asynchronous ones, which platform clipboards can
+ // provide. E.g: X11 and Wayland.
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ quit_closure_ = run_loop.QuitClosure();
+
+ // Set a timeout timer after which the request will be aborted.
+ base::OneShotTimer abort_timer;
+ abort_timer.Start(FROM_HERE, kRequestTimeout,
+ base::BindOnce(&Request::Abort, GetWeakPtr()));
+
+ run_loop.Run();
+ return std::move(result_);
+ }
- void PerformRequestAndWaitForResult(ClipboardBuffer buffer,
- Request* request) {
- DCHECK(request);
- DCHECK(!abort_timer_.IsRunning());
- DCHECK(!pending_request_);
-
- pending_request_ = request;
- switch (pending_request_->type) {
- case (RequestType::kRead):
- DispatchReadRequest(buffer, request);
- break;
- case (RequestType::kOffer):
- DispatchOfferRequest(buffer, request);
- break;
- case (RequestType::kGetMime):
- DispatchGetMimeRequest(buffer, request);
- break;
+ void Finish(const Result& result) {
+ DCHECK_EQ(state_, State::kStarted);
+ state_ = State::kDone;
+ result_ = result;
+ if (!quit_closure_.is_null())
+ std::move(quit_closure_).Run();
}
- if (!pending_request_)
- return;
+ void FinishWithOptional(const base::Optional<Result>& result) {
+ Finish(result.value_or(Result{}));
+ }
- // TODO(https://crbug.com/913422): the implementation is known to be
- // dangerous, and may cause blocks in ui thread. But base::Clipboard was
- // designed to have synchronous APIs rather than asynchronous ones that at
- // least two system clipboards on X11 and Wayland provide.
- base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
- request->finish_closure = run_loop.QuitClosure();
+ base::WeakPtr<Request<Result>> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
- // Set a timeout timer after which the request will be aborted.
- abort_timer_.Start(FROM_HERE, kRequestTimeout, this,
- &AsyncClipboardOzone::AbortStalledRequest);
- run_loop.Run();
- }
+ private:
+ void Abort() {
+ DCHECK_EQ(state_, State::kStarted);
+ Finish(Result{});
+ state_ = State::kAborted;
+ }
- void AbortStalledRequest() {
- if (pending_request_ && pending_request_->finish_closure)
- std::move(pending_request_->finish_closure).Run();
- }
+ // Keeps track of the request state.
+ State state_ = State::kStarted;
- void DispatchReadRequest(ClipboardBuffer buffer, Request* request) {
- auto callback = base::BindOnce(&AsyncClipboardOzone::OnTextRead,
- weak_factory_.GetWeakPtr());
- platform_clipboard_->RequestClipboardData(
- buffer, request->requested_mime_type, &request->data_map,
- std::move(callback));
- }
+ // Holds the sync loop quit closure.
+ base::OnceClosure quit_closure_;
- void DispatchOfferRequest(ClipboardBuffer buffer, Request* request) {
- auto callback = base::BindOnce(&AsyncClipboardOzone::OnOfferDone,
- weak_factory_.GetWeakPtr());
- platform_clipboard_->OfferClipboardData(buffer, request->data_map,
- std::move(callback));
- }
+ // Stores the request result.
+ Result result_ = {};
- void DispatchGetMimeRequest(ClipboardBuffer buffer, Request* request) {
- auto callback = base::BindOnce(&AsyncClipboardOzone::OnGotMimeTypes,
- weak_factory_.GetWeakPtr());
- platform_clipboard_->GetAvailableMimeTypes(buffer, std::move(callback));
- }
+ base::WeakPtrFactory<Request<Result>> weak_factory_{this};
+ };
- void OnTextRead(const base::Optional<PlatformClipboard::Data>& data) {
- // |data| is already set in request's data_map, so just finish request
- // processing.
- CompleteRequest();
+ std::vector<std::string> GetMimeTypes(ClipboardBuffer buffer) {
+ using MimeTypesRequest = Request<std::vector<std::string>>;
+ MimeTypesRequest request;
+ platform_clipboard_->GetAvailableMimeTypes(
+ buffer,
+ base::BindOnce(&MimeTypesRequest::Finish, request.GetWeakPtr()));
+ return request.TakeResultSync();
}
- void OnOfferDone() { CompleteRequest(); }
-
- void OnGotMimeTypes(const std::vector<std::string>& mime_types) {
- pending_request_->mime_types = std::move(mime_types);
- CompleteRequest();
+ PlatformClipboard::Data Read(ClipboardBuffer buffer,
+ const std::string& mime_type) {
+ using ReadRequest = Request<PlatformClipboard::Data>;
+ ReadRequest request;
+ PlatformClipboard::DataMap data_map;
+ platform_clipboard_->RequestClipboardData(
+ buffer, mime_type, &data_map,
+ base::BindOnce(&ReadRequest::FinishWithOptional, request.GetWeakPtr()));
+ return request.TakeResultSync().release();
}
- void CompleteRequest() {
- if (!pending_request_)
- return;
- abort_timer_.Stop();
- if (pending_request_->finish_closure)
- std::move(pending_request_->finish_closure).Run();
- pending_request_ = nullptr;
+ void Offer(ClipboardBuffer buffer, PlatformClipboard::DataMap data_map) {
+ using OfferRequest = Request<bool>;
+ OfferRequest request;
+ offered_data_[buffer] = data_map;
+ platform_clipboard_->OfferClipboardData(
+ buffer, data_map,
+ base::BindOnce(&OfferRequest::Finish, request.GetWeakPtr(), true));
+ request.TakeResultSync();
}
void UpdateClipboardSequenceNumber(ClipboardBuffer buffer) {
@@ -291,12 +286,6 @@ class ClipboardOzone::AsyncClipboardOzone {
// read data if we still own it.
base::flat_map<ClipboardBuffer, PlatformClipboard::DataMap> offered_data_;
- // A current pending request being processed.
- Request* pending_request_ = nullptr;
-
- // Aborts |pending_request| after Request::timeout.
- base::RepeatingTimer abort_timer_;
-
// Provides communication to a system clipboard under ozone level.
PlatformClipboard* const platform_clipboard_ = nullptr;
@@ -308,12 +297,16 @@ class ClipboardOzone::AsyncClipboardOzone {
};
// Uses the factory in the clipboard_linux otherwise.
-#if defined(OS_CHROMEOS) || !defined(OS_LINUX)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
// Clipboard factory method.
Clipboard* Clipboard::Create() {
// linux-chromeos uses non-backed clipboard by default, but supports ozone x11
// with flag --use-system-clipbboard.
-#if defined(OS_CHROMEOS) && BUILDFLAG(OZONE_PLATFORM_X11)
+#if BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(OZONE_PLATFORM_X11)
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseSystemClipboard)) {
return new ClipboardNonBacked;
@@ -343,6 +336,11 @@ ClipboardOzone::~ClipboardOzone() = default;
void ClipboardOzone::OnPreShutdown() {}
+DataTransferEndpoint* ClipboardOzone::GetSource(ClipboardBuffer buffer) const {
+ auto it = data_src_.find(buffer);
+ return it == data_src_.end() ? nullptr : it->second.get();
+}
+
uint64_t ClipboardOzone::GetSequenceNumber(ClipboardBuffer buffer) const {
return async_clipboard_ozone_->GetSequenceNumber(buffer);
}
@@ -360,6 +358,7 @@ bool ClipboardOzone::IsFormatAvailable(
void ClipboardOzone::Clear(ClipboardBuffer buffer) {
async_clipboard_ozone_->Clear(buffer);
+ data_src_[buffer].reset();
}
// TODO(crbug.com/1103194): |data_dst| should be supported.
@@ -499,6 +498,19 @@ void ClipboardOzone::ReadCustomData(ClipboardBuffer buffer,
}
// TODO(crbug.com/1103194): |data_dst| should be supported.
+void ClipboardOzone::ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const {
+ DCHECK(CalledOnValidThread());
+ RecordRead(ClipboardFormatMetric::kFilenames);
+
+ auto clipboard_data = async_clipboard_ozone_->ReadClipboardDataAndWait(
+ buffer, kMimeTypeURIList);
+ std::string uri_list(clipboard_data.begin(), clipboard_data.end());
+ *result = ui::URIListToFileInfos(uri_list);
+}
+
+// TODO(crbug.com/1103194): |data_dst| should be supported.
void ClipboardOzone::ReadBookmark(const DataTransferEndpoint* data_dst,
base::string16* title,
std::string* url) const {
@@ -549,6 +561,8 @@ void ClipboardOzone::WritePortableRepresentations(
async_clipboard_ozone_->OfferData(ClipboardBuffer::kSelection);
}
}
+
+ data_src_[buffer] = std::move(data_src);
}
// TODO(crbug.com/1103194): |data_src| should be supported
@@ -560,6 +574,8 @@ void ClipboardOzone::WritePlatformRepresentations(
DispatchPlatformRepresentations(std::move(platform_representations));
async_clipboard_ozone_->OfferData(buffer);
+
+ data_src_[buffer] = std::move(data_src);
}
void ClipboardOzone::WriteText(const char* text_data, size_t text_len) {
@@ -587,6 +603,12 @@ void ClipboardOzone::WriteRTF(const char* rtf_data, size_t data_len) {
async_clipboard_ozone_->InsertData(std::move(data), {kMimeTypeRTF});
}
+void ClipboardOzone::WriteFilenames(std::vector<ui::FileInfo> filenames) {
+ std::string uri_list = ui::FileInfosToURIList(filenames);
+ std::vector<uint8_t> data(uri_list.begin(), uri_list.end());
+ async_clipboard_ozone_->InsertData(std::move(data), {kMimeTypeURIList});
+}
+
void ClipboardOzone::WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
diff --git a/chromium/ui/base/clipboard/clipboard_ozone.h b/chromium/ui/base/clipboard/clipboard_ozone.h
index b46a7c5703e..70f0be365d0 100644
--- a/chromium/ui/base/clipboard/clipboard_ozone.h
+++ b/chromium/ui/base/clipboard/clipboard_ozone.h
@@ -25,6 +25,7 @@ class ClipboardOzone : public Clipboard {
// Clipboard overrides:
void OnPreShutdown() override;
+ DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardBuffer buffer,
@@ -61,6 +62,9 @@ class ClipboardOzone : public Clipboard {
const base::string16& type,
const DataTransferEndpoint* data_dst,
base::string16* result) const override;
+ void ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const override;
void ReadBookmark(const DataTransferEndpoint* data_dst,
base::string16* title,
std::string* url) const override;
@@ -83,6 +87,7 @@ class ClipboardOzone : public Clipboard {
size_t url_len) override;
void WriteSvg(const char* markup_data, size_t markup_len) override;
void WriteRTF(const char* rtf_data, size_t data_len) override;
+ void WriteFilenames(std::vector<ui::FileInfo> filenames) override;
void WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
@@ -98,6 +103,8 @@ class ClipboardOzone : public Clipboard {
class AsyncClipboardOzone;
std::unique_ptr<AsyncClipboardOzone> async_clipboard_ozone_;
+ base::flat_map<ClipboardBuffer, std::unique_ptr<DataTransferEndpoint>>
+ data_src_;
DISALLOW_COPY_AND_ASSIGN(ClipboardOzone);
};
diff --git a/chromium/ui/base/clipboard/clipboard_test_template.h b/chromium/ui/base/clipboard/clipboard_test_template.h
index 7be5cd2d0b8..533f759787e 100644
--- a/chromium/ui/base/clipboard/clipboard_test_template.h
+++ b/chromium/ui/base/clipboard/clipboard_test_template.h
@@ -21,11 +21,15 @@
#include <memory>
#include <string>
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
#include "base/pickle.h"
#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#include "build/chromeos_buildflags.h"
@@ -44,6 +48,7 @@
#include "ui/base/clipboard/test/test_clipboard.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
+#include "ui/base/ui_base_features.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/half_float.h"
#include "url/origin.h"
@@ -109,9 +114,13 @@ class MockPolicyController : public DataTransferPolicyController {
MockPolicyController();
~MockPolicyController() override;
- MOCK_CONST_METHOD2(IsDataReadAllowed,
- bool(const DataTransferEndpoint* const data_src,
- const DataTransferEndpoint* const data_dst));
+ MOCK_METHOD2(IsClipboardReadAllowed,
+ bool(const DataTransferEndpoint* const data_src,
+ const DataTransferEndpoint* const data_dst));
+ MOCK_METHOD3(IsDragDropAllowed,
+ bool(const DataTransferEndpoint* const data_src,
+ const DataTransferEndpoint* const data_dst,
+ const bool is_drop));
};
MockPolicyController::MockPolicyController() = default;
@@ -157,8 +166,9 @@ TYPED_TEST(ClipboardTest, TextTest) {
EXPECT_THAT(this->GetAvailableTypes(ClipboardBuffer::kCopyPaste),
Contains(ASCIIToUTF16(kMimeTypeText)));
-#if defined(USE_OZONE) && !defined(OS_CHROMEOS) && !defined(OS_FUCHSIA) && \
- !BUILDFLAG(IS_CHROMECAST) && !BUILDFLAG(IS_LACROS)
+#if defined(USE_OZONE) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
+ !defined(OS_FUCHSIA) && !BUILDFLAG(IS_CHROMECAST) && \
+ !BUILDFLAG(IS_CHROMEOS_LACROS)
// TODO(https://crbug.com/1096425): remove this if condition. It seems like
// we have this condition working for Ozone/Linux, but not for X11/Linux.
if (features::IsUsingOzonePlatform()) {
@@ -260,7 +270,9 @@ TYPED_TEST(ClipboardTest, RTFTest) {
}
#endif // !defined(OS_ANDROID)
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
TYPED_TEST(ClipboardTest, MultipleBufferTest) {
if (!ui::Clipboard::IsSupportedClipboardBuffer(
ui::ClipboardBuffer::kSelection)) {
@@ -403,6 +415,41 @@ TYPED_TEST(ClipboardTest, BookmarkTest) {
}
#endif // !defined(OS_POSIX) || defined(OS_APPLE)
+#if !defined(OS_ANDROID)
+// Filenames is not implemented in ClipboardAndroid.
+TYPED_TEST(ClipboardTest, FilenamesTest) {
+ base::test::ScopedFeatureList features;
+ features.InitWithFeatures({features::kClipboardFilenames}, {});
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath file;
+ ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.GetPath(), &file));
+
+ {
+ ScopedClipboardWriter clipboard_writer(ClipboardBuffer::kCopyPaste);
+ clipboard_writer.WriteFilenames(
+ ui::FileInfosToURIList({ui::FileInfo(file, base::FilePath())}));
+ }
+
+ EXPECT_TRUE(this->clipboard().IsFormatAvailable(
+ ClipboardFormatType::GetFilenamesType(), ClipboardBuffer::kCopyPaste,
+ /* data_dst = */ nullptr));
+
+ std::vector<base::string16> types;
+ this->clipboard().ReadAvailableTypes(ClipboardBuffer::kCopyPaste,
+ /* data_dst = */ nullptr, &types);
+ EXPECT_EQ(1u, types.size());
+ EXPECT_EQ("text/uri-list", base::UTF16ToUTF8(types[0]));
+
+ std::vector<ui::FileInfo> filenames;
+ this->clipboard().ReadFilenames(ClipboardBuffer::kCopyPaste,
+ /* data_dst = */ nullptr, &filenames);
+ EXPECT_EQ(1u, filenames.size());
+ EXPECT_EQ(file, filenames[0].path);
+}
+#endif // !defined(OS_ANDROID)
+
TYPED_TEST(ClipboardTest, MultiFormatTest) {
base::string16 text(ASCIIToUTF16("Hi!")), text_result;
base::string16 markup(ASCIIToUTF16("<strong>Hi!</string>")), markup_result;
@@ -483,7 +530,7 @@ TYPED_TEST(ClipboardTest, URLTest) {
// TODO(tonikitoo, msisov): enable back for ClipboardOzone implements
// selection support. https://crbug.com/911992
#if defined(OS_POSIX) && !defined(OS_APPLE) && !defined(OS_ANDROID) && \
- !defined(OS_CHROMEOS) && !defined(USE_OZONE)
+ !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(USE_OZONE)
ascii_text.clear();
this->clipboard().ReadAsciiText(ClipboardBuffer::kSelection,
/* data_dst = */ nullptr, &ascii_text);
@@ -683,7 +730,7 @@ TYPED_TEST(ClipboardTest, DataTest) {
// because ClipboardInternal only supports one raw type.
#if (!defined(USE_AURA) || defined(OS_WIN) || defined(USE_OZONE) || \
defined(USE_X11)) && \
- !defined(OS_CHROMEOS)
+ !BUILDFLAG(IS_CHROMEOS_ASH)
TYPED_TEST(ClipboardTest, MultipleDataTest) {
const std::string kFormatString1 = "chromium/x-test-format1";
const ClipboardFormatType kFormat1 =
@@ -745,8 +792,10 @@ TYPED_TEST(ClipboardTest, ReadAvailablePlatformSpecificFormatNamesTest) {
EXPECT_THAT(raw_types, Contains(ASCIIToUTF16("public.utf8-plain-text")));
EXPECT_THAT(raw_types, Contains(ASCIIToUTF16("NSStringPboardType")));
EXPECT_EQ(raw_types.size(), static_cast<uint64_t>(2));
-#elif defined(OS_LINUX) && !defined(OS_CHROMEOS) && \
- !BUILDFLAG(IS_CHROMECAST) && !BUILDFLAG(IS_LACROS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#elif defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
+ !BUILDFLAG(IS_CHROMECAST) && !BUILDFLAG(IS_CHROMEOS_LACROS)
EXPECT_THAT(raw_types, Contains(ASCIIToUTF16(kMimeTypeText)));
EXPECT_THAT(raw_types, Contains(ASCIIToUTF16("TEXT")));
EXPECT_THAT(raw_types, Contains(ASCIIToUTF16("STRING")));
@@ -1021,7 +1070,7 @@ TYPED_TEST(ClipboardTest, WriteImageEmptyParams) {
// Policy controller is only intended to be used in Chrome OS, so the following
// policy related tests are only run on Chrome OS.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Test that copy/paste would work normally if the policy controller didn't
// restrict the clipboard data.
TYPED_TEST(ClipboardTest, PolicyAllowDataRead) {
@@ -1033,7 +1082,7 @@ TYPED_TEST(ClipboardTest, PolicyAllowDataRead) {
std::make_unique<DataTransferEndpoint>(url::Origin()));
writer.WriteText(kTestText);
}
- EXPECT_CALL(*policy_controller, IsDataReadAllowed)
+ EXPECT_CALL(*policy_controller, IsClipboardReadAllowed)
.WillRepeatedly(testing::Return(true));
base::string16 read_result;
this->clipboard().ReadText(ClipboardBuffer::kCopyPaste,
@@ -1053,7 +1102,7 @@ TYPED_TEST(ClipboardTest, PolicyDisallow_ReadText) {
std::make_unique<DataTransferEndpoint>(url::Origin()));
writer.WriteText(kTestText);
}
- EXPECT_CALL(*policy_controller, IsDataReadAllowed)
+ EXPECT_CALL(*policy_controller, IsClipboardReadAllowed)
.WillRepeatedly(testing::Return(false));
base::string16 read_result;
this->clipboard().ReadText(ClipboardBuffer::kCopyPaste,
@@ -1064,14 +1113,14 @@ TYPED_TEST(ClipboardTest, PolicyDisallow_ReadText) {
TYPED_TEST(ClipboardTest, PolicyDisallow_ReadImage) {
auto policy_controller = std::make_unique<MockPolicyController>();
- EXPECT_CALL(*policy_controller, IsDataReadAllowed)
+ EXPECT_CALL(*policy_controller, IsClipboardReadAllowed)
.WillRepeatedly(testing::Return(false));
const SkBitmap& image = clipboard_test_util::ReadImage(&this->clipboard());
::testing::Mock::VerifyAndClearExpectations(policy_controller.get());
EXPECT_EQ(true, image.empty());
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_util_win.cc b/chromium/ui/base/clipboard/clipboard_util_win.cc
index 8c6486c0212..9a212a9f485 100644
--- a/chromium/ui/base/clipboard/clipboard_util_win.cc
+++ b/chromium/ui/base/clipboard/clipboard_util_win.cc
@@ -33,6 +33,9 @@ namespace ui {
namespace {
+constexpr STGMEDIUM kNullStorageMedium = {.tymed = TYMED_NULL,
+ .pUnkForRelease = nullptr};
+
bool HasData(IDataObject* data_object, const ClipboardFormatType& format) {
FORMATETC format_etc = format.ToFormatEtc();
return SUCCEEDED(data_object->QueryGetData(&format_etc));
@@ -584,6 +587,53 @@ bool ClipboardUtil::GetFilenames(IDataObject* data_object,
return false;
}
+STGMEDIUM ClipboardUtil::CreateStorageForFileNames(
+ const std::vector<FileInfo>& filenames) {
+ // CF_HDROP clipboard format consists of DROPFILES structure, a series of file
+ // names including the terminating null character and the additional null
+ // character at the tail to terminate the array.
+ // For example,
+ //| DROPFILES | FILENAME 1 | NULL | ... | FILENAME n | NULL | NULL |
+ // For more details, please refer to
+ // https://docs.microsoft.com/en-us/windows/desktop/shell/clipboard#cf_hdrop
+
+ if (filenames.empty())
+ return kNullStorageMedium;
+
+ const size_t kDropFilesHeaderSizeInBytes = sizeof(DROPFILES);
+ size_t total_bytes = kDropFilesHeaderSizeInBytes;
+ for (const auto& filename : filenames) {
+ // Allocate memory of the filename's length including the null
+ // character.
+ total_bytes += (filename.path.value().length() + 1) * sizeof(wchar_t);
+ }
+ // |data| needs to be terminated by an additional null character.
+ total_bytes += sizeof(wchar_t);
+
+ // GHND combines GMEM_MOVEABLE and GMEM_ZEROINIT, and GMEM_ZEROINIT
+ // initializes memory contents to zero.
+ HANDLE hdata = GlobalAlloc(GHND, total_bytes);
+
+ base::win::ScopedHGlobal<DROPFILES*> locked_mem(hdata);
+ DROPFILES* drop_files = locked_mem.get();
+ drop_files->pFiles = sizeof(DROPFILES);
+ drop_files->fWide = TRUE;
+
+ wchar_t* data = reinterpret_cast<wchar_t*>(
+ reinterpret_cast<BYTE*>(drop_files) + kDropFilesHeaderSizeInBytes);
+
+ size_t next_filename_offset = 0;
+ for (const auto& filename : filenames) {
+ wcscpy(data + next_filename_offset, filename.path.value().c_str());
+ // Skip the terminating null character of the filename.
+ next_filename_offset += filename.path.value().length() + 1;
+ }
+
+ STGMEDIUM storage = {
+ .tymed = TYMED_HGLOBAL, .hGlobal = hdata, .pUnkForRelease = nullptr};
+ return storage;
+}
+
bool ClipboardUtil::GetVirtualFilenames(
IDataObject* data_object,
std::vector<base::FilePath>* filenames) {
diff --git a/chromium/ui/base/clipboard/clipboard_util_win.h b/chromium/ui/base/clipboard/clipboard_util_win.h
index 2c0af5d665c..3e17b4c0133 100644
--- a/chromium/ui/base/clipboard/clipboard_util_win.h
+++ b/chromium/ui/base/clipboard/clipboard_util_win.h
@@ -16,6 +16,7 @@
#include "base/component_export.h"
#include "base/files/file_path.h"
#include "base/strings/string16.h"
+#include "ui/base/clipboard/file_info.h"
class GURL;
@@ -47,6 +48,10 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardUtil {
static bool GetFilenames(IDataObject* data_object,
std::vector<std::wstring>* filenames);
+ // Creates a new STGMEDIUM object to hold files.
+ static STGMEDIUM CreateStorageForFileNames(
+ const std::vector<FileInfo>& filenames);
+
// Fills a vector of display names of "virtual files" in the data store, but
// does not actually retrieve the file contents. Display names are assured to
// be unique. Method is called on drag enter of the Chromium drop target, when
diff --git a/chromium/ui/base/clipboard/clipboard_win.cc b/chromium/ui/base/clipboard/clipboard_win.cc
index 344b847b0e2..84071dbb29c 100644
--- a/chromium/ui/base/clipboard/clipboard_win.cc
+++ b/chromium/ui/base/clipboard/clipboard_win.cc
@@ -7,11 +7,13 @@
#include "ui/base/clipboard/clipboard_win.h"
+#include <objidl.h>
#include <shellapi.h>
#include <shlobj.h>
#include "base/bind.h"
#include "base/check_op.h"
+#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
@@ -19,13 +21,17 @@
#include "base/numerics/safe_conversions.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"
+#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_offset_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/current_thread.h"
#include "base/win/message_window.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/scoped_hdc.h"
+#include "base/win/scoped_hglobal.h"
+#include "net/base/filename_util.h"
#include "skia/ext/skia_utils_base.h"
#include "skia/ext/skia_utils_win.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -34,8 +40,10 @@
#include "ui/base/clipboard/clipboard_util_win.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/ui_base_features.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/size.h"
+#include "url/gurl.h"
namespace ui {
@@ -222,6 +230,19 @@ void TrimAfterNull(StringType* result) {
result->resize(pos);
}
+bool ReadFilenamesAvailable() {
+ // Only support filenames if chrome://flags#clipboard-filenames is enabled.
+ if (!base::FeatureList::IsEnabled(features::kClipboardFilenames))
+ return false;
+
+ return ::IsClipboardFormatAvailable(
+ ClipboardFormatType::GetCFHDropType().ToFormatEtc().cfFormat) ||
+ ::IsClipboardFormatAvailable(
+ ClipboardFormatType::GetFilenameType().ToFormatEtc().cfFormat) ||
+ ::IsClipboardFormatAvailable(
+ ClipboardFormatType::GetFilenameAType().ToFormatEtc().cfFormat);
+}
+
} // namespace
// Clipboard factory method.
@@ -241,6 +262,12 @@ ClipboardWin::~ClipboardWin() {
void ClipboardWin::OnPreShutdown() {}
+// DataTransferEndpoint is not used on this platform.
+DataTransferEndpoint* ClipboardWin::GetSource(ClipboardBuffer buffer) const {
+ DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
+ return nullptr;
+}
+
uint64_t ClipboardWin::GetSequenceNumber(ClipboardBuffer buffer) const {
DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
return ::GetClipboardSequenceNumber();
@@ -253,6 +280,8 @@ bool ClipboardWin::IsFormatAvailable(
ClipboardBuffer buffer,
const DataTransferEndpoint* data_dst) const {
DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
+ if (format == ClipboardFormatType::GetFilenameType())
+ return ReadFilenamesAvailable();
return ::IsClipboardFormatAvailable(format.ToFormatEtc().cfFormat) != FALSE;
}
@@ -285,6 +314,8 @@ void ClipboardWin::ReadAvailableTypes(
types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
if (::IsClipboardFormatAvailable(CF_DIB))
types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
+ if (ReadFilenamesAvailable())
+ types->push_back(base::UTF8ToUTF16(kMimeTypeURIList));
// Acquire the clipboard to read WebCustomDataType types.
ScopedClipboard clipboard;
@@ -509,6 +540,75 @@ void ClipboardWin::ReadCustomData(ClipboardBuffer buffer,
// |data_dst| is not used. It's only passed to be consistent with other
// platforms.
+void ClipboardWin::ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const {
+ DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
+ DCHECK(result);
+ RecordRead(ClipboardFormatMetric::kFilenames);
+
+ result->clear();
+ if (!ReadFilenamesAvailable())
+ return;
+
+ // Acquire the clipboard.
+ ScopedClipboard clipboard;
+ if (!clipboard.Acquire(GetClipboardWindow()))
+ return;
+
+ // TODO(crbug.com/1178671): Refactor similar code in clipboard_utils_win:
+ // ClipboardUtil::GetFilenames() and reuse rather than duplicate.
+ HANDLE data = ::GetClipboardData(
+ ClipboardFormatType::GetCFHDropType().ToFormatEtc().cfFormat);
+ if (data) {
+ {
+ base::win::ScopedHGlobal<HDROP> hdrop(data);
+ if (!hdrop.get())
+ return;
+
+ const int kMaxFilenameLen = 4096;
+ const unsigned num_files = DragQueryFileW(hdrop.get(), 0xffffffff, 0, 0);
+ for (unsigned int i = 0; i < num_files; ++i) {
+ wchar_t filename[kMaxFilenameLen];
+ if (!DragQueryFileW(hdrop.get(), i, filename, kMaxFilenameLen))
+ continue;
+ base::FilePath path(filename);
+ result->push_back(ui::FileInfo(path, base::FilePath()));
+ }
+ }
+ return;
+ }
+
+ data = ::GetClipboardData(
+ ClipboardFormatType::GetFilenameType().ToFormatEtc().cfFormat);
+ if (data) {
+ {
+ // filename using Unicode
+ base::win::ScopedHGlobal<wchar_t*> filename(data);
+ if (filename.get() && filename.get()[0]) {
+ base::FilePath path(filename.get());
+ result->push_back(ui::FileInfo(path, base::FilePath()));
+ }
+ }
+ return;
+ }
+
+ data = ::GetClipboardData(
+ ClipboardFormatType::GetFilenameAType().ToFormatEtc().cfFormat);
+ if (data) {
+ {
+ // filename using ASCII
+ base::win::ScopedHGlobal<char*> filename(data);
+ if (filename.get() && filename.get()[0]) {
+ base::FilePath path(base::SysNativeMBToWide(filename.get()));
+ result->push_back(ui::FileInfo(path, base::FilePath()));
+ }
+ }
+ }
+}
+
+// |data_dst| is not used. It's only passed to be consistent with other
+// platforms.
void ClipboardWin::ReadBookmark(const DataTransferEndpoint* data_dst,
base::string16* title,
std::string* url) const {
@@ -632,6 +732,13 @@ void ClipboardWin::WriteRTF(const char* rtf_data, size_t data_len) {
WriteData(ClipboardFormatType::GetRtfType(), rtf_data, data_len);
}
+void ClipboardWin::WriteFilenames(std::vector<ui::FileInfo> filenames) {
+ STGMEDIUM storage = ClipboardUtil::CreateStorageForFileNames(filenames);
+ if (storage.tymed == TYMED_NULL)
+ return;
+ WriteToClipboard(ClipboardFormatType::GetCFHDropType(), storage.hGlobal);
+}
+
void ClipboardWin::WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
diff --git a/chromium/ui/base/clipboard/clipboard_win.h b/chromium/ui/base/clipboard/clipboard_win.h
index e3532315b68..a3129d23e57 100644
--- a/chromium/ui/base/clipboard/clipboard_win.h
+++ b/chromium/ui/base/clipboard/clipboard_win.h
@@ -35,6 +35,7 @@ class ClipboardWin : public Clipboard {
// Clipboard overrides:
void OnPreShutdown() override;
+ DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardBuffer buffer,
@@ -71,6 +72,9 @@ class ClipboardWin : public Clipboard {
const base::string16& type,
const DataTransferEndpoint* data_dst,
base::string16* result) const override;
+ void ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const override;
void ReadBookmark(const DataTransferEndpoint* data_dst,
base::string16* title,
std::string* url) const override;
@@ -92,6 +96,7 @@ class ClipboardWin : public Clipboard {
size_t url_len) override;
void WriteSvg(const char* markup_data, size_t markup_len) override;
void WriteRTF(const char* rtf_data, size_t data_len) override;
+ void WriteFilenames(std::vector<ui::FileInfo> filenames) override;
void WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
diff --git a/chromium/ui/base/clipboard/clipboard_x11.cc b/chromium/ui/base/clipboard/clipboard_x11.cc
index 13966680032..767819294ad 100644
--- a/chromium/ui/base/clipboard/clipboard_x11.cc
+++ b/chromium/ui/base/clipboard/clipboard_x11.cc
@@ -11,6 +11,8 @@
#include <memory>
#include <set>
+#include "base/containers/contains.h"
+#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/macros.h"
@@ -18,7 +20,6 @@
#include "base/memory/singleton.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
-#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"
@@ -27,19 +28,20 @@
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/nine_image_painter_factory.h"
+#include "ui/base/ui_base_features.h"
#include "ui/base/x/selection_owner.h"
#include "ui/base/x/selection_requestor.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
-#include "ui/events/platform/x11/x11_event_source.h"
-#include "ui/events/x/x11_window_event_manager.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
#include "ui/gfx/x/xfixes.h"
#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_util.h"
namespace ui {
@@ -51,7 +53,7 @@ const char kClipboardManager[] = "CLIPBOARD_MANAGER";
///////////////////////////////////////////////////////////////////////////////
// Uses the XFixes API to provide sequence numbers for GetSequenceNumber().
-class SelectionChangeObserver : public XEventObserver {
+class SelectionChangeObserver : public x11::EventObserver {
public:
static SelectionChangeObserver* GetInstance();
@@ -66,9 +68,8 @@ class SelectionChangeObserver : public XEventObserver {
SelectionChangeObserver();
~SelectionChangeObserver() override;
- // XEventObserver:
- void WillProcessXEvent(x11::Event* xev) override;
- void DidProcessXEvent(x11::Event* xev) override {}
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& xev) override;
x11::Atom clipboard_atom_{};
uint64_t clipboard_sequence_number_{};
@@ -78,14 +79,15 @@ class SelectionChangeObserver : public XEventObserver {
};
SelectionChangeObserver::SelectionChangeObserver() {
- auto& xfixes = x11::Connection::Get()->xfixes();
+ auto* connection = x11::Connection::Get();
+ auto& xfixes = connection->xfixes();
// Let the server know the client version. No need to sync since we don't
// care what version is running on the server.
xfixes.QueryVersion({x11::XFixes::major_version, x11::XFixes::minor_version});
if (!xfixes.present())
return;
- clipboard_atom_ = gfx::GetAtom(kClipboard);
+ clipboard_atom_ = x11::GetAtom(kClipboard);
auto mask = x11::XFixes::SelectionEventMask::SetSelectionOwner |
x11::XFixes::SelectionEventMask::SelectionWindowDestroy |
x11::XFixes::SelectionEventMask::SelectionClientClose;
@@ -95,7 +97,7 @@ SelectionChangeObserver::SelectionChangeObserver() {
// primary and the clipboard buffers. Register anyway just to be safe.
xfixes.SelectSelectionInput({GetX11RootWindow(), x11::Atom::PRIMARY, mask});
- X11EventSource::GetInstance()->AddXEventObserver(this);
+ connection->AddEventObserver(this);
}
// We are a singleton; we will outlive the event source.
@@ -105,8 +107,8 @@ SelectionChangeObserver* SelectionChangeObserver::GetInstance() {
return base::Singleton<SelectionChangeObserver>::get();
}
-void SelectionChangeObserver::WillProcessXEvent(x11::Event* xev) {
- auto* ev = xev->As<x11::XFixes::SelectionNotifyEvent>();
+void SelectionChangeObserver::OnEvent(const x11::Event& xev) {
+ auto* ev = xev.As<x11::XFixes::SelectionNotifyEvent>();
if (!ev)
return;
@@ -154,7 +156,7 @@ bool TargetList::ContainsText() const {
}
bool TargetList::ContainsFormat(const ClipboardFormatType& format_type) const {
- x11::Atom atom = gfx::GetAtom(format_type.GetName().c_str());
+ x11::Atom atom = x11::GetAtom(format_type.GetName().c_str());
return ContainsAtom(atom);
}
@@ -174,7 +176,7 @@ x11::Window GetSelectionOwner(x11::Atom selection) {
// Private implementation of our X11 integration. Keeps X11 headers out of the
// majority of chrome, which break badly.
-class ClipboardX11::X11Details : public XEventDispatcher {
+class ClipboardX11::X11Details : public x11::EventObserver {
public:
X11Details();
~X11Details() override;
@@ -235,8 +237,8 @@ class ClipboardX11::X11Details : public XEventDispatcher {
void StoreCopyPasteDataAndWait();
private:
- // XEventDispatcher:
- bool DispatchXEvent(x11::Event* xev) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& xev) override;
// Our X11 state.
x11::Connection* connection_;
@@ -246,7 +248,7 @@ class ClipboardX11::X11Details : public XEventDispatcher {
x11::Window x_window_;
// Events selected on |x_window_|.
- std::unique_ptr<XScopedEventSelector> x_window_events_;
+ std::unique_ptr<x11::XScopedEventSelector> x_window_events_;
// Object which requests and receives selection data.
SelectionRequestor selection_requestor_;
@@ -264,23 +266,20 @@ class ClipboardX11::X11Details : public XEventDispatcher {
ClipboardX11::X11Details::X11Details()
: connection_(x11::Connection::Get()),
x_root_window_(ui::GetX11RootWindow()),
- x_window_(CreateDummyWindow("Chromium Clipboard Window")),
+ x_window_(x11::CreateDummyWindow("Chromium Clipboard Window")),
selection_requestor_(x_window_, this),
- clipboard_owner_(connection_, x_window_, gfx::GetAtom(kClipboard)),
+ clipboard_owner_(connection_, x_window_, x11::GetAtom(kClipboard)),
primary_owner_(connection_, x_window_, x11::Atom::PRIMARY) {
- SetStringProperty(x_window_, x11::Atom::WM_NAME, x11::Atom::STRING,
- "Chromium clipboard");
- x_window_events_ = std::make_unique<XScopedEventSelector>(
+ x11::SetStringProperty(x_window_, x11::Atom::WM_NAME, x11::Atom::STRING,
+ "Chromium clipboard");
+ x_window_events_ = std::make_unique<x11::XScopedEventSelector>(
x_window_, x11::EventMask::PropertyChange);
- if (X11EventSource::GetInstance())
- X11EventSource::GetInstance()->AddXEventDispatcher(this);
+ connection_->AddEventObserver(this);
}
ClipboardX11::X11Details::~X11Details() {
- if (X11EventSource::GetInstance())
- X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
-
+ connection_->RemoveEventObserver(this);
connection_->DestroyWindow({x_window_});
}
@@ -293,7 +292,7 @@ x11::Atom ClipboardX11::X11Details::LookupSelectionForClipboardBuffer(
}
x11::Atom ClipboardX11::X11Details::GetCopyPasteSelection() const {
- return gfx::GetAtom(kClipboard);
+ return x11::GetAtom(kClipboard);
}
const SelectionFormatMap& ClipboardX11::X11Details::LookupStorageForAtom(
@@ -312,7 +311,7 @@ void ClipboardX11::X11Details::CreateNewClipboardData() {
void ClipboardX11::X11Details::InsertMapping(
const std::string& key,
const scoped_refptr<base::RefCountedMemory>& memory) {
- x11::Atom atom_key = gfx::GetAtom(key.c_str());
+ x11::Atom atom_key = x11::GetAtom(key.c_str());
clipboard_data_.Insert(atom_key, memory);
}
@@ -366,9 +365,9 @@ TargetList ClipboardX11::X11Details::WaitAndGetTargetsList(
x11::Atom out_type = x11::Atom::None;
if (selection_requestor_.PerformBlockingConvertSelection(
- selection_name, gfx::GetAtom(kTargets), &data, &out_type)) {
+ selection_name, x11::GetAtom(kTargets), &data, &out_type)) {
// Some apps return an |out_type| of "TARGETS". (crbug.com/377893)
- if (out_type == x11::Atom::ATOM || out_type == gfx::GetAtom(kTargets)) {
+ if (out_type == x11::Atom::ATOM || out_type == x11::GetAtom(kTargets)) {
const x11::Atom* atom_array =
reinterpret_cast<const x11::Atom*>(data.data());
for (size_t i = 0; i < data.size() / sizeof(x11::Atom); ++i)
@@ -402,7 +401,7 @@ std::vector<x11::Atom> ClipboardX11::X11Details::GetTextAtoms() const {
std::vector<x11::Atom> ClipboardX11::X11Details::GetAtomsForFormat(
const ClipboardFormatType& format) {
- return {gfx::GetAtom(format.GetName().c_str())};
+ return {x11::GetAtom(format.GetName().c_str())};
}
void ClipboardX11::X11Details::Clear(ClipboardBuffer buffer) {
@@ -417,7 +416,7 @@ void ClipboardX11::X11Details::StoreCopyPasteDataAndWait() {
if (GetSelectionOwner(selection) != x_window_)
return;
- x11::Atom clipboard_manager_atom = gfx::GetAtom(kClipboardManager);
+ x11::Atom clipboard_manager_atom = x11::GetAtom(kClipboardManager);
if (GetSelectionOwner(clipboard_manager_atom) == x11::Window::None)
return;
@@ -428,47 +427,45 @@ void ClipboardX11::X11Details::StoreCopyPasteDataAndWait() {
base::TimeTicks start = base::TimeTicks::Now();
selection_requestor_.PerformBlockingConvertSelectionWithParameter(
- gfx::GetAtom(kClipboardManager), gfx::GetAtom(kSaveTargets), targets);
+ x11::GetAtom(kClipboardManager), x11::GetAtom(kSaveTargets), targets);
UMA_HISTOGRAM_TIMES("Clipboard.X11StoreCopyPasteDuration",
base::TimeTicks::Now() - start);
}
-bool ClipboardX11::X11Details::DispatchXEvent(x11::Event* xev) {
- if (auto* request = xev->As<x11::SelectionRequestEvent>()) {
+void ClipboardX11::X11Details::OnEvent(const x11::Event& xev) {
+ if (auto* request = xev.As<x11::SelectionRequestEvent>()) {
if (request->owner != x_window_)
- return false;
+ return;
if (request->selection == x11::Atom::PRIMARY) {
- primary_owner_.OnSelectionRequest(*xev);
+ primary_owner_.OnSelectionRequest(*request);
} else {
// We should not get requests for the CLIPBOARD_MANAGER selection
// because we never take ownership of it.
DCHECK_EQ(GetCopyPasteSelection(), request->selection);
- clipboard_owner_.OnSelectionRequest(*xev);
+ clipboard_owner_.OnSelectionRequest(*request);
}
- } else if (auto* notify = xev->As<x11::SelectionNotifyEvent>()) {
- if (notify->requestor != x_window_)
- return false;
- selection_requestor_.OnSelectionNotify(*notify);
- } else if (auto* clear = xev->As<x11::SelectionClearEvent>()) {
+ } else if (auto* notify = xev.As<x11::SelectionNotifyEvent>()) {
+ if (notify->requestor == x_window_)
+ selection_requestor_.OnSelectionNotify(*notify);
+ } else if (auto* clear = xev.As<x11::SelectionClearEvent>()) {
if (clear->owner != x_window_)
- return false;
+ return;
if (clear->selection == x11::Atom::PRIMARY) {
- primary_owner_.OnSelectionClear(*xev);
+ primary_owner_.OnSelectionClear(*clear);
} else {
// We should not get requests for the CLIPBOARD_MANAGER selection
// because we never take ownership of it.
DCHECK_EQ(GetCopyPasteSelection(), clear->selection);
- clipboard_owner_.OnSelectionClear(*xev);
+ clipboard_owner_.OnSelectionClear(*clear);
}
- } else if (auto* prop = xev->As<x11::PropertyNotifyEvent>()) {
- if (primary_owner_.CanDispatchPropertyEvent(*xev))
- primary_owner_.OnPropertyEvent(*xev);
- if (clipboard_owner_.CanDispatchPropertyEvent(*xev))
- clipboard_owner_.OnPropertyEvent(*xev);
- if (selection_requestor_.CanDispatchPropertyEvent(*xev))
- selection_requestor_.OnPropertyEvent(*xev);
+ } else if (auto* prop = xev.As<x11::PropertyNotifyEvent>()) {
+ if (primary_owner_.CanDispatchPropertyEvent(*prop))
+ primary_owner_.OnPropertyEvent(*prop);
+ if (clipboard_owner_.CanDispatchPropertyEvent(*prop))
+ clipboard_owner_.OnPropertyEvent(*prop);
+ if (selection_requestor_.CanDispatchPropertyEvent(*prop))
+ selection_requestor_.OnPropertyEvent(*prop);
}
- return false;
}
///////////////////////////////////////////////////////////////////////////////
@@ -487,6 +484,12 @@ void ClipboardX11::OnPreShutdown() {
x11_details_->StoreCopyPasteDataAndWait();
}
+DataTransferEndpoint* ClipboardX11::GetSource(ClipboardBuffer buffer) const {
+ DCHECK(CalledOnValidThread());
+ auto it = data_src_.find(buffer);
+ return it == data_src_.end() ? nullptr : it->second.get();
+}
+
uint64_t ClipboardX11::GetSequenceNumber(ClipboardBuffer buffer) const {
DCHECK(CalledOnValidThread());
if (buffer == ClipboardBuffer::kCopyPaste)
@@ -516,6 +519,7 @@ void ClipboardX11::Clear(ClipboardBuffer buffer) {
DCHECK(CalledOnValidThread());
DCHECK(IsSupportedClipboardBuffer(buffer));
x11_details_->Clear(buffer);
+ data_src_[buffer].reset();
}
// |data_dst| is not used. It's only passed to be consistent with other
@@ -539,6 +543,10 @@ void ClipboardX11::ReadAvailableTypes(
types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
if (target_list.ContainsFormat(ClipboardFormatType::GetBitmapType()))
types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
+ // Only support filenames if chrome://flags#clipboard-filenames is enabled.
+ if (target_list.ContainsFormat(ClipboardFormatType::GetFilenamesType()) &&
+ base::FeatureList::IsEnabled(features::kClipboardFilenames))
+ types->push_back(base::UTF8ToUTF16(kMimeTypeURIList));
SelectionData data(x11_details_->RequestAndWaitForTypes(
buffer, x11_details_->GetAtomsForFormat(
@@ -697,6 +705,23 @@ void ClipboardX11::ReadCustomData(ClipboardBuffer buffer,
// |data_dst| is not used. It's only passed to be consistent with other
// platforms.
+void ClipboardX11::ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const {
+ DCHECK(CalledOnValidThread());
+ RecordRead(ClipboardFormatMetric::kFilenames);
+
+ SelectionData data(x11_details_->RequestAndWaitForTypes(
+ buffer, x11_details_->GetAtomsForFormat(
+ ClipboardFormatType::GetFilenamesType())));
+ std::string uri_list;
+ if (data.IsValid())
+ data.AssignTo(&uri_list);
+ *result = ui::URIListToFileInfos(uri_list);
+}
+
+// |data_dst| is not used. It's only passed to be consistent with other
+// platforms.
void ClipboardX11::ReadBookmark(const DataTransferEndpoint* data_dst,
base::string16* title,
std::string* url) const {
@@ -752,6 +777,8 @@ void ClipboardX11::WritePortableRepresentations(
x11_details_->TakeOwnershipOfSelection(ClipboardBuffer::kSelection);
}
}
+
+ data_src_[buffer] = std::move(data_src);
}
// |data_src| is not used. It's only passed to be consistent with other
@@ -766,6 +793,7 @@ void ClipboardX11::WritePlatformRepresentations(
x11_details_->CreateNewClipboardData();
DispatchPlatformRepresentations(std::move(platform_representations));
x11_details_->TakeOwnershipOfSelection(buffer);
+ data_src_[buffer] = std::move(data_src);
}
void ClipboardX11::WriteText(const char* text_data, size_t text_len) {
@@ -809,6 +837,14 @@ void ClipboardX11::WriteRTF(const char* rtf_data, size_t data_len) {
WriteData(ClipboardFormatType::GetRtfType(), rtf_data, data_len);
}
+void ClipboardX11::WriteFilenames(std::vector<ui::FileInfo> filenames) {
+ std::string uri_list = ui::FileInfosToURIList(filenames);
+ scoped_refptr<base::RefCountedMemory> mem(
+ base::RefCountedString::TakeString(&uri_list));
+ x11_details_->InsertMapping(ClipboardFormatType::GetFilenamesType().GetName(),
+ mem);
+}
+
void ClipboardX11::WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
diff --git a/chromium/ui/base/clipboard/clipboard_x11.h b/chromium/ui/base/clipboard/clipboard_x11.h
index 803b4408686..05896354132 100644
--- a/chromium/ui/base/clipboard/clipboard_x11.h
+++ b/chromium/ui/base/clipboard/clipboard_x11.h
@@ -24,6 +24,7 @@ class ClipboardX11 : public Clipboard {
// Clipboard overrides:
void OnPreShutdown() override;
+ DataTransferEndpoint* GetSource(ClipboardBuffer buffer) const override;
uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
bool IsFormatAvailable(const ClipboardFormatType& format,
ClipboardBuffer buffer,
@@ -60,6 +61,9 @@ class ClipboardX11 : public Clipboard {
const base::string16& type,
const DataTransferEndpoint* data_dst,
base::string16* result) const override;
+ void ReadFilenames(ClipboardBuffer buffer,
+ const DataTransferEndpoint* data_dst,
+ std::vector<ui::FileInfo>* result) const override;
void ReadBookmark(const DataTransferEndpoint* data_dst,
base::string16* title,
std::string* url) const override;
@@ -84,6 +88,7 @@ class ClipboardX11 : public Clipboard {
size_t url_len) override;
void WriteSvg(const char* markup_data, size_t markup_len) override;
void WriteRTF(const char* rtf_data, size_t data_len) override;
+ void WriteFilenames(std::vector<ui::FileInfo> filenames) override;
void WriteBookmark(const char* title_data,
size_t title_len,
const char* url_data,
@@ -100,6 +105,8 @@ class ClipboardX11 : public Clipboard {
// own class derived from Clipboard?
class X11Details;
std::unique_ptr<X11Details> x11_details_;
+ base::flat_map<ClipboardBuffer, std::unique_ptr<DataTransferEndpoint>>
+ data_src_;
DISALLOW_COPY_AND_ASSIGN(ClipboardX11);
};
diff --git a/chromium/ui/base/clipboard/file_info.cc b/chromium/ui/base/clipboard/file_info.cc
new file mode 100644
index 00000000000..2ee1d3ae1e7
--- /dev/null
+++ b/chromium/ui/base/clipboard/file_info.cc
@@ -0,0 +1,167 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/clipboard/file_info.h"
+
+#include "base/strings/escape.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+
+namespace ui {
+namespace {
+
+constexpr char kFileUrlPrefix[] = "file://";
+constexpr char kFileSchemePrefix[] = "file:";
+constexpr char kURIListSeparator[] = "\r\n";
+
+// Returns true if path starts with a letter, followed by a colon, followed
+// by a path separator.
+bool StartsWithDriveLetter(base::StringPiece path) {
+ return path.length() > 2 && base::IsAsciiAlpha(path[0]) && path[1] == ':' &&
+ base::FilePath::IsSeparator(path[2]);
+}
+
+// We implement our own URLToPath() and PathToURL() rather than use
+// net::FileUrlToFilePath() or net::FilePathToFileURL() since //net code works
+// differently on each platform and is overly strict. In particular, it doesn't
+// allow Windows network paths such as //ChromeOS/MyFiles on OS_CHROMEOS.
+//
+// This code is a little different in nature to most other path handling in that
+// we expect this code to roundtrip both posix and windows paths (local or
+// network) when running on either platform.
+//
+// Convert file:// |url| to a FilePath. Returns empty if |url| is invalid.
+// This function expects an absolute path since it is not possible to encode
+// a relative path as a file:// URL. The third slash in 'file:///' is not
+// mandatory, but without it, the path is considered a network path
+// (file://host/path). If a drive letter followed by colon and slash is detected
+// (file:///C:/path), the path is assumed to be windows path 'C:/path', but
+// without the slash (file:///C:path), the path is assumed to posix '/C:path'
+// rather than windows relative path 'C:path'.
+base::FilePath URLToPath(base::StringPiece url) {
+ // Must start with 'file://' with at least 1 more char.
+ std::string prefix(kFileUrlPrefix);
+ if (url.size() <= prefix.size() ||
+ !base::StartsWith(url, prefix, base::CompareCase::SENSITIVE)) {
+ return base::FilePath();
+ }
+
+ // Skip slashes after 'file:' if needed:
+ size_t path_start;
+ if (url[prefix.size()] == '/') {
+ // file:///path => /path
+ path_start = prefix.size();
+ if (StartsWithDriveLetter(url.substr(path_start + 1))) {
+ // file:///C:/path => C:/path
+ ++path_start;
+ }
+ } else {
+ // file://host/path => //host/path
+ DCHECK_EQ(prefix.size(), 7u);
+ path_start = prefix.size() - 2;
+ }
+
+ std::string result = base::UnescapeBinaryURLComponent(url.substr(path_start));
+#if defined(OS_WIN)
+ return base::FilePath(base::UTF8ToWide(result)).NormalizePathSeparators();
+#else
+ return base::FilePath(result);
+#endif
+}
+
+} // namespace
+
+FileInfo::FileInfo() = default;
+
+FileInfo::FileInfo(const base::FilePath& path,
+ const base::FilePath& display_name)
+ : path(path), display_name(display_name) {}
+
+FileInfo::~FileInfo() = default;
+
+bool FileInfo::operator==(const FileInfo& other) const {
+ return path == other.path && display_name == other.display_name;
+}
+
+std::vector<FileInfo> URIListToFileInfos(const base::StringPiece& uri_list) {
+ std::vector<FileInfo> result;
+ std::vector<base::StringPiece> lines =
+ base::SplitStringPiece(uri_list, kURIListSeparator, base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+ for (const base::StringPiece& line : lines) {
+ base::FilePath path = URLToPath(line);
+ if (!path.empty()) {
+ result.push_back(FileInfo(path, base::FilePath()));
+ }
+ }
+ return result;
+}
+
+std::string FilePathToFileURL(const base::FilePath& file_path) {
+ std::string url;
+#if defined(OS_WIN)
+ std::string path = base::WideToUTF8(file_path.value());
+#else
+ std::string path = file_path.value();
+#endif
+ // Allocate maximum possible size upfront:
+ // 'file:' + '///' + (3 x path.size() for percent encoding).
+ url.reserve((sizeof(kFileSchemePrefix) - 1) + 3 + (3 * path.size()));
+ url += kFileSchemePrefix;
+
+ // Add slashes after 'file:' if needed:
+ if (path.size() > 1 && base::FilePath::IsSeparator(path[0]) &&
+ base::FilePath::IsSeparator(path[1])) {
+ // //host/path => file://host/path
+ } else if (path.size() > 0 && base::FilePath::IsSeparator(path[0])) {
+ // /absolute/path => file:///absolute/path
+ url += "//";
+ } else {
+ // relative/path => file:///relative/path
+ // C:/path => file:///C:/path
+ // A relative path can't be encoded as a file:// URL, so we will produce an
+ // absolute path like GURL() does. We do expect input to be absolute, and
+ // ideally, we would DCHECK(file_path.IsAbsolute()), but it is possible that
+ // we are interpreting a windows path while running on a posix platform.
+ url += "///";
+ }
+
+ for (char c : path) {
+ // Encode special characters `%;#?\`.
+ if (c == '%' || c == ';' || c == '#' || c == '?' ||
+#if !defined(OS_WIN)
+ // Backslash is percent-encoded on posix platforms.
+ c == '\\' ||
+#endif
+ // Encode space and all control chars.
+ c <= ' ') {
+ static const char kHexChars[] = "0123456789ABCDEF";
+ url += '%';
+ url += kHexChars[(c >> 4) & 0xf];
+ url += kHexChars[c & 0xf];
+
+#if defined(OS_WIN)
+ } else if (c == '\\') {
+ // Backslash is converted to slash on windows.
+ url += '/';
+#endif
+ } else {
+ url += c;
+ }
+ }
+
+ return url;
+}
+
+std::string FileInfosToURIList(const std::vector<FileInfo>& filenames) {
+ std::vector<std::string> uri_list;
+ for (const FileInfo& file : filenames) {
+ uri_list.push_back(FilePathToFileURL(file.path));
+ }
+ return base::JoinString(uri_list, kURIListSeparator);
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/clipboard/file_info.h b/chromium/ui/base/clipboard/file_info.h
new file mode 100644
index 00000000000..27bfdb35641
--- /dev/null
+++ b/chromium/ui/base/clipboard/file_info.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CLIPBOARD_FILE_INFO_H_
+#define UI_BASE_CLIPBOARD_FILE_INFO_H_
+
+#include <string>
+
+#include "base/component_export.h"
+#include "base/files/file_path.h"
+#include "base/strings/string_piece_forward.h"
+
+namespace ui {
+
+// struct that bundles a file's path with an optional display name.
+struct COMPONENT_EXPORT(UI_BASE_FILE_INFO) FileInfo {
+ FileInfo();
+ FileInfo(const base::FilePath& path, const base::FilePath& display_name);
+ ~FileInfo();
+ bool operator==(const FileInfo& other) const;
+
+ base::FilePath path;
+ base::FilePath display_name; // Optional.
+};
+
+// Returns UTF8 file:// URL. |file_path| is expected to be an absolute path, and
+// will be encoded as one regardless. E.g. '/path' and 'path' both encode as
+// 'file:///path'.
+std::string COMPONENT_EXPORT(UI_BASE_FILE_INFO)
+ FilePathToFileURL(const base::FilePath& file_path);
+
+// Returns a list of ui::FileInfo from the text/uri-list CRLF-separated file://
+// URLs in |uri_list| as per
+// https://www.iana.org/assignments/media-types/text/uri-list
+// URLs which cannot be parsed are ignored.
+std::vector<FileInfo> COMPONENT_EXPORT(UI_BASE_FILE_INFO)
+ URIListToFileInfos(const base::StringPiece& uri_list);
+
+// Returns UTF8 text/uri-list CRLF-separated file:// URLs from filenames.
+std::string COMPONENT_EXPORT(UI_BASE_FILE_INFO)
+ FileInfosToURIList(const std::vector<FileInfo>& filenames);
+
+} // namespace ui
+
+#endif // UI_BASE_CLIPBOARD_FILE_INFO_H_
diff --git a/chromium/ui/base/clipboard/file_info_fuzzer.cc b/chromium/ui/base/clipboard/file_info_fuzzer.cc
new file mode 100644
index 00000000000..79e5b48241e
--- /dev/null
+++ b/chromium/ui/base/clipboard/file_info_fuzzer.cc
@@ -0,0 +1,17 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_piece.h"
+#include "ui/base/clipboard/file_info.h"
+
+namespace ui {
+
+// Entry point for LibFuzzer.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ base::StringPiece data_piece(reinterpret_cast<const char*>(data), size);
+ std::vector<ui::FileInfo> files = ui::URIListToFileInfos(data_piece);
+ return 0;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/clipboard/file_info_unittest.cc b/chromium/ui/base/clipboard/file_info_unittest.cc
new file mode 100644
index 00000000000..fa17e4a3d8d
--- /dev/null
+++ b/chromium/ui/base/clipboard/file_info_unittest.cc
@@ -0,0 +1,114 @@
+// Copyright 2021 The Chromium 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/file_info.h"
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/strings/string_util.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+namespace ui {
+
+// Tests parsing from text/uri-list to list of FileInfo.
+TEST(FileInfoTest, Roundtrip) {
+ struct TestCase {
+ std::string uri_list;
+ std::vector<base::FilePath::StringType> paths;
+ base::Optional<std::string> uri_list_roundtrip;
+ };
+ const TestCase tests[] = {
+ // Empty text/uri-list should give empty list.
+ {"", {}},
+ // Single path should give a single result.
+ {"file:///path", {FPL("/path")}},
+ // Multiple paths should be parsed.
+ {"file:///path1\r\nfile:///path2", {FPL("/path1"), FPL("/path2")}},
+ // Invalid URLs should be ignored.
+ {"/path", {}},
+ {"notfile:///path", {}},
+ {"file:path", {}},
+ {"file:/path", {}},
+ {"file://", {}},
+ // Network paths should be allowed.
+ {"file://host", {FPL("//host")}},
+ {"file://host/path", {FPL("//host/path")}},
+ // Root filesystem '/'.
+ {"file:///", {FPL("/")}},
+ // Windows paths.
+ {"file:///C:/path", {FPL("C:/path")}},
+ {"file:///C:/", {FPL("C:/")}},
+ // Not quite windows paths.
+ {"file:///C:", {FPL("/C:")}},
+ {"file:///CD:/path", {FPL("/CD:/path")}},
+ {"file:///C:path", {FPL("/C:path")}},
+ {"file:///:/path", {FPL("/:/path")}},
+ // Encoded chars.
+ {"file:///colon:", {FPL("/colon:")}},
+ {"file:///colon%3A", {FPL("/colon:")}, "file:///colon:"},
+ {"file:///truncated%", {FPL("/truncated%")}, "file:///truncated%25"},
+ {"file:///truncated%1", {FPL("/truncated%1")}, "file:///truncated%251"},
+ {"file:///percent%25", {FPL("/percent%")}},
+ {"file:///percent%2525", {FPL("/percent%25")}},
+ {"file:///space ", {FPL("/space")}, "file:///space"},
+ {"file:///space%20", {FPL("/space ")}},
+ {"file:///path%2525:%3B%23&=%0A%20", {FPL("/path%25:;#&=\n ")}},
+ };
+ for (const TestCase& test : tests) {
+ std::vector<base::FilePath::StringType> expected;
+ for (const auto& path : test.paths) {
+ expected.push_back(
+ base::FilePath(path).NormalizePathSeparators().value());
+ }
+ std::vector<FileInfo> file_infos = URIListToFileInfos(test.uri_list);
+ std::vector<base::FilePath::StringType> actual;
+ for (const FileInfo& file_info : file_infos) {
+ actual.push_back(file_info.path.value());
+ }
+ EXPECT_EQ(expected, actual);
+ if (!file_infos.empty()) {
+ std::string uri_list = FileInfosToURIList(file_infos);
+ EXPECT_EQ(test.uri_list_roundtrip.value_or(test.uri_list), uri_list);
+ }
+ }
+}
+
+TEST(FileInfoTest, Backslashes) {
+ struct TestCase {
+ base::FilePath::StringType path;
+ std::string uri_list;
+ base::Optional<base::FilePath::StringType> path_roundtrip;
+ };
+ const TestCase tests[] = {
+#if defined(OS_WIN)
+ // File paths with backslash should roundtrip on windows.
+ {FPL("C:\\path"), "file:///C:/path"},
+ {FPL("\\path"), "file:///path"},
+ {FPL("\\\\host\\path"), "file://host/path"},
+#else
+ // File paths with backslash should be escaped on posix, and relative path
+ // becomes absolute path.
+ {FPL("C:\\path"), "file:///C:%5Cpath", FPL("/C:\\path")},
+ {FPL("\\path"), "file:///%5Cpath", FPL("/\\path")},
+ {FPL("\\\\host\\path"), "file:///%5C%5Chost%5Cpath",
+ FPL("/\\\\host\\path")},
+#endif
+ };
+ for (const TestCase& test : tests) {
+ FileInfo file_info(base::FilePath(test.path), base::FilePath());
+ std::string uri_list = FileInfosToURIList({file_info});
+ EXPECT_EQ(test.uri_list, uri_list);
+
+ std::vector<FileInfo> filenames = URIListToFileInfos(uri_list);
+ EXPECT_EQ(1u, filenames.size());
+ EXPECT_EQ(test.path_roundtrip.value_or(test.path),
+ filenames[0].path.value());
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/clipboard/scoped_clipboard_writer.cc b/chromium/ui/base/clipboard/scoped_clipboard_writer.cc
index d49f3ff31a4..852462421f8 100644
--- a/chromium/ui/base/clipboard/scoped_clipboard_writer.cc
+++ b/chromium/ui/base/clipboard/scoped_clipboard_writer.cc
@@ -85,6 +85,14 @@ void ScopedClipboardWriter::WriteRTF(const std::string& rtf_data) {
objects_[Clipboard::PortableFormat::kRtf] = parameters;
}
+void ScopedClipboardWriter::WriteFilenames(const std::string& uri_list) {
+ RecordWrite(ClipboardFormatMetric::kFilenames);
+ Clipboard::ObjectMapParams parameters;
+ parameters.push_back(
+ Clipboard::ObjectMapParam(uri_list.begin(), uri_list.end()));
+ objects_[Clipboard::PortableFormat::kFilenames] = parameters;
+}
+
void ScopedClipboardWriter::WriteBookmark(const base::string16& bookmark_title,
const std::string& url) {
if (bookmark_title.empty() || url.empty())
diff --git a/chromium/ui/base/clipboard/scoped_clipboard_writer.h b/chromium/ui/base/clipboard/scoped_clipboard_writer.h
index 1dd0bae74fe..5e6ccf7afd0 100644
--- a/chromium/ui/base/clipboard/scoped_clipboard_writer.h
+++ b/chromium/ui/base/clipboard/scoped_clipboard_writer.h
@@ -53,6 +53,12 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ScopedClipboardWriter {
// Adds RTF to the clipboard.
void WriteRTF(const std::string& rtf_data);
+ // Adds text/uri-list filenames to the clipboard.
+ // Security Note: This function is expected to be called only by exo in
+ // Chrome OS. It should not be called by renderers or any other untrusted
+ // party since any paths written to the clipboard can be read by renderers.
+ void WriteFilenames(const std::string& uri_list);
+
// Adds a bookmark to the clipboard.
void WriteBookmark(const base::string16& bookmark_title,
const std::string& url);
diff --git a/chromium/ui/base/cocoa/menu_controller_unittest.mm b/chromium/ui/base/cocoa/menu_controller_unittest.mm
index 4d317fc2767..549e3abc18a 100644
--- a/chromium/ui/base/cocoa/menu_controller_unittest.mm
+++ b/chromium/ui/base/cocoa/menu_controller_unittest.mm
@@ -517,8 +517,9 @@ TEST_F(MenuControllerTest, Validate) {
TEST_F(MenuControllerTest, LabelFontList) {
Delegate delegate;
const gfx::FontList& bold =
- ResourceBundle::GetSharedInstance().GetFontListWithDelta(
- 0, gfx::Font::NORMAL, gfx::Font::Weight::BOLD);
+ ResourceBundle::GetSharedInstance().GetFontListForDetails(
+ ui::ResourceBundle::FontDetails(std::string(), 0,
+ gfx::Font::Weight::BOLD));
FontListMenuModel model(&delegate, &bold, 0);
model.AddItem(1, ASCIIToUTF16("one"));
model.AddItem(2, ASCIIToUTF16("two"));
diff --git a/chromium/ui/base/cocoa/nsmenuitem_additions.h b/chromium/ui/base/cocoa/nsmenuitem_additions.h
new file mode 100644
index 00000000000..6ac3570a891
--- /dev/null
+++ b/chromium/ui/base/cocoa/nsmenuitem_additions.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2009 The Chromium 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_NSMENUITEM_ADDITIONS_H_
+#define UI_BASE_COCOA_NSMENUITEM_ADDITIONS_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/component_export.h"
+
+@interface NSMenuItem (ChromeAdditions)
+
+// Returns true exactly if the menu item would fire if it would be put into
+// a menu and then |menu performKeyEquivalent:event| was called.
+// This method always returns NO if the menu item is not enabled.
+- (BOOL)cr_firesForKeyEvent:(NSEvent*)event;
+
+@end
+
+namespace ui {
+namespace cocoa {
+
+// Used by tests to set internal state without having to change global input
+// source.
+void COMPONENT_EXPORT(UI_BASE)
+ SetIsInputSourceCommandQwertyForTesting(bool is_command_qwerty);
+
+// Returns whether the named keyboard layout has the command-qwerty behavior,
+// meaning that the layout acts as though it was QWERTY when the command key is
+// held.
+bool COMPONENT_EXPORT(UI_BASE)
+ IsKeyboardLayoutCommandQwerty(NSString* layout_id);
+
+} // namespace cocoa
+} // namespace ui
+
+#endif // UI_BASE_COCOA_NSMENUITEM_ADDITIONS_H_
diff --git a/chromium/ui/base/cocoa/nsmenuitem_additions.mm b/chromium/ui/base/cocoa/nsmenuitem_additions.mm
new file mode 100644
index 00000000000..acd5f6c58ef
--- /dev/null
+++ b/chromium/ui/base/cocoa/nsmenuitem_additions.mm
@@ -0,0 +1,197 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ui/base/cocoa/nsmenuitem_additions.h"
+
+#include <Carbon/Carbon.h>
+
+#include "base/check.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "ui/events/keycodes/keyboard_code_conversion_mac.h"
+
+namespace ui {
+namespace cocoa {
+
+namespace {
+bool g_is_input_source_command_qwerty = false;
+} // namespace
+
+void SetIsInputSourceCommandQwertyForTesting(bool is_command_qwerty) {
+ g_is_input_source_command_qwerty = is_command_qwerty;
+}
+
+bool IsKeyboardLayoutCommandQwerty(NSString* layout_id) {
+ return [layout_id isEqualToString:@"com.apple.keylayout.DVORAK-QWERTYCMD"] ||
+ [layout_id isEqualToString:@"com.apple.keylayout.Dhivehi-QWERTY"];
+}
+
+} // namespace cocoa
+} // namespace ui
+
+@interface KeyboardInputSourceListener : NSObject
+@end
+
+@implementation KeyboardInputSourceListener
+
+- (instancetype)init {
+ if (self = [super init]) {
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(inputSourceDidChange:)
+ name:NSTextInputContextKeyboardSelectionDidChangeNotification
+ object:nil];
+ [self updateInputSource];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)updateInputSource {
+ base::ScopedCFTypeRef<TISInputSourceRef> inputSource(
+ TISCopyCurrentKeyboardInputSource());
+ NSString* layoutId = (NSString*)TISGetInputSourceProperty(
+ inputSource.get(), kTISPropertyInputSourceID);
+ ui::cocoa::g_is_input_source_command_qwerty =
+ ui::cocoa::IsKeyboardLayoutCommandQwerty(layoutId);
+}
+
+- (void)inputSourceDidChange:(NSNotification*)notification {
+ [self updateInputSource];
+}
+
+@end
+
+@implementation NSMenuItem (ChromeAdditions)
+
+- (BOOL)cr_firesForKeyEvent:(NSEvent*)event {
+ if (![self isEnabled])
+ return NO;
+
+ DCHECK([event type] == NSKeyDown);
+ // In System Preferences->Keyboard->Keyboard Shortcuts, it is possible to add
+ // arbitrary keyboard shortcuts to applications. It is not documented how this
+ // works in detail, but |NSMenuItem| has a method |userKeyEquivalent| that
+ // sounds related.
+ // However, it looks like |userKeyEquivalent| is equal to |keyEquivalent| when
+ // a user shortcut is set in system preferences, i.e. Cocoa automatically
+ // sets/overwrites |keyEquivalent| as well. Hence, this method can ignore
+ // |userKeyEquivalent| and check |keyEquivalent| only.
+
+ // Menu item key equivalents are nearly all stored without modifiers. The
+ // exception is shift, which is included in the key and not in the modifiers
+ // for printable characters (but not for stuff like arrow keys etc).
+ NSString* eventString = [event charactersIgnoringModifiers];
+ NSUInteger eventModifiers =
+ [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
+
+ // cmd-opt-a gives some weird char as characters and "a" as
+ // charactersWithoutModifiers with an US layout, but an "a" as characters and
+ // a weird char as "charactersWithoutModifiers" with a cyrillic layout. Oh,
+ // Cocoa! Instead of getting the current layout from Text Input Services,
+ // and then requesting the kTISPropertyUnicodeKeyLayoutData and looking in
+ // there, let's try a pragmatic hack.
+ if ([eventString length] == 0 ||
+ ([eventString characterAtIndex:0] > 0x7f &&
+ [[event characters] length] > 0 &&
+ [[event characters] characterAtIndex:0] <= 0x7f)) {
+ eventString = [event characters];
+
+ // Process the shift if necessary.
+ if (eventModifiers & NSShiftKeyMask)
+ eventString = [eventString uppercaseString];
+ }
+
+ if ([eventString length] == 0 || [[self keyEquivalent] length] == 0)
+ return NO;
+
+ // Turns out esc never fires unless cmd or ctrl is down.
+ if ([event keyCode] == kVK_Escape &&
+ (eventModifiers & (NSControlKeyMask | NSCommandKeyMask)) == 0)
+ return NO;
+
+ // From the |NSMenuItem setKeyEquivalent:| documentation:
+ //
+ // If you want to specify the Backspace key as the key equivalent for a menu
+ // item, use a single character string with NSBackspaceCharacter (defined in
+ // NSText.h as 0x08) and for the Forward Delete key, use NSDeleteCharacter
+ // (defined in NSText.h as 0x7F). Note that these are not the same characters
+ // you get from an NSEvent key-down event when pressing those keys.
+ if ([[self keyEquivalent] characterAtIndex:0] == NSBackspaceCharacter &&
+ [eventString characterAtIndex:0] == NSDeleteCharacter) {
+ unichar chr = NSBackspaceCharacter;
+ eventString = [NSString stringWithCharacters:&chr length:1];
+
+ // Make sure "shift" is not removed from modifiers below.
+ eventModifiers |= NSFunctionKeyMask;
+ }
+ if ([[self keyEquivalent] characterAtIndex:0] == NSDeleteCharacter &&
+ [eventString characterAtIndex:0] == NSDeleteFunctionKey) {
+ unichar chr = NSDeleteCharacter;
+ eventString = [NSString stringWithCharacters:&chr length:1];
+
+ // Make sure "shift" is not removed from modifiers below.
+ eventModifiers |= NSFunctionKeyMask;
+ }
+
+ // We intentionally leak this object.
+ static __attribute__((unused)) KeyboardInputSourceListener* listener =
+ [[KeyboardInputSourceListener alloc] init];
+
+ // We typically want to compare [NSMenuItem keyEquivalent] against [NSEvent
+ // charactersIgnoringModifiers]. There are special command-qwerty layouts
+ // (such as DVORAK-QWERTY) which use QWERTY-style shortcuts when the Command
+ // key is held down. In this case, we want to use the keycode of the event
+ // rather than looking at the characters.
+ if (ui::cocoa::g_is_input_source_command_qwerty) {
+ ui::KeyboardCode windows_keycode =
+ ui::KeyboardCodeFromKeyCode(event.keyCode);
+ unichar shifted_character, character;
+ ui::MacKeyCodeForWindowsKeyCode(windows_keycode, event.modifierFlags,
+ &shifted_character, &character);
+ eventString = [NSString stringWithFormat:@"%C", shifted_character];
+ }
+
+ // On all keyboards, treat cmd + <number key> as the equivalent numerical key.
+ // This is technically incorrect, since the actual character produced may not
+ // be a number key, but this causes Chrome to match platform behavior. For
+ // example, on the Czech keyboard, we want to interpret cmd + '+' as cmd +
+ // '1', even though the '1' character normally requires cmd + shift + '+'.
+ if (eventModifiers == NSCommandKeyMask) {
+ ui::KeyboardCode windows_keycode =
+ ui::KeyboardCodeFromKeyCode(event.keyCode);
+ if (windows_keycode >= ui::VKEY_0 && windows_keycode <= ui::VKEY_9) {
+ eventString =
+ [NSString stringWithFormat:@"%d", windows_keycode - ui::VKEY_0];
+ }
+ }
+
+ // [ctr + shift + tab] generates the "End of Medium" keyEquivalent rather than
+ // "Horizontal Tab". We still use "Horizontal Tab" in the main menu to match
+ // the behavior of Safari and Terminal. Thus, we need to explicitly check for
+ // this case.
+ if ((eventModifiers & NSShiftKeyMask) &&
+ [eventString isEqualToString:@"\x19"]) {
+ eventString = @"\x9";
+ } else {
+ // Clear shift key for printable characters, excluding tab.
+ if ((eventModifiers & (NSNumericPadKeyMask | NSFunctionKeyMask)) == 0 &&
+ [[self keyEquivalent] characterAtIndex:0] != '\r' &&
+ [[self keyEquivalent] characterAtIndex:0] != '\x9') {
+ eventModifiers &= ~NSShiftKeyMask;
+ }
+ }
+
+ // Clear all non-interesting modifiers
+ eventModifiers &=
+ NSCommandKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSShiftKeyMask;
+
+ return [eventString isEqualToString:[self keyEquivalent]] &&
+ eventModifiers == [self keyEquivalentModifierMask];
+}
+
+@end
diff --git a/chromium/ui/base/cocoa/nsmenuitem_additions_unittest.mm b/chromium/ui/base/cocoa/nsmenuitem_additions_unittest.mm
new file mode 100644
index 00000000000..d17a47623d5
--- /dev/null
+++ b/chromium/ui/base/cocoa/nsmenuitem_additions_unittest.mm
@@ -0,0 +1,471 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ui/base/cocoa/nsmenuitem_additions.h"
+
+#include <Carbon/Carbon.h>
+
+#include <ostream>
+
+#include "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/keycodes/keyboard_code_conversion_mac.h"
+
+std::ostream& operator<<(std::ostream& out, NSObject* obj) {
+ return out << base::SysNSStringToUTF8([obj description]);
+}
+
+std::ostream& operator<<(std::ostream& out, NSMenuItem* item) {
+ return out << "NSMenuItem " << base::SysNSStringToUTF8([item keyEquivalent]);
+}
+
+namespace ui {
+namespace cocoa {
+namespace {
+
+NSEvent* KeyEvent(const NSUInteger modifierFlags,
+ NSString* chars,
+ NSString* charsNoMods,
+ const NSUInteger keyCode) {
+ return [NSEvent keyEventWithType:NSKeyDown
+ location:NSZeroPoint
+ modifierFlags:modifierFlags
+ timestamp:0.0
+ windowNumber:0
+ context:nil
+ characters:chars
+ charactersIgnoringModifiers:charsNoMods
+ isARepeat:NO
+ keyCode:keyCode];
+}
+
+NSMenuItem* MenuItem(NSString* equiv, NSUInteger mask) {
+ NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:@""
+ action:NULL
+ keyEquivalent:@""] autorelease];
+ [item setKeyEquivalent:equiv];
+ [item setKeyEquivalentModifierMask:mask];
+ return item;
+}
+
+// Returns whether a keyboard layout is one of the "commandless" cyrillic
+// layouts introduced in 10.15: these layouts do not ever fire key equivalents
+// (in any app, not just Chrome) and appear not to be intended for full-time
+// use.
+bool IsCommandlessCyrillicLayout(NSString* layoutId) {
+ return [layoutId isEqualToString:@"com.apple.keylayout.Kyrgyz-Cyrillic"] ||
+ [layoutId isEqualToString:@"com.apple.keylayout.Mongolian-Cyrillic"];
+}
+
+void ExpectKeyFiresItemEq(bool result,
+ NSEvent* key,
+ NSMenuItem* item,
+ bool compareCocoa) {
+ EXPECT_EQ(result, [item cr_firesForKeyEvent:key]) << key << '\n' << item;
+
+ // Make sure that Cocoa does in fact agree with our expectations. However,
+ // in some cases cocoa behaves weirdly (if you create e.g. a new event that
+ // contains all fields of the event that you get when hitting cmd-a with a
+ // russion keyboard layout, the copy won't fire a menu item that has cmd-a as
+ // key equivalent, even though the original event would) and isn't a good
+ // oracle function.
+ if (compareCocoa) {
+ base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu!"]);
+ [menu setAutoenablesItems:NO];
+ EXPECT_FALSE([menu performKeyEquivalent:key]);
+ [menu addItem:item];
+ EXPECT_EQ(result, [menu performKeyEquivalent:key]) << key << '\n' << item;
+ }
+}
+
+void ExpectKeyFiresItem(NSEvent* key,
+ NSMenuItem* item,
+ bool compareCocoa = true) {
+ ExpectKeyFiresItemEq(true, key, item, compareCocoa);
+}
+
+void ExpectKeyDoesntFireItem(NSEvent* key,
+ NSMenuItem* item,
+ bool compareCocoa = true) {
+ ExpectKeyFiresItemEq(false, key, item, compareCocoa);
+}
+
+TEST(NSMenuItemAdditionsTest, TestFiresForKeyEvent) {
+ // These test cases were built by writing a small test app that has a
+ // MainMenu.xib with a given key equivalent set in Interface Builder and a
+ // some code that prints both the key equivalent that fires a menu item and
+ // the menu item's key equivalent and modifier masks. I then pasted those
+ // below. This was done with a US layout, unless otherwise noted. In the
+ // comments, "z" always means the physical "z" key on a US layout no matter
+ // what character that key produces.
+
+ NSMenuItem* item;
+ NSEvent* key;
+ unichar ch;
+ NSString* s;
+
+ // Sanity
+ item = MenuItem(@"", 0);
+ EXPECT_TRUE([item isEnabled]);
+
+ // a
+ key = KeyEvent(0x100, @"a", @"a", 0);
+ item = MenuItem(@"a", 0);
+ ExpectKeyFiresItem(key, item);
+ ExpectKeyDoesntFireItem(KeyEvent(0x20102, @"A", @"A", 0), item);
+
+ // Disabled menu item
+ key = KeyEvent(0x100, @"a", @"a", 0);
+ item = MenuItem(@"a", 0);
+ [item setEnabled:NO];
+ ExpectKeyDoesntFireItem(key, item, false);
+
+ // shift-a
+ key = KeyEvent(0x20102, @"A", @"A", 0);
+ item = MenuItem(@"A", 0);
+ ExpectKeyFiresItem(key, item);
+ ExpectKeyDoesntFireItem(KeyEvent(0x100, @"a", @"a", 0), item);
+
+ // cmd-shift-t
+ key = KeyEvent(0x12010a, @"t", @"T", 0);
+ item = MenuItem(@"T", 0x100000);
+ ExpectKeyFiresItem(key, item);
+ item = MenuItem(@"t", 0x100000);
+ ExpectKeyDoesntFireItem(key, item);
+
+ // cmd-opt-shift-a
+ key = KeyEvent(0x1a012a, @"\u00c5", @"A", 0);
+ item = MenuItem(@"A", 0x180000);
+ ExpectKeyFiresItem(key, item);
+
+ // cmd-opt-a
+ key = KeyEvent(0x18012a, @"\u00e5", @"a", 0);
+ item = MenuItem(@"a", 0x180000);
+ ExpectKeyFiresItem(key, item);
+
+ // cmd-=
+ key = KeyEvent(0x100110, @"=", @"=", 0x18);
+ item = MenuItem(@"=", 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // cmd-shift-=
+ key = KeyEvent(0x12010a, @"=", @"+", 0x18);
+ item = MenuItem(@"+", 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // Turns out Cocoa fires "+ 100108 + 18" if you hit cmd-= and the menu only
+ // has a cmd-+ shortcut. But that's transparent for |cr_firesForKeyEvent:|.
+
+ // ctrl-3
+ key = KeyEvent(0x40101, @"3", @"3", 0x14);
+ item = MenuItem(@"3", 0x40000);
+ ExpectKeyFiresItem(key, item);
+
+ // return
+ key = KeyEvent(0, @"\r", @"\r", 0x24);
+ item = MenuItem(@"\r", 0);
+ ExpectKeyFiresItem(key, item);
+
+ // shift-return
+ key = KeyEvent(0x20102, @"\r", @"\r", 0x24);
+ item = MenuItem(@"\r", 0x20000);
+ ExpectKeyFiresItem(key, item);
+
+ // shift-left
+ ch = NSLeftArrowFunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0xa20102, s, s, 0x7b);
+ item = MenuItem(s, 0x20000);
+ ExpectKeyFiresItem(key, item);
+
+ // shift-f1 (with a layout that needs the fn key down for f1)
+ ch = NSF1FunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0x820102, s, s, 0x7a);
+ item = MenuItem(s, 0x20000);
+ ExpectKeyFiresItem(key, item);
+
+ // esc
+ // Turns out this doesn't fire.
+ key = KeyEvent(0x100, @"\e", @"\e", 0x35);
+ item = MenuItem(@"\e", 0);
+ ExpectKeyDoesntFireItem(key, item, false);
+
+ // shift-esc
+ // Turns out this doesn't fire.
+ key = KeyEvent(0x20102, @"\e", @"\e", 0x35);
+ item = MenuItem(@"\e", 0x20000);
+ ExpectKeyDoesntFireItem(key, item, false);
+
+ // cmd-esc
+ key = KeyEvent(0x100108, @"\e", @"\e", 0x35);
+ item = MenuItem(@"\e", 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // ctrl-esc
+ key = KeyEvent(0x40101, @"\e", @"\e", 0x35);
+ item = MenuItem(@"\e", 0x40000);
+ ExpectKeyFiresItem(key, item);
+
+ // delete ("backspace")
+ key = KeyEvent(0x100, @"\x7f", @"\x7f", 0x33);
+ item = MenuItem(@"\x08", 0);
+ ExpectKeyFiresItem(key, item, false);
+
+ // shift-delete
+ key = KeyEvent(0x20102, @"\x7f", @"\x7f", 0x33);
+ item = MenuItem(@"\x08", 0x20000);
+ ExpectKeyFiresItem(key, item, false);
+
+ // forwarddelete (fn-delete / fn-backspace)
+ ch = NSDeleteFunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0x800100, s, s, 0x75);
+ item = MenuItem(@"\x7f", 0);
+ ExpectKeyFiresItem(key, item, false);
+
+ // shift-forwarddelete (shift-fn-delete / shift-fn-backspace)
+ ch = NSDeleteFunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0x820102, s, s, 0x75);
+ item = MenuItem(@"\x7f", 0x20000);
+ ExpectKeyFiresItem(key, item, false);
+
+ // fn-left
+ ch = NSHomeFunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0x800100, s, s, 0x73);
+ item = MenuItem(s, 0);
+ ExpectKeyFiresItem(key, item);
+
+ // cmd-left
+ ch = NSLeftArrowFunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0xb00108, s, s, 0x7b);
+ item = MenuItem(s, 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // Hitting the "a" key with a russian keyboard layout -- does not fire
+ // a menu item that has "a" as key equiv.
+ key = KeyEvent(0x100, @"\u0444", @"\u0444", 0);
+ item = MenuItem(@"a", 0);
+ ExpectKeyDoesntFireItem(key, item);
+
+ // cmd-a on a russion layout -- fires for a menu item with cmd-a as key equiv.
+ key = KeyEvent(0x100108, @"a", @"\u0444", 0);
+ item = MenuItem(@"a", 0x100000);
+ ExpectKeyFiresItem(key, item, false);
+
+ // cmd-z on US layout
+ key = KeyEvent(0x100108, @"z", @"z", 6);
+ item = MenuItem(@"z", 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // cmd-y on german layout (has same keycode as cmd-z on us layout, shouldn't
+ // fire).
+ key = KeyEvent(0x100108, @"y", @"y", 6);
+ item = MenuItem(@"z", 0x100000);
+ ExpectKeyDoesntFireItem(key, item);
+
+ // cmd-z on german layout
+ key = KeyEvent(0x100108, @"z", @"z", 0x10);
+ item = MenuItem(@"z", 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // fn-return (== enter)
+ key = KeyEvent(0x800100, @"\x3", @"\x3", 0x4c);
+ item = MenuItem(@"\r", 0);
+ ExpectKeyDoesntFireItem(key, item);
+
+ // cmd-z on dvorak layout (so that the key produces ';')
+ key = KeyEvent(0x100108, @";", @";", 6);
+ ExpectKeyDoesntFireItem(key, MenuItem(@"z", 0x100000));
+ ExpectKeyFiresItem(key, MenuItem(@";", 0x100000));
+
+ // Change to Command-QWERTY
+ SetIsInputSourceCommandQwertyForTesting(true);
+
+ // cmd-z on dvorak qwerty layout (so that the key produces ';', but 'z' if
+ // cmd is down)
+ key = KeyEvent(0x100108, @"z", @";", 6);
+ ExpectKeyFiresItem(key, MenuItem(@"z", 0x100000), false);
+ ExpectKeyDoesntFireItem(key, MenuItem(@";", 0x100000), false);
+
+ // On dvorak-qwerty, pressing the keys for 'cmd' and '=' triggers an event
+ // whose characters are cmd-'+'.
+ // cmd-'+' on dvorak qwerty should not trigger a menu item for cmd-']', and
+ // not a menu item for cmd-'+'.
+ key = KeyEvent(0x100108, @"+", @"+", 30);
+ ExpectKeyFiresItem(key, MenuItem(@"]", 0x100000), false);
+ ExpectKeyDoesntFireItem(key, MenuItem(@"+", 0x100000), false);
+
+ // cmd-shift-'+' on dvorak qwerty should trigger a menu item for cmd-shift-'}'
+ // and not a menu item for cmd-shift-'+'.
+ key = KeyEvent(0x12010a, @"}", @"+", 30);
+ ExpectKeyFiresItem(key, MenuItem(@"}", 0x100000), false);
+ ExpectKeyDoesntFireItem(key, MenuItem(@"+", 0x100000), false);
+
+ // ctr-shift-tab should trigger correctly.
+ key = KeyEvent(0x60103, @"\x19", @"\x19", 48);
+ ExpectKeyFiresItem(key, MenuItem(@"\x9", NSShiftKeyMask | NSControlKeyMask),
+ false);
+ ExpectKeyDoesntFireItem(key, MenuItem(@"\x9", NSControlKeyMask), false);
+
+ // Change away from Command-QWERTY
+ SetIsInputSourceCommandQwertyForTesting(false);
+
+ // cmd-shift-z on dvorak layout (so that we get a ':')
+ key = KeyEvent(0x12010a, @";", @":", 6);
+ ExpectKeyFiresItem(key, MenuItem(@":", 0x100000));
+ ExpectKeyDoesntFireItem(key, MenuItem(@";", 0x100000));
+
+ // On PT layout, caps lock should not affect the keyEquivalent.
+ key = KeyEvent(0x110108, @"T", @"t", 17);
+ ExpectKeyFiresItem(key, MenuItem(@"t", 0x100000));
+ ExpectKeyDoesntFireItem(key, MenuItem(@"T", 0x100000));
+
+ // cmd-s with a serbian layout (just "s" produces something that looks a lot
+ // like "c" in some fonts, but is actually \u0441. cmd-s activates a menu item
+ // with key equivalent "s", not "c")
+ key = KeyEvent(0x100108, @"s", @"\u0441", 1);
+ ExpectKeyFiresItem(key, MenuItem(@"s", 0x100000), false);
+ ExpectKeyDoesntFireItem(key, MenuItem(@"c", 0x100000));
+
+ // ctr + shift + tab produces the "End of Medium" keyEquivalent, even though
+ // it should produce the "Horizontal Tab" keyEquivalent. Check to make sure
+ // it matches anyways.
+ key = KeyEvent(0x60103, @"\x19", @"\x19", 1);
+ ExpectKeyFiresItem(key, MenuItem(@"\x9", NSShiftKeyMask | NSControlKeyMask),
+ false);
+
+ // In 2-set Korean layout, (cmd + shift + t) and (cmd + t) both produce
+ // multi-byte unmodified chars. For keyEquivalent purposes, we use their
+ // raw characters, where "shift" should be handled correctly.
+ key = KeyEvent(0x100108, @"t", @"\u3145", 17);
+ ExpectKeyFiresItem(key, MenuItem(@"t", NSCommandKeyMask),
+ /*compareCocoa=*/false);
+ ExpectKeyDoesntFireItem(key, MenuItem(@"T", NSCommandKeyMask),
+ /*compareCocoa=*/false);
+
+ key = KeyEvent(0x12010a, @"t", @"\u3146", 17);
+ ExpectKeyDoesntFireItem(key, MenuItem(@"t", NSCommandKeyMask),
+ /*compareCocoa=*/false);
+ ExpectKeyFiresItem(key, MenuItem(@"T", NSCommandKeyMask),
+ /*compareCocoa=*/false);
+
+ // On Czech layout, cmd + '+' should instead trigger cmd + '1'.
+ key = KeyEvent(0x100108, @"1", @"+", 18);
+ ExpectKeyFiresItem(key, MenuItem(@"1", NSCommandKeyMask),
+ /*compareCocoa=*/false);
+
+ // On Vietnamese layout, cmd + '' [vkeycode = 18] should instead trigger cmd +
+ // '1'. Ditto for other number keys.
+ key = KeyEvent(0x100108, @"1", @"", 18);
+ ExpectKeyFiresItem(key, MenuItem(@"1", NSCommandKeyMask),
+ /*compareCocoa=*/false);
+ key = KeyEvent(0x100108, @"4", @"", 21);
+ ExpectKeyFiresItem(key, MenuItem(@"4", NSCommandKeyMask),
+ /*compareCocoa=*/false);
+
+ // On French AZERTY layout, cmd + '&' [vkeycode = 18] should instead trigger
+ // cmd + '1'. Ditto for other number keys.
+ key = KeyEvent(0x100108, @"&", @"&", 18);
+ ExpectKeyFiresItem(key, MenuItem(@"1", NSCommandKeyMask),
+ /*compareCocoa=*/false);
+ key = KeyEvent(0x100108, @"é", @"é", 19);
+ ExpectKeyFiresItem(key, MenuItem(@"2", NSCommandKeyMask),
+ /*compareCocoa=*/false);
+}
+
+NSString* keyCodeToCharacter(NSUInteger keyCode,
+ EventModifiers modifiers,
+ TISInputSourceRef layout) {
+ UInt32 deadKeyStateUnused = 0;
+ UniChar unicodeChar = ui::TranslatedUnicodeCharFromKeyCode(
+ layout, (UInt16)keyCode, kUCKeyActionDown, modifiers, LMGetKbdType(),
+ &deadKeyStateUnused);
+
+ CFStringRef temp =
+ CFStringCreateWithCharacters(kCFAllocatorDefault, &unicodeChar, 1);
+ return [(NSString*)temp autorelease];
+}
+
+TEST(NSMenuItemAdditionsTest, TestMOnDifferentLayouts) {
+ // There's one key -- "m" -- that has the same keycode on most keyboard
+ // layouts. This function tests a menu item with cmd-m as key equivalent
+ // can be fired on all layouts.
+ NSMenuItem* item = MenuItem(@"m", 0x100000);
+
+ NSDictionary* filter = [NSDictionary
+ dictionaryWithObject:(NSString*)kTISTypeKeyboardLayout
+ forKey:(NSString*)kTISPropertyInputSourceType];
+
+ // Docs say that including all layouts instead of just the active ones is
+ // slow, but there's no way around that.
+ NSArray* list =
+ (NSArray*)TISCreateInputSourceList((CFDictionaryRef)filter, true);
+ for (id layout in list) {
+ TISInputSourceRef ref = (TISInputSourceRef)layout;
+
+ NSUInteger keyCode = 0x2e; // "m" on a US layout and most other layouts.
+
+ // On a few layouts, "m" has a different key code.
+ NSString* layoutId =
+ (NSString*)TISGetInputSourceProperty(ref, kTISPropertyInputSourceID);
+ if ([layoutId isEqualToString:@"com.apple.keylayout.Belgian"] ||
+ [layoutId isEqualToString:@"com.apple.keylayout.Italian"] ||
+ [layoutId isEqualToString:@"com.apple.keylayout.ABC-AZERTY"] ||
+ [layoutId hasPrefix:@"com.apple.keylayout.French"]) {
+ keyCode = 0x29;
+ } else if ([layoutId isEqualToString:@"com.apple.keylayout.Turkish"] ||
+ [layoutId
+ isEqualToString:@"com.apple.keylayout.Turkish-Standard"]) {
+ keyCode = 0x28;
+ } else if ([layoutId isEqualToString:@"com.apple.keylayout.Dvorak-Left"]) {
+ keyCode = 0x16;
+ } else if ([layoutId isEqualToString:@"com.apple.keylayout.Dvorak-Right"]) {
+ keyCode = 0x1a;
+ } else if ([layoutId
+ isEqualToString:@"com.apple.keylayout.Tibetan-Wylie"]) {
+ // In Tibetan-Wylie, the only way to type the "m" character is with cmd +
+ // key_code=0x2e. As such, it doesn't make sense for this same combination
+ // to trigger a keyEquivalent, since then it won't be possible to type
+ // "m".
+ continue;
+ } else if (IsCommandlessCyrillicLayout(layoutId)) {
+ // Commandless layouts have no way to trigger a menu key equivalent at
+ // all, in any app.
+ continue;
+ }
+
+ if (IsKeyboardLayoutCommandQwerty(layoutId)) {
+ SetIsInputSourceCommandQwertyForTesting(true);
+ }
+
+ EventModifiers modifiers = cmdKey >> 8;
+ NSString* chars = keyCodeToCharacter(keyCode, modifiers, ref);
+ NSString* charsIgnoringMods = keyCodeToCharacter(keyCode, 0, ref);
+ NSEvent* key = KeyEvent(0x100000, chars, charsIgnoringMods, keyCode);
+ if ([layoutId isEqualToString:@"com.apple.keylayout.Dvorak-Left"] ||
+ [layoutId isEqualToString:@"com.apple.keylayout.Dvorak-Right"]) {
+ // On Dvorak, we expect this comparison to fail because the cmd + <keycode
+ // for numerical key> will always trigger tab switching. This causes
+ // Chrome to match the behavior of Safari, and has been expected by users
+ // of every other keyboard layout.
+ ExpectKeyDoesntFireItem(key, item, false);
+ } else {
+ ExpectKeyFiresItem(key, item, false);
+ }
+
+ if (IsKeyboardLayoutCommandQwerty(layoutId)) {
+ SetIsInputSourceCommandQwertyForTesting(false);
+ }
+ }
+ CFRelease(list);
+}
+
+} // namespace
+} // namespace cocoa
+} // namespace ui
diff --git a/chromium/ui/base/cursor/BUILD.gn b/chromium/ui/base/cursor/BUILD.gn
index 947ff85b6ef..23ebb70fbf3 100644
--- a/chromium/ui/base/cursor/BUILD.gn
+++ b/chromium/ui/base/cursor/BUILD.gn
@@ -24,12 +24,8 @@ component("cursor_base") {
]
deps = [ "//ui/gfx:geometry_skia" ]
- if (is_win) {
- sources += [ "cursor_win.cc" ]
- }
-
- if (use_x11 || use_ozone) {
- sources += [ "cursor_ozone.cc" ]
+ if (use_aura) {
+ sources += [ "cursor_aura.cc" ]
}
}
@@ -48,6 +44,7 @@ if (use_aura) {
component("cursor") {
output_name = "ui_base_cursor"
sources = [
+ "cursor_loader.cc",
"cursor_loader.h",
"cursor_lookup.cc",
"cursor_lookup.h",
@@ -75,8 +72,10 @@ if (use_aura) {
if (is_win) {
sources += [
- "cursor_loader_win.cc",
- "cursor_loader_win.h",
+ "win/win_cursor.cc",
+ "win/win_cursor.h",
+ "win/win_cursor_factory.cc",
+ "win/win_cursor_factory.h",
]
deps += [ "//ui/resources:ui_unscaled_resources_grd" ]
}
@@ -92,13 +91,6 @@ if (use_aura) {
]
deps += [ "//build:chromeos_buildflags" ]
}
-
- if (use_x11 || use_ozone) {
- sources += [
- "cursor_loader_ozone.cc",
- "cursor_loader_ozone.h",
- ]
- }
}
}
diff --git a/chromium/ui/base/cursor/cursor.h b/chromium/ui/base/cursor/cursor.h
index 1c54756715d..e5ffd67ffa3 100644
--- a/chromium/ui/base/cursor/cursor.h
+++ b/chromium/ui/base/cursor/cursor.h
@@ -17,13 +17,10 @@
namespace ui {
-#if defined(OS_WIN)
-typedef ::HCURSOR PlatformCursor;
-#else
// NOTE: On Ozone platforms, the type is chosen at runtime, and is either
// X11Cursor* or BitmapCursorOzone*.
-typedef void* PlatformCursor;
-#endif
+// On Windows, it's WinCursor*.
+using PlatformCursor = void*;
// Ref-counted cursor that supports both default and custom cursors.
class COMPONENT_EXPORT(UI_BASE_CURSOR_BASE) Cursor {
diff --git a/chromium/ui/base/cursor/cursor_ozone.cc b/chromium/ui/base/cursor/cursor_aura.cc
index b41f4ca3b67..b41f4ca3b67 100644
--- a/chromium/ui/base/cursor/cursor_ozone.cc
+++ b/chromium/ui/base/cursor/cursor_aura.cc
diff --git a/chromium/ui/base/cursor/cursor_factory.cc b/chromium/ui/base/cursor/cursor_factory.cc
index 5a987bf501a..65afecadbb6 100644
--- a/chromium/ui/base/cursor/cursor_factory.cc
+++ b/chromium/ui/base/cursor/cursor_factory.cc
@@ -9,6 +9,7 @@
#include "base/check.h"
#include "base/check_op.h"
#include "base/notreached.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
namespace ui {
@@ -67,4 +68,123 @@ void CursorFactory::ObserveThemeChanges() {
NOTIMPLEMENTED();
}
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+
+// Returns a cursor name compatible with either X11 or the FreeDesktop.org
+// cursor spec ([1] and [2]), followed by fallbacks that can work as
+// replacements in some environments where the original may not be available
+// (e.g. desktop environments other than GNOME and KDE).
+//
+// TODO(hferreiro): each list starts with the FreeDesktop.org icon name but
+// "ns-resize", "ew-resize", "nesw-resize", "nwse-resize", "grab", "grabbing",
+// which were not available in older versions of Breeze, the default KDE theme.
+//
+// [1]
+// https://www.x.org/releases/current/doc/libX11/libX11/libX11.html#x_font_cursors
+// [2] https://www.freedesktop.org/wiki/Specifications/cursor-spec/
+std::vector<std::string> CursorNamesFromType(mojom::CursorType type) {
+ switch (type) {
+ case mojom::CursorType::kMove:
+ // Returning "move" is the correct thing here, but Blink doesn't make a
+ // distinction between move and all-scroll. Other platforms use a cursor
+ // more consistent with all-scroll, so use that.
+ case mojom::CursorType::kMiddlePanning:
+ case mojom::CursorType::kMiddlePanningVertical:
+ case mojom::CursorType::kMiddlePanningHorizontal:
+ return {"all-scroll", "fleur"};
+ case mojom::CursorType::kEastPanning:
+ case mojom::CursorType::kEastResize:
+ return {"e-resize", "right_side"};
+ case mojom::CursorType::kNorthPanning:
+ case mojom::CursorType::kNorthResize:
+ return {"n-resize", "top_side"};
+ case mojom::CursorType::kNorthEastPanning:
+ case mojom::CursorType::kNorthEastResize:
+ return {"ne-resize", "top_right_corner"};
+ case mojom::CursorType::kNorthWestPanning:
+ case mojom::CursorType::kNorthWestResize:
+ return {"nw-resize", "top_left_corner"};
+ case mojom::CursorType::kSouthPanning:
+ case mojom::CursorType::kSouthResize:
+ return {"s-resize", "bottom_side"};
+ case mojom::CursorType::kSouthEastPanning:
+ case mojom::CursorType::kSouthEastResize:
+ return {"se-resize", "bottom_right_corner"};
+ case mojom::CursorType::kSouthWestPanning:
+ case mojom::CursorType::kSouthWestResize:
+ return {"sw-resize", "bottom_left_corner"};
+ case mojom::CursorType::kWestPanning:
+ case mojom::CursorType::kWestResize:
+ return {"w-resize", "left_side"};
+ case mojom::CursorType::kNone:
+ return {"none"};
+ case mojom::CursorType::kGrab:
+ return {"openhand", "grab"};
+ case mojom::CursorType::kGrabbing:
+ return {"closedhand", "grabbing", "hand2"};
+ case mojom::CursorType::kCross:
+ return {"crosshair", "cross"};
+ case mojom::CursorType::kHand:
+ return {"pointer", "hand", "hand2"};
+ case mojom::CursorType::kIBeam:
+ return {"text", "xterm"};
+ case mojom::CursorType::kProgress:
+ return {"progress", "left_ptr_watch", "watch"};
+ case mojom::CursorType::kWait:
+ return {"wait", "watch"};
+ case mojom::CursorType::kHelp:
+ return {"help"};
+ case mojom::CursorType::kNorthSouthResize:
+ return {"sb_v_double_arrow", "ns-resize"};
+ case mojom::CursorType::kEastWestResize:
+ return {"sb_h_double_arrow", "ew-resize"};
+ case mojom::CursorType::kColumnResize:
+ return {"col-resize", "sb_h_double_arrow"};
+ case mojom::CursorType::kRowResize:
+ return {"row-resize", "sb_v_double_arrow"};
+ case mojom::CursorType::kNorthEastSouthWestResize:
+ return {"size_bdiag", "nesw-resize", "fd_double_arrow"};
+ case mojom::CursorType::kNorthWestSouthEastResize:
+ return {"size_fdiag", "nwse-resize", "bd_double_arrow"};
+ case mojom::CursorType::kVerticalText:
+ return {"vertical-text"};
+ case mojom::CursorType::kZoomIn:
+ return {"zoom-in"};
+ case mojom::CursorType::kZoomOut:
+ return {"zoom-out"};
+ case mojom::CursorType::kCell:
+ return {"cell", "plus"};
+ case mojom::CursorType::kContextMenu:
+ return {"context-menu"};
+ case mojom::CursorType::kAlias:
+ return {"alias"};
+ case mojom::CursorType::kNoDrop:
+ return {"no-drop"};
+ case mojom::CursorType::kCopy:
+ return {"copy"};
+ case mojom::CursorType::kNotAllowed:
+ return {"not-allowed", "crossed_circle"};
+ case mojom::CursorType::kDndNone:
+ return {"dnd-none", "hand2"};
+ case mojom::CursorType::kDndMove:
+ return {"dnd-move", "hand2"};
+ case mojom::CursorType::kDndCopy:
+ return {"dnd-copy", "hand2"};
+ case mojom::CursorType::kDndLink:
+ return {"dnd-link", "hand2"};
+ case mojom::CursorType::kCustom:
+ // kCustom is for custom image cursors. The platform cursor will be set
+ // at WebCursor::GetNativeCursor().
+ NOTREACHED();
+ FALLTHROUGH;
+ case mojom::CursorType::kNull:
+ case mojom::CursorType::kPointer:
+ return {"left_ptr"};
+ }
+ NOTREACHED();
+ return {"left_ptr"};
+}
+
+#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+
} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor_factory.h b/chromium/ui/base/cursor/cursor_factory.h
index 57c70c9e60a..7de026b856b 100644
--- a/chromium/ui/base/cursor/cursor_factory.h
+++ b/chromium/ui/base/cursor/cursor_factory.h
@@ -9,6 +9,7 @@
#include "base/component_export.h"
#include "base/optional.h"
+#include "build/build_config.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
class SkBitmap;
@@ -66,6 +67,11 @@ class COMPONENT_EXPORT(UI_BASE_CURSOR_BASE) CursorFactory {
virtual void ObserveThemeChanges();
};
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+COMPONENT_EXPORT(UI_BASE_CURSOR_BASE)
+std::vector<std::string> CursorNamesFromType(mojom::CursorType type);
+#endif
+
} // namespace ui
#endif // UI_BASE_CURSOR_CURSOR_FACTORY_H_
diff --git a/chromium/ui/base/cursor/cursor_loader_ozone.cc b/chromium/ui/base/cursor/cursor_loader.cc
index 6d386672c9e..20544e2d3f4 100644
--- a/chromium/ui/base/cursor/cursor_loader_ozone.cc
+++ b/chromium/ui/base/cursor/cursor_loader.cc
@@ -1,18 +1,19 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium 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_ozone.h"
+#include "ui/base/cursor/cursor_loader.h"
-#include <memory>
+#include <map>
#include <vector>
-#include "base/ranges/algorithm.h"
+#include "base/check.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/cursor/cursor_size.h"
#include "ui/base/cursor/cursor_util.h"
#include "ui/base/cursor/cursors_aura.h"
-#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom.h"
#include "ui/gfx/geometry/point.h"
namespace ui {
@@ -26,33 +27,52 @@ const int kAnimatedCursorFrameDelayMs = 25;
} // namespace
-CursorLoaderOzone::CursorLoaderOzone(bool use_platform_cursors)
+CursorLoader::CursorLoader(bool use_platform_cursors)
: use_platform_cursors_(use_platform_cursors),
factory_(CursorFactory::GetInstance()) {}
-CursorLoaderOzone::~CursorLoaderOzone() {
+CursorLoader::~CursorLoader() {
UnloadCursors();
}
-void CursorLoaderOzone::UnloadCursors() {
+void CursorLoader::UnloadCursors() {
for (const auto& image_cursor : image_cursors_)
factory_->UnrefImageCursor(image_cursor.second);
image_cursors_.clear();
}
-void CursorLoaderOzone::SetPlatformCursor(gfx::NativeCursor* cursor) {
+bool CursorLoader::SetDisplayData(display::Display::Rotation rotation,
+ float scale) {
+ if (rotation_ == rotation && scale_ == scale)
+ return false;
+
+ rotation_ = rotation;
+ scale_ = scale;
+ UnloadCursors();
+ return true;
+}
+
+void CursorLoader::SetSize(CursorSize size) {
+ if (size_ == size)
+ return;
+
+ size_ = size;
+ UnloadCursors();
+}
+
+void CursorLoader::SetPlatformCursor(Cursor* cursor) {
DCHECK(cursor);
- // The platform cursor was already set via WebCursor::GetPlatformCursor.
+ // The platform cursor was already set via WebCursor::GetNativeCursor.
if (cursor->type() == mojom::CursorType::kCustom)
return;
cursor->set_image_scale_factor(scale());
cursor->SetPlatformCursor(CursorFromType(cursor->type()));
}
-void CursorLoaderOzone::LoadImageCursor(mojom::CursorType type,
- int resource_id,
- const gfx::Point& hot) {
+void CursorLoader::LoadImageCursor(mojom::CursorType type,
+ int resource_id,
+ const gfx::Point& hot) {
gfx::Point hotspot = hot;
if (base::ranges::count(kAnimatedCursorTypes, type) == 0) {
SkBitmap bitmap;
@@ -67,7 +87,7 @@ void CursorLoaderOzone::LoadImageCursor(mojom::CursorType type,
}
}
-PlatformCursor CursorLoaderOzone::CursorFromType(mojom::CursorType type) {
+PlatformCursor CursorLoader::CursorFromType(mojom::CursorType type) {
// An image cursor is loaded for this type.
if (image_cursors_.count(type))
return image_cursors_[type];
@@ -80,6 +100,7 @@ PlatformCursor CursorLoaderOzone::CursorFromType(mojom::CursorType type) {
factory_->GetDefaultCursor(type);
if (default_cursor)
return *default_cursor;
+ LOG(ERROR) << "Failed to load a platform cursor of type " << type;
}
// Loads the default Aura cursor bitmap for the cursor type. Falls back on
@@ -94,8 +115,7 @@ PlatformCursor CursorLoaderOzone::CursorFromType(mojom::CursorType type) {
return platform;
}
-// Gets default Aura cursor bitmap/hotspot and creates a PlatformCursor with it.
-PlatformCursor CursorLoaderOzone::LoadCursorFromAsset(mojom::CursorType type) {
+PlatformCursor CursorLoader::LoadCursorFromAsset(mojom::CursorType type) {
int resource_id;
gfx::Point hotspot;
if (GetCursorDataFor(size(), type, scale(), &resource_id, &hotspot)) {
@@ -105,8 +125,4 @@ PlatformCursor CursorLoaderOzone::LoadCursorFromAsset(mojom::CursorType type) {
return nullptr;
}
-std::unique_ptr<CursorLoader> CursorLoader::Create(bool use_platform_cursors) {
- return std::make_unique<CursorLoaderOzone>(use_platform_cursors);
-}
-
} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor_loader.h b/chromium/ui/base/cursor/cursor_loader.h
index 0c516d7fa7c..767758e1619 100644
--- a/chromium/ui/base/cursor/cursor_loader.h
+++ b/chromium/ui/base/cursor/cursor_loader.h
@@ -5,22 +5,28 @@
#ifndef UI_BASE_CURSOR_CURSOR_LOADER_H_
#define UI_BASE_CURSOR_CURSOR_LOADER_H_
+#include <map>
#include <memory>
#include "base/component_export.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/cursor_size.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
#include "ui/display/display.h"
-#include "ui/gfx/native_widget_types.h"
+
+namespace gfx {
+class Point;
+}
namespace ui {
+class CursorFactory;
class COMPONENT_EXPORT(UI_BASE_CURSOR) CursorLoader {
public:
- CursorLoader() = default;
+ explicit CursorLoader(bool use_platform_cursors = true);
CursorLoader(const CursorLoader&) = delete;
CursorLoader& operator=(const CursorLoader&) = delete;
- virtual ~CursorLoader() = default;
+ ~CursorLoader();
// Returns the rotation and scale of the currently loaded cursor.
display::Display::Rotation rotation() const { return rotation_; }
@@ -28,39 +34,34 @@ class COMPONENT_EXPORT(UI_BASE_CURSOR) CursorLoader {
// Sets the rotation and scale the cursors are loaded for.
// Returns true if the cursor image was reloaded.
- bool SetDisplayData(display::Display::Rotation rotation, float scale) {
- if (rotation_ == rotation && scale_ == scale)
- return false;
-
- rotation_ = rotation;
- scale_ = scale;
- UnloadCursors();
- return true;
- }
+ bool SetDisplayData(display::Display::Rotation rotation, float scale);
// Returns the size of the currently loaded cursor.
CursorSize size() const { return size_; }
// Sets the size of the mouse cursor icon.
- void set_size(CursorSize size) {
- if (size_ == size)
- return;
+ void SetSize(CursorSize size);
- size_ = size;
- UnloadCursors();
- }
+ // Sets the platform cursor based on the type of |cursor|.
+ void SetPlatformCursor(Cursor* cursor);
- // Sets the platform cursor based on the native type of |cursor|.
- virtual void SetPlatformCursor(gfx::NativeCursor* cursor) = 0;
+ private:
+ // Resets the cursor cache.
+ void UnloadCursors();
+ void LoadImageCursor(mojom::CursorType id,
+ int resource_id,
+ const gfx::Point& hot);
+ PlatformCursor CursorFromType(mojom::CursorType type);
+ PlatformCursor LoadCursorFromAsset(mojom::CursorType type);
- // Creates a CursorLoader.
- static std::unique_ptr<CursorLoader> Create(bool use_platform_cursors = true);
+ // Whether to use cursors provided by the underlying platform (e.g. X11
+ // cursors). If false or in the case of a failure, Chromium assets will be
+ // used instead.
+ const bool use_platform_cursors_;
- protected:
- // Resets the cursor cache.
- virtual void UnloadCursors() = 0;
+ std::map<mojom::CursorType, PlatformCursor> image_cursors_;
+ CursorFactory* factory_ = nullptr;
- private:
// The current scale of the mouse cursor icon.
float scale_ = 1.0f;
diff --git a/chromium/ui/base/cursor/cursor_loader_ozone.h b/chromium/ui/base/cursor/cursor_loader_ozone.h
deleted file mode 100644
index bf1c11f6afb..00000000000
--- a/chromium/ui/base/cursor/cursor_loader_ozone.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_CURSOR_CURSOR_LOADER_OZONE_H_
-#define UI_BASE_CURSOR_CURSOR_LOADER_OZONE_H_
-
-#include <map>
-
-#include "base/component_export.h"
-#include "base/macros.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/base/cursor/cursor_loader.h"
-#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace ui {
-class CursorFactory;
-
-class COMPONENT_EXPORT(UI_BASE_CURSOR) CursorLoaderOzone : public CursorLoader {
- public:
- explicit CursorLoaderOzone(bool use_platform_cursors);
- ~CursorLoaderOzone() override;
-
- // CursorLoader overrides:
- void SetPlatformCursor(gfx::NativeCursor* cursor) override;
-
- private:
- // CursorLoader overrides:
- void UnloadCursors() override;
-
- void LoadImageCursor(mojom::CursorType id,
- int resource_id,
- const gfx::Point& hot);
- PlatformCursor CursorFromType(mojom::CursorType type);
- PlatformCursor LoadCursorFromAsset(mojom::CursorType type);
-
- // Whether to use cursors provided by the underlying platform (e.g. X11
- // cursors). If false or in the case of a failure, Chromium assets will be
- // used instead.
- const bool use_platform_cursors_;
-
- // Pointers are owned by ResourceBundle and must not be freed here.
- std::map<mojom::CursorType, PlatformCursor> image_cursors_;
- CursorFactory* factory_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(CursorLoaderOzone);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_CURSOR_CURSOR_LOADER_OZONE_H_
diff --git a/chromium/ui/base/cursor/cursor_loader_unittest.cc b/chromium/ui/base/cursor/cursor_loader_unittest.cc
index 67b4c2be1ce..a609fa4e554 100644
--- a/chromium/ui/base/cursor/cursor_loader_unittest.cc
+++ b/chromium/ui/base/cursor/cursor_loader_unittest.cc
@@ -4,10 +4,17 @@
#include "ui/base/cursor/cursor_loader.h"
+#include "base/memory/scoped_refptr.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
+#if defined(OS_WIN)
+#include "ui/base/cursor/win/win_cursor.h"
+#include "ui/base/cursor/win/win_cursor_factory.h"
+#endif
+
#if defined(USE_OZONE)
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#endif
@@ -23,25 +30,32 @@ namespace ui {
namespace {
PlatformCursor LoadInvisibleCursor() {
- auto cursor_loader = CursorLoader::Create();
+ CursorLoader cursor_loader;
Cursor cursor(mojom::CursorType::kNone);
- cursor_loader->SetPlatformCursor(&cursor);
+ cursor_loader.SetPlatformCursor(&cursor);
return cursor.platform();
}
} // namespace
-#if !defined(USE_X11)
-TEST(CursorLoaderTest, InvisibleCursorOnNotX11) {
-#if defined(USE_OZONE)
- BitmapCursorFactoryOzone cursor_factory;
+#if defined(OS_WIN)
+TEST(CursorLoaderTest, InvisibleCursor) {
+ WinCursorFactory cursor_factory;
+ auto* invisible_cursor = static_cast<WinCursor*>(LoadInvisibleCursor());
+ ASSERT_NE(invisible_cursor, nullptr);
+ EXPECT_EQ(invisible_cursor->hcursor(), nullptr);
+}
#endif
+
+#if defined(USE_OZONE) && !defined(USE_X11)
+TEST(CursorLoaderTest, InvisibleCursor) {
+ BitmapCursorFactoryOzone cursor_factory;
EXPECT_EQ(LoadInvisibleCursor(), nullptr);
}
#endif
#if defined(USE_X11)
-TEST(CursorLoaderTest, InvisibleCursorOnX11) {
+TEST(CursorLoaderTest, InvisibleCursor) {
X11CursorFactory cursor_factory;
// Building an image cursor with an invalid SkBitmap should return the
// invisible cursor in X11.
diff --git a/chromium/ui/base/cursor/cursor_loader_win.h b/chromium/ui/base/cursor/cursor_loader_win.h
deleted file mode 100644
index cbe7d000138..00000000000
--- a/chromium/ui/base/cursor/cursor_loader_win.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_CURSOR_CURSOR_LOADER_WIN_H_
-#define UI_BASE_CURSOR_CURSOR_LOADER_WIN_H_
-
-#include "base/component_export.h"
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "ui/base/cursor/cursor_loader.h"
-
-namespace ui {
-
-class COMPONENT_EXPORT(UI_BASE_CURSOR) CursorLoaderWin : public CursorLoader {
- public:
- CursorLoaderWin();
- ~CursorLoaderWin() override;
-
- // Overridden from CursorLoader:
- void UnloadCursors() override;
- void SetPlatformCursor(gfx::NativeCursor* cursor) override;
-
- // Used to pass the cursor resource module name to the cursor loader. This is
- // typically used to load non system cursors.
- static void SetCursorResourceModule(const base::string16& module_name);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CursorLoaderWin);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_CURSOR_CURSOR_LOADER_WIN_H_
diff --git a/chromium/ui/base/cursor/cursor_util.cc b/chromium/ui/base/cursor/cursor_util.cc
index ee513696649..57b1bb6dcbc 100644
--- a/chromium/ui/base/cursor/cursor_util.cc
+++ b/chromium/ui/base/cursor/cursor_util.cc
@@ -99,8 +99,9 @@ void ScaleAndRotateCursorBitmapAndHotpoint(float scale,
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->pixmap().scalePixels(
+ scaled_bitmap.pixmap(),
+ {SkFilterMode::kLinear, SkMipmapMode::kNearest});
}
*bitmap = scaled_bitmap;
diff --git a/chromium/ui/base/cursor/cursor_win.cc b/chromium/ui/base/cursor/cursor_win.cc
deleted file mode 100644
index 2d4aafea8d5..00000000000
--- a/chromium/ui/base/cursor/cursor_win.cc
+++ /dev/null
@@ -1,17 +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/base/cursor/cursor.h"
-
-namespace ui {
-
-void Cursor::RefCustomCursor() {
- // TODO(winguru):
-}
-
-void Cursor::UnrefCustomCursor() {
- // TODO(winguru):
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/cursor/cursors_aura.cc b/chromium/ui/base/cursor/cursors_aura.cc
index c527ac4d8eb..c63ea7594e4 100644
--- a/chromium/ui/base/cursor/cursors_aura.cc
+++ b/chromium/ui/base/cursor/cursors_aura.cc
@@ -18,7 +18,8 @@
#include "ui/resources/grit/ui_resources.h"
#if defined(OS_WIN)
-#include "ui/base/cursor/cursor_loader_win.h"
+#include "ui/base/cursor/cursor_loader.h"
+#include "ui/base/cursor/win/win_cursor.h"
#include "ui/gfx/icon_util.h"
#endif
@@ -297,9 +298,10 @@ bool GetCursorDataFor(CursorSize cursor_size,
SkBitmap GetDefaultBitmap(const Cursor& cursor) {
#if defined(OS_WIN)
Cursor cursor_copy = cursor;
- ui::CursorLoaderWin cursor_loader;
+ CursorLoader cursor_loader;
cursor_loader.SetPlatformCursor(&cursor_copy);
- return IconUtil::CreateSkBitmapFromHICON(cursor_copy.platform());
+ return IconUtil::CreateSkBitmapFromHICON(
+ static_cast<WinCursor*>(cursor_copy.platform())->hcursor());
#else
int resource_id;
gfx::Point hotspot;
@@ -316,9 +318,10 @@ SkBitmap GetDefaultBitmap(const Cursor& cursor) {
gfx::Point GetDefaultHotspot(const Cursor& cursor) {
#if defined(OS_WIN)
Cursor cursor_copy = cursor;
- ui::CursorLoaderWin cursor_loader;
+ CursorLoader cursor_loader;
cursor_loader.SetPlatformCursor(&cursor_copy);
- return IconUtil::GetHotSpotFromHICON(cursor_copy.platform());
+ return IconUtil::GetHotSpotFromHICON(
+ static_cast<WinCursor*>(cursor_copy.platform())->hcursor());
#else
int resource_id;
gfx::Point hotspot;
diff --git a/chromium/ui/base/cursor/mojom/cursor.mojom b/chromium/ui/base/cursor/mojom/cursor.mojom
index 56230736c31..f7852c06330 100644
--- a/chromium/ui/base/cursor/mojom/cursor.mojom
+++ b/chromium/ui/base/cursor/mojom/cursor.mojom
@@ -17,7 +17,7 @@ struct Cursor {
gfx.mojom.Point hotspot;
// The custom bitmap. Must be non-empty if |cursor_type| is kCustom.
- skia.mojom.Bitmap? bitmap;
+ skia.mojom.BitmapN32? bitmap;
// This is the image scale of this cursor.
float image_scale_factor;
diff --git a/chromium/ui/base/cursor/mojom/cursor_mojom_traits_unittest.cc b/chromium/ui/base/cursor/mojom/cursor_mojom_traits_unittest.cc
index 88f888b2709..8c4ecc2e2f6 100644
--- a/chromium/ui/base/cursor/mojom/cursor_mojom_traits_unittest.cc
+++ b/chromium/ui/base/cursor/mojom/cursor_mojom_traits_unittest.cc
@@ -17,7 +17,8 @@ namespace ui {
namespace {
bool EchoCursor(const ui::Cursor& in, ui::Cursor* out) {
- return mojom::Cursor::Deserialize(mojom::Cursor::Serialize(&in), out);
+ return mojom::Cursor::DeserializeFromMessage(
+ mojom::Cursor::SerializeAsMessage(&in), out);
}
using CursorStructTraitsTest = testing::Test;
diff --git a/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.cc b/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.cc
index f16c01a02a7..1fbb8d5d6ad 100644
--- a/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.cc
+++ b/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.cc
@@ -117,6 +117,10 @@ BitmapCursorOzone::BitmapCursorOzone(mojom::CursorType type,
bitmaps_.end());
}
+BitmapCursorOzone::BitmapCursorOzone(mojom::CursorType type,
+ void* platform_data)
+ : type_(type), platform_data_(platform_data) {}
+
BitmapCursorOzone::~BitmapCursorOzone() = default;
const gfx::Point& BitmapCursorOzone::hotspot() {
diff --git a/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h b/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h
index db049fb4532..0fa94409e0c 100644
--- a/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h
+++ b/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h
@@ -37,6 +37,9 @@ class COMPONENT_EXPORT(UI_BASE_CURSOR) BitmapCursorOzone
const gfx::Point& hotspot,
int frame_delay_ms);
+ // Creates a cursor with external storage.
+ BitmapCursorOzone(mojom::CursorType type, void* platform_data);
+
mojom::CursorType type() const { return type_; }
const gfx::Point& hotspot();
const SkBitmap& bitmap();
@@ -45,6 +48,9 @@ class COMPONENT_EXPORT(UI_BASE_CURSOR) BitmapCursorOzone
const std::vector<SkBitmap>& bitmaps();
int frame_delay_ms();
+ // For theme cursors.
+ void* platform_data() { return platform_data_; }
+
private:
friend class base::RefCounted<BitmapCursorOzone>;
~BitmapCursorOzone();
@@ -54,6 +60,10 @@ class COMPONENT_EXPORT(UI_BASE_CURSOR) BitmapCursorOzone
gfx::Point hotspot_;
int frame_delay_ms_;
+ // Platform cursor data. Having this non-nullptr means that this cursor
+ // is supplied by the platform.
+ void* const platform_data_ = nullptr;
+
DISALLOW_COPY_AND_ASSIGN(BitmapCursorOzone);
};
@@ -61,9 +71,6 @@ class COMPONENT_EXPORT(UI_BASE_CURSOR) BitmapCursorOzone
//
// This is a base class for platforms where PlatformCursor is an SkBitmap
// combined with a gfx::Point for the hotspot.
-//
-// Subclasses need only implement SetBitmapCursor() as everything else is
-// implemented here.
class COMPONENT_EXPORT(UI_BASE_CURSOR) BitmapCursorFactoryOzone
: public CursorFactory {
public:
diff --git a/chromium/ui/base/cursor/win/win_cursor.cc b/chromium/ui/base/cursor/win/win_cursor.cc
new file mode 100644
index 00000000000..afa707faffd
--- /dev/null
+++ b/chromium/ui/base/cursor/win/win_cursor.cc
@@ -0,0 +1,19 @@
+// Copyright 2021 The Chromium 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/win/win_cursor.h"
+
+#include <windows.h>
+
+namespace ui {
+
+WinCursor::WinCursor(HCURSOR hcursor) {
+ hcursor_ = hcursor;
+}
+
+WinCursor::~WinCursor() {
+ DestroyIcon(hcursor_);
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cursor/win/win_cursor.h b/chromium/ui/base/cursor/win/win_cursor.h
new file mode 100644
index 00000000000..e1f787f7710
--- /dev/null
+++ b/chromium/ui/base/cursor/win/win_cursor.h
@@ -0,0 +1,35 @@
+// Copyright 2021 The Chromium 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_WIN_WIN_CURSOR_H_
+#define UI_BASE_CURSOR_WIN_WIN_CURSOR_H_
+
+#include "base/component_export.h"
+#include "base/memory/ref_counted.h"
+#include "base/win/windows_types.h"
+
+namespace ui {
+
+// Ref counted class to hold a Windows cursor, i.e. an HCURSOR. Clears the
+// resources on destruction.
+class COMPONENT_EXPORT(UI_BASE_CURSOR) WinCursor
+ : public base::RefCounted<WinCursor> {
+ public:
+ explicit WinCursor(HCURSOR hcursor = nullptr);
+ WinCursor(const WinCursor&) = delete;
+ WinCursor& operator=(const WinCursor&) = delete;
+
+ HCURSOR hcursor() const { return hcursor_; }
+
+ private:
+ friend class base::RefCounted<WinCursor>;
+
+ ~WinCursor();
+
+ HCURSOR hcursor_;
+};
+
+} // namespace ui
+
+#endif // UI_BASE_CURSOR_WIN_WIN_CURSOR_H_
diff --git a/chromium/ui/base/cursor/cursor_loader_win.cc b/chromium/ui/base/cursor/win/win_cursor_factory.cc
index 392fd85d6f3..bde6a5be63f 100644
--- a/chromium/ui/base/cursor/cursor_loader_win.cc
+++ b/chromium/ui/base/cursor/win/win_cursor_factory.cc
@@ -1,30 +1,38 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium 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_win.h"
+#include "ui/base/cursor/win/win_cursor_factory.h"
#include <windows.h>
-#include <memory>
+#include <string>
-#include "base/lazy_instance.h"
+#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
+#include "base/optional.h"
+#include "base/win/scoped_gdi_object.h"
+#include "base/win/windows_types.h"
#include "ui/base/cursor/cursor.h"
-#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom.h"
+#include "ui/base/resource/resource_bundle_win.h"
+#include "ui/gfx/icon_util.h"
#include "ui/resources/grit/ui_unscaled_resources.h"
namespace ui {
-
namespace {
-base::LazyInstance<base::string16>::DestructorAtExit
- g_cursor_resource_module_name;
+WinCursor* ToWinCursor(PlatformCursor cursor) {
+ return static_cast<WinCursor*>(cursor);
+}
-const wchar_t* GetCursorId(gfx::NativeCursor native_cursor) {
- switch (native_cursor.type()) {
+PlatformCursor ToPlatformCursor(WinCursor* cursor) {
+ return static_cast<PlatformCursor>(cursor);
+}
+
+const wchar_t* GetCursorId(mojom::CursorType type) {
+ switch (type) {
case mojom::CursorType::kNull:
- return IDC_ARROW;
case mojom::CursorType::kPointer:
return IDC_ARROW;
case mojom::CursorType::kCross:
@@ -38,27 +46,19 @@ const wchar_t* GetCursorId(gfx::NativeCursor native_cursor) {
case mojom::CursorType::kHelp:
return IDC_HELP;
case mojom::CursorType::kEastResize:
+ case mojom::CursorType::kWestResize:
+ case mojom::CursorType::kEastWestResize:
return IDC_SIZEWE;
case mojom::CursorType::kNorthResize:
- return IDC_SIZENS;
- case mojom::CursorType::kNorthEastResize:
- return IDC_SIZENESW;
- case mojom::CursorType::kNorthWestResize:
- return IDC_SIZENWSE;
case mojom::CursorType::kSouthResize:
- return IDC_SIZENS;
- case mojom::CursorType::kSouthEastResize:
- return IDC_SIZENWSE;
- case mojom::CursorType::kSouthWestResize:
- return IDC_SIZENESW;
- case mojom::CursorType::kWestResize:
- return IDC_SIZEWE;
case mojom::CursorType::kNorthSouthResize:
return IDC_SIZENS;
- case mojom::CursorType::kEastWestResize:
- return IDC_SIZEWE;
+ case mojom::CursorType::kNorthEastResize:
+ case mojom::CursorType::kSouthWestResize:
case mojom::CursorType::kNorthEastSouthWestResize:
return IDC_SIZENESW;
+ case mojom::CursorType::kNorthWestResize:
+ case mojom::CursorType::kSouthEastResize:
case mojom::CursorType::kNorthWestSouthEastResize:
return IDC_SIZENWSE;
case mojom::CursorType::kMove:
@@ -66,7 +66,6 @@ const wchar_t* GetCursorId(gfx::NativeCursor native_cursor) {
case mojom::CursorType::kProgress:
return IDC_APPSTARTING;
case mojom::CursorType::kNoDrop:
- return IDC_NO;
case mojom::CursorType::kNotAllowed:
return IDC_NO;
case mojom::CursorType::kColumnResize:
@@ -111,63 +110,66 @@ const wchar_t* GetCursorId(gfx::NativeCursor native_cursor) {
return MAKEINTRESOURCE(IDC_COPYCUR);
case mojom::CursorType::kAlias:
return MAKEINTRESOURCE(IDC_ALIAS);
+ case mojom::CursorType::kDndCopy:
+ case mojom::CursorType::kDndLink:
+ case mojom::CursorType::kDndMove:
+ case mojom::CursorType::kDndNone:
case mojom::CursorType::kContextMenu:
- case mojom::CursorType::kCustom:
- case mojom::CursorType::kNone:
NOTIMPLEMENTED();
return IDC_ARROW;
- default:
+ case mojom::CursorType::kNone:
+ case mojom::CursorType::kCustom:
NOTREACHED();
return IDC_ARROW;
}
+ NOTREACHED();
+ return IDC_ARROW;
}
} // namespace
-std::unique_ptr<CursorLoader> CursorLoader::Create(bool use_platform_cursors) {
- return std::make_unique<CursorLoaderWin>();
-}
-
-CursorLoaderWin::CursorLoaderWin() {
-}
+WinCursorFactory::WinCursorFactory() = default;
+
+WinCursorFactory::~WinCursorFactory() = default;
+
+base::Optional<PlatformCursor> WinCursorFactory::GetDefaultCursor(
+ mojom::CursorType type) {
+ if (!default_cursors_.count(type)) {
+ // Using a dark 1x1 bit bmp for the kNone cursor may still cause DWM to do
+ // composition work unnecessarily. Better to totally remove it from the
+ // screen. crbug.com/1069698
+ HCURSOR hcursor = nullptr;
+ if (type != mojom::CursorType::kNone) {
+ const wchar_t* id = GetCursorId(type);
+ hcursor = LoadCursor(nullptr, id);
+ // Try loading the cursor from the Chromium resources.
+ if (!hcursor)
+ hcursor = LoadCursorFromResourcesDataDLL(id);
+ if (!hcursor)
+ return base::nullopt;
+ }
+ default_cursors_[type] = base::MakeRefCounted<WinCursor>(hcursor);
+ }
-CursorLoaderWin::~CursorLoaderWin() {
+ auto cursor = default_cursors_[type];
+ return ToPlatformCursor(cursor.get());
}
-void CursorLoaderWin::UnloadCursors() {
- // NOTIMPLEMENTED();
+PlatformCursor WinCursorFactory::CreateImageCursor(mojom::CursorType type,
+ const SkBitmap& bitmap,
+ const gfx::Point& hotspot) {
+ auto cursor = base::MakeRefCounted<WinCursor>(
+ IconUtil::CreateCursorFromSkBitmap(bitmap, hotspot).release());
+ cursor->AddRef();
+ return ToPlatformCursor(cursor.get());
}
-void CursorLoaderWin::SetPlatformCursor(gfx::NativeCursor* cursor) {
- if (cursor->type() == mojom::CursorType::kCustom)
- return;
-
- // Using a dark 1x1 bit bmp kNone cursor may still cause DWM to do composition
- // work unnecessarily. Better to totally remove it from the screen.
- // crbug.com/1069698
- if (cursor->type() == mojom::CursorType::kNone) {
- cursor->SetPlatformCursor(nullptr);
- return;
- }
-
- if (cursor->platform()) {
- cursor->SetPlatformCursor(cursor->platform());
- } else {
- const wchar_t* cursor_id = GetCursorId(*cursor);
- PlatformCursor platform_cursor = LoadCursor(nullptr, cursor_id);
- if (!platform_cursor && !g_cursor_resource_module_name.Get().empty()) {
- platform_cursor = LoadCursor(
- GetModuleHandle(g_cursor_resource_module_name.Get().c_str()),
- cursor_id);
- }
- cursor->SetPlatformCursor(platform_cursor);
- }
+void WinCursorFactory::RefImageCursor(PlatformCursor cursor) {
+ ToWinCursor(cursor)->AddRef();
}
-// static
-void CursorLoaderWin::SetCursorResourceModule(
- const base::string16& module_name) {
- g_cursor_resource_module_name.Get() = module_name;
+void WinCursorFactory::UnrefImageCursor(PlatformCursor cursor) {
+ ToWinCursor(cursor)->Release();
}
} // namespace ui
diff --git a/chromium/ui/base/cursor/win/win_cursor_factory.h b/chromium/ui/base/cursor/win/win_cursor_factory.h
new file mode 100644
index 00000000000..21b6c53eb71
--- /dev/null
+++ b/chromium/ui/base/cursor/win/win_cursor_factory.h
@@ -0,0 +1,46 @@
+// Copyright 2021 The Chromium 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_WIN_WIN_CURSOR_FACTORY_H_
+#define UI_BASE_CURSOR_WIN_WIN_CURSOR_FACTORY_H_
+
+#include <map>
+
+#include "base/component_export.h"
+#include "base/memory/scoped_refptr.h"
+#include "ui/base/cursor/cursor_factory.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
+#include "ui/base/cursor/win/win_cursor.h"
+
+class SkBitmap;
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+class COMPONENT_EXPORT(UI_BASE_CURSOR) WinCursorFactory : public CursorFactory {
+ public:
+ WinCursorFactory();
+ WinCursorFactory(const WinCursorFactory&) = delete;
+ WinCursorFactory& operator=(const WinCursorFactory&) = delete;
+ ~WinCursorFactory() override;
+
+ // CursorFactory:
+ base::Optional<PlatformCursor> GetDefaultCursor(
+ mojom::CursorType type) override;
+ PlatformCursor CreateImageCursor(mojom::CursorType type,
+ const SkBitmap& bitmap,
+ const gfx::Point& hotspot) override;
+ void RefImageCursor(PlatformCursor cursor) override;
+ void UnrefImageCursor(PlatformCursor cursor) override;
+
+ private:
+ std::map<mojom::CursorType, scoped_refptr<WinCursor>> default_cursors_;
+};
+
+} // namespace ui
+
+#endif // UI_BASE_CURSOR_WIN_WIN_CURSOR_FACTORY_H_
diff --git a/chromium/ui/base/data_transfer_policy/BUILD.gn b/chromium/ui/base/data_transfer_policy/BUILD.gn
index aeea4b1d324..eb2ec113013 100644
--- a/chromium/ui/base/data_transfer_policy/BUILD.gn
+++ b/chromium/ui/base/data_transfer_policy/BUILD.gn
@@ -17,6 +17,17 @@ component("data_transfer_policy") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
+ "//url",
+ ]
+}
+
+source_set("unittests") {
+ testonly = true
+ sources = [ "data_transfer_endpoint_unittest.cc" ]
+ deps = [
+ ":data_transfer_policy",
+ "//testing/gtest",
"//url",
]
}
diff --git a/chromium/ui/base/data_transfer_policy/data_transfer_endpoint.cc b/chromium/ui/base/data_transfer_policy/data_transfer_endpoint.cc
index a5f3c7bdac8..5f12aca7450 100644
--- a/chromium/ui/base/data_transfer_policy/data_transfer_endpoint.cc
+++ b/chromium/ui/base/data_transfer_policy/data_transfer_endpoint.cc
@@ -30,10 +30,22 @@ DataTransferEndpoint::DataTransferEndpoint(const DataTransferEndpoint& other) =
DataTransferEndpoint::DataTransferEndpoint(DataTransferEndpoint&& other) =
default;
+DataTransferEndpoint& DataTransferEndpoint::operator=(
+ const DataTransferEndpoint& other) = default;
+
+DataTransferEndpoint& DataTransferEndpoint::operator=(
+ DataTransferEndpoint&& other) = default;
+
bool DataTransferEndpoint::operator==(const DataTransferEndpoint& other) const {
- return origin_ == other.origin_ && type_ == other.type_;
+ return origin_ == other.origin_ && type_ == other.type_ &&
+ notify_if_restricted_ == other.notify_if_restricted_;
}
DataTransferEndpoint::~DataTransferEndpoint() = default;
+bool DataTransferEndpoint::IsSameOriginWith(
+ const DataTransferEndpoint& other) const {
+ return IsUrlType() && (type_ == other.type_) && (origin_ == other.origin_);
+}
+
} // namespace ui
diff --git a/chromium/ui/base/data_transfer_policy/data_transfer_endpoint.h b/chromium/ui/base/data_transfer_policy/data_transfer_endpoint.h
index cd510a56011..d3a9d2f3c85 100644
--- a/chromium/ui/base/data_transfer_policy/data_transfer_endpoint.h
+++ b/chromium/ui/base/data_transfer_policy/data_transfer_endpoint.h
@@ -7,6 +7,7 @@
#include "base/optional.h"
#include "base/stl_util.h"
+#include "build/chromeos_buildflags.h"
#include "url/origin.h"
namespace ui {
@@ -17,16 +18,16 @@ namespace ui {
enum class EndpointType {
kDefault = 0, // This type shouldn't be used if any of the following types is
// a better match.
-#if defined(OS_CHROMEOS) || (OS_LINUX) || (OS_FUCHSIA)
- kGuestOs = 1, // Guest OS: PluginVM, Crostini.
-#endif // defined(OS_CHROMEOS) || (OS_LINUX) || (OS_FUCHSIA)
-#if defined(OS_CHROMEOS)
- kArc = 2, // ARC.
-#endif // defined(OS_CHROMEOS)
- kUrl = 3, // Website URL e.g. www.example.com.
- kClipboardHistory = 4, // Clipboard History UI has privileged access to any
+ kUrl = 1, // Website URL e.g. www.example.com.
+ kClipboardHistory = 2, // Clipboard History UI has privileged access to any
// clipboard data.
- kMaxValue = kClipboardHistory
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ kUnknownVm = 3, // The VM type is not identified.
+ kArc = 4, // ARC.
+ kBorealis = 5, // Borealis OS.
+ kCrostini = 6, // Crostini.
+ kPluginVm = 7 // Plugin VM App.
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
};
// DataTransferEndpoint represents:
@@ -49,10 +50,13 @@ class COMPONENT_EXPORT(UI_BASE_DATA_TRANSFER_POLICY) DataTransferEndpoint {
DataTransferEndpoint(const DataTransferEndpoint& other);
DataTransferEndpoint(DataTransferEndpoint&& other);
- DataTransferEndpoint& operator=(const DataTransferEndpoint& other) = delete;
- DataTransferEndpoint& operator=(DataTransferEndpoint&& other) = delete;
+ DataTransferEndpoint& operator=(const DataTransferEndpoint& other);
+ DataTransferEndpoint& operator=(DataTransferEndpoint&& other);
bool operator==(const DataTransferEndpoint& other) const;
+ bool operator!=(const DataTransferEndpoint& other) const {
+ return !(*this == other);
+ }
~DataTransferEndpoint();
@@ -64,12 +68,16 @@ class COMPONENT_EXPORT(UI_BASE_DATA_TRANSFER_POLICY) DataTransferEndpoint {
bool notify_if_restricted() const { return notify_if_restricted_; }
+ // Returns true if both of the endpoints have the same origin_ and type_ ==
+ // kUrl.
+ bool IsSameOriginWith(const DataTransferEndpoint& other) const;
+
private:
// This variable should always have a value representing the object type.
- const EndpointType type_;
+ EndpointType type_;
// The url::Origin of the data endpoint. It always has a value if `type_` ==
// EndpointType::kUrl, otherwise it's empty.
- const base::Optional<url::Origin> origin_;
+ base::Optional<url::Origin> origin_;
// This variable should be set to true, if paste is initiated by the user.
// Otherwise it should be set to false, so the user won't see a notification
// when the data is restricted by the rules of data leak prevention policy
diff --git a/chromium/ui/base/data_transfer_policy/data_transfer_endpoint_unittest.cc b/chromium/ui/base/data_transfer_policy/data_transfer_endpoint_unittest.cc
new file mode 100644
index 00000000000..222c0d75185
--- /dev/null
+++ b/chromium/ui/base/data_transfer_policy/data_transfer_endpoint_unittest.cc
@@ -0,0 +1,71 @@
+// Copyright 2021 The Chromium 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/data_transfer_policy/data_transfer_endpoint.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace ui {
+
+namespace {
+constexpr char kExample1Url[] = "https://wwww.example1.com";
+constexpr char kExample2Url[] = "https://wwww.example2.com";
+} // namespace
+
+// Tests that cloning DataTransferEndpoint object will clone all of its data
+// members.
+TEST(DataTransferEndpointTest, Clone) {
+ DataTransferEndpoint original1(EndpointType::kClipboardHistory,
+ /*notify_if_restricted=*/true);
+ DataTransferEndpoint clone1(original1);
+
+ EXPECT_EQ(original1.type(), clone1.type());
+ EXPECT_EQ(original1.notify_if_restricted(), clone1.notify_if_restricted());
+
+ DataTransferEndpoint original2(url::Origin::Create(GURL(kExample1Url)),
+ /*notify_if_restricted=*/false);
+ DataTransferEndpoint clone2(original2);
+
+ EXPECT_EQ(original2.type(), clone2.type());
+ EXPECT_TRUE(clone2.origin()->IsSameOriginWith(*original2.origin()));
+ EXPECT_EQ(original2.notify_if_restricted(), clone2.notify_if_restricted());
+}
+
+// Tests that two DataTransferEndpoint objects won't be equal unless they have
+// the same values for all of their data members.
+TEST(DataTransferEndpointTest, Equal) {
+ DataTransferEndpoint default_endpoint1(EndpointType::kDefault,
+ /*notify_if_restricted=*/true);
+ DataTransferEndpoint default_endpoint2(EndpointType::kDefault,
+ /*notify_if_restricted=*/false);
+
+ EXPECT_FALSE(default_endpoint1 == default_endpoint2);
+
+ DataTransferEndpoint url_endpoint1(url::Origin::Create(GURL(kExample1Url)),
+ /*notify_if_restricted=*/true);
+ DataTransferEndpoint url_endpoint2(url::Origin::Create(GURL(kExample1Url)),
+ /*notify_if_restricted=*/true);
+
+ EXPECT_TRUE(url_endpoint1 == url_endpoint2);
+}
+
+// Tests DataTransferEndpoint::IsSameOriginWith.
+TEST(DataTransferEndpointTest, IsSameOriginWith) {
+ DataTransferEndpoint default_endpoint(EndpointType::kDefault,
+ /*notify_if_restricted=*/true);
+ DataTransferEndpoint url_endpoint1(url::Origin::Create(GURL(kExample1Url)),
+ /*notify_if_restricted=*/false);
+ DataTransferEndpoint url_endpoint2(url::Origin::Create(GURL(kExample2Url)),
+ /*notify_if_restricted=*/true);
+ DataTransferEndpoint url_endpoint3(url::Origin::Create(GURL(kExample1Url)),
+ /*notify_if_restricted=*/true);
+
+ EXPECT_FALSE(url_endpoint2.IsSameOriginWith(default_endpoint));
+ EXPECT_FALSE(url_endpoint1.IsSameOriginWith(url_endpoint2));
+ EXPECT_TRUE(url_endpoint1.IsSameOriginWith(url_endpoint3));
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/data_transfer_policy/data_transfer_policy_controller.h b/chromium/ui/base/data_transfer_policy/data_transfer_policy_controller.h
index a858af9b447..6d7f7f2bd52 100644
--- a/chromium/ui/base/data_transfer_policy/data_transfer_policy_controller.h
+++ b/chromium/ui/base/data_transfer_policy/data_transfer_policy_controller.h
@@ -10,10 +10,10 @@
namespace ui {
-// The DataTransfer filter controls transferring data via drag-and-drop and
-// clipboard read operations. It allows/disallows transferring the data given
-// the source of the data and the destination trying to access the data and a
-// set of rules controlling these source and destination.
+// The DataTransfer policy controller controls transferring data via
+// drag-and-drop and clipboard read operations. It allows/disallows transferring
+// the data given the source of the data and the destination trying to access
+// the data and a set of rules controlling these source and destination.
class COMPONENT_EXPORT(UI_BASE_DATA_TRANSFER_POLICY)
DataTransferPolicyController {
public:
@@ -27,9 +27,17 @@ class COMPONENT_EXPORT(UI_BASE_DATA_TRANSFER_POLICY)
// Indicates that restricting data transfer is no longer required.
static void DeleteInstance();
- virtual bool IsDataReadAllowed(
+ // nullptr can be passed instead of `data_src` or `data_dst`. If clipboard
+ // read is not allowed, this function will show a notification to the user.
+ virtual bool IsClipboardReadAllowed(
const DataTransferEndpoint* const data_src,
- const DataTransferEndpoint* const data_dst) const = 0;
+ const DataTransferEndpoint* const data_dst) = 0;
+
+ // nullptr can be passed instead of `data_src` or `data_dst`. If dropping the
+ // data is not allowed, this function will show a notification to the user.
+ virtual bool IsDragDropAllowed(const DataTransferEndpoint* const data_src,
+ const DataTransferEndpoint* const data_dst,
+ const bool is_drop) = 0;
protected:
DataTransferPolicyController();
diff --git a/chromium/ui/base/dragdrop/drag_drop_types.cc b/chromium/ui/base/dragdrop/drag_drop_types.cc
new file mode 100644
index 00000000000..96ea4c33e2f
--- /dev/null
+++ b/chromium/ui/base/dragdrop/drag_drop_types.cc
@@ -0,0 +1,23 @@
+// Copyright 2021 The Chromium 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/dragdrop/drag_drop_types.h"
+
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
+
+namespace ui {
+
+using mojom::DragOperation;
+
+// Ensure that the DragDropTypes::DragOperation enum values stay in sync with
+// mojom::DragOperation.
+#define STATIC_ASSERT_ENUM(a, b) \
+ static_assert(static_cast<int>(a) == static_cast<int>(b), \
+ "enum mismatch: " #a)
+STATIC_ASSERT_ENUM(DragDropTypes::DRAG_NONE, DragOperation::kNone);
+STATIC_ASSERT_ENUM(DragDropTypes::DRAG_COPY, DragOperation::kCopy);
+STATIC_ASSERT_ENUM(DragDropTypes::DRAG_LINK, DragOperation::kLink);
+STATIC_ASSERT_ENUM(DragDropTypes::DRAG_MOVE, DragOperation::kMove);
+
+} // namespace ui
diff --git a/chromium/ui/base/dragdrop/drag_drop_types.h b/chromium/ui/base/dragdrop/drag_drop_types.h
index a6f049535dc..54162dda703 100644
--- a/chromium/ui/base/dragdrop/drag_drop_types.h
+++ b/chromium/ui/base/dragdrop/drag_drop_types.h
@@ -14,11 +14,15 @@ namespace ui {
class COMPONENT_EXPORT(UI_BASE) DragDropTypes {
public:
+ // These constants match their equivalents in NSDragOperation and
+ // should not be renumbered.
+ // TODO(https://crbug.com/1093536): replace this enum with
+ // ui::mojom::DragOperation.
enum DragOperation {
DRAG_NONE = 0,
- DRAG_MOVE = 1 << 0,
- DRAG_COPY = 1 << 1,
- DRAG_LINK = 1 << 2
+ DRAG_COPY = 1,
+ DRAG_LINK = 2,
+ DRAG_MOVE = 16,
};
#if defined(OS_WIN)
diff --git a/chromium/ui/base/dragdrop/file_info/BUILD.gn b/chromium/ui/base/dragdrop/file_info/BUILD.gn
deleted file mode 100644
index e443e727344..00000000000
--- a/chromium/ui/base/dragdrop/file_info/BUILD.gn
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-component("file_info") {
- defines = [ "IS_UI_BASE_DRAGDROP_FILE_INFO_IMPL" ]
- sources = [
- "file_info.cc",
- "file_info.h",
- ]
-
- deps = [ "//base" ]
-}
diff --git a/chromium/ui/base/dragdrop/file_info/file_info.cc b/chromium/ui/base/dragdrop/file_info/file_info.cc
deleted file mode 100644
index f26afad7835..00000000000
--- a/chromium/ui/base/dragdrop/file_info/file_info.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/dragdrop/file_info/file_info.h"
-
-namespace ui {
-
-FileInfo::FileInfo() = default;
-
-FileInfo::FileInfo(const base::FilePath& path,
- const base::FilePath& display_name)
- : path(path), display_name(display_name) {}
-
-FileInfo::~FileInfo() = default;
-
-bool FileInfo::operator==(const FileInfo& other) const {
- return path == other.path && display_name == other.display_name;
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/dragdrop/file_info/file_info.h b/chromium/ui/base/dragdrop/file_info/file_info.h
deleted file mode 100644
index c8ae96008f0..00000000000
--- a/chromium/ui/base/dragdrop/file_info/file_info.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_DRAGDROP_FILE_INFO_FILE_INFO_H_
-#define UI_BASE_DRAGDROP_FILE_INFO_FILE_INFO_H_
-
-#include "base/component_export.h"
-#include "base/files/file_path.h"
-
-namespace ui {
-
-// struct that bundles a file's path with an optional display name.
-struct COMPONENT_EXPORT(UI_BASE_DRAGDROP_FILE_INFO) FileInfo {
- FileInfo();
- FileInfo(const base::FilePath& path, const base::FilePath& display_name);
- ~FileInfo();
- bool operator==(const FileInfo& other) const;
-
- base::FilePath path;
- base::FilePath display_name; // Optional.
-};
-
-} // namespace ui
-
-#endif // UI_BASE_DRAGDROP_FILE_INFO_FILE_INFO_H_
diff --git a/chromium/ui/base/dragdrop/mojom/drag_drop_types.mojom b/chromium/ui/base/dragdrop/mojom/drag_drop_types.mojom
index bd378c3dd9a..bd2c81f2141 100644
--- a/chromium/ui/base/dragdrop/mojom/drag_drop_types.mojom
+++ b/chromium/ui/base/dragdrop/mojom/drag_drop_types.mojom
@@ -8,3 +8,14 @@ enum DragEventSource {
kMouse,
kTouch
};
+
+// "Verb" of a drag-and-drop operation as negotiated between the source and
+// destination.
+// These constants match their equivalents in NSDragOperation and
+// should not be renumbered.
+enum DragOperation {
+ kNone = 0,
+ kCopy = 1,
+ kLink = 2,
+ kMove = 16,
+};
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider.h b/chromium/ui/base/dragdrop/os_exchange_data_provider.h
index b398fe64fa0..32c95b457dd 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider.h
@@ -19,9 +19,9 @@
#include "base/files/file_path.h"
#include "base/strings/string16.h"
#include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/dragdrop/download_file_info.h"
#include "ui/base/dragdrop/download_file_interface.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
#include "url/gurl.h"
#if defined(USE_AURA) || defined(OS_APPLE)
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 f264b8b5eb1..98daf64f30b 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm
@@ -17,9 +17,9 @@
#include "ui/base/clipboard/clipboard_format_type.h"
#import "ui/base/clipboard/clipboard_util_mac.h"
#include "ui/base/clipboard/custom_data_helper.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
#import "ui/base/dragdrop/cocoa_dnd_util.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
#include "url/gurl.h"
@interface CrPasteboardItemWrapper : NSObject <NSPasteboardWriting>
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc
index a858abbe290..61dd3b457a7 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc
@@ -10,10 +10,11 @@
#include "base/files/file_path.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
#include "net/base/filename_util.h"
#include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "url/gurl.h"
@@ -36,6 +37,12 @@ std::unique_ptr<OSExchangeDataProvider> OSExchangeDataProviderNonBacked::Clone()
// We skip copying the drag images.
clone->html_ = html_;
clone->base_url_ = base_url_;
+ clone->source_ =
+ source_ ? std::make_unique<ui::DataTransferEndpoint>(*source_.get())
+ : nullptr;
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+ clone->originated_from_renderer_ = originated_from_renderer_;
+#endif
return clone;
}
@@ -43,13 +50,13 @@ std::unique_ptr<OSExchangeDataProvider> OSExchangeDataProviderNonBacked::Clone()
void OSExchangeDataProviderNonBacked::MarkOriginatedFromRenderer() {
// TODO(dcheng): Currently unneeded because ChromeOS Aura correctly separates
// URL and filename metadata, and does not implement the DownloadURL protocol.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
originated_from_renderer_ = true;
#endif
}
bool OSExchangeDataProviderNonBacked::DidOriginateFromRenderer() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return false;
#else
return originated_from_renderer_;
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed.h b/chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed.h
index c30cef45611..40f9bd82890 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed.h
@@ -11,7 +11,8 @@
#include "base/component_export.h"
#include "base/pickle.h"
#include "build/build_config.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
+#include "build/chromeos_buildflags.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/dragdrop/os_exchange_data_provider.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/image/image_skia.h"
@@ -110,7 +111,8 @@ class COMPONENT_EXPORT(UI_BASE) OSExchangeDataProviderNonBacked
base::string16 html_;
GURL base_url_;
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+ // For marking data originating from the renderer.
bool originated_from_renderer_ = false;
#endif
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed_unittest.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed_unittest.cc
new file mode 100644
index 00000000000..25240c6144c
--- /dev/null
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_non_backed_unittest.cc
@@ -0,0 +1,94 @@
+// Copyright 2020 The Chromium 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 "os_exchange_data_provider_non_backed.h"
+
+#include <memory>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece_forward.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "url/gurl.h"
+
+namespace ui {
+
+namespace {
+const char kTestString[] = "Hello World!";
+const char kUrl[] = "https://example.com";
+const char kUrlTitle[] = "example";
+const char kFileName[] = "file.pdf";
+const char kHtml[] = "<h1>Random Title</h1>";
+const char kBaseUrl[] = "www.example2.com";
+} // namespace
+
+// Tests that cloning OsExchangeDataProviderNonBacked object will clone all of
+// its data members.
+TEST(OSExchangeDataProviderNonBackedTest, CloneTest) {
+ OSExchangeDataProviderNonBacked original;
+
+ original.SetString(base::UTF8ToUTF16(kTestString));
+ original.SetURL(GURL(kUrl), base::UTF8ToUTF16(kUrlTitle));
+
+ base::Pickle original_pickle;
+ original_pickle.WriteString16(base::UTF8ToUTF16(kTestString));
+ original.SetPickledData(ClipboardFormatType::GetPlainTextType(),
+ original_pickle);
+ original.SetHtml(base::UTF8ToUTF16(kHtml), GURL(kBaseUrl));
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+ original.MarkOriginatedFromRenderer();
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
+ url::Origin origin(url::Origin::Create(GURL("www.example.com")));
+ original.SetSource(std::make_unique<DataTransferEndpoint>(origin));
+
+ std::unique_ptr<OSExchangeDataProvider> copy = original.Clone();
+ base::string16 copy_string;
+ EXPECT_TRUE(copy->GetString(&copy_string));
+ EXPECT_EQ(base::UTF8ToUTF16(kTestString), copy_string);
+
+ GURL copy_url;
+ base::string16 copy_title;
+ EXPECT_TRUE(copy->GetURLAndTitle(
+ FilenameToURLPolicy::DO_NOT_CONVERT_FILENAMES, &copy_url, &copy_title));
+ EXPECT_EQ(GURL(kUrl), copy_url);
+ EXPECT_EQ(base::UTF8ToUTF16(kUrlTitle), copy_title);
+
+ base::Pickle copy_pickle;
+ copy->GetPickledData(ClipboardFormatType::GetPlainTextType(), &copy_pickle);
+ base::PickleIterator pickle_itr(copy_pickle);
+ base::string16 copy_pickle_string;
+ EXPECT_TRUE(pickle_itr.ReadString16(&copy_pickle_string));
+ EXPECT_EQ(base::UTF8ToUTF16(kTestString), copy_pickle_string);
+
+ base::string16 copy_html;
+ GURL copy_base_url;
+ EXPECT_TRUE(copy->GetHtml(&copy_html, &copy_base_url));
+ EXPECT_EQ(base::UTF8ToUTF16(kHtml), copy_html);
+ EXPECT_EQ(GURL(kBaseUrl), copy_base_url);
+
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+ EXPECT_TRUE(copy->DidOriginateFromRenderer());
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
+
+ DataTransferEndpoint* data_endpoint = copy->GetSource();
+ EXPECT_TRUE(data_endpoint);
+ EXPECT_TRUE(data_endpoint->IsUrlType());
+ EXPECT_EQ(origin, *data_endpoint->origin());
+}
+
+TEST(OSExchangeDataProviderNonBackedTest, FileNameCloneTest) {
+ OSExchangeDataProviderNonBacked original;
+ original.SetFilename(base::FilePath(kFileName));
+
+ std::unique_ptr<OSExchangeDataProvider> copy = original.Clone();
+ base::FilePath copy_file_path;
+ EXPECT_TRUE(copy->GetFilename(&copy_file_path));
+ EXPECT_EQ(base::FilePath(kFileName), copy_file_path);
+}
+
+} // namespace ui \ No newline at end of file
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 516fb31fcbd..53dd7a63945 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
@@ -34,8 +34,8 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/clipboard/clipboard_util_win.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_win.h"
#include "ui/gfx/geometry/point.h"
@@ -56,8 +56,6 @@ constexpr STGMEDIUM kNullStorageMedium = {.tymed = TYMED_NULL,
STGMEDIUM CreateStorageForBytes(const void* data, size_t bytes);
template <typename T>
STGMEDIUM CreateStorageForString(const std::basic_string<T>& data);
-// Creates a new STGMEDIUM object to hold files.
-STGMEDIUM CreateStorageForFileNames(const std::vector<FileInfo>& filenames);
STGMEDIUM CreateIdListStorageForFileName(const base::FilePath& path);
// Creates a File Descriptor for the creation of a file to the given URL and
// returns a handle to it.
@@ -364,7 +362,7 @@ void OSExchangeDataProviderWin::SetFilename(const base::FilePath& path) {
void OSExchangeDataProviderWin::SetFilenames(
const std::vector<FileInfo>& filenames) {
- STGMEDIUM storage = CreateStorageForFileNames(filenames);
+ STGMEDIUM storage = ClipboardUtil::CreateStorageForFileNames(filenames);
if (storage.tymed == TYMED_NULL)
return;
@@ -678,8 +676,10 @@ void OSExchangeDataProviderWin::SetDownloadFileInfo(
// TODO(dcheng): Is it actually possible for filename to be empty here? I
// think we always synthesize one in WebContentsDragWin.
STGMEDIUM storage = kNullStorageMedium;
- if (!download->filename.empty())
- CreateStorageForFileNames({FileInfo(download->filename, base::FilePath())});
+ if (!download->filename.empty()) {
+ ClipboardUtil::CreateStorageForFileNames(
+ {FileInfo(download->filename, base::FilePath())});
+ }
// Add CF_HDROP.
auto info = DataObjectImpl::StoredDataInfo::TakeStorageMedium(
@@ -880,8 +880,8 @@ void DataObjectImpl::OnDownloadCompleted(const base::FilePath& file_path) {
if (downloader)
downloader->Stop();
// Replace stored data.
- STGMEDIUM storage =
- CreateStorageForFileNames({FileInfo(file_path, base::FilePath())});
+ STGMEDIUM storage = ClipboardUtil::CreateStorageForFileNames(
+ {FileInfo(file_path, base::FilePath())});
content = StoredDataInfo::TakeStorageMedium(
ClipboardFormatType::GetCFHDropType().ToFormatEtc(), storage);
content->downloader = std::move(downloader);
@@ -1084,52 +1084,6 @@ STGMEDIUM CreateStorageForString(const std::basic_string<T>& data) {
(data.size() + 1) * sizeof(typename std::basic_string<T>::value_type));
}
-STGMEDIUM CreateStorageForFileNames(const std::vector<FileInfo>& filenames) {
- // CF_HDROP clipboard format consists of DROPFILES structure, a series of file
- // names including the terminating null character and the additional null
- // character at the tail to terminate the array.
- // For example,
- //| DROPFILES | FILENAME 1 | NULL | ... | FILENAME n | NULL | NULL |
- // For more details, please refer to
- // https://docs.microsoft.com/en-us/windows/desktop/shell/clipboard#cf_hdrop
-
- if (filenames.empty())
- return kNullStorageMedium;
-
- const size_t kDropFilesHeaderSizeInBytes = sizeof(DROPFILES);
- size_t total_bytes = kDropFilesHeaderSizeInBytes;
- for (const auto& filename : filenames) {
- // Allocate memory of the filename's length including the null
- // character.
- total_bytes += (filename.path.value().length() + 1) * sizeof(wchar_t);
- }
- // |data| needs to be terminated by an additional null character.
- total_bytes += sizeof(wchar_t);
-
- // GHND combines GMEM_MOVEABLE and GMEM_ZEROINIT, and GMEM_ZEROINIT
- // initializes memory contents to zero.
- HANDLE hdata = GlobalAlloc(GHND, total_bytes);
-
- base::win::ScopedHGlobal<DROPFILES*> locked_mem(hdata);
- DROPFILES* drop_files = locked_mem.get();
- drop_files->pFiles = sizeof(DROPFILES);
- drop_files->fWide = TRUE;
-
- wchar_t* data = reinterpret_cast<wchar_t*>(
- reinterpret_cast<BYTE*>(drop_files) + kDropFilesHeaderSizeInBytes);
-
- size_t next_filename_offset = 0;
- for (const auto& filename : filenames) {
- wcscpy(data + next_filename_offset, filename.path.value().c_str());
- // Skip the terminating null character of the filename.
- next_filename_offset += filename.path.value().length() + 1;
- }
-
- STGMEDIUM storage = {
- .tymed = TYMED_HGLOBAL, .hGlobal = hdata, .pUnkForRelease = nullptr};
- return storage;
-}
-
LPITEMIDLIST PIDLNext(LPITEMIDLIST pidl) {
return reinterpret_cast<LPITEMIDLIST>(
reinterpret_cast<BYTE*>(pidl) + pidl->mkid.cb);
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_x11.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_x11.cc
index 8365cc492e5..419325a9ff4 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_x11.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_x11.cc
@@ -22,12 +22,12 @@ OSExchangeDataProviderX11::OSExchangeDataProviderX11(
: XOSExchangeDataProvider(x_window, selection) {}
OSExchangeDataProviderX11::OSExchangeDataProviderX11() {
- X11EventSource::GetInstance()->AddXEventDispatcher(this);
+ x11::Connection::Get()->AddEventObserver(this);
}
OSExchangeDataProviderX11::~OSExchangeDataProviderX11() {
if (own_window())
- X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+ x11::Connection::Get()->RemoveEventObserver(this);
}
std::unique_ptr<OSExchangeDataProvider> OSExchangeDataProviderX11::Clone()
@@ -38,13 +38,10 @@ std::unique_ptr<OSExchangeDataProvider> OSExchangeDataProviderX11::Clone()
return std::move(ret);
}
-bool OSExchangeDataProviderX11::DispatchXEvent(x11::Event* xev) {
- auto* selection = xev->As<x11::SelectionRequestEvent>();
- if (selection && selection->owner == x_window()) {
- selection_owner().OnSelectionRequest(*xev);
- return true;
- }
- return false;
+void OSExchangeDataProviderX11::OnEvent(const x11::Event& xev) {
+ auto* selection = xev.As<x11::SelectionRequestEvent>();
+ if (selection && selection->owner == x_window())
+ selection_owner().OnSelectionRequest(*selection);
}
void OSExchangeDataProviderX11::SetSource(
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_x11.h b/chromium/ui/base/dragdrop/os_exchange_data_provider_x11.h
index 60dac520176..a361febc3c2 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_x11.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_x11.h
@@ -7,7 +7,7 @@
#include "base/component_export.h"
#include "ui/base/x/x11_os_exchange_data_provider.h"
-#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
namespace ui {
@@ -15,7 +15,7 @@ namespace ui {
// OSExchangeDataProvider implementation for x11 linux.
class COMPONENT_EXPORT(UI_BASE) OSExchangeDataProviderX11
: public XOSExchangeDataProvider,
- public XEventDispatcher {
+ public x11::EventObserver {
public:
// |x_window| is the window the cursor is over, and |selection| is the set of
// data being offered.
@@ -35,8 +35,8 @@ class COMPONENT_EXPORT(UI_BASE) OSExchangeDataProviderX11
// OSExchangeDataProvider:
std::unique_ptr<OSExchangeDataProvider> Clone() const override;
- // XEventDispatcher:
- bool DispatchXEvent(x11::Event* xev) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& xev) override;
void SetSource(std::unique_ptr<DataTransferEndpoint> data_source) override;
DataTransferEndpoint* GetSource() const override;
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_x11_unittest.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_x11_unittest.cc
index e22500a79b9..f2de8eb58b6 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_x11_unittest.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_x11_unittest.cc
@@ -9,7 +9,7 @@
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/x11_atom_cache.h"
@@ -33,7 +33,7 @@ class OSExchangeDataProviderX11Test : public testing::Test {
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedString::TakeString(&contents_copy));
- provider.format_map_.Insert(gfx::GetAtom(kMimeTypeURIList), mem);
+ provider.format_map_.Insert(x11::GetAtom(kMimeTypeURIList), mem);
}
protected:
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc b/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
index e57cc2eb849..3c92fb07ef1 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
@@ -13,7 +13,7 @@
#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/file_info.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider.h"
#include "ui/events/platform/platform_event_source.h"
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 5e30d7560e2..e5485f63956 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc
@@ -12,6 +12,7 @@
#include "base/files/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
#include "base/win/scoped_hglobal.h"
@@ -19,7 +20,7 @@
#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/file_info.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
#include "url/gurl.h"
@@ -144,7 +145,7 @@ class OSExchangeDataWinTest : public ::testing::Test {
TEST_F(OSExchangeDataWinTest, StringDataAccessViaCOM) {
OSExchangeData data;
std::wstring input = L"O hai googlz.";
- data.SetString(input);
+ data.SetString(base::AsString16(input));
Microsoft::WRL::ComPtr<IDataObject> com_data(
OSExchangeDataProviderWin::GetIDataObject(data));
@@ -187,10 +188,10 @@ TEST_F(OSExchangeDataWinTest, StringDataWritingViaCOM) {
OSExchangeData data2(data.provider().Clone());
EXPECT_TRUE(data2.HasURL(FilenameToURLPolicy::CONVERT_FILENAMES));
GURL url_from_data;
- std::wstring title;
+ base::string16 title;
EXPECT_TRUE(data2.GetURLAndTitle(FilenameToURLPolicy::CONVERT_FILENAMES,
&url_from_data, &title));
- GURL reference_url(input);
+ GURL reference_url(base::AsStringPiece16(input));
EXPECT_EQ(reference_url.spec(), url_from_data.spec());
}
@@ -235,16 +236,16 @@ TEST_F(OSExchangeDataWinTest, RemoveData) {
OSExchangeData data2(data.provider().Clone());
EXPECT_TRUE(data2.HasURL(FilenameToURLPolicy::CONVERT_FILENAMES));
GURL url_from_data;
- std::wstring title;
+ base::string16 title;
EXPECT_TRUE(data2.GetURLAndTitle(FilenameToURLPolicy::CONVERT_FILENAMES,
&url_from_data, &title));
- EXPECT_EQ(GURL(input2).spec(), url_from_data.spec());
+ EXPECT_EQ(GURL(base::AsStringPiece16(input2)).spec(), url_from_data.spec());
}
TEST_F(OSExchangeDataWinTest, URLDataAccessViaCOM) {
OSExchangeData data;
GURL url("http://www.google.com/");
- data.SetURL(url, L"");
+ data.SetURL(url, base::string16());
Microsoft::WRL::ComPtr<IDataObject> com_data(
OSExchangeDataProviderWin::GetIDataObject(data));
@@ -265,8 +266,8 @@ TEST_F(OSExchangeDataWinTest, MultipleFormatsViaCOM) {
OSExchangeData data;
std::string url_spec = "http://www.google.com/";
GURL url(url_spec);
- std::wstring text = L"O hai googlz.";
- data.SetURL(url, L"Google");
+ base::string16 text = STRING16_LITERAL("O hai googlz.");
+ data.SetURL(url, STRING16_LITERAL("Google"));
data.SetString(text);
Microsoft::WRL::ComPtr<IDataObject> com_data(
@@ -298,8 +299,8 @@ TEST_F(OSExchangeDataWinTest, MultipleFormatsViaCOM) {
TEST_F(OSExchangeDataWinTest, EnumerationViaCOM) {
OSExchangeData data;
- data.SetURL(GURL("http://www.google.com/"), L"");
- data.SetString(L"O hai googlz.");
+ data.SetURL(GURL("http://www.google.com/"), base::string16());
+ data.SetString(STRING16_LITERAL("O hai googlz."));
CLIPFORMAT cfstr_file_group_descriptor =
RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
@@ -388,7 +389,7 @@ TEST_F(OSExchangeDataWinTest, TestURLExchangeFormatsViaCOM) {
OSExchangeData data;
std::string url_spec = "http://www.google.com/";
GURL url(url_spec);
- std::wstring url_title = L"www.google.com";
+ base::string16 url_title = STRING16_LITERAL("www.google.com");
data.SetURL(url, url_title);
// File contents access via COM
@@ -717,16 +718,15 @@ TEST_F(OSExchangeDataWinTest, VirtualFilesDuplicateNamesCaseInsensitivity) {
}
TEST_F(OSExchangeDataWinTest, VirtualFilesInvalidAndDuplicateNames) {
- const base::string16 kInvalidFileNameCharacters(
+ const std::wstring kInvalidFileNameCharacters(
FILE_PATH_LITERAL("\\/:*?\"<>|"));
- const base::string16 kInvalidFilePathCharacters(
- FILE_PATH_LITERAL("/*?\"<>|"));
+ const std::wstring kInvalidFilePathCharacters(FILE_PATH_LITERAL("/*?\"<>|"));
const base::FilePath kPathWithInvalidFileNameCharacters =
base::FilePath(kInvalidFileNameCharacters)
.AddExtension(FILE_PATH_LITERAL("txt"));
const base::FilePath kEmptyDisplayName(FILE_PATH_LITERAL(""));
const base::FilePath kMaxPathDisplayName =
- base::FilePath(base::string16(MAX_PATH - 5, L'a'))
+ base::FilePath(std::wstring(MAX_PATH - 5, L'a'))
.AddExtension(FILE_PATH_LITERAL("txt"));
const std::vector<std::pair<base::FilePath, std::string>>
@@ -762,7 +762,7 @@ TEST_F(OSExchangeDataWinTest, VirtualFilesInvalidAndDuplicateNames) {
EXPECT_EQ(kTestFilenamesAndContents.size(), file_infos.size());
for (size_t i = 0; i < file_infos.size(); i++) {
// Check that display name does not contain invalid characters.
- EXPECT_EQ(std::string::npos,
+ EXPECT_EQ(std::wstring::npos,
file_infos[i].display_name.value().find_first_of(
kInvalidFileNameCharacters));
// Check that display name is unique.
@@ -790,7 +790,7 @@ TEST_F(OSExchangeDataWinTest, VirtualFilesInvalidAndDuplicateNames) {
EXPECT_EQ(kTestFilenamesAndContents.size(), file_infos.size());
for (size_t i = 0; i < retrieved_virtual_files_.size(); i++) {
// Check that display name does not contain invalid characters.
- EXPECT_EQ(std::string::npos,
+ EXPECT_EQ(std::wstring::npos,
retrieved_virtual_files_[i].display_name.value().find_first_of(
kInvalidFileNameCharacters));
// Check that display name is unique.
@@ -801,7 +801,7 @@ TEST_F(OSExchangeDataWinTest, VirtualFilesInvalidAndDuplicateNames) {
}
// Check that temp file path does not contain invalid characters (except
// for separator).
- EXPECT_EQ(std::string::npos,
+ EXPECT_EQ(std::wstring::npos,
retrieved_virtual_files_[i].path.value().find_first_of(
kInvalidFilePathCharacters));
// Check that temp file path is unique.
@@ -903,10 +903,10 @@ TEST_F(OSExchangeDataWinTest, VirtualFilesEmptyContents) {
TEST_F(OSExchangeDataWinTest, CFHtml) {
OSExchangeData data;
GURL url("http://www.google.com/");
- std::wstring html(
- L"<HTML>\n<BODY>\n"
- L"<b>bold.</b> <i><b>This is bold italic.</b></i>\n"
- L"</BODY>\n</HTML>");
+ base::string16 html(
+ STRING16_LITERAL("<HTML>\n<BODY>\n"
+ "<b>bold.</b> <i><b>This is bold italic.</b></i>\n"
+ "</BODY>\n</HTML>"));
data.SetHtml(html, url);
// Check the CF_HTML too.
@@ -915,7 +915,7 @@ TEST_F(OSExchangeDataWinTest, CFHtml) {
"StartFragment:0000000175\r\nEndFragment:0000000252\r\n"
"SourceURL:http://www.google.com/\r\n<html>\r\n<body>\r\n"
"<!--StartFragment-->");
- expected_cf_html += base::WideToUTF8(html);
+ expected_cf_html += base::UTF16ToUTF8(html);
expected_cf_html.append("<!--EndFragment-->\r\n</body>\r\n</html>");
FORMATETC format = ClipboardFormatType::GetHtmlType().ToFormatEtc();
@@ -930,18 +930,18 @@ TEST_F(OSExchangeDataWinTest, CFHtml) {
TEST_F(OSExchangeDataWinTest, SetURLWithMaxPath) {
OSExchangeData data;
- std::wstring long_title(MAX_PATH + 1, L'a');
+ base::string16 long_title(MAX_PATH + 1, STRING16_LITERAL('a'));
data.SetURL(GURL("http://google.com"), long_title);
}
TEST_F(OSExchangeDataWinTest, ProvideURLForPlainTextURL) {
OSExchangeData data;
- data.SetString(L"http://google.com");
+ data.SetString(STRING16_LITERAL("http://google.com"));
OSExchangeData data2(data.provider().Clone());
ASSERT_TRUE(data2.HasURL(FilenameToURLPolicy::CONVERT_FILENAMES));
GURL read_url;
- std::wstring title;
+ base::string16 title;
EXPECT_TRUE(data2.GetURLAndTitle(FilenameToURLPolicy::CONVERT_FILENAMES,
&read_url, &title));
EXPECT_EQ(GURL("http://google.com"), read_url);
diff --git a/chromium/ui/base/emoji/emoji_panel_helper.h b/chromium/ui/base/emoji/emoji_panel_helper.h
index df37ef0162f..5eb33c7bbd9 100644
--- a/chromium/ui/base/emoji/emoji_panel_helper.h
+++ b/chromium/ui/base/emoji/emoji_panel_helper.h
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/component_export.h"
#include "base/macros.h"
+#include "build/chromeos_buildflags.h"
namespace ui {
@@ -18,7 +19,7 @@ COMPONENT_EXPORT(UI_BASE) bool IsEmojiPanelSupported();
// Invokes the commands to show the Emoji Panel.
COMPONENT_EXPORT(UI_BASE) void ShowEmojiPanel();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Sets a callback to show the emoji panel (ChromeOS only).
COMPONENT_EXPORT(UI_BASE)
void SetShowEmojiKeyboardCallback(base::RepeatingClosure callback);
diff --git a/chromium/ui/base/idle/BUILD.gn b/chromium/ui/base/idle/BUILD.gn
index adfd4c02bc5..2f472b5c581 100644
--- a/chromium/ui/base/idle/BUILD.gn
+++ b/chromium/ui/base/idle/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
if (is_mac) {
@@ -23,7 +24,7 @@ component("idle") {
"//ui/base",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//chromeos/dbus/session_manager" ]
}
@@ -34,7 +35,7 @@ component("idle") {
"idle_internal.h",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [ "idle_chromeos.cc" ]
}
@@ -50,11 +51,11 @@ component("idle") {
sources += [ "idle_fuchsia.cc" ]
}
- if (is_linux && !is_chromeos) {
+ if (is_linux || is_chromeos_lacros) {
sources += [ "idle_linux.cc" ]
}
- if (use_x11 && !is_chromeos) {
+ if (use_x11 && !is_chromeos_ash) {
deps += [ "//ui/base/x" ]
}
diff --git a/chromium/ui/base/idle/idle_linux.cc b/chromium/ui/base/idle/idle_linux.cc
index bd8a44d733f..3b97a45618c 100644
--- a/chromium/ui/base/idle/idle_linux.cc
+++ b/chromium/ui/base/idle/idle_linux.cc
@@ -9,6 +9,8 @@
#if defined(USE_X11)
#include "ui/base/x/x11_idle_query.h"
#include "ui/base/x/x11_screensaver_window_finder.h"
+#else
+#include "base/notreached.h"
#endif
#if defined(USE_OZONE)
diff --git a/chromium/ui/base/ime/BUILD.gn b/chromium/ui/base/ime/BUILD.gn
index 970a0527ade..194c8383e2d 100644
--- a/chromium/ui/base/ime/BUILD.gn
+++ b/chromium/ui/base/ime/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
source_set("text_input_types") {
@@ -38,7 +39,7 @@ component("ime_types") {
"//skia",
]
- if (is_chromeos || use_ozone) {
+ if (is_chromeos_ash || use_ozone) {
sources += [
"character_composer.cc",
"character_composer.h",
@@ -60,10 +61,6 @@ component("ime") {
"input_method_base.cc",
"input_method_base.h",
"input_method_delegate.h",
- "input_method_keyboard_controller.h",
- "input_method_keyboard_controller_observer.h",
- "input_method_keyboard_controller_stub.cc",
- "input_method_keyboard_controller_stub.h",
"input_method_minimal.cc",
"input_method_minimal.h",
"input_method_observer.h",
@@ -72,6 +69,10 @@ component("ime") {
"text_edit_commands.h",
"text_input_client.cc",
"text_input_client.h",
+ "virtual_keyboard_controller.h",
+ "virtual_keyboard_controller_observer.h",
+ "virtual_keyboard_controller_stub.cc",
+ "virtual_keyboard_controller_stub.h",
]
defines = [ "IS_UI_BASE_IME_IMPL" ]
@@ -91,4 +92,6 @@ component("ime") {
"//ui/gfx/geometry",
"//ui/gfx/range",
]
+
+ deps = [ "//build:chromeos_buildflags" ]
}
diff --git a/chromium/ui/base/ime/DIR_METADATA b/chromium/ui/base/ime/DIR_METADATA
index 40507e198d2..9f8d08102a4 100644
--- a/chromium/ui/base/ime/DIR_METADATA
+++ b/chromium/ui/base/ime/DIR_METADATA
@@ -7,5 +7,6 @@
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
monorail {
- component: "UI>Input>Text>IME"
-} \ No newline at end of file
+ component: "OS>Inputs" # for Chrome/Chromium OS only.
+ # For OSes other than Chrome/Chromium OS, please use "UI>Input>Text>IME".
+}
diff --git a/chromium/ui/base/ime/OWNERS b/chromium/ui/base/ime/OWNERS
index 5e184ce0640..3bf3a83c1a8 100644
--- a/chromium/ui/base/ime/OWNERS
+++ b/chromium/ui/base/ime/OWNERS
@@ -2,6 +2,7 @@
shuchen@chromium.org
yhanada@chromium.org
keithlee@chromium.org
+shend@chromium.org
# backup reviewers.
yukishiino@chromium.org
diff --git a/chromium/ui/base/ime/character_composer_unittest.cc b/chromium/ui/base/ime/character_composer_unittest.cc
index 092df61840d..5c4565c253e 100644
--- a/chromium/ui/base/ime/character_composer_unittest.cc
+++ b/chromium/ui/base/ime/character_composer_unittest.cc
@@ -8,7 +8,7 @@
#include <memory>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
diff --git a/chromium/ui/base/ime/chromeos/BUILD.gn b/chromium/ui/base/ime/chromeos/BUILD.gn
index 0d4ff07fd7d..f68783743db 100644
--- a/chromium/ui/base/ime/chromeos/BUILD.gn
+++ b/chromium/ui/base/ime/chromeos/BUILD.gn
@@ -2,7 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-assert(is_chromeos)
+import("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash)
source_set("ime_types") {
sources = [ "ime_keyset.h" ]
@@ -42,16 +44,6 @@ component("chromeos") {
"input_method_manager.h",
"input_method_util.cc",
"input_method_util.h",
- "mock_component_extension_ime_manager.cc",
- "mock_component_extension_ime_manager.h",
- "mock_component_extension_ime_manager_delegate.cc",
- "mock_component_extension_ime_manager_delegate.h",
- "mock_ime_candidate_window_handler.cc",
- "mock_ime_candidate_window_handler.h",
- "mock_ime_engine_handler.cc",
- "mock_ime_engine_handler.h",
- "mock_ime_input_context_handler.cc",
- "mock_ime_input_context_handler.h",
]
defines = [ "IS_UI_BASE_IME_CHROMEOS_IMPL" ]
@@ -64,8 +56,6 @@ component("chromeos") {
deps = [
":ime_types",
"//build:branding_buildflags",
- "//chromeos/constants",
- "//chromeos/ime:gencode",
"//chromeos/services/ime/public/mojom",
"//chromeos/system",
"//third_party/icu",
diff --git a/chromium/ui/base/ime/dummy_input_method.cc b/chromium/ui/base/ime/dummy_input_method.cc
index da32e766c9c..f1f7a2f2322 100644
--- a/chromium/ui/base/ime/dummy_input_method.cc
+++ b/chromium/ui/base/ime/dummy_input_method.cc
@@ -93,8 +93,7 @@ void DummyInputMethod::AddObserver(InputMethodObserver* observer) {
void DummyInputMethod::RemoveObserver(InputMethodObserver* observer) {
}
-InputMethodKeyboardController*
-DummyInputMethod::GetInputMethodKeyboardController() {
+VirtualKeyboardController* DummyInputMethod::GetVirtualKeyboardController() {
return nullptr;
}
diff --git a/chromium/ui/base/ime/dummy_input_method.h b/chromium/ui/base/ime/dummy_input_method.h
index fba6e76cdb2..35536b61970 100644
--- a/chromium/ui/base/ime/dummy_input_method.h
+++ b/chromium/ui/base/ime/dummy_input_method.h
@@ -47,7 +47,7 @@ class DummyInputMethod : public InputMethod {
void AddObserver(InputMethodObserver* observer) override;
void RemoveObserver(InputMethodObserver* observer) override;
- InputMethodKeyboardController* GetInputMethodKeyboardController() override;
+ VirtualKeyboardController* GetVirtualKeyboardController() override;
private:
DISALLOW_COPY_AND_ASSIGN(DummyInputMethod);
diff --git a/chromium/ui/base/ime/dummy_text_input_client.cc b/chromium/ui/base/ime/dummy_text_input_client.cc
index 14dc45935f4..38114a428c2 100644
--- a/chromium/ui/base/ime/dummy_text_input_client.cc
+++ b/chromium/ui/base/ime/dummy_text_input_client.cc
@@ -10,6 +10,7 @@
#include "base/strings/string_util.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/rect.h"
@@ -43,7 +44,9 @@ void DummyTextInputClient::ClearCompositionText() {
SetCompositionText(CompositionText());
}
-void DummyTextInputClient::InsertText(const base::string16& text) {
+void DummyTextInputClient::InsertText(
+ const base::string16& text,
+ InsertTextCursorBehavior cursor_behavior) {
insert_text_history_.push_back(text);
}
@@ -146,7 +149,7 @@ bool DummyTextInputClient::ShouldDoLearning() {
return false;
}
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
bool DummyTextInputClient::SetCompositionFromExistingText(
const gfx::Range& range,
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) {
@@ -154,7 +157,7 @@ bool DummyTextInputClient::SetCompositionFromExistingText(
}
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
gfx::Range DummyTextInputClient::GetAutocorrectRange() const {
return autocorrect_range_;
}
@@ -163,20 +166,11 @@ gfx::Rect DummyTextInputClient::GetAutocorrectCharacterBounds() const {
}
bool DummyTextInputClient::SetAutocorrectRange(
- const base::string16& autocorrect_text,
const gfx::Range& range) {
- // Clears autocorrect range if text is empty.
- // autocorrect_text content is ignored.
- if (autocorrect_text.empty()) {
- autocorrect_range_ = gfx::Range();
- } else {
- autocorrect_range_ = range;
- }
+ autocorrect_range_ = range;
return true;
}
-void DummyTextInputClient::ClearAutocorrectRange() {}
-
#endif
#if defined(OS_WIN)
diff --git a/chromium/ui/base/ime/dummy_text_input_client.h b/chromium/ui/base/ime/dummy_text_input_client.h
index ac615643367..d686a4741d3 100644
--- a/chromium/ui/base/ime/dummy_text_input_client.h
+++ b/chromium/ui/base/ime/dummy_text_input_client.h
@@ -10,11 +10,13 @@
#include "base/macros.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/ime/text_input_client.h"
namespace ui {
// Dummy implementation of TextInputClient. All functions do nothing.
+// TODO(crbug.com/1148157): Replace this class with FakeTextInputClient.
class DummyTextInputClient : public TextInputClient {
public:
DummyTextInputClient();
@@ -27,7 +29,8 @@ class DummyTextInputClient : public TextInputClient {
void SetCompositionText(const CompositionText& composition) override;
uint32_t ConfirmCompositionText(bool keep_selection) override;
void ClearCompositionText() override;
- void InsertText(const base::string16& text) override;
+ void InsertText(const base::string16& text,
+ InsertTextCursorBehavior cursor_behavior) override;
void InsertChar(const KeyEvent& event) override;
TextInputType GetTextInputType() const override;
TextInputMode GetTextInputMode() const override;
@@ -56,18 +59,16 @@ class DummyTextInputClient : public TextInputClient {
ukm::SourceId GetClientSourceForMetrics() const override;
bool ShouldDoLearning() override;
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
bool SetCompositionFromExistingText(
const gfx::Range& range,
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
gfx::Range GetAutocorrectRange() const override;
gfx::Rect GetAutocorrectCharacterBounds() const override;
- bool SetAutocorrectRange(const base::string16& autocorrect_text,
- const gfx::Range& range) override;
- void ClearAutocorrectRange() override;
+ bool SetAutocorrectRange(const gfx::Range& range) override;
#endif
#if defined(OS_WIN)
diff --git a/chromium/ui/base/ime/fake_text_input_client.cc b/chromium/ui/base/ime/fake_text_input_client.cc
new file mode 100644
index 00000000000..647dbec8a0f
--- /dev/null
+++ b/chromium/ui/base/ime/fake_text_input_client.cc
@@ -0,0 +1,183 @@
+// Copyright 2020 The Chromium 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/ime/fake_text_input_client.h"
+
+#include "base/check_op.h"
+#include "build/chromeos_buildflags.h"
+#include "ui/events/event_constants.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace ui {
+
+FakeTextInputClient::FakeTextInputClient(TextInputType text_input_type)
+ : text_input_type_(text_input_type) {}
+
+FakeTextInputClient::~FakeTextInputClient() = default;
+
+void FakeTextInputClient::set_text_input_type(TextInputType text_input_type) {
+ text_input_type_ = text_input_type;
+}
+
+void FakeTextInputClient::SetTextAndSelection(const base::string16& text,
+ gfx::Range selection) {
+ DCHECK_LE(selection_.end(), text.length());
+ text_ = text;
+ selection_ = selection;
+}
+
+void FakeTextInputClient::SetCompositionText(
+ const CompositionText& composition) {}
+
+uint32_t FakeTextInputClient::ConfirmCompositionText(bool keep_selection) {
+ return UINT32_MAX;
+}
+
+void FakeTextInputClient::ClearCompositionText() {}
+
+void FakeTextInputClient::InsertText(
+ const base::string16& text,
+ TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ text_.insert(selection_.start(), text);
+
+ if (cursor_behavior ==
+ TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText) {
+ selection_ = gfx::Range(selection_.start() + text.length(),
+ selection_.end() + text.length());
+ }
+}
+
+void FakeTextInputClient::InsertChar(const KeyEvent& event) {}
+
+TextInputType FakeTextInputClient::GetTextInputType() const {
+ return text_input_type_;
+}
+
+TextInputMode FakeTextInputClient::GetTextInputMode() const {
+ return TEXT_INPUT_MODE_NONE;
+}
+
+base::i18n::TextDirection FakeTextInputClient::GetTextDirection() const {
+ return base::i18n::UNKNOWN_DIRECTION;
+}
+
+int FakeTextInputClient::GetTextInputFlags() const {
+ return EF_NONE;
+}
+
+bool FakeTextInputClient::CanComposeInline() const {
+ return false;
+}
+
+gfx::Rect FakeTextInputClient::GetCaretBounds() const {
+ return {};
+}
+
+bool FakeTextInputClient::GetCompositionCharacterBounds(uint32_t index,
+ gfx::Rect* rect) const {
+ return false;
+}
+
+bool FakeTextInputClient::HasCompositionText() const {
+ return false;
+}
+
+ui::TextInputClient::FocusReason FakeTextInputClient::GetFocusReason() const {
+ return ui::TextInputClient::FOCUS_REASON_NONE;
+}
+
+bool FakeTextInputClient::GetTextRange(gfx::Range* range) const {
+ *range = gfx::Range(0, text_.length());
+ return true;
+}
+
+bool FakeTextInputClient::GetCompositionTextRange(gfx::Range* range) const {
+ return false;
+}
+
+bool FakeTextInputClient::GetEditableSelectionRange(gfx::Range* range) const {
+ *range = selection_;
+ return true;
+}
+
+bool FakeTextInputClient::SetEditableSelectionRange(const gfx::Range& range) {
+ return false;
+}
+
+bool FakeTextInputClient::DeleteRange(const gfx::Range& range) {
+ return false;
+}
+
+bool FakeTextInputClient::GetTextFromRange(const gfx::Range& range,
+ base::string16* text) const {
+ return false;
+}
+
+void FakeTextInputClient::OnInputMethodChanged() {}
+
+bool FakeTextInputClient::ChangeTextDirectionAndLayoutAlignment(
+ base::i18n::TextDirection direction) {
+ return false;
+}
+
+void FakeTextInputClient::ExtendSelectionAndDelete(size_t before,
+ size_t after) {}
+
+void FakeTextInputClient::EnsureCaretNotInRect(const gfx::Rect& rect) {}
+
+bool FakeTextInputClient::IsTextEditCommandEnabled(
+ TextEditCommand command) const {
+ return false;
+}
+
+void FakeTextInputClient::SetTextEditCommandForNextKeyEvent(
+ TextEditCommand command) {}
+
+ukm::SourceId FakeTextInputClient::GetClientSourceForMetrics() const {
+ return {};
+}
+
+bool FakeTextInputClient::ShouldDoLearning() {
+ return false;
+}
+
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
+bool FakeTextInputClient::SetCompositionFromExistingText(
+ const gfx::Range& range,
+ const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) {
+ if (range.start() < 0 || range.end() > text_.length())
+ return false;
+
+ composition_range_ = range;
+ ime_text_spans_ = ui_ime_text_spans;
+ return true;
+}
+#endif
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+gfx::Range FakeTextInputClient::GetAutocorrectRange() const {
+ return {};
+}
+
+gfx::Rect FakeTextInputClient::GetAutocorrectCharacterBounds() const {
+ return {};
+}
+
+bool FakeTextInputClient::SetAutocorrectRange(const gfx::Range& range) {
+ return false;
+}
+#endif
+
+#if defined(OS_WIN)
+void FakeTextInputClient::GetActiveTextInputControlLayoutBounds(
+ base::Optional<gfx::Rect>* control_bounds,
+ base::Optional<gfx::Rect>* selection_bounds) {}
+
+void FakeTextInputClient::SetActiveCompositionForAccessibility(
+ const gfx::Range& range,
+ const base::string16& active_composition_text,
+ bool is_composition_committed) {}
+#endif
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/fake_text_input_client.h b/chromium/ui/base/ime/fake_text_input_client.h
new file mode 100644
index 00000000000..fbf2c6bd532
--- /dev/null
+++ b/chromium/ui/base/ime/fake_text_input_client.h
@@ -0,0 +1,101 @@
+// Copyright 2020 The Chromium 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_IME_FAKE_TEXT_INPUT_CLIENT_H_
+#define UI_BASE_IME_FAKE_TEXT_INPUT_CLIENT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
+#include "ui/base/ime/text_input_client.h"
+
+namespace ui {
+
+// Fake in-memory implementation of TextInputClient used for testing.
+// This class should act as a 'reference implementation' for TextInputClient.
+class FakeTextInputClient : public TextInputClient {
+ public:
+ explicit FakeTextInputClient(TextInputType text_input_type);
+ FakeTextInputClient(const FakeTextInputClient& other) = delete;
+ FakeTextInputClient& operator=(const FakeTextInputClient& other) = delete;
+ ~FakeTextInputClient() override;
+
+ void set_text_input_type(TextInputType text_input_type);
+ void SetTextAndSelection(const base::string16& text, gfx::Range selection);
+
+ const base::string16& text() const { return text_; }
+ const gfx::Range& selection() const { return selection_; }
+ const gfx::Range& composition_range() const { return composition_range_; }
+ const std::vector<ui::ImeTextSpan>& ime_text_spans() const {
+ return ime_text_spans_;
+ }
+
+ // TextInputClient:
+ void SetCompositionText(const CompositionText& composition) override;
+ uint32_t ConfirmCompositionText(bool keep_selection) override;
+ void ClearCompositionText() override;
+ void InsertText(
+ const base::string16& text,
+ TextInputClient::InsertTextCursorBehavior cursor_behavior) override;
+ void InsertChar(const KeyEvent& event) override;
+ TextInputType GetTextInputType() const override;
+ TextInputMode GetTextInputMode() const override;
+ base::i18n::TextDirection GetTextDirection() const override;
+ int GetTextInputFlags() const override;
+ bool CanComposeInline() const override;
+ gfx::Rect GetCaretBounds() const override;
+ bool GetCompositionCharacterBounds(uint32_t index,
+ gfx::Rect* rect) const override;
+ bool HasCompositionText() const override;
+ ui::TextInputClient::FocusReason GetFocusReason() const override;
+ bool GetTextRange(gfx::Range* range) const override;
+ bool GetCompositionTextRange(gfx::Range* range) const 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;
+ void OnInputMethodChanged() override;
+ bool ChangeTextDirectionAndLayoutAlignment(
+ base::i18n::TextDirection direction) override;
+ void ExtendSelectionAndDelete(size_t before, size_t after) override;
+ void EnsureCaretNotInRect(const gfx::Rect& rect) override;
+ bool IsTextEditCommandEnabled(TextEditCommand command) const override;
+ void SetTextEditCommandForNextKeyEvent(TextEditCommand command) override;
+ ukm::SourceId GetClientSourceForMetrics() const override;
+ bool ShouldDoLearning() override;
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
+ bool SetCompositionFromExistingText(
+ const gfx::Range& range,
+ const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
+#endif
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ gfx::Range GetAutocorrectRange() const override;
+ gfx::Rect GetAutocorrectCharacterBounds() const override;
+ bool SetAutocorrectRange(const gfx::Range& range) override;
+#endif
+#if defined(OS_WIN)
+ void GetActiveTextInputControlLayoutBounds(
+ base::Optional<gfx::Rect>* control_bounds,
+ base::Optional<gfx::Rect>* selection_bounds) override;
+ void SetActiveCompositionForAccessibility(
+ const gfx::Range& range,
+ const base::string16& active_composition_text,
+ bool is_composition_committed) override;
+#endif
+
+ private:
+ TextInputType text_input_type_;
+ base::string16 text_;
+ gfx::Range selection_;
+ gfx::Range composition_range_;
+ std::vector<ui::ImeTextSpan> ime_text_spans_;
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_FAKE_TEXT_INPUT_CLIENT_H_
diff --git a/chromium/ui/base/ime/fuchsia/BUILD.gn b/chromium/ui/base/ime/fuchsia/BUILD.gn
index 2fb3d45ba28..e4a1e8ece6d 100644
--- a/chromium/ui/base/ime/fuchsia/BUILD.gn
+++ b/chromium/ui/base/ime/fuchsia/BUILD.gn
@@ -10,14 +10,15 @@ component("fuchsia") {
sources = [
"input_method_fuchsia.cc",
"input_method_fuchsia.h",
- "input_method_keyboard_controller_fuchsia.cc",
- "input_method_keyboard_controller_fuchsia.h",
+ "virtual_keyboard_controller_fuchsia.cc",
+ "virtual_keyboard_controller_fuchsia.h",
]
defines = [ "IS_UI_BASE_IME_FUCHSIA_IMPL" ]
public_deps = [
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.input",
+ "//third_party/fuchsia-sdk/sdk/pkg/scenic_cpp",
"//third_party/fuchsia-sdk/sdk/pkg/sys_cpp",
"//ui/base/ime",
"//ui/events",
diff --git a/chromium/ui/base/ime/fuchsia/input_method_fuchsia.cc b/chromium/ui/base/ime/fuchsia/input_method_fuchsia.cc
index 9959fa3d031..5b6b97dde06 100644
--- a/chromium/ui/base/ime/fuchsia/input_method_fuchsia.cc
+++ b/chromium/ui/base/ime/fuchsia/input_method_fuchsia.cc
@@ -18,7 +18,7 @@
namespace ui {
InputMethodFuchsia::InputMethodFuchsia(internal::InputMethodDelegate* delegate,
- gfx::AcceleratedWidget widget)
+ fuchsia::ui::views::ViewRef view_ref)
: InputMethodBase(delegate),
event_converter_(this),
ime_client_binding_(this),
@@ -29,8 +29,7 @@ InputMethodFuchsia::InputMethodFuchsia(internal::InputMethodDelegate* delegate,
InputMethodFuchsia::~InputMethodFuchsia() {}
-InputMethodKeyboardController*
-InputMethodFuchsia::GetInputMethodKeyboardController() {
+VirtualKeyboardController* InputMethodFuchsia::GetVirtualKeyboardController() {
return &virtual_keyboard_controller_;
}
diff --git a/chromium/ui/base/ime/fuchsia/input_method_fuchsia.h b/chromium/ui/base/ime/fuchsia/input_method_fuchsia.h
index e0d8e8b6a77..52aa48db4e7 100644
--- a/chromium/ui/base/ime/fuchsia/input_method_fuchsia.h
+++ b/chromium/ui/base/ime/fuchsia/input_method_fuchsia.h
@@ -7,11 +7,12 @@
#include <fuchsia/ui/input/cpp/fidl.h>
#include <lib/fidl/cpp/binding.h>
+#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include <memory>
#include "base/component_export.h"
#include "base/macros.h"
-#include "ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.h"
+#include "ui/base/ime/fuchsia/virtual_keyboard_controller_fuchsia.h"
#include "ui/base/ime/input_method_base.h"
#include "ui/base/ime/input_method_delegate.h"
#include "ui/events/fuchsia/input_event_dispatcher.h"
@@ -27,7 +28,7 @@ class COMPONENT_EXPORT(UI_BASE_IME_FUCHSIA) InputMethodFuchsia
public fuchsia::ui::input::InputMethodEditorClient {
public:
InputMethodFuchsia(internal::InputMethodDelegate* delegate,
- gfx::AcceleratedWidget widget);
+ fuchsia::ui::views::ViewRef view_ref);
~InputMethodFuchsia() override;
fuchsia::ui::input::ImeService* ime_service() const {
@@ -35,7 +36,7 @@ class COMPONENT_EXPORT(UI_BASE_IME_FUCHSIA) InputMethodFuchsia
}
// InputMethodBase interface implementation.
- InputMethodKeyboardController* GetInputMethodKeyboardController() override;
+ VirtualKeyboardController* GetVirtualKeyboardController() override;
ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* event) override;
void OnCaretBoundsChanged(const TextInputClient* client) override;
void CancelComposition(const TextInputClient* client) override;
@@ -67,7 +68,7 @@ class COMPONENT_EXPORT(UI_BASE_IME_FUCHSIA) InputMethodFuchsia
fuchsia::ui::input::ImeServicePtr ime_service_;
fuchsia::ui::input::InputMethodEditorPtr ime_;
fuchsia::ui::input::ImeVisibilityServicePtr ime_visibility_;
- InputMethodKeyboardControllerFuchsia virtual_keyboard_controller_;
+ VirtualKeyboardControllerFuchsia virtual_keyboard_controller_;
DISALLOW_COPY_AND_ASSIGN(InputMethodFuchsia);
};
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
deleted file mode 100644
index 32cf15ef5a8..00000000000
--- a/chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.h
+++ /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.
-
-#ifndef UI_BASE_IME_FUCHSIA_INPUT_METHOD_KEYBOARD_CONTROLLER_FUCHSIA_H_
-#define UI_BASE_IME_FUCHSIA_INPUT_METHOD_KEYBOARD_CONTROLLER_FUCHSIA_H_
-
-#include <fuchsia/ui/input/cpp/fidl.h>
-
-#include "base/component_export.h"
-#include "base/macros.h"
-#include "ui/base/ime/input_method_keyboard_controller.h"
-
-namespace ui {
-
-// Manages visibility of the onscreen keyboard.
-class COMPONENT_EXPORT(UI_BASE_IME) InputMethodKeyboardControllerFuchsia
- : public InputMethodKeyboardController {
- public:
- // |ime_service| must outlive |this|.
- explicit InputMethodKeyboardControllerFuchsia(
- fuchsia::ui::input::ImeService* ime_service);
-
- ~InputMethodKeyboardControllerFuchsia() override;
-
- // InputMethodKeyboardController implementation.
- bool DisplayVirtualKeyboard() override;
- void DismissVirtualKeyboard() override;
- void AddObserver(InputMethodKeyboardControllerObserver* observer) override;
- void RemoveObserver(InputMethodKeyboardControllerObserver* observer) override;
- bool IsKeyboardVisible() override;
-
- private:
- fuchsia::ui::input::ImeService* const ime_service_;
- fuchsia::ui::input::ImeVisibilityServicePtr ime_visibility_;
- bool keyboard_visible_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(InputMethodKeyboardControllerFuchsia);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_IME_FUCHSIA_INPUT_METHOD_KEYBOARD_CONTROLLER_FUCHSIA_H_
diff --git a/chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc b/chromium/ui/base/ime/fuchsia/virtual_keyboard_controller_fuchsia.cc
index a99e7298aeb..f5d113048c2 100644
--- a/chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc
+++ b/chromium/ui/base/ime/fuchsia/virtual_keyboard_controller_fuchsia.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.h"
+#include "ui/base/ime/fuchsia/virtual_keyboard_controller_fuchsia.h"
#include <lib/sys/cpp/component_context.h>
#include <utility>
@@ -14,7 +14,7 @@
namespace ui {
-InputMethodKeyboardControllerFuchsia::InputMethodKeyboardControllerFuchsia(
+VirtualKeyboardControllerFuchsia::VirtualKeyboardControllerFuchsia(
fuchsia::ui::input::ImeService* ime_service)
: ime_service_(ime_service),
ime_visibility_(
@@ -32,29 +32,28 @@ InputMethodKeyboardControllerFuchsia::InputMethodKeyboardControllerFuchsia(
};
}
-InputMethodKeyboardControllerFuchsia::~InputMethodKeyboardControllerFuchsia() =
- default;
+VirtualKeyboardControllerFuchsia::~VirtualKeyboardControllerFuchsia() = default;
-bool InputMethodKeyboardControllerFuchsia::DisplayVirtualKeyboard() {
+bool VirtualKeyboardControllerFuchsia::DisplayVirtualKeyboard() {
ime_service_->ShowKeyboard();
return true;
}
-void InputMethodKeyboardControllerFuchsia::DismissVirtualKeyboard() {
+void VirtualKeyboardControllerFuchsia::DismissVirtualKeyboard() {
ime_service_->HideKeyboard();
}
-void InputMethodKeyboardControllerFuchsia::AddObserver(
- InputMethodKeyboardControllerObserver* observer) {
+void VirtualKeyboardControllerFuchsia::AddObserver(
+ VirtualKeyboardControllerObserver* observer) {
NOTIMPLEMENTED();
}
-void InputMethodKeyboardControllerFuchsia::RemoveObserver(
- InputMethodKeyboardControllerObserver* observer) {
+void VirtualKeyboardControllerFuchsia::RemoveObserver(
+ VirtualKeyboardControllerObserver* observer) {
NOTIMPLEMENTED();
}
-bool InputMethodKeyboardControllerFuchsia::IsKeyboardVisible() {
+bool VirtualKeyboardControllerFuchsia::IsKeyboardVisible() {
return keyboard_visible_;
}
diff --git a/chromium/ui/base/ime/fuchsia/virtual_keyboard_controller_fuchsia.h b/chromium/ui/base/ime/fuchsia/virtual_keyboard_controller_fuchsia.h
new file mode 100644
index 00000000000..f4118cd1d01
--- /dev/null
+++ b/chromium/ui/base/ime/fuchsia/virtual_keyboard_controller_fuchsia.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_BASE_IME_FUCHSIA_VIRTUAL_KEYBOARD_CONTROLLER_FUCHSIA_H_
+#define UI_BASE_IME_FUCHSIA_VIRTUAL_KEYBOARD_CONTROLLER_FUCHSIA_H_
+
+#include <fuchsia/ui/input/cpp/fidl.h>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "ui/base/ime/virtual_keyboard_controller.h"
+
+namespace ui {
+
+// Manages visibility of the onscreen keyboard.
+class COMPONENT_EXPORT(UI_BASE_IME) VirtualKeyboardControllerFuchsia
+ : public VirtualKeyboardController {
+ public:
+ // |ime_service| must outlive |this|.
+ explicit VirtualKeyboardControllerFuchsia(
+ fuchsia::ui::input::ImeService* ime_service);
+
+ ~VirtualKeyboardControllerFuchsia() override;
+
+ // VirtualKeyboardController implementation.
+ bool DisplayVirtualKeyboard() override;
+ void DismissVirtualKeyboard() override;
+ void AddObserver(VirtualKeyboardControllerObserver* observer) override;
+ void RemoveObserver(VirtualKeyboardControllerObserver* observer) override;
+ bool IsKeyboardVisible() override;
+
+ private:
+ fuchsia::ui::input::ImeService* const ime_service_;
+ fuchsia::ui::input::ImeVisibilityServicePtr ime_visibility_;
+ bool keyboard_visible_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardControllerFuchsia);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_FUCHSIA_VIRTUAL_KEYBOARD_CONTROLLER_FUCHSIA_H_
diff --git a/chromium/ui/base/ime/init/BUILD.gn b/chromium/ui/base/ime/init/BUILD.gn
index dd772acb8ec..28dda76ff0d 100644
--- a/chromium/ui/base/ime/init/BUILD.gn
+++ b/chromium/ui/base/ime/init/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
component("init") {
@@ -22,7 +23,10 @@ component("init") {
"//ui/gfx:native_widget_types",
]
- deps = [ "//ui/base" ]
+ deps = [
+ "//build:chromeos_buildflags",
+ "//ui/base",
+ ]
if (is_win) {
deps += [ "//ui/base/ime/win" ]
@@ -30,10 +34,10 @@ component("init") {
if (is_mac) {
deps += [ "//ui/base/ime/mac" ]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//ui/base/ime/chromeos" ]
}
- if (is_linux && !is_chromeos) {
+ if (is_linux || is_chromeos_lacros) {
deps += [ "//ui/base/ime/linux" ]
}
if (use_ozone) {
diff --git a/chromium/ui/base/ime/init/input_method_initializer.cc b/chromium/ui/base/ime/init/input_method_initializer.cc
index 92d616a16f9..00c863a7271 100644
--- a/chromium/ui/base/ime/init/input_method_initializer.cc
+++ b/chromium/ui/base/ime/init/input_method_initializer.cc
@@ -7,10 +7,11 @@
#include <ostream>
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/base/ime/chromeos/ime_bridge.h"
-#elif defined(USE_AURA) && defined(OS_LINUX)
+#elif defined(USE_AURA) && (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
#include "base/check.h"
#include "ui/base/ime/linux/fake_input_method_context_factory.h"
#elif defined(OS_WIN)
@@ -20,7 +21,7 @@
namespace {
-#if !defined(OS_CHROMEOS) && defined(USE_AURA) && defined(OS_LINUX)
+#if defined(USE_AURA) && (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
const ui::LinuxInputMethodContextFactory*
g_linux_input_method_context_factory_for_testing;
#endif
@@ -30,7 +31,7 @@ const ui::LinuxInputMethodContextFactory*
namespace ui {
void InitializeInputMethod() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IMEBridge::Initialize();
#elif defined(OS_WIN)
TSFBridge::Initialize();
@@ -38,7 +39,7 @@ void InitializeInputMethod() {
}
void ShutdownInputMethod() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IMEBridge::Shutdown();
#elif defined(OS_WIN)
TSFBridge::Shutdown();
@@ -46,9 +47,9 @@ void ShutdownInputMethod() {
}
void InitializeInputMethodForTesting() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IMEBridge::Initialize();
-#elif defined(USE_AURA) && defined(OS_LINUX)
+#elif defined(USE_AURA) && (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
if (!g_linux_input_method_context_factory_for_testing)
g_linux_input_method_context_factory_for_testing =
new FakeInputMethodContextFactory();
@@ -65,9 +66,9 @@ void InitializeInputMethodForTesting() {
}
void ShutdownInputMethodForTesting() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IMEBridge::Shutdown();
-#elif defined(USE_AURA) && defined(OS_LINUX)
+#elif defined(USE_AURA) && (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
const LinuxInputMethodContextFactory* factory =
LinuxInputMethodContextFactory::instance();
CHECK(!factory || factory == g_linux_input_method_context_factory_for_testing)
diff --git a/chromium/ui/base/ime/input_method.h b/chromium/ui/base/ime/input_method.h
index 9ead7fa666e..0b91ccb01bb 100644
--- a/chromium/ui/base/ime/input_method.h
+++ b/chromium/ui/base/ime/input_method.h
@@ -24,7 +24,7 @@ namespace internal {
class InputMethodDelegate;
} // namespace internal
-class InputMethodKeyboardController;
+class VirtualKeyboardController;
class InputMethodObserver;
class KeyEvent;
class TextInputClient;
@@ -167,7 +167,7 @@ class InputMethod {
virtual void SetOnScreenKeyboardBounds(const gfx::Rect& new_bounds) {}
// Return the keyboard controller; used only on Windows.
- virtual InputMethodKeyboardController* GetInputMethodKeyboardController() = 0;
+ virtual VirtualKeyboardController* GetVirtualKeyboardController() = 0;
};
} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_base.cc b/chromium/ui/base/ime/input_method_base.cc
index 36a615a58b4..40245cc4261 100644
--- a/chromium/ui/base/ime/input_method_base.cc
+++ b/chromium/ui/base/ime/input_method_base.cc
@@ -10,9 +10,9 @@
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "ui/base/ime/input_method_delegate.h"
-#include "ui/base/ime/input_method_keyboard_controller_stub.h"
#include "ui/base/ime/input_method_observer.h"
#include "ui/base/ime/text_input_client.h"
+#include "ui/base/ime/virtual_keyboard_controller_stub.h"
#include "ui/events/event.h"
namespace ui {
@@ -22,7 +22,7 @@ InputMethodBase::InputMethodBase(internal::InputMethodDelegate* delegate)
InputMethodBase::InputMethodBase(
internal::InputMethodDelegate* delegate,
- std::unique_ptr<InputMethodKeyboardController> keyboard_controller)
+ std::unique_ptr<VirtualKeyboardController> keyboard_controller)
: delegate_(delegate),
keyboard_controller_(std::move(keyboard_controller)) {}
@@ -110,7 +110,7 @@ bool InputMethodBase::GetClientShouldDoLearning() {
void InputMethodBase::ShowVirtualKeyboardIfEnabled() {
for (InputMethodObserver& observer : observer_list_)
observer.OnShowVirtualKeyboardIfEnabled();
- if (auto* keyboard = GetInputMethodKeyboardController())
+ if (auto* keyboard = GetVirtualKeyboardController())
keyboard->DisplayVirtualKeyboard();
}
@@ -122,8 +122,7 @@ void InputMethodBase::RemoveObserver(InputMethodObserver* observer) {
observer_list_.RemoveObserver(observer);
}
-InputMethodKeyboardController*
-InputMethodBase::GetInputMethodKeyboardController() {
+VirtualKeyboardController* InputMethodBase::GetVirtualKeyboardController() {
return keyboard_controller_.get();
}
diff --git a/chromium/ui/base/ime/input_method_base.h b/chromium/ui/base/ime/input_method_base.h
index 70edaa143dc..3c0d1a4c98f 100644
--- a/chromium/ui/base/ime/input_method_base.h
+++ b/chromium/ui/base/ime/input_method_base.h
@@ -68,12 +68,12 @@ class COMPONENT_EXPORT(UI_BASE_IME) InputMethodBase
void AddObserver(InputMethodObserver* observer) override;
void RemoveObserver(InputMethodObserver* observer) override;
- InputMethodKeyboardController* GetInputMethodKeyboardController() override;
+ VirtualKeyboardController* GetVirtualKeyboardController() override;
protected:
explicit InputMethodBase(internal::InputMethodDelegate* delegate);
InputMethodBase(internal::InputMethodDelegate* delegate,
- std::unique_ptr<InputMethodKeyboardController> controller);
+ std::unique_ptr<VirtualKeyboardController> controller);
virtual void OnWillChangeFocusedClient(TextInputClient* focused_before,
TextInputClient* focused) {}
@@ -124,7 +124,7 @@ class COMPONENT_EXPORT(UI_BASE_IME) InputMethodBase
// Screen bounds of a on-screen keyboard.
gfx::Rect keyboard_bounds_;
- std::unique_ptr<InputMethodKeyboardController> const keyboard_controller_;
+ std::unique_ptr<VirtualKeyboardController> const keyboard_controller_;
DISALLOW_COPY_AND_ASSIGN(InputMethodBase);
};
diff --git a/chromium/ui/base/ime/input_method_base_unittest.cc b/chromium/ui/base/ime/input_method_base_unittest.cc
index 62b02b48c47..6c252435676 100644
--- a/chromium/ui/base/ime/input_method_base_unittest.cc
+++ b/chromium/ui/base/ime/input_method_base_unittest.cc
@@ -9,7 +9,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/run_loop.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/ime/dummy_text_input_client.h"
@@ -172,8 +172,8 @@ class MockInputMethodObserver : public InputMethodObserver {
DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver);
};
-typedef ScopedObserver<InputMethod, InputMethodObserver>
- InputMethodScopedObserver;
+typedef base::ScopedObservation<InputMethod, InputMethodObserver>
+ InputMethodScopedObservation;
void SetFocusedTextInputClient(InputMethod* input_method,
TextInputClient* text_input_client) {
@@ -187,8 +187,8 @@ TEST_F(InputMethodBaseTest, SetFocusedTextInputClient) {
ClientChangeVerifier verifier;
MockInputMethodBase input_method(&verifier);
MockInputMethodObserver input_method_observer(&verifier);
- InputMethodScopedObserver scoped_observer(&input_method_observer);
- scoped_observer.Add(&input_method);
+ InputMethodScopedObservation scoped_observation(&input_method_observer);
+ scoped_observation.Observe(&input_method);
// Assume that the top-level-widget gains focus.
input_method.OnFocus();
@@ -246,8 +246,8 @@ TEST_F(InputMethodBaseTest, DetachTextInputClient) {
ClientChangeVerifier verifier;
MockInputMethodBase input_method(&verifier);
MockInputMethodObserver input_method_observer(&verifier);
- InputMethodScopedObserver scoped_observer(&input_method_observer);
- scoped_observer.Add(&input_method);
+ InputMethodScopedObservation scoped_observation(&input_method_observer);
+ scoped_observation.Observe(&input_method);
// Assume that the top-level-widget gains focus.
input_method.OnFocus();
diff --git a/chromium/ui/base/ime/input_method_keyboard_controller_stub.cc b/chromium/ui/base/ime/input_method_keyboard_controller_stub.cc
deleted file mode 100644
index 3f865435f42..00000000000
--- a/chromium/ui/base/ime/input_method_keyboard_controller_stub.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/ime/input_method_keyboard_controller_stub.h"
-
-namespace ui {
-
-// InputMethodKeyboardControllerStub member definitions.
-InputMethodKeyboardControllerStub::InputMethodKeyboardControllerStub() {}
-
-InputMethodKeyboardControllerStub::~InputMethodKeyboardControllerStub() {}
-
-bool InputMethodKeyboardControllerStub::DisplayVirtualKeyboard() {
- return false;
-}
-
-void InputMethodKeyboardControllerStub::DismissVirtualKeyboard() {}
-
-void InputMethodKeyboardControllerStub::AddObserver(
- InputMethodKeyboardControllerObserver* observer) {}
-
-void InputMethodKeyboardControllerStub::RemoveObserver(
- InputMethodKeyboardControllerObserver* observer) {}
-
-bool InputMethodKeyboardControllerStub::IsKeyboardVisible() {
- return false;
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_keyboard_controller_stub.h b/chromium/ui/base/ime/input_method_keyboard_controller_stub.h
deleted file mode 100644
index 2dfcd7c91a2..00000000000
--- a/chromium/ui/base/ime/input_method_keyboard_controller_stub.h
+++ /dev/null
@@ -1,34 +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_BASE_IME_INPUT_METHOD_KEYBOARD_CONTROLLER_STUB_H_
-#define UI_BASE_IME_INPUT_METHOD_KEYBOARD_CONTROLLER_STUB_H_
-
-#include "base/component_export.h"
-#include "base/macros.h"
-#include "ui/base/ime/input_method_keyboard_controller.h"
-
-namespace ui {
-
-// This class provides a stub InputMethodKeyboardController.
-class COMPONENT_EXPORT(UI_BASE_IME) InputMethodKeyboardControllerStub final
- : public InputMethodKeyboardController {
- public:
- InputMethodKeyboardControllerStub();
- ~InputMethodKeyboardControllerStub() override;
-
- // InputMethodKeyboardController overrides.
- bool DisplayVirtualKeyboard() override;
- void DismissVirtualKeyboard() override;
- void AddObserver(InputMethodKeyboardControllerObserver* observer) override;
- void RemoveObserver(InputMethodKeyboardControllerObserver* observer) override;
- bool IsKeyboardVisible() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InputMethodKeyboardControllerStub);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_IME_INPUT_METHOD_KEYBOARD_CONTROLLER_STUB_H_
diff --git a/chromium/ui/base/ime/linux/BUILD.gn b/chromium/ui/base/ime/linux/BUILD.gn
index aee5960f688..672a47ae34b 100644
--- a/chromium/ui/base/ime/linux/BUILD.gn
+++ b/chromium/ui/base/ime/linux/BUILD.gn
@@ -2,9 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/linux/pangocairo/pangocairo.gni")
-assert(is_linux && !is_chromeos)
+assert(is_linux || is_chromeos_lacros)
component("linux") {
output_name = "ui_base_ime_linux"
diff --git a/chromium/ui/base/ime/linux/input_method_auralinux.cc b/chromium/ui/base/ime/linux/input_method_auralinux.cc
index b1b79237e31..f4725590f58 100644
--- a/chromium/ui/base/ime/linux/input_method_auralinux.cc
+++ b/chromium/ui/base/ime/linux/input_method_auralinux.cc
@@ -149,7 +149,9 @@ ui::EventDispatchDetails InputMethodAuraLinux::ProcessKeyEventDone(
// the default behavior (e.g. trigger search, etc.)
// In such case, don't do InsertChar because a key should only trigger the
// keydown event once.
- client->InsertText(result_text_);
+ client->InsertText(
+ result_text_,
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
// If the client changes we assume that the original target has been
// destroyed.
if (client != GetTextInputClient()) {
@@ -309,7 +311,9 @@ void InputMethodAuraLinux::OnCommit(const base::string16& text) {
if (details.dispatcher_destroyed)
return;
if (!event.stopped_propagation() && !details.target_destroyed)
- GetTextInputClient()->InsertText(text);
+ GetTextInputClient()->InsertText(
+ text,
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
composition_ = CompositionText();
}
}
diff --git a/chromium/ui/base/ime/linux/input_method_auralinux_unittest.cc b/chromium/ui/base/ime/linux/input_method_auralinux_unittest.cc
index dfea78d1fc1..3f2de2f7597 100644
--- a/chromium/ui/base/ime/linux/input_method_auralinux_unittest.cc
+++ b/chromium/ui/base/ime/linux/input_method_auralinux_unittest.cc
@@ -237,7 +237,9 @@ class TextInputClientForTesting : public DummyTextInputClient {
composition_text.clear();
}
- void InsertText(const base::string16& text) override {
+ void InsertText(
+ const base::string16& text,
+ TextInputClient::InsertTextCursorBehavior cursor_behavior) override {
if (HasCompositionText()) {
TestResult::GetInstance()->RecordAction(
base::ASCIIToUTF16("compositionend"));
diff --git a/chromium/ui/base/ime/linux/text_edit_command_auralinux.cc b/chromium/ui/base/ime/linux/text_edit_command_auralinux.cc
index a694f59397e..9a5d56c4c18 100644
--- a/chromium/ui/base/ime/linux/text_edit_command_auralinux.cc
+++ b/chromium/ui/base/ime/linux/text_edit_command_auralinux.cc
@@ -127,6 +127,11 @@ std::string TextEditCommandAuraLinux::GetCommandString() const {
return "SetMark";
case TextEditCommand::UNSELECT:
return "Unselect";
+ case TextEditCommand::SCROLL_PAGE_DOWN:
+ case TextEditCommand::SCROLL_PAGE_UP:
+ case TextEditCommand::SCROLL_TO_BEGINNING_OF_DOCUMENT:
+ case TextEditCommand::SCROLL_TO_END_OF_DOCUMENT:
+ // Scroll commands are used by Mac only
case TextEditCommand::INVALID_COMMAND:
NOTREACHED();
return std::string();
diff --git a/chromium/ui/base/ime/mock_input_method.cc b/chromium/ui/base/ime/mock_input_method.cc
index 6ef10947256..35fa91b0dec 100644
--- a/chromium/ui/base/ime/mock_input_method.cc
+++ b/chromium/ui/base/ime/mock_input_method.cc
@@ -129,8 +129,7 @@ void MockInputMethod::RemoveObserver(InputMethodObserver* observer) {
observer_list_.RemoveObserver(observer);
}
-InputMethodKeyboardController*
-MockInputMethod::GetInputMethodKeyboardController() {
+VirtualKeyboardController* MockInputMethod::GetVirtualKeyboardController() {
return &keyboard_controller_;
}
diff --git a/chromium/ui/base/ime/mock_input_method.h b/chromium/ui/base/ime/mock_input_method.h
index 3cbfa920c9a..4074c5a30a7 100644
--- a/chromium/ui/base/ime/mock_input_method.h
+++ b/chromium/ui/base/ime/mock_input_method.h
@@ -13,8 +13,8 @@
#include "base/observer_list.h"
#include "build/build_config.h"
#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/input_method_keyboard_controller_stub.h"
#include "ui/base/ime/input_method_observer.h"
+#include "ui/base/ime/virtual_keyboard_controller_stub.h"
namespace ui {
@@ -58,7 +58,7 @@ class COMPONENT_EXPORT(UI_BASE_IME) MockInputMethod : public InputMethod {
void ShowVirtualKeyboardIfEnabled() override;
void AddObserver(InputMethodObserver* observer) override;
void RemoveObserver(InputMethodObserver* observer) override;
- InputMethodKeyboardController* GetInputMethodKeyboardController() override;
+ VirtualKeyboardController* GetVirtualKeyboardController() override;
private:
@@ -66,7 +66,7 @@ class COMPONENT_EXPORT(UI_BASE_IME) MockInputMethod : public InputMethod {
base::ObserverList<InputMethodObserver>::Unchecked observer_list_;
internal::InputMethodDelegate* delegate_;
- InputMethodKeyboardControllerStub keyboard_controller_;
+ VirtualKeyboardControllerStub keyboard_controller_;
DISALLOW_COPY_AND_ASSIGN(MockInputMethod);
};
diff --git a/chromium/ui/base/ime/text_edit_commands.h b/chromium/ui/base/ime/text_edit_commands.h
index 7d744b099de..1e8fbe7a568 100644
--- a/chromium/ui/base/ime/text_edit_commands.h
+++ b/chromium/ui/base/ime/text_edit_commands.h
@@ -56,6 +56,11 @@ enum class TextEditCommand {
MOVE_WORD_LEFT_AND_MODIFY_SELECTION,
MOVE_WORD_RIGHT,
MOVE_WORD_RIGHT_AND_MODIFY_SELECTION,
+ // On Mac, scroll commands have different shortcuts as move commands.
+ SCROLL_PAGE_DOWN,
+ SCROLL_PAGE_UP,
+ SCROLL_TO_BEGINNING_OF_DOCUMENT,
+ SCROLL_TO_END_OF_DOCUMENT,
UNDO,
REDO,
CUT,
@@ -71,6 +76,13 @@ enum class TextEditCommand {
// LAST_COMMAND must be the last one. Add new command before it.
LAST_COMMAND,
INVALID_COMMAND = LAST_COMMAND,
+
+ // Below are commands on Mac with default system key bindings that are
+ // not supported yet.
+ //
+ // centerSelectionInVisibleArea Ctrl + L
+ // complete Option + Esc
+ // deleteBackwardByDecomposingPreviousCharacter Ctrl + Delete
};
} // namespace ui
diff --git a/chromium/ui/base/ime/text_input_client.h b/chromium/ui/base/ime/text_input_client.h
index e6e900080ff..51e67bb0523 100644
--- a/chromium/ui/base/ime/text_input_client.h
+++ b/chromium/ui/base/ime/text_input_client.h
@@ -17,6 +17,7 @@
#include "base/optional.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "ui/base/ime/composition_text.h"
#include "ui/base/ime/input_method_delegate.h"
@@ -52,7 +53,7 @@ class COMPONENT_EXPORT(UI_BASE_IME) TextInputClient {
FOCUS_REASON_OTHER,
};
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
enum SubClass {
kRenderWidgetHostViewAura = 0,
kArcImeService = 1,
@@ -82,10 +83,20 @@ class COMPONENT_EXPORT(UI_BASE_IME) TextInputClient {
// Removes current composition text.
virtual void ClearCompositionText() = 0;
+ enum class InsertTextCursorBehavior {
+ // Move cursor to the position after the last character in the text.
+ // e.g. for "hello", the cursor will be right after "o".
+ kMoveCursorAfterText,
+ // Move cursor to the position before the first character in the text.
+ // e.g. for "hello", the cursor will be right before "h".
+ kMoveCursorBeforeText,
+ };
+
// Inserts a given text at the insertion point. Current composition text or
// selection will be removed. This method should never be called when the
// current text input type is TEXT_INPUT_TYPE_NONE.
- virtual void InsertText(const base::string16& text) = 0;
+ virtual void InsertText(const base::string16& text,
+ InsertTextCursorBehavior cursor_behavior) = 0;
// Inserts a single char at the insertion point. Unlike above InsertText()
// method, this method takes an |event| parameter indicating
@@ -220,7 +231,7 @@ class COMPONENT_EXPORT(UI_BASE_IME) TextInputClient {
// fields that are considered 'private' (e.g. in incognito tabs).
virtual bool ShouldDoLearning() = 0;
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
// Start composition over a given UTF-16 code range from existing text. This
// should only be used for composition scenario when IME wants to start
// composition on existing text. Returns whether the operation was successful.
@@ -230,7 +241,7 @@ class COMPONENT_EXPORT(UI_BASE_IME) TextInputClient {
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) = 0;
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Return the start and end index of the autocorrect range. If non-existent,
// return an empty Range.
virtual gfx::Range GetAutocorrectRange() const = 0;
@@ -241,15 +252,12 @@ class COMPONENT_EXPORT(UI_BASE_IME) TextInputClient {
// These bounds are in screen coordinates.
virtual gfx::Rect GetAutocorrectCharacterBounds() const = 0;
- // Set the autocorrect range and return if it has been set correctly as a
- // boolean value. If text or range is empty, existing autocorrect range is
- // cleared. Out of range results in failure and no modification will be made.
- virtual bool SetAutocorrectRange(const base::string16& autocorrect_text,
- const gfx::Range& range) = 0;
-
- // Clear the autocorrect range and remove the underline under the
- // autocorrect text.
- virtual void ClearAutocorrectRange() = 0;
+ // Sets the autocorrect range to |range|. Clients should show some visual
+ // indication of the range, such as flashing or underlining. If |range| is
+ // empty, then the autocorrect range is cleared.
+ // Returns true if the operation was successful. If |range| is invalid, then
+ // no modifications are made and this function returns false.
+ virtual bool SetAutocorrectRange(const gfx::Range& range) = 0;
#endif
#if defined(OS_WIN)
diff --git a/chromium/ui/base/ime/utf_offset_unittest.cc b/chromium/ui/base/ime/utf_offset_unittest.cc
index 2c4af2576dc..1deb7d626bc 100644
--- a/chromium/ui/base/ime/utf_offset_unittest.cc
+++ b/chromium/ui/base/ime/utf_offset_unittest.cc
@@ -4,6 +4,7 @@
#include "ui/base/ime/utf_offset.h"
+#include "base/logging.h"
#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
diff --git a/chromium/ui/base/ime/input_method_keyboard_controller.h b/chromium/ui/base/ime/virtual_keyboard_controller.h
index e33521214d8..6301eb04cfe 100644
--- a/chromium/ui/base/ime/input_method_keyboard_controller.h
+++ b/chromium/ui/base/ime/virtual_keyboard_controller.h
@@ -2,20 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_BASE_IME_INPUT_METHOD_KEYBOARD_CONTROLLER_H_
-#define UI_BASE_IME_INPUT_METHOD_KEYBOARD_CONTROLLER_H_
+#ifndef UI_BASE_IME_VIRTUAL_KEYBOARD_CONTROLLER_H_
+#define UI_BASE_IME_VIRTUAL_KEYBOARD_CONTROLLER_H_
#include "base/component_export.h"
namespace ui {
-class InputMethodKeyboardControllerObserver;
+class VirtualKeyboardControllerObserver;
// This class provides functionality to display the on screen keyboard and
// add observers to observe changes in it.
-class COMPONENT_EXPORT(UI_BASE_IME) InputMethodKeyboardController {
+class COMPONENT_EXPORT(UI_BASE_IME) VirtualKeyboardController {
public:
- virtual ~InputMethodKeyboardController() = default;
+ virtual ~VirtualKeyboardController() = default;
// Attempt to display the keyboard.
virtual bool DisplayVirtualKeyboard() = 0;
@@ -24,19 +24,18 @@ class COMPONENT_EXPORT(UI_BASE_IME) InputMethodKeyboardController {
virtual void DismissVirtualKeyboard() = 0;
// Adds a registered observer.
- virtual void AddObserver(InputMethodKeyboardControllerObserver* observer) = 0;
+ virtual void AddObserver(VirtualKeyboardControllerObserver* observer) = 0;
// Removes a registered observer.
- virtual void RemoveObserver(
- InputMethodKeyboardControllerObserver* observer) = 0;
+ virtual void RemoveObserver(VirtualKeyboardControllerObserver* observer) = 0;
// Returns true if the virtual keyboard is currently visible.
virtual bool IsKeyboardVisible() = 0;
protected:
- InputMethodKeyboardController() = default;
+ VirtualKeyboardController() = default;
};
} // namespace ui
-#endif // UI_BASE_IME_INPUT_METHOD_KEYBOARD_CONTROLLER_H_
+#endif // UI_BASE_IME_VIRTUAL_KEYBOARD_CONTROLLER_H_
diff --git a/chromium/ui/base/ime/input_method_keyboard_controller_observer.h b/chromium/ui/base/ime/virtual_keyboard_controller_observer.h
index 6ec42e35bfc..f55b93f5d07 100644
--- a/chromium/ui/base/ime/input_method_keyboard_controller_observer.h
+++ b/chromium/ui/base/ime/virtual_keyboard_controller_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_BASE_IME_INPUT_METHOD_KEYBOARD_CONTROLLER_OBSERVER_H_
-#define UI_BASE_IME_INPUT_METHOD_KEYBOARD_CONTROLLER_OBSERVER_H_
+#ifndef UI_BASE_IME_VIRTUAL_KEYBOARD_CONTROLLER_OBSERVER_H_
+#define UI_BASE_IME_VIRTUAL_KEYBOARD_CONTROLLER_OBSERVER_H_
#include "base/component_export.h"
@@ -15,16 +15,16 @@ namespace ui {
// This observer class provides a method to observe on screen
// keyboard changes.
-class COMPONENT_EXPORT(UI_BASE_IME) InputMethodKeyboardControllerObserver {
+class COMPONENT_EXPORT(UI_BASE_IME) VirtualKeyboardControllerObserver {
public:
// The |keyboard_rect| parameter contains the bounds of the keyboard in dips.
virtual void OnKeyboardVisible(const gfx::Rect& keyboard_rect) = 0;
virtual void OnKeyboardHidden() = 0;
protected:
- virtual ~InputMethodKeyboardControllerObserver() = default;
+ virtual ~VirtualKeyboardControllerObserver() = default;
};
} // namespace ui
-#endif // UI_BASE_IME_INPUT_METHOD_KEYBOARD_CONTROLLER_OBSERVER_H_
+#endif // UI_BASE_IME_VIRTUAL_KEYBOARD_CONTROLLER_OBSERVER_H_
diff --git a/chromium/ui/base/ime/virtual_keyboard_controller_stub.cc b/chromium/ui/base/ime/virtual_keyboard_controller_stub.cc
new file mode 100644
index 00000000000..e48f421114d
--- /dev/null
+++ b/chromium/ui/base/ime/virtual_keyboard_controller_stub.cc
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/virtual_keyboard_controller_stub.h"
+
+namespace ui {
+
+// VirtualKeyboardControllerStub member definitions.
+VirtualKeyboardControllerStub::VirtualKeyboardControllerStub() {}
+
+VirtualKeyboardControllerStub::~VirtualKeyboardControllerStub() {}
+
+bool VirtualKeyboardControllerStub::DisplayVirtualKeyboard() {
+ return false;
+}
+
+void VirtualKeyboardControllerStub::DismissVirtualKeyboard() {}
+
+void VirtualKeyboardControllerStub::AddObserver(
+ VirtualKeyboardControllerObserver* observer) {}
+
+void VirtualKeyboardControllerStub::RemoveObserver(
+ VirtualKeyboardControllerObserver* observer) {}
+
+bool VirtualKeyboardControllerStub::IsKeyboardVisible() {
+ return false;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/virtual_keyboard_controller_stub.h b/chromium/ui/base/ime/virtual_keyboard_controller_stub.h
new file mode 100644
index 00000000000..5982eee03fa
--- /dev/null
+++ b/chromium/ui/base/ime/virtual_keyboard_controller_stub.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_BASE_IME_VIRTUAL_KEYBOARD_CONTROLLER_STUB_H_
+#define UI_BASE_IME_VIRTUAL_KEYBOARD_CONTROLLER_STUB_H_
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "ui/base/ime/virtual_keyboard_controller.h"
+
+namespace ui {
+
+// This class provides a stub VirtualKeyboardController.
+class COMPONENT_EXPORT(UI_BASE_IME) VirtualKeyboardControllerStub final
+ : public VirtualKeyboardController {
+ public:
+ VirtualKeyboardControllerStub();
+ ~VirtualKeyboardControllerStub() override;
+
+ // VirtualKeyboardController overrides.
+ bool DisplayVirtualKeyboard() override;
+ void DismissVirtualKeyboard() override;
+ void AddObserver(VirtualKeyboardControllerObserver* observer) override;
+ void RemoveObserver(VirtualKeyboardControllerObserver* observer) override;
+ bool IsKeyboardVisible() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardControllerStub);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_VIRTUAL_KEYBOARD_CONTROLLER_STUB_H_
diff --git a/chromium/ui/base/ime/win/imm32_manager.cc b/chromium/ui/base/ime/win/imm32_manager.cc
index 75018d3fffa..26f17604d02 100644
--- a/chromium/ui/base/ime/win/imm32_manager.cc
+++ b/chromium/ui/base/ime/win/imm32_manager.cc
@@ -77,7 +77,6 @@ void GetImeTextSpans(HIMC imm_context,
ui::ImeTextSpan ime_text_span;
ime_text_span.start_offset = clause_data[i];
ime_text_span.end_offset = clause_data[i + 1];
- ime_text_span.underline_color = SK_ColorBLACK;
ime_text_span.thickness = ui::ImeTextSpan::Thickness::kThin;
ime_text_span.background_color = SK_ColorTRANSPARENT;
diff --git a/chromium/ui/base/ime/win/input_method_win_base.cc b/chromium/ui/base/ime/win/input_method_win_base.cc
index fc9c8d3a0f2..f07ce6fef45 100644
--- a/chromium/ui/base/ime/win/input_method_win_base.cc
+++ b/chromium/ui/base/ime/win/input_method_win_base.cc
@@ -31,7 +31,7 @@ namespace {
// is returned to IME for improving conversion accuracy.
constexpr size_t kExtraNumberOfChars = 20;
-std::unique_ptr<InputMethodKeyboardController> CreateKeyboardController(
+std::unique_ptr<VirtualKeyboardController> CreateKeyboardController(
HWND toplevel_window_handle) {
if (base::FeatureList::IsEnabled(features::kInputPaneOnScreenKeyboard) &&
base::win::GetVersion() >= base::win::Version::WIN10_RS4) {
diff --git a/chromium/ui/base/ime/win/input_method_win_imm32.cc b/chromium/ui/base/ime/win/input_method_win_imm32.cc
index 20defba624b..07341babad1 100644
--- a/chromium/ui/base/ime/win/input_method_win_imm32.cc
+++ b/chromium/ui/base/ime/win/input_method_win_imm32.cc
@@ -227,7 +227,9 @@ LRESULT InputMethodWinImm32::OnImeComposition(HWND window_handle,
ui::CompositionText composition;
if (imm32_manager_.GetResult(window_handle, lparam, &composition.text)) {
if (!IsTextInputTypeNone())
- GetTextInputClient()->InsertText(composition.text);
+ GetTextInputClient()->InsertText(
+ composition.text,
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
imm32_manager_.ResetComposition(window_handle);
// Fall though and try reading the composition string.
// Japanese IMEs send a message containing both GCS_RESULTSTR and
diff --git a/chromium/ui/base/ime/win/input_method_win_tsf.cc b/chromium/ui/base/ime/win/input_method_win_tsf.cc
index bf0422c5d77..f22ddceeda4 100644
--- a/chromium/ui/base/ime/win/input_method_win_tsf.cc
+++ b/chromium/ui/base/ime/win/input_method_win_tsf.cc
@@ -4,8 +4,8 @@
#include "ui/base/ime/win/input_method_win_tsf.h"
-#include "ui/base/ime/input_method_keyboard_controller.h"
#include "ui/base/ime/text_input_client.h"
+#include "ui/base/ime/virtual_keyboard_controller.h"
#include "ui/base/ime/win/tsf_bridge.h"
#include "ui/base/ime/win/tsf_event_router.h"
@@ -176,11 +176,7 @@ void InputMethodWinTSF::ConfirmCompositionText() {
}
void InputMethodWinTSF::ShowVirtualKeyboardIfEnabled() {
- // TODO(crbug.com/1031786): Enable this once TSF input pane policy bug is
- // fixed if (ui::TSFBridge::GetInstance())
- // ui::TSFBridge::GetInstance()->SetInputPanelPolicy(
- // /*inputPanelPolicyManual*/ false);
- if (auto* controller = GetInputMethodKeyboardController())
+ if (auto* controller = GetVirtualKeyboardController())
controller->DisplayVirtualKeyboard();
}
diff --git a/chromium/ui/base/ime/win/mock_tsf_bridge.cc b/chromium/ui/base/ime/win/mock_tsf_bridge.cc
index 6989d94b370..a15f2bedd43 100644
--- a/chromium/ui/base/ime/win/mock_tsf_bridge.cc
+++ b/chromium/ui/base/ime/win/mock_tsf_bridge.cc
@@ -61,11 +61,6 @@ TextInputClient* MockTSFBridge::GetFocusedTextInputClient() const {
return text_input_client_;
}
-void MockTSFBridge::SetInputPanelPolicy(bool input_panel_policy_manual) {
- if (tsf_text_store_)
- tsf_text_store_->SetInputPanelPolicy(input_panel_policy_manual);
-}
-
bool MockTSFBridge::IsInputLanguageCJK() {
return false;
}
diff --git a/chromium/ui/base/ime/win/mock_tsf_bridge.h b/chromium/ui/base/ime/win/mock_tsf_bridge.h
index 45568a60004..d613db794aa 100644
--- a/chromium/ui/base/ime/win/mock_tsf_bridge.h
+++ b/chromium/ui/base/ime/win/mock_tsf_bridge.h
@@ -33,7 +33,6 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) MockTSFBridge : public TSFBridge {
Microsoft::WRL::ComPtr<ITfThreadMgr> GetThreadManager() override;
TextInputClient* GetFocusedTextInputClient() const override;
bool IsInputLanguageCJK() override;
- void SetInputPanelPolicy(bool input_panel_policy_manual) override;
// Resets MockTSFBridge state including function call counter.
void Reset();
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
index f9898d22a40..c8f8cf82655 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
@@ -12,7 +12,7 @@
#include "base/win/com_init_util.h"
#include "base/win/core_winrt_util.h"
#include "base/win/windows_version.h"
-#include "ui/base/ime/input_method_keyboard_controller_observer.h"
+#include "ui/base/ime/virtual_keyboard_controller_observer.h"
namespace ui {
@@ -282,13 +282,13 @@ void OnScreenKeyboardDisplayManagerInputPane::DismissVirtualKeyboard() {
}
void OnScreenKeyboardDisplayManagerInputPane::AddObserver(
- InputMethodKeyboardControllerObserver* observer) {
+ VirtualKeyboardControllerObserver* observer) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
observers_.AddObserver(observer);
}
void OnScreenKeyboardDisplayManagerInputPane::RemoveObserver(
- InputMethodKeyboardControllerObserver* observer) {
+ VirtualKeyboardControllerObserver* observer) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
observers_.RemoveObserver(observer);
}
@@ -314,7 +314,7 @@ void OnScreenKeyboardDisplayManagerInputPane::NotifyObserversOnKeyboardShown(
gfx::Rect dip_rect) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
is_keyboard_visible_ = true;
- for (InputMethodKeyboardControllerObserver& observer : observers_)
+ for (VirtualKeyboardControllerObserver& observer : observers_)
observer.OnKeyboardVisible(dip_rect);
}
@@ -322,7 +322,7 @@ void OnScreenKeyboardDisplayManagerInputPane::
NotifyObserversOnKeyboardHidden() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
is_keyboard_visible_ = false;
- for (InputMethodKeyboardControllerObserver& observer : observers_)
+ for (VirtualKeyboardControllerObserver& observer : observers_)
observer.OnKeyboardHidden();
}
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h
index 68b15c27f21..cd88f30e9e7 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h
@@ -17,8 +17,8 @@
#include "base/observer_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/win/windows_types.h"
-#include "ui/base/ime/input_method_keyboard_controller.h"
#include "ui/base/ime/mojom/virtual_keyboard_types.mojom-shared.h"
+#include "ui/base/ime/virtual_keyboard_controller.h"
#include "ui/base/ime/win/virtual_keyboard_debounce_timer.h"
#include "ui/gfx/geometry/rect.h"
@@ -30,23 +30,23 @@ class OnScreenKeyboardTest;
// that uses InputPane which is available on Windows >= 10.0.10240.0.
class COMPONENT_EXPORT(UI_BASE_IME_WIN)
OnScreenKeyboardDisplayManagerInputPane final
- : public InputMethodKeyboardController {
+ : public VirtualKeyboardController {
public:
explicit OnScreenKeyboardDisplayManagerInputPane(HWND hwnd);
~OnScreenKeyboardDisplayManagerInputPane() override;
- // InputMethodKeyboardController:
+ // VirtualKeyboardController:
bool DisplayVirtualKeyboard() override;
void DismissVirtualKeyboard() override;
- void AddObserver(InputMethodKeyboardControllerObserver* observer) override;
- void RemoveObserver(InputMethodKeyboardControllerObserver* observer) override;
+ void AddObserver(VirtualKeyboardControllerObserver* observer) override;
+ void RemoveObserver(VirtualKeyboardControllerObserver* observer) override;
bool IsKeyboardVisible() override;
void SetInputPaneForTesting(
Microsoft::WRL::ComPtr<ABI::Windows::UI::ViewManagement::IInputPane>
pane);
// Returns whether show/hide VK API is called from
- // InputMethodKeyboardController or not.
+ // VirtualKeyboardController or not.
mojom::VirtualKeyboardVisibilityRequest
GetLastVirtualKeyboardVisibilityRequest() const {
return last_vk_visibility_request_;
@@ -63,7 +63,7 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN)
// The main window which displays the on screen keyboard.
const HWND hwnd_;
- base::ObserverList<InputMethodKeyboardControllerObserver, false>::Unchecked
+ base::ObserverList<VirtualKeyboardControllerObserver, false>::Unchecked
observers_;
const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
const scoped_refptr<base::SingleThreadTaskRunner> background_task_runner_;
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc
index ec93a4b2966..fbd39ca40a4 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc
@@ -20,7 +20,7 @@
#include "base/win/scoped_co_mem.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
-#include "ui/base/ime/input_method_keyboard_controller_observer.h"
+#include "ui/base/ime/virtual_keyboard_controller_observer.h"
#include "ui/base/win/hidden_window.h"
#include "ui/display/win/screen_win.h"
#include "ui/gfx/geometry/dip_util.h"
@@ -288,17 +288,16 @@ void OnScreenKeyboardDisplayManagerTabTip::DismissVirtualKeyboard() {
}
void OnScreenKeyboardDisplayManagerTabTip::AddObserver(
- InputMethodKeyboardControllerObserver* observer) {
+ VirtualKeyboardControllerObserver* observer) {
observers_.AddObserver(observer);
}
void OnScreenKeyboardDisplayManagerTabTip::RemoveObserver(
- InputMethodKeyboardControllerObserver* observer) {
+ VirtualKeyboardControllerObserver* observer) {
observers_.RemoveObserver(observer);
}
-bool OnScreenKeyboardDisplayManagerTabTip::GetOSKPath(
- base::string16* osk_path) {
+bool OnScreenKeyboardDisplayManagerTabTip::GetOSKPath(std::wstring* osk_path) {
DCHECK(osk_path);
// We need to launch TabTip.exe from the location specified under the
@@ -317,7 +316,7 @@ bool OnScreenKeyboardDisplayManagerTabTip::GetOSKPath(
return false;
}
- osk_path->resize(base::string16::traits_type::length(osk_path->c_str()));
+ osk_path->resize(wcslen(osk_path->c_str()));
*osk_path = base::ToLowerASCII(*osk_path);
@@ -326,7 +325,7 @@ bool OnScreenKeyboardDisplayManagerTabTip::GetOSKPath(
// %CommonProgramFiles% which needs to be replaced with the corrsponding
// expanded string.
// If the path does not begin with %CommonProgramFiles% we use it as is.
- if (common_program_files_offset != base::string16::npos) {
+ if (common_program_files_offset != std::wstring::npos) {
// Preserve the beginning quote in the path.
osk_path->erase(common_program_files_offset,
wcslen(L"%commonprogramfiles%"));
@@ -340,7 +339,7 @@ bool OnScreenKeyboardDisplayManagerTabTip::GetOSKPath(
// We then replace the %CommonProgramFiles% value with the actual common
// files path found in the process.
- base::string16 common_program_files_path;
+ std::wstring common_program_files_path;
DWORD buffer_size =
GetEnvironmentVariable(L"CommonProgramW6432", nullptr, 0);
if (buffer_size) {
@@ -368,12 +367,12 @@ bool OnScreenKeyboardDisplayManagerTabTip::IsKeyboardVisible() {
void OnScreenKeyboardDisplayManagerTabTip::NotifyKeyboardVisible(
const gfx::Rect& occluded_rect) {
- for (InputMethodKeyboardControllerObserver& observer : observers_)
+ for (VirtualKeyboardControllerObserver& observer : observers_)
observer.OnKeyboardVisible(occluded_rect);
}
void OnScreenKeyboardDisplayManagerTabTip::NotifyKeyboardHidden() {
- for (InputMethodKeyboardControllerObserver& observer : observers_)
+ for (VirtualKeyboardControllerObserver& observer : observers_)
observer.OnKeyboardHidden();
}
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h
index f718926d662..68521961907 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h
@@ -5,39 +5,40 @@
#ifndef UI_BASE_IME_WIN_ON_SCREEN_KEYBOARD_DISPLAY_MANAGER_TAP_TIP_H_
#define UI_BASE_IME_WIN_ON_SCREEN_KEYBOARD_DISPLAY_MANAGER_TAP_TIP_H_
+#include <string>
+
#include "base/component_export.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/observer_list.h"
-#include "base/strings/string16.h"
-#include "ui/base/ime/input_method_keyboard_controller.h"
+#include "ui/base/ime/virtual_keyboard_controller.h"
#include "ui/gfx/geometry/rect.h"
namespace ui {
class OnScreenKeyboardDetector;
-// This class provides an implementation of the InputMethodKeyboardController
+// This class provides an implementation of the VirtualKeyboardController
// that uses heuristics and the TabTip.exe to display the on screen keyboard.
// Used on Windows > 7 and Windows < 10.0.10240.0
class COMPONENT_EXPORT(UI_BASE_IME_WIN)
OnScreenKeyboardDisplayManagerTabTip final
- : public InputMethodKeyboardController {
+ : public VirtualKeyboardController {
public:
OnScreenKeyboardDisplayManagerTabTip(HWND hwnd);
~OnScreenKeyboardDisplayManagerTabTip() override;
- // InputMethodKeyboardController overrides.
+ // VirtualKeyboardController overrides.
bool DisplayVirtualKeyboard() override;
void DismissVirtualKeyboard() override;
- void AddObserver(InputMethodKeyboardControllerObserver* observer) override;
- void RemoveObserver(InputMethodKeyboardControllerObserver* observer) override;
+ void AddObserver(VirtualKeyboardControllerObserver* observer) override;
+ void RemoveObserver(VirtualKeyboardControllerObserver* observer) override;
bool IsKeyboardVisible() override;
// Returns the path of the on screen keyboard exe (TabTip.exe) in the
// |osk_path| parameter.
// Returns true on success.
- bool GetOSKPath(base::string16* osk_path);
+ bool GetOSKPath(std::wstring* osk_path);
private:
friend class OnScreenKeyboardTest;
@@ -47,12 +48,12 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN)
void NotifyKeyboardHidden();
std::unique_ptr<OnScreenKeyboardDetector> keyboard_detector_;
- base::ObserverList<InputMethodKeyboardControllerObserver, false>::Unchecked
+ base::ObserverList<VirtualKeyboardControllerObserver, false>::Unchecked
observers_;
HWND hwnd_;
// The location of TabTip.exe.
- base::string16 osk_path_;
+ std::wstring osk_path_;
DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardDisplayManagerTabTip);
};
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc
index 9f14005acfd..d75398fb64b 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc
@@ -12,23 +12,23 @@
#include "base/win/windows_version.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/ime/input_method_keyboard_controller_observer.h"
+#include "ui/base/ime/virtual_keyboard_controller_observer.h"
#include "ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h"
#include "ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.h"
namespace ui {
-class MockInputMethodKeyboardControllerObserver
- : public InputMethodKeyboardControllerObserver {
+class MockVirtualKeyboardControllerObserver
+ : public VirtualKeyboardControllerObserver {
public:
- MockInputMethodKeyboardControllerObserver() = default;
- virtual ~MockInputMethodKeyboardControllerObserver() = default;
+ MockVirtualKeyboardControllerObserver() = default;
+ virtual ~MockVirtualKeyboardControllerObserver() = default;
MOCK_METHOD1(OnKeyboardVisible, void(const gfx::Rect&));
MOCK_METHOD0(OnKeyboardHidden, void());
private:
- DISALLOW_COPY_AND_ASSIGN(MockInputMethodKeyboardControllerObserver);
+ DISALLOW_COPY_AND_ASSIGN(MockVirtualKeyboardControllerObserver);
};
class MockInputPane
@@ -145,10 +145,10 @@ TEST_F(OnScreenKeyboardTest, OSKPath) {
keyboard_display_manager(CreateTabTip());
EXPECT_NE(nullptr, keyboard_display_manager);
- base::string16 osk_path;
+ std::wstring osk_path;
EXPECT_TRUE(keyboard_display_manager->GetOSKPath(&osk_path));
EXPECT_FALSE(osk_path.empty());
- EXPECT_TRUE(osk_path.find(L"tabtip.exe") != base::string16::npos);
+ EXPECT_TRUE(osk_path.find(L"tabtip.exe") != std::wstring::npos);
// The path read from the registry can be quoted. To check for the existence
// of the file we use the base::PathExists function which internally uses the
@@ -168,8 +168,8 @@ TEST_F(OnScreenKeyboardTest, InputPane) {
std::unique_ptr<OnScreenKeyboardDisplayManagerInputPane>
keyboard_display_manager = CreateInputPane();
- std::unique_ptr<MockInputMethodKeyboardControllerObserver> observer =
- std::make_unique<MockInputMethodKeyboardControllerObserver>();
+ std::unique_ptr<MockVirtualKeyboardControllerObserver> observer =
+ std::make_unique<MockVirtualKeyboardControllerObserver>();
Microsoft::WRL::ComPtr<MockInputPane> input_pane =
Microsoft::WRL::Make<MockInputPane>();
@@ -196,8 +196,8 @@ TEST_F(OnScreenKeyboardTest, InputPaneDebounceTimerTest) {
std::unique_ptr<OnScreenKeyboardDisplayManagerInputPane>
keyboard_display_manager = CreateInputPane();
- std::unique_ptr<MockInputMethodKeyboardControllerObserver> observer =
- std::make_unique<MockInputMethodKeyboardControllerObserver>();
+ std::unique_ptr<MockVirtualKeyboardControllerObserver> observer =
+ std::make_unique<MockVirtualKeyboardControllerObserver>();
Microsoft::WRL::ComPtr<MockInputPane> input_pane =
Microsoft::WRL::Make<MockInputPane>();
@@ -230,8 +230,8 @@ TEST_F(OnScreenKeyboardTest, InputPaneDestruction) {
std::unique_ptr<OnScreenKeyboardDisplayManagerInputPane>
keyboard_display_manager = CreateInputPane();
- std::unique_ptr<MockInputMethodKeyboardControllerObserver> observer =
- std::make_unique<MockInputMethodKeyboardControllerObserver>();
+ std::unique_ptr<MockVirtualKeyboardControllerObserver> observer =
+ std::make_unique<MockVirtualKeyboardControllerObserver>();
Microsoft::WRL::ComPtr<MockInputPane> input_pane =
Microsoft::WRL::Make<MockInputPane>();
diff --git a/chromium/ui/base/ime/win/tsf_bridge.cc b/chromium/ui/base/ime/win/tsf_bridge.cc
index 74080828239..73e528641e8 100644
--- a/chromium/ui/base/ime/win/tsf_bridge.cc
+++ b/chromium/ui/base/ime/win/tsf_bridge.cc
@@ -12,6 +12,7 @@
#include "base/stl_util.h"
#include "base/task/current_thread.h"
#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/trace_event.h"
#include "base/win/scoped_variant.h"
#include "ui/base/ime/input_method_delegate.h"
#include "ui/base/ime/text_input_client.h"
@@ -46,7 +47,6 @@ class TSFBridgeImpl : public TSFBridge {
bool IsInputLanguageCJK() override;
Microsoft::WRL::ComPtr<ITfThreadMgr> GetThreadManager() override;
TextInputClient* GetFocusedTextInputClient() const override;
- void SetInputPanelPolicy(bool input_panel_policy_manual) override;
private:
// Returns S_OK if |tsf_document_map_| is successfully initialized. This
@@ -233,6 +233,13 @@ void TSFBridgeImpl::OnTextInputTypeChanged(const TextInputClient* client) {
return;
}
+ // Since we reuse TSF document for same text input type, there is a case where
+ // focus is switched between two text fields with same input type. We should
+ // prepare the TSF document for reuse by clearing focus first.
+ if (input_type_ != TEXT_INPUT_TYPE_NONE &&
+ input_type_ == client_->GetTextInputType()) {
+ thread_manager_->SetFocus(nullptr);
+ }
input_type_ = client_->GetTextInputType();
TSFDocument* document = GetAssociatedDocument();
if (!document)
@@ -258,15 +265,6 @@ void TSFBridgeImpl::OnTextLayoutChanged() {
document->text_store->SendOnLayoutChange();
}
-void TSFBridgeImpl::SetInputPanelPolicy(bool input_panel_policy_manual) {
- TSFDocument* document = GetAssociatedDocument();
- if (!document)
- return;
- if (!document->text_store)
- return;
- document->text_store->SetInputPanelPolicy(input_panel_policy_manual);
-}
-
bool TSFBridgeImpl::CancelComposition() {
DCHECK(base::CurrentUIThread::IsSet());
DCHECK(IsInitialized());
@@ -614,6 +612,7 @@ TSFBridge::~TSFBridge() {}
// static
HRESULT TSFBridge::Initialize() {
+ TRACE_EVENT0("ime", "TSFBridge::Initialize");
if (!base::CurrentUIThread::IsSet()) {
return E_FAIL;
}
@@ -662,6 +661,7 @@ void TSFBridge::ReplaceThreadLocalTSFBridge(TSFBridge* new_instance) {
// static
void TSFBridge::Shutdown() {
+ TRACE_EVENT0("ime", "TSFBridge::Shutdown");
if (!base::CurrentUIThread::IsSet()) {
}
ReplaceThreadLocalTSFBridge(nullptr);
diff --git a/chromium/ui/base/ime/win/tsf_bridge.h b/chromium/ui/base/ime/win/tsf_bridge.h
index 035b22c7e89..1f2adb247bf 100644
--- a/chromium/ui/base/ime/win/tsf_bridge.h
+++ b/chromium/ui/base/ime/win/tsf_bridge.h
@@ -95,17 +95,6 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFBridge {
// Returns the focused text input client.
virtual TextInputClient* GetFocusedTextInputClient() const = 0;
- // Sets the input panel policy in TSFTextStore so that input service
- // could invoke the software input panel (SIP) on Windows.
- // input_panel_policy_manual equals to false would make the SIP policy
- // to automatic meaning TSF would raise/dismiss the SIP based on TSFTextStore
- // focus and other heuristics that input service have added on Windows to
- // provide a consistent behavior across all apps on Windows.
- // input_panel_policy_manual equals to true would make the SIP policy to
- // manual meaning TSF wouldn't raise/dismiss the SIP automatically. This is
- // used to control the SIP behavior based on user interaction with the page.
- virtual void SetInputPanelPolicy(bool input_panel_policy_manual) = 0;
-
protected:
// Uses GetInstance() instead.
TSFBridge();
diff --git a/chromium/ui/base/ime/win/tsf_input_policy_unittest.cc b/chromium/ui/base/ime/win/tsf_input_policy_unittest.cc
deleted file mode 100644
index ad602b71a4a..00000000000
--- a/chromium/ui/base/ime/win/tsf_input_policy_unittest.cc
+++ /dev/null
@@ -1,346 +0,0 @@
-// Copyright (c) 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/ime/win/tsf_text_store.h"
-
-#include <initguid.h> // for GUID_NULL and GUID_PROP_INPUTSCOPE
-
-#include <InputScope.h>
-#include <OleCtl.h>
-#include <wrl/client.h>
-
-#if defined(OS_WIN)
-#include <vector>
-#endif
-
-#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 "build/build_config.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/ime/dummy_input_method.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/base/ime/win/mock_tsf_bridge.h"
-#include "ui/events/event.h"
-#include "ui/events/event_dispatcher.h"
-#include "ui/gfx/geometry/rect.h"
-
-using testing::_;
-using testing::Invoke;
-using testing::Return;
-
-namespace ui {
-namespace {
-
-class MockTextInputClient : public TextInputClient {
- public:
- ~MockTextInputClient() {}
- MOCK_METHOD1(SetCompositionText, void(const ui::CompositionText&));
- MOCK_METHOD1(ConfirmCompositionText, uint32_t(bool));
- MOCK_METHOD0(ClearCompositionText, void());
- MOCK_METHOD1(InsertText, void(const base::string16&));
- MOCK_METHOD1(InsertChar, void(const ui::KeyEvent&));
- MOCK_CONST_METHOD0(GetTextInputType, ui::TextInputType());
- MOCK_CONST_METHOD0(GetTextInputMode, ui::TextInputMode());
- MOCK_CONST_METHOD0(GetTextDirection, base::i18n::TextDirection());
- MOCK_CONST_METHOD0(GetTextInputFlags, int());
- MOCK_CONST_METHOD0(CanComposeInline, bool());
- MOCK_CONST_METHOD0(GetCaretBounds, gfx::Rect());
- MOCK_CONST_METHOD2(GetCompositionCharacterBounds, bool(uint32_t, gfx::Rect*));
- MOCK_CONST_METHOD0(HasCompositionText, bool());
- MOCK_CONST_METHOD0(GetFocusReason, ui::TextInputClient::FocusReason());
- MOCK_METHOD0(ShouldDoLearning, bool());
- MOCK_CONST_METHOD1(GetTextRange, bool(gfx::Range*));
- MOCK_CONST_METHOD1(GetCompositionTextRange, bool(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*));
- MOCK_METHOD0(OnInputMethodChanged, void());
- MOCK_METHOD1(ChangeTextDirectionAndLayoutAlignment,
- bool(base::i18n::TextDirection));
- MOCK_METHOD2(ExtendSelectionAndDelete, void(size_t, size_t));
- MOCK_METHOD1(EnsureCaretNotInRect, void(const gfx::Rect&));
- MOCK_CONST_METHOD1(IsTextEditCommandEnabled, bool(TextEditCommand));
- MOCK_METHOD1(SetTextEditCommandForNextKeyEvent, void(TextEditCommand));
- MOCK_CONST_METHOD0(GetClientSourceForMetrics, ukm::SourceId());
- MOCK_METHOD2(SetCompositionFromExistingText,
- bool(const gfx::Range&, const std::vector<ui::ImeTextSpan>&));
- MOCK_METHOD3(SetActiveCompositionForAccessibility,
- void(const gfx::Range&, const base::string16&, bool));
- MOCK_METHOD2(GetActiveTextInputControlLayoutBounds,
- void(base::Optional<gfx::Rect>* control_bounds,
- base::Optional<gfx::Rect>* selection_bounds));
-};
-
-class MockInputMethodDelegate : public internal::InputMethodDelegate {
- public:
- ~MockInputMethodDelegate() {}
- MOCK_METHOD1(DispatchKeyEventPostIME, EventDispatchDetails(KeyEvent*));
-};
-
-class MockStoreACPSink : public ITextStoreACPSink {
- public:
- MockStoreACPSink() : ref_count_(0) {}
-
- // IUnknown
- ULONG STDMETHODCALLTYPE AddRef() override {
- return InterlockedIncrement(&ref_count_);
- }
- ULONG STDMETHODCALLTYPE Release() override {
- const LONG count = InterlockedDecrement(&ref_count_);
- if (!count) {
- delete this;
- return 0;
- }
- return static_cast<ULONG>(count);
- }
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** report) override {
- if (iid == IID_IUnknown || iid == IID_ITextStoreACPSink) {
- *report = static_cast<ITextStoreACPSink*>(this);
- } else {
- *report = nullptr;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
- }
-
- // ITextStoreACPSink
- MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
- OnTextChange,
- HRESULT(DWORD, const TS_TEXTCHANGE*));
- MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, OnSelectionChange, HRESULT());
- MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
- OnLayoutChange,
- HRESULT(TsLayoutCode, TsViewCookie));
- MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, OnStatusChange, HRESULT(DWORD));
- MOCK_METHOD4_WITH_CALLTYPE(STDMETHODCALLTYPE,
- OnAttrsChange,
- HRESULT(LONG, LONG, ULONG, const TS_ATTRID*));
- MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, OnLockGranted, HRESULT(DWORD));
- MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE,
- OnStartEditTransaction,
- HRESULT());
- MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE,
- OnEndEditTransaction,
- HRESULT());
-
- private:
- virtual ~MockStoreACPSink() {}
-
- volatile LONG ref_count_;
-};
-
-class FakeInputMethod : public DummyInputMethod {
- public:
- FakeInputMethod() : client_(nullptr), count_show_ime_if_needed_(0) {}
-
- void SetFocusedTextInputClient(TextInputClient* client) override {
- count_set_focused_text_input_client_++;
- client_ = client;
- }
-
- TextInputClient* GetTextInputClient() const override { return client_; }
-
- void ShowVirtualKeyboardIfEnabled() override {
- count_show_ime_if_needed_++;
- // Set the input policy in textstore using TSFBridge
- tsf_bridge_->SetInputPanelPolicy(/*inputPanelPolicyManual*/ false);
- }
-
- void DetachTextInputClient(TextInputClient* client) override {
- if (client_ == client)
- client_ = nullptr;
- // Set the input policy in textstore using TSFBridge
- tsf_bridge_->SetInputPanelPolicy(/*inputPanelPolicyManual*/ true);
- }
-
- void OnTextInputTypeChanged(const TextInputClient* client) override {
- count_on_text_input_type_changed_++;
- }
-
- void SetTSFTextStoreForBridge(TSFTextStore* tsf_text_store) {
- tsf_bridge_ = new MockTSFBridge();
- tsf_bridge_->SetTSFTextStoreForTesting(tsf_text_store);
- }
-
- int count_show_ime_if_needed() const { return count_show_ime_if_needed_; }
-
- private:
- TextInputClient* client_;
- MockTSFBridge* tsf_bridge_;
- int count_show_ime_if_needed_;
- int count_set_focused_text_input_client_;
- int count_on_text_input_type_changed_;
-};
-
-const HWND kWindowHandle = reinterpret_cast<HWND>(1);
-
-} // namespace
-
-class TSFInputPanelTest : public testing::Test {
- protected:
- void SetUp() override {
- text_store_ = new TSFTextStore();
- EXPECT_EQ(S_OK, text_store_->Initialize());
- sink_ = new MockStoreACPSink();
- EXPECT_EQ(S_OK, text_store_->AdviseSink(IID_ITextStoreACPSink, sink_.get(),
- TS_AS_ALL_SINKS));
- text_store_->SetFocusedTextInputClient(kWindowHandle, &text_input_client_);
- text_store_->SetInputMethodDelegate(&input_method_delegate_);
- fake_input_method_ = std::make_unique<FakeInputMethod>();
- fake_input_method_->SetTSFTextStoreForBridge(text_store_.get());
- }
-
- void TearDown() override {
- EXPECT_EQ(S_OK, text_store_->UnadviseSink(sink_.get()));
- sink_ = nullptr;
- text_store_ = nullptr;
- }
-
- // Accessors to the internal state of TSFTextStore.
-
- base::win::ScopedCOMInitializer com_initializer_;
- MockTextInputClient text_input_client_;
- MockInputMethodDelegate input_method_delegate_;
- scoped_refptr<TSFTextStore> text_store_;
- scoped_refptr<MockStoreACPSink> sink_;
- std::unique_ptr<FakeInputMethod> fake_input_method_;
-};
-
-class TSFMultipleInputPanelTest : public testing::Test {
- protected:
- void SetUp() override {
- text_store1_ = new TSFTextStore();
- EXPECT_EQ(S_OK, text_store1_->Initialize());
- text_store2_ = new TSFTextStore();
- EXPECT_EQ(S_OK, text_store2_->Initialize());
- sink1_ = new MockStoreACPSink();
- sink2_ = new MockStoreACPSink();
- EXPECT_EQ(S_OK, text_store1_->AdviseSink(IID_ITextStoreACPSink,
- sink1_.get(), TS_AS_ALL_SINKS));
- EXPECT_EQ(S_OK, text_store2_->AdviseSink(IID_ITextStoreACPSink,
- sink2_.get(), TS_AS_ALL_SINKS));
- text_store1_->SetFocusedTextInputClient(kWindowHandle,
- &text_input_client1_);
- text_store1_->SetInputMethodDelegate(&input_method_delegate_);
- text_store2_->SetFocusedTextInputClient(kWindowHandle,
- &text_input_client2_);
- text_store2_->SetInputMethodDelegate(&input_method_delegate_);
- fake_input_method_ = std::make_unique<FakeInputMethod>();
- fake_input_method_->SetTSFTextStoreForBridge(text_store1_.get());
- }
-
- void SwitchToDifferentTSFTextStore() {
- fake_input_method_->SetTSFTextStoreForBridge(text_store2_.get());
- }
-
- void TearDown() override {
- EXPECT_EQ(S_OK, text_store1_->UnadviseSink(sink1_.get()));
- EXPECT_EQ(S_OK, text_store2_->UnadviseSink(sink2_.get()));
- sink1_ = nullptr;
- sink2_ = nullptr;
- text_store1_ = nullptr;
- text_store2_ = nullptr;
- }
-
- // Accessors to the internal state of TSFTextStore.
-
- base::win::ScopedCOMInitializer com_initializer_;
- MockTextInputClient text_input_client1_;
- MockTextInputClient text_input_client2_;
- MockInputMethodDelegate input_method_delegate_;
- scoped_refptr<TSFTextStore> text_store1_;
- scoped_refptr<TSFTextStore> text_store2_;
- scoped_refptr<MockStoreACPSink> sink1_;
- scoped_refptr<MockStoreACPSink> sink2_;
- std::unique_ptr<FakeInputMethod> fake_input_method_;
-};
-
-namespace {
-
-TEST_F(TSFInputPanelTest, GetStatusTest) {
- TS_STATUS status = {};
- EXPECT_EQ(S_OK, text_store_->GetStatus(&status));
- EXPECT_EQ((ULONG)TS_SD_INPUTPANEMANUALDISPLAYENABLE, status.dwDynamicFlags);
- EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
- status.dwStaticFlags);
-}
-
-TEST_F(TSFInputPanelTest, ManualInputPaneToAutomaticPolicyTest) {
- TS_STATUS status = {};
- EXPECT_EQ(S_OK, text_store_->GetStatus(&status));
- EXPECT_EQ((ULONG)TS_SD_INPUTPANEMANUALDISPLAYENABLE, status.dwDynamicFlags);
- EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
- status.dwStaticFlags);
- // TODO(crbug.com/1031786): Change this test once this bug is fixed
- fake_input_method_->ShowVirtualKeyboardIfEnabled();
- EXPECT_EQ(S_OK, text_store_->GetStatus(&status));
- EXPECT_EQ((ULONG)TS_SD_INPUTPANEMANUALDISPLAYENABLE, status.dwDynamicFlags);
- EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
- status.dwStaticFlags);
-}
-
-// TODO(crbug.com/1031786): Enable this test this once this bug is fixed.
-TEST_F(TSFInputPanelTest, DISABLED_AutomaticInputPaneToManualPolicyTest) {
- TS_STATUS status = {};
- // Invoke the virtual keyboard through InputMethod
- // and test if the automatic policy flag has been set or not.
- EXPECT_EQ(S_OK, text_store_->GetStatus(&status));
- EXPECT_EQ((ULONG)TS_SD_INPUTPANEMANUALDISPLAYENABLE, status.dwDynamicFlags);
- EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
- status.dwStaticFlags);
- fake_input_method_->ShowVirtualKeyboardIfEnabled();
- EXPECT_EQ(S_OK, text_store_->GetStatus(&status));
- EXPECT_NE((ULONG)TS_SD_INPUTPANEMANUALDISPLAYENABLE, status.dwDynamicFlags);
- EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
- status.dwStaticFlags);
- fake_input_method_->DetachTextInputClient(nullptr);
- EXPECT_EQ(S_OK, text_store_->GetStatus(&status));
- EXPECT_EQ((ULONG)TS_SD_INPUTPANEMANUALDISPLAYENABLE, status.dwDynamicFlags);
- EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
- status.dwStaticFlags);
-}
-
-// TODO(crbug.com/1031786): Enable this test this once this bug is fixed.
-TEST_F(TSFMultipleInputPanelTest,
- DISABLED_InputPaneSwitchForMultipleTSFTextStoreTest) {
- TS_STATUS status = {};
- // Invoke the virtual keyboard through InputMethod
- // and test if the automatic policy flag has been set or not.
- EXPECT_EQ(S_OK, text_store1_->GetStatus(&status));
- EXPECT_EQ((ULONG)TS_SD_INPUTPANEMANUALDISPLAYENABLE, status.dwDynamicFlags);
- EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
- status.dwStaticFlags);
- fake_input_method_->ShowVirtualKeyboardIfEnabled();
- EXPECT_EQ(S_OK, text_store1_->GetStatus(&status));
- EXPECT_NE((ULONG)TS_SD_INPUTPANEMANUALDISPLAYENABLE, status.dwDynamicFlags);
- EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
- status.dwStaticFlags);
- fake_input_method_->DetachTextInputClient(nullptr);
- SwitchToDifferentTSFTextStore();
- // Different TSFTextStore is in focus so manual policy should be set in the
- // previous one
- EXPECT_EQ(S_OK, text_store1_->GetStatus(&status));
- EXPECT_EQ((ULONG)TS_SD_INPUTPANEMANUALDISPLAYENABLE, status.dwDynamicFlags);
- EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
- status.dwStaticFlags);
- EXPECT_EQ(S_OK, text_store2_->GetStatus(&status));
- EXPECT_EQ((ULONG)TS_SD_INPUTPANEMANUALDISPLAYENABLE, status.dwDynamicFlags);
- EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
- status.dwStaticFlags);
- fake_input_method_->ShowVirtualKeyboardIfEnabled();
- EXPECT_EQ(S_OK, text_store2_->GetStatus(&status));
- EXPECT_NE((ULONG)TS_SD_INPUTPANEMANUALDISPLAYENABLE, status.dwDynamicFlags);
- EXPECT_EQ((ULONG)(TS_SS_TRANSITORY | TS_SS_NOHIDDENTEXT),
- status.dwStaticFlags);
-}
-
-} // namespace
-
-} // namespace ui
diff --git a/chromium/ui/base/ime/win/tsf_input_scope.cc b/chromium/ui/base/ime/win/tsf_input_scope.cc
index d60126e2ea4..b4b60b58031 100644
--- a/chromium/ui/base/ime/win/tsf_input_scope.cc
+++ b/chromium/ui/base/ime/win/tsf_input_scope.cc
@@ -8,8 +8,8 @@
#include "base/check.h"
#include "base/compiler_specific.h"
+#include "base/containers/contains.h"
#include "base/macros.h"
-#include "base/stl_util.h"
#include "base/task/current_thread.h"
#include "base/win/windows_version.h"
diff --git a/chromium/ui/base/ime/win/tsf_text_store.cc b/chromium/ui/base/ime/win/tsf_text_store.cc
index 9a59bba2346..5289629ade9 100644
--- a/chromium/ui/base/ime/win/tsf_text_store.cc
+++ b/chromium/ui/base/ime/win/tsf_text_store.cc
@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/numerics/ranges.h"
+#include "base/trace_event/trace_event.h"
#include "base/win/scoped_variant.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/ime/win/tsf_input_scope.h"
@@ -47,7 +48,9 @@ bool GetWindowClientRect(HWND window_handle,
} // namespace
-TSFTextStore::TSFTextStore() {}
+TSFTextStore::TSFTextStore() {
+ TRACE_EVENT0("ime", "TSFTextStore::TSFTextStore");
+}
TSFTextStore::~TSFTextStore() {}
@@ -214,6 +217,9 @@ HRESULT TSFTextStore::GetScreenExt(TsViewCookie view_cookie, RECT* rect) {
rect->right = right_bottom.x;
rect->bottom = right_bottom.y;
}
+
+ TRACE_EVENT1("ime", "TSFTextStore::GetScreenExt", "control_bounding_rect",
+ gfx::Rect(*rect).ToString());
return S_OK;
}
@@ -242,12 +248,7 @@ HRESULT TSFTextStore::GetSelection(ULONG selection_index,
HRESULT TSFTextStore::GetStatus(TS_STATUS* status) {
if (!status)
return E_INVALIDARG;
- // TODO(snianu): Uncomment this once TSF fix for input pane policy is
- // serviced.
- // if (input_panel_policy_manual_)
- // status->dwDynamicFlags |= TS_SD_INPUTPANEMANUALDISPLAYENABLE;
- // else
- // status->dwDynamicFlags &= ~TS_SD_INPUTPANEMANUALDISPLAYENABLE;
+
status->dwDynamicFlags |= TS_SD_INPUTPANEMANUALDISPLAYENABLE;
// We don't support hidden text.
// TODO(IME): Remove TS_SS_TRANSITORY to support Korean reconversion
@@ -408,6 +409,8 @@ HRESULT TSFTextStore::GetTextExt(TsViewCookie view_cookie,
result_rect.value())
.ToRECT();
*clipped = FALSE;
+ TRACE_EVENT1("ime", "TSFTextStore::GetTextExt", "selection_bounding_rect",
+ gfx::Rect(*rect).ToString());
return S_OK;
}
@@ -619,7 +622,7 @@ HRESULT TSFTextStore::RequestLock(DWORD lock_flags, HRESULT* result) {
if (!text_input_client_)
return E_UNEXPECTED;
- // If string_pending_insertion_ is empty, then there are three cases:
+ // If string_pending_insertion_ is empty, then there are four cases:
// 1. there is no composition We only need to do comparison between our
// cache and latest textinputstate and send notifications accordingly.
// 2. A new composition is about to start on existing text. We need to start
@@ -627,16 +630,20 @@ HRESULT TSFTextStore::RequestLock(DWORD lock_flags, HRESULT* result) {
// 3. There is composition. User cancels the composition by deleting all of
// the composing text, we need to reset the composition_start_ and call
// into blink to complete the existing composition(later in this method).
+ // 4. There is no composition. IME removes previous inserted text. We need to
+ // ask tic to delete the text range.
if (string_pending_insertion_.empty()) {
if (!text_input_client_->HasCompositionText()) {
+ // Remove replacing text.
+ if (new_text_inserted_ && !replace_text_range_.is_empty() &&
+ !replace_text_size_) {
+ is_tic_write_in_progress_ = true;
+ text_input_client_->SetEditableSelectionRange(replace_text_range_);
+ text_input_client_->ExtendSelectionAndDelete(0, 0);
+ is_tic_write_in_progress_ = false;
+ }
if (has_composition_range_ && on_start_composition_called_) {
is_tic_write_in_progress_ = true;
- // Remove replacing text first before starting composition.
- if (new_text_inserted_ && !replace_text_range_.is_empty() &&
- !replace_text_size_) {
- text_input_client_->SetEditableSelectionRange(replace_text_range_);
- text_input_client_->ExtendSelectionAndDelete(0, 0);
- }
string_pending_insertion_ = string_buffer_document_.substr(
composition_range_.GetMin(), composition_range_.length());
StartCompositionOnExistingText();
@@ -802,6 +809,7 @@ HRESULT TSFTextStore::SetText(DWORD flags,
const wchar_t* text_buffer,
ULONG text_buffer_size,
TS_TEXTCHANGE* text_change) {
+ TRACE_EVENT0("ime", "TSFTextStore::SetText");
if (!HasReadWriteLock())
return TS_E_NOLOCK;
@@ -838,6 +846,7 @@ HRESULT TSFTextStore::UnadviseSink(IUnknown* unknown) {
HRESULT TSFTextStore::OnStartComposition(ITfCompositionView* composition_view,
BOOL* ok) {
+ TRACE_EVENT0("ime", "TSFTextStore::OnStartComposition");
if (ok)
*ok = TRUE;
@@ -851,6 +860,7 @@ HRESULT TSFTextStore::OnUpdateComposition(ITfCompositionView* composition_view,
}
HRESULT TSFTextStore::OnEndComposition(ITfCompositionView* composition_view) {
+ TRACE_EVENT0("ime", "TSFTextStore::OnEndComposition");
return S_OK;
}
@@ -911,6 +921,7 @@ void TSFTextStore::DispatchKeyEvent(ui::EventType type,
HRESULT TSFTextStore::OnEndEdit(ITfContext* context,
TfEditCookie read_only_edit_cookie,
ITfEditRecord* edit_record) {
+ TRACE_EVENT0("ime", "TSFTextStore::OnEndEdit");
if (!context || !edit_record)
return E_INVALIDARG;
@@ -980,6 +991,7 @@ HRESULT TSFTextStore::OnEndEdit(ITfContext* context,
bool TSFTextStore::GetDisplayAttribute(TfGuidAtom guid_atom,
TF_DISPLAYATTRIBUTE* attribute) {
+ TRACE_EVENT0("ime", "TSFTextStore::GetDisplayAttribute");
GUID guid;
if (FAILED(category_manager_->GetGUID(guid_atom, &guid)))
return false;
@@ -1073,7 +1085,6 @@ bool TSFTextStore::GetCompositionStatus(
ImeTextSpan span;
span.start_offset = start_pos;
span.end_offset = start_pos + length;
- span.underline_color = SK_ColorBLACK;
span.background_color = SK_ColorTRANSPARENT;
if (selection_.EqualsIgnoringDirection(
gfx::Range(span.start_offset, span.end_offset))) {
@@ -1087,12 +1098,29 @@ bool TSFTextStore::GetCompositionStatus(
return true;
}
+void TSFTextStore::ResetCompositionState() {
+ previous_composition_string_.clear();
+ previous_composition_start_ = 0;
+ previous_composition_selection_range_ = gfx::Range::InvalidRange();
+ previous_text_spans_.clear();
+
+ string_pending_insertion_.clear();
+ composition_range_.set_start(0);
+ composition_range_.set_end(0);
+
+ selection_ = gfx::Range(composition_from_client_.end(),
+ composition_from_client_.end());
+ composition_start_ = selection_.end();
+}
+
bool TSFTextStore::TerminateComposition() {
+ TRACE_EVENT0("ime", "TSFTextStore::TerminateComposition");
if (context_ && has_composition_range_) {
Microsoft::WRL::ComPtr<ITfContextOwnerCompositionServices> service;
if (SUCCEEDED(context_->QueryInterface(IID_PPV_ARGS(&service)))) {
service->TerminateComposition(nullptr);
+ has_composition_range_ = false;
return true;
}
}
@@ -1108,6 +1136,10 @@ void TSFTextStore::CalculateTextandSelectionDiffAndNotifyIfNeeded() {
is_tic_write_in_progress_)
return;
+ // TODO(snianu) Perhaps we can do the diff at the TextInputManager layer and
+ // only report the diffs?
+ TRACE_EVENT0("ime",
+ "TSFTextStore::CalculateTextandSelectionDiffAndNotifyIfNeeded");
gfx::Range latest_buffer_range_from_client;
base::string16 latest_buffer_from_client;
gfx::Range latest_selection_from_client;
@@ -1212,10 +1244,17 @@ void TSFTextStore::CalculateTextandSelectionDiffAndNotifyIfNeeded() {
// into us during notification.
is_notification_in_progress_ = true;
if (notify_text_change && text_changed) {
+ TRACE_EVENT2(
+ "ime", "TSFTextStore::CalculateTextandSelectionDiffAndNotifyIfNeeded",
+ "text_change_start", std::to_string(text_change.acpStart),
+ "text_change_end", std::to_string(text_change.acpNewEnd));
text_store_acp_sink_->OnTextChange(0, &text_change);
}
if (notify_selection_change && selection_changed) {
+ TRACE_EVENT1(
+ "ime", "TSFTextStore::CalculateTextandSelectionDiffAndNotifyIfNeeded",
+ "new_selection", selection_.ToString());
text_store_acp_sink_->OnSelectionChange();
}
is_notification_in_progress_ = false;
@@ -1261,7 +1300,14 @@ bool TSFTextStore::CancelComposition() {
// TODO(IME): Check other platforms to see if |CancelComposition()| is
// actually working or not.
- return ConfirmComposition();
+ if (edit_flag_ || !text_input_client_)
+ return false;
+
+ TRACE_EVENT0("ime", "TSFTextStore::CancelComposition");
+
+ ResetCompositionState();
+
+ return TerminateComposition();
}
bool TSFTextStore::ConfirmComposition() {
@@ -1275,34 +1321,22 @@ bool TSFTextStore::ConfirmComposition() {
if (!text_input_client_)
return false;
- previous_composition_string_.clear();
- previous_composition_start_ = 0;
- previous_composition_selection_range_ = gfx::Range::InvalidRange();
- previous_text_spans_.clear();
- string_pending_insertion_.clear();
- selection_ = gfx::Range(composition_from_client_.end(),
- composition_from_client_.end());
- composition_start_ = selection_.end();
+ ResetCompositionState();
return TerminateComposition();
}
-void TSFTextStore::SetInputPanelPolicy(bool input_panel_policy_manual) {
- input_panel_policy_manual_ = input_panel_policy_manual;
- // This notification tells TSF that the input pane flag has changed.
- // TSF queries for the status of this flag using GetStatus and gets
- // the updated value.
- text_store_acp_sink_->OnStatusChange(TS_SD_INPUTPANEMANUALDISPLAYENABLE);
-}
-
void TSFTextStore::SendOnLayoutChange() {
// A re-entrant call leads to infinite loop in TSF.
// We bail out if are in the process of notifying TSF about changes.
if (is_notification_in_progress_)
return;
CalculateTextandSelectionDiffAndNotifyIfNeeded();
- if (text_store_acp_sink_ && (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE))
+ if (text_store_acp_sink_ &&
+ (text_store_acp_sink_mask_ & TS_AS_LAYOUT_CHANGE)) {
+ TRACE_EVENT0("ime", "TSFTextStore::SendOnLayoutChange");
text_store_acp_sink_->OnLayoutChange(TS_LC_CHANGE, 0);
+ }
}
bool TSFTextStore::HasReadLock() const {
@@ -1408,7 +1442,9 @@ void TSFTextStore::CommitTextAndEndCompositionIfAny(size_t old_size,
composition_text.selection.set_end(new_committed_string.size());
text_input_client_->SetCompositionText(composition_text);
}
- text_input_client_->InsertText(new_committed_string);
+ text_input_client_->InsertText(
+ new_committed_string,
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
} else {
text_input_client_->ClearCompositionText();
}
diff --git a/chromium/ui/base/ime/win/tsf_text_store.h b/chromium/ui/base/ime/win/tsf_text_store.h
index efcc912812e..f41d80116ba 100644
--- a/chromium/ui/base/ime/win/tsf_text_store.h
+++ b/chromium/ui/base/ime/win/tsf_text_store.h
@@ -251,12 +251,13 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFTextStore
// Sends OnLayoutChange() via |text_store_acp_sink_|.
void SendOnLayoutChange();
- void SetInputPanelPolicy(bool input_panel_policy_manual);
-
private:
friend class TSFTextStoreTest;
friend class TSFTextStoreTestCallback;
+ // Reset states tracking the composition in the text store.
+ void ResetCompositionState();
+
// Terminate an active composition for this text store.
bool TerminateComposition();
@@ -439,15 +440,6 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) TSFTextStore
Microsoft::WRL::ComPtr<ITfDisplayAttributeMgr> display_attribute_manager_;
Microsoft::WRL::ComPtr<ITfContext> context_;
- // input_panel_policy_manual_ equals to false would make the SIP policy
- // to automatic meaning TSF would raise/dismiss the SIP based on TSFTextStore
- // focus and other heuristics that input service have added on Windows to
- // provide a consistent behavior across all apps on Windows.
- // input_panel_policy_manual_ equals to true would make the SIP policy to
- // manual meaning TSF wouldn't raise/dismiss the SIP automatically. This is
- // used to control the SIP behavior based on user interaction with the page.
- bool input_panel_policy_manual_ = true;
-
DISALLOW_COPY_AND_ASSIGN(TSFTextStore);
};
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 0e97f5ef1b7..8b13dc1df3c 100644
--- a/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
+++ b/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -37,7 +37,10 @@ class MockTextInputClient : public TextInputClient {
MOCK_METHOD1(SetCompositionText, void(const ui::CompositionText&));
MOCK_METHOD1(ConfirmCompositionText, uint32_t(bool));
MOCK_METHOD0(ClearCompositionText, void());
- MOCK_METHOD1(InsertText, void(const base::string16&));
+ MOCK_METHOD2(
+ InsertText,
+ void(const base::string16&,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior));
MOCK_METHOD1(InsertChar, void(const ui::KeyEvent&));
MOCK_CONST_METHOD0(GetTextInputType, ui::TextInputType());
MOCK_CONST_METHOD0(GetTextInputMode, ui::TextInputMode());
@@ -254,7 +257,7 @@ class TSFTextStoreTestCallback {
void SetTextTest(LONG acp_start,
LONG acp_end,
- const base::string16& text,
+ const std::wstring& text,
HRESULT error_code) {
TS_TEXTCHANGE change = {};
ASSERT_EQ(error_code,
@@ -269,7 +272,7 @@ class TSFTextStoreTestCallback {
void GetTextTest(LONG acp_start,
LONG acp_end,
- const base::string16& expected_string,
+ const std::wstring& expected_string,
LONG expected_next_acp) {
wchar_t buffer[1024] = {};
ULONG text_buffer_copied = 0;
@@ -281,7 +284,7 @@ class TSFTextStoreTestCallback {
&run_info_buffer_copied, &next_acp));
ASSERT_EQ(expected_string.size(), text_buffer_copied);
EXPECT_EQ(expected_string,
- base::string16(buffer, buffer + text_buffer_copied));
+ std::wstring(buffer, buffer + text_buffer_copied));
if (text_buffer_copied > 0) {
EXPECT_EQ(1u, run_info_buffer_copied);
EXPECT_EQ(expected_string.size(), run_info.uCount);
@@ -363,6 +366,22 @@ class TSFTextStoreTestCallback {
acp_end, &rect, &clipped));
}
+ void ResetCompositionStateTest() {
+ EXPECT_TRUE(text_store_->previous_composition_string_.empty());
+ EXPECT_EQ(0u, text_store_->previous_composition_start_);
+ EXPECT_EQ(gfx::Range::InvalidRange(),
+ text_store_->previous_composition_selection_range_);
+ EXPECT_TRUE(text_store_->previous_text_spans_.empty());
+
+ EXPECT_TRUE(text_store_->string_pending_insertion_.empty());
+ EXPECT_TRUE(text_store_->composition_range_.is_empty());
+ EXPECT_EQ(text_store_->composition_from_client_.end(),
+ text_store_->selection_.start());
+ EXPECT_EQ(text_store_->composition_from_client_.end(),
+ text_store_->selection_.end());
+ EXPECT_EQ(text_store_->selection_.end(), text_store_->composition_start_);
+ }
+
void SetHasCompositionText(bool compText) {
has_composition_text_ = compText;
}
@@ -382,7 +401,7 @@ class TSFTextStoreTestCallback {
composition_range_.set_end(end);
}
- void SetTextBuffer(const wchar_t* buffer) {
+ void SetTextBuffer(const base::char16* buffer) {
text_buffer_.clear();
text_buffer_.assign(buffer);
}
@@ -391,7 +410,7 @@ class TSFTextStoreTestCallback {
gfx::Range text_range_;
gfx::Range selection_range_;
gfx::Range composition_range_;
- base::string16 text_buffer_ = L"";
+ base::string16 text_buffer_;
scoped_refptr<TSFTextStore> text_store_;
private:
@@ -413,7 +432,7 @@ TEST_F(TSFTextStoreTest, GetStatusTest) {
TEST_F(TSFTextStoreTest, QueryInsertTest) {
LONG result_start = 0;
LONG result_end = 0;
- *string_buffer() = L"";
+ *string_buffer() = base::string16();
*composition_start() = 0;
EXPECT_EQ(E_INVALIDARG,
text_store_->QueryInsert(0, 0, 0, nullptr, &result_end));
@@ -423,7 +442,7 @@ TEST_F(TSFTextStoreTest, QueryInsertTest) {
text_store_->QueryInsert(0, 0, 0, &result_start, &result_end));
EXPECT_EQ(0, result_start);
EXPECT_EQ(0, result_end);
- *string_buffer() = L"1234";
+ *string_buffer() = STRING16_LITERAL("1234");
*composition_start() = 1;
EXPECT_EQ(S_OK,
text_store_->QueryInsert(0, 1, 0, &result_start, &result_end));
@@ -638,16 +657,18 @@ class RequestLockTextChangeTestCallback : public TSFTextStoreTestCallback {
EXPECT_TRUE(HasReadWriteLock());
*edit_flag() = true;
- SetInternalState(L"012345", 6, 6, 6);
+ SetInternalState(STRING16_LITERAL("012345"), 6, 6, 6);
text_spans()->clear();
state_ = 2;
return S_OK;
}
- void InsertText(const base::string16& text) {
+ void InsertText(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
EXPECT_EQ(2, state_);
- EXPECT_EQ(L"012345", text);
+ EXPECT_EQ(STRING16_LITERAL("012345"), text);
state_ = 3;
}
@@ -658,7 +679,7 @@ class RequestLockTextChangeTestCallback : public TSFTextStoreTestCallback {
}
bool GetTextFromRange(const gfx::Range& range, base::string16* text) const {
- base::string16 string_buffer = L"012345";
+ base::string16 string_buffer = STRING16_LITERAL("012345");
*text = string_buffer.substr(range.GetMin(), range.length());
return true;
}
@@ -705,7 +726,7 @@ TEST_F(TSFTextStoreTest, RequestLockOnTextChangeTest) {
EXPECT_CALL(*sink_, OnSelectionChange())
.WillOnce(Invoke(&callback,
&RequestLockTextChangeTestCallback::OnSelectionChange));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(
Invoke(&callback, &RequestLockTextChangeTestCallback::InsertText));
EXPECT_CALL(text_input_client_, GetEditableSelectionRange(_))
@@ -734,12 +755,12 @@ class SelectionTestCallback : public TSFTextStoreTestCallback {
: TSFTextStoreTestCallback(text_store) {}
HRESULT ReadLockGranted(DWORD flags) {
- SetInternalState(L"", 0, 0, 0);
+ SetInternalState(base::string16(), 0, 0, 0);
GetSelectionTest(0, 0);
SetSelectionTest(0, 0, TF_E_NOLOCK);
- SetInternalState(L"012345", 0, 0, 3);
+ SetInternalState(STRING16_LITERAL("012345"), 0, 0, 3);
GetSelectionTest(0, 3);
SetSelectionTest(0, 0, TF_E_NOLOCK);
@@ -748,7 +769,7 @@ class SelectionTestCallback : public TSFTextStoreTestCallback {
}
HRESULT ReadWriteLockGranted(DWORD flags) {
- SetInternalState(L"", 0, 0, 0);
+ SetInternalState(base::string16(), 0, 0, 0);
SetSelectionTest(0, 0, S_OK);
GetSelectionTest(0, 0);
@@ -756,7 +777,7 @@ class SelectionTestCallback : public TSFTextStoreTestCallback {
SetSelectionTest(1, 0, TF_E_INVALIDPOS);
SetSelectionTest(1, 1, TF_E_INVALIDPOS);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetSelectionTest(0, 0, S_OK);
SetSelectionTest(0, 1, S_OK);
@@ -833,7 +854,7 @@ class SetGetTextTestCallback : public TSFTextStoreTestCallback {
GetTextTest(0, 0, L"", 0);
GetTextErrorTest(0, 1, TF_E_INVALIDPOS);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
GetTextErrorTest(-1, -1, TF_E_INVALIDPOS);
GetTextErrorTest(-1, 0, TF_E_INVALIDPOS);
@@ -895,13 +916,13 @@ class SetGetTextTestCallback : public TSFTextStoreTestCallback {
}
HRESULT ReadWriteLockGranted(DWORD flags) {
- SetInternalState(L"", 0, 0, 0);
+ SetInternalState(base::string16(), 0, 0, 0);
SetTextTest(0, 0, L"", S_OK);
- SetInternalState(L"", 0, 0, 0);
+ SetInternalState(base::string16(), 0, 0, 0);
SetTextTest(0, 1, L"", TS_E_INVALIDPOS);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(0, 0, L"", S_OK);
SetTextTest(0, 1, L"", S_OK);
@@ -923,17 +944,17 @@ class SetGetTextTestCallback : public TSFTextStoreTestCallback {
SetTextTest(3, 3, L"", TS_E_INVALIDPOS);
GetTextTest(0, -1, L"4", 1);
GetSelectionTest(1, 1);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(3, 6, L"", S_OK);
GetTextTest(0, -1, L"0126", 4);
GetSelectionTest(3, 3);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(3, 7, L"", S_OK);
GetTextTest(0, -1, L"012", 3);
GetSelectionTest(3, 3);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(3, 8, L"", TS_E_INVALIDPOS);
@@ -944,12 +965,12 @@ class SetGetTextTestCallback : public TSFTextStoreTestCallback {
SetTextTest(6, 6, L"", S_OK);
GetTextTest(0, -1, L"0123456", 7);
GetSelectionTest(6, 6);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(6, 7, L"", S_OK);
GetTextTest(0, -1, L"012345", 6);
GetSelectionTest(6, 6);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(6, 8, L"", TS_E_INVALIDPOS);
@@ -961,36 +982,36 @@ class SetGetTextTestCallback : public TSFTextStoreTestCallback {
SetTextTest(7, 7, L"", S_OK);
GetTextTest(0, -1, L"0123456", 7);
GetSelectionTest(7, 7);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(7, 8, L"", TS_E_INVALIDPOS);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(3, 3, L"abc", S_OK);
GetTextTest(0, -1, L"012abc3456", 10);
GetSelectionTest(3, 6);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(3, 6, L"abc", S_OK);
GetTextTest(0, -1, L"012abc6", 7);
GetSelectionTest(3, 6);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(3, 7, L"abc", S_OK);
GetTextTest(0, -1, L"012abc", 6);
GetSelectionTest(3, 6);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(6, 6, L"abc", S_OK);
GetTextTest(0, -1, L"012345abc6", 10);
GetSelectionTest(6, 9);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(6, 7, L"abc", S_OK);
GetTextTest(0, -1, L"012345abc", 9);
GetSelectionTest(6, 9);
- SetInternalState(L"0123456", 3, 3, 3);
+ SetInternalState(STRING16_LITERAL("0123456"), 3, 3, 3);
SetTextTest(7, 7, L"abc", S_OK);
GetTextTest(0, -1, L"0123456abc", 10);
GetSelectionTest(7, 10);
@@ -1033,12 +1054,12 @@ class InsertTextAtSelectionTestCallback : public TSFTextStoreTestCallback {
HRESULT ReadLockGranted(DWORD flags) {
const wchar_t kBuffer[] = L"0123456789";
- SetInternalState(L"abcedfg", 0, 0, 0);
+ SetInternalState(STRING16_LITERAL("abcedfg"), 0, 0, 0);
InsertTextAtSelectionQueryOnlyTest(kBuffer, 10, 0, 0);
GetSelectionTest(0, 0);
InsertTextAtSelectionQueryOnlyTest(kBuffer, 0, 0, 0);
- SetInternalState(L"abcedfg", 0, 2, 5);
+ SetInternalState(STRING16_LITERAL("abcedfg"), 0, 2, 5);
InsertTextAtSelectionQueryOnlyTest(kBuffer, 10, 2, 5);
GetSelectionTest(2, 5);
InsertTextAtSelectionQueryOnlyTest(kBuffer, 0, 2, 5);
@@ -1052,34 +1073,34 @@ class InsertTextAtSelectionTestCallback : public TSFTextStoreTestCallback {
}
HRESULT ReadWriteLockGranted(DWORD flags) {
- SetInternalState(L"abcedfg", 0, 0, 0);
+ SetInternalState(STRING16_LITERAL("abcedfg"), 0, 0, 0);
const wchar_t kBuffer[] = L"0123456789";
InsertTextAtSelectionQueryOnlyTest(kBuffer, 10, 0, 0);
GetSelectionTest(0, 0);
InsertTextAtSelectionQueryOnlyTest(kBuffer, 0, 0, 0);
- SetInternalState(L"", 0, 0, 0);
+ SetInternalState(base::string16(), 0, 0, 0);
InsertTextAtSelectionTest(kBuffer, 10, 0, 10, 0, 0, 10);
GetSelectionTest(0, 10);
GetTextTest(0, -1, L"0123456789", 10);
- SetInternalState(L"abcedfg", 0, 0, 0);
+ SetInternalState(STRING16_LITERAL("abcedfg"), 0, 0, 0);
InsertTextAtSelectionTest(kBuffer, 10, 0, 10, 0, 0, 10);
GetSelectionTest(0, 10);
GetTextTest(0, -1, L"0123456789abcedfg", 17);
- SetInternalState(L"abcedfg", 0, 0, 3);
+ SetInternalState(STRING16_LITERAL("abcedfg"), 0, 0, 3);
InsertTextAtSelectionTest(kBuffer, 0, 0, 0, 0, 3, 0);
GetSelectionTest(0, 0);
GetTextTest(0, -1, L"edfg", 4);
- SetInternalState(L"abcedfg", 0, 3, 7);
+ SetInternalState(STRING16_LITERAL("abcedfg"), 0, 3, 7);
InsertTextAtSelectionTest(kBuffer, 10, 3, 13, 3, 7, 13);
GetSelectionTest(3, 13);
GetTextTest(0, -1, L"abc0123456789", 13);
- SetInternalState(L"abcedfg", 0, 7, 7);
+ SetInternalState(STRING16_LITERAL("abcedfg"), 0, 7, 7);
InsertTextAtSelectionTest(kBuffer, 10, 7, 17, 7, 7, 17);
GetSelectionTest(7, 17);
GetTextTest(0, -1, L"abcedfg0123456789", 17);
@@ -1140,7 +1161,7 @@ class ScenarioTestCallback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"axyzc", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("axyzc"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(5u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -1174,10 +1195,14 @@ class ScenarioTestCallback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText2(const base::string16& text) { EXPECT_EQ(L"axy", text); }
+ void InsertText2(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("axy"), text);
+ }
void SetCompositionText2(const ui::CompositionText& composition) {
- EXPECT_EQ(L"ZCPc", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("ZCPc"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(4u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -1198,8 +1223,10 @@ class ScenarioTestCallback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText3(const base::string16& text) {
- EXPECT_EQ(L"ZCPc", text);
+ void InsertText3(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("ZCPc"), text);
has_composition_text_ = false;
}
@@ -1227,7 +1254,7 @@ class ScenarioTestCallback : public TSFTextStoreTestCallback {
}
void SetCompositionText4(const ui::CompositionText& composition) {
- EXPECT_EQ(L"EFGH", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("EFGH"), composition.text);
EXPECT_EQ(4u, composition.selection.start());
EXPECT_EQ(4u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -1258,7 +1285,7 @@ class ScenarioTestCallback : public TSFTextStoreTestCallback {
// still need to call into TextInputClient to set composition text
// to update selection range even though composition text is unchanged.
void SetCompositionText5(const ui::CompositionText& composition) {
- EXPECT_EQ(L"EFGH", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("EFGH"), composition.text);
EXPECT_EQ(2u, composition.selection.start());
EXPECT_EQ(2u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -1279,7 +1306,7 @@ TEST_F(TSFTextStoreTest, ScenarioTest) {
.WillOnce(Invoke(&callback, &ScenarioTestCallback::SetCompositionText4))
.WillOnce(Invoke(&callback, &ScenarioTestCallback::SetCompositionText5));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(Invoke(&callback, &ScenarioTestCallback::InsertText2))
.WillOnce(Invoke(&callback, &ScenarioTestCallback::InsertText3));
@@ -1318,7 +1345,7 @@ class GetTextExtTestCallback : public TSFTextStoreTestCallback {
layout_prepared_character_num_(0) {}
HRESULT LockGranted(DWORD flags) {
- SetInternalState(L"0123456789012", 0, 0, 0);
+ SetInternalState(STRING16_LITERAL("0123456789012"), 0, 0, 0);
layout_prepared_character_num_ = 13;
has_composition_text_ = true;
@@ -1344,23 +1371,23 @@ class GetTextExtTestCallback : public TSFTextStoreTestCallback {
has_composition_text_ = false;
GetTextExtTest(view_cookie, 0, 0, 1, 2, 4, 6);
- SetInternalState(L"", 0, 0, 0);
+ SetInternalState(base::string16(), 0, 0, 0);
GetTextExtTest(view_cookie, 0, 0, 1, 2, 4, 6);
// Last character is not available due to timing issue of async API.
// In this case, we will get first character bounds instead of whole text
// bounds.
- SetInternalState(L"abc", 0, 0, 3);
+ SetInternalState(STRING16_LITERAL("abc"), 0, 0, 3);
layout_prepared_character_num_ = 2;
has_composition_text_ = true;
GetTextExtTest(view_cookie, 0, 0, 11, 12, 11, 20);
// TODO(nona, kinaba): Remove following test case after PPAPI supporting
// GetCompositionCharacterBounds.
- SetInternalState(L"a", 0, 0, 1);
+ SetInternalState(STRING16_LITERAL("a"), 0, 0, 1);
layout_prepared_character_num_ = 0;
GetTextExtTest(view_cookie, 0, 1, 1, 2, 4, 6);
- SetInternalState(L"abc", 0, 0, 3);
+ SetInternalState(STRING16_LITERAL("abc"), 0, 0, 3);
GetTextExtNoLayoutTest(view_cookie, 2, 3);
return S_OK;
@@ -1511,7 +1538,7 @@ class KeyEventTestCallback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"a", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("a"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(1u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -1554,13 +1581,15 @@ class KeyEventTestCallback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText2(const base::string16& text) {
- EXPECT_EQ(L"a", text);
+ void InsertText2(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("a"), text);
SetHasCompositionText(false);
}
void SetCompositionText2(const ui::CompositionText& composition) {
- EXPECT_EQ(L"B", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("B"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(1u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -1597,8 +1626,10 @@ class KeyEventTestCallback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText3(const base::string16& text) {
- EXPECT_EQ(L"B", text);
+ void InsertText3(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("B"), text);
SetHasCompositionText(false);
}
@@ -1623,7 +1654,7 @@ TEST_F(TSFTextStoreTest, KeyEventTest) {
.WillOnce(Invoke(&callback, &KeyEventTestCallback::SetCompositionText1))
.WillOnce(Invoke(&callback, &KeyEventTestCallback::SetCompositionText2));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(Invoke(&callback, &KeyEventTestCallback::InsertText2))
.WillOnce(Invoke(&callback, &KeyEventTestCallback::InsertText3));
@@ -1692,7 +1723,7 @@ class AccessibilityEventTestCallback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"a", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("a"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(1u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -1710,7 +1741,7 @@ class AccessibilityEventTestCallback : public TSFTextStoreTestCallback {
const gfx::Range& range,
const base::string16& active_composition_text,
bool committed_composition) {
- EXPECT_EQ(L"a", active_composition_text);
+ EXPECT_EQ(STRING16_LITERAL("a"), active_composition_text);
EXPECT_EQ(0u, range.start());
EXPECT_EQ(1u, range.end());
}
@@ -1767,7 +1798,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
GetTextTest(0, -1, L"", 0);
SetTextRange(0, 1);
- SetTextBuffer(L"a");
+ SetTextBuffer(STRING16_LITERAL("a"));
SetSelectionRange(1, 1);
*composition_start() = 1;
return S_OK;
@@ -1812,16 +1843,18 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText2(const base::string16& text) {
- EXPECT_EQ(L"bcde", text);
+ void InsertText2(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("bcde"), text);
SetTextRange(0, 5);
SetSelectionRange(5, 5);
- SetTextBuffer(L"abcde");
+ SetTextBuffer(STRING16_LITERAL("abcde"));
}
HRESULT LockGranted3(DWORD flags) {
SetTextRange(0, 5);
- SetTextBuffer(L"about");
+ SetTextBuffer(STRING16_LITERAL("about"));
SetSelectionRange(0, 5);
return S_OK;
}
@@ -1857,7 +1890,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
HRESULT LockGranted4(DWORD flags) {
SetTextRange(0, 5);
- SetTextBuffer(L"abFGt");
+ SetTextBuffer(STRING16_LITERAL("abFGt"));
SetSelectionRange(3, 4);
return S_OK;
}
@@ -1893,7 +1926,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
HRESULT LockGranted5(DWORD flags) {
SetTextRange(0, 3);
- SetTextBuffer(L"aHI");
+ SetTextBuffer(STRING16_LITERAL("aHI"));
SetSelectionRange(3, 3);
return S_OK;
}
@@ -1929,7 +1962,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
HRESULT LockGranted6(DWORD flags) {
SetTextRange(0, 5);
- SetTextBuffer(L"JKLMN");
+ SetTextBuffer(STRING16_LITERAL("JKLMN"));
SetSelectionRange(2, 5);
return S_OK;
}
@@ -1965,7 +1998,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
HRESULT LockGranted7(DWORD flags) {
SetTextRange(0, 0);
- SetTextBuffer(L"");
+ SetTextBuffer(STRING16_LITERAL(""));
SetSelectionRange(0, 0);
return S_OK;
}
@@ -2001,7 +2034,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
HRESULT LockGranted8(DWORD flags) {
SetTextRange(0, 3);
- SetTextBuffer(L"OPQ");
+ SetTextBuffer(STRING16_LITERAL("OPQ"));
SetSelectionRange(0, 2);
return S_OK;
}
@@ -2037,7 +2070,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
HRESULT LockGranted9(DWORD flags) {
SetTextRange(0, 3);
- SetTextBuffer(L"OPR");
+ SetTextBuffer(STRING16_LITERAL("OPR"));
SetSelectionRange(2, 3);
return S_OK;
}
@@ -2073,7 +2106,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
HRESULT LockGranted10(DWORD flags) {
SetTextRange(0, 3);
- SetTextBuffer(L"SPR");
+ SetTextBuffer(STRING16_LITERAL("SPR"));
SetSelectionRange(0, 1);
return S_OK;
}
@@ -2109,7 +2142,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
// 11. renderer proc changes buffer from "SPR" to "STPR".
HRESULT LockGranted11(DWORD flags) {
SetTextRange(0, 4);
- SetTextBuffer(L"STPR");
+ SetTextBuffer(STRING16_LITERAL("STPR"));
SetSelectionRange(2, 2);
return S_OK;
}
@@ -2146,7 +2179,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
// 12. renderer proc changes buffer from "STPR" to "PR".
HRESULT LockGranted12(DWORD flags) {
SetTextRange(0, 2);
- SetTextBuffer(L"PR");
+ SetTextBuffer(STRING16_LITERAL("PR"));
SetSelectionRange(0, 0);
return S_OK;
}
@@ -2183,7 +2216,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
// 13. renderer proc changes buffer from "PR" to "UPR".
HRESULT LockGranted13(DWORD flags) {
SetTextRange(0, 3);
- SetTextBuffer(L"UPR");
+ SetTextBuffer(STRING16_LITERAL("UPR"));
SetSelectionRange(1, 1);
return S_OK;
}
@@ -2220,7 +2253,7 @@ class DiffingAlgorithmTestCallback : public TSFTextStoreTestCallback {
// 14. renderer proc changes buffer from "UPR" to "UPVWR".
HRESULT LockGranted14(DWORD flags) {
SetTextRange(0, 5);
- SetTextBuffer(L"UPVWR");
+ SetTextBuffer(STRING16_LITERAL("UPVWR"));
SetSelectionRange(4, 4);
return S_OK;
}
@@ -2309,7 +2342,7 @@ TEST_F(TSFTextStoreTest, DiffingAlgorithmTest) {
.WillOnce(Invoke(&callback,
&DiffingAlgorithmTestCallback::OnSelectionChange14));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(Invoke(&callback, &DiffingAlgorithmTestCallback::InsertText2));
EXPECT_CALL(*sink_, OnLockGranted(_))
@@ -2468,7 +2501,7 @@ class RegressionTestCallback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"a", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("a"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(1u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -2518,13 +2551,15 @@ class RegressionTestCallback : public TSFTextStoreTestCallback {
return ui::EventDispatchDetails();
}
- void InsertText2(const base::string16& text) {
- EXPECT_EQ(L"a", text);
+ void InsertText2(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("a"), text);
SetHasCompositionText(false);
}
void SetCompositionText2(const ui::CompositionText& composition) {
- EXPECT_EQ(L"a", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("a"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(1u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -2550,8 +2585,10 @@ class RegressionTestCallback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText3(const base::string16& text) {
- EXPECT_EQ(L"a", text);
+ void InsertText3(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("a"), text);
SetHasCompositionText(false);
}
@@ -2581,12 +2618,16 @@ class RegressionTestCallback : public TSFTextStoreTestCallback {
// We expect this call since the composition was started and committed during
// same edit session.
void SetCompositionText4(const ui::CompositionText& composition) {
- EXPECT_EQ(L"c", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("c"), composition.text);
ASSERT_EQ(1u, composition.ime_text_spans.size());
ASSERT_EQ(gfx::Range(1, 1), composition.selection);
}
- void InsertText4(const base::string16& text) { EXPECT_EQ(L"c", text); }
+ void InsertText4(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("c"), text);
+ }
HRESULT LockGranted5(DWORD flags) {
GetTextTest(0, -1, L"aac", 3);
@@ -2621,7 +2662,7 @@ class RegressionTestCallback : public TSFTextStoreTestCallback {
}
void SetCompositionText5(const ui::CompositionText& composition) {
- EXPECT_EQ(L"d", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("d"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(1u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -2650,8 +2691,10 @@ class RegressionTestCallback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText6(const base::string16& text) {
- EXPECT_EQ(L"e", text);
+ void InsertText6(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("e"), text);
SetHasCompositionText(false);
}
@@ -2680,7 +2723,7 @@ TEST_F(TSFTextStoreTest, RegressionTest) {
.WillOnce(
Invoke(&callback, &RegressionTestCallback::DispatchKeyEventPostIME5));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(Invoke(&callback, &RegressionTestCallback::InsertText2))
.WillOnce(Invoke(&callback, &RegressionTestCallback::InsertText3))
.WillOnce(Invoke(&callback, &RegressionTestCallback::InsertText4))
@@ -2759,7 +2802,7 @@ class RegressionTest2Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText2(const ui::CompositionText& composition) {
- EXPECT_EQ(L"DE", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("DE"), composition.text);
EXPECT_EQ(2u, composition.selection.start());
EXPECT_EQ(2u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -2786,8 +2829,10 @@ class RegressionTest2Callback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText3(const base::string16& text) {
- EXPECT_EQ(L"DE", text);
+ void InsertText3(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("DE"), text);
SetHasCompositionText(false);
}
@@ -2801,7 +2846,7 @@ TEST_F(TSFTextStoreTest, RegressionTest2) {
.WillOnce(
Invoke(&callback, &RegressionTest2Callback::SetCompositionText2));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(Invoke(&callback, &RegressionTest2Callback::InsertText3));
EXPECT_CALL(*sink_, OnLockGranted(_))
@@ -2856,7 +2901,7 @@ class RegressionTest3Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"a", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("a"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(1u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -2887,7 +2932,7 @@ class RegressionTest3Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText2(const ui::CompositionText& composition) {
- EXPECT_EQ(L"", composition.text);
+ EXPECT_EQ(base::string16(), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(0u, composition.selection.end());
ASSERT_EQ(0u, composition.ime_text_spans.size());
@@ -2905,7 +2950,7 @@ TEST_F(TSFTextStoreTest, RegressionTest3) {
.WillOnce(
Invoke(&callback, &RegressionTest3Callback::SetCompositionText2));
- EXPECT_CALL(text_input_client_, InsertText(_)).Times(0);
+ EXPECT_CALL(text_input_client_, InsertText(_, _)).Times(0);
EXPECT_CALL(*sink_, OnLockGranted(_))
.WillOnce(Invoke(&callback, &RegressionTest3Callback::LockGranted1))
@@ -2956,7 +3001,7 @@ class RegressionTest4Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"a", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("a"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(1u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -2984,8 +3029,10 @@ class RegressionTest4Callback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText2(const base::string16& text) {
- EXPECT_EQ(L"a", text);
+ void InsertText2(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("a"), text);
SetHasCompositionText(false);
}
@@ -2999,7 +3046,7 @@ TEST_F(TSFTextStoreTest, RegressionTest4) {
.WillOnce(
Invoke(&callback, &RegressionTest4Callback::SetCompositionText1));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(Invoke(&callback, &RegressionTest4Callback::InsertText2));
EXPECT_CALL(*sink_, OnLockGranted(_))
@@ -3058,7 +3105,7 @@ class RegressionTest5Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"aa", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("aa"), composition.text);
EXPECT_EQ(2u, composition.selection.start());
EXPECT_EQ(2u, composition.selection.end());
ASSERT_EQ(2u, composition.ime_text_spans.size());
@@ -3101,7 +3148,7 @@ class RegressionTest5Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText2(const ui::CompositionText& composition) {
- EXPECT_EQ(L"aa", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("aa"), composition.text);
EXPECT_EQ(2u, composition.selection.start());
EXPECT_EQ(2u, composition.selection.end());
ASSERT_EQ(2u, composition.ime_text_spans.size());
@@ -3126,8 +3173,10 @@ class RegressionTest5Callback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText3(const base::string16& text) {
- EXPECT_EQ(L"aa", text);
+ void InsertText3(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("aa"), text);
SetHasCompositionText(false);
}
@@ -3143,7 +3192,7 @@ TEST_F(TSFTextStoreTest, RegressionTest5) {
.WillOnce(
Invoke(&callback, &RegressionTest5Callback::SetCompositionText2));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(Invoke(&callback, &RegressionTest5Callback::InsertText3));
EXPECT_CALL(*sink_, OnLockGranted(_))
@@ -3200,7 +3249,7 @@ class RegressionTest6Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"a", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("a"), composition.text);
EXPECT_EQ(1u, composition.selection.start());
EXPECT_EQ(1u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -3223,8 +3272,10 @@ class RegressionTest6Callback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText2(const base::string16& text) {
- EXPECT_EQ(L"a", text);
+ void InsertText2(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("a"), text);
SetHasCompositionText(false);
}
@@ -3238,7 +3289,7 @@ TEST_F(TSFTextStoreTest, RegressionTest6) {
.WillOnce(
Invoke(&callback, &RegressionTest6Callback::SetCompositionText1));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(Invoke(&callback, &RegressionTest6Callback::InsertText2));
EXPECT_CALL(*sink_, OnLockGranted(_))
@@ -3288,7 +3339,7 @@ class UnderlineStyleTestCallback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"a", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("a"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(1u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -3388,8 +3439,10 @@ class RegressionTest7Callback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText3(const base::string16& text) {
- EXPECT_EQ(L"a", text);
+ void InsertText3(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("a"), text);
SetHasCompositionText(false);
}
@@ -3404,7 +3457,7 @@ TEST_F(TSFTextStoreTest, RegressionTest7) {
Invoke(&callback,
&RegressionTest7Callback::SetCompositionFromExistingText2));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(Invoke(&callback, &RegressionTest7Callback::InsertText3));
EXPECT_CALL(*sink_, OnLockGranted(_))
@@ -3458,7 +3511,7 @@ class RegressionTest8Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"bbbb", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("bbbb"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(4u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -3552,7 +3605,7 @@ class RegressionTest9Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText2(const ui::CompositionText& composition) {
- EXPECT_EQ(L"bbbb", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("bbbb"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(4u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -3584,7 +3637,7 @@ class RegressionTest9Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText3(const ui::CompositionText& composition) {
- EXPECT_EQ(L"bbcc", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("bbcc"), composition.text);
EXPECT_EQ(2u, composition.selection.start());
EXPECT_EQ(4u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -3608,8 +3661,10 @@ class RegressionTest9Callback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText4(const base::string16& text) {
- EXPECT_EQ(L"bbcc", text);
+ void InsertText4(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("bbcc"), text);
SetHasCompositionText(false);
}
@@ -3630,7 +3685,7 @@ TEST_F(TSFTextStoreTest, RegressionTest9) {
.WillOnce(
Invoke(&callback, &RegressionTest9Callback::SetCompositionText3));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(Invoke(&callback, &RegressionTest9Callback::InsertText4));
EXPECT_CALL(*sink_, OnLockGranted(_))
@@ -3690,7 +3745,7 @@ class RegressionTest10Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"abcd", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("abcd"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(4u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -3732,7 +3787,7 @@ class RegressionTest10Callback : public TSFTextStoreTestCallback {
}
void SetCompositionText2(const ui::CompositionText& composition) {
- EXPECT_EQ(L"abcd", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("abcd"), composition.text);
EXPECT_EQ(2u, composition.selection.start());
EXPECT_EQ(2u, composition.selection.end());
ASSERT_EQ(2u, composition.ime_text_spans.size());
@@ -3811,6 +3866,159 @@ TEST_F(TSFTextStoreTest, RegressionTest10) {
EXPECT_EQ(S_OK, result);
}
+// |CancelComposition| should reset all tracking composition state.
+class RegressionTest11Callback : public TSFTextStoreTestCallback {
+ public:
+ explicit RegressionTest11Callback(TSFTextStore* text_store)
+ : TSFTextStoreTestCallback(text_store) {}
+
+ HRESULT LockGranted1(DWORD flags) {
+ SetTextTest(0, 0, L"abcd", S_OK);
+ SetSelectionTest(0, 4, S_OK);
+
+ text_spans()->clear();
+ ImeTextSpan text_span;
+ text_span.start_offset = 0;
+ text_span.end_offset = 4;
+ text_span.underline_color = SK_ColorBLACK;
+ text_span.thickness = ImeTextSpan::Thickness::kThin;
+ text_span.background_color = SK_ColorTRANSPARENT;
+ text_spans()->push_back(text_span);
+ *edit_flag() = true;
+ *composition_start() = 0;
+ composition_range()->set_start(0);
+ composition_range()->set_end(4);
+ text_store_->OnKeyTraceDown(65u, 1966081u);
+ *has_composition_range() = true;
+
+ return S_OK;
+ }
+
+ void SetCompositionText(const ui::CompositionText& composition) {
+ EXPECT_EQ(STRING16_LITERAL("abcd"), composition.text);
+ EXPECT_EQ(0u, composition.selection.start());
+ EXPECT_EQ(4u, composition.selection.end());
+ ASSERT_EQ(1u, composition.ime_text_spans.size());
+ EXPECT_EQ(0u, composition.ime_text_spans[0].start_offset);
+ EXPECT_EQ(4u, composition.ime_text_spans[0].end_offset);
+ SetHasCompositionText(true);
+ SetCompositionTextRange(0, 4);
+ }
+
+ HRESULT LockGranted2(DWORD flags) {
+ *edit_flag() = false;
+ return S_OK;
+ }
+
+ HRESULT LockGranted3(DWORD flags) {
+ ResetCompositionStateTest();
+ return S_OK;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RegressionTest11Callback);
+};
+
+TEST_F(TSFTextStoreTest, RegressionTest11) {
+ RegressionTest11Callback callback(text_store_.get());
+ EXPECT_CALL(text_input_client_, SetCompositionText(_))
+ .WillOnce(
+ Invoke(&callback, &RegressionTest11Callback::SetCompositionText));
+
+ EXPECT_CALL(*sink_, OnLockGranted(_))
+ .WillOnce(Invoke(&callback, &RegressionTest11Callback::LockGranted1))
+ .WillOnce(Invoke(&callback, &RegressionTest11Callback::LockGranted2))
+ .WillOnce(Invoke(&callback, &RegressionTest11Callback::LockGranted3));
+
+ ON_CALL(text_input_client_, GetCompositionTextRange(_))
+ .WillByDefault(Invoke(
+ &callback, &TSFTextStoreTestCallback::GetCompositionTextRange));
+
+ ON_CALL(text_input_client_, GetTextRange(_))
+ .WillByDefault(
+ Invoke(&callback, &TSFTextStoreTestCallback::GetTextRange));
+
+ ON_CALL(text_input_client_, GetTextFromRange(_, _))
+ .WillByDefault(
+ Invoke(&callback, &TSFTextStoreTestCallback::GetTextFromRange));
+
+ ON_CALL(text_input_client_, GetEditableSelectionRange(_))
+ .WillByDefault(Invoke(
+ &callback, &TSFTextStoreTestCallback::GetEditableSelectionRange));
+
+ ON_CALL(text_input_client_, HasCompositionText())
+ .WillByDefault(
+ Invoke(&callback, &TSFTextStoreTestCallback::HasCompositionText));
+
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(S_OK, result);
+
+ result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(S_OK, result);
+
+ text_store_->CancelComposition();
+
+ result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(S_OK, result);
+}
+
+// regression tests for crbug.com/1156612.
+// We should remove selected text even if there is no new composition and IME
+// ask us to delete a previously inserted text.
+class RegressionTest12Callback : public TSFTextStoreTestCallback {
+ public:
+ explicit RegressionTest12Callback(TSFTextStore* text_store)
+ : TSFTextStoreTestCallback(text_store) {}
+
+ HRESULT LockGranted1(DWORD flags) {
+ SetTextTest(0, 0, L"a", S_OK);
+ SetSelectionTest(1, 1, S_OK);
+ return S_OK;
+ }
+
+ HRESULT LockGranted2(DWORD flags) {
+ GetTextTest(0, -1, L"a", 1);
+ SetTextTest(0, 1, L"", S_OK);
+
+ text_spans()->clear();
+ *edit_flag() = true;
+
+ return S_OK;
+ }
+
+ HRESULT LockGranted3(DWORD flags) {
+ GetTextTest(0, -1, L"", 0);
+
+ return S_OK;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RegressionTest12Callback);
+};
+
+TEST_F(TSFTextStoreTest, RegressionTest12) {
+ RegressionTest12Callback callback(text_store_.get());
+
+ EXPECT_CALL(text_input_client_, ExtendSelectionAndDelete(_, _)).Times(1);
+ EXPECT_CALL(*sink_, OnLockGranted(_))
+ .WillOnce(Invoke(&callback, &RegressionTest12Callback::LockGranted1))
+ .WillOnce(Invoke(&callback, &RegressionTest12Callback::LockGranted2))
+ .WillOnce(Invoke(&callback, &RegressionTest12Callback::LockGranted3));
+
+ HRESULT result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(S_OK, result);
+ result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(S_OK, result);
+ result = kInvalidResult;
+ EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+ EXPECT_EQ(S_OK, result);
+}
+
// Test multiple |SetText| call in one edit session.
class MultipleSetTextCallback : public TSFTextStoreTestCallback {
public:
@@ -3819,7 +4027,7 @@ class MultipleSetTextCallback : public TSFTextStoreTestCallback {
HRESULT LockGranted1(DWORD flags) {
SetTextRange(0, 6);
- SetTextBuffer(L"123456");
+ SetTextBuffer(STRING16_LITERAL("123456"));
SetTextTest(0, 0, L"123456", S_OK);
SetSelectionRange(6, 6);
*composition_start() = 1;
@@ -3927,7 +4135,7 @@ class TextInputClientReentrancyTestCallback : public TSFTextStoreTestCallback {
}
void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"a", composition.text);
+ EXPECT_EQ(STRING16_LITERAL("a"), composition.text);
EXPECT_EQ(0u, composition.selection.start());
EXPECT_EQ(1u, composition.selection.end());
ASSERT_EQ(1u, composition.ime_text_spans.size());
@@ -3935,7 +4143,7 @@ class TextInputClientReentrancyTestCallback : public TSFTextStoreTestCallback {
EXPECT_EQ(1u, composition.ime_text_spans[0].end_offset);
SetHasCompositionText(true);
SetTextRange(0, 1);
- SetTextBuffer(L"a");
+ SetTextBuffer(STRING16_LITERAL("a"));
SetSelectionRange(0, 1);
}
@@ -3952,11 +4160,13 @@ class TextInputClientReentrancyTestCallback : public TSFTextStoreTestCallback {
return S_OK;
}
- void InsertText2(const base::string16& text) {
- EXPECT_EQ(L"a", text);
+ void InsertText2(
+ const base::string16& text,
+ ui::TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+ EXPECT_EQ(STRING16_LITERAL("a"), text);
SetHasCompositionText(false);
SetSelectionRange(1, 1);
- SetTextBuffer(L"b");
+ SetTextBuffer(STRING16_LITERAL("b"));
HRESULT result = kInvalidResult;
EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
EXPECT_EQ(S_OK, result);
@@ -3990,7 +4200,7 @@ TEST_F(TSFTextStoreTest, TextInputClientReentrancTest) {
.WillOnce(Invoke(&callback,
&TextInputClientReentrancyTestCallback::LockGranted4));
- EXPECT_CALL(text_input_client_, InsertText(_))
+ EXPECT_CALL(text_input_client_, InsertText(_, _))
.WillOnce(Invoke(&callback,
&TextInputClientReentrancyTestCallback::InsertText2));
diff --git a/chromium/ui/base/l10n/l10n_font_util.cc b/chromium/ui/base/l10n/l10n_font_util.cc
index fa6f7d950e4..7165d277e28 100644
--- a/chromium/ui/base/l10n/l10n_font_util.cc
+++ b/chromium/ui/base/l10n/l10n_font_util.cc
@@ -7,33 +7,26 @@
#include "base/check_op.h"
#include "base/strings/string_number_conversions.h"
#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
namespace ui {
-int GetLocalizedContentsWidthForFont(int col_resource_id,
- const gfx::Font& font) {
+int GetLocalizedContentsWidthForFontList(int col_resource_id,
+ const gfx::FontList& font_list) {
int chars = 0;
base::StringToInt(l10n_util::GetStringUTF8(col_resource_id), &chars);
- int width = font.GetExpectedTextWidth(chars);
+ int width = font_list.GetExpectedTextWidth(chars);
DCHECK_GT(width, 0);
return width;
}
-int GetLocalizedContentsHeightForFont(int row_resource_id,
- const gfx::Font& font) {
+int GetLocalizedContentsHeightForFontList(int row_resource_id,
+ const gfx::FontList& font_list) {
int lines = 0;
base::StringToInt(l10n_util::GetStringUTF8(row_resource_id), &lines);
- int height = font.GetHeight() * lines;
+ int height = font_list.GetHeight() * lines;
DCHECK_GT(height, 0);
return height;
}
-gfx::Size GetLocalizedContentsSizeForFont(int col_resource_id,
- int row_resource_id,
- const gfx::Font& font) {
- return gfx::Size(GetLocalizedContentsWidthForFont(col_resource_id, font),
- GetLocalizedContentsHeightForFont(row_resource_id, font));
-}
-
} // namespace ui
diff --git a/chromium/ui/base/l10n/l10n_font_util.h b/chromium/ui/base/l10n/l10n_font_util.h
index 81dffd348f1..979be47f05d 100644
--- a/chromium/ui/base/l10n/l10n_font_util.h
+++ b/chromium/ui/base/l10n/l10n_font_util.h
@@ -9,7 +9,7 @@
#include "ui/gfx/geometry/size.h"
namespace gfx {
-class Font;
+class FontList;
}
namespace ui {
@@ -19,15 +19,11 @@ namespace ui {
// localized string resource identified by |col_resource_id|, the height in the
// same fashion.
COMPONENT_EXPORT(UI_BASE)
-int GetLocalizedContentsWidthForFont(int col_resource_id,
- const gfx::Font& font);
+int GetLocalizedContentsWidthForFontList(int col_resource_id,
+ const gfx::FontList& font_list);
COMPONENT_EXPORT(UI_BASE)
-int GetLocalizedContentsHeightForFont(int row_resource_id,
- const gfx::Font& font);
-COMPONENT_EXPORT(UI_BASE)
-gfx::Size GetLocalizedContentsSizeForFont(int col_resource_id,
- int row_resource_id,
- const gfx::Font& font);
+int GetLocalizedContentsHeightForFontList(int row_resource_id,
+ const gfx::FontList& font_list);
} // namespace ui
diff --git a/chromium/ui/base/l10n/l10n_util.cc b/chromium/ui/base/l10n/l10n_util.cc
index 291e24f9e77..8004a13658e 100644
--- a/chromium/ui/base/l10n/l10n_util.cc
+++ b/chromium/ui/base/l10n/l10n_util.cc
@@ -19,7 +19,10 @@
#include "base/i18n/number_formatting.h"
#include "base/i18n/rtl.h"
#include "base/i18n/string_compare.h"
+#include "base/i18n/uchar.h"
#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -29,6 +32,7 @@
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/icu/source/common/unicode/rbbi.h"
#include "third_party/icu/source/common/unicode/uloc.h"
#include "ui/base/l10n/l10n_util_collator.h"
@@ -56,16 +60,17 @@ static const char* const kAcceptLanguageList[] = {
"am", // Amharic
"an", // Aragonese
"ar", // Arabic
+ "as", // Assamese
"ast", // Asturian
"az", // Azerbaijani
"be", // Belarusian
"bg", // Bulgarian
- "bh", // Bihari
"bn", // Bengali
"br", // Breton
"bs", // Bosnian
"ca", // Catalan
"ceb", // Cebuano
+ "chr", // Cherokee
"ckb", // Kurdish (Arabic), Sorani
"co", // Corsican
"cs", // Czech
@@ -141,6 +146,7 @@ static const char* const kAcceptLanguageList[] = {
"km", // Cambodian
"kn", // Kannada
"ko", // Korean
+ "kok", // Konkani
"ku", // Kurdish
"ky", // Kyrgyz
"la", // Latin
@@ -167,7 +173,7 @@ static const char* const kAcceptLanguageList[] = {
"ny", // Nyanja
"oc", // Occitan
"om", // Oromo
- "or", // Oriya
+ "or", // Odia (Oriya)
"pa", // Punjabi
"pl", // Polish
"ps", // Pashto
@@ -178,6 +184,7 @@ static const char* const kAcceptLanguageList[] = {
"rm", // Romansh
"ro", // Romanian
"ru", // Russian
+ "rw", // Kinyarwanda
"sd", // Sindhi
"sh", // Serbo-Croatian
"si", // Sinhalese
@@ -198,16 +205,18 @@ static const char* const kAcceptLanguageList[] = {
"th", // Thai
"ti", // Tigrinya
"tk", // Turkmen
+ "tn", // Tswana
"to", // Tonga
"tr", // Turkish
"tt", // Tatar
"tw", // Twi
- "ug", // Uighur
+ "ug", // Uyghur
"uk", // Ukrainian
"ur", // Urdu
"uz", // Uzbek
"vi", // Vietnamese
"wa", // Walloon
+ "wo", // Wolof
"xh", // Xhosa
"yi", // Yiddish
"yo", // Yoruba
@@ -218,6 +227,32 @@ static const char* const kAcceptLanguageList[] = {
"zu", // Zulu
};
+// The list of locales that expected on the current platform, generated from the
+// |locales| variable in GN (defined in build/config/locales.gni). This is
+// equivalently the list of locales that we expect to have translation strings
+// for on the current platform. Guaranteed to be in sorted order and guaranteed
+// to have no duplicates.
+//
+// Note that this could have false positives at runtime on Android and iOS:
+// - On Android, some locales aren't shipped (|android_apk_omitted_locales| in
+// GN), and some locales files are dynamically shipped in app bundles
+// (|android_bundle_only_locales|). Both of these lists are included in
+// this variable.
+// - On iOS, some locales aren't shipped (|ios_unsupported_locales|) as they are
+// not supported by the operating system. These locales are included in this
+// variable.
+//
+// To avoid false positives on these platforms, use
+// ui::ResourceBundle::LocaleDataPakExists() to check whether the locales exist
+// on disk instead (requires I/O).
+static const char* const kPlatformLocales[] = {
+#define PLATFORM_LOCALE(locale) #locale,
+// The below is generated by tools/l10n/generate_locales_list.py, which is
+// run in the //ui/base:locales_list_gen build rule.
+#include "ui/base/l10n/l10n_util_locales_list.inc"
+#undef PLATFORM_LOCALE
+};
+
// Returns true if |locale_name| has an alias in the ICU data file.
bool IsDuplicateName(const std::string& locale_name) {
static const char* const kDuplicateNames[] = {
@@ -258,8 +293,15 @@ bool IsLocalePartiallyPopulated(const std::string& locale_name) {
return !l10n_util::IsLocaleNameTranslated("en", locale_name);
}
-#if !defined(OS_APPLE)
-bool IsLocaleAvailable(const std::string& locale) {
+// If |perform_io| is false, this will not perform any I/O but may return false
+// positives on Android and iOS. See the |kPlatformLocales| documentation for
+// more information.
+bool HasStringsForLocale(const std::string& locale,
+ const bool perform_io = true) {
+ if (!perform_io) {
+ return std::binary_search(std::begin(kPlatformLocales),
+ std::end(kPlatformLocales), locale);
+ }
// If locale has any illegal characters in it, we don't want to try to
// load it because it may be pointing outside the locale data file directory.
if (!base::i18n::IsFilenameLegal(base::ASCIIToUTF16(locale)))
@@ -267,12 +309,11 @@ bool IsLocaleAvailable(const std::string& locale) {
// IsLocalePartiallyPopulated() can be called here for an early return w/o
// checking the resource availability below. It'd help when Chrome is run
- // under a system locale Chrome is not localized to (e.g.Farsi on Linux),
+ // under a system locale Chrome is not localized to (e.g. Farsi on Linux),
// but it'd slow down the start up time a little bit for locales Chrome is
// localized to. So, we don't call it here.
return ui::ResourceBundle::LocaleDataPakExists(locale);
}
-#endif
// On Linux, the text layout engine Pango determines paragraph directionality
// by looking at the first strongly-directional character in the text. This
@@ -335,12 +376,12 @@ std::string GetLanguage(const std::string& locale) {
return std::string(locale, 0, hyphen_pos);
}
-// TODO(jshin): revamp this function completely to use a more sytematic
+// TODO(jshin): revamp this function completely to use a more systematic
// and generic locale fallback based on ICU/CLDR.
bool CheckAndResolveLocale(const std::string& locale,
- std::string* resolved_locale) {
-#if !defined(OS_APPLE)
- if (IsLocaleAvailable(locale)) {
+ std::string* resolved_locale,
+ const bool perform_io) {
+ if (HasStringsForLocale(locale, perform_io)) {
*resolved_locale = locale;
return true;
}
@@ -365,10 +406,17 @@ bool CheckAndResolveLocale(const std::string& locale,
// Spanish locale).
if (base::LowerCaseEqualsASCII(lang, "es") &&
!base::LowerCaseEqualsASCII(region, "es")) {
+#if defined(OS_IOS)
+ // iOS uses a different name for es-419 (es-MX).
+ tmp_locale.append("-MX");
+#else
tmp_locale.append("-419");
- } else if (base::LowerCaseEqualsASCII(lang, "pt")) {
+#endif
+ } else if (base::LowerCaseEqualsASCII(lang, "pt") &&
+ !base::LowerCaseEqualsASCII(region, "br")) {
// Map pt-RR other than pt-BR to pt-PT. Note that "pt" by itself maps to
- // pt-BR (logic below).
+ // pt-BR (logic below), and we need to explicitly check for pt-BR here as
+ // it is unavailable on iOS.
tmp_locale.append("-PT");
} else if (base::LowerCaseEqualsASCII(lang, "zh")) {
// Map zh-HK and zh-MO to zh-TW. Otherwise, zh-FOO is mapped to zh-CN.
@@ -390,7 +438,7 @@ bool CheckAndResolveLocale(const std::string& locale,
tmp_locale.append("-GB");
}
}
- if (IsLocaleAvailable(tmp_locale)) {
+ if (HasStringsForLocale(tmp_locale, perform_io)) {
resolved_locale->swap(tmp_locale);
return true;
}
@@ -408,19 +456,21 @@ bool CheckAndResolveLocale(const std::string& locale,
for (const auto& alias : kAliasMap) {
if (base::LowerCaseEqualsASCII(lang, alias.source)) {
std::string tmp_locale(alias.dest);
- if (IsLocaleAvailable(tmp_locale)) {
+ if (HasStringsForLocale(tmp_locale, perform_io)) {
resolved_locale->swap(tmp_locale);
return true;
}
}
}
-#else
- NOTIMPLEMENTED();
-#endif // !defined(OS_APPLE)
return false;
}
+bool CheckAndResolveLocale(const std::string& locale,
+ std::string* resolved_locale) {
+ return CheckAndResolveLocale(locale, resolved_locale, /*perform_io=*/true);
+}
+
#if defined(OS_APPLE)
std::string GetApplicationLocaleInternalMac(const std::string& pref_locale) {
// Use any override (Cocoa for the browser), otherwise use the preference
@@ -471,7 +521,7 @@ std::string GetApplicationLocaleInternalNonMac(const std::string& pref_locale) {
// On Android, query java.util.Locale for the default locale.
candidates.push_back(base::android::GetDefaultLocaleString());
-#elif defined(USE_GLIB) && !defined(OS_CHROMEOS)
+#elif defined(USE_GLIB) && !BUILDFLAG(IS_CHROMEOS_ASH)
// GLib implements correct environment variable parsing with
// the precedence order: LANGUAGE, LC_ALL, LC_MESSAGES and LANG.
// We used to use our custom parsing code along with ICU for this purpose.
@@ -500,7 +550,7 @@ std::string GetApplicationLocaleInternalNonMac(const std::string& pref_locale) {
// Fallback on en-US.
const std::string fallback_locale("en-US");
- if (IsLocaleAvailable(fallback_locale))
+ if (HasStringsForLocale(fallback_locale))
return fallback_locale;
return std::string();
@@ -585,11 +635,13 @@ base::string16 GetDisplayNameForLocale(const std::string& locale,
if (locale_code[0] == '-' || locale_code[0] == '_') {
actual_size = uloc_getDisplayCountry(
locale_code.c_str(), display_locale.c_str(),
- base::WriteInto(&display_name, kBufferSize), kBufferSize - 1, &error);
+ base::i18n::ToUCharPtr(base::WriteInto(&display_name, kBufferSize)),
+ kBufferSize - 1, &error);
} else {
actual_size = uloc_getDisplayName(
locale_code.c_str(), display_locale.c_str(),
- base::WriteInto(&display_name, kBufferSize), kBufferSize - 1, &error);
+ base::i18n::ToUCharPtr(base::WriteInto(&display_name, kBufferSize)),
+ kBufferSize - 1, &error);
}
if (disallow_default && U_USING_DEFAULT_WARNING == error)
return base::string16();
@@ -868,10 +920,37 @@ void SortStrings16(const std::string& locale,
SortVectorWithStringKey(locale, strings, false);
}
-const std::vector<std::string>& GetAvailableLocales() {
+const std::vector<std::string>& GetAvailableICULocales() {
return g_available_locales.Get();
}
+const std::vector<std::string>& GetLocalesWithStrings() {
+ static base::NoDestructor<std::vector<std::string>> available_locales([] {
+ std::vector<std::string> locales;
+ for (const char* accept_language : kAcceptLanguageList) {
+ std::string locale(accept_language);
+ std::string resolved_locale;
+
+ // As there are many callers of GetLocalesWithStrings from threads where
+ // I/O is prohibited, we cannot perform I/O here.
+ if (!l10n_util::CheckAndResolveLocale(locale, &resolved_locale,
+ /*perform_io=*/false))
+ continue;
+
+ // We shouldn't show the user any other Chinese locales other than the
+ // ones that we have strings for (i.e. when resolved_locale == locale).
+ if (resolved_locale != locale &&
+ base::LowerCaseEqualsASCII(l10n_util::GetLanguage(locale), "zh"))
+ continue;
+
+ locales.push_back(locale);
+ }
+ return locales;
+ }());
+
+ return *available_locales;
+}
+
void GetAcceptLanguagesForLocale(const std::string& display_locale,
std::vector<std::string>* locale_codes) {
for (const char* accept_language : kAcceptLanguageList) {
@@ -916,4 +995,12 @@ size_t GetAcceptLanguageListSizeForTesting() {
return base::size(kAcceptLanguageList);
}
+const char* const* GetPlatformLocalesForTesting() {
+ return kPlatformLocales;
+}
+
+size_t GetPlatformLocalesSizeForTesting() {
+ return base::size(kPlatformLocales);
+}
+
} // namespace l10n_util
diff --git a/chromium/ui/base/l10n/l10n_util.h b/chromium/ui/base/l10n/l10n_util.h
index b821be44665..5ebdb2e16a0 100644
--- a/chromium/ui/base/l10n/l10n_util.h
+++ b/chromium/ui/base/l10n/l10n_util.h
@@ -29,6 +29,15 @@ COMPONENT_EXPORT(UI_BASE) std::string GetLanguage(const std::string& locale);
// This method translates a generic locale name to one of the locally defined
// ones. This method returns true if it succeeds.
+// If |perform_io| is false, this will not perform any I/O but may return false
+// positives on Android and iOS. See the |kPlatformLocales| documentation in
+// l10n_util.cc for more information.
+COMPONENT_EXPORT(UI_BASE)
+bool CheckAndResolveLocale(const std::string& locale,
+ std::string* resolved_locale,
+ const bool perform_io);
+
+// Convenience wrapper for the above (with |perform_io| set to true).
COMPONENT_EXPORT(UI_BASE)
bool CheckAndResolveLocale(const std::string& locale,
std::string* resolved_locale);
@@ -217,9 +226,17 @@ COMPONENT_EXPORT(UI_BASE)
void SortStrings16(const std::string& locale,
std::vector<base::string16>* strings);
-// Returns a vector of available locale codes. E.g., a vector containing
-// en-US, es, fr, fi, pt-PT, pt-BR, etc.
-COMPONENT_EXPORT(UI_BASE) const std::vector<std::string>& GetAvailableLocales();
+// Returns a vector of available locale codes from ICU. E.g., a vector
+// containing en-US, es, fr, fi, pt-PT, pt-BR, etc.
+COMPONENT_EXPORT(UI_BASE)
+const std::vector<std::string>& GetAvailableICULocales();
+
+// Returns a vector of locale codes for which we have translation strings for,
+// including locales which have valid fallbacks.
+// E.g., a vector containing en-US, en-CA, en-GB, es, fr, pt-PT, pt-BR, etc.
+// This is a strict subset of the vector returned from GetAcceptLanguages.
+COMPONENT_EXPORT(UI_BASE)
+const std::vector<std::string>& GetLocalesWithStrings();
// Returns a vector of locale codes usable for accept-languages.
COMPONENT_EXPORT(UI_BASE)
@@ -245,6 +262,10 @@ COMPONENT_EXPORT(UI_BASE) const char* const* GetAcceptLanguageListForTesting();
COMPONENT_EXPORT(UI_BASE) size_t GetAcceptLanguageListSizeForTesting();
+COMPONENT_EXPORT(UI_BASE) const char* const* GetPlatformLocalesForTesting();
+
+COMPONENT_EXPORT(UI_BASE) size_t GetPlatformLocalesSizeForTesting();
+
} // namespace l10n_util
#endif // UI_BASE_L10N_L10N_UTIL_H_
diff --git a/chromium/ui/base/l10n/l10n_util_android.cc b/chromium/ui/base/l10n/l10n_util_android.cc
index 9d3ce2a1fae..4a509dfd3da 100644
--- a/chromium/ui/base/l10n/l10n_util_android.cc
+++ b/chromium/ui/base/l10n/l10n_util_android.cc
@@ -12,9 +12,7 @@
#include "base/check.h"
#include "base/i18n/rtl.h"
#include "base/strings/string_util.h"
-#include "base/time/time.h"
#include "third_party/icu/source/common/unicode/uloc.h"
-#include "ui/base/l10n/time_format.h"
#include "ui/base/ui_base_jni_headers/LocalizationUtils_jni.h"
using base::android::JavaParamRef;
@@ -96,16 +94,12 @@ base::string16 GetDisplayNameForLocale(const std::string& locale,
return ConvertJavaStringToUTF16(java_result);
}
-ScopedJavaLocalRef<jstring> JNI_LocalizationUtils_GetDurationString(
- JNIEnv* env,
- jlong timeInMillis) {
- ScopedJavaLocalRef<jstring> jtime_remaining =
- base::android::ConvertUTF16ToJavaString(
- env,
- ui::TimeFormat::Simple(
- ui::TimeFormat::FORMAT_REMAINING, ui::TimeFormat::LENGTH_SHORT,
- base::TimeDelta::FromMilliseconds(timeInMillis)));
- return jtime_remaining;
+ScopedJavaLocalRef<jstring> JNI_LocalizationUtils_GetNativeUiLocale(
+ JNIEnv* env) {
+ ScopedJavaLocalRef<jstring> native_ui_locale_string =
+ base::android::ConvertUTF8ToJavaString(env,
+ base::i18n::GetConfiguredLocale());
+ return native_ui_locale_string;
}
} // namespace l10n_util
diff --git a/chromium/ui/base/l10n/l10n_util_unittest.cc b/chromium/ui/base/l10n/l10n_util_unittest.cc
index 4c2fd2a2b1b..4b7b3406557 100644
--- a/chromium/ui/base/l10n/l10n_util_unittest.cc
+++ b/chromium/ui/base/l10n/l10n_util_unittest.cc
@@ -4,8 +4,10 @@
#include <stddef.h>
+#include <cstring>
#include <memory>
+#include "base/containers/flat_set.h"
#include "base/environment.h"
#include "base/files/file_util.h"
#include "base/i18n/case_conversion.h"
@@ -19,6 +21,7 @@
#include "base/test/icu_test_util.h"
#include "base/test/scoped_path_override.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "third_party/icu/source/common/unicode/locid.h"
@@ -78,7 +81,7 @@ TEST_F(L10nUtilTest, GetString) {
// On Android, we are disabling this test since GetApplicationLocale() just
// returns the system's locale, which, similarly, is not easily unit tested.
-#if defined(OS_POSIX) && defined(USE_GLIB) && !defined(OS_CHROMEOS)
+#if defined(OS_POSIX) && defined(USE_GLIB) && !BUILDFLAG(IS_CHROMEOS_ASH)
const bool kPlatformHasDefaultLocale = 1;
const bool kUseLocaleFromEnvironment = 1;
const bool kSupportsLocalePreference = 0;
@@ -582,7 +585,7 @@ TEST_F(L10nUtilTest, TimeDurationFormatAllLocales) {
// Verify that base::TimeDurationFormat() works for all available locales:
// http://crbug.com/707515
base::TimeDelta kDelta = base::TimeDelta::FromMinutes(15 * 60 + 42);
- for (const std::string& locale : l10n_util::GetAvailableLocales()) {
+ for (const std::string& locale : l10n_util::GetAvailableICULocales()) {
base::i18n::SetICUDefaultLocale(locale);
base::string16 str;
const bool result =
@@ -592,3 +595,50 @@ TEST_F(L10nUtilTest, TimeDurationFormatAllLocales) {
EXPECT_FALSE(str.empty()) << "Got empty string for " << locale;
}
}
+
+TEST_F(L10nUtilTest, GetLocalesWithStrings) {
+ // Convert the vector to a set for easy lookup.
+ const base::flat_set<std::string> locales =
+ l10n_util::GetLocalesWithStrings();
+
+ // Common locales which should be available on all platforms.
+ EXPECT_TRUE(locales.contains("en") || locales.contains("en-US"));
+ EXPECT_TRUE(locales.contains("en-GB"));
+ EXPECT_TRUE(locales.contains("es") || locales.contains("es-ES"));
+ EXPECT_TRUE(locales.contains("fr") || locales.contains("fr-FR"));
+
+ // Locales that we should have valid fallbacks for.
+ EXPECT_TRUE(locales.contains("en-CA"));
+ EXPECT_TRUE(locales.contains("es-AR"));
+ EXPECT_TRUE(locales.contains("fr-CA"));
+
+ // Locales that should not be included:
+ // English (Germany). A valid locale and in ICU's list of locales, but not in
+ // our list of Accept-Language locales.
+ EXPECT_FALSE(locales.contains("en-DE"));
+ // Esperanto. Unlikely to be localised and historically included in
+ // GetAvailableICULocales.
+ EXPECT_FALSE(locales.contains("eo"));
+}
+
+TEST_F(L10nUtilTest, PlatformLocalesIsSorted) {
+ const char* const* locales = l10n_util::GetPlatformLocalesForTesting();
+ const size_t locales_size = l10n_util::GetPlatformLocalesSizeForTesting();
+
+ // Check adjacent pairs and ensure they are in sorted order without
+ // duplicates.
+
+ // All 0-length and 1-length lists are sorted.
+ if (locales_size <= 1) {
+ return;
+ }
+
+ const char* last_locale = locales[0];
+ for (size_t i = 1; i < locales_size; i++) {
+ const char* cur_locale = locales[i];
+ EXPECT_LT(strcmp(last_locale, cur_locale), 0)
+ << "Incorrect ordering in kPlatformLocales: " << last_locale
+ << " >= " << cur_locale;
+ last_locale = cur_locale;
+ }
+}
diff --git a/chromium/ui/base/l10n/time_format.cc b/chromium/ui/base/l10n/time_format.cc
index 2e51714bc35..4316a212ba0 100644
--- a/chromium/ui/base/l10n/time_format.cc
+++ b/chromium/ui/base/l10n/time_format.cc
@@ -8,6 +8,7 @@
#include "base/check_op.h"
#include "base/component_export.h"
+#include "base/i18n/uchar.h"
#include "base/lazy_instance.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
@@ -144,8 +145,9 @@ base::string16 TimeFormat::DetailedWithMonthAndYear(
DCHECK_GT(capacity, 1);
base::string16 result;
UErrorCode error = U_ZERO_ERROR;
- time_string.extract(static_cast<UChar*>(base::WriteInto(&result, capacity)),
- capacity, error);
+ time_string.extract(
+ base::i18n::ToUCharPtr(base::WriteInto(&result, capacity)), capacity,
+ error);
DCHECK(U_SUCCESS(error));
return result;
}
diff --git a/chromium/ui/base/layout_unittest.cc b/chromium/ui/base/layout_unittest.cc
index 7c975e6b155..0b4cdf53e54 100644
--- a/chromium/ui/base/layout_unittest.cc
+++ b/chromium/ui/base/layout_unittest.cc
@@ -5,9 +5,10 @@
#include "ui/base/layout.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/command_line.h"
#include "ui/base/ui_base_switches.h"
#endif
diff --git a/chromium/ui/base/models/dialog_model.cc b/chromium/ui/base/models/dialog_model.cc
index b1077c7788f..ceccc112e59 100644
--- a/chromium/ui/base/models/dialog_model.cc
+++ b/chromium/ui/base/models/dialog_model.cc
@@ -10,7 +10,7 @@
namespace ui {
DialogModel::Builder::Builder(std::unique_ptr<DialogModelDelegate> delegate)
- : model_(std::make_unique<DialogModel>(util::PassKey<Builder>(),
+ : model_(std::make_unique<DialogModel>(base::PassKey<Builder>(),
std::move(delegate))) {}
DialogModel::Builder::Builder() : Builder(nullptr) {}
@@ -75,7 +75,7 @@ DialogModel::Builder& DialogModel::Builder::SetInitiallyFocusedField(
return *this;
}
-DialogModel::DialogModel(util::PassKey<Builder>,
+DialogModel::DialogModel(base::PassKey<Builder>,
std::unique_ptr<DialogModelDelegate> delegate)
: delegate_(std::move(delegate)) {
if (delegate_)
@@ -88,9 +88,11 @@ void DialogModel::AddBodyText(const DialogModelLabel& label) {
AddField(std::make_unique<DialogModelBodyText>(GetPassKey(), this, label));
}
-void DialogModel::AddCheckbox(int unique_id, const DialogModelLabel& label) {
+void DialogModel::AddCheckbox(int unique_id,
+ const DialogModelLabel& label,
+ const DialogModelCheckbox::Params& params) {
AddField(std::make_unique<DialogModelCheckbox>(GetPassKey(), this, unique_id,
- label));
+ label, params));
}
void DialogModel::AddCombobox(base::string16 label,
@@ -118,7 +120,7 @@ DialogModelField* DialogModel::GetFieldByUniqueId(int unique_id) {
if (field->unique_id_ == unique_id)
return field.get();
}
- NOTREACHED();
+ NOTREACHED() << "No field with unique_id: " << unique_id;
return nullptr;
}
@@ -134,22 +136,22 @@ DialogModelTextfield* DialogModel::GetTextfieldByUniqueId(int unique_id) {
return GetFieldByUniqueId(unique_id)->AsTextfield();
}
-void DialogModel::OnDialogAccepted(util::PassKey<DialogModelHost>) {
+void DialogModel::OnDialogAccepted(base::PassKey<DialogModelHost>) {
if (accept_callback_)
std::move(accept_callback_).Run();
}
-void DialogModel::OnDialogCancelled(util::PassKey<DialogModelHost>) {
+void DialogModel::OnDialogCancelled(base::PassKey<DialogModelHost>) {
if (cancel_callback_)
std::move(cancel_callback_).Run();
}
-void DialogModel::OnDialogClosed(util::PassKey<DialogModelHost>) {
+void DialogModel::OnDialogClosed(base::PassKey<DialogModelHost>) {
if (close_callback_)
std::move(close_callback_).Run();
}
-void DialogModel::OnWindowClosing(util::PassKey<DialogModelHost>) {
+void DialogModel::OnWindowClosing(base::PassKey<DialogModelHost>) {
if (window_closing_callback_)
std::move(window_closing_callback_).Run();
}
diff --git a/chromium/ui/base/models/dialog_model.h b/chromium/ui/base/models/dialog_model.h
index 4a5be0d6837..f219925a6ce 100644
--- a/chromium/ui/base/models/dialog_model.h
+++ b/chromium/ui/base/models/dialog_model.h
@@ -11,7 +11,7 @@
#include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "base/strings/string16.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "ui/base/models/dialog_model_field.h"
#include "ui/base/models/dialog_model_host.h"
#include "ui/base/models/image_model.h"
@@ -191,8 +191,11 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
}
// Adds a checkbox. See DialogModel::AddCheckbox().
- Builder& AddCheckbox(int unique_id, const DialogModelLabel& label) {
- model_->AddCheckbox(unique_id, label);
+ Builder& AddCheckbox(int unique_id,
+ const DialogModelLabel& label,
+ const DialogModelCheckbox::Params& params =
+ DialogModelCheckbox::Params()) {
+ model_->AddCheckbox(unique_id, label, params);
return *this;
}
@@ -222,7 +225,7 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
std::unique_ptr<DialogModel> model_;
};
- DialogModel(util::PassKey<DialogModel::Builder>,
+ DialogModel(base::PassKey<DialogModel::Builder>,
std::unique_ptr<DialogModelDelegate> delegate);
DialogModel(const DialogModel&) = delete;
@@ -238,7 +241,10 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
void AddBodyText(const DialogModelLabel& label);
// Adds a checkbox ([checkbox] label) at the end of the dialog model.
- void AddCheckbox(int unique_id, const DialogModelLabel& label);
+ void AddCheckbox(int unique_id,
+ const DialogModelLabel& label,
+ const DialogModelCheckbox::Params& params =
+ DialogModelCheckbox::Params());
// Adds a labeled combobox (label: [model]) at the end of the dialog model.
void AddCombobox(base::string16 label,
@@ -266,51 +272,51 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
DialogModelCombobox* GetComboboxByUniqueId(int unique_id);
DialogModelTextfield* GetTextfieldByUniqueId(int unique_id);
- // Methods with util::PassKey<DialogModelHost> are only intended to be called
+ // Methods with base::PassKey<DialogModelHost> are only intended to be called
// by the DialogModelHost implementation.
- void OnDialogAccepted(util::PassKey<DialogModelHost>);
- void OnDialogCancelled(util::PassKey<DialogModelHost>);
- void OnDialogClosed(util::PassKey<DialogModelHost>);
- void OnWindowClosing(util::PassKey<DialogModelHost>);
+ void OnDialogAccepted(base::PassKey<DialogModelHost>);
+ void OnDialogCancelled(base::PassKey<DialogModelHost>);
+ void OnDialogClosed(base::PassKey<DialogModelHost>);
+ void OnWindowClosing(base::PassKey<DialogModelHost>);
// Called when added to a DialogModelHost.
- void set_host(util::PassKey<DialogModelHost>, DialogModelHost* host) {
+ void set_host(base::PassKey<DialogModelHost>, DialogModelHost* host) {
host_ = host;
}
const base::Optional<bool>& override_show_close_button(
- util::PassKey<DialogModelHost>) const {
+ base::PassKey<DialogModelHost>) const {
return override_show_close_button_;
}
- const base::string16& title(util::PassKey<DialogModelHost>) const {
+ const base::string16& title(base::PassKey<DialogModelHost>) const {
return title_;
}
- const ImageModel& icon(util::PassKey<DialogModelHost>) const { return icon_; }
+ const ImageModel& icon(base::PassKey<DialogModelHost>) const { return icon_; }
base::Optional<int> initially_focused_field(
- util::PassKey<DialogModelHost>) const {
+ base::PassKey<DialogModelHost>) const {
return initially_focused_field_;
}
- bool is_alert_dialog(util::PassKey<DialogModelHost>) const {
+ bool is_alert_dialog(base::PassKey<DialogModelHost>) const {
return is_alert_dialog_;
}
- DialogModelButton* ok_button(util::PassKey<DialogModelHost>) {
+ DialogModelButton* ok_button(base::PassKey<DialogModelHost>) {
return ok_button_.has_value() ? &ok_button_.value() : nullptr;
}
- DialogModelButton* cancel_button(util::PassKey<DialogModelHost>) {
+ DialogModelButton* cancel_button(base::PassKey<DialogModelHost>) {
return cancel_button_.has_value() ? &cancel_button_.value() : nullptr;
}
- DialogModelButton* extra_button(util::PassKey<DialogModelHost>) {
+ DialogModelButton* extra_button(base::PassKey<DialogModelHost>) {
return extra_button_.has_value() ? &extra_button_.value() : nullptr;
}
- bool close_on_deactivate(util::PassKey<DialogModelHost>) const {
+ bool close_on_deactivate(base::PassKey<DialogModelHost>) const {
return close_on_deactivate_;
}
@@ -318,13 +324,13 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
// though they should be handled separately (OK button has fixed position in
// dialog).
const std::vector<std::unique_ptr<DialogModelField>>& fields(
- util::PassKey<DialogModelHost>) {
+ base::PassKey<DialogModelHost>) {
return fields_;
}
private:
- util::PassKey<DialogModel> GetPassKey() {
- return util::PassKey<DialogModel>();
+ base::PassKey<DialogModel> GetPassKey() {
+ return base::PassKey<DialogModel>();
}
void AddField(std::unique_ptr<DialogModelField> field);
diff --git a/chromium/ui/base/models/dialog_model_field.cc b/chromium/ui/base/models/dialog_model_field.cc
index 3432b970aa8..a323903381f 100644
--- a/chromium/ui/base/models/dialog_model_field.cc
+++ b/chromium/ui/base/models/dialog_model_field.cc
@@ -33,7 +33,7 @@ DialogModelLabel::DialogModelLabel(base::string16 fixed_string)
: message_id_(-1), string_(std::move(fixed_string)) {}
const base::string16& DialogModelLabel::GetString(
- util::PassKey<DialogModelHost>) const {
+ base::PassKey<DialogModelHost>) const {
DCHECK(links_.empty());
return string_;
}
@@ -51,7 +51,7 @@ DialogModelLabel DialogModelLabel::CreateWithLinks(int message_id,
return DialogModelLabel(message_id, std::move(links));
}
-DialogModelField::DialogModelField(util::PassKey<DialogModel>,
+DialogModelField::DialogModelField(base::PassKey<DialogModel>,
DialogModel* model,
Type type,
int unique_id,
@@ -65,27 +65,27 @@ DialogModelField::DialogModelField(util::PassKey<DialogModel>,
DialogModelField::~DialogModelField() = default;
-DialogModelButton* DialogModelField::AsButton(util::PassKey<DialogModelHost>) {
+DialogModelButton* DialogModelField::AsButton(base::PassKey<DialogModelHost>) {
return AsButton();
}
DialogModelBodyText* DialogModelField::AsBodyText(
- util::PassKey<DialogModelHost>) {
+ base::PassKey<DialogModelHost>) {
return AsBodyText();
}
DialogModelCheckbox* DialogModelField::AsCheckbox(
- util::PassKey<DialogModelHost>) {
+ base::PassKey<DialogModelHost>) {
return AsCheckbox();
}
DialogModelCombobox* DialogModelField::AsCombobox(
- util::PassKey<DialogModelHost>) {
+ base::PassKey<DialogModelHost>) {
return AsCombobox();
}
DialogModelTextfield* DialogModelField::AsTextfield(
- util::PassKey<DialogModelHost>) {
+ base::PassKey<DialogModelHost>) {
return AsTextfield();
}
@@ -131,7 +131,7 @@ DialogModelButton::Params& DialogModelButton::Params::AddAccelerator(
}
DialogModelButton::DialogModelButton(
- util::PassKey<DialogModel> pass_key,
+ base::PassKey<DialogModel> pass_key,
DialogModel* model,
base::RepeatingCallback<void(const Event&)> callback,
base::string16 label,
@@ -148,12 +148,12 @@ DialogModelButton::DialogModelButton(
DialogModelButton::~DialogModelButton() = default;
-void DialogModelButton::OnPressed(util::PassKey<DialogModelHost>,
+void DialogModelButton::OnPressed(base::PassKey<DialogModelHost>,
const Event& event) {
callback_.Run(event);
}
-DialogModelBodyText::DialogModelBodyText(util::PassKey<DialogModel> pass_key,
+DialogModelBodyText::DialogModelBodyText(base::PassKey<DialogModel> pass_key,
DialogModel* model,
const DialogModelLabel& label)
: DialogModelField(pass_key,
@@ -165,20 +165,23 @@ DialogModelBodyText::DialogModelBodyText(util::PassKey<DialogModel> pass_key,
DialogModelBodyText::~DialogModelBodyText() = default;
-DialogModelCheckbox::DialogModelCheckbox(util::PassKey<DialogModel> pass_key,
- DialogModel* model,
- int unique_id,
- const DialogModelLabel& label)
+DialogModelCheckbox::DialogModelCheckbox(
+ base::PassKey<DialogModel> pass_key,
+ DialogModel* model,
+ int unique_id,
+ const DialogModelLabel& label,
+ const DialogModelCheckbox::Params& params)
: DialogModelField(pass_key,
model,
kCheckbox,
unique_id,
base::flat_set<Accelerator>()),
- label_(label) {}
+ label_(label),
+ is_checked_(params.is_checked_) {}
DialogModelCheckbox::~DialogModelCheckbox() = default;
-void DialogModelCheckbox::OnChecked(util::PassKey<DialogModelHost>,
+void DialogModelCheckbox::OnChecked(base::PassKey<DialogModelHost>,
bool is_checked) {
is_checked_ = is_checked;
}
@@ -205,14 +208,8 @@ DialogModelCombobox::Params& DialogModelCombobox::Params::AddAccelerator(
return *this;
}
-DialogModelCombobox::Params& DialogModelCombobox::Params::SetAccessibleName(
- base::string16 accessible_name) {
- accessible_name_ = std::move(accessible_name);
- return *this;
-}
-
DialogModelCombobox::DialogModelCombobox(
- util::PassKey<DialogModel> pass_key,
+ base::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label,
std::unique_ptr<ui::ComboboxModel> combobox_model,
@@ -230,12 +227,12 @@ DialogModelCombobox::DialogModelCombobox(
DialogModelCombobox::~DialogModelCombobox() = default;
-void DialogModelCombobox::OnSelectedIndexChanged(util::PassKey<DialogModelHost>,
+void DialogModelCombobox::OnSelectedIndexChanged(base::PassKey<DialogModelHost>,
int selected_index) {
selected_index_ = selected_index;
}
-void DialogModelCombobox::OnPerformAction(util::PassKey<DialogModelHost>) {
+void DialogModelCombobox::OnPerformAction(base::PassKey<DialogModelHost>) {
if (callback_)
callback_.Run();
}
@@ -256,14 +253,8 @@ DialogModelTextfield::Params& DialogModelTextfield::Params::AddAccelerator(
return *this;
}
-DialogModelTextfield::Params& DialogModelTextfield::Params::SetAccessibleName(
- base::string16 accessible_name) {
- accessible_name_ = accessible_name;
- return *this;
-}
-
DialogModelTextfield::DialogModelTextfield(
- util::PassKey<DialogModel> pass_key,
+ base::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label,
base::string16 text,
@@ -279,7 +270,7 @@ DialogModelTextfield::DialogModelTextfield(
DialogModelTextfield::~DialogModelTextfield() = default;
-void DialogModelTextfield::OnTextChanged(util::PassKey<DialogModelHost>,
+void DialogModelTextfield::OnTextChanged(base::PassKey<DialogModelHost>,
base::string16 text) {
text_ = std::move(text);
}
diff --git a/chromium/ui/base/models/dialog_model_field.h b/chromium/ui/base/models/dialog_model_field.h
index 1e2c2c87d50..54b50c7670f 100644
--- a/chromium/ui/base/models/dialog_model_field.h
+++ b/chromium/ui/base/models/dialog_model_field.h
@@ -7,8 +7,9 @@
#include "base/callback.h"
#include "base/containers/flat_set.h"
+#include "base/gtest_prod_util.h"
#include "base/strings/string16.h"
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/models/combobox_model.h"
@@ -59,7 +60,7 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelLabel {
// links() and message_id() to construct the final label. This is required to
// style the final label appropriately and support link callbacks. The caller
// is responsible for checking links().empty() before calling this.
- const base::string16& GetString(util::PassKey<DialogModelHost>) const;
+ const base::string16& GetString(base::PassKey<DialogModelHost>) const;
DialogModelLabel& set_is_secondary() {
is_secondary_ = true;
@@ -71,14 +72,14 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelLabel {
return *this;
}
- int message_id(util::PassKey<DialogModelHost>) const { return message_id_; }
- const std::vector<Link> links(util::PassKey<DialogModelHost>) const {
+ int message_id(base::PassKey<DialogModelHost>) const { return message_id_; }
+ const std::vector<Link> links(base::PassKey<DialogModelHost>) const {
return links_;
}
- bool is_secondary(util::PassKey<DialogModelHost>) const {
+ bool is_secondary(base::PassKey<DialogModelHost>) const {
return is_secondary_;
}
- bool allow_character_break(util::PassKey<DialogModelHost>) const {
+ bool allow_character_break(base::PassKey<DialogModelHost>) const {
return allow_character_break_;
}
@@ -108,23 +109,24 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelField {
DialogModelField& operator=(const DialogModelField&) = delete;
virtual ~DialogModelField();
- // Methods with util::PassKey<DialogModelHost> are only intended to be called
+ // Methods with base::PassKey<DialogModelHost> are only intended to be called
// by the DialogModelHost implementation.
- Type type(util::PassKey<DialogModelHost>) const { return type_; }
+ Type type(base::PassKey<DialogModelHost>) const { return type_; }
const base::flat_set<Accelerator>& accelerators(
- util::PassKey<DialogModelHost>) const {
+ base::PassKey<DialogModelHost>) const {
return accelerators_;
}
- DialogModelButton* AsButton(util::PassKey<DialogModelHost>);
- DialogModelBodyText* AsBodyText(util::PassKey<DialogModelHost>);
- DialogModelCheckbox* AsCheckbox(util::PassKey<DialogModelHost>);
- DialogModelCombobox* AsCombobox(util::PassKey<DialogModelHost>);
- DialogModelTextfield* AsTextfield(util::PassKey<DialogModelHost>);
+ int unique_id(base::PassKey<DialogModelHost>) const { return unique_id_; }
+ DialogModelButton* AsButton(base::PassKey<DialogModelHost>);
+ DialogModelBodyText* AsBodyText(base::PassKey<DialogModelHost>);
+ DialogModelCheckbox* AsCheckbox(base::PassKey<DialogModelHost>);
+ DialogModelCombobox* AsCombobox(base::PassKey<DialogModelHost>);
+ DialogModelTextfield* AsTextfield(base::PassKey<DialogModelHost>);
protected:
// Children of this class need to be constructed through DialogModel to help
// enforce that they're added to the model.
- DialogModelField(util::PassKey<DialogModel>,
+ DialogModelField(base::PassKey<DialogModel>,
DialogModel* model,
Type type,
int unique_id,
@@ -138,6 +140,7 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelField {
private:
friend class DialogModel;
+ FRIEND_TEST_ALL_PREFIXES(DialogModelButtonTest, UsesParamsUniqueId);
DialogModel* const model_;
const Type type_;
@@ -159,7 +162,6 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelButton : public DialogModelField {
Params& SetUniqueId(int unique_id);
Params& AddAccelerator(Accelerator accelerator);
- Params& SetAccessibleName(base::string16 accessible_name);
private:
friend class DialogModelButton;
@@ -170,7 +172,7 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelButton : public DialogModelField {
// Note that this is constructed through a DialogModel which adds it to model
// fields.
- DialogModelButton(util::PassKey<DialogModel> pass_key,
+ DialogModelButton(base::PassKey<DialogModel> pass_key,
DialogModel* model,
base::RepeatingCallback<void(const Event&)> callback,
base::string16 label,
@@ -179,12 +181,12 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelButton : public DialogModelField {
DialogModelButton& operator=(const DialogModelButton&) = delete;
~DialogModelButton() override;
- // Methods with util::PassKey<DialogModelHost> are only intended to be called
+ // Methods with base::PassKey<DialogModelHost> are only intended to be called
// by the DialogModelHost implementation.
- const base::string16& label(util::PassKey<DialogModelHost>) const {
+ const base::string16& label(base::PassKey<DialogModelHost>) const {
return label_;
}
- void OnPressed(util::PassKey<DialogModelHost>, const Event& event);
+ void OnPressed(base::PassKey<DialogModelHost>, const Event& event);
private:
friend class DialogModel;
@@ -201,14 +203,14 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelBodyText : public DialogModelField {
public:
// Note that this is constructed through a DialogModel which adds it to model
// fields.
- DialogModelBodyText(util::PassKey<DialogModel> pass_key,
+ DialogModelBodyText(base::PassKey<DialogModel> pass_key,
DialogModel* model,
const DialogModelLabel& label);
DialogModelBodyText(const DialogModelBodyText&) = delete;
DialogModelBodyText& operator=(const DialogModelBodyText&) = delete;
~DialogModelBodyText() override;
- const DialogModelLabel& label(util::PassKey<DialogModelHost>) const {
+ const DialogModelLabel& label(base::PassKey<DialogModelHost>) const {
return label_;
}
@@ -219,26 +221,45 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelBodyText : public DialogModelField {
// Field class representing a checkbox with descriptive text.
class COMPONENT_EXPORT(UI_BASE) DialogModelCheckbox : public DialogModelField {
public:
+ class COMPONENT_EXPORT(UI_BASE) Params {
+ public:
+ Params() = default;
+ Params(const Params&) = delete;
+ Params& operator=(const Params&) = delete;
+ ~Params() = default;
+
+ Params& SetIsChecked(bool is_checked) {
+ is_checked_ = is_checked;
+ return *this;
+ }
+
+ private:
+ friend class DialogModelCheckbox;
+
+ bool is_checked_ = false;
+ };
+
// Note that this is constructed through a DialogModel which adds it to model
// fields.
- DialogModelCheckbox(util::PassKey<DialogModel> pass_key,
+ DialogModelCheckbox(base::PassKey<DialogModel> pass_key,
DialogModel* model,
int unique_id,
- const DialogModelLabel& label);
+ const DialogModelLabel& label,
+ const Params& params);
DialogModelCheckbox(const DialogModelCheckbox&) = delete;
DialogModelCheckbox& operator=(const DialogModelCheckbox&) = delete;
~DialogModelCheckbox() override;
bool is_checked() const { return is_checked_; }
- void OnChecked(util::PassKey<DialogModelHost>, bool is_checked);
- const DialogModelLabel& label(util::PassKey<DialogModelHost>) const {
+ void OnChecked(base::PassKey<DialogModelHost>, bool is_checked);
+ const DialogModelLabel& label(base::PassKey<DialogModelHost>) const {
return label_;
}
private:
const DialogModelLabel label_;
- bool is_checked_ = false;
+ bool is_checked_;
};
// Field class representing a combobox and corresponding label to describe the
@@ -258,7 +279,11 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelCombobox : public DialogModelField {
Params& SetUniqueId(int unique_id);
Params& AddAccelerator(Accelerator accelerator);
- Params& SetAccessibleName(base::string16 accessible_name);
+
+ Params& SetAccessibleName(base::string16 accessible_name) {
+ accessible_name_ = std::move(accessible_name);
+ return *this;
+ }
// The combobox callback is invoked when an item has been selected. This
// nominally happens when selecting an item in the combobox menu. The
@@ -278,7 +303,7 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelCombobox : public DialogModelField {
// Note that this is constructed through a DialogModel which adds it to model
// fields.
- DialogModelCombobox(util::PassKey<DialogModel> pass_key,
+ DialogModelCombobox(base::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label,
std::unique_ptr<ui::ComboboxModel> combobox_model,
@@ -290,17 +315,17 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelCombobox : public DialogModelField {
int selected_index() const { return selected_index_; }
ui::ComboboxModel* combobox_model() { return combobox_model_.get(); }
- // Methods with util::PassKey<DialogModelHost> are only intended to be called
+ // Methods with base::PassKey<DialogModelHost> are only intended to be called
// by the DialogModelHost implementation.
- const base::string16& label(util::PassKey<DialogModelHost>) const {
+ const base::string16& label(base::PassKey<DialogModelHost>) const {
return label_;
}
- const base::string16& accessible_name(util::PassKey<DialogModelHost>) const {
+ const base::string16& accessible_name(base::PassKey<DialogModelHost>) const {
return accessible_name_;
}
- void OnSelectedIndexChanged(util::PassKey<DialogModelHost>,
+ void OnSelectedIndexChanged(base::PassKey<DialogModelHost>,
int selected_index);
- void OnPerformAction(util::PassKey<DialogModelHost>);
+ void OnPerformAction(base::PassKey<DialogModelHost>);
private:
friend class DialogModel;
@@ -329,7 +354,11 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelTextfield : public DialogModelField {
Params& SetUniqueId(int unique_id);
Params& AddAccelerator(Accelerator accelerator);
- Params& SetAccessibleName(base::string16 accessible_name);
+
+ Params& SetAccessibleName(base::string16 accessible_name) {
+ accessible_name_ = std::move(accessible_name);
+ return *this;
+ }
private:
friend class DialogModelTextfield;
@@ -341,7 +370,7 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelTextfield : public DialogModelField {
// Note that this is constructed through a DialogModel which adds it to model
// fields.
- DialogModelTextfield(util::PassKey<DialogModel> pass_key,
+ DialogModelTextfield(base::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label,
base::string16 text,
@@ -352,15 +381,15 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelTextfield : public DialogModelField {
const base::string16& text() const { return text_; }
- // Methods with util::PassKey<DialogModelHost> are only intended to be called
+ // Methods with base::PassKey<DialogModelHost> are only intended to be called
// by the DialogModelHost implementation.
- const base::string16& label(util::PassKey<DialogModelHost>) const {
+ const base::string16& label(base::PassKey<DialogModelHost>) const {
return label_;
}
- const base::string16& accessible_name(util::PassKey<DialogModelHost>) const {
+ const base::string16& accessible_name(base::PassKey<DialogModelHost>) const {
return accessible_name_;
}
- void OnTextChanged(util::PassKey<DialogModelHost>, base::string16 text);
+ void OnTextChanged(base::PassKey<DialogModelHost>, base::string16 text);
private:
friend class DialogModel;
diff --git a/chromium/ui/base/models/dialog_model_host.h b/chromium/ui/base/models/dialog_model_host.h
index 30590f063ef..73e0a49b9b8 100644
--- a/chromium/ui/base/models/dialog_model_host.h
+++ b/chromium/ui/base/models/dialog_model_host.h
@@ -5,7 +5,7 @@
#ifndef UI_BASE_MODELS_DIALOG_MODEL_HOST_H_
#define UI_BASE_MODELS_DIALOG_MODEL_HOST_H_
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
namespace ui {
@@ -19,19 +19,14 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelHost {
// or DialogModelHost.
virtual void Close() = 0;
- // Selects all text of a textfield.
- // TODO(pbos): Reconsider whether this should be implied by if the textfield
- // is initially focused.
- virtual void SelectAllText(int unique_id) = 0;
-
protected:
friend class DialogModel;
friend class DialogModelField;
// This PassKey is used to make sure that some methods on DialogModel
// are only called as part of the host integration.
- static util::PassKey<DialogModelHost> GetPassKey() {
- return util::PassKey<DialogModelHost>();
+ static base::PassKey<DialogModelHost> GetPassKey() {
+ return base::PassKey<DialogModelHost>();
}
// Called when various parts of the model changes.
diff --git a/chromium/ui/base/models/dialog_model_unittest.cc b/chromium/ui/base/models/dialog_model_unittest.cc
new file mode 100644
index 00000000000..83b8a0e9ff0
--- /dev/null
+++ b/chromium/ui/base/models/dialog_model_unittest.cc
@@ -0,0 +1,164 @@
+// Copyright 2020 The Chromium 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"
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/bind.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/test/test_dialog_model_host.h"
+#include "ui/events/event.h"
+
+namespace ui {
+
+class DialogModelButtonTest : public testing::Test {};
+
+TEST_F(DialogModelButtonTest, UsesParamsUniqueId) {
+ constexpr int kUniqueId = 42;
+ // TODO(pbos): Replace AddOkButton() with AddButton() once buttons in dialogs
+ // are supported.
+ std::unique_ptr<DialogModel> model =
+ DialogModel::Builder()
+ .AddOkButton(base::OnceClosure(), base::string16(),
+ DialogModelButton::Params().SetUniqueId(kUniqueId))
+ .Build();
+ EXPECT_EQ(kUniqueId,
+ model->ok_button(TestDialogModelHost::GetPassKey())->unique_id_);
+}
+
+TEST_F(DialogModelButtonTest, UsesParamsAccelerators) {
+ const Accelerator accelerator_1;
+ const Accelerator accelerator_2(VKEY_Z, EF_SHIFT_DOWN | EF_CONTROL_DOWN);
+
+ // TODO(pbos): Replace AddOkButton() with AddButton() once buttons in dialogs
+ // are supported.
+ std::unique_ptr<DialogModel> model =
+ DialogModel::Builder()
+ .AddOkButton(base::OnceClosure(), base::string16(),
+ DialogModelButton::Params()
+ .AddAccelerator(accelerator_1)
+ .AddAccelerator(accelerator_2))
+ .Build();
+ EXPECT_THAT(model->ok_button(TestDialogModelHost::GetPassKey())
+ ->accelerators(TestDialogModelHost::GetPassKey()),
+ testing::UnorderedElementsAre(accelerator_1, accelerator_2));
+}
+
+TEST_F(DialogModelButtonTest, UsesCallback) {
+ int callback_count = 0;
+ std::unique_ptr<KeyEvent> last_event;
+ // TODO(pbos): Replace AddExtraButton() with AddButton() once buttons in
+ // dialogs are supported.
+ std::unique_ptr<DialogModel> model =
+ DialogModel::Builder()
+ .AddDialogExtraButton(
+ base::BindLambdaForTesting([&](const Event& event) {
+ ++callback_count;
+ last_event = std::make_unique<KeyEvent>(*event.AsKeyEvent());
+ }),
+ base::string16())
+ .Build();
+ DialogModelButton* const button =
+ model->extra_button(TestDialogModelHost::GetPassKey());
+
+ KeyEvent first_event(ET_KEY_PRESSED, VKEY_RETURN, EF_NONE);
+ button->OnPressed(TestDialogModelHost::GetPassKey(), first_event);
+ EXPECT_EQ(1, callback_count);
+ EXPECT_EQ(first_event.key_code(), last_event->key_code());
+
+ KeyEvent second_event(ET_KEY_PRESSED, VKEY_SPACE, EF_NONE);
+ button->OnPressed(TestDialogModelHost::GetPassKey(), second_event);
+ EXPECT_EQ(2, callback_count);
+ EXPECT_EQ(second_event.key_code(), last_event->key_code());
+}
+
+class DialogModelDialogButtonTest : public testing::Test {
+ public:
+ enum DialogButtonId {
+ kCancelButton,
+ kExtraButton,
+ kOkButton,
+ };
+
+ void DialogButtonUsesArguments(DialogButtonId button_id) {
+ DialogModel::Builder builder;
+
+ // Callback to verify that the first parameter is used.
+ bool callback_called = false;
+ base::OnceClosure callback = base::BindRepeating(
+ [](bool* callback_called) { *callback_called = true; },
+ &callback_called);
+
+ // Label to verify the second parameter.
+ base::string16 label = base::ASCIIToUTF16("my cool button");
+
+ // The presence of an accelerator in |params| will be used to verify that
+ // |params| are forwarded correctly to the DialogModelButton constructor.
+ DialogModelButton::Params params;
+ Accelerator accelerator(VKEY_Z, EF_SHIFT_DOWN | EF_CONTROL_DOWN);
+ params.AddAccelerator(accelerator);
+
+ switch (button_id) {
+ case kCancelButton:
+ builder.AddCancelButton(std::move(callback), label, params);
+ break;
+ case kExtraButton:
+ // Wrap the callback into a repeating callback that'll only be called
+ // once so the same verification can be used for the extra button.
+ builder.AddDialogExtraButton(
+ base::BindRepeating(
+ [](base::OnceClosure* callback, const Event& event) {
+ std::move(*callback).Run();
+ },
+ &callback),
+ label, params);
+ break;
+ case kOkButton:
+ builder.AddOkButton(std::move(callback), label, params);
+ break;
+ }
+ std::unique_ptr<DialogModel> model = builder.Build();
+
+ // Get the DialogModelButton and trigger the corresponding callback.
+ DialogModelButton* button = nullptr;
+ switch (button_id) {
+ case kCancelButton:
+ button = model->cancel_button(TestDialogModelHost::GetPassKey());
+ model->OnDialogCancelled(TestDialogModelHost::GetPassKey());
+ break;
+ case kExtraButton:
+ button = model->extra_button(TestDialogModelHost::GetPassKey());
+ button->OnPressed(TestDialogModelHost::GetPassKey(),
+ KeyEvent(ET_KEY_PRESSED, VKEY_RETURN, EF_NONE));
+ break;
+ case kOkButton:
+ button = model->ok_button(TestDialogModelHost::GetPassKey());
+ model->OnDialogAccepted(TestDialogModelHost::GetPassKey());
+ break;
+ }
+ ASSERT_TRUE(button);
+
+ EXPECT_TRUE(callback_called) << "The callback parameter wasn't used.";
+ EXPECT_EQ(label, button->label(TestDialogModelHost::GetPassKey()))
+ << "The label parameter wasn't used.";
+ EXPECT_THAT(button->accelerators(TestDialogModelHost::GetPassKey()),
+ testing::UnorderedElementsAre(accelerator))
+ << "The params parameter wasn't used.";
+ }
+};
+
+TEST_F(DialogModelDialogButtonTest, OkButtonUsesArguments) {
+ DialogButtonUsesArguments(kOkButton);
+}
+
+TEST_F(DialogModelDialogButtonTest, ExtraButtonUsesArguments) {
+ DialogButtonUsesArguments(kExtraButton);
+}
+
+TEST_F(DialogModelDialogButtonTest, CancelButtonUsesArguments) {
+ DialogButtonUsesArguments(kCancelButton);
+}
+
+} // namespace ui \ No newline at end of file
diff --git a/chromium/ui/base/models/list_selection_model.cc b/chromium/ui/base/models/list_selection_model.cc
index 90c66420a9b..0138856da32 100644
--- a/chromium/ui/base/models/list_selection_model.cc
+++ b/chromium/ui/base/models/list_selection_model.cc
@@ -8,7 +8,7 @@
#include <valarray>
#include "base/check_op.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
namespace ui {
@@ -85,10 +85,11 @@ void ListSelectionModel::IncrementFrom(int index) {
void ListSelectionModel::DecrementFrom(int index) {
for (auto i = selected_indices_.begin(); i != selected_indices_.end();) {
- if (DecrementFromImpl(index, &(*i)))
+ if (DecrementFromImpl(index, &(*i))) {
i = selected_indices_.erase(i);
- else
+ } else {
++i;
+ }
}
DecrementFromImpl(index, &anchor_);
DecrementFromImpl(index, &active_);
@@ -98,7 +99,7 @@ void ListSelectionModel::SetSelectedIndex(int index) {
anchor_ = active_ = index;
selected_indices_.clear();
if (index != kUnselectedIndex)
- selected_indices_.push_back(index);
+ selected_indices_.insert(index);
}
bool ListSelectionModel::IsSelected(int index) const {
@@ -106,16 +107,23 @@ bool ListSelectionModel::IsSelected(int index) const {
}
void ListSelectionModel::AddIndexToSelection(int index) {
- if (!IsSelected(index)) {
- selected_indices_.push_back(index);
- std::sort(selected_indices_.begin(), selected_indices_.end());
+ selected_indices_.insert(index);
+}
+
+void ListSelectionModel::AddIndexRangeToSelection(int index_start,
+ int index_end) {
+ DCHECK_LE(index_start, index_end);
+
+ if (index_start == index_end)
+ return AddIndexToSelection(index_start);
+
+ for (int i = index_start; i <= index_end; ++i) {
+ selected_indices_.insert(i);
}
}
void ListSelectionModel::RemoveIndexFromSelection(int index) {
- auto i = std::find(selected_indices_.begin(), selected_indices_.end(), index);
- if (i != selected_indices_.end())
- selected_indices_.erase(i);
+ selected_indices_.erase(index);
}
void ListSelectionModel::SetSelectionFromAnchorTo(int index) {
@@ -123,9 +131,9 @@ void ListSelectionModel::SetSelectionFromAnchorTo(int index) {
SetSelectedIndex(index);
} else {
int delta = std::abs(index - anchor_);
- SelectedIndices new_selection(delta + 1, 0);
+ SelectedIndices new_selection;
for (int i = 0, min = std::min(index, anchor_); i <= delta; ++i)
- new_selection[i] = i + min;
+ new_selection.insert(i + min);
selected_indices_.swap(new_selection);
active_ = index;
}
@@ -137,10 +145,8 @@ void ListSelectionModel::AddSelectionFromAnchorTo(int index) {
} else {
for (int i = std::min(index, anchor_), end = std::max(index, anchor_);
i <= end; ++i) {
- if (!IsSelected(i))
- selected_indices_.push_back(i);
+ selected_indices_.insert(i);
}
- std::sort(selected_indices_.begin(), selected_indices_.end());
active_ = index;
}
}
@@ -195,13 +201,11 @@ void ListSelectionModel::Move(int old_index, int new_index, int length) {
// still sorted piecewise, and |pivot_value| is a lower bound for elements in
// [low, middle), and an upper bound for [middle, high).
std::rotate(low, middle, high);
- DCHECK(std::is_sorted(selected_indices_.begin(), selected_indices_.end()));
}
void ListSelectionModel::Clear() {
anchor_ = active_ = kUnselectedIndex;
- SelectedIndices empty_selection;
- selected_indices_.swap(empty_selection);
+ selected_indices_.clear();
}
} // namespace ui
diff --git a/chromium/ui/base/models/list_selection_model.h b/chromium/ui/base/models/list_selection_model.h
index 4c98ae9f645..7c672f9006f 100644
--- a/chromium/ui/base/models/list_selection_model.h
+++ b/chromium/ui/base/models/list_selection_model.h
@@ -7,9 +7,8 @@
#include <stddef.h>
-#include <vector>
-
#include "base/component_export.h"
+#include "base/containers/flat_set.h"
namespace ui {
@@ -27,7 +26,7 @@ namespace ui {
// active index correspond to the same thing.
class COMPONENT_EXPORT(UI_BASE) ListSelectionModel {
public:
- using SelectedIndices = std::vector<int>;
+ using SelectedIndices = base::flat_set<int>;
// Used to identify no selection.
static constexpr int kUnselectedIndex = -1;
@@ -80,6 +79,10 @@ class COMPONENT_EXPORT(UI_BASE) ListSelectionModel {
// indices.
void AddIndexToSelection(int index);
+ // Adds indices between |index_start| and |index_end|, inclusive.
+ // This does not change the active or anchor indices.
+ void AddIndexRangeToSelection(int index_start, int index_end);
+
// Removes |index| from the selection. This does not change the active or
// anchor indices.
void RemoveIndexFromSelection(int index);
diff --git a/chromium/ui/base/models/list_selection_model_unittest.cc b/chromium/ui/base/models/list_selection_model_unittest.cc
index 8c52ba11939..898ae5ee8ca 100644
--- a/chromium/ui/base/models/list_selection_model_unittest.cc
+++ b/chromium/ui/base/models/list_selection_model_unittest.cc
@@ -24,10 +24,14 @@ static std::string StateAsString(const ListSelectionModel& model) {
" selection=";
const ListSelectionModel::SelectedIndices& selection(
model.selected_indices());
- for (size_t i = 0; i < selection.size(); ++i) {
- if (i != 0)
+ bool first = true;
+ for (int index : selection) {
+ if (first) {
+ first = false;
+ } else {
result += " ";
- result += base::NumberToString(selection[i]);
+ }
+ result += base::NumberToString(index);
}
return result;
}
@@ -98,6 +102,18 @@ TEST_F(ListSelectionModelTest, AddIndexToSelected) {
EXPECT_EQ("active=-1 anchor=-1 selection=2 4", StateAsString(model));
}
+TEST_F(ListSelectionModelTest, AddIndexRangeToSelection) {
+ ListSelectionModel model;
+ model.AddIndexRangeToSelection(2, 3);
+ EXPECT_EQ("active=-1 anchor=-1 selection=2 3", StateAsString(model));
+
+ model.AddIndexRangeToSelection(4, 5);
+ EXPECT_EQ("active=-1 anchor=-1 selection=2 3 4 5", StateAsString(model));
+
+ model.AddIndexRangeToSelection(1, 1);
+ EXPECT_EQ("active=-1 anchor=-1 selection=1 2 3 4 5", StateAsString(model));
+}
+
TEST_F(ListSelectionModelTest, RemoveIndexFromSelection) {
ListSelectionModel model;
model.SetSelectedIndex(2);
diff --git a/chromium/ui/base/models/menu_model.cc b/chromium/ui/base/models/menu_model.cc
index 32070758287..d73c88e4152 100644
--- a/chromium/ui/base/models/menu_model.cc
+++ b/chromium/ui/base/models/menu_model.cc
@@ -68,6 +68,10 @@ ImageModel MenuModel::GetMinorIconAt(int index) const {
return ImageModel();
}
+bool MenuModel::MayHaveMnemonicsAt(int index) const {
+ return true;
+}
+
const gfx::FontList* MenuModel::GetLabelFontListAt(int index) const {
return nullptr;
}
diff --git a/chromium/ui/base/models/menu_model.h b/chromium/ui/base/models/menu_model.h
index c746b37d627..bf7988cab13 100644
--- a/chromium/ui/base/models/menu_model.h
+++ b/chromium/ui/base/models/menu_model.h
@@ -84,6 +84,10 @@ class COMPONENT_EXPORT(UI_BASE) MenuModel
// updated each time the menu is shown.
virtual bool IsItemDynamicAt(int index) const = 0;
+ // Returns whether the menu item at the specified index has a user-set title,
+ // in which case it should always be treated as plain text.
+ virtual bool MayHaveMnemonicsAt(int index) const;
+
// Returns the font list used for the label at the specified index.
// If NULL, then the default font list should be used.
virtual const gfx::FontList* GetLabelFontListAt(int index) const;
diff --git a/chromium/ui/base/models/simple_menu_model.cc b/chromium/ui/base/models/simple_menu_model.cc
index 0c37f6e2cae..7db4ef95402 100644
--- a/chromium/ui/base/models/simple_menu_model.cc
+++ b/chromium/ui/base/models/simple_menu_model.cc
@@ -325,6 +325,11 @@ void SimpleMenuModel::SetIsNewFeatureAt(int index, bool is_new_feature) {
items_[ValidateItemIndex(index)].is_new_feature = is_new_feature;
}
+void SimpleMenuModel::SetMayHaveMnemonicsAt(int index,
+ bool may_have_mnemonics) {
+ items_[ValidateItemIndex(index)].may_have_mnemonics = may_have_mnemonics;
+}
+
void SimpleMenuModel::Clear() {
items_.clear();
MenuItemsChanged();
@@ -452,6 +457,10 @@ bool SimpleMenuModel::IsNewFeatureAt(int index) const {
return items_[ValidateItemIndex(index)].is_new_feature;
}
+bool SimpleMenuModel::MayHaveMnemonicsAt(int index) const {
+ return items_[ValidateItemIndex(index)].may_have_mnemonics;
+}
+
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 31669898f91..7cefe1d152e 100644
--- a/chromium/ui/base/models/simple_menu_model.h
+++ b/chromium/ui/base/models/simple_menu_model.h
@@ -169,6 +169,9 @@ class COMPONENT_EXPORT(UI_BASE) SimpleMenuModel : public MenuModel {
// Sets whether the item at |index| is new.
void SetIsNewFeatureAt(int index, bool is_new_feature);
+ // Sets whether the item at |index| is may have mnemonics.
+ void SetMayHaveMnemonicsAt(int index, bool may_have_mnemonics);
+
// Clears all items. Note that it does not free MenuModel of submenu.
void Clear();
@@ -195,6 +198,7 @@ class COMPONENT_EXPORT(UI_BASE) SimpleMenuModel : public MenuModel {
bool IsVisibleAt(int index) const override;
bool IsAlertedAt(int index) const override;
bool IsNewFeatureAt(int index) const override;
+ bool MayHaveMnemonicsAt(int index) const override;
void ActivatedAt(int index) override;
void ActivatedAt(int index, int event_flags) override;
MenuModel* GetSubmenuModelAt(int index) const override;
@@ -229,6 +233,7 @@ class COMPONENT_EXPORT(UI_BASE) SimpleMenuModel : public MenuModel {
bool enabled = true;
bool visible = true;
bool is_new_feature = false;
+ bool may_have_mnemonics = true;
};
typedef std::vector<Item> ItemVector;
diff --git a/chromium/ui/base/pointer/touch_ui_controller.cc b/chromium/ui/base/pointer/touch_ui_controller.cc
index d91151b4433..8c325d9be49 100644
--- a/chromium/ui/base/pointer/touch_ui_controller.cc
+++ b/chromium/ui/base/pointer/touch_ui_controller.cc
@@ -105,8 +105,8 @@ void TouchUiController::OnTabletModeToggled(bool enabled) {
TouchUiChanged();
}
-std::unique_ptr<TouchUiController::Subscription>
-TouchUiController::RegisterCallback(const base::RepeatingClosure& closure) {
+base::CallbackListSubscription TouchUiController::RegisterCallback(
+ const base::RepeatingClosure& closure) {
return callback_list_.Add(closure);
}
diff --git a/chromium/ui/base/pointer/touch_ui_controller.h b/chromium/ui/base/pointer/touch_ui_controller.h
index bcd93ac60e9..441bfe51309 100644
--- a/chromium/ui/base/pointer/touch_ui_controller.h
+++ b/chromium/ui/base/pointer/touch_ui_controller.h
@@ -24,7 +24,6 @@ namespace ui {
class COMPONENT_EXPORT(UI_BASE) TouchUiController {
public:
using CallbackList = base::RepeatingClosureList;
- using Subscription = CallbackList::Subscription;
enum class TouchUiState {
kDisabled,
@@ -62,7 +61,7 @@ class COMPONENT_EXPORT(UI_BASE) TouchUiController {
((touch_ui_state_ == TouchUiState::kAuto) && tablet_mode_);
}
- std::unique_ptr<Subscription> RegisterCallback(
+ base::CallbackListSubscription RegisterCallback(
const base::RepeatingClosure& closure);
void OnTabletModeToggled(bool enabled);
diff --git a/chromium/ui/base/pointer/touch_ui_controller_unittest.cc b/chromium/ui/base/pointer/touch_ui_controller_unittest.cc
index 98d7baa0848..c2baa976db4 100644
--- a/chromium/ui/base/pointer/touch_ui_controller_unittest.cc
+++ b/chromium/ui/base/pointer/touch_ui_controller_unittest.cc
@@ -5,7 +5,6 @@
#include <string>
#include "base/macros.h"
-#include "base/scoped_observer.h"
#include "base/test/bind.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/pointer/touch_ui_controller.h"
@@ -25,7 +24,7 @@ class TestObserver {
private:
int touch_ui_changes_ = 0;
- std::unique_ptr<ui::TouchUiController::Subscription> subscription_;
+ base::CallbackListSubscription subscription_;
};
} // namespace
diff --git a/chromium/ui/base/prediction/empty_predictor.cc b/chromium/ui/base/prediction/empty_predictor.cc
index 98598808b49..c1cacb3641c 100644
--- a/chromium/ui/base/prediction/empty_predictor.cc
+++ b/chromium/ui/base/prediction/empty_predictor.cc
@@ -30,7 +30,8 @@ bool EmptyPredictor::HasPrediction() const {
}
std::unique_ptr<InputPredictor::InputData> EmptyPredictor::GeneratePrediction(
- base::TimeTicks predict_time) const {
+ base::TimeTicks predict_time,
+ base::TimeDelta frame_interval) {
if (!HasPrediction())
return nullptr;
return std::make_unique<InputData>(last_input_.value());
diff --git a/chromium/ui/base/prediction/empty_predictor.h b/chromium/ui/base/prediction/empty_predictor.h
index 408261bf596..ebb41b3972e 100644
--- a/chromium/ui/base/prediction/empty_predictor.h
+++ b/chromium/ui/base/prediction/empty_predictor.h
@@ -30,7 +30,8 @@ class COMPONENT_EXPORT(UI_BASE_PREDICTION) EmptyPredictor
// Returns the last_input_ for testing.
std::unique_ptr<InputData> GeneratePrediction(
- base::TimeTicks predict_time) const override;
+ base::TimeTicks predict_time,
+ base::TimeDelta frame_interval) override;
// Returns kTimeInterval for testing.
base::TimeDelta TimeInterval() const override;
diff --git a/chromium/ui/base/prediction/input_predictor.h b/chromium/ui/base/prediction/input_predictor.h
index 50b8a9c236c..a77491aa0c5 100644
--- a/chromium/ui/base/prediction/input_predictor.h
+++ b/chromium/ui/base/prediction/input_predictor.h
@@ -47,8 +47,12 @@ class COMPONENT_EXPORT(UI_BASE_PREDICTION) InputPredictor {
virtual bool HasPrediction() const = 0;
// Generate the prediction based on current points.
+ // It can use a latency based on the vsync refresh rate: `frame_interval`.
+ // TODO(crbug.com/1142061): Remove the `frame_interval` arg if the expriment
+ // concludes that a frame-dependent latency isn't better.
virtual std::unique_ptr<InputData> GeneratePrediction(
- base::TimeTicks predict_time) const = 0;
+ base::TimeTicks predict_time,
+ base::TimeDelta frame_interval = base::TimeDelta::FromSeconds(0)) = 0;
// Returns the maximum of prediction available for resampling
// before having side effects (jitter, wrong orientation, etc..)
diff --git a/chromium/ui/base/prediction/input_predictor_unittest_helpers.h b/chromium/ui/base/prediction/input_predictor_unittest_helpers.h
index db2dadfa896..2ce8fef46e8 100644
--- a/chromium/ui/base/prediction/input_predictor_unittest_helpers.h
+++ b/chromium/ui/base/prediction/input_predictor_unittest_helpers.h
@@ -21,9 +21,9 @@ class InputPredictorTest : public testing::Test {
InputPredictorTest();
~InputPredictorTest() override;
- static base::TimeTicks FromMilliseconds(int64_t ms) {
+ static base::TimeTicks FromMilliseconds(double ms) {
return test::PredictionUnittestHelpers::GetStaticTimeStampForTests() +
- base::TimeDelta::FromMilliseconds(ms);
+ base::TimeDelta::FromMillisecondsD(ms);
}
void ValidatePredictor(const std::vector<double>& x,
diff --git a/chromium/ui/base/prediction/kalman_predictor.cc b/chromium/ui/base/prediction/kalman_predictor.cc
index df359f5da65..2678cfe640d 100644
--- a/chromium/ui/base/prediction/kalman_predictor.cc
+++ b/chromium/ui/base/prediction/kalman_predictor.cc
@@ -71,7 +71,8 @@ bool KalmanPredictor::HasPrediction() const {
}
std::unique_ptr<InputPredictor::InputData> KalmanPredictor::GeneratePrediction(
- base::TimeTicks predict_time) const {
+ base::TimeTicks predict_time,
+ base::TimeDelta frame_interval) {
if (!HasPrediction())
return nullptr;
diff --git a/chromium/ui/base/prediction/kalman_predictor.h b/chromium/ui/base/prediction/kalman_predictor.h
index 89d7b466b21..a748a1de34b 100644
--- a/chromium/ui/base/prediction/kalman_predictor.h
+++ b/chromium/ui/base/prediction/kalman_predictor.h
@@ -48,7 +48,8 @@ class COMPONENT_EXPORT(UI_BASE_PREDICTION) KalmanPredictor
// Generate the prediction based on stored points and given time_stamp.
// Return false if no prediction available.
std::unique_ptr<InputData> GeneratePrediction(
- base::TimeTicks predict_time) const override;
+ base::TimeTicks predict_time,
+ base::TimeDelta frame_interval) override;
// Return the filtered value of time intervals.
base::TimeDelta TimeInterval() const override;
diff --git a/chromium/ui/base/prediction/least_squares_predictor.cc b/chromium/ui/base/prediction/least_squares_predictor.cc
index ab3c37c1246..ef3085bd481 100644
--- a/chromium/ui/base/prediction/least_squares_predictor.cc
+++ b/chromium/ui/base/prediction/least_squares_predictor.cc
@@ -82,7 +82,8 @@ gfx::Matrix3F LeastSquaresPredictor::GetXMatrix() const {
}
std::unique_ptr<InputPredictor::InputData>
-LeastSquaresPredictor::GeneratePrediction(base::TimeTicks predict_time) const {
+LeastSquaresPredictor::GeneratePrediction(base::TimeTicks predict_time,
+ base::TimeDelta frame_interval) {
if (!HasPrediction())
return nullptr;
diff --git a/chromium/ui/base/prediction/least_squares_predictor.h b/chromium/ui/base/prediction/least_squares_predictor.h
index 12b9f1ce9fe..a8460125a14 100644
--- a/chromium/ui/base/prediction/least_squares_predictor.h
+++ b/chromium/ui/base/prediction/least_squares_predictor.h
@@ -38,7 +38,8 @@ class COMPONENT_EXPORT(UI_BASE_PREDICTION) LeastSquaresPredictor
// Generate the prediction based on stored points and given time_stamp.
// Return false if no prediction available.
std::unique_ptr<InputData> GeneratePrediction(
- base::TimeTicks predict_time) const override;
+ base::TimeTicks predict_time,
+ base::TimeDelta frame_interval) override;
// Return the averaged value of time intervals.
base::TimeDelta TimeInterval() const override;
diff --git a/chromium/ui/base/prediction/linear_predictor.cc b/chromium/ui/base/prediction/linear_predictor.cc
index 9f85488335b..08a2ca51c6e 100644
--- a/chromium/ui/base/prediction/linear_predictor.cc
+++ b/chromium/ui/base/prediction/linear_predictor.cc
@@ -81,7 +81,8 @@ bool LinearPredictor::HasPrediction() const {
}
std::unique_ptr<InputPredictor::InputData> LinearPredictor::GeneratePrediction(
- base::TimeTicks predict_time) const {
+ base::TimeTicks predict_time,
+ base::TimeDelta frame_interval) {
if (!HasPrediction())
return nullptr;
diff --git a/chromium/ui/base/prediction/linear_predictor.h b/chromium/ui/base/prediction/linear_predictor.h
index 0f3bac523d0..96997350393 100644
--- a/chromium/ui/base/prediction/linear_predictor.h
+++ b/chromium/ui/base/prediction/linear_predictor.h
@@ -42,7 +42,8 @@ class COMPONENT_EXPORT(UI_BASE_PREDICTION) LinearPredictor
// Generate the prediction based on stored points and given time_stamp.
// Return false if no prediction available.
std::unique_ptr<InputData> GeneratePrediction(
- base::TimeTicks predict_time) const override;
+ base::TimeTicks predict_time,
+ base::TimeDelta frame_interval) override;
// Return the average time delta in the event queue.
base::TimeDelta TimeInterval() const override;
diff --git a/chromium/ui/base/prediction/linear_resampling.cc b/chromium/ui/base/prediction/linear_resampling.cc
index 850e99c0c3b..92bd5f07b2d 100644
--- a/chromium/ui/base/prediction/linear_resampling.cc
+++ b/chromium/ui/base/prediction/linear_resampling.cc
@@ -6,6 +6,8 @@
#include <algorithm>
+#include <base/feature_list.h>
+#include "base/strings/string_number_conversions.h"
#include "ui/base/ui_base_features.h"
namespace ui {
@@ -22,7 +24,13 @@ constexpr auto kResampleMaxPrediction = base::TimeDelta::FromMilliseconds(8);
// resampling either doing interpolation or extrapolating a closer future time
// so that resampled result is more accurate and has less noise. This adds some
// latency during resampling but a few ms should be fine.
-constexpr auto kResampleLatency = base::TimeDelta::FromMilliseconds(5);
+constexpr auto kResampleLatency = base::TimeDelta::FromMilliseconds(-5);
+// The optimal prediction anticipation from experimentation: In the study
+// https://bit.ly/3iyQf8V we found that, on a machine with VSync at 60Hz, adding
+// 1/2 * frame_interval (on top of kResampleLatency) minimizes the Lag on touch
+// scrolling. + 1/2 * (1/60) - 5ms = 3.3ms.
+constexpr auto kResampleLatencyExperimental =
+ base::TimeDelta::FromMillisecondsD(3.3);
// Get position at |sample_time| by linear interpolate/extrapolate a and b.
inline gfx::PointF lerp(const InputPredictor::InputData& a,
@@ -71,11 +79,14 @@ bool LinearResampling::HasPrediction() const {
}
std::unique_ptr<InputPredictor::InputData> LinearResampling::GeneratePrediction(
- base::TimeTicks frame_time) const {
+ base::TimeTicks frame_time,
+ base::TimeDelta frame_interval) {
if (!HasPrediction())
return nullptr;
- base::TimeTicks sample_time = frame_time - kResampleLatency;
+ base::TimeDelta resample_latency =
+ latency_calculator_.GetResampleLatency(frame_interval);
+ base::TimeTicks sample_time = frame_time + resample_latency;
base::TimeDelta max_prediction =
std::min(kResampleMaxPrediction, events_dt_ / 2.0);
@@ -94,4 +105,37 @@ base::TimeDelta LinearResampling::TimeInterval() const {
return kTimeInterval;
}
+base::TimeDelta LinearResampling::LatencyCalculator::GetResampleLatency(
+ base::TimeDelta frame_interval) {
+ // Cache |resample_latency_| and recalculate only when |frame_interval|
+ // changes.
+ if (frame_interval != frame_interval_ || resample_latency_.is_zero()) {
+ frame_interval_ = frame_interval;
+ resample_latency_ = CalculateLatency();
+ }
+ return resample_latency_;
+}
+
+base::TimeDelta LinearResampling::LatencyCalculator::CalculateLatency() {
+ std::string prediction_type = GetFieldTrialParamValueByFeature(
+ ::features::kResamplingScrollEventsExperimentalPrediction, "mode");
+
+ if (prediction_type != ::features::kPredictionTypeTimeBased &&
+ prediction_type != ::features::kPredictionTypeFramesBased)
+ return kResampleLatency;
+
+ std::string latency_value = GetFieldTrialParamValueByFeature(
+ ::features::kResamplingScrollEventsExperimentalPrediction, "latency");
+ double latency;
+ if (base::StringToDouble(latency_value, &latency)) {
+ return prediction_type == ::features::kPredictionTypeTimeBased
+ ? base::TimeDelta::FromMillisecondsD(latency)
+ : latency * frame_interval_ + kResampleLatency;
+ }
+
+ return prediction_type == ::features::kPredictionTypeTimeBased
+ ? kResampleLatencyExperimental
+ : 0.5 * frame_interval_ + kResampleLatency;
+}
+
} // namespace ui
diff --git a/chromium/ui/base/prediction/linear_resampling.h b/chromium/ui/base/prediction/linear_resampling.h
index 4e44d44d352..c100a754ec9 100644
--- a/chromium/ui/base/prediction/linear_resampling.h
+++ b/chromium/ui/base/prediction/linear_resampling.h
@@ -38,12 +38,24 @@ class COMPONENT_EXPORT(UI_BASE_PREDICTION) LinearResampling
// Generate the prediction based on stored points and given frame_time.
// Return false if no prediction available.
std::unique_ptr<InputData> GeneratePrediction(
- base::TimeTicks frame_time) const override;
+ base::TimeTicks frame_time,
+ base::TimeDelta frame_interval) override;
// Return the average time delta in the event queue.
base::TimeDelta TimeInterval() const override;
private:
+ // Class to cache the Resample Latency to avoid its recalculation each frame.
+ class LatencyCalculator {
+ public:
+ base::TimeDelta GetResampleLatency(base::TimeDelta frame_interval);
+
+ private:
+ base::TimeDelta CalculateLatency();
+ base::TimeDelta resample_latency_;
+ base::TimeDelta frame_interval_;
+ };
+
static constexpr size_t kNumEventsForResampling = 2;
// Store the last events received
@@ -52,6 +64,8 @@ class COMPONENT_EXPORT(UI_BASE_PREDICTION) LinearResampling
// Store the current delta time between the last 2 events
base::TimeDelta events_dt_;
+ LatencyCalculator latency_calculator_;
+
DISALLOW_COPY_AND_ASSIGN(LinearResampling);
};
diff --git a/chromium/ui/base/prediction/linear_resampling_unittest.cc b/chromium/ui/base/prediction/linear_resampling_unittest.cc
index 9ae3bda367f..9ab31aa81a2 100644
--- a/chromium/ui/base/prediction/linear_resampling_unittest.cc
+++ b/chromium/ui/base/prediction/linear_resampling_unittest.cc
@@ -4,6 +4,7 @@
#include "ui/base/prediction/linear_resampling.h"
+#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/prediction/input_predictor_unittest_helpers.h"
#include "ui/base/ui_base_features.h"
@@ -17,6 +18,51 @@ class LinearResamplingTest : public InputPredictorTest {
void SetUp() override { predictor_ = std::make_unique<LinearResampling>(); }
+ void ValidatePredictorFrameBased(
+ const std::vector<double>& events_x,
+ const std::vector<double>& events_y,
+ const std::vector<double>& events_time_ms,
+ const std::vector<double>& prediction_time_ms,
+ const std::vector<double>& predicted_x,
+ const std::vector<double>& predicted_y,
+ const double vsync_frequency) {
+ // LinearResampling* predictor =
+ // dynamic_cast<LinearResampling*>(predictor_.get());
+ base::TimeDelta frame_interval =
+ base::TimeDelta::FromSecondsD(1.0f / vsync_frequency);
+
+ predictor_->Reset();
+ std::vector<double> computed_x;
+ std::vector<double> computed_y;
+ size_t current_prediction_index = 0;
+ for (size_t i = 0; i < events_time_ms.size(); i++) {
+ InputPredictor::InputData data = {gfx::PointF(events_x[i], events_y[i]),
+ FromMilliseconds(events_time_ms[i])};
+ predictor_->Update(data);
+
+ if (predictor_->HasPrediction()) {
+ auto result = predictor_->GeneratePrediction(
+ FromMilliseconds(prediction_time_ms[current_prediction_index]),
+ frame_interval);
+ EXPECT_TRUE(result);
+ computed_x.push_back(result->pos.x());
+ computed_y.push_back(result->pos.y());
+ EXPECT_GT(result->time_stamp, base::TimeTicks());
+ current_prediction_index++;
+ }
+ }
+
+ EXPECT_TRUE(computed_x.size() == predicted_x.size());
+ if (computed_x.size() == predicted_x.size()) {
+ for (size_t i = 0; i < predicted_x.size(); i++) {
+ EXPECT_NEAR(computed_x[i], predicted_x[i], kEpsilon);
+ EXPECT_NEAR(computed_y[i], predicted_y[i], kEpsilon);
+ }
+ }
+ }
+
+ base::test::ScopedFeatureList feature_list;
+
DISALLOW_COPY_AND_ASSIGN(LinearResamplingTest);
};
@@ -119,5 +165,95 @@ TEST_F(LinearResamplingTest, TimeInterval) {
base::TimeDelta::FromMilliseconds(t[1] - t[0]));
}
+// Tests resampling with the experimental latency if +3.3ms instead of
+// the default -5ms.
+TEST_F(LinearResamplingTest, ResamplingValueWithExperimentalLatencyTimeBased) {
+ base::FieldTrialParams params;
+ params["mode"] = ::features::kPredictionTypeTimeBased;
+ feature_list.Reset();
+ feature_list.InitAndEnableFeatureWithParameters(
+ features::kResamplingScrollEventsExperimentalPrediction, params);
+
+ std::vector<double> x = {10, 20, 30};
+ std::vector<double> y = {5, 25, 35};
+ std::vector<double> t = {15, 24, 32};
+
+ // Resample at `frame_time` = 24.7 ms, `sample_time` = 24.7+3.3 = 28ms.
+ // Resample at `frame_time` = 32.7 ms, `sample_time` = 32.7+3.3 = 36ms.
+ std::vector<double> pred_ts = {24.7, 32.7};
+ std::vector<double> pred_x = {24.44, 35};
+ std::vector<double> pred_y = {33.89, 40};
+ ValidatePredictor(x, y, t, pred_ts, pred_x, pred_y);
+}
+
+// Tests resampling with the experimental latency if +1ms (using switch) instead
+// of the default -5ms.
+TEST_F(LinearResamplingTest,
+ ResamplingValueWithExperimentalLatencyTimeBasedSwitch) {
+ base::FieldTrialParams params;
+ params["mode"] = ::features::kPredictionTypeTimeBased;
+ params["latency"] = "1.0";
+ feature_list.Reset();
+ feature_list.InitAndEnableFeatureWithParameters(
+ features::kResamplingScrollEventsExperimentalPrediction, params);
+
+ std::vector<double> x = {10, 20, 30};
+ std::vector<double> y = {5, 25, 35};
+ std::vector<double> t = {15, 24, 32};
+
+ // Resample at `frame_time` = 27 ms, `sample_time` = 27+1 = 28ms.
+ // Resample at `frame_time` = 35 ms, `sample_time` = 35+1 = 36ms.
+ std::vector<double> pred_ts = {27, 35};
+ std::vector<double> pred_x = {24.44, 35};
+ std::vector<double> pred_y = {33.89, 40};
+ ValidatePredictor(x, y, t, pred_ts, pred_x, pred_y);
+}
+
+// Tests resampling with the experimental latency if +0.5*`frame_interval`
+// instead of the default -5ms.
+TEST_F(LinearResamplingTest, ResamplingValueWithExperimentalLatencyFrameBased) {
+ base::FieldTrialParams params;
+ params["mode"] = ::features::kPredictionTypeFramesBased;
+ feature_list.Reset();
+ feature_list.InitAndEnableFeatureWithParameters(
+ features::kResamplingScrollEventsExperimentalPrediction, params);
+
+ std::vector<double> x = {10, 20, 30};
+ std::vector<double> y = {5, 25, 35};
+ std::vector<double> t = {15, 24, 32};
+
+ // Using 100Hz frequency => `frame_interval` = 10ms
+ // Resample at `frame_time` = 33 ms, `sample_time` = 28-5+0.5*10 = 28ms.
+ // Resample at `frame_time` = 41 ms, `sample_time` = 36-5+0.5*10 = 36ms.
+ std::vector<double> pred_ts = {28, 36};
+ std::vector<double> pred_x = {24.44, 35};
+ std::vector<double> pred_y = {33.89, 40};
+ ValidatePredictorFrameBased(x, y, t, pred_ts, pred_x, pred_y, 100);
+}
+
+// Tests resampling with the experimental latency if +0.5*`frame_interval`
+// (using switch) instead of the default -5ms.
+TEST_F(LinearResamplingTest,
+ ResamplingValueWithExperimentalLatencyFrameBasedSwitch) {
+ base::FieldTrialParams params;
+ params["mode"] = ::features::kPredictionTypeFramesBased;
+ params["latency"] = "1.0";
+ feature_list.Reset();
+ feature_list.InitAndEnableFeatureWithParameters(
+ features::kResamplingScrollEventsExperimentalPrediction, params);
+
+ std::vector<double> x = {10, 20, 30};
+ std::vector<double> y = {5, 25, 35};
+ std::vector<double> t = {15, 24, 32};
+
+ // Using 200Hz frequency => `frame_interval` = 5ms
+ // Resample at `frame_time` = 33 ms, `sample_time` = 28-5+1*5 = 28ms.
+ // Resample at `frame_time` = 41 ms, `sample_time` = 36-5+1*5 = 36ms.
+ std::vector<double> pred_ts = {28, 36};
+ std::vector<double> pred_x = {24.44, 35};
+ std::vector<double> pred_y = {33.89, 40};
+ ValidatePredictorFrameBased(x, y, t, pred_ts, pred_x, pred_y, 200);
+}
+
} // namespace test
} // namespace ui
diff --git a/chromium/ui/base/resource/data_pack.cc b/chromium/ui/base/resource/data_pack.cc
index 09513e6aed2..a3f14e9a1ea 100644
--- a/chromium/ui/base/resource/data_pack.cc
+++ b/chromium/ui/base/resource/data_pack.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/memory_mapped_file.h"
@@ -17,7 +18,6 @@
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/synchronization/lock.h"
#include "base/sys_byteorder.h"
diff --git a/chromium/ui/base/resource/resource_bundle.cc b/chromium/ui/base/resource/resource_bundle.cc
index 2b24b4ce2e2..910662d25a4 100644
--- a/chromium/ui/base/resource/resource_bundle.cc
+++ b/chromium/ui/base/resource/resource_bundle.cc
@@ -12,6 +12,7 @@
#include "base/big_endian.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/debug/alias.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
@@ -20,13 +21,13 @@
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/path_service.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "net/filter/gzip_header.h"
#include "skia/ext/image_operations.h"
#include "third_party/brotli/include/brotli/decode.h"
@@ -54,7 +55,7 @@
#include "ui/base/resource/resource_bundle_android.h"
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
#include "ui/gfx/platform_font_skia.h"
#endif
@@ -223,33 +224,20 @@ class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource);
};
-struct ResourceBundle::FontKey {
- FontKey(const std::string& typeface,
- int in_size_delta,
- gfx::Font::FontStyle in_style,
- gfx::Font::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(typeface, size_delta, style, weight) ==
- std::tie(rhs.typeface, rhs.size_delta, rhs.style, rhs.weight);
- }
+ResourceBundle::FontDetails::FontDetails(std::string typeface,
+ int size_delta,
+ gfx::Font::Weight weight)
+ : typeface(typeface), size_delta(size_delta), weight(weight) {}
- bool operator<(const FontKey& rhs) const {
- return std::tie(typeface, size_delta, style, weight) <
- std::tie(rhs.typeface, rhs.size_delta, rhs.style, rhs.weight);
- }
+bool ResourceBundle::FontDetails::operator==(const FontDetails& rhs) const {
+ return std::tie(typeface, size_delta, weight) ==
+ std::tie(rhs.typeface, rhs.size_delta, rhs.weight);
+}
- std::string typeface;
- int size_delta;
- gfx::Font::FontStyle style;
- gfx::Font::Weight weight;
-};
+bool ResourceBundle::FontDetails::operator<(const FontDetails& rhs) const {
+ return std::tie(typeface, size_delta, weight) <
+ std::tie(rhs.typeface, rhs.size_delta, rhs.weight);
+}
// static
std::string ResourceBundle::InitSharedInstanceWithLocale(
@@ -384,22 +372,8 @@ base::FilePath ResourceBundle::GetLocaleFilePath(
base::FilePath locale_file_path;
if (base::PathService::Get(ui::DIR_LOCALES, &locale_file_path)) {
-#if defined(OS_ANDROID)
- if (locale_file_path.value().find("chromium_tests") == std::string::npos) {
- std::string extracted_file_suffix =
- base::android::BuildInfo::GetInstance()->extracted_file_suffix();
- locale_file_path = locale_file_path.AppendASCII(
- app_locale + kPakFileExtension + extracted_file_suffix);
- } else {
- // TODO(agrieve): Update tests to not side-load pak files and remove
- // this special-case. https://crbug.com/691719
- locale_file_path =
- locale_file_path.AppendASCII(app_locale + kPakFileExtension);
- }
-#else
locale_file_path =
locale_file_path.AppendASCII(app_locale + kPakFileExtension);
-#endif
}
// Note: The delegate GetPathForLocalePack() override is currently only used
@@ -448,6 +422,7 @@ std::string ResourceBundle::LoadLocaleResources(const std::string& pref_locale,
}
locale_resources_data_ = std::move(data_pack);
+ loaded_locale_ = pref_locale;
return app_locale;
}
#endif // defined(OS_ANDROID)
@@ -557,7 +532,7 @@ gfx::Image& ResourceBundle::GetImageNamed(int resource_id) {
if (image.IsEmpty()) {
DCHECK(!data_packs_.empty()) << "Missing call to SetResourcesDataDLL?";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ui::ScaleFactor scale_factor_to_load = GetMaxScaleFactor();
#elif defined(OS_WIN)
ui::ScaleFactor scale_factor_to_load =
@@ -750,74 +725,56 @@ base::RefCountedMemory* ResourceBundle::LoadLocalizedResourceBytes(
return LoadDataResourceBytes(resource_id);
}
-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::GetFontListWithDelta(int size_delta) {
+ return GetFontListForDetails(FontDetails(std::string(), size_delta));
}
-const gfx::FontList& ResourceBundle::GetFontListWithTypefaceAndDelta(
- const std::string& typeface,
- int size_delta,
- gfx::Font::FontStyle style,
- gfx::Font::Weight weight) {
+const gfx::FontList& ResourceBundle::GetFontListForDetails(
+ const FontDetails& details) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- const FontKey styled_key(typeface, size_delta, style, weight);
-
- auto found = font_cache_.find(styled_key);
+ auto found = font_cache_.find(details);
if (found != font_cache_.end())
return found->second;
- const FontKey base_key(typeface, 0, gfx::Font::NORMAL,
- gfx::Font::Weight::NORMAL);
+ const FontDetails base_details(details.typeface);
gfx::FontList default_font_list = gfx::FontList();
gfx::FontList base_font_list =
- typeface.empty()
+ details.typeface.empty()
? default_font_list
- : gfx::FontList({typeface}, default_font_list.GetFontStyle(),
+ : gfx::FontList({details.typeface}, default_font_list.GetFontStyle(),
default_font_list.GetFontSize(),
default_font_list.GetFontWeight());
- font_cache_.emplace(base_key, base_font_list);
- gfx::FontList& base = font_cache_.find(base_key)->second;
- if (styled_key == base_key)
+ font_cache_.emplace(base_details, base_font_list);
+ gfx::FontList& base = font_cache_.find(base_details)->second;
+ if (details == base_details)
return base;
// Fonts of a given style are derived from the unstyled font of the same size.
// 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(typeface, size_delta, gfx::Font::NORMAL,
- gfx::Font::Weight::NORMAL);
- auto sized = font_cache_.emplace(sized_key, base_font_list);
+ const FontDetails sized_details(details.typeface, details.size_delta);
+ auto sized = font_cache_.emplace(sized_details, base_font_list);
if (sized.second)
- sized.first->second = base.DeriveWithSizeDelta(size_delta);
- if (styled_key == sized_key) {
+ sized.first->second = base.DeriveWithSizeDelta(details.size_delta);
+ if (details == sized_details) {
return sized.first->second;
}
- auto styled = font_cache_.emplace(styled_key, base_font_list);
+ auto styled = font_cache_.emplace(details, 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);
+ 0, sized.first->second.GetFontStyle(), details.weight);
return styled.first->second;
}
-const gfx::Font& ResourceBundle::GetFontWithDelta(int size_delta,
- gfx::Font::FontStyle style,
- gfx::Font::Weight weight) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return GetFontListWithDelta(size_delta, style, weight).GetPrimaryFont();
-}
-
const gfx::FontList& ResourceBundle::GetFontList(FontStyle legacy_style) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- gfx::Font::Weight font_weight = gfx::Font::Weight::NORMAL;
+ gfx::Font::Weight weight = gfx::Font::Weight::NORMAL;
if (legacy_style == BoldFont || legacy_style == MediumBoldFont)
- font_weight = gfx::Font::Weight::BOLD;
+ weight = gfx::Font::Weight::BOLD;
int size_delta = 0;
switch (legacy_style) {
@@ -836,7 +793,7 @@ const gfx::FontList& ResourceBundle::GetFontList(FontStyle legacy_style) {
break;
}
- return GetFontListWithDelta(size_delta, gfx::Font::NORMAL, font_weight);
+ return GetFontListForDetails(FontDetails(std::string(), size_delta, weight));
}
const gfx::Font& ResourceBundle::GetFont(FontStyle style) {
@@ -969,7 +926,7 @@ void ResourceBundle::AddDataPack(std::unique_ptr<DataPack> data_pack) {
}
void ResourceBundle::InitDefaultFontList() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
// InitDefaultFontList() is called earlier than overriding the locale strings.
// So we call the |GetLocalizedStringImpl()| which doesn't set the flag
// |can_override_locale_string_resources_| to false. This is okay, because the
@@ -1097,11 +1054,15 @@ base::string16 ResourceBundle::GetLocalizedStringImpl(int resource_id) const {
// Fall back on the main data pack (shouldn't be any strings here except
// in unittests).
data = GetRawDataResource(resource_id);
+#if defined(OS_FUCHSIA)
+ CHECK(!data.empty());
+#else // !defined(OS_FUCHSIA)
if (data.empty()) {
LOG(WARNING) << "unable to find resource: " << resource_id;
NOTREACHED();
return base::string16();
}
+#endif // !defined(OS_FUCHSIA)
}
}
diff --git a/chromium/ui/base/resource/resource_bundle.h b/chromium/ui/base/resource/resource_bundle.h
index 51dbdfab396..48c329f00c3 100644
--- a/chromium/ui/base/resource/resource_bundle.h
+++ b/chromium/ui/base/resource/resource_bundle.h
@@ -67,6 +67,26 @@ class COMPONENT_EXPORT(UI_BASE) ResourceBundle {
LargeFont,
};
+ struct COMPONENT_EXPORT(UI_BASE) FontDetails {
+ explicit FontDetails(std::string typeface = std::string(),
+ int size_delta = 0,
+ gfx::Font::Weight weight = gfx::Font::Weight::NORMAL);
+ FontDetails(const FontDetails&) = default;
+ FontDetails(FontDetails&&) = default;
+ FontDetails& operator=(const FontDetails&) = default;
+ FontDetails& operator=(FontDetails&&) = default;
+ ~FontDetails() = default;
+
+ bool operator==(const FontDetails& rhs) const;
+ bool operator<(const FontDetails& rhs) const;
+
+ // If typeface is empty, we default to the platform-specific "Base" font
+ // list.
+ std::string typeface;
+ int size_delta;
+ gfx::Font::Weight weight;
+ };
+
enum LoadResources {
LOAD_COMMON_RESOURCES,
DO_NOT_LOAD_COMMON_RESOURCES
@@ -293,26 +313,11 @@ class COMPONENT_EXPORT(UI_BASE) ResourceBundle {
// Returns a font list derived from the platform-specific "Base" font list.
// The result is always cached and exists for the lifetime of the process.
- const gfx::FontList& GetFontListWithDelta(
- int size_delta,
- 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,
- gfx::Font::FontStyle style = gfx::Font::NORMAL,
- gfx::Font::Weight weight = gfx::Font::Weight::NORMAL);
+ const gfx::FontList& GetFontListWithDelta(int size_delta);
+
+ // Returns a font list for the given set of |details|. The result is always
+ // cached and exists for the lifetime of the process.
+ const gfx::FontList& GetFontListForDetails(const FontDetails& details);
// Deprecated. Returns fonts using hard-coded size deltas implied by |style|.
const gfx::FontList& GetFontList(FontStyle style);
@@ -360,6 +365,7 @@ class COMPONENT_EXPORT(UI_BASE) ResourceBundle {
mangle_localized_strings_ = mangle;
}
+ std::string GetLoadedLocaleForTesting() { return loaded_locale_; }
#if DCHECK_IS_ON()
// Gets whether overriding locale strings is supported.
bool get_can_override_locale_string_resources_for_test() {
@@ -380,8 +386,6 @@ class COMPONENT_EXPORT(UI_BASE) ResourceBundle {
class ResourceBundleImageSource;
friend class ResourceBundleImageSource;
- struct FontKey;
-
using IdToStringMap = std::unordered_map<int, base::string16>;
// Ctor/dtor are private, since we're a singleton.
@@ -509,7 +513,7 @@ class COMPONENT_EXPORT(UI_BASE) ResourceBundle {
// platform base font size, plus style, to the FontList. Cached to avoid
// repeated GDI creation/destruction and font derivation.
// Must be accessed only from UI thread.
- std::map<FontKey, gfx::FontList> font_cache_;
+ std::map<FontDetails, gfx::FontList> font_cache_;
base::FilePath overridden_pak_path_;
@@ -522,6 +526,10 @@ class COMPONENT_EXPORT(UI_BASE) ResourceBundle {
bool is_test_resources_ = false;
bool mangle_localized_strings_ = false;
+ // This is currently just used by the testing infrastructure to make sure
+ // the loaded locale_ is en-US at the start of each unit_test.
+ std::string loaded_locale_;
+
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(ResourceBundle);
diff --git a/chromium/ui/base/resource/resource_bundle_android.cc b/chromium/ui/base/resource/resource_bundle_android.cc
index ddb0e045499..bc5d5289dd6 100644
--- a/chromium/ui/base/resource/resource_bundle_android.cc
+++ b/chromium/ui/base/resource/resource_bundle_android.cc
@@ -106,6 +106,8 @@ bool ResourceBundle::LocaleDataPakExists(const std::string& locale) {
}
if (!GetPathForAndroidLocalePakWithinApk(locale, in_split, log_error).empty())
return true;
+
+ // Fall back to checking on disk, which is necessary only for tests.
const auto path = GetLocaleFilePath(locale);
return !path.empty() && base::PathExists(path);
}
@@ -122,9 +124,7 @@ std::string ResourceBundle::LoadLocaleResources(const std::string& pref_locale,
// a) WebView strings, which are always stored uncompressed under
// assets/stored-locales/ inside the APK or App Bundle.
//
- // b) For APKs, the Chrome UI strings are stored under assets/locales/
- // in compressed form. The relevant pak files is extracted on startup
- // and stored on the /data partition, with a version-specific suffix.
+ // b) For APKs, the Chrome UI strings are stored under assets/locales/.
//
// c) For App Bundles, Chrome UI strings are stored uncompressed under
// assets/locales#lang_<lang>/ (where <lang> is an Android language code)
@@ -139,8 +139,7 @@ std::string ResourceBundle::LoadLocaleResources(const std::string& pref_locale,
//
// If false, try to load it from the app bundle specific location
// (e.g. locales#lang_<language>/<locale>.pak). If the latter does not
- // exist, try to lookup the extracted APK-specific locale .pak file
- // from /data/app/.../<locale>.pak@<version> instead.
+ // exist, try to lookup the APK-specific locale .pak file.
//
// g_locale_paks_in_apk is set by SetLocalePaksStoredInApk() which
// is called from the WebView startup code.
@@ -172,7 +171,7 @@ std::string ResourceBundle::LoadLocaleResources(const std::string& pref_locale,
LoadLocalePakFromApk(app_locale, true, &g_locale_pack_region);
}
if (g_locale_pack_fd < 0) {
- // Otherwise, try to locate the extracted locale .pak file.
+ // Otherwise, try to locate the side-loaded locale .pak file (for tests).
if (locale_file_path.empty()) {
auto path = GetLocaleFilePath(app_locale);
if (base::PathExists(path))
diff --git a/chromium/ui/base/resource/resource_bundle_unittest.cc b/chromium/ui/base/resource/resource_bundle_unittest.cc
index bfa3dab5e80..255adcedf3f 100644
--- a/chromium/ui/base/resource/resource_bundle_unittest.cc
+++ b/chromium/ui/base/resource/resource_bundle_unittest.cc
@@ -18,6 +18,7 @@
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -576,7 +577,7 @@ TEST_F(ResourceBundleImageTest, GetImageNamed) {
gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
// ChromeOS/Windows load highest scale factor first.
EXPECT_EQ(ui::SCALE_FACTOR_200P,
GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
diff --git a/chromium/ui/base/resource/resource_bundle_win.cc b/chromium/ui/base/resource/resource_bundle_win.cc
index 1cf3aaffc76..1db7224d9c8 100644
--- a/chromium/ui/base/resource/resource_bundle_win.cc
+++ b/chromium/ui/base/resource/resource_bundle_win.cc
@@ -4,6 +4,8 @@
#include "ui/base/resource/resource_bundle_win.h"
+#include <windows.h>
+
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "skia/ext/image_operations.h"
@@ -50,4 +52,8 @@ HICON LoadThemeIconFromResourcesDataDLL(int icon_id) {
return ::LoadIcon(GetCurrentResourceDLL(), MAKEINTRESOURCE(icon_id));
}
+HCURSOR LoadCursorFromResourcesDataDLL(const wchar_t* cursor_id) {
+ return ::LoadCursor(GetCurrentResourceDLL(), cursor_id);
+}
+
} // namespace ui;
diff --git a/chromium/ui/base/resource/resource_bundle_win.h b/chromium/ui/base/resource/resource_bundle_win.h
index 167f40c1ce3..44956d2244a 100644
--- a/chromium/ui/base/resource/resource_bundle_win.h
+++ b/chromium/ui/base/resource/resource_bundle_win.h
@@ -7,9 +7,8 @@
#include "build/build_config.h"
-#include <windows.h>
-
#include "base/component_export.h"
+#include "base/win/windows_types.h"
namespace ui {
@@ -20,6 +19,10 @@ COMPONENT_EXPORT(UI_BASE) void SetResourcesDataDLL(HINSTANCE handle);
// Loads and returns an icon from the app module.
COMPONENT_EXPORT(UI_BASE) HICON LoadThemeIconFromResourcesDataDLL(int icon_id);
+// Loads and returns a cursor from the app module.
+COMPONENT_EXPORT(UI_BASE)
+HCURSOR LoadCursorFromResourcesDataDLL(const wchar_t* cursor_id);
+
} // namespace ui
#endif // UI_BASE_RESOURCE_RESOURCE_DATA_DLL_WIN_H_
diff --git a/chromium/ui/base/template_expressions.cc b/chromium/ui/base/template_expressions.cc
index 2f6573447c6..34064ebadd1 100644
--- a/chromium/ui/base/template_expressions.cc
+++ b/chromium/ui/base/template_expressions.cc
@@ -12,6 +12,7 @@
#include "base/optional.h"
#include "base/stl_util.h"
#include "base/values.h"
+#include "build/chromeos_buildflags.h"
#include "net/base/escape.h"
#if DCHECK_IS_ON()
@@ -121,7 +122,7 @@ bool EscapeForJS(const std::string& in_string,
bool HasUnexpectedPlaceholder(const std::string& key,
const std::string& replacement) {
// TODO(crbug.com/988031): Fix display aria labels.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
if (key == "displayResolutionText")
return false;
#endif
diff --git a/chromium/ui/base/ui_base_features.cc b/chromium/ui/base/ui_base_features.cc
index 2d856a29782..67570bdd33c 100644
--- a/chromium/ui/base/ui_base_features.cc
+++ b/chromium/ui/base/ui_base_features.cc
@@ -6,6 +6,10 @@
#include "build/chromeos_buildflags.h"
+#if !defined(OS_IOS)
+#include "media/media_buildflags.h" // nogncheck
+#endif
+
#if defined(OS_WIN)
#include "base/win/windows_version.h"
#endif
@@ -20,17 +24,18 @@ namespace features {
// If enabled, calculate native window occlusion - Windows-only.
const base::Feature kCalculateNativeWinOcclusion{
"CalculateNativeWinOcclusion", base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kCalculateNativeWinOcclusionCheckVirtualDesktopUsed{
- "CalculateNativeWinOcclusionCheckVirtualDesktopUsed",
- base::FEATURE_DISABLED_BY_DEFAULT};
#endif // OW_WIN
+// Whether or not filenames are supported on the clipboard.
+// https://crbug.com/1175483
+const base::Feature kClipboardFilenames{"ClipboardFilenames",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Whether or not to delegate color queries to the color provider.
const base::Feature kColorProviderRedirection = {
"ColorProviderRedirection", base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Integrate input method specific settings to Chrome OS settings page.
// https://crbug.com/895886.
const base::Feature kSettingsShowsPerKeyboardSettings = {
@@ -42,9 +47,20 @@ const base::Feature kNewShortcutMapping = {"NewShortcutMapping",
base::FEATURE_DISABLED_BY_DEFAULT};
bool IsNewShortcutMappingEnabled() {
- return base::FeatureList::IsEnabled(kNewShortcutMapping);
+ // kImprovedKeyboardShortcuts supercedes kNewShortcutMapping.
+ return !IsImprovedKeyboardShortcutsEnabled() &&
+ base::FeatureList::IsEnabled(kNewShortcutMapping);
}
-#endif // defined(OS_CHROMEOS)
+
+// This feature supercedes kNewShortcutMapping.
+const base::Feature kImprovedKeyboardShortcuts = {
+ "ImprovedKeyboardShortcuts", base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsImprovedKeyboardShortcutsEnabled() {
+ return base::FeatureList::IsEnabled(kImprovedKeyboardShortcuts);
+}
+
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Update of the virtual keyboard settings UI as described in
// https://crbug.com/876901.
@@ -77,7 +93,8 @@ bool IsNotificationIndicatorEnabled() {
// Enables GPU rasterization for all UI drawing (where not blocklisted).
const base::Feature kUiGpuRasterization = {"UiGpuRasterization",
-#if defined(OS_APPLE) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#if defined(OS_APPLE) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_FUCHSIA) || \
+ BUILDFLAG(IS_CHROMEOS_LACROS)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -108,8 +125,10 @@ const base::Feature kCompositorThreadedScrollbarScrolling = {
// native apps on Windows.
const base::Feature kExperimentalFlingAnimation {
"ExperimentalFlingAnimation",
-#if defined(OS_WIN) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS) && !BUILDFLAG(IS_LACROS))
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_WIN) || (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
+ !BUILDFLAG(IS_CHROMEOS_LACROS))
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -157,7 +176,7 @@ const base::Feature kDirectManipulationStylus = {
// Enables forced colors mode for web content.
const base::Feature kForcedColors{"ForcedColors",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
bool IsForcedColorsEnabled() {
static const bool forced_colors_enabled =
@@ -185,7 +204,14 @@ bool IsEyeDropperEnabled() {
// and Mac. This feature will be released for Android in later milestones. See
// crbug.com/1086530 for the Desktop launch bug.
const base::Feature kCSSColorSchemeUARendering = {
- "CSSColorSchemeUARendering", base::FEATURE_DISABLED_BY_DEFAULT};
+ "CSSColorSchemeUARendering",
+#if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_LINUX) || \
+ defined(OS_APPLE)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
bool IsCSSColorSchemeUARenderingEnabled() {
static const bool css_color_scheme_ua_rendering_enabled =
@@ -220,18 +246,43 @@ bool IsUseCommonSelectPopupEnabled() {
return base::FeatureList::IsEnabled(features::kUseCommonSelectPopup);
}
-#if defined(OS_CHROMEOS)
+// Enables keyboard accessible tooltip.
+const base::Feature kKeyboardAccessibleTooltip{
+ "KeyboardAccessibleTooltip", base::FEATURE_ENABLED_BY_DEFAULT};
+
+bool IsKeyboardAccessibleTooltipEnabled() {
+ static const bool keyboard_accessible_tooltip_enabled =
+ base::FeatureList::IsEnabled(features::kKeyboardAccessibleTooltip);
+ return keyboard_accessible_tooltip_enabled;
+}
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
const base::Feature kHandwritingGesture = {"HandwritingGesture",
base::FEATURE_ENABLED_BY_DEFAULT};
#endif
const base::Feature kSynchronousPageFlipTesting{
- "SynchronousPageFlipTesting", base::FEATURE_DISABLED_BY_DEFAULT};
+ "SynchronousPageFlipTesting",
+#if defined(OS_IOS)
+ base::FEATURE_DISABLED_BY_DEFAULT
+#else
+// We can't combine these directives because BUILDFLAG won't be defined on iOS.
+#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+#endif
+};
bool IsSynchronousPageFlipTestingEnabled() {
return base::FeatureList::IsEnabled(kSynchronousPageFlipTesting);
}
+const base::Feature kResamplingScrollEventsExperimentalPrediction{
+ "ResamplingScrollEventsExperimentalPrediction",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
#if defined(USE_X11) || defined(USE_OZONE)
const base::Feature kUseOzonePlatform {
"UseOzonePlatform",
@@ -247,7 +298,7 @@ bool IsUsingOzonePlatform() {
// Only allow enabling and disabling the OzonePlatform on USE_X11 && USE_OZONE
// builds.
static const bool using_ozone_platform =
-#if defined(USE_X11) && defined(USE_OZONE) && !BUILDFLAG(IS_LACROS)
+#if defined(USE_X11) && defined(USE_OZONE) && !BUILDFLAG(IS_CHROMEOS_LACROS)
base::FeatureList::IsEnabled(kUseOzonePlatform);
#elif defined(USE_X11) && !defined(USE_OZONE)
// This shouldn't be switchable for pure X11 builds.
@@ -271,9 +322,17 @@ const char kPredictorNameEmpty[] = "empty";
const char kFilterNameEmpty[] = "empty_filter";
const char kFilterNameOneEuro[] = "one_euro_filter";
+const char kPredictionTypeTimeBased[] = "time";
+const char kPredictionTypeFramesBased[] = "frames";
+const char kPredictionTypeDefaultTime[] = "3.3";
+const char kPredictionTypeDefaultFramesRatio[] = "0.5";
+
const base::Feature kSwipeToMoveCursor{"SwipeToMoveCursor",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kUIDebugTools{"ui-debug-tools",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
bool IsSwipeToMoveCursorEnabled() {
static const bool enabled =
base::FeatureList::IsEnabled(kSwipeToMoveCursor)
diff --git a/chromium/ui/base/ui_base_features.h b/chromium/ui/base/ui_base_features.h
index 304805ea7f8..c764b047529 100644
--- a/chromium/ui/base/ui_base_features.h
+++ b/chromium/ui/base/ui_base_features.h
@@ -8,6 +8,7 @@
#include "base/component_export.h"
#include "base/feature_list.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/buildflags.h"
namespace features {
@@ -15,15 +16,17 @@ namespace features {
// Keep sorted!
COMPONENT_EXPORT(UI_BASE_FEATURES)
+extern const base::Feature kClipboardFilenames;
+COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kColorProviderRedirection;
COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kCompositorThreadedScrollbarScrolling;
COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kExperimentalFlingAnimation;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kSettingsShowsPerKeyboardSettings;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kInputMethodSettingsUiUpdate;
COMPONENT_EXPORT(UI_BASE_FEATURES)
@@ -47,8 +50,6 @@ COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsUiGpuRasterizationEnabled();
COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kCalculateNativeWinOcclusion;
COMPONENT_EXPORT(UI_BASE_FEATURES)
-extern const base::Feature kCalculateNativeWinOcclusionCheckVirtualDesktopUsed;
-COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kElasticOverscrollWin;
COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kInputPaneOnScreenKeyboard;
@@ -92,7 +93,12 @@ COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kUseCommonSelectPopup;
COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsUseCommonSelectPopupEnabled();
-#if defined(OS_CHROMEOS)
+// Used to enable keyboard accessible tooltips.
+COMPONENT_EXPORT(UI_BASE_FEATURES)
+extern const base::Feature kKeyboardAccessibleTooltip;
+COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsKeyboardAccessibleTooltipEnabled();
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kHandwritingGesture;
@@ -101,6 +107,14 @@ extern const base::Feature kNewShortcutMapping;
COMPONENT_EXPORT(UI_BASE_FEATURES)
bool IsNewShortcutMappingEnabled();
+
+// This flag is intended to supercede kNewShortcutMapping above.
+COMPONENT_EXPORT(UI_BASE_FEATURES)
+extern const base::Feature kImprovedKeyboardShortcuts;
+
+COMPONENT_EXPORT(UI_BASE_FEATURES)
+bool IsImprovedKeyboardShortcutsEnabled();
+
#endif
// Indicates whether DrmOverlayManager should used the synchronous API to
@@ -139,6 +153,23 @@ COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const char kPredictorNameLinearResampling[];
COMPONENT_EXPORT(UI_BASE_FEATURES) extern const char kPredictorNameEmpty[];
+// Enables resampling of scroll events using an experimental latency of +3.3ms
+// instead of the original -5ms.
+COMPONENT_EXPORT(UI_BASE_FEATURES)
+extern const base::Feature kResamplingScrollEventsExperimentalPrediction;
+
+// The type of prediction used. TimeBased uses a fixed timing, FramesBased uses
+// a ratio of the vsync refresh rate. The timing/ratio can be changed on the
+// command line through a `latency` param.
+COMPONENT_EXPORT(UI_BASE_FEATURES) extern const char kPredictionTypeTimeBased[];
+COMPONENT_EXPORT(UI_BASE_FEATURES)
+extern const char kPredictionTypeFramesBased[];
+// The default values for `latency`
+COMPONENT_EXPORT(UI_BASE_FEATURES)
+extern const char kPredictionTypeDefaultTime[];
+COMPONENT_EXPORT(UI_BASE_FEATURES)
+extern const char kPredictionTypeDefaultFramesRatio[];
+
// The type of filter to use for filtering events. These values are used as the
// 'filter' feature param for |blink::features::kFilteringScrollPrediction|.
COMPONENT_EXPORT(UI_BASE_FEATURES) extern const char kFilterNameEmpty[];
@@ -148,6 +179,9 @@ COMPONENT_EXPORT(UI_BASE_FEATURES) extern const char kFilterNameOneEuro[];
COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kSwipeToMoveCursor;
+// Enables UI debugging tools such as shortcuts.
+COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kUIDebugTools;
+
COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsSwipeToMoveCursorEnabled();
} // namespace features
diff --git a/chromium/ui/base/ui_base_switches_util.cc b/chromium/ui/base/ui_base_switches_util.cc
index 353f5332686..1763af36824 100644
--- a/chromium/ui/base/ui_base_switches_util.cc
+++ b/chromium/ui/base/ui_base_switches_util.cc
@@ -6,13 +6,14 @@
#include "base/command_line.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/ui_base_switches.h"
namespace switches {
bool IsTouchDragDropEnabled() {
const auto* const command_line = base::CommandLine::ForCurrentProcess();
-#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID)
return !command_line->HasSwitch(kDisableTouchDragDrop);
#else
return command_line->HasSwitch(kEnableTouchDragDrop);
diff --git a/chromium/ui/base/ui_features.gni b/chromium/ui/base/ui_features.gni
index e5203cd56d3..c664f73e57f 100644
--- a/chromium/ui/base/ui_features.gni
+++ b/chromium/ui/base/ui_features.gni
@@ -8,11 +8,27 @@ declare_args() {
# Optional system library.
use_xkbcommon = use_ozone && (is_linux || is_chromeos) && !is_chromecast
- # Whether the platform provides a native accessibility toolkit.
+ # Whether the platform provides a native accessibility toolkit, in other words
+ # the platform has a C/C++ interface for accessibility that Chrome
+ # implements/subclasses in some way - win, mac, linux.
has_native_accessibility = use_atk || is_win || is_mac
+ # Whether the platform provide platform-specific accessibility implementation,
+ # i.e. there an accessibility API of some kind on this platform that's
+ # implemented in Chrome's browser process, but not necessarily something that
+ # looks like subclassing an interface - so that includes Android (the Java
+ # AccessibilityNodeProvider API) and Fuchsia (uses fidl messaging, kind of
+ # like mojo).
+ has_platform_accessibility_support = false
+
# Whether the message center should be included for displaying notifications.
- enable_message_center = is_win || is_mac || is_linux || is_chromeos || is_fuchsia
+ enable_message_center =
+ is_win || is_mac || is_linux || is_chromeos || is_fuchsia
}
+# Android does have platform accessibility support that's implemented using
+# BrowserAccessibilityManager. But unlike Windows, Mac and Linux it does not use
+# AXPlatformNode to implement a native C++ API, instead it bridges to a Java API.
+has_platform_accessibility_support = has_native_accessibility || is_android
+
enable_hidpi = is_mac || is_win || is_linux || is_chromeos || is_ios
diff --git a/chromium/ui/base/webui/resource_path.h b/chromium/ui/base/webui/resource_path.h
new file mode 100644
index 00000000000..17458938493
--- /dev/null
+++ b/chromium/ui/base/webui/resource_path.h
@@ -0,0 +1,15 @@
+// Copyright 2021 The Chromium 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_WEBUI_RESOURCE_PATH_H_
+#define UI_BASE_WEBUI_RESOURCE_PATH_H_
+
+namespace webui {
+struct ResourcePath {
+ const char* const path;
+ int id;
+};
+} // namespace webui
+
+#endif // UI_BASE_WEBUI_RESOURCE_PATH_H_
diff --git a/chromium/ui/base/webui/web_ui_util.cc b/chromium/ui/base/webui/web_ui_util.cc
index a3fa61f66d8..c6cd6de9ee1 100644
--- a/chromium/ui/base/webui/web_ui_util.cc
+++ b/chromium/ui/base/webui/web_ui_util.cc
@@ -16,6 +16,7 @@
#include "base/strings/string_util.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "net/base/escape.h"
#include "third_party/modp_b64/modp_b64.h"
#include "ui/base/l10n/l10n_util.h"
@@ -221,7 +222,9 @@ void AppendWebUiCssTextDefaults(std::string* html) {
std::string GetFontFamily() {
std::string font_family = l10n_util::GetStringUTF8(IDS_WEB_FONT_FAMILY);
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
std::string font_name = ui::ResourceBundle::GetSharedInstance()
.GetFont(ui::ResourceBundle::BaseFont)
.GetFontName();
diff --git a/chromium/ui/base/win/hwnd_subclass.cc b/chromium/ui/base/win/hwnd_subclass.cc
index 6b35766a9b4..db2dbe756ef 100644
--- a/chromium/ui/base/win/hwnd_subclass.cc
+++ b/chromium/ui/base/win/hwnd_subclass.cc
@@ -7,10 +7,10 @@
#include <algorithm>
#include "base/check.h"
+#include "base/containers/contains.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
-#include "base/stl_util.h"
#include "ui/base/win/touch_input.h"
#include "ui/gfx/win/hwnd_util.h"
diff --git a/chromium/ui/base/win/shell.h b/chromium/ui/base/win/shell.h
index 758c354bb09..7cd212c4de4 100644
--- a/chromium/ui/base/win/shell.h
+++ b/chromium/ui/base/win/shell.h
@@ -45,18 +45,18 @@ COMPONENT_EXPORT(UI_BASE) bool PreventWindowFromPinning(HWND hwnd);
// for the given window. |app_icon_index| should be set to 0 if the app icon
// file only has a single icon.
COMPONENT_EXPORT(UI_BASE)
-void SetAppDetailsForWindow(const base::string16& app_id,
+void SetAppDetailsForWindow(const std::wstring& app_id,
const base::FilePath& app_icon_path,
int app_icon_index,
- const base::string16& relaunch_command,
- const base::string16& relaunch_display_name,
+ const std::wstring& relaunch_command,
+ const std::wstring& relaunch_display_name,
HWND hwnd);
// Sets the application id given as the Application Model ID for the window
// specified. This method is used to insure that different web applications
// do not group together on the Win7 task bar.
COMPONENT_EXPORT(UI_BASE)
-void SetAppIdForWindow(const base::string16& app_id, HWND hwnd);
+void SetAppIdForWindow(const std::wstring& app_id, HWND hwnd);
// Sets the application icon for the window specified.
COMPONENT_EXPORT(UI_BASE)
@@ -68,8 +68,8 @@ void SetAppIconForWindow(const base::FilePath& app_icon_path,
// Windows will use this information for grouping on the taskbar, and to create
// a shortcut if the window is pinned to the taskbar.
COMPONENT_EXPORT(UI_BASE)
-void SetRelaunchDetailsForWindow(const base::string16& relaunch_command,
- const base::string16& display_name,
+void SetRelaunchDetailsForWindow(const std::wstring& relaunch_command,
+ const std::wstring& display_name,
HWND hwnd);
// Clears the Window Property Store on an HWND.
diff --git a/chromium/ui/base/x/BUILD.gn b/chromium/ui/base/x/BUILD.gn
index b1aa641a4fe..12ee24dd707 100644
--- a/chromium/ui/base/x/BUILD.gn
+++ b/chromium/ui/base/x/BUILD.gn
@@ -76,6 +76,7 @@ component("x") {
deps = [
"//base",
"//base:i18n",
+ "//build:chromeos_buildflags",
"//net",
"//skia",
"//ui/base:data_exchange",
@@ -83,10 +84,10 @@ component("x") {
"//ui/base:hit_test",
"//ui/base:wm_role_names",
"//ui/base/clipboard:clipboard_types",
+ "//ui/base/clipboard:file_info",
"//ui/base/cursor:cursor_base",
"//ui/base/cursor:theme_manager",
"//ui/base/cursor/mojom:cursor_type",
- "//ui/base/dragdrop/file_info",
"//ui/display/util",
"//ui/events",
"//ui/events/devices/x11",
diff --git a/chromium/ui/base/x/selection_owner.cc b/chromium/ui/base/x/selection_owner.cc
index 6cbe80cc372..d3da89be763 100644
--- a/chromium/ui/base/x/selection_owner.cc
+++ b/chromium/ui/base/x/selection_owner.cc
@@ -11,8 +11,8 @@
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/platform/x11/x11_event_source.h"
-#include "ui/events/x/x11_window_event_manager.h"
#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
#include "ui/gfx/x/xproto.h"
#include "ui/gfx/x/xproto_util.h"
@@ -39,16 +39,11 @@ const int kIncrementalTransferTimeoutMs = 10000;
static_assert(KSelectionOwnerTimerPeriodMs <= kIncrementalTransferTimeoutMs,
"timer period must be <= transfer timeout");
-// Returns a conservative max size of the data we can pass into
-// XChangeProperty(). Copied from GTK.
-size_t GetMaxRequestSize(x11::Connection* connection) {
- long extended_max_size = connection->extended_max_request_length();
- long max_size =
- (extended_max_size ? extended_max_size
- : connection->setup().maximum_request_length) -
- 100;
- return std::min(static_cast<long>(0x40000),
- std::max(static_cast<long>(0), max_size));
+size_t GetMaxIncrementalTransferSize() {
+ ssize_t size = x11::Connection::Get()->MaxRequestSizeInBytes();
+ // Conservatively subtract 100 bytes for the GetProperty request, padding etc.
+ DCHECK_GT(size, 100);
+ return std::min<size_t>(size - 100, 0x100000);
}
// Gets the value of an atom pair array property. On success, true is returned
@@ -60,7 +55,7 @@ bool GetAtomPairArrayProperty(
std::vector<x11::Atom> atoms;
// Since this is an array of atom pairs, ensure ensure |atoms|
// has an element count that's a multiple of 2.
- if (!ui::GetArrayProperty(window, property, &atoms) || atoms.size() % 2 != 0)
+ if (!GetArrayProperty(window, property, &atoms) || atoms.size() % 2 != 0)
return false;
value->clear();
@@ -85,9 +80,7 @@ void SetSelectionOwner(x11::Window window,
SelectionOwner::SelectionOwner(x11::Connection* connection,
x11::Window x_window,
x11::Atom selection_name)
- : x_window_(x_window),
- selection_name_(selection_name),
- max_request_size_(GetMaxRequestSize(connection)) {}
+ : x_window_(x_window), selection_name_(selection_name) {}
SelectionOwner::~SelectionOwner() {
// If we are the selection owner, we need to release the selection so we
@@ -117,8 +110,8 @@ void SelectionOwner::ClearSelectionOwner() {
format_map_ = SelectionFormatMap();
}
-void SelectionOwner::OnSelectionRequest(const x11::Event& x11_event) {
- auto& request = *x11_event.As<x11::SelectionRequestEvent>();
+void SelectionOwner::OnSelectionRequest(
+ const x11::SelectionRequestEvent& request) {
auto requestor = request.requestor;
x11::Atom requested_target = request.target;
x11::Atom requested_property = request.property;
@@ -133,7 +126,7 @@ void SelectionOwner::OnSelectionRequest(const x11::Event& x11_event) {
.property = x11::Atom::None, // Indicates failure
};
- if (requested_target == gfx::GetAtom(kMultiple)) {
+ if (requested_target == x11::GetAtom(kMultiple)) {
// The contents of |requested_property| should be a list of
// <target,property> pairs.
std::vector<std::pair<x11::Atom, x11::Atom>> conversions;
@@ -149,8 +142,8 @@ void SelectionOwner::OnSelectionRequest(const x11::Event& x11_event) {
// Set the property to indicate which conversions succeeded. This matches
// what GTK does.
- ui::SetArrayProperty(requestor, requested_property,
- gfx::GetAtom(kAtomPair), conversion_results);
+ SetArrayProperty(requestor, requested_property, x11::GetAtom(kAtomPair),
+ conversion_results);
reply.property = requested_property;
}
@@ -163,19 +156,20 @@ void SelectionOwner::OnSelectionRequest(const x11::Event& x11_event) {
x11::SendEvent(reply, requestor, x11::EventMask::NoEvent);
}
-void SelectionOwner::OnSelectionClear(const x11::Event& event) {
- DLOG(ERROR) << "SelectionClear";
+void SelectionOwner::OnSelectionClear(const x11::SelectionClearEvent& event) {
+ DVLOG(1) << "SelectionClear";
// TODO(erg): If we receive a SelectionClear event while we're handling data,
// we need to delay clearing.
}
-bool SelectionOwner::CanDispatchPropertyEvent(const x11::Event& event) {
- return event.As<x11::PropertyNotifyEvent>()->state == x11::Property::Delete &&
+bool SelectionOwner::CanDispatchPropertyEvent(
+ const x11::PropertyNotifyEvent& event) {
+ return event.state == x11::Property::Delete &&
FindIncrementalTransferForEvent(event) != incremental_transfers_.end();
}
-void SelectionOwner::OnPropertyEvent(const x11::Event& event) {
+void SelectionOwner::OnPropertyEvent(const x11::PropertyNotifyEvent& event) {
auto it = FindIncrementalTransferForEvent(event);
if (it == incremental_transfers_.end())
return;
@@ -188,17 +182,17 @@ void SelectionOwner::OnPropertyEvent(const x11::Event& event) {
bool SelectionOwner::ProcessTarget(x11::Atom target,
x11::Window requestor,
x11::Atom property) {
- x11::Atom multiple_atom = gfx::GetAtom(kMultiple);
- x11::Atom save_targets_atom = gfx::GetAtom(kSaveTargets);
- x11::Atom targets_atom = gfx::GetAtom(kTargets);
- x11::Atom timestamp_atom = gfx::GetAtom(kTimestamp);
+ x11::Atom multiple_atom = x11::GetAtom(kMultiple);
+ x11::Atom save_targets_atom = x11::GetAtom(kSaveTargets);
+ x11::Atom targets_atom = x11::GetAtom(kTargets);
+ x11::Atom timestamp_atom = x11::GetAtom(kTimestamp);
if (target == multiple_atom || target == save_targets_atom)
return false;
if (target == timestamp_atom) {
- ui::SetProperty(requestor, property, x11::Atom::INTEGER,
- acquired_selection_timestamp_);
+ SetProperty(requestor, property, x11::Atom::INTEGER,
+ acquired_selection_timestamp_);
return true;
}
@@ -209,19 +203,19 @@ bool SelectionOwner::ProcessTarget(x11::Atom target,
save_targets_atom, multiple_atom};
RetrieveTargets(&targets);
- ui::SetArrayProperty(requestor, property, x11::Atom::ATOM, targets);
+ SetArrayProperty(requestor, property, x11::Atom::ATOM, targets);
return true;
}
// Try to find the data type in map.
auto it = format_map_.find(target);
if (it != format_map_.end()) {
- if (it->second->size() > max_request_size_) {
+ if (it->second->size() > GetMaxIncrementalTransferSize()) {
// We must send the data back in several chunks due to a limitation in
// the size of X requests. Notify the selection requestor that the data
// will be sent incrementally by returning data of type "INCR".
uint32_t length = it->second->size();
- ui::SetProperty(requestor, property, gfx::GetAtom(kIncr), length);
+ SetProperty(requestor, property, x11::GetAtom(kIncr), length);
// Wait for the selection requestor to indicate that it has processed
// the selection result before sending the first chunk of data. The
@@ -231,7 +225,7 @@ bool SelectionOwner::ProcessTarget(x11::Atom target,
base::TimeDelta::FromMilliseconds(kIncrementalTransferTimeoutMs);
incremental_transfers_.emplace_back(
requestor, target, property,
- std::make_unique<XScopedEventSelector>(
+ std::make_unique<x11::XScopedEventSelector>(
requestor, x11::EventMask::PropertyChange),
it->second, 0, timeout);
@@ -247,7 +241,7 @@ bool SelectionOwner::ProcessTarget(x11::Atom target,
} else {
auto& mem = it->second;
std::vector<uint8_t> data(mem->data(), mem->data() + mem->size());
- ui::SetArrayProperty(requestor, property, target, data);
+ SetArrayProperty(requestor, property, target, data);
}
return true;
}
@@ -259,11 +253,10 @@ bool SelectionOwner::ProcessTarget(x11::Atom target,
void SelectionOwner::ProcessIncrementalTransfer(IncrementalTransfer* transfer) {
size_t remaining = transfer->data->size() - transfer->offset;
- size_t chunk_length = std::min(remaining, max_request_size_);
+ size_t chunk_length = std::min(remaining, GetMaxIncrementalTransferSize());
const uint8_t* data = transfer->data->front() + transfer->offset;
std::vector<uint8_t> buf(data, data + chunk_length);
- ui::SetArrayProperty(transfer->window, transfer->property, transfer->target,
- buf);
+ SetArrayProperty(transfer->window, transfer->property, transfer->target, buf);
transfer->offset += chunk_length;
transfer->timeout =
base::TimeTicks::Now() +
@@ -295,11 +288,11 @@ void SelectionOwner::CompleteIncrementalTransfer(
}
std::vector<SelectionOwner::IncrementalTransfer>::iterator
-SelectionOwner::FindIncrementalTransferForEvent(const x11::Event& event) {
+SelectionOwner::FindIncrementalTransferForEvent(
+ const x11::PropertyNotifyEvent& prop) {
for (auto it = incremental_transfers_.begin();
it != incremental_transfers_.end(); ++it) {
- const auto* prop = event.As<x11::PropertyNotifyEvent>();
- if (it->window == prop->window && it->property == prop->atom)
+ if (it->window == prop.window && it->property == prop.atom)
return it;
}
return incremental_transfers_.end();
@@ -309,7 +302,7 @@ SelectionOwner::IncrementalTransfer::IncrementalTransfer(
x11::Window window,
x11::Atom target,
x11::Atom property,
- std::unique_ptr<XScopedEventSelector> event_selector,
+ std::unique_ptr<x11::XScopedEventSelector> event_selector,
const scoped_refptr<base::RefCountedMemory>& data,
int offset,
base::TimeTicks timeout)
diff --git a/chromium/ui/base/x/selection_owner.h b/chromium/ui/base/x/selection_owner.h
index 2d82e43ec31..a6cd6a1f89e 100644
--- a/chromium/ui/base/x/selection_owner.h
+++ b/chromium/ui/base/x/selection_owner.h
@@ -18,9 +18,11 @@
#include "ui/base/x/selection_utils.h"
#include "ui/gfx/x/event.h"
-namespace ui {
-
+namespace x11 {
class XScopedEventSelector;
+}
+
+namespace ui {
COMPONENT_EXPORT(UI_BASE_X) extern const char kIncr[];
COMPONENT_EXPORT(UI_BASE_X) extern const char kSaveTargets[];
@@ -53,25 +55,26 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner {
void ClearSelectionOwner();
// It is our owner's responsibility to plumb X11 events on |xwindow_| to us.
- void OnSelectionRequest(const x11::Event& event);
- void OnSelectionClear(const x11::Event& event);
+ void OnSelectionRequest(const x11::SelectionRequestEvent& event);
+ void OnSelectionClear(const x11::SelectionClearEvent& event);
// Returns true if SelectionOwner can process the XPropertyEvent event,
// |event|.
- bool CanDispatchPropertyEvent(const x11::Event& event);
+ bool CanDispatchPropertyEvent(const x11::PropertyNotifyEvent& event);
- void OnPropertyEvent(const x11::Event& event);
+ void OnPropertyEvent(const x11::PropertyNotifyEvent& event);
private:
// Holds state related to an incremental data transfer.
struct IncrementalTransfer {
- IncrementalTransfer(x11::Window window,
- x11::Atom target,
- x11::Atom property,
- std::unique_ptr<XScopedEventSelector> event_selector,
- const scoped_refptr<base::RefCountedMemory>& data,
- int offset,
- base::TimeTicks timeout);
+ IncrementalTransfer(
+ x11::Window window,
+ x11::Atom target,
+ x11::Atom property,
+ std::unique_ptr<x11::XScopedEventSelector> event_selector,
+ const scoped_refptr<base::RefCountedMemory>& data,
+ int offset,
+ base::TimeTicks timeout);
~IncrementalTransfer();
// Move-only class.
@@ -85,7 +88,7 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner {
x11::Atom property;
// Selects events on |window|.
- std::unique_ptr<XScopedEventSelector> event_selector;
+ std::unique_ptr<x11::XScopedEventSelector> event_selector;
// The data to be transferred.
scoped_refptr<base::RefCountedMemory> data;
@@ -122,7 +125,7 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner {
// Returns the incremental data transfer, if any, which was waiting for
// |event|.
std::vector<IncrementalTransfer>::iterator FindIncrementalTransferForEvent(
- const x11::Event& event);
+ const x11::PropertyNotifyEvent& event);
// Our X11 state.
x11::Window x_window_;
@@ -133,9 +136,6 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner {
// The time that this instance took ownership of its selection.
x11::Time acquired_selection_timestamp_;
- // The maximum size of data we can put in XChangeProperty().
- size_t max_request_size_;
-
// The data we are currently serving.
SelectionFormatMap format_map_;
diff --git a/chromium/ui/base/x/selection_requestor.cc b/chromium/ui/base/x/selection_requestor.cc
index 6e01199f153..6c466d7e8a3 100644
--- a/chromium/ui/base/x/selection_requestor.cc
+++ b/chromium/ui/base/x/selection_requestor.cc
@@ -14,6 +14,7 @@
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_util.h"
namespace ui {
@@ -21,16 +22,9 @@ namespace {
const char kChromeSelection[] = "CHROME_SELECTION";
-// The period of |abort_timer_|. Arbitrary but must be <= than
-// kRequestTimeoutMs.
-const int KSelectionRequestorTimerPeriodMs = 100;
-
// The amount of time to wait for a request to complete before aborting it.
const int kRequestTimeoutMs = 1000;
-static_assert(KSelectionRequestorTimerPeriodMs <= kRequestTimeoutMs,
- "timer period must be <= request timeout");
-
// Combines |data| into a single std::vector<uint8_t>.
std::vector<uint8_t> CombineData(
const std::vector<scoped_refptr<base::RefCountedMemory>>& data) {
@@ -49,12 +43,12 @@ std::vector<uint8_t> CombineData(
} // namespace
SelectionRequestor::SelectionRequestor(x11::Window x_window,
- XEventDispatcher* dispatcher)
+ x11::EventObserver* observer)
: x_window_(x_window),
x_property_(x11::Atom::None),
- dispatcher_(dispatcher),
+ observer_(observer),
current_request_index_(0u) {
- x_property_ = gfx::GetAtom(kChromeSelection);
+ x_property_ = x11::GetAtom(kChromeSelection);
}
SelectionRequestor::~SelectionRequestor() = default;
@@ -81,9 +75,6 @@ bool SelectionRequestor::PerformBlockingConvertSelection(
}
requests_.erase(request_it);
- if (requests_.empty())
- abort_timer_.Stop();
-
if (request.success) {
if (out_data)
*out_data = CombineData(request.out_data);
@@ -97,7 +88,8 @@ void SelectionRequestor::PerformBlockingConvertSelectionWithParameter(
x11::Atom selection,
x11::Atom target,
const std::vector<x11::Atom>& parameter) {
- SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter);
+ SetArrayProperty(x_window_, x11::GetAtom(kChromeSelection), x11::Atom::ATOM,
+ parameter);
PerformBlockingConvertSelection(selection, target, nullptr, nullptr);
}
@@ -125,7 +117,7 @@ void SelectionRequestor::OnSelectionNotify(
request->target != selection.target) {
// ICCCM requires us to delete the property passed into SelectionNotify.
if (event_property != x11::Atom::None)
- ui::DeleteProperty(x_window_, event_property);
+ x11::DeleteProperty(x_window_, event_property);
return;
}
@@ -140,9 +132,9 @@ void SelectionRequestor::OnSelectionNotify(
}
}
if (event_property != x11::Atom::None)
- ui::DeleteProperty(x_window_, event_property);
+ x11::DeleteProperty(x_window_, event_property);
- if (request->out_type == gfx::GetAtom(kIncr)) {
+ if (request->out_type == x11::GetAtom(kIncr)) {
request->data_sent_incrementally = true;
request->out_data.clear();
request->out_type = x11::Atom::None;
@@ -153,13 +145,14 @@ void SelectionRequestor::OnSelectionNotify(
}
}
-bool SelectionRequestor::CanDispatchPropertyEvent(const x11::Event& event) {
- const auto* prop = event.As<x11::PropertyNotifyEvent>();
- return prop->window == x_window_ && prop->atom == x_property_ &&
- prop->state == x11::Property::NewValue;
+bool SelectionRequestor::CanDispatchPropertyEvent(
+ const x11::PropertyNotifyEvent& prop) {
+ return prop.window == x_window_ && prop.atom == x_property_ &&
+ prop.state == x11::Property::NewValue;
}
-void SelectionRequestor::OnPropertyEvent(const x11::Event& event) {
+void SelectionRequestor::OnPropertyEvent(
+ const x11::PropertyNotifyEvent& event) {
Request* request = GetCurrentRequest();
if (!request || !request->data_sent_incrementally)
return;
@@ -182,7 +175,7 @@ void SelectionRequestor::OnPropertyEvent(const x11::Event& event) {
request->out_type = out_type;
// Delete the property to tell the selection owner to send the next chunk.
- ui::DeleteProperty(x_window_, x_property_);
+ x11::DeleteProperty(x_window_, x_property_);
request->timeout = base::TimeTicks::Now() +
base::TimeDelta::FromMilliseconds(kRequestTimeoutMs);
@@ -248,8 +241,8 @@ void SelectionRequestor::BlockTillSelectionNotifyForRequest(Request* request) {
event = x11::Event();
}
} else if (auto* prop = event.As<x11::PropertyNotifyEvent>()) {
- if (CanDispatchPropertyEvent(event)) {
- OnPropertyEvent(event);
+ if (CanDispatchPropertyEvent(*prop)) {
+ OnPropertyEvent(*prop);
event = x11::Event();
}
}
diff --git a/chromium/ui/base/x/selection_requestor.h b/chromium/ui/base/x/selection_requestor.h
index e9a38ceb19c..7770071492d 100644
--- a/chromium/ui/base/x/selection_requestor.h
+++ b/chromium/ui/base/x/selection_requestor.h
@@ -14,12 +14,14 @@
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/time/time.h"
-#include "base/timer/timer.h"
#include "ui/events/platform_event.h"
#include "ui/gfx/x/event.h"
+namespace x11 {
+class EventObserver;
+}
+
namespace ui {
-class XEventDispatcher;
class SelectionData;
// Requests and later receives data from the X11 server through the selection
@@ -31,7 +33,7 @@ class SelectionData;
// implement per-component fast-paths.
class COMPONENT_EXPORT(UI_BASE) SelectionRequestor {
public:
- SelectionRequestor(x11::Window xwindow, XEventDispatcher* dispatcher);
+ SelectionRequestor(x11::Window xwindow, x11::EventObserver* observer);
~SelectionRequestor();
// Does the work of requesting |target| from |selection|, spinning up the
@@ -61,9 +63,9 @@ class COMPONENT_EXPORT(UI_BASE) SelectionRequestor {
// Returns true if SelectionOwner can process the XChangeProperty event,
// |event|.
- bool CanDispatchPropertyEvent(const x11::Event& event);
+ bool CanDispatchPropertyEvent(const x11::PropertyNotifyEvent& event);
- void OnPropertyEvent(const x11::Event& event);
+ void OnPropertyEvent(const x11::PropertyNotifyEvent& event);
private:
friend class SelectionRequestorTest;
@@ -123,12 +125,12 @@ class COMPONENT_EXPORT(UI_BASE) SelectionRequestor {
// the selection.
x11::Atom x_property_;
- // Dispatcher which handles SelectionNotify and SelectionRequest for
+ // Observer which handles SelectionNotify and SelectionRequest for
// |selection_name_|. PerformBlockingConvertSelection() calls the
- // dispatcher directly if PerformBlockingConvertSelection() is called after
+ // observer directly if PerformBlockingConvertSelection() is called after
// the PlatformEventSource is destroyed.
// Not owned.
- XEventDispatcher* dispatcher_;
+ x11::EventObserver* observer_;
// In progress requests. Requests are added to the list at the start of
// PerformBlockingConvertSelection() and are removed and destroyed right
@@ -140,9 +142,6 @@ class COMPONENT_EXPORT(UI_BASE) SelectionRequestor {
// called and for which we are waiting for a SelectionNotify response.
size_t current_request_index_;
- // Used to abort requests if the selection owner takes too long to respond.
- base::RepeatingTimer abort_timer_;
-
DISALLOW_COPY_AND_ASSIGN(SelectionRequestor);
};
diff --git a/chromium/ui/base/x/selection_requestor_unittest.cc b/chromium/ui/base/x/selection_requestor_unittest.cc
index ba68529c289..77deaaa42e5 100644
--- a/chromium/ui/base/x/selection_requestor_unittest.cc
+++ b/chromium/ui/base/x/selection_requestor_unittest.cc
@@ -21,6 +21,7 @@
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_util.h"
namespace ui {
@@ -37,8 +38,8 @@ class SelectionRequestorTest : public testing::Test {
void SendSelectionNotify(x11::Atom selection,
x11::Atom target,
const std::string& value) {
- ui::SetStringProperty(x_window_, requestor_->x_property_,
- gfx::GetAtom("STRING"), value);
+ x11::SetStringProperty(x_window_, requestor_->x_property_,
+ x11::Atom::STRING, value);
requestor_->OnSelectionNotify({
.requestor = x_window_,
@@ -51,7 +52,7 @@ class SelectionRequestorTest : public testing::Test {
protected:
void SetUp() override {
// Create a window for the selection requestor to use.
- x_window_ = CreateDummyWindow();
+ x_window_ = x11::CreateDummyWindow();
event_source_ = PlatformEventSource::CreateDefault();
CHECK(PlatformEventSource::GetInstance());
@@ -93,7 +94,7 @@ void PerformBlockingConvertSelection(SelectionRequestor* requestor,
EXPECT_EQ(expected_data.size(), out_data.size());
EXPECT_EQ(expected_data, ui::RefCountedMemoryToString(
base::RefCountedBytes::TakeVector(&out_data)));
- EXPECT_EQ(gfx::GetAtom("STRING"), out_type);
+ EXPECT_EQ(x11::Atom::STRING, out_type);
}
} // namespace
@@ -105,10 +106,10 @@ TEST_F(SelectionRequestorTest, DISABLED_NestedRequests) {
// Assume that |selection| will have no owner. If there is an owner, the owner
// will set the property passed into the XConvertSelection() request which is
// undesirable.
- x11::Atom selection = gfx::GetAtom("FAKE_SELECTION");
+ x11::Atom selection = x11::GetAtom("FAKE_SELECTION");
- x11::Atom target1 = gfx::GetAtom("TARGET1");
- x11::Atom target2 = gfx::GetAtom("TARGET2");
+ x11::Atom target1 = x11::GetAtom("TARGET1");
+ x11::Atom target2 = x11::GetAtom("TARGET2");
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&PerformBlockingConvertSelection,
diff --git a/chromium/ui/base/x/selection_utils.cc b/chromium/ui/base/x/selection_utils.cc
index 72e02bcd354..155cfc703bd 100644
--- a/chromium/ui/base/x/selection_utils.cc
+++ b/chromium/ui/base/x/selection_utils.cc
@@ -8,9 +8,9 @@
#include <set>
+#include "base/containers/contains.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -21,24 +21,24 @@ namespace ui {
std::vector<x11::Atom> GetTextAtomsFrom() {
std::vector<x11::Atom> atoms;
- atoms.push_back(gfx::GetAtom(kMimeTypeLinuxUtf8String));
- atoms.push_back(gfx::GetAtom(kMimeTypeLinuxString));
- atoms.push_back(gfx::GetAtom(kMimeTypeLinuxText));
- atoms.push_back(gfx::GetAtom(kMimeTypeText));
- atoms.push_back(gfx::GetAtom(kMimeTypeTextUtf8));
+ atoms.push_back(x11::GetAtom(kMimeTypeLinuxUtf8String));
+ atoms.push_back(x11::GetAtom(kMimeTypeLinuxString));
+ atoms.push_back(x11::GetAtom(kMimeTypeLinuxText));
+ atoms.push_back(x11::GetAtom(kMimeTypeText));
+ atoms.push_back(x11::GetAtom(kMimeTypeTextUtf8));
return atoms;
}
std::vector<x11::Atom> GetURLAtomsFrom() {
std::vector<x11::Atom> atoms;
- atoms.push_back(gfx::GetAtom(kMimeTypeURIList));
- atoms.push_back(gfx::GetAtom(kMimeTypeMozillaURL));
+ atoms.push_back(x11::GetAtom(kMimeTypeURIList));
+ atoms.push_back(x11::GetAtom(kMimeTypeMozillaURL));
return atoms;
}
std::vector<x11::Atom> GetURIListAtomsFrom() {
std::vector<x11::Atom> atoms;
- atoms.push_back(gfx::GetAtom(kMimeTypeURIList));
+ atoms.push_back(x11::GetAtom(kMimeTypeURIList));
return atoms;
}
@@ -170,12 +170,12 @@ size_t SelectionData::GetSize() const {
}
std::string SelectionData::GetText() const {
- if (type_ == gfx::GetAtom(kMimeTypeLinuxUtf8String) ||
- type_ == gfx::GetAtom(kMimeTypeLinuxText) ||
- type_ == gfx::GetAtom(kMimeTypeTextUtf8)) {
+ if (type_ == x11::GetAtom(kMimeTypeLinuxUtf8String) ||
+ type_ == x11::GetAtom(kMimeTypeLinuxText) ||
+ type_ == x11::GetAtom(kMimeTypeTextUtf8)) {
return RefCountedMemoryToString(memory_);
- } else if (type_ == gfx::GetAtom(kMimeTypeLinuxString) ||
- type_ == gfx::GetAtom(kMimeTypeText)) {
+ } else if (type_ == x11::GetAtom(kMimeTypeLinuxString) ||
+ type_ == x11::GetAtom(kMimeTypeText)) {
std::string result;
base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_),
base::kCodepageLatin1, &result);
@@ -191,14 +191,14 @@ std::string SelectionData::GetText() const {
base::string16 SelectionData::GetHtml() const {
base::string16 markup;
- if (type_ == gfx::GetAtom(kMimeTypeHTML)) {
+ if (type_ == x11::GetAtom(kMimeTypeHTML)) {
const unsigned char* data = GetData();
size_t size = GetSize();
// If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is
// UTF-16, otherwise assume UTF-8.
- if (size >= 2 && reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) {
- markup.assign(reinterpret_cast<const uint16_t*>(data) + 1,
+ if (size >= 2 && reinterpret_cast<const base::char16*>(data)[0] == 0xFEFF) {
+ markup.assign(reinterpret_cast<const base::char16*>(data) + 1,
(size / 2) - 1);
} else {
base::UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup);
diff --git a/chromium/ui/base/x/x11_cursor.cc b/chromium/ui/base/x/x11_cursor.cc
index c483bd7f798..0b9d548d8b8 100644
--- a/chromium/ui/base/x/x11_cursor.cc
+++ b/chromium/ui/base/x/x11_cursor.cc
@@ -6,6 +6,7 @@
#include "ui/base/x/x11_cursor_loader.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/xproto.h"
namespace ui {
diff --git a/chromium/ui/base/x/x11_cursor.h b/chromium/ui/base/x/x11_cursor.h
index dba2dbe88e8..bf5966298ed 100644
--- a/chromium/ui/base/x/x11_cursor.h
+++ b/chromium/ui/base/x/x11_cursor.h
@@ -7,6 +7,7 @@
#include <vector>
+#include "base/callback.h"
#include "base/component_export.h"
#include "base/memory/ref_counted.h"
#include "ui/gfx/x/xproto.h"
diff --git a/chromium/ui/base/x/x11_cursor_factory.cc b/chromium/ui/base/x/x11_cursor_factory.cc
index bfd662b201a..b7557703714 100644
--- a/chromium/ui/base/x/x11_cursor_factory.cc
+++ b/chromium/ui/base/x/x11_cursor_factory.cc
@@ -30,119 +30,6 @@ scoped_refptr<X11Cursor> CreateInvisibleCursor(XCursorLoader* cursor_loader) {
return cursor_loader->CreateCursor(bitmap, gfx::Point(0, 0));
}
-// Returns a cursor name, compatible with either X11 or the FreeDesktop.org
-// cursor spec
-// (https://www.x.org/releases/current/doc/libX11/libX11/libX11.html#x_font_cursors
-// and https://www.freedesktop.org/wiki/Specifications/cursor-spec/), followed
-// by fallbacks that can work as replacements in some environments where the
-// original may not be available (e.g. desktop environments other than
-// GNOME and KDE).
-// TODO(hferreiro): each list starts with the FreeDesktop.org icon name but
-// "ns-resize", "ew-resize", "nesw-resize", "nwse-resize", "grab", "grabbing",
-// which were not available in older versions of Breeze, the default KDE theme.
-std::vector<std::string> CursorNamesFromType(mojom::CursorType type) {
- switch (type) {
- case mojom::CursorType::kMove:
- // Returning "move" is the correct thing here, but Blink doesn't make a
- // distinction between move and all-scroll. Other platforms use a cursor
- // more consistent with all-scroll, so use that.
- case mojom::CursorType::kMiddlePanning:
- case mojom::CursorType::kMiddlePanningVertical:
- case mojom::CursorType::kMiddlePanningHorizontal:
- return {"all-scroll", "fleur"};
- case mojom::CursorType::kEastPanning:
- case mojom::CursorType::kEastResize:
- return {"e-resize", "right_side"};
- case mojom::CursorType::kNorthPanning:
- case mojom::CursorType::kNorthResize:
- return {"n-resize", "top_side"};
- case mojom::CursorType::kNorthEastPanning:
- case mojom::CursorType::kNorthEastResize:
- return {"ne-resize", "top_right_corner"};
- case mojom::CursorType::kNorthWestPanning:
- case mojom::CursorType::kNorthWestResize:
- return {"nw-resize", "top_left_corner"};
- case mojom::CursorType::kSouthPanning:
- case mojom::CursorType::kSouthResize:
- return {"s-resize", "bottom_side"};
- case mojom::CursorType::kSouthEastPanning:
- case mojom::CursorType::kSouthEastResize:
- return {"se-resize", "bottom_right_corner"};
- case mojom::CursorType::kSouthWestPanning:
- case mojom::CursorType::kSouthWestResize:
- return {"sw-resize", "bottom_left_corner"};
- case mojom::CursorType::kWestPanning:
- case mojom::CursorType::kWestResize:
- return {"w-resize", "left_side"};
- case mojom::CursorType::kNone:
- return {"none"};
- case mojom::CursorType::kGrab:
- return {"openhand", "grab"};
- case mojom::CursorType::kGrabbing:
- return {"closedhand", "grabbing", "hand2"};
- case mojom::CursorType::kCross:
- return {"crosshair", "cross"};
- case mojom::CursorType::kHand:
- return {"pointer", "hand", "hand2"};
- case mojom::CursorType::kIBeam:
- return {"text", "xterm"};
- case mojom::CursorType::kProgress:
- return {"progress", "left_ptr_watch", "watch"};
- case mojom::CursorType::kWait:
- return {"wait", "watch"};
- case mojom::CursorType::kHelp:
- return {"help"};
- case mojom::CursorType::kNorthSouthResize:
- return {"sb_v_double_arrow", "ns-resize"};
- case mojom::CursorType::kEastWestResize:
- return {"sb_h_double_arrow", "ew-resize"};
- case mojom::CursorType::kColumnResize:
- return {"col-resize", "sb_h_double_arrow"};
- case mojom::CursorType::kRowResize:
- return {"row-resize", "sb_v_double_arrow"};
- case mojom::CursorType::kNorthEastSouthWestResize:
- return {"size_bdiag", "nesw-resize", "fd_double_arrow"};
- case mojom::CursorType::kNorthWestSouthEastResize:
- return {"size_fdiag", "nwse-resize", "bd_double_arrow"};
- case mojom::CursorType::kVerticalText:
- return {"vertical-text"};
- case mojom::CursorType::kZoomIn:
- return {"zoom-in"};
- case mojom::CursorType::kZoomOut:
- return {"zoom-out"};
- case mojom::CursorType::kCell:
- return {"cell", "plus"};
- case mojom::CursorType::kContextMenu:
- return {"context-menu"};
- case mojom::CursorType::kAlias:
- return {"alias"};
- case mojom::CursorType::kNoDrop:
- return {"no-drop"};
- case mojom::CursorType::kCopy:
- return {"copy"};
- case mojom::CursorType::kNotAllowed:
- return {"not-allowed", "crossed_circle"};
- case mojom::CursorType::kDndNone:
- return {"dnd-none", "hand2"};
- case mojom::CursorType::kDndMove:
- return {"dnd-move", "hand2"};
- case mojom::CursorType::kDndCopy:
- return {"dnd-copy", "hand2"};
- case mojom::CursorType::kDndLink:
- return {"dnd-link", "hand2"};
- case mojom::CursorType::kCustom:
- // kCustom is for custom image cursors. The platform cursor will be set
- // at WebCursor::GetPlatformCursor().
- NOTREACHED();
- FALLTHROUGH;
- case mojom::CursorType::kNull:
- case mojom::CursorType::kPointer:
- return {"left_ptr"};
- }
- NOTREACHED();
- return {"left_ptr"};
-}
-
} // namespace
X11CursorFactory::X11CursorFactory()
@@ -205,7 +92,7 @@ void X11CursorFactory::UnrefImageCursor(PlatformCursor cursor) {
void X11CursorFactory::ObserveThemeChanges() {
auto* cursor_theme_manager = CursorThemeManager::GetInstance();
DCHECK(cursor_theme_manager);
- cursor_theme_observer_.Add(cursor_theme_manager);
+ cursor_theme_observation_.Observe(cursor_theme_manager);
}
void X11CursorFactory::OnCursorThemeNameChanged(
diff --git a/chromium/ui/base/x/x11_cursor_factory.h b/chromium/ui/base/x/x11_cursor_factory.h
index ab4d55b233a..9a9ae76b190 100644
--- a/chromium/ui/base/x/x11_cursor_factory.h
+++ b/chromium/ui/base/x/x11_cursor_factory.h
@@ -11,7 +11,7 @@
#include "base/component_export.h"
#include "base/memory/scoped_refptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/cursor/cursor_theme_manager.h"
#include "ui/base/cursor/cursor_theme_manager_observer.h"
@@ -63,8 +63,8 @@ class COMPONENT_EXPORT(UI_BASE_X) X11CursorFactory
std::map<mojom::CursorType, scoped_refptr<X11Cursor>> default_cursors_;
- ScopedObserver<CursorThemeManager, CursorThemeManagerObserver>
- cursor_theme_observer_{this};
+ base::ScopedObservation<CursorThemeManager, CursorThemeManagerObserver>
+ cursor_theme_observation_{this};
};
} // namespace ui
diff --git a/chromium/ui/base/x/x11_cursor_loader.cc b/chromium/ui/base/x/x11_cursor_loader.cc
index afce41bb1ea..e218771aa33 100644
--- a/chromium/ui/base/x/x11_cursor_loader.cc
+++ b/chromium/ui/base/x/x11_cursor_loader.cc
@@ -20,6 +20,7 @@
#include "base/sequence_checker.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece_forward.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/sys_byteorder.h"
@@ -30,7 +31,9 @@
#include "ui/base/cursor/cursor_theme_manager.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_util.h"
extern "C" {
const char* XcursorLibraryPath(void);
@@ -290,14 +293,15 @@ XCursorLoader::XCursorLoader(x11::Connection* connection)
: connection_(connection) {
auto ver_cookie = connection_->render().QueryVersion(
{x11::Render::major_version, x11::Render::minor_version});
- auto pf_cookie = connection_->render().QueryPictFormats({});
+ auto pf_cookie = connection_->render().QueryPictFormats();
cursor_font_ = connection_->GenerateId<x11::Font>();
connection_->OpenFont({cursor_font_, "cursor"});
- std::string resource_manager;
- if (ui::GetStringProperty(connection_->default_root(), "RESOURCE_MANAGER",
- &resource_manager)) {
- ParseXResources(resource_manager);
+ std::vector<char> resource_manager;
+ if (GetArrayProperty(connection_->default_root(), x11::Atom::RESOURCE_MANAGER,
+ &resource_manager)) {
+ ParseXResources(
+ base::StringPiece(resource_manager.data(), resource_manager.size()));
}
if (auto reply = ver_cookie.Sync()) {
@@ -454,7 +458,7 @@ uint32_t XCursorLoader::GetPreferredCursorSize() const {
kScreenCursorRatio;
}
-void XCursorLoader::ParseXResources(const std::string& resources) {
+void XCursorLoader::ParseXResources(base::StringPiece resources) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::StringPairs pairs;
base::SplitStringIntoKeyValuePairs(resources, ':', '\n', &pairs);
diff --git a/chromium/ui/base/x/x11_cursor_loader.h b/chromium/ui/base/x/x11_cursor_loader.h
index 851f5245a90..3f7bbb6b050 100644
--- a/chromium/ui/base/x/x11_cursor_loader.h
+++ b/chromium/ui/base/x/x11_cursor_loader.h
@@ -55,7 +55,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XCursorLoader {
// Populate the |rm_*| variables from the value of the RESOURCE_MANAGER
// property on the root window.
- void ParseXResources(const std::string& resources);
+ void ParseXResources(base::StringPiece resources);
uint16_t CursorNamesToChar(const std::vector<std::string>& names) const;
diff --git a/chromium/ui/base/x/x11_display_manager.cc b/chromium/ui/base/x/x11_display_manager.cc
index 170aeb8b914..1e52983bb35 100644
--- a/chromium/ui/base/x/x11_display_manager.cc
+++ b/chromium/ui/base/x/x11_display_manager.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/base/x/x11_display_util.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/randr.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
@@ -61,15 +62,12 @@ void XDisplayManager::RemoveObserver(display::DisplayObserver* observer) {
change_notifier_.RemoveObserver(observer);
}
-bool XDisplayManager::ProcessEvent(x11::Event* xev) {
- DCHECK(xev);
- auto* prop = xev->As<x11::PropertyNotifyEvent>();
- if (xev->As<x11::RandR::NotifyEvent>() ||
- (prop && prop->atom == gfx::GetAtom("_NET_WORKAREA"))) {
+void XDisplayManager::OnEvent(const x11::Event& xev) {
+ auto* prop = xev.As<x11::PropertyNotifyEvent>();
+ if (xev.As<x11::RandR::NotifyEvent>() ||
+ (prop && prop->atom == x11::GetAtom("_NET_WORKAREA"))) {
DispatchDelayedDisplayListUpdate();
- return true;
}
- return false;
}
void XDisplayManager::SetDisplayList(std::vector<display::Display> displays) {
diff --git a/chromium/ui/base/x/x11_display_manager.h b/chromium/ui/base/x/x11_display_manager.h
index 069ec82c926..f21c200646d 100644
--- a/chromium/ui/base/x/x11_display_manager.h
+++ b/chromium/ui/base/x/x11_display_manager.h
@@ -47,7 +47,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XDisplayManager
void Init();
bool IsXrandrAvailable() const;
- bool ProcessEvent(x11::Event* xev);
+ void OnEvent(const x11::Event& xev);
void UpdateDisplayList();
void DispatchDelayedDisplayListUpdate();
display::Display GetPrimaryDisplay() const;
diff --git a/chromium/ui/base/x/x11_display_util.cc b/chromium/ui/base/x/x11_display_util.cc
index f5d93cffb3d..ac0501960d6 100644
--- a/chromium/ui/base/x/x11_display_util.cc
+++ b/chromium/ui/base/x/x11_display_util.cc
@@ -20,6 +20,7 @@
#include "ui/gfx/geometry/vector3d_f.h"
#include "ui/gfx/x/randr.h"
#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/xproto_util.h"
namespace ui {
@@ -52,8 +53,8 @@ void ClipWorkArea(std::vector<display::Display>* displays,
float scale) {
x11::Window x_root_window = ui::GetX11RootWindow();
- std::vector<int> value;
- if (!ui::GetIntArrayProperty(x_root_window, "_NET_WORKAREA", &value) ||
+ std::vector<int32_t> value;
+ if (!GetArrayProperty(x_root_window, x11::GetAtom("_NET_WORKAREA"), &value) ||
value.size() < 4) {
return;
}
@@ -139,7 +140,7 @@ std::vector<uint8_t> GetEDIDProperty(x11::RandR* randr,
x11::RandR::Output output) {
auto future = randr->GetOutputProperty(x11::RandR::GetOutputPropertyRequest{
.output = output,
- .property = gfx::GetAtom(kRandrEdidProperty),
+ .property = x11::GetAtom(kRandrEdidProperty),
.long_length = 128});
auto response = future.Sync();
std::vector<uint8_t> edid;
diff --git a/chromium/ui/base/x/x11_drag_context.cc b/chromium/ui/base/x/x11_drag_context.cc
index 32cbb35a503..b42333c8e13 100644
--- a/chromium/ui/base/x/x11_drag_context.cc
+++ b/chromium/ui/base/x/x11_drag_context.cc
@@ -13,6 +13,7 @@
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_util.h"
namespace ui {
@@ -51,8 +52,8 @@ XDragContext::XDragContext(x11::Window local_window,
bool get_types_from_property = ((event.data.data32[1] & 1) != 0);
if (get_types_from_property) {
- if (!GetAtomArrayProperty(source_window_, kXdndTypeList,
- &unfetched_targets_)) {
+ if (!GetArrayProperty(source_window_, x11::GetAtom(kXdndTypeList),
+ &unfetched_targets_)) {
return;
}
} else {
@@ -118,8 +119,8 @@ void XDragContext::RequestNextTarget() {
unfetched_targets_.pop_back();
x11::Connection::Get()->ConvertSelection(
- {local_window_, gfx::GetAtom(kXdndSelection), target,
- gfx::GetAtom(kChromiumDragReciever), position_time_stamp_});
+ {local_window_, x11::GetAtom(kXdndSelection), target,
+ x11::GetAtom(kChromiumDragReciever), position_time_stamp_});
}
void XDragContext::OnSelectionNotify(const x11::SelectionNotifyEvent& event) {
@@ -136,7 +137,7 @@ void XDragContext::OnSelectionNotify(const x11::SelectionNotifyEvent& event) {
auto target = static_cast<x11::Atom>(event.target);
if (event.property != x11::Atom::None) {
- DCHECK_EQ(property, gfx::GetAtom(kChromiumDragReciever));
+ DCHECK_EQ(property, x11::GetAtom(kChromiumDragReciever));
scoped_refptr<base::RefCountedMemory> data;
x11::Atom type = x11::Atom::None;
@@ -164,10 +165,12 @@ void XDragContext::ReadActions() {
XDragDropClient::GetForWindow(source_window_);
if (!source_client) {
std::vector<x11::Atom> atom_array;
- if (!GetAtomArrayProperty(source_window_, kXdndActionList, &atom_array))
+ if (!GetArrayProperty(source_window_, x11::GetAtom(kXdndActionList),
+ &atom_array)) {
actions_.clear();
- else
+ } else {
actions_.swap(atom_array);
+ }
} else {
// We have a property notify set up for other windows in case they change
// their action list. Thankfully, the views interface is static and you
@@ -188,17 +191,17 @@ int XDragContext::GetDragOperation() const {
void XDragContext::MaskOperation(x11::Atom xdnd_operation,
int* drag_operation) const {
- if (xdnd_operation == gfx::GetAtom(kXdndActionCopy))
+ if (xdnd_operation == x11::GetAtom(kXdndActionCopy))
*drag_operation |= DragDropTypes::DRAG_COPY;
- else if (xdnd_operation == gfx::GetAtom(kXdndActionMove))
+ else if (xdnd_operation == x11::GetAtom(kXdndActionMove))
*drag_operation |= DragDropTypes::DRAG_MOVE;
- else if (xdnd_operation == gfx::GetAtom(kXdndActionLink))
+ else if (xdnd_operation == x11::GetAtom(kXdndActionLink))
*drag_operation |= DragDropTypes::DRAG_LINK;
}
bool XDragContext::DispatchPropertyNotifyEvent(
const x11::PropertyNotifyEvent& prop) {
- if (prop.atom == gfx::GetAtom(kXdndActionList)) {
+ if (prop.atom == x11::GetAtom(kXdndActionList)) {
ReadActions();
return true;
}
diff --git a/chromium/ui/base/x/x11_drag_context.h b/chromium/ui/base/x/x11_drag_context.h
index 5e9a2ca6a39..ae7cacc1b78 100644
--- a/chromium/ui/base/x/x11_drag_context.h
+++ b/chromium/ui/base/x/x11_drag_context.h
@@ -10,7 +10,6 @@
#include "base/component_export.h"
#include "ui/base/x/selection_utils.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/xproto.h"
diff --git a/chromium/ui/base/x/x11_drag_drop_client.cc b/chromium/ui/base/x/x11_drag_drop_client.cc
index 2fa606f94c2..b394e9ec887 100644
--- a/chromium/ui/base/x/x11_drag_drop_client.cc
+++ b/chromium/ui/base/x/x11_drag_drop_client.cc
@@ -123,22 +123,22 @@ static base::LazyInstance<std::map<x11::Window, XDragDropClient*>>::Leaky
// we're most likely to take on drop.
x11::Atom XDragOperationToAtom(int drag_operation) {
if (drag_operation & DragDropTypes::DRAG_COPY)
- return gfx::GetAtom(kXdndActionCopy);
+ return x11::GetAtom(kXdndActionCopy);
if (drag_operation & DragDropTypes::DRAG_MOVE)
- return gfx::GetAtom(kXdndActionMove);
+ return x11::GetAtom(kXdndActionMove);
if (drag_operation & DragDropTypes::DRAG_LINK)
- return gfx::GetAtom(kXdndActionLink);
+ return x11::GetAtom(kXdndActionLink);
return x11::Atom::None;
}
// Converts a single action atom to a drag operation.
DragDropTypes::DragOperation AtomToDragOperation(x11::Atom atom) {
- if (atom == gfx::GetAtom(kXdndActionCopy))
+ if (atom == x11::GetAtom(kXdndActionCopy))
return DragDropTypes::DRAG_COPY;
- if (atom == gfx::GetAtom(kXdndActionMove))
+ if (atom == x11::GetAtom(kXdndActionMove))
return DragDropTypes::DRAG_MOVE;
- if (atom == gfx::GetAtom(kXdndActionLink))
+ if (atom == x11::GetAtom(kXdndActionLink))
return DragDropTypes::DRAG_LINK;
return DragDropTypes::DRAG_NONE;
@@ -188,8 +188,8 @@ XDragDropClient::XDragDropClient(XDragDropClient::Delegate* delegate,
// Mark that we are aware of drag and drop concepts.
uint32_t xdnd_version = kMaxXdndVersion;
- ui::SetProperty(xwindow_, gfx::GetAtom(kXdndAware), x11::Atom::ATOM,
- xdnd_version);
+ SetProperty(xwindow_, x11::GetAtom(kXdndAware), x11::Atom::ATOM,
+ xdnd_version);
// Some tests change the DesktopDragDropClientAuraX11 associated with an
// |xwindow|.
@@ -203,11 +203,11 @@ XDragDropClient::~XDragDropClient() {
std::vector<x11::Atom> XDragDropClient::GetOfferedDragOperations() const {
std::vector<x11::Atom> operations;
if (drag_operation_ & DragDropTypes::DRAG_COPY)
- operations.push_back(gfx::GetAtom(kXdndActionCopy));
+ operations.push_back(x11::GetAtom(kXdndActionCopy));
if (drag_operation_ & DragDropTypes::DRAG_MOVE)
- operations.push_back(gfx::GetAtom(kXdndActionMove));
+ operations.push_back(x11::GetAtom(kXdndActionMove));
if (drag_operation_ & DragDropTypes::DRAG_LINK)
- operations.push_back(gfx::GetAtom(kXdndActionLink));
+ operations.push_back(x11::GetAtom(kXdndActionLink));
return operations;
}
@@ -267,17 +267,17 @@ void XDragDropClient::ProcessMouseMove(const gfx::Point& screen_point,
bool XDragDropClient::HandleXdndEvent(const x11::ClientMessageEvent& event) {
x11::Atom message_type = event.type;
- if (message_type == gfx::GetAtom("XdndEnter"))
+ if (message_type == x11::GetAtom("XdndEnter"))
OnXdndEnter(event);
- else if (message_type == gfx::GetAtom("XdndLeave"))
+ else if (message_type == x11::GetAtom("XdndLeave"))
OnXdndLeave(event);
- else if (message_type == gfx::GetAtom("XdndPosition"))
+ else if (message_type == x11::GetAtom("XdndPosition"))
OnXdndPosition(event);
- else if (message_type == gfx::GetAtom("XdndStatus"))
+ else if (message_type == x11::GetAtom("XdndStatus"))
OnXdndStatus(event);
- else if (message_type == gfx::GetAtom("XdndFinished"))
+ else if (message_type == x11::GetAtom("XdndFinished"))
OnXdndFinished(event);
- else if (message_type == gfx::GetAtom("XdndDrop"))
+ else if (message_type == x11::GetAtom("XdndDrop"))
OnXdndDrop(event);
else
return false;
@@ -443,7 +443,7 @@ void XDragDropClient::OnSelectionNotify(
// ICCCM requires us to delete the property passed into SelectionNotify.
if (xselection.property != x11::Atom::None)
- ui::DeleteProperty(xwindow_, xselection.property);
+ x11::DeleteProperty(xwindow_, xselection.property);
}
void XDragDropClient::InitDrag(int operation, const OSExchangeData* data) {
@@ -461,18 +461,19 @@ void XDragDropClient::InitDrag(int operation, const OSExchangeData* data) {
std::vector<x11::Atom> actions = GetOfferedDragOperations();
if (!source_provider_->file_contents_name().empty()) {
- actions.push_back(gfx::GetAtom(kXdndActionDirectSave));
- SetStringProperty(xwindow_, gfx::GetAtom(kXdndDirectSave0),
- gfx::GetAtom(kMimeTypeText),
+ actions.push_back(x11::GetAtom(kXdndActionDirectSave));
+ SetStringProperty(xwindow_, x11::GetAtom(kXdndDirectSave0),
+ x11::GetAtom(kMimeTypeText),
source_provider_->file_contents_name().AsUTF8Unsafe());
}
- SetAtomArrayProperty(xwindow_, kXdndActionList, "ATOM", actions);
+ SetArrayProperty(xwindow_, x11::GetAtom(kXdndActionList), x11::Atom::ATOM,
+ actions);
}
void XDragDropClient::CleanupDrag() {
source_provider_ = nullptr;
- ui::DeleteProperty(xwindow_, gfx::GetAtom(kXdndActionList));
- ui::DeleteProperty(xwindow_, gfx::GetAtom(kXdndDirectSave0));
+ x11::DeleteProperty(xwindow_, x11::GetAtom(kXdndActionList));
+ x11::DeleteProperty(xwindow_, x11::GetAtom(kXdndDirectSave0));
}
void XDragDropClient::UpdateModifierState(int flags) {
@@ -578,7 +579,7 @@ x11::ClientMessageEvent XDragDropClient::PrepareXdndClientMessage(
const char* message,
x11::Window recipient) const {
x11::ClientMessageEvent xev;
- xev.type = gfx::GetAtom(message);
+ xev.type = x11::GetAtom(message);
xev.window = recipient;
xev.format = 32;
xev.data.data32.fill(0);
@@ -600,10 +601,10 @@ x11::Window XDragDropClient::FindWindowFor(const gfx::Point& screen_point) {
// Figure out which window we should test as XdndAware. If |target| has
// XdndProxy, it will set that proxy on target, and if not, |target|'s
// original value will remain.
- GetProperty(target, gfx::GetAtom(kXdndProxy), &target);
+ GetProperty(target, x11::GetAtom(kXdndProxy), &target);
- int version;
- if (GetIntProperty(target, kXdndAware, &version) &&
+ uint32_t version;
+ if (GetProperty(target, x11::GetAtom(kXdndAware), &version) &&
version >= kMaxXdndVersion) {
return target;
}
@@ -636,7 +637,8 @@ void XDragDropClient::SendXdndEnter(x11::Window dest_window,
if (targets.size() > 3) {
xev.data.data32[1] |= 1;
- SetAtomArrayProperty(xwindow(), kXdndTypeList, "ATOM", targets);
+ SetArrayProperty(xwindow(), x11::GetAtom(kXdndTypeList), x11::Atom::ATOM,
+ targets);
} else {
// Pack the targets into the enter message.
for (size_t i = 0; i < targets.size(); ++i)
diff --git a/chromium/ui/base/x/x11_gl_egl_utility.cc b/chromium/ui/base/x/x11_gl_egl_utility.cc
index b921f6291c7..bf92de82142 100644
--- a/chromium/ui/base/x/x11_gl_egl_utility.cc
+++ b/chromium/ui/base/x/x11_gl_egl_utility.cc
@@ -39,7 +39,7 @@ void GetPlatformExtraDisplayAttribs(EGLenum platform_type,
// get it anyway.
if (platform_type != EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE) {
x11::VisualId visual_id;
- ui::XVisualManager::GetInstance()->ChooseVisualForWindow(
+ XVisualManager::GetInstance()->ChooseVisualForWindow(
true, &visual_id, nullptr, nullptr, nullptr);
attributes->push_back(EGL_X11_VISUAL_ID_ANGLE);
attributes->push_back(static_cast<EGLAttrib>(visual_id));
@@ -54,8 +54,8 @@ void ChoosePlatformCustomAlphaAndBufferSize(EGLint* alpha_size,
// can't use XVisualManager.
if (gl::GLSurfaceEGL::GetNativeDisplay() != EGL_DEFAULT_DISPLAY) {
uint8_t depth;
- ui::XVisualManager::GetInstance()->ChooseVisualForWindow(
- true, nullptr, &depth, nullptr, nullptr);
+ XVisualManager::GetInstance()->ChooseVisualForWindow(true, nullptr, &depth,
+ nullptr, nullptr);
*buffer_size = depth;
*alpha_size = *buffer_size == 32 ? 8 : 0;
}
@@ -65,4 +65,11 @@ bool IsTransparentBackgroundSupported() {
return ui::XVisualManager::GetInstance()->ArgbVisualAvailable();
}
+bool UpdateVisualsOnGpuInfoChanged(bool software_rendering,
+ x11::VisualId default_visual_id,
+ x11::VisualId transparent_visual_id) {
+ return XVisualManager::GetInstance()->UpdateVisualsOnGpuInfoChanged(
+ software_rendering, default_visual_id, transparent_visual_id);
+}
+
} // namespace ui
diff --git a/chromium/ui/base/x/x11_gl_egl_utility.h b/chromium/ui/base/x/x11_gl_egl_utility.h
index 8f559f28e28..fd33bbbe842 100644
--- a/chromium/ui/base/x/x11_gl_egl_utility.h
+++ b/chromium/ui/base/x/x11_gl_egl_utility.h
@@ -8,6 +8,7 @@
#include <vector>
#include "third_party/khronos/EGL/egl.h"
+#include "ui/gfx/x/xproto.h"
namespace ui {
@@ -22,6 +23,12 @@ void ChoosePlatformCustomAlphaAndBufferSize(EGLint* alpha_size,
// Returns whether transparent background is suppored.
bool IsTransparentBackgroundSupported();
+// Wraps XVisualManager::UpdateVisualsOnGpuInfoChanged(), passes parameters to
+// it directly. Returns whether provided visuals are valid.
+bool UpdateVisualsOnGpuInfoChanged(bool software_rendering,
+ x11::VisualId default_visual_id,
+ x11::VisualId transparent_visual_id);
+
} // namespace ui
#endif // UI_BASE_X_X11_GL_EGL_UTILITY_H_
diff --git a/chromium/ui/base/x/x11_idle_query.cc b/chromium/ui/base/x/x11_idle_query.cc
index c880e49080f..0bda0a4bd60 100644
--- a/chromium/ui/base/x/x11_idle_query.cc
+++ b/chromium/ui/base/x/x11_idle_query.cc
@@ -5,6 +5,7 @@
#include "ui/base/x/x11_idle_query.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/screensaver.h"
namespace ui {
@@ -19,7 +20,7 @@ IdleQueryX11::~IdleQueryX11() = default;
int IdleQueryX11::IdleTime() {
if (auto reply = connection_->screensaver()
- .QueryInfo({connection_->default_root()})
+ .QueryInfo(connection_->default_root())
.Sync()) {
return reply->ms_since_user_input / 1000;
}
diff --git a/chromium/ui/base/x/x11_menu_list.cc b/chromium/ui/base/x/x11_menu_list.cc
index 5cea1a41421..ea8bea983e4 100644
--- a/chromium/ui/base/x/x11_menu_list.cc
+++ b/chromium/ui/base/x/x11_menu_list.cc
@@ -9,6 +9,7 @@
#include "base/memory/singleton.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/xproto_util.h"
namespace ui {
@@ -18,16 +19,16 @@ XMenuList* XMenuList::GetInstance() {
}
XMenuList::XMenuList()
- : menu_type_atom_(gfx::GetAtom("_NET_WM_WINDOW_TYPE_MENU")) {}
+ : menu_type_atom_(x11::GetAtom("_NET_WM_WINDOW_TYPE_MENU")) {}
XMenuList::~XMenuList() {
menus_.clear();
}
void XMenuList::MaybeRegisterMenu(x11::Window menu) {
- int value = 0;
- if (!GetIntProperty(menu, "_NET_WM_WINDOW_TYPE", &value) ||
- static_cast<x11::Atom>(value) != menu_type_atom_) {
+ x11::Atom value;
+ if (!GetProperty(menu, x11::GetAtom("_NET_WM_WINDOW_TYPE"), &value) ||
+ value != menu_type_atom_) {
return;
}
menus_.push_back(menu);
diff --git a/chromium/ui/base/x/x11_menu_registrar.cc b/chromium/ui/base/x/x11_menu_registrar.cc
index 847829c4664..8cb29cc296f 100644
--- a/chromium/ui/base/x/x11_menu_registrar.cc
+++ b/chromium/ui/base/x/x11_menu_registrar.cc
@@ -9,10 +9,9 @@
#include "ui/base/x/x11_menu_list.h"
#include "ui/base/x/x11_util.h"
-#include "ui/events/x/x11_window_event_manager.h"
-#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/scoped_ignore_errors.h"
#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
#include "ui/gfx/x/xproto.h"
namespace {
@@ -33,25 +32,22 @@ X11MenuRegistrar* X11MenuRegistrar::Get() {
}
X11MenuRegistrar::X11MenuRegistrar() {
- if (ui::X11EventSource::HasInstance())
- ui::X11EventSource::GetInstance()->AddXEventDispatcher(this);
+ x11::Connection::Get()->AddEventObserver(this);
- x_root_window_events_ = std::make_unique<ui::XScopedEventSelector>(
+ x_root_window_events_ = std::make_unique<x11::XScopedEventSelector>(
ui::GetX11RootWindow(),
x11::EventMask::StructureNotify | x11::EventMask::SubstructureNotify);
}
X11MenuRegistrar::~X11MenuRegistrar() {
- if (ui::X11EventSource::HasInstance())
- ui::X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+ x11::Connection::Get()->RemoveEventObserver(this);
}
-bool X11MenuRegistrar::DispatchXEvent(x11::Event* xev) {
- if (auto* create = xev->As<x11::CreateNotifyEvent>())
+void X11MenuRegistrar::OnEvent(const x11::Event& xev) {
+ if (auto* create = xev.As<x11::CreateNotifyEvent>())
OnWindowCreatedOrDestroyed(true, create->window);
- else if (auto* destroy = xev->As<x11::DestroyNotifyEvent>())
+ else if (auto* destroy = xev.As<x11::DestroyNotifyEvent>())
OnWindowCreatedOrDestroyed(false, destroy->window);
- return false;
}
void X11MenuRegistrar::OnWindowCreatedOrDestroyed(bool created,
diff --git a/chromium/ui/base/x/x11_menu_registrar.h b/chromium/ui/base/x/x11_menu_registrar.h
index 2e6584fb696..3d5c68da1d5 100644
--- a/chromium/ui/base/x/x11_menu_registrar.h
+++ b/chromium/ui/base/x/x11_menu_registrar.h
@@ -11,24 +11,26 @@
#include <string>
#include <vector>
-#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
-namespace ui {
-
+namespace x11 {
class XScopedEventSelector;
+}
+
+namespace ui {
// A singleton that owns global objects related to the desktop and listens for
// X11 events on the X11 root window. Destroys itself when the browser
// shuts down.
-class X11MenuRegistrar : public ui::XEventDispatcher {
+class X11MenuRegistrar : public x11::EventObserver {
public:
// Returns the singleton handler. Creates one if one has not
// already been created.
static X11MenuRegistrar* Get();
- // ui::XEventDispatcher
- bool DispatchXEvent(x11::Event* event) override;
+ // x11::EventObserver
+ void OnEvent(const x11::Event& event) override;
private:
X11MenuRegistrar();
@@ -39,7 +41,7 @@ class X11MenuRegistrar : public ui::XEventDispatcher {
void OnWindowCreatedOrDestroyed(bool created, x11::Window window);
// Events selected on |x_root_window_|.
- std::unique_ptr<ui::XScopedEventSelector> x_root_window_events_;
+ std::unique_ptr<x11::XScopedEventSelector> x_root_window_events_;
};
} // namespace ui
diff --git a/chromium/ui/base/x/x11_os_exchange_data_provider.cc b/chromium/ui/base/x/x11_os_exchange_data_provider.cc
index d76cbc9d28c..78d2b362c2d 100644
--- a/chromium/ui/base/x/x11_os_exchange_data_provider.cc
+++ b/chromium/ui/base/x/x11_os_exchange_data_provider.cc
@@ -13,11 +13,12 @@
#include "net/base/filename_util.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/xproto_util.h"
// Note: the GetBlah() methods are used immediately by the
// web_contents_view_aura.cc:PrepareDropData(), while the omnibox is a
@@ -43,14 +44,14 @@ XOSExchangeDataProvider::XOSExchangeDataProvider(
own_window_(false),
x_window_(x_window),
format_map_(selection),
- selection_owner_(connection_, x_window_, gfx::GetAtom(kDndSelection)) {}
+ selection_owner_(connection_, x_window_, x11::GetAtom(kDndSelection)) {}
XOSExchangeDataProvider::XOSExchangeDataProvider()
: connection_(x11::Connection::Get()),
x_root_window_(ui::GetX11RootWindow()),
own_window_(true),
- x_window_(CreateDummyWindow("Chromium Drag & Drop Window")),
- selection_owner_(connection_, x_window_, gfx::GetAtom(kDndSelection)) {}
+ x_window_(x11::CreateDummyWindow("Chromium Drag & Drop Window")),
+ selection_owner_(connection_, x_window_, x11::GetAtom(kDndSelection)) {}
XOSExchangeDataProvider::~XOSExchangeDataProvider() {
if (own_window_)
@@ -80,13 +81,13 @@ std::unique_ptr<OSExchangeDataProvider> XOSExchangeDataProvider::Clone() const {
void XOSExchangeDataProvider::MarkOriginatedFromRenderer() {
std::string empty;
- format_map_.Insert(gfx::GetAtom(kRendererTaint),
+ format_map_.Insert(x11::GetAtom(kRendererTaint),
scoped_refptr<base::RefCountedMemory>(
base::RefCountedString::TakeString(&empty)));
}
bool XOSExchangeDataProvider::DidOriginateFromRenderer() const {
- return format_map_.find(gfx::GetAtom(kRendererTaint)) != format_map_.end();
+ return format_map_.find(x11::GetAtom(kRendererTaint)) != format_map_.end();
}
void XOSExchangeDataProvider::SetString(const base::string16& text_data) {
@@ -97,10 +98,10 @@ void XOSExchangeDataProvider::SetString(const base::string16& text_data) {
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedString::TakeString(&utf8));
- format_map_.Insert(gfx::GetAtom(kMimeTypeText), mem);
- format_map_.Insert(gfx::GetAtom(kMimeTypeLinuxText), mem);
- format_map_.Insert(gfx::GetAtom(kMimeTypeLinuxString), mem);
- format_map_.Insert(gfx::GetAtom(kMimeTypeLinuxUtf8String), mem);
+ format_map_.Insert(x11::GetAtom(kMimeTypeText), mem);
+ format_map_.Insert(x11::GetAtom(kMimeTypeLinuxText), mem);
+ format_map_.Insert(x11::GetAtom(kMimeTypeLinuxString), mem);
+ format_map_.Insert(x11::GetAtom(kMimeTypeLinuxUtf8String), mem);
}
void XOSExchangeDataProvider::SetURL(const GURL& url,
@@ -118,7 +119,7 @@ void XOSExchangeDataProvider::SetURL(const GURL& url,
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedBytes::TakeVector(&data));
- format_map_.Insert(gfx::GetAtom(kMimeTypeMozillaURL), mem);
+ format_map_.Insert(x11::GetAtom(kMimeTypeMozillaURL), mem);
// Set a string fallback as well.
SetString(spec);
@@ -138,7 +139,7 @@ void XOSExchangeDataProvider::SetURL(const GURL& url,
std::string netscape_url = url.spec();
netscape_url += "\n";
netscape_url += base::UTF16ToUTF8(title);
- format_map_.Insert(gfx::GetAtom(kNetscapeURL),
+ format_map_.Insert(x11::GetAtom(kNetscapeURL),
scoped_refptr<base::RefCountedMemory>(
base::RefCountedString::TakeString(&netscape_url)));
}
@@ -162,7 +163,7 @@ void XOSExchangeDataProvider::SetFilenames(
std::string joined_data = base::JoinString(paths, "\n");
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedString::TakeString(&joined_data));
- format_map_.Insert(gfx::GetAtom(kMimeTypeURIList), mem);
+ format_map_.Insert(x11::GetAtom(kMimeTypeURIList), mem);
}
void XOSExchangeDataProvider::SetPickledData(const ClipboardFormatType& format,
@@ -175,7 +176,7 @@ void XOSExchangeDataProvider::SetPickledData(const ClipboardFormatType& format,
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedBytes::TakeVector(&bytes));
- format_map_.Insert(gfx::GetAtom(format.GetName().c_str()), mem);
+ format_map_.Insert(x11::GetAtom(format.GetName().c_str()), mem);
}
bool XOSExchangeDataProvider::GetString(base::string16* result) const {
@@ -213,7 +214,7 @@ bool XOSExchangeDataProvider::GetURLAndTitle(FilenameToURLPolicy policy,
// but that doesn't match the assumptions of the rest of the system which
// expect single types.
- if (data.GetType() == gfx::GetAtom(kMimeTypeMozillaURL)) {
+ if (data.GetType() == x11::GetAtom(kMimeTypeMozillaURL)) {
// Mozilla URLs are (UTF16: URL, newline, title).
base::string16 unparsed;
data.AssignTo(&unparsed);
@@ -230,7 +231,7 @@ bool XOSExchangeDataProvider::GetURLAndTitle(FilenameToURLPolicy policy,
*url = GURL(tokens[0]);
return true;
}
- } else if (data.GetType() == gfx::GetAtom(kMimeTypeURIList)) {
+ } else if (data.GetType() == x11::GetAtom(kMimeTypeURIList)) {
std::vector<std::string> tokens = ui::ParseURIList(data);
for (const std::string& token : tokens) {
GURL test_url(token);
@@ -282,7 +283,7 @@ bool XOSExchangeDataProvider::GetFilenames(
bool XOSExchangeDataProvider::GetPickledData(const ClipboardFormatType& format,
base::Pickle* pickle) const {
std::vector<x11::Atom> requested_types;
- requested_types.push_back(gfx::GetAtom(format.GetName().c_str()));
+ requested_types.push_back(x11::GetAtom(format.GetName().c_str()));
ui::SelectionData data(format_map_.GetFirstOf(requested_types));
if (data.IsValid()) {
@@ -315,10 +316,10 @@ bool XOSExchangeDataProvider::HasURL(FilenameToURLPolicy policy) const {
// 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(kMimeTypeMozillaURL)) {
+ if (data.GetType() == x11::GetAtom(kMimeTypeMozillaURL)) {
// File managers shouldn't be using this type, so this is a URL.
return true;
- } else if (data.GetType() == gfx::GetAtom(ui::kMimeTypeURIList)) {
+ } else if (data.GetType() == x11::GetAtom(ui::kMimeTypeURIList)) {
std::vector<std::string> tokens = ui::ParseURIList(data);
for (const std::string& token : tokens) {
if (!GURL(token).SchemeIsFile() ||
@@ -361,7 +362,7 @@ bool XOSExchangeDataProvider::HasFile() const {
bool XOSExchangeDataProvider::HasCustomFormat(
const ClipboardFormatType& format) const {
std::vector<x11::Atom> url_atoms;
- url_atoms.push_back(gfx::GetAtom(format.GetName().c_str()));
+ url_atoms.push_back(x11::GetAtom(format.GetName().c_str()));
std::vector<x11::Atom> requested_types;
GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
@@ -372,7 +373,7 @@ void XOSExchangeDataProvider::SetFileContents(
const base::FilePath& filename,
const std::string& file_contents) {
DCHECK(!filename.empty());
- DCHECK(!base::Contains(format_map(), gfx::GetAtom(kMimeTypeMozillaURL)));
+ DCHECK(!base::Contains(format_map(), x11::GetAtom(kMimeTypeMozillaURL)));
set_file_contents_name(filename);
// Direct save handling is a complicated juggling affair between this class,
// SelectionFormat, and XDragDropClient. The general idea behind
@@ -390,11 +391,11 @@ void XOSExchangeDataProvider::SetFileContents(
// things simpler for Chrome, we always 'fail' and let the destination do
// the work.
std::string failure("F");
- InsertData(gfx::GetAtom("XdndDirectSave0"),
+ InsertData(x11::GetAtom("XdndDirectSave0"),
scoped_refptr<base::RefCountedMemory>(
base::RefCountedString::TakeString(&failure)));
std::string file_contents_copy = file_contents;
- InsertData(gfx::GetAtom("application/octet-stream"),
+ InsertData(x11::GetAtom("application/octet-stream"),
scoped_refptr<base::RefCountedMemory>(
base::RefCountedString::TakeString(&file_contents_copy)));
}
@@ -410,13 +411,13 @@ void XOSExchangeDataProvider::SetHtml(const base::string16& html,
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedBytes::TakeVector(&bytes));
- format_map_.Insert(gfx::GetAtom(kMimeTypeHTML), mem);
+ format_map_.Insert(x11::GetAtom(kMimeTypeHTML), mem);
}
bool XOSExchangeDataProvider::GetHtml(base::string16* html,
GURL* base_url) const {
std::vector<x11::Atom> url_atoms;
- url_atoms.push_back(gfx::GetAtom(kMimeTypeHTML));
+ url_atoms.push_back(x11::GetAtom(kMimeTypeHTML));
std::vector<x11::Atom> requested_types;
GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
@@ -432,7 +433,7 @@ bool XOSExchangeDataProvider::GetHtml(base::string16* html,
bool XOSExchangeDataProvider::HasHtml() const {
std::vector<x11::Atom> url_atoms;
- url_atoms.push_back(gfx::GetAtom(kMimeTypeHTML));
+ url_atoms.push_back(x11::GetAtom(kMimeTypeHTML));
std::vector<x11::Atom> requested_types;
GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
diff --git a/chromium/ui/base/x/x11_pointer_grab.cc b/chromium/ui/base/x/x11_pointer_grab.cc
index 9e003369a0d..b90f9e3c613 100644
--- a/chromium/ui/base/x/x11_pointer_grab.cc
+++ b/chromium/ui/base/x/x11_pointer_grab.cc
@@ -132,7 +132,7 @@ void UngrabPointer() {
}
}
// Try core pointer ungrab in case the XInput2 pointer ungrab failed.
- connection->UngrabPointer({}).IgnoreError();
+ connection->UngrabPointer().IgnoreError();
}
} // namespace ui
diff --git a/chromium/ui/base/x/x11_screensaver_window_finder.cc b/chromium/ui/base/x/x11_screensaver_window_finder.cc
index 41c0da28282..accaf0717d8 100644
--- a/chromium/ui/base/x/x11_screensaver_window_finder.cc
+++ b/chromium/ui/base/x/x11_screensaver_window_finder.cc
@@ -5,12 +5,14 @@
#include "ui/base/x/x11_screensaver_window_finder.h"
#include "base/command_line.h"
+#include "base/strings/string_piece_forward.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/switches.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/scoped_ignore_errors.h"
#include "ui/gfx/x/screensaver.h"
#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/xproto_util.h"
namespace ui {
@@ -29,7 +31,7 @@ bool ScreensaverWindowFinder::ScreensaverWindowExists() {
{x11::ScreenSaver::major_version, x11::ScreenSaver::minor_version});
auto reply =
- connection->screensaver().QueryInfo({connection->default_root()}).Sync();
+ connection->screensaver().QueryInfo(connection->default_root()).Sync();
if (reply && static_cast<x11::ScreenSaver::State>(reply->state) ==
x11::ScreenSaver::State::On) {
return true;
@@ -39,14 +41,13 @@ bool ScreensaverWindowFinder::ScreensaverWindowExists() {
// info.state == ScreenSaverOff or info.state == ScreenSaverDisabled does not
// necessarily mean that a screensaver is not active, so add a special check
// for xscreensaver.
- x11::Atom lock_atom = gfx::GetAtom("LOCK");
- std::vector<int> atom_properties;
- if (GetIntArrayProperty(GetX11RootWindow(), "_SCREENSAVER_STATUS",
- &atom_properties) &&
+ x11::Atom lock_atom = x11::GetAtom("LOCK");
+ std::vector<x11::Atom> atom_properties;
+ if (GetArrayProperty(GetX11RootWindow(), x11::GetAtom("_SCREENSAVER_STATUS"),
+ &atom_properties) &&
atom_properties.size() > 0) {
- if (atom_properties[0] == static_cast<int>(lock_atom)) {
+ if (atom_properties[0] == lock_atom)
return true;
- }
}
// Also check the top level windows to see if any of them are screensavers.
@@ -69,16 +70,17 @@ bool ScreensaverWindowFinder::IsScreensaverWindow(x11::Window window) const {
return false;
// For xscreensaver, the window should have _SCREENSAVER_VERSION property.
- if (ui::PropertyExists(window, "_SCREENSAVER_VERSION"))
+ if (ui::PropertyExists(window, x11::GetAtom("_SCREENSAVER_VERSION")))
return true;
// For all others, like gnome-screensaver, the window's WM_CLASS property
// should contain "screensaver".
- std::string value;
- if (!ui::GetStringProperty(window, "WM_CLASS", &value))
+ std::vector<char> value;
+ if (!GetArrayProperty(window, x11::Atom::WM_CLASS, &value))
return false;
- return value.find("screensaver") != std::string::npos;
+ return base::StringPiece(value.data(), value.size()).find("screensaver") !=
+ base::StringPiece::npos;
}
} // namespace ui
diff --git a/chromium/ui/base/x/x11_shm_image_pool.cc b/chromium/ui/base/x/x11_shm_image_pool.cc
index 3adadda03cd..c00f6468fb4 100644
--- a/chromium/ui/base/x/x11_shm_image_pool.cc
+++ b/chromium/ui/base/x/x11_shm_image_pool.cc
@@ -18,6 +18,7 @@
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "net/base/url_util.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/events/platform/platform_event_source.h"
@@ -56,7 +57,7 @@ std::size_t MaxShmSegmentSize() {
return max_size;
}
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
bool IsRemoteHost(const std::string& name) {
if (name.empty())
return false;
@@ -119,13 +120,13 @@ XShmImagePool::XShmImagePool(x11::Connection* connection,
enable_multibuffering_(enable_multibuffering),
frame_states_(frames_pending) {
if (enable_multibuffering_)
- X11EventSource::GetInstance()->AddXEventDispatcher(this);
+ connection_->AddEventObserver(this);
}
XShmImagePool::~XShmImagePool() {
Cleanup();
if (enable_multibuffering_)
- X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+ connection_->RemoveEventObserver(this);
}
bool XShmImagePool::Resize(const gfx::Size& pixel_size) {
@@ -138,7 +139,7 @@ bool XShmImagePool::Resize(const gfx::Size& pixel_size) {
std::unique_ptr<XShmImagePool, decltype(cleanup_fn)> cleanup{this,
cleanup_fn};
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
if (!ShouldUseMitShm(connection_))
return false;
#endif
@@ -210,12 +211,15 @@ bool XShmImagePool::Resize(const gfx::Size& pixel_size) {
}
}
+ const auto* visual_info = connection_->GetVisualInfoFromId(visual_);
+ if (!visual_info)
+ return false;
+ size_t row_bytes = RowBytesForVisualWidth(*visual_info, pixel_size.width());
+
for (FrameState& state : frame_states_) {
state.bitmap = SkBitmap();
- if (!state.bitmap.installPixels(image_info, state.shmaddr,
- image_info.minRowBytes())) {
+ if (!state.bitmap.installPixels(image_info, state.shmaddr, row_bytes))
return false;
- }
state.canvas = std::make_unique<SkCanvas>(state.bitmap);
}
@@ -276,16 +280,13 @@ void XShmImagePool::DispatchShmCompletionEvent(
}
}
-bool XShmImagePool::DispatchXEvent(x11::Event* xev) {
+void XShmImagePool::OnEvent(const x11::Event& xev) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(enable_multibuffering_);
- auto* completion = xev->As<x11::Shm::CompletionEvent>();
- if (!completion || completion->drawable.value != drawable_.value)
- return false;
-
- DispatchShmCompletionEvent(*completion);
- return true;
+ auto* completion = xev.As<x11::Shm::CompletionEvent>();
+ if (completion && completion->drawable.value == drawable_.value)
+ DispatchShmCompletionEvent(*completion);
}
void XShmImagePool::Cleanup() {
diff --git a/chromium/ui/base/x/x11_shm_image_pool.h b/chromium/ui/base/x/x11_shm_image_pool.h
index a0e44920307..77b537c22ba 100644
--- a/chromium/ui/base/x/x11_shm_image_pool.h
+++ b/chromium/ui/base/x/x11_shm_image_pool.h
@@ -17,7 +17,6 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/base/x/x11_util.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/shm.h"
@@ -26,7 +25,7 @@ namespace ui {
// Creates XImages backed by shared memory that will be shared with the X11
// server for processing.
-class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool : public XEventDispatcher {
+class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool : public x11::EventObserver {
public:
XShmImagePool(x11::Connection* connection,
x11::Drawable drawable,
@@ -77,8 +76,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool : public XEventDispatcher {
x11::Shm::Seg shmseg{};
};
- // XEventDispatcher:
- bool DispatchXEvent(x11::Event* xev) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& xev) override;
void Cleanup();
diff --git a/chromium/ui/base/x/x11_software_bitmap_presenter.cc b/chromium/ui/base/x/x11_software_bitmap_presenter.cc
index 2c0a8bf8095..9f35bb15cc4 100644
--- a/chromium/ui/base/x/x11_software_bitmap_presenter.cc
+++ b/chromium/ui/base/x/x11_software_bitmap_presenter.cc
@@ -24,8 +24,10 @@
#include "ui/base/x/x11_util.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
#include "ui/gfx/x/xproto_types.h"
+#include "ui/gfx/x/xproto_util.h"
namespace ui {
@@ -104,7 +106,7 @@ bool X11SoftwareBitmapPresenter::CompositeBitmap(x11::Connection* connection,
kPremul_SkAlphaType);
if (!fg_bitmap.installPixels(image_info, const_cast<void*>(data), 4 * width))
return false;
- canvas.drawBitmap(fg_bitmap, 0, 0);
+ canvas.drawImage(fg_bitmap.asImage(), 0, 0);
canvas.flush();
connection->PutImage({x11::ImageFormat::ZPixmap, widget, gc, width, height, x,
@@ -140,7 +142,7 @@ X11SoftwareBitmapPresenter::X11SoftwareBitmapPresenter(
// TODO(thomasanderson): Avoid going through the X11 server to plumb this
// property in.
- ui::GetIntProperty(widget_, "CHROMIUM_COMPOSITE_WINDOW", &composite_);
+ GetProperty(widget_, x11::GetAtom("CHROMIUM_COMPOSITE_WINDOW"), &composite_);
}
X11SoftwareBitmapPresenter::~X11SoftwareBitmapPresenter() {
diff --git a/chromium/ui/base/x/x11_software_bitmap_presenter.h b/chromium/ui/base/x/x11_software_bitmap_presenter.h
index d862609d2b3..ac1b951003a 100644
--- a/chromium/ui/base/x/x11_software_bitmap_presenter.h
+++ b/chromium/ui/base/x/x11_software_bitmap_presenter.h
@@ -65,7 +65,7 @@ class COMPONENT_EXPORT(UI_BASE_X) X11SoftwareBitmapPresenter {
// If nonzero, indicates that the widget should be drawn over its
// parent-relative background.
- int composite_ = 0;
+ uint8_t composite_ = 0;
std::unique_ptr<ui::XShmImagePool> shm_pool_;
bool needs_swap_ = false;
diff --git a/chromium/ui/base/x/x11_user_input_monitor.cc b/chromium/ui/base/x/x11_user_input_monitor.cc
index 4b9ae0158a4..192bd704f5f 100644
--- a/chromium/ui/base/x/x11_user_input_monitor.cc
+++ b/chromium/ui/base/x/x11_user_input_monitor.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "ui/events/devices/x11/xinput_util.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
+#include "ui/gfx/x/future.h"
namespace ui {
@@ -23,15 +24,11 @@ void XUserInputMonitor::WillDestroyCurrentMessageLoop() {
StopMonitor();
}
-bool XUserInputMonitor::ShouldContinueStream() const {
- return true;
-}
-
-void XUserInputMonitor::DispatchXEvent(x11::Event* event) {
+void XUserInputMonitor::OnEvent(const x11::Event& event) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
DCHECK(write_key_press_callback_);
- auto* raw = event->As<x11::Input::RawDeviceEvent>();
+ auto* raw = event.As<x11::Input::RawDeviceEvent>();
if (!raw || (raw->opcode != x11::Input::RawDeviceEvent::RawKeyPress &&
raw->opcode != x11::Input::RawDeviceEvent::RawKeyRelease)) {
return;
@@ -72,6 +69,7 @@ void XUserInputMonitor::StartMonitor(WriteKeyPressCallback& callback) {
}
}
+ connection_->AddEventObserver(this);
if (!connection_->xinput().present()) {
LOG(ERROR) << "X Input extension not available.";
StopMonitor();
@@ -125,7 +123,7 @@ void XUserInputMonitor::StopMonitor() {
void XUserInputMonitor::OnConnectionData() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
- connection_->Dispatch(this);
+ connection_->DispatchAll();
}
} // namespace ui
diff --git a/chromium/ui/base/x/x11_user_input_monitor.h b/chromium/ui/base/x/x11_user_input_monitor.h
index 708817c9321..7d2417c312b 100644
--- a/chromium/ui/base/x/x11_user_input_monitor.h
+++ b/chromium/ui/base/x/x11_user_input_monitor.h
@@ -23,7 +23,7 @@ namespace ui {
class COMPONENT_EXPORT(UI_BASE_X) XUserInputMonitor
: public base::SupportsWeakPtr<XUserInputMonitor>,
public base::CurrentThread::DestructionObserver,
- public x11::Connection::Delegate {
+ public x11::EventObserver {
public:
using WriteKeyPressCallback = base::RepeatingCallback<
void(const base::WritableSharedMemoryMapping& shmem, uint32_t count)>;
@@ -44,9 +44,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XUserInputMonitor
// base::CurrentThread::DestructionObserver:
void WillDestroyCurrentMessageLoop() override;
- // x11::Connection::Delegate:
- bool ShouldContinueStream() const override;
- void DispatchXEvent(x11::Event* event) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& event) override;
void OnConnectionData();
diff --git a/chromium/ui/base/x/x11_util.cc b/chromium/ui/base/x/x11_util.cc
index e9e4671a80c..130708ac2e2 100644
--- a/chromium/ui/base/x/x11_util.cc
+++ b/chromium/ui/base/x/x11_util.cc
@@ -22,16 +22,17 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
+#include "base/containers/contains.h"
#include "base/environment.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
#include "base/memory/singleton.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -42,6 +43,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkImageInfo.h"
@@ -100,7 +102,7 @@ bool SupportsEWMH() {
x11::Window wm_window = x11::Window::None;
if (!GetProperty(GetX11RootWindow(),
- gfx::GetAtom("_NET_SUPPORTING_WM_CHECK"), &wm_window)) {
+ x11::GetAtom("_NET_SUPPORTING_WM_CHECK"), &wm_window)) {
supports_ewmh = false;
return false;
}
@@ -116,7 +118,7 @@ bool SupportsEWMH() {
// we check that too.
x11::Window wm_window_property = x11::Window::None;
supports_ewmh =
- GetProperty(wm_window, gfx::GetAtom("_NET_SUPPORTING_WM_CHECK"),
+ GetProperty(wm_window, x11::GetAtom("_NET_SUPPORTING_WM_CHECK"),
&wm_window_property) &&
wm_window_property == wm_window;
}
@@ -130,12 +132,16 @@ bool GetWindowManagerName(std::string* wm_name) {
return false;
x11::Window wm_window = x11::Window::None;
- if (!GetProperty(GetX11RootWindow(), gfx::GetAtom("_NET_SUPPORTING_WM_CHECK"),
+ if (!GetProperty(GetX11RootWindow(), x11::GetAtom("_NET_SUPPORTING_WM_CHECK"),
&wm_window)) {
return false;
}
- return GetStringProperty(wm_window, "_NET_WM_NAME", wm_name);
+ std::vector<char> str;
+ if (!GetArrayProperty(wm_window, x11::GetAtom("_NET_WM_NAME"), &str))
+ return false;
+ wm_name->assign(str.data(), str.size());
+ return true;
}
// Returns whether the X11 Screen Saver Extension can be used to disable the
@@ -167,16 +173,9 @@ base::Value NewDescriptionValuePair(base::StringPiece desc,
} // namespace
-void DeleteProperty(x11::Window window, x11::Atom name) {
- x11::Connection::Get()->DeleteProperty({
- .window = static_cast<x11::Window>(window),
- .property = name,
- });
-}
-
bool GetWmNormalHints(x11::Window window, SizeHints* hints) {
std::vector<uint32_t> hints32;
- if (!GetArrayProperty(window, gfx::GetAtom("WM_NORMAL_HINTS"), &hints32))
+ if (!GetArrayProperty(window, x11::Atom::WM_NORMAL_HINTS, &hints32))
return false;
if (hints32.size() != sizeof(SizeHints) / 4)
return false;
@@ -187,13 +186,13 @@ bool GetWmNormalHints(x11::Window window, SizeHints* hints) {
void SetWmNormalHints(x11::Window window, const SizeHints& hints) {
std::vector<uint32_t> hints32(sizeof(SizeHints) / 4);
memcpy(hints32.data(), &hints, sizeof(SizeHints));
- ui::SetArrayProperty(window, gfx::GetAtom("WM_NORMAL_HINTS"),
- gfx::GetAtom("WM_SIZE_HINTS"), hints32);
+ SetArrayProperty(window, x11::Atom::WM_NORMAL_HINTS, x11::Atom::WM_SIZE_HINTS,
+ hints32);
}
bool GetWmHints(x11::Window window, WmHints* hints) {
std::vector<uint32_t> hints32;
- if (!GetArrayProperty(window, gfx::GetAtom("WM_HINTS"), &hints32))
+ if (!GetArrayProperty(window, x11::Atom::WM_HINTS, &hints32))
return false;
if (hints32.size() != sizeof(WmHints) / 4)
return false;
@@ -204,8 +203,7 @@ bool GetWmHints(x11::Window window, WmHints* hints) {
void SetWmHints(x11::Window window, const WmHints& hints) {
std::vector<uint32_t> hints32(sizeof(WmHints) / 4);
memcpy(hints32.data(), &hints, sizeof(WmHints));
- ui::SetArrayProperty(window, gfx::GetAtom("WM_HINTS"),
- gfx::GetAtom("WM_HINTS"), hints32);
+ SetArrayProperty(window, x11::Atom::WM_HINTS, x11::Atom::WM_HINTS, hints32);
}
void WithdrawWindow(x11::Window window) {
@@ -240,22 +238,13 @@ void DefineCursor(x11::Window window, x11::Cursor cursor) {
.Sync();
}
-x11::Window CreateDummyWindow(const std::string& name) {
- auto* connection = x11::Connection::Get();
- auto window = connection->GenerateId<x11::Window>();
- connection->CreateWindow(x11::CreateWindowRequest{
- .wid = window,
- .parent = connection->default_root(),
- .x = -100,
- .y = -100,
- .width = 10,
- .height = 10,
- .c_class = x11::WindowClass::InputOnly,
- .override_redirect = x11::Bool32(true),
- });
- if (!name.empty())
- SetStringProperty(window, x11::Atom::WM_NAME, x11::Atom::STRING, name);
- return window;
+size_t RowBytesForVisualWidth(const x11::Connection::VisualInfo& visual_info,
+ int width) {
+ auto bpp = visual_info.format->bits_per_pixel;
+ auto align = visual_info.format->scanline_pad;
+ size_t row_bits = bpp * width;
+ row_bits += (align - (row_bits % align)) % align;
+ return (row_bits + 7) / 8;
}
void DrawPixmap(x11::Connection* connection,
@@ -269,15 +258,15 @@ void DrawPixmap(x11::Connection* connection,
int dst_y,
int width,
int height) {
+ // 24 bytes for the PutImage header, an additional 4 bytes in case this is an
+ // extended size request, and an additional 4 bytes in case padding is needed.
+ constexpr size_t kPutImageExtraSize = 32;
+
const auto* visual_info = connection->GetVisualInfoFromId(visual);
if (!visual_info)
return;
- auto bpp = visual_info->format->bits_per_pixel;
- auto align = visual_info->format->scanline_pad;
- size_t row_bits = bpp * width;
- row_bits += (align - (row_bits % align)) % align;
- size_t row_bytes = (row_bits + 7) / 8;
+ size_t row_bytes = RowBytesForVisualWidth(*visual_info, width);
auto color_type = ColorTypeForVisual(visual);
if (color_type == kUnknown_SkColorType) {
@@ -292,19 +281,30 @@ void DrawPixmap(x11::Connection* connection,
std::vector<uint8_t> vec(row_bytes * height);
SkPixmap pixmap(image_info, vec.data(), row_bytes);
skia_pixmap.readPixels(pixmap, src_x, src_y);
- x11::PutImageRequest put_image_request{
- .format = x11::ImageFormat::ZPixmap,
- .drawable = drawable,
- .gc = gc,
- .width = width,
- .height = height,
- .dst_x = dst_x,
- .dst_y = dst_y,
- .left_pad = 0,
- .depth = visual_info->format->depth,
- .data = base::RefCountedBytes::TakeVector(&vec),
- };
- connection->PutImage(put_image_request);
+
+ DCHECK_GT(connection->MaxRequestSizeInBytes(), kPutImageExtraSize);
+ int rows_per_request =
+ (connection->MaxRequestSizeInBytes() - kPutImageExtraSize) / row_bytes;
+ DCHECK_GT(rows_per_request, 1);
+ for (int row = 0; row < height; row += rows_per_request) {
+ size_t n_rows = std::min<size_t>(rows_per_request, height - row);
+ auto data = base::MakeRefCounted<base::RefCountedStaticMemory>(
+ vec.data() + row * row_bytes, n_rows * row_bytes);
+ connection->PutImage({
+ .format = x11::ImageFormat::ZPixmap,
+ .drawable = drawable,
+ .gc = gc,
+ .width = width,
+ .height = n_rows,
+ .dst_x = dst_x,
+ .dst_y = dst_y + row,
+ .left_pad = 0,
+ .depth = visual_info->format->depth,
+ .data = data,
+ });
+ }
+ // Flush since the PutImage requests depend on |vec| being alive.
+ connection->Flush();
}
bool IsXInput2Available() {
@@ -312,14 +312,14 @@ bool IsXInput2Available() {
}
bool QueryShmSupport() {
- static bool supported = x11::Connection::Get()->shm().QueryVersion({}).Sync();
+ static bool supported = x11::Connection::Get()->shm().QueryVersion().Sync();
return supported;
}
-int CoalescePendingMotionEvents(const x11::Event* x11_event,
+int CoalescePendingMotionEvents(const x11::Event& x11_event,
x11::Event* last_event) {
- const auto* motion = x11_event->As<x11::MotionNotifyEvent>();
- const auto* device = x11_event->As<x11::Input::DeviceEvent>();
+ const auto* motion = x11_event.As<x11::MotionNotifyEvent>();
+ const auto* device = x11_event.As<x11::Input::DeviceEvent>();
DCHECK(motion || device);
auto* conn = x11::Connection::Get();
int num_coalesced = 0;
@@ -407,7 +407,7 @@ void SetUseOSWindowFrame(x11::Window window, bool use_os_window_frame) {
std::vector<uint32_t> hints(sizeof(MotifWmHints) / sizeof(uint32_t));
memcpy(hints.data(), &motif_hints, sizeof(MotifWmHints));
- x11::Atom hint_atom = gfx::GetAtom("_MOTIF_WM_HINTS");
+ x11::Atom hint_atom = x11::GetAtom("_MOTIF_WM_HINTS");
SetArrayProperty(window, hint_atom, hint_atom, hints);
}
@@ -419,13 +419,14 @@ x11::Window GetX11RootWindow() {
return x11::Connection::Get()->default_screen().root;
}
-bool GetCurrentDesktop(int* desktop) {
- return GetIntProperty(GetX11RootWindow(), "_NET_CURRENT_DESKTOP", desktop);
+bool GetCurrentDesktop(int32_t* desktop) {
+ return GetProperty(GetX11RootWindow(), x11::GetAtom("_NET_CURRENT_DESKTOP"),
+ desktop);
}
void SetHideTitlebarWhenMaximizedProperty(x11::Window window,
HideTitlebarWhenMaximized property) {
- SetProperty(window, gfx::GetAtom("_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED"),
+ SetProperty(window, x11::GetAtom("_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED"),
x11::Atom::CARDINAL, static_cast<uint32_t>(property));
}
@@ -440,15 +441,15 @@ bool IsWindowVisible(x11::Window window) {
// Minimized windows are not visible.
std::vector<x11::Atom> wm_states;
- if (GetAtomArrayProperty(window, "_NET_WM_STATE", &wm_states)) {
- x11::Atom hidden_atom = gfx::GetAtom("_NET_WM_STATE_HIDDEN");
+ if (GetArrayProperty(window, x11::GetAtom("_NET_WM_STATE"), &wm_states)) {
+ x11::Atom hidden_atom = x11::GetAtom("_NET_WM_STATE_HIDDEN");
if (base::Contains(wm_states, hidden_atom))
return false;
}
// Some compositing window managers (notably kwin) do not actually unmap
// windows on desktop switch, so we also must check the current desktop.
- int window_desktop, current_desktop;
+ int32_t window_desktop, current_desktop;
return (!GetWindowDesktop(window, &window_desktop) ||
!GetCurrentDesktop(&current_desktop) ||
window_desktop == kAllDesktops || window_desktop == current_desktop);
@@ -459,7 +460,7 @@ bool GetInnerWindowBounds(x11::Window window, gfx::Rect* rect) {
auto root = static_cast<x11::Window>(GetX11RootWindow());
x11::Connection* connection = x11::Connection::Get();
- auto get_geometry = connection->GetGeometry({x11_window});
+ auto get_geometry = connection->GetGeometry(x11_window);
auto translate_coords = connection->TranslateCoordinates({x11_window, root});
// Sync after making both requests so only one round-trip is made.
@@ -477,8 +478,8 @@ bool GetInnerWindowBounds(x11::Window window, gfx::Rect* rect) {
}
bool GetWindowExtents(x11::Window window, gfx::Insets* extents) {
- std::vector<int> insets;
- if (!GetIntArrayProperty(window, "_NET_FRAME_EXTENTS", &insets))
+ std::vector<int32_t> insets;
+ if (!GetArrayProperty(window, x11::GetAtom("_NET_FRAME_EXTENTS"), &insets))
return false;
if (insets.size() != 4)
return false;
@@ -559,11 +560,11 @@ bool WindowContainsPoint(x11::Window window, gfx::Point screen_loc) {
return true;
}
-bool PropertyExists(x11::Window window, const std::string& property_name) {
+bool PropertyExists(x11::Window window, x11::Atom property) {
auto response = x11::Connection::Get()
->GetProperty(x11::GetPropertyRequest{
.window = static_cast<x11::Window>(window),
- .property = gfx::GetAtom(property_name),
+ .property = property,
.long_length = 1,
})
.Sync();
@@ -589,73 +590,6 @@ bool GetRawBytesOfProperty(x11::Window window,
return true;
}
-bool GetIntProperty(x11::Window window,
- const std::string& property_name,
- int* value) {
- return GetProperty(window, gfx::GetAtom(property_name), value);
-}
-
-bool GetIntArrayProperty(x11::Window window,
- const std::string& property_name,
- std::vector<int32_t>* value) {
- return GetArrayProperty(window, gfx::GetAtom(property_name), value);
-}
-
-bool GetAtomArrayProperty(x11::Window window,
- const std::string& property_name,
- std::vector<x11::Atom>* value) {
- return GetArrayProperty(window, gfx::GetAtom(property_name), value);
-}
-
-bool GetStringProperty(x11::Window window,
- const std::string& property_name,
- std::string* value) {
- std::vector<char> str;
- if (!GetArrayProperty(window, gfx::GetAtom(property_name), &str))
- return false;
-
- value->assign(str.data(), str.size());
- return true;
-}
-
-void SetIntProperty(x11::Window window,
- const std::string& name,
- const std::string& type,
- int32_t value) {
- std::vector<int> values(1, value);
- return SetIntArrayProperty(window, name, type, values);
-}
-
-void SetIntArrayProperty(x11::Window window,
- const std::string& name,
- const std::string& type,
- const std::vector<int32_t>& value) {
- SetArrayProperty(window, gfx::GetAtom(name), gfx::GetAtom(type), value);
-}
-
-void SetAtomProperty(x11::Window window,
- const std::string& name,
- const std::string& type,
- x11::Atom value) {
- std::vector<x11::Atom> values(1, value);
- return SetAtomArrayProperty(window, name, type, values);
-}
-
-void SetAtomArrayProperty(x11::Window window,
- const std::string& name,
- const std::string& type,
- const std::vector<x11::Atom>& value) {
- SetArrayProperty(window, gfx::GetAtom(name), gfx::GetAtom(type), value);
-}
-
-void SetStringProperty(x11::Window window,
- x11::Atom property,
- x11::Atom type,
- const std::string& value) {
- std::vector<char> str(value.begin(), value.end());
- SetArrayProperty(window, property, type, str);
-}
-
void SetWindowClassHint(x11::Connection* connection,
x11::Window window,
const std::string& res_name,
@@ -667,11 +601,11 @@ void SetWindowClassHint(x11::Connection* connection,
}
void SetWindowRole(x11::Window window, const std::string& role) {
- x11::Atom prop = gfx::GetAtom("WM_WINDOW_ROLE");
+ x11::Atom prop = x11::GetAtom("WM_WINDOW_ROLE");
if (role.empty())
- DeleteProperty(window, prop);
+ x11::DeleteProperty(window, prop);
else
- SetStringProperty(window, prop, x11::Atom::STRING, role);
+ x11::SetStringProperty(window, prop, x11::Atom::STRING, role);
}
void SetWMSpecState(x11::Window window,
@@ -679,7 +613,7 @@ void SetWMSpecState(x11::Window window,
x11::Atom state1,
x11::Atom state2) {
SendClientMessage(
- window, GetX11RootWindow(), gfx::GetAtom("_NET_WM_STATE"),
+ window, GetX11RootWindow(), x11::GetAtom("_NET_WM_STATE"),
{enabled ? kNetWMStateAdd : kNetWMStateRemove,
static_cast<uint32_t>(state1), static_cast<uint32_t>(state2), 1, 0});
}
@@ -695,7 +629,7 @@ void DoWMMoveResize(x11::Connection* connection,
// grabs when it receives the event below.
connection->UngrabPointer({x11::Time::CurrentTime});
- SendClientMessage(window, root_window, gfx::GetAtom("_NET_WM_MOVERESIZE"),
+ SendClientMessage(window, root_window, x11::GetAtom("_NET_WM_MOVERESIZE"),
{location_px.x(), location_px.y(), direction, 0, 0});
}
@@ -768,13 +702,13 @@ bool IsWmTiling(WindowManagerName window_manager) {
}
}
-bool GetWindowDesktop(x11::Window window, int* desktop) {
- return GetIntProperty(window, "_NET_WM_DESKTOP", desktop);
+bool GetWindowDesktop(x11::Window window, int32_t* desktop) {
+ return GetProperty(window, x11::GetAtom("_NET_WM_DESKTOP"), desktop);
}
// Returns true if |window| is a named window.
bool IsWindowNamed(x11::Window window) {
- return PropertyExists(window, "WM_NAME");
+ return PropertyExists(window, x11::Atom::WM_NAME);
}
bool EnumerateChildren(EnumerateWindowsDelegate* delegate,
@@ -848,7 +782,7 @@ void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate) {
}
bool GetXWindowStack(x11::Window window, std::vector<x11::Window>* windows) {
- if (!GetArrayProperty(window, gfx::GetAtom("_NET_CLIENT_LIST_STACKING"),
+ if (!GetArrayProperty(window, x11::GetAtom("_NET_CLIENT_LIST_STACKING"),
windows)) {
return false;
}
@@ -973,7 +907,7 @@ UMALinuxWindowManager GetWindowManagerUMA() {
bool IsCompositingManagerPresent() {
auto is_compositing_manager_present_impl = []() {
auto response = x11::Connection::Get()
- ->GetSelectionOwner({gfx::GetAtom("_NET_WM_CM_S0")})
+ ->GetSelectionOwner({x11::GetAtom("_NET_WM_CM_S0")})
.Sync();
return response && response->owner != x11::Window::None;
};
@@ -987,10 +921,11 @@ bool IsX11WindowFullScreen(x11::Window window) {
// If _NET_WM_STATE_FULLSCREEN is in _NET_SUPPORTED, use the presence or
// absence of _NET_WM_STATE_FULLSCREEN in _NET_WM_STATE to determine
// whether we're fullscreen.
- x11::Atom fullscreen_atom = gfx::GetAtom("_NET_WM_STATE_FULLSCREEN");
+ x11::Atom fullscreen_atom = x11::GetAtom("_NET_WM_STATE_FULLSCREEN");
if (WmSupportsHint(fullscreen_atom)) {
std::vector<x11::Atom> atom_properties;
- if (GetAtomArrayProperty(window, "_NET_WM_STATE", &atom_properties)) {
+ if (GetArrayProperty(window, x11::GetAtom("_NET_WM_STATE"),
+ &atom_properties)) {
return base::Contains(atom_properties, fullscreen_atom);
}
}
@@ -1016,8 +951,8 @@ void SuspendX11ScreenSaver(bool suspend) {
x11::Connection::Get()->screensaver().Suspend({suspend});
}
-base::Value GpuExtraInfoAsListValue(unsigned long system_visual,
- unsigned long rgba_visual) {
+base::Value GpuExtraInfoAsListValue(x11::VisualId system_visual,
+ x11::VisualId rgba_visual) {
base::Value result(base::Value::Type::LIST);
result.Append(
NewDescriptionValuePair("Window manager", ui::GuessWindowManagerName()));
@@ -1034,10 +969,12 @@ base::Value GpuExtraInfoAsListValue(unsigned long system_visual,
"Compositing manager",
ui::IsCompositingManagerPresent() ? "Yes" : "No"));
}
- result.Append(NewDescriptionValuePair("System visual ID",
- base::NumberToString(system_visual)));
- result.Append(NewDescriptionValuePair("RGBA visual ID",
- base::NumberToString(rgba_visual)));
+ result.Append(NewDescriptionValuePair(
+ "System visual ID",
+ base::NumberToString(static_cast<uint32_t>(system_visual))));
+ result.Append(NewDescriptionValuePair(
+ "RGBA visual ID",
+ base::NumberToString(static_cast<uint32_t>(rgba_visual))));
return result;
}
@@ -1046,8 +983,8 @@ bool WmSupportsHint(x11::Atom atom) {
return false;
std::vector<x11::Atom> supported_atoms;
- if (!GetAtomArrayProperty(GetX11RootWindow(), "_NET_SUPPORTED",
- &supported_atoms)) {
+ if (!GetArrayProperty(GetX11RootWindow(), x11::GetAtom("_NET_SUPPORTED"),
+ &supported_atoms)) {
return false;
}
@@ -1062,7 +999,7 @@ gfx::ICCProfile GetICCProfileForMonitor(int monitor) {
? "_ICC_PROFILE"
: base::StringPrintf("_ICC_PROFILE_%d", monitor);
scoped_refptr<base::RefCountedMemory> data;
- if (GetRawBytesOfProperty(GetX11RootWindow(), gfx::GetAtom(atom_name), &data,
+ if (GetRawBytesOfProperty(GetX11RootWindow(), x11::GetAtom(atom_name), &data,
nullptr)) {
icc_profile = gfx::ICCProfile::FromData(data->data(), data->size());
}
@@ -1079,7 +1016,7 @@ bool IsSyncExtensionAvailable() {
// builds as long as our EGL impl for Ozone/X11 is not mature enough and we do
// not receive swap completions on time, which results in weird resize behaviour
// as X Server waits for the XSyncCounter changes.
-#if defined(OS_CHROMEOS) || defined(USE_OZONE)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(USE_OZONE)
return false;
#else
static bool result =
@@ -1149,7 +1086,7 @@ bool IsVulkanSurfaceSupported() {
};
auto* connection = x11::Connection::Get();
for (const auto* extension : extensions) {
- if (connection->QueryExtension({extension}).Sync())
+ if (connection->QueryExtension(extension).Sync())
return true;
}
return false;
@@ -1236,9 +1173,10 @@ bool XVisualManager::GetVisualInfo(x11::VisualId visual_id,
return GetVisualInfoImpl(visual_id, depth, colormap, visual_has_alpha);
}
-bool XVisualManager::OnGPUInfoChanged(bool software_rendering,
- x11::VisualId system_visual_id,
- x11::VisualId transparent_visual_id) {
+bool XVisualManager::UpdateVisualsOnGpuInfoChanged(
+ bool software_rendering,
+ x11::VisualId system_visual_id,
+ x11::VisualId transparent_visual_id) {
base::AutoLock lock(lock_);
// TODO(thomasanderson): Cache these visual IDs as a property of the root
// window so that newly created browser processes can get them immediately.
diff --git a/chromium/ui/base/x/x11_util.h b/chromium/ui/base/x/x11_util.h
index ca024c442a6..450525f41b5 100644
--- a/chromium/ui/base/x/x11_util.h
+++ b/chromium/ui/base/x/x11_util.h
@@ -6,13 +6,8 @@
#define UI_BASE_X_X11_UTIL_H_
// This file declares utility functions for X11 (Linux only).
-//
-// These functions do not require the Xlib headers to be included (which is why
-// we use a void* for Visual*). The Xlib headers are highly polluting so we try
-// hard to limit their spread into the rest of the code.
-
-#include <stddef.h>
+#include <cstddef>
#include <memory>
#include <string>
#include <unordered_map>
@@ -33,6 +28,8 @@
#include "ui/gfx/icc_profile.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
+#include "ui/gfx/x/future.h"
+#include "ui/gfx/x/xproto.h"
#include "ui/gfx/x/xproto_types.h"
typedef unsigned long Cursor;
@@ -127,77 +124,6 @@ struct WmHints {
// These functions use the default display and this /must/ be called from
// the UI thread. Thus, they don't support multiple displays.
-template <typename T>
-bool GetArrayProperty(x11::Window window,
- x11::Atom name,
- std::vector<T>* value,
- x11::Atom* out_type = nullptr,
- size_t amount = 0) {
- static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "");
-
- size_t bytes = amount * sizeof(T);
- // The length field specifies the maximum amount of data we would like the
- // server to give us. It's specified in units of 4 bytes, so divide by 4.
- // Add 3 before division to round up.
- size_t length = (bytes + 3) / 4;
- using lentype = decltype(x11::GetPropertyRequest::long_length);
- auto response =
- x11::Connection::Get()
- ->GetProperty(x11::GetPropertyRequest{
- .window = static_cast<x11::Window>(window),
- .property = name,
- .long_length =
- amount ? length : std::numeric_limits<lentype>::max()})
- .Sync();
- if (!response || response->format != CHAR_BIT * sizeof(T))
- return false;
-
- DCHECK_EQ(response->format / CHAR_BIT * response->value_len,
- response->value->size());
- value->resize(response->value_len);
- memcpy(value->data(), response->value->data(), response->value->size());
- if (out_type)
- *out_type = response->type;
- return true;
-}
-
-template <typename T>
-bool GetProperty(x11::Window window, const x11::Atom name, T* value) {
- std::vector<T> values;
- if (!GetArrayProperty(window, name, &values, nullptr, 1) || values.empty())
- return false;
- *value = values[0];
- return true;
-}
-
-template <typename T>
-void SetArrayProperty(x11::Window window,
- x11::Atom name,
- x11::Atom type,
- const std::vector<T>& values) {
- static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "");
- std::vector<uint8_t> data(sizeof(T) * values.size());
- memcpy(data.data(), values.data(), sizeof(T) * values.size());
- x11::Connection::Get()->ChangeProperty(x11::ChangePropertyRequest{
- .window = static_cast<x11::Window>(window),
- .property = name,
- .type = type,
- .format = CHAR_BIT * sizeof(T),
- .data_len = values.size(),
- .data = base::RefCountedBytes::TakeVector(&data)});
-}
-
-template <typename T>
-void SetProperty(x11::Window window,
- x11::Atom name,
- x11::Atom type,
- const T& value) {
- SetArrayProperty(window, name, type, std::vector<T>{value});
-}
-
-COMPONENT_EXPORT(UI_BASE_X)
-void DeleteProperty(x11::Window window, x11::Atom name);
-
COMPONENT_EXPORT(UI_BASE_X)
bool GetWmNormalHints(x11::Window window, SizeHints* hints);
@@ -223,7 +149,8 @@ COMPONENT_EXPORT(UI_BASE_X)
void DefineCursor(x11::Window window, x11::Cursor cursor);
COMPONENT_EXPORT(UI_BASE_X)
-x11::Window CreateDummyWindow(const std::string& name = "");
+size_t RowBytesForVisualWidth(const x11::Connection::VisualInfo& visual_info,
+ int width);
// Draws an SkPixmap on |drawable| using the given |gc|, converting to the
// server side visual as needed.
@@ -252,7 +179,7 @@ COMPONENT_EXPORT(UI_BASE_X) bool QueryShmSupport();
// the queue, and return the number eliminated, storing the last one in
// |last_event|.
COMPONENT_EXPORT(UI_BASE_X)
-int CoalescePendingMotionEvents(const x11::Event* xev, x11::Event* last_event);
+int CoalescePendingMotionEvents(const x11::Event& xev, x11::Event* last_event);
// Sets whether |window| should use the OS window frame.
COMPONENT_EXPORT(UI_BASE_X)
@@ -267,7 +194,7 @@ COMPONENT_EXPORT(UI_BASE_X) bool IsShapeExtensionAvailable();
COMPONENT_EXPORT(UI_BASE_X) x11::Window GetX11RootWindow();
// Returns the user's current desktop.
-COMPONENT_EXPORT(UI_BASE_X) bool GetCurrentDesktop(int* desktop);
+COMPONENT_EXPORT(UI_BASE_X) bool GetCurrentDesktop(int32_t* desktop);
enum HideTitlebarWhenMaximized : uint32_t {
SHOW_TITLEBAR_WHEN_MAXIMIZED = 0,
@@ -302,7 +229,7 @@ bool WindowContainsPoint(x11::Window window, gfx::Point screen_loc);
// Return true if |window| has any property with |property_name|.
COMPONENT_EXPORT(UI_BASE_X)
-bool PropertyExists(x11::Window window, const std::string& property_name);
+bool PropertyExists(x11::Window window, x11::Atom property);
// Returns the raw bytes from a property with minimal
// interpretation. |out_data| should be freed by XFree() after use.
@@ -312,54 +239,6 @@ bool GetRawBytesOfProperty(x11::Window window,
scoped_refptr<base::RefCountedMemory>* out_data,
x11::Atom* out_type);
-// Get the value of an int, int array, atom array or string property. On
-// success, true is returned and the value is stored in |value|.
-//
-// These functions should no longer be used. TODO(thomasanderson): migrate
-// existing callers to {Set,Get}{,Array}Property<> instead.
-COMPONENT_EXPORT(UI_BASE_X)
-bool GetIntProperty(x11::Window window,
- const std::string& property_name,
- int32_t* value);
-COMPONENT_EXPORT(UI_BASE_X)
-bool GetIntArrayProperty(x11::Window window,
- const std::string& property_name,
- std::vector<int32_t>* value);
-COMPONENT_EXPORT(UI_BASE_X)
-bool GetAtomArrayProperty(x11::Window window,
- const std::string& property_name,
- std::vector<x11::Atom>* value);
-COMPONENT_EXPORT(UI_BASE_X)
-bool GetStringProperty(x11::Window window,
- const std::string& property_name,
- std::string* value);
-
-COMPONENT_EXPORT(UI_BASE_X)
-void SetIntProperty(x11::Window window,
- const std::string& name,
- const std::string& type,
- int32_t value);
-COMPONENT_EXPORT(UI_BASE_X)
-void SetIntArrayProperty(x11::Window window,
- const std::string& name,
- const std::string& type,
- const std::vector<int32_t>& value);
-COMPONENT_EXPORT(UI_BASE_X)
-void SetAtomProperty(x11::Window window,
- const std::string& name,
- const std::string& type,
- x11::Atom value);
-COMPONENT_EXPORT(UI_BASE_X)
-void SetAtomArrayProperty(x11::Window window,
- const std::string& name,
- const std::string& type,
- const std::vector<x11::Atom>& value);
-COMPONENT_EXPORT(UI_BASE_X)
-void SetStringProperty(x11::Window window,
- x11::Atom property,
- x11::Atom type,
- const std::string& value);
-
// Sets the WM_CLASS attribute for a given X11 window.
COMPONENT_EXPORT(UI_BASE_X)
void SetWindowClassHint(x11::Connection* connection,
@@ -400,11 +279,11 @@ bool HasWMSpecProperty(const base::flat_set<x11::Atom>& properties,
// frame based on the currently-running window manager.
COMPONENT_EXPORT(UI_BASE_X) bool GetCustomFramePrefDefault();
-static const int kAllDesktops = -1;
+static const int32_t kAllDesktops = -1;
// Queries the desktop |window| is on, kAllDesktops if sticky. Returns false if
// property not found.
COMPONENT_EXPORT(UI_BASE_X)
-bool GetWindowDesktop(x11::Window window, int* desktop);
+bool GetWindowDesktop(x11::Window window, int32_t* desktop);
// Implementers of this interface receive a notification for every X window of
// the main display.
@@ -520,8 +399,8 @@ COMPONENT_EXPORT(UI_BASE_X) void SuspendX11ScreenSaver(bool suspend);
// Returns human readable description of the window manager, desktop, and
// other system properties related to the compositing.
COMPONENT_EXPORT(UI_BASE_X)
-base::Value GpuExtraInfoAsListValue(unsigned long system_visual,
- unsigned long rgba_visual);
+base::Value GpuExtraInfoAsListValue(x11::VisualId system_visual,
+ x11::VisualId rgba_visual);
// Returns true if the window manager supports the given hint.
COMPONENT_EXPORT(UI_BASE_X) bool WmSupportsHint(x11::Atom atom);
@@ -577,9 +456,9 @@ class COMPONENT_EXPORT(UI_BASE_X) XVisualManager {
// necessary for the GPU process to find out which visuals are best for GL
// because we don't want to load GL in the browser process. Returns false iff
// |default_visual_id| or |transparent_visual_id| are invalid.
- bool OnGPUInfoChanged(bool software_rendering,
- x11::VisualId default_visual_id,
- x11::VisualId transparent_visual_id);
+ bool UpdateVisualsOnGpuInfoChanged(bool software_rendering,
+ x11::VisualId default_visual_id,
+ x11::VisualId transparent_visual_id);
// Are all of the system requirements met for using transparent visuals?
bool ArgbVisualAvailable() const;
diff --git a/chromium/ui/base/x/x11_whole_screen_move_loop.cc b/chromium/ui/base/x/x11_whole_screen_move_loop.cc
index 09a0c5a7f58..db678799dbf 100644
--- a/chromium/ui/base/x/x11_whole_screen_move_loop.cc
+++ b/chromium/ui/base/x/x11_whole_screen_move_loop.cc
@@ -23,11 +23,10 @@
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/events/platform/scoped_event_dispatcher.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/events/x/events_x_utils.h"
-#include "ui/events/x/x11_window_event_manager.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/keysyms/keysyms.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
#include "ui/gfx/x/xproto.h"
namespace ui {
@@ -79,9 +78,13 @@ X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {
void X11WholeScreenMoveLoop::DispatchMouseMovement() {
if (!last_motion_in_screen_)
return;
+ auto weak_ref = weak_factory_.GetWeakPtr();
delegate_->OnMouseMovement(last_motion_in_screen_->root_location(),
last_motion_in_screen_->flags(),
last_motion_in_screen_->time_stamp());
+ // The delegate may delete this during dispatch.
+ if (!weak_ref)
+ return;
last_motion_in_screen_.reset();
}
@@ -277,7 +280,7 @@ void X11WholeScreenMoveLoop::CreateDragInputWindow(
x11::EventMask::ButtonPress | x11::EventMask::ButtonRelease |
x11::EventMask::PointerMotion | x11::EventMask::KeyPress |
x11::EventMask::KeyRelease | x11::EventMask::StructureNotify;
- grab_input_window_events_ = std::make_unique<ui::XScopedEventSelector>(
+ grab_input_window_events_ = std::make_unique<x11::XScopedEventSelector>(
grab_input_window_, event_mask);
connection->MapWindow({grab_input_window_});
RaiseWindow(grab_input_window_);
diff --git a/chromium/ui/base/x/x11_whole_screen_move_loop.h b/chromium/ui/base/x/x11_whole_screen_move_loop.h
index e56d82910ab..72e7ed09968 100644
--- a/chromium/ui/base/x/x11_whole_screen_move_loop.h
+++ b/chromium/ui/base/x/x11_whole_screen_move_loop.h
@@ -22,10 +22,13 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/x/connection.h"
+namespace x11 {
+class XScopedEventSelector;
+}
+
namespace ui {
class MouseEvent;
class ScopedEventDispatcher;
-class XScopedEventSelector;
// Runs a nested run loop and grabs the mouse. This is used to implement
// dragging.
@@ -77,7 +80,7 @@ class COMPONENT_EXPORT(UI_BASE_X) X11WholeScreenMoveLoop
x11::Window grab_input_window_;
// Events selected on |grab_input_window_|.
- std::unique_ptr<ui::XScopedEventSelector> grab_input_window_events_;
+ std::unique_ptr<x11::XScopedEventSelector> grab_input_window_events_;
// Whether the pointer was grabbed on |grab_input_window_|.
bool grabbed_pointer_;
diff --git a/chromium/ui/base/x/x11_window.cc b/chromium/ui/base/x/x11_window.cc
index 988ffa93bf2..585a09a2b6d 100644
--- a/chromium/ui/base/x/x11_window.cc
+++ b/chromium/ui/base/x/x11_window.cc
@@ -14,6 +14,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "build/chromeos_buildflags.h"
#include "net/base/network_interfaces.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/base/hit_test_x11.h"
@@ -28,7 +29,6 @@
#include "ui/events/event_utils.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/events/x/events_x_utils.h"
-#include "ui/events/x/x11_window_event_manager.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep.h"
@@ -36,6 +36,7 @@
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_path.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
#include "ui/gfx/x/xfixes.h"
#include "ui/gfx/x/xinput.h"
#include "ui/gfx/x/xproto.h"
@@ -48,7 +49,7 @@ namespace {
// Special value of the _NET_WM_DESKTOP property which indicates that the window
// should appear on all workspaces/desktops.
-const int kAllWorkspaces = 0xFFFFFFFF;
+const int32_t kAllWorkspaces = -1;
constexpr char kX11WindowRolePopup[] = "popup";
constexpr char kX11WindowRoleBubble[] = "bubble";
@@ -195,29 +196,29 @@ void XWindow::Init(const Configuration& config) {
switch (config.type) {
case WindowType::kMenu:
req.override_redirect = x11::Bool32(true);
- window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_MENU");
+ window_type = x11::GetAtom("_NET_WM_WINDOW_TYPE_MENU");
break;
case WindowType::kTooltip:
req.override_redirect = x11::Bool32(true);
- window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
+ window_type = x11::GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
break;
case WindowType::kPopup:
req.override_redirect = x11::Bool32(true);
- window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
+ window_type = x11::GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
break;
case WindowType::kDrag:
req.override_redirect = x11::Bool32(true);
- window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_DND");
+ window_type = x11::GetAtom("_NET_WM_WINDOW_TYPE_DND");
break;
default:
- window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
+ window_type = x11::GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
break;
}
// An in-activatable window should not interact with the system wm.
if (!activatable_ || config.override_redirect)
req.override_redirect = x11::Bool32(true);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
req.override_redirect = x11::Bool32(UseTestConfigForPlatformWindows());
#endif
@@ -239,9 +240,9 @@ void XWindow::Init(const Configuration& config) {
std::string atom_name =
"_NET_SYSTEM_TRAY_S" +
base::NumberToString(connection_->DefaultScreenId());
- auto selection = connection_->GetSelectionOwner({gfx::GetAtom(atom_name)});
+ auto selection = connection_->GetSelectionOwner({x11::GetAtom(atom_name)});
if (auto reply = selection.Sync()) {
- GetProperty(reply->owner, gfx::GetAtom("_NET_SYSTEM_TRAY_VISUAL"),
+ GetProperty(reply->owner, x11::GetAtom("_NET_SYSTEM_TRAY_VISUAL"),
&visual_id_);
}
}
@@ -297,7 +298,7 @@ void XWindow::Init(const Configuration& config) {
x11::EventMask::VisibilityChange | x11::EventMask::StructureNotify |
x11::EventMask::PropertyChange | x11::EventMask::PointerMotion;
xwindow_events_ =
- std::make_unique<XScopedEventSelector>(xwindow_, event_mask);
+ std::make_unique<x11::XScopedEventSelector>(xwindow_, event_mask);
connection_->Flush();
if (IsXInput2Available())
@@ -319,17 +320,17 @@ void XWindow::Init(const Configuration& config) {
// 7. Desktop compositor responses user mouse move events, and starts a new
// resize process, go to step 1.
std::vector<x11::Atom> protocols = {
- gfx::GetAtom("WM_DELETE_WINDOW"),
- gfx::GetAtom("_NET_WM_PING"),
- gfx::GetAtom("_NET_WM_SYNC_REQUEST"),
+ x11::GetAtom("WM_DELETE_WINDOW"),
+ x11::GetAtom("_NET_WM_PING"),
+ x11::GetAtom("_NET_WM_SYNC_REQUEST"),
};
- SetArrayProperty(xwindow_, gfx::GetAtom("WM_PROTOCOLS"), x11::Atom::ATOM,
+ SetArrayProperty(xwindow_, x11::GetAtom("WM_PROTOCOLS"), x11::Atom::ATOM,
protocols);
// We need a WM_CLIENT_MACHINE value so we integrate with the desktop
// environment.
- SetStringProperty(xwindow_, gfx::GetAtom("WM_CLIENT_MACHINE"),
- gfx::GetAtom("STRING"), net::GetHostName());
+ SetStringProperty(xwindow_, x11::Atom::WM_CLIENT_MACHINE, x11::Atom::STRING,
+ net::GetHostName());
// Likewise, the X server needs to know this window's pid so it knows which
// program to kill if the window hangs.
@@ -337,9 +338,9 @@ void XWindow::Init(const Configuration& config) {
static_assert(sizeof(uint32_t) >= sizeof(pid_t),
"pid_t should not be larger than uint32_t");
uint32_t pid = getpid();
- SetProperty(xwindow_, gfx::GetAtom("_NET_WM_PID"), x11::Atom::CARDINAL, pid);
+ SetProperty(xwindow_, x11::GetAtom("_NET_WM_PID"), x11::Atom::CARDINAL, pid);
- SetProperty(xwindow_, gfx::GetAtom("_NET_WM_WINDOW_TYPE"), x11::Atom::ATOM,
+ SetProperty(xwindow_, x11::GetAtom("_NET_WM_WINDOW_TYPE"), x11::Atom::ATOM,
window_type);
// The changes to |window_properties_| here will be sent to the X server just
@@ -349,23 +350,25 @@ void XWindow::Init(const Configuration& config) {
if ((config.type == WindowType::kPopup ||
config.type == WindowType::kBubble) &&
!config.force_show_in_taskbar) {
- window_properties_.insert(gfx::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
+ window_properties_.insert(x11::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
}
// If the window should stay on top of other windows, add the
// _NET_WM_STATE_ABOVE property.
is_always_on_top_ = config.keep_on_top;
if (is_always_on_top_)
- window_properties_.insert(gfx::GetAtom("_NET_WM_STATE_ABOVE"));
+ window_properties_.insert(x11::GetAtom("_NET_WM_STATE_ABOVE"));
workspace_ = base::nullopt;
if (config.visible_on_all_workspaces) {
- window_properties_.insert(gfx::GetAtom("_NET_WM_STATE_STICKY"));
- SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllWorkspaces);
+ window_properties_.insert(x11::GetAtom("_NET_WM_STATE_STICKY"));
+ SetProperty(xwindow_, x11::GetAtom("_NET_WM_DESKTOP"), x11::Atom::CARDINAL,
+ kAllWorkspaces);
} else if (!config.workspace.empty()) {
- int workspace;
+ int32_t workspace;
if (base::StringToInt(config.workspace, &workspace))
- SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", workspace);
+ SetProperty(xwindow_, x11::GetAtom("_NET_WM_DESKTOP"),
+ x11::Atom::CARDINAL, workspace);
}
if (!config.wm_class_name.empty() || !config.wm_class_class.empty()) {
@@ -401,8 +404,8 @@ void XWindow::Init(const Configuration& config) {
}
if (config.prefer_dark_theme) {
- SetStringProperty(xwindow_, gfx::GetAtom("_GTK_THEME_VARIANT"),
- gfx::GetAtom("UTF8_STRING"), kDarkGtkThemeVariant);
+ SetStringProperty(xwindow_, x11::GetAtom("_GTK_THEME_VARIANT"),
+ x11::GetAtom("UTF8_STRING"), kDarkGtkThemeVariant);
}
if (IsSyncExtensionAvailable()) {
@@ -417,14 +420,16 @@ void XWindow::Init(const Configuration& config) {
// Set XSyncCounter as window property _NET_WM_SYNC_REQUEST_COUNTER. the
// compositor will listen on them during resizing.
- SetArrayProperty(xwindow_, gfx::GetAtom("_NET_WM_SYNC_REQUEST_COUNTER"),
+ SetArrayProperty(xwindow_, x11::GetAtom("_NET_WM_SYNC_REQUEST_COUNTER"),
x11::Atom::CARDINAL, counters);
}
// Always composite Chromium windows if a compositing WM is used. Sometimes,
// WMs will not composite fullscreen windows as an optimization, but this can
// lead to tearing of fullscreen videos.
- SetIntProperty(xwindow_, "_NET_WM_BYPASS_COMPOSITOR", "CARDINAL", 2);
+ x11::SetProperty<uint32_t>(xwindow_,
+ x11::GetAtom("_NET_WM_BYPASS_COMPOSITOR"),
+ x11::Atom::CARDINAL, 2);
if (config.icon)
SetXWindowIcons(gfx::ImageSkia(), *config.icon);
@@ -446,18 +451,18 @@ void XWindow::Map(bool inactive) {
? x11::Time::CurrentTime
: X11EventSource::GetInstance()->GetTimestamp();
if (inactive || wm_user_time_ms != x11::Time::CurrentTime) {
- SetProperty(xwindow_, gfx::GetAtom("_NET_WM_USER_TIME"),
+ SetProperty(xwindow_, x11::GetAtom("_NET_WM_USER_TIME"),
x11::Atom::CARDINAL, wm_user_time_ms);
}
UpdateMinAndMaxSize();
if (window_properties_.empty()) {
- DeleteProperty(xwindow_, gfx::GetAtom("_NET_WM_STATE"));
+ x11::DeleteProperty(xwindow_, x11::GetAtom("_NET_WM_STATE"));
} else {
- SetAtomArrayProperty(xwindow_, "_NET_WM_STATE", "ATOM",
- std::vector<x11::Atom>(std::begin(window_properties_),
- std::end(window_properties_)));
+ SetArrayProperty(xwindow_, x11::GetAtom("_NET_WM_STATE"), x11::Atom::ATOM,
+ std::vector<x11::Atom>(std::begin(window_properties_),
+ std::end(window_properties_)));
}
connection_->MapWindow({xwindow_});
@@ -490,23 +495,23 @@ void XWindow::Maximize() {
// save this one for later too.
should_maximize_after_map_ = !window_mapped_in_client_;
- SetWMSpecState(true, gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
- gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
+ SetWMSpecState(true, x11::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
+ x11::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
}
void XWindow::Minimize() {
if (window_mapped_in_client_) {
- SendClientMessage(xwindow_, x_root_window_, gfx::GetAtom("WM_CHANGE_STATE"),
+ SendClientMessage(xwindow_, x_root_window_, x11::GetAtom("WM_CHANGE_STATE"),
{WM_STATE_ICONIC, 0, 0, 0, 0});
} else {
- SetWMSpecState(true, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::Atom::None);
+ SetWMSpecState(true, x11::GetAtom("_NET_WM_STATE_HIDDEN"), x11::Atom::None);
}
}
void XWindow::Unmaximize() {
should_maximize_after_map_ = false;
- SetWMSpecState(false, gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
- gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
+ SetWMSpecState(false, x11::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
+ x11::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
}
bool XWindow::Hide() {
@@ -522,11 +527,11 @@ bool XWindow::Hide() {
}
void XWindow::Unhide() {
- SetWMSpecState(false, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::Atom::None);
+ SetWMSpecState(false, x11::GetAtom("_NET_WM_STATE_HIDDEN"), x11::Atom::None);
}
void XWindow::SetFullscreen(bool fullscreen) {
- SetWMSpecState(fullscreen, gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"),
+ SetWMSpecState(fullscreen, x11::GetAtom("_NET_WM_STATE_FULLSCREEN"),
x11::Atom::None);
}
@@ -542,7 +547,7 @@ void XWindow::Activate() {
// https://code.google.com/p/wmii/issues/detail?id=266
static bool wm_supports_active_window =
GuessWindowManager() != WM_WMII &&
- WmSupportsHint(gfx::GetAtom("_NET_ACTIVE_WINDOW"));
+ WmSupportsHint(x11::GetAtom("_NET_ACTIVE_WINDOW"));
x11::Time timestamp = X11EventSource::GetInstance()->GetTimestamp();
@@ -561,7 +566,7 @@ void XWindow::Activate() {
0,
};
SendClientMessage(xwindow_, x_root_window_,
- gfx::GetAtom("_NET_ACTIVE_WINDOW"), data);
+ x11::GetAtom("_NET_ACTIVE_WINDOW"), data);
} else {
RaiseWindow(xwindow_);
// Directly ask the X server to give focus to the window. Note that the call
@@ -665,19 +670,19 @@ bool XWindow::IsXWindowVisible() const {
bool XWindow::IsMinimized() const {
return HasWMSpecProperty(window_properties_,
- gfx::GetAtom("_NET_WM_STATE_HIDDEN"));
+ x11::GetAtom("_NET_WM_STATE_HIDDEN"));
}
bool XWindow::IsMaximized() const {
return (HasWMSpecProperty(window_properties_,
- gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")) &&
+ x11::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")) &&
HasWMSpecProperty(window_properties_,
- gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")));
+ x11::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")));
}
bool XWindow::IsFullscreen() const {
return HasWMSpecProperty(window_properties_,
- gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"));
+ x11::GetAtom("_NET_WM_STATE_FULLSCREEN"));
}
gfx::Rect XWindow::GetOuterBounds() const {
@@ -743,9 +748,9 @@ bool XWindow::SetTitle(base::string16 title) {
window_title_ = title;
std::string utf8str = base::UTF16ToUTF8(title);
- SetStringProperty(xwindow_, gfx::GetAtom("_NET_WM_NAME"),
- gfx::GetAtom("UTF8_STRING"), utf8str);
- SetStringProperty(xwindow_, x11::Atom::WM_NAME, gfx::GetAtom("UTF8_STRING"),
+ SetStringProperty(xwindow_, x11::GetAtom("_NET_WM_NAME"),
+ x11::GetAtom("UTF8_STRING"), utf8str);
+ SetStringProperty(xwindow_, x11::Atom::WM_NAME, x11::GetAtom("UTF8_STRING"),
utf8str);
return true;
}
@@ -762,9 +767,9 @@ void XWindow::SetXWindowOpacity(float opacity) {
uint32_t cardinality = opacity_8bit * channel_multiplier;
if (cardinality == 0xffffffff) {
- DeleteProperty(xwindow_, gfx::GetAtom("_NET_WM_WINDOW_OPACITY"));
+ x11::DeleteProperty(xwindow_, x11::GetAtom("_NET_WM_WINDOW_OPACITY"));
} else {
- SetProperty(xwindow_, gfx::GetAtom("_NET_WM_WINDOW_OPACITY"),
+ SetProperty(xwindow_, x11::GetAtom("_NET_WM_WINDOW_OPACITY"),
x11::Atom::CARDINAL, cardinality);
}
}
@@ -806,13 +811,13 @@ void XWindow::SetXWindowIcons(const gfx::ImageSkia& window_icon,
SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data);
if (!data.empty()) {
- SetArrayProperty(xwindow_, gfx::GetAtom("_NET_WM_ICON"),
+ SetArrayProperty(xwindow_, x11::GetAtom("_NET_WM_ICON"),
x11::Atom::CARDINAL, data);
}
}
void XWindow::SetXWindowVisibleOnAllWorkspaces(bool visible) {
- SetWMSpecState(visible, gfx::GetAtom("_NET_WM_STATE_STICKY"),
+ SetWMSpecState(visible, x11::GetAtom("_NET_WM_STATE_STICKY"),
x11::Atom::None);
int new_desktop = 0;
@@ -824,7 +829,7 @@ void XWindow::SetXWindowVisibleOnAllWorkspaces(bool visible) {
}
workspace_ = kAllWorkspaces;
- SendClientMessage(xwindow_, x_root_window_, gfx::GetAtom("_NET_WM_DESKTOP"),
+ SendClientMessage(xwindow_, x_root_window_, x11::GetAtom("_NET_WM_DESKTOP"),
{new_desktop, 0, 0, 0, 0});
}
@@ -847,12 +852,11 @@ void XWindow::MoveCursorTo(const gfx::Point& location_in_pixels) {
void XWindow::ResetWindowRegion() {
std::unique_ptr<std::vector<x11::Rectangle>> xregion;
if (!use_custom_shape() && !IsMaximized() && !IsFullscreen()) {
- SkPath window_mask;
- GetWindowMaskForXWindow(bounds().size(), &window_mask);
+ SkPath window_mask = GetWindowMaskForXWindow();
// Some frame views define a custom (non-rectangular) window mask. If
// so, use it to define the window shape. If not, fall through.
if (window_mask.countPoints() > 0)
- xregion = gfx::CreateRegionFromSkPath(window_mask);
+ xregion = x11::CreateRegionFromSkPath(window_mask);
}
UpdateWindowRegion(std::move(xregion));
}
@@ -871,7 +875,7 @@ void XWindow::OnWorkspaceUpdated() {
void XWindow::SetAlwaysOnTop(bool always_on_top) {
is_always_on_top_ = always_on_top;
- SetWMSpecState(always_on_top, gfx::GetAtom("_NET_WM_STATE_ABOVE"),
+ SetWMSpecState(always_on_top, x11::GetAtom("_NET_WM_STATE_ABOVE"),
x11::Atom::None);
}
@@ -1091,7 +1095,7 @@ void XWindow::WmMoveResize(int hittest, const gfx::Point& location) const {
DoWMMoveResize(connection_, x_root_window_, xwindow_, location, direction);
}
-void XWindow::ProcessEvent(x11::Event* xev) {
+void XWindow::OnEvent(const x11::Event& xev) {
// We can lose track of the window's position when the window is reparented.
// When the parent window is moved, we won't get an event, so the window's
// position relative to the root window will get out-of-sync. We can re-sync
@@ -1099,8 +1103,8 @@ void XWindow::ProcessEvent(x11::Event* xev) {
// ButtonRelease, MotionNotify) which include the pointer location both
// relative to this window and relative to the root window, so we can
// calculate this window's position from that information.
- gfx::Point window_point = EventLocationFromXEvent(*xev);
- gfx::Point root_point = EventSystemLocationFromXEvent(*xev);
+ gfx::Point window_point = EventLocationFromXEvent(xev);
+ gfx::Point root_point = EventSystemLocationFromXEvent(xev);
if (!window_point.IsOrigin() && !root_point.IsOrigin()) {
gfx::Point window_origin = gfx::Point() + (root_point - window_point);
if (bounds_in_pixels_.origin() != window_origin) {
@@ -1111,20 +1115,20 @@ void XWindow::ProcessEvent(x11::Event* xev) {
// May want to factor CheckXEventForConsistency(xev); into a common location
// since it is called here.
- if (auto* crossing = xev->As<x11::CrossingEvent>()) {
+ if (auto* crossing = xev.As<x11::CrossingEvent>()) {
bool focus = crossing->same_screen_focus & CROSSING_FLAG_FOCUS;
OnCrossingEvent(crossing->opcode == x11::CrossingEvent::EnterNotify, focus,
crossing->mode, crossing->detail);
- } else if (auto* expose = xev->As<x11::ExposeEvent>()) {
+ } else if (auto* expose = xev.As<x11::ExposeEvent>()) {
gfx::Rect damage_rect_in_pixels(expose->x, expose->y, expose->width,
expose->height);
OnXWindowDamageEvent(damage_rect_in_pixels);
- } else if (auto* focus = xev->As<x11::FocusEvent>()) {
+ } else if (auto* focus = xev.As<x11::FocusEvent>()) {
OnFocusEvent(focus->opcode == x11::FocusEvent::In, focus->mode,
focus->detail);
- } else if (auto* configure = xev->As<x11::ConfigureNotifyEvent>()) {
+ } else if (auto* configure = xev.As<x11::ConfigureNotifyEvent>()) {
OnConfigureEvent(*configure);
- } else if (auto* crossing = xev->As<x11::Input::CrossingEvent>()) {
+ } else if (auto* crossing = xev.As<x11::Input::CrossingEvent>()) {
TouchFactory* factory = TouchFactory::GetInstance();
if (factory->ShouldProcessCrossingEvent(*crossing)) {
auto mode = XI2ModeToXMode(crossing->mode);
@@ -1144,46 +1148,46 @@ void XWindow::ProcessEvent(x11::Event* xev) {
break;
}
}
- } else if (xev->As<x11::MapNotifyEvent>()) {
+ } else if (xev.As<x11::MapNotifyEvent>()) {
OnWindowMapped();
- } else if (xev->As<x11::UnmapNotifyEvent>()) {
+ } else if (xev.As<x11::UnmapNotifyEvent>()) {
window_mapped_in_server_ = false;
has_pointer_ = false;
has_pointer_grab_ = false;
has_pointer_focus_ = false;
has_window_focus_ = false;
- } else if (auto* client = xev->As<x11::ClientMessageEvent>()) {
+ } else if (auto* client = xev.As<x11::ClientMessageEvent>()) {
x11::Atom message_type = client->type;
- if (message_type == gfx::GetAtom("WM_PROTOCOLS")) {
+ if (message_type == x11::GetAtom("WM_PROTOCOLS")) {
x11::Atom protocol = static_cast<x11::Atom>(client->data.data32[0]);
- if (protocol == gfx::GetAtom("WM_DELETE_WINDOW")) {
+ if (protocol == x11::GetAtom("WM_DELETE_WINDOW")) {
// We have received a close message from the window manager.
OnXWindowCloseRequested();
- } else if (protocol == gfx::GetAtom("_NET_WM_PING")) {
+ } else if (protocol == x11::GetAtom("_NET_WM_PING")) {
x11::ClientMessageEvent reply_event = *client;
reply_event.window = x_root_window_;
x11::SendEvent(reply_event, x_root_window_,
x11::EventMask::SubstructureNotify |
x11::EventMask::SubstructureRedirect);
- } else if (protocol == gfx::GetAtom("_NET_WM_SYNC_REQUEST")) {
+ } else if (protocol == x11::GetAtom("_NET_WM_SYNC_REQUEST")) {
pending_counter_value_ =
client->data.data32[2] +
(static_cast<int64_t>(client->data.data32[3]) << 32);
pending_counter_value_is_extended_ = client->data.data32[4] != 0;
}
} else {
- OnXWindowDragDropEvent(xev);
+ OnXWindowDragDropEvent(*client);
}
- } else if (auto* property = xev->As<x11::PropertyNotifyEvent>()) {
+ } else if (auto* property = xev.As<x11::PropertyNotifyEvent>()) {
x11::Atom changed_atom = property->atom;
- if (changed_atom == gfx::GetAtom("_NET_WM_STATE"))
+ if (changed_atom == x11::GetAtom("_NET_WM_STATE"))
OnWMStateUpdated();
- else if (changed_atom == gfx::GetAtom("_NET_FRAME_EXTENTS"))
+ else if (changed_atom == x11::GetAtom("_NET_FRAME_EXTENTS"))
OnFrameExtentsUpdated();
- else if (changed_atom == gfx::GetAtom("_NET_WM_DESKTOP"))
+ else if (changed_atom == x11::GetAtom("_NET_WM_DESKTOP"))
OnWorkspaceUpdated();
- } else if (auto* selection = xev->As<x11::SelectionNotifyEvent>()) {
- OnXWindowSelectionEvent(xev);
+ } else if (auto* selection = xev.As<x11::SelectionNotifyEvent>()) {
+ OnXWindowSelectionEvent(*selection);
}
}
@@ -1196,7 +1200,7 @@ void XWindow::UpdateWMUserTime(Event* event) {
type == ET_TOUCH_PRESSED) {
uint32_t wm_user_time_ms =
(event->time_stamp() - base::TimeTicks()).InMilliseconds();
- SetProperty(xwindow_, gfx::GetAtom("_NET_WM_USER_TIME"),
+ SetProperty(xwindow_, x11::GetAtom("_NET_WM_USER_TIME"),
x11::Atom::CARDINAL, wm_user_time_ms);
}
}
@@ -1272,7 +1276,7 @@ void XWindow::OnWMStateUpdated() {
// unmapped, leave the state unchanged so it will be restored when the window
// is remapped.
std::vector<x11::Atom> atom_list;
- if (GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list) ||
+ if (GetArrayProperty(xwindow_, x11::GetAtom("_NET_WM_STATE"), &atom_list) ||
window_mapped_in_client_) {
UpdateWindowProperties(
base::flat_set<x11::Atom>(std::begin(atom_list), std::end(atom_list)));
@@ -1291,14 +1295,14 @@ void XWindow::UpdateWindowProperties(
// do preprocessing before the x window's fullscreen state is toggled.
is_always_on_top_ = HasWMSpecProperty(window_properties_,
- gfx::GetAtom("_NET_WM_STATE_ABOVE"));
+ x11::GetAtom("_NET_WM_STATE_ABOVE"));
OnXWindowStateChanged();
ResetWindowRegion();
}
void XWindow::OnFrameExtentsUpdated() {
- std::vector<int> insets;
- if (GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) &&
+ std::vector<int32_t> insets;
+ if (GetArrayProperty(xwindow_, x11::GetAtom("_NET_FRAME_EXTENTS"), &insets) &&
insets.size() == 4) {
// |insets| are returned in the order: [left, right, top, bottom].
native_window_frame_borders_in_pixels_ =
@@ -1458,12 +1462,12 @@ void XWindow::SetXWindowShape(std::unique_ptr<NativeShapeRects> native_shape,
if (native_region.getBoundaryPath(&path_in_dip)) {
SkPath path_in_pixels;
path_in_dip.transform(SkMatrix(transform.matrix()), &path_in_pixels);
- xregion = gfx::CreateRegionFromSkPath(path_in_pixels);
+ xregion = x11::CreateRegionFromSkPath(path_in_pixels);
} else {
xregion = std::make_unique<std::vector<x11::Rectangle>>();
}
} else {
- xregion = gfx::CreateRegionFromSkRegion(native_region);
+ xregion = x11::CreateRegionFromSkRegion(native_region);
}
}
@@ -1541,26 +1545,28 @@ void XWindow::NotifyBoundsChanged(const gfx::Rect& new_bounds_in_px) {
bool XWindow::InitializeAsStatusIcon() {
std::string atom_name = "_NET_SYSTEM_TRAY_S" +
base::NumberToString(connection_->DefaultScreenId());
- auto reply = connection_->GetSelectionOwner({gfx::GetAtom(atom_name)}).Sync();
+ auto reply = connection_->GetSelectionOwner({x11::GetAtom(atom_name)}).Sync();
if (!reply || reply->owner == x11::Window::None)
return false;
auto manager = reply->owner;
- SetIntArrayProperty(xwindow_, "_XEMBED_INFO", "CARDINAL",
- {kXembedInfoProtocolVersion, kXembedInfoFlags});
+ SetArrayProperty(
+ xwindow_, x11::GetAtom("_XEMBED_INFO"), x11::Atom::CARDINAL,
+ std::vector<uint32_t>{kXembedInfoProtocolVersion, kXembedInfoFlags});
x11::ChangeWindowAttributesRequest req{xwindow_};
if (has_alpha()) {
req.background_pixel = 0;
} else {
- SetIntProperty(xwindow_, "CHROMIUM_COMPOSITE_WINDOW", "CARDINAL", 1);
+ SetProperty(xwindow_, x11::GetAtom("CHROMIUM_COMPOSITE_WINDOW"),
+ x11::Atom::CARDINAL, static_cast<uint32_t>(1));
req.background_pixmap =
static_cast<x11::Pixmap>(x11::BackPixmap::ParentRelative);
}
connection_->ChangeWindowAttributes(req);
auto future = SendClientMessage(
- manager, manager, gfx::GetAtom("_NET_SYSTEM_TRAY_OPCODE"),
+ manager, manager, x11::GetAtom("_NET_SYSTEM_TRAY_OPCODE"),
{static_cast<uint32_t>(X11EventSource::GetInstance()->GetTimestamp()),
kSystemTrayRequestDock, static_cast<uint32_t>(xwindow_), 0, 0},
x11::EventMask::NoEvent);
diff --git a/chromium/ui/base/x/x11_window.h b/chromium/ui/base/x/x11_window.h
index 4078ea5dc7b..0a870d41a04 100644
--- a/chromium/ui/base/x/x11_window.h
+++ b/chromium/ui/base/x/x11_window.h
@@ -33,10 +33,13 @@ class ImageSkia;
class Transform;
} // namespace gfx
+namespace x11 {
+class XScopedEventSelector;
+}
+
namespace ui {
class Event;
-class XScopedEventSelector;
class X11Cursor;
////////////////////////////////////////////////////////////////////////////////
@@ -118,7 +121,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow {
bool IsTransientWindowTargetedBy(const x11::Event& x11_event) const;
void SetTransientWindow(x11::Window window);
void WmMoveResize(int hittest, const gfx::Point& location) const;
- void ProcessEvent(x11::Event* xev);
+ void OnEvent(const x11::Event& xev);
void SetSize(const gfx::Size& size_in_pixels);
void SetBounds(const gfx::Rect& requested_bounds);
@@ -252,12 +255,12 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow {
virtual void OnXWindowWorkspaceChanged() = 0;
virtual void OnXWindowLostPointerGrab() = 0;
virtual void OnXWindowLostCapture() = 0;
- virtual void OnXWindowSelectionEvent(x11::Event* xev) = 0;
- virtual void OnXWindowDragDropEvent(x11::Event* xev) = 0;
+ virtual void OnXWindowSelectionEvent(
+ const x11::SelectionNotifyEvent& xev) = 0;
+ virtual void OnXWindowDragDropEvent(const x11::ClientMessageEvent& xev) = 0;
virtual base::Optional<gfx::Size> GetMinimumSizeForXWindow() = 0;
virtual base::Optional<gfx::Size> GetMaximumSizeForXWindow() = 0;
- virtual void GetWindowMaskForXWindow(const gfx::Size& size,
- SkPath* window_mask) = 0;
+ virtual SkPath GetWindowMaskForXWindow() = 0;
// The display and the native X window hosting the root window.
x11::Connection* const connection_;
@@ -268,7 +271,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow {
x11::Window transient_window_ = x11::Window::None;
// Events selected on |xwindow_|.
- std::unique_ptr<ui::XScopedEventSelector> xwindow_events_;
+ std::unique_ptr<x11::XScopedEventSelector> xwindow_events_;
// The window manager state bits.
base::flat_set<x11::Atom> window_properties_;
diff --git a/chromium/ui/base/x/x11_workspace_handler.cc b/chromium/ui/base/x/x11_workspace_handler.cc
index 84ae4701b14..c0130e63525 100644
--- a/chromium/ui/base/x/x11_workspace_handler.cc
+++ b/chromium/ui/base/x/x11_workspace_handler.cc
@@ -6,9 +6,8 @@
#include "base/strings/string_number_conversions.h"
#include "ui/base/x/x11_util.h"
-#include "ui/events/x/x11_window_event_manager.h"
-#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
#include "ui/gfx/x/xproto.h"
namespace ui {
@@ -19,8 +18,8 @@ x11::Future<x11::GetPropertyReply> GetWorkspace() {
auto* connection = x11::Connection::Get();
return connection->GetProperty(x11::GetPropertyRequest{
.window = connection->default_screen().root,
- .property = static_cast<x11::Atom>(gfx::GetAtom("_NET_CURRENT_DESKTOP")),
- .type = static_cast<x11::Atom>(gfx::GetAtom("CARDINAL")),
+ .property = static_cast<x11::Atom>(x11::GetAtom("_NET_CURRENT_DESKTOP")),
+ .type = static_cast<x11::Atom>(x11::Atom::CARDINAL),
.long_length = 1,
});
}
@@ -30,16 +29,14 @@ x11::Future<x11::GetPropertyReply> GetWorkspace() {
X11WorkspaceHandler::X11WorkspaceHandler(Delegate* delegate)
: x_root_window_(ui::GetX11RootWindow()), delegate_(delegate) {
DCHECK(delegate_);
- if (ui::X11EventSource::HasInstance())
- ui::X11EventSource::GetInstance()->AddXEventDispatcher(this);
+ x11::Connection::Get()->AddEventObserver(this);
- x_root_window_events_ = std::make_unique<ui::XScopedEventSelector>(
+ x_root_window_events_ = std::make_unique<x11::XScopedEventSelector>(
x_root_window_, x11::EventMask::PropertyChange);
}
X11WorkspaceHandler::~X11WorkspaceHandler() {
- if (ui::X11EventSource::HasInstance())
- ui::X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+ x11::Connection::Get()->RemoveEventObserver(this);
}
std::string X11WorkspaceHandler::GetCurrentWorkspace() {
@@ -48,16 +45,13 @@ std::string X11WorkspaceHandler::GetCurrentWorkspace() {
return workspace_;
}
-bool X11WorkspaceHandler::DispatchXEvent(x11::Event* xev) {
- auto* prop = xev->As<x11::PropertyNotifyEvent>();
+void X11WorkspaceHandler::OnEvent(const x11::Event& xev) {
+ auto* prop = xev.As<x11::PropertyNotifyEvent>();
if (prop && prop->window == x_root_window_ &&
- prop->atom == gfx::GetAtom("_NET_CURRENT_DESKTOP")) {
+ prop->atom == x11::GetAtom("_NET_CURRENT_DESKTOP")) {
GetWorkspace().OnResponse(base::BindOnce(
&X11WorkspaceHandler::OnWorkspaceResponse, weak_factory_.GetWeakPtr()));
- return true;
}
-
- return false;
}
void X11WorkspaceHandler::OnWorkspaceResponse(
@@ -65,7 +59,7 @@ void X11WorkspaceHandler::OnWorkspaceResponse(
if (!response || response->format != 32 || response->value->size() < 4)
return;
DCHECK_EQ(response->bytes_after, 0U);
- DCHECK_EQ(response->type, static_cast<x11::Atom>(gfx::GetAtom("CARDINAL")));
+ DCHECK_EQ(response->type, static_cast<x11::Atom>(x11::Atom::CARDINAL));
uint32_t workspace;
memcpy(&workspace, response->value->data(), 4);
diff --git a/chromium/ui/base/x/x11_workspace_handler.h b/chromium/ui/base/x/x11_workspace_handler.h
index cf6f1b45603..2a4e7935013 100644
--- a/chromium/ui/base/x/x11_workspace_handler.h
+++ b/chromium/ui/base/x/x11_workspace_handler.h
@@ -9,17 +9,19 @@
#include "base/component_export.h"
#include "base/memory/weak_ptr.h"
-#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/xproto.h"
-namespace ui {
-
+namespace x11 {
class XScopedEventSelector;
+}
+
+namespace ui {
// Listens for global workspace changes and notifies observers.
class COMPONENT_EXPORT(UI_BASE_X) X11WorkspaceHandler
- : public ui::XEventDispatcher {
+ : public x11::EventObserver {
public:
class Delegate {
public:
@@ -39,8 +41,8 @@ class COMPONENT_EXPORT(UI_BASE_X) X11WorkspaceHandler
std::string GetCurrentWorkspace();
private:
- // ui::XEventDispatcher
- bool DispatchXEvent(x11::Event* event) override;
+ // x11::EventObserver
+ void OnEvent(const x11::Event& event) override;
void OnWorkspaceResponse(x11::GetPropertyResponse response);
@@ -48,7 +50,7 @@ class COMPONENT_EXPORT(UI_BASE_X) X11WorkspaceHandler
x11::Window x_root_window_;
// Events selected on x_root_window_.
- std::unique_ptr<ui::XScopedEventSelector> x_root_window_events_;
+ std::unique_ptr<x11::XScopedEventSelector> x_root_window_events_;
std::string workspace_;
diff --git a/chromium/ui/base/x/xwmstartupcheck/xwmstartupcheck.cc b/chromium/ui/base/x/xwmstartupcheck/xwmstartupcheck.cc
index 9954e562e97..596a5dcdfc6 100644
--- a/chromium/ui/base/x/xwmstartupcheck/xwmstartupcheck.cc
+++ b/chromium/ui/base/x/xwmstartupcheck/xwmstartupcheck.cc
@@ -14,6 +14,8 @@
#include "base/command_line.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/event.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/xproto.h"
void CalculateTimeout(const timespec& now,
diff --git a/chromium/ui/chromeos/BUILD.gn b/chromium/ui/chromeos/BUILD.gn
index f5bf43ba8c4..902d4b9fd7f 100644
--- a/chromium/ui/chromeos/BUILD.gn
+++ b/chromium/ui/chromeos/BUILD.gn
@@ -2,10 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
import("//testing/test.gni")
-assert(is_chromeos)
+assert(is_chromeos_ash)
component("chromeos") {
output_name = "ui_chromeos"
@@ -17,9 +18,9 @@ component("chromeos") {
]
defines = [ "UI_CHROMEOS_IMPLEMENTATION" ]
deps = [
+ "//ash/constants",
"//base",
"//base/third_party/dynamic_annotations",
- "//chromeos/constants",
"//chromeos/dbus/power",
"//chromeos/dbus/power:power_manager_proto",
"//components/device_event_log",
diff --git a/chromium/ui/chromeos/events/BUILD.gn b/chromium/ui/chromeos/events/BUILD.gn
index 3792fdbcefc..39af81f32b7 100644
--- a/chromium/ui/chromeos/events/BUILD.gn
+++ b/chromium/ui/chromeos/events/BUILD.gn
@@ -2,10 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ozone.gni")
import("//build/config/ui.gni")
-assert(is_chromeos)
+assert(is_chromeos_ash)
source_set("events") {
output_name = "ui_chromeos_events"
@@ -19,8 +20,8 @@ source_set("events") {
"pref_names.h",
]
deps = [
+ "//ash/constants",
"//base",
- "//chromeos/constants",
"//device/udev_linux",
"//ui/base:features",
"//ui/base/ime/chromeos",
diff --git a/chromium/ui/chromeos/strings/BUILD.gn b/chromium/ui/chromeos/strings/BUILD.gn
index c6d41f524c1..f41128adf85 100644
--- a/chromium/ui/chromeos/strings/BUILD.gn
+++ b/chromium/ui/chromeos/strings/BUILD.gn
@@ -2,65 +2,13 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/locales.gni")
import("//tools/grit/grit_rule.gni")
grit("strings") {
source = "../ui_chromeos_strings.grd"
- outputs = [
- "grit/ui_chromeos_strings.h",
- "ui_chromeos_strings_am.pak",
- "ui_chromeos_strings_ar.pak",
- "ui_chromeos_strings_bg.pak",
- "ui_chromeos_strings_bn.pak",
- "ui_chromeos_strings_ca.pak",
- "ui_chromeos_strings_cs.pak",
- "ui_chromeos_strings_da.pak",
- "ui_chromeos_strings_de.pak",
- "ui_chromeos_strings_el.pak",
- "ui_chromeos_strings_en-GB.pak",
- "ui_chromeos_strings_en-US.pak",
- "ui_chromeos_strings_es-419.pak",
- "ui_chromeos_strings_es.pak",
- "ui_chromeos_strings_et.pak",
- "ui_chromeos_strings_fake-bidi.pak",
- "ui_chromeos_strings_fa.pak",
- "ui_chromeos_strings_fil.pak",
- "ui_chromeos_strings_fi.pak",
- "ui_chromeos_strings_fr.pak",
- "ui_chromeos_strings_gu.pak",
- "ui_chromeos_strings_he.pak",
- "ui_chromeos_strings_hi.pak",
- "ui_chromeos_strings_hr.pak",
- "ui_chromeos_strings_hu.pak",
- "ui_chromeos_strings_id.pak",
- "ui_chromeos_strings_it.pak",
- "ui_chromeos_strings_ja.pak",
- "ui_chromeos_strings_kn.pak",
- "ui_chromeos_strings_ko.pak",
- "ui_chromeos_strings_lt.pak",
- "ui_chromeos_strings_lv.pak",
- "ui_chromeos_strings_ml.pak",
- "ui_chromeos_strings_mr.pak",
- "ui_chromeos_strings_ms.pak",
- "ui_chromeos_strings_nb.pak",
- "ui_chromeos_strings_nl.pak",
- "ui_chromeos_strings_pl.pak",
- "ui_chromeos_strings_pt-BR.pak",
- "ui_chromeos_strings_pt-PT.pak",
- "ui_chromeos_strings_ro.pak",
- "ui_chromeos_strings_ru.pak",
- "ui_chromeos_strings_sk.pak",
- "ui_chromeos_strings_sl.pak",
- "ui_chromeos_strings_sr.pak",
- "ui_chromeos_strings_sv.pak",
- "ui_chromeos_strings_sw.pak",
- "ui_chromeos_strings_ta.pak",
- "ui_chromeos_strings_te.pak",
- "ui_chromeos_strings_th.pak",
- "ui_chromeos_strings_tr.pak",
- "ui_chromeos_strings_uk.pak",
- "ui_chromeos_strings_vi.pak",
- "ui_chromeos_strings_zh-CN.pak",
- "ui_chromeos_strings_zh-TW.pak",
- ]
+ outputs =
+ [ "grit/ui_chromeos_strings.h" ] +
+ process_file_template(locales_with_fake_bidi,
+ [ "ui_chromeos_strings_{{source_name_part}}.pak" ])
}
diff --git a/chromium/ui/color/BUILD.gn b/chromium/ui/color/BUILD.gn
index 898dd69d377..ca2c15eaa1d 100644
--- a/chromium/ui/color/BUILD.gn
+++ b/chromium/ui/color/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/buildflag_header.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//testing/test.gni")
import("//ui/base/ui_features.gni")
@@ -82,7 +83,7 @@ component("mixers") {
public_deps = [ "//base" ]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [ "cros/native_color_mixers.cc" ]
} else if (is_fuchsia) {
sources += [ "fuchsia/native_color_mixers.cc" ]
diff --git a/chromium/ui/color/DIR_METADATA b/chromium/ui/color/DIR_METADATA
new file mode 100644
index 00000000000..f31293e3139
--- /dev/null
+++ b/chromium/ui/color/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI"
+}
diff --git a/chromium/ui/color/OWNERS b/chromium/ui/color/OWNERS
index 56165ee0926..bf426d601e0 100644
--- a/chromium/ui/color/OWNERS
+++ b/chromium/ui/color/OWNERS
@@ -1,3 +1 @@
pkasting@chromium.org
-
-# COMPONENT: UI \ No newline at end of file
diff --git a/chromium/ui/compositor/BUILD.gn b/chromium/ui/compositor/BUILD.gn
index 65a978aebaa..75b4168ede8 100644
--- a/chromium/ui/compositor/BUILD.gn
+++ b/chromium/ui/compositor/BUILD.gn
@@ -69,6 +69,8 @@ component("compositor") {
"throughput_tracker.cc",
"throughput_tracker.h",
"throughput_tracker_host.h",
+ "total_animation_throughput_reporter.cc",
+ "total_animation_throughput_reporter.h",
"transform_animation_curve_adapter.cc",
"transform_animation_curve_adapter.h",
"transform_recorder.cc",
@@ -88,6 +90,7 @@ component("compositor") {
deps = [
"//base",
"//base/third_party/dynamic_annotations",
+ "//build:chromeos_buildflags",
"//cc/animation",
"//cc/paint",
"//components/viz/host",
@@ -98,6 +101,7 @@ component("compositor") {
"//ui/events",
"//ui/gfx",
"//ui/gfx/animation",
+ "//ui/gfx/animation/keyframe",
"//ui/gfx/geometry",
"//ui/gl",
]
@@ -116,6 +120,8 @@ component("compositor") {
static_library("test_support") {
testonly = true
sources = [
+ "test/animation_throughput_reporter_test_base.cc",
+ "test/animation_throughput_reporter_test_base.h",
"test/direct_layer_tree_frame_sink.cc",
"test/direct_layer_tree_frame_sink.h",
"test/draw_waiter_for_test.cc",
@@ -146,6 +152,8 @@ static_library("test_support") {
"test/test_suite.h",
"test/test_utils.cc",
"test/test_utils.h",
+ "test/throughput_report_checker.cc",
+ "test/throughput_report_checker.h",
]
if (is_android) {
@@ -163,6 +171,7 @@ static_library("test_support") {
public_deps = [ ":compositor" ]
deps = [
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//cc",
"//cc:test_support",
"//components/viz/host",
@@ -235,6 +244,8 @@ test("compositor_unittests") {
"layer_owner_unittest.cc",
"layer_unittest.cc",
"run_all_unittests.cc",
+ "throughput_tracker_unittest.cc",
+ "total_animation_throughput_reporter_unittest.cc",
"transform_animation_curve_adapter_unittest.cc",
]
@@ -245,6 +256,7 @@ test("compositor_unittests") {
":test_support",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//cc",
"//cc:test_support",
"//components/viz/common",
diff --git a/chromium/ui/compositor/DIR_METADATA b/chromium/ui/compositor/DIR_METADATA
new file mode 100644
index 00000000000..aef9ec1a6cf
--- /dev/null
+++ b/chromium/ui/compositor/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+ component: "Internals>Compositing"
+}
+team_email: "graphics-dev@chromium.org"
diff --git a/chromium/ui/compositor/OWNERS b/chromium/ui/compositor/OWNERS
index e75e3f022ed..3807753ca24 100644
--- a/chromium/ui/compositor/OWNERS
+++ b/chromium/ui/compositor/OWNERS
@@ -8,6 +8,3 @@ vollick@chromium.org
# Animation
per-file *animat*=ajuma@chromium.org
per-file *animat*=loyso@chromium.org
-
-# COMPONENT: Internals>Compositing
-# TEAM: graphics-dev@chromium.org
diff --git a/chromium/ui/compositor/animation_throughput_reporter.cc b/chromium/ui/compositor/animation_throughput_reporter.cc
index 5704e26554d..043a349fccd 100644
--- a/chromium/ui/compositor/animation_throughput_reporter.cc
+++ b/chromium/ui/compositor/animation_throughput_reporter.cc
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "base/check.h"
-#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "cc/animation/animation.h"
@@ -23,6 +22,16 @@
namespace ui {
+// AnimationTracker tracks the layer animations that are created during the
+// lifetime of its owner AnimationThroughputReporter.
+//
+// Lifetime of this tracker class is a bit complicated. If there are animations
+// to track (i.e. HasAnimationsToTrack() returns true) when the owner reporter
+// is going away, it needs to have the same lifetime of the animations to track
+// the performance. In such case, the owner reporter would drop the ownership
+// and set set_should_delete() to let the tracker manages its own lifetime
+// based on LayerAnimationObserver signals. On the other hand, if there are no
+// animations to track, the tracker is released with its owner reporter.
class AnimationThroughputReporter::AnimationTracker
: public CallbackLayerAnimationObserver {
public:
@@ -34,12 +43,14 @@ class AnimationThroughputReporter::AnimationTracker
report_callback_(std::move(report_callback)) {
DCHECK(report_callback_);
}
+
AnimationTracker(const AnimationTracker& other) = delete;
AnimationTracker& operator=(const AnimationTracker& other) = delete;
+
~AnimationTracker() override = default;
- // Whether there are attached animation sequences to track.
- bool IsTrackingAnimation() const { return !attached_sequences().empty(); }
+ // Whether there are/will be animations to track.
+ bool HasAnimationsToTrack() const { return !attached_sequences().empty(); }
void set_should_delete(bool should_delete) { should_delete_ = should_delete; }
@@ -90,13 +101,12 @@ class AnimationThroughputReporter::AnimationTracker
// No tracking if |animator_| is not attached to a timeline. Layer animation
// sequence would not tick without a timeline.
- if (!AnimationThroughputReporter::IsAnimatorAttachedToTimeline(
- animator_.get())) {
+ if (!AnimationThroughputReporter::IsAnimatorAttachedToTimeline(animator_)) {
return;
}
ui::Compositor* compositor =
- AnimationThroughputReporter::GetCompositor(animator_.get());
+ AnimationThroughputReporter::GetCompositor(animator_);
throughput_tracker_ = compositor->RequestNewThroughputTracker();
throughput_tracker_->Start(report_callback_);
}
@@ -119,7 +129,7 @@ class AnimationThroughputReporter::AnimationTracker
// Whether this class should delete itself on animation ended.
bool should_delete_ = false;
- scoped_refptr<LayerAnimator> animator_;
+ LayerAnimator* const animator_;
base::Optional<ThroughputTracker> throughput_tracker_;
@@ -130,11 +140,11 @@ class AnimationThroughputReporter::AnimationTracker
};
AnimationThroughputReporter::AnimationThroughputReporter(
- LayerAnimator* animator,
+ scoped_refptr<LayerAnimator> animator,
ReportCallback report_callback)
- : animator_(animator),
+ : animator_(std::move(animator)),
animation_tracker_(
- std::make_unique<AnimationTracker>(animator_,
+ std::make_unique<AnimationTracker>(animator_.get(),
std::move(report_callback))) {
animator_->AddObserver(animation_tracker_.get());
}
@@ -145,8 +155,17 @@ AnimationThroughputReporter::~AnimationThroughputReporter() {
// from the scheduled animation sequences.
animator_->observers_.RemoveObserver(animation_tracker_.get());
+ // Drop the animator reference. If this is the last reference, the animator
+ // will be destroyed. When the animator destruction happens, it destroys its
+ // LayerAnimationSequences and detach observers from them. As a result,
+ // AnimationTracker::OnAnimationEnded would be called after all animation
+ // sequences are detached. After this, animator will no longer be accessed
+ // by AnimationTracker and HasAnimationsToTrack() would correctly report
+ // that there are no animations to track.
+ animator_.reset();
+
// |animation_tracker_| deletes itself when its tracked animations finish.
- if (animation_tracker_->IsTrackingAnimation())
+ if (animation_tracker_->HasAnimationsToTrack())
animation_tracker_.release()->set_should_delete(true);
}
diff --git a/chromium/ui/compositor/animation_throughput_reporter.h b/chromium/ui/compositor/animation_throughput_reporter.h
index 334a9eddee4..59b728dfcaf 100644
--- a/chromium/ui/compositor/animation_throughput_reporter.h
+++ b/chromium/ui/compositor/animation_throughput_reporter.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/callback_forward.h"
+#include "base/memory/scoped_refptr.h"
#include "cc/metrics/frame_sequence_metrics.h"
#include "ui/compositor/compositor_export.h"
@@ -37,7 +38,7 @@ class COMPOSITOR_EXPORT AnimationThroughputReporter {
public:
using ReportCallback = base::RepeatingCallback<void(
const cc::FrameSequenceMetrics::CustomReportData&)>;
- AnimationThroughputReporter(LayerAnimator* animator,
+ AnimationThroughputReporter(scoped_refptr<LayerAnimator> animator,
ReportCallback report_callback);
AnimationThroughputReporter(const AnimationThroughputReporter&) = delete;
AnimationThroughputReporter& operator=(const AnimationThroughputReporter&) =
@@ -57,7 +58,7 @@ class COMPOSITOR_EXPORT AnimationThroughputReporter {
// List here to access LayerAnimation's private |anmation_| member.
static bool IsAnimatorAttachedToTimeline(LayerAnimator* animator);
- LayerAnimator* const animator_;
+ scoped_refptr<LayerAnimator> animator_;
std::unique_ptr<AnimationTracker> animation_tracker_;
};
diff --git a/chromium/ui/compositor/animation_throughput_reporter_unittest.cc b/chromium/ui/compositor/animation_throughput_reporter_unittest.cc
index d39b01bfdab..99f6b194043 100644
--- a/chromium/ui/compositor/animation_throughput_reporter_unittest.cc
+++ b/chromium/ui/compositor/animation_throughput_reporter_unittest.cc
@@ -6,73 +6,21 @@
#include <memory>
-#include "base/run_loop.h"
#include "base/test/bind.h"
-#include "base/test/task_environment.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
-#include "base/timer/timer.h"
+#include "build/build_config.h"
#include "cc/metrics/frame_sequence_metrics.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/compositor/test/test_compositor_host.h"
-#include "ui/compositor/test/test_context_factories.h"
+#include "ui/compositor/test/animation_throughput_reporter_test_base.h"
+#include "ui/compositor/test/throughput_report_checker.h"
#include "ui/gfx/geometry/rect.h"
namespace ui {
-class AnimationThroughputReporterTest : public testing::Test {
- public:
- AnimationThroughputReporterTest()
- : task_environment_(base::test::TaskEnvironment::MainThreadType::UI) {}
- AnimationThroughputReporterTest(const AnimationThroughputReporterTest&) =
- delete;
- AnimationThroughputReporterTest& operator=(
- const AnimationThroughputReporterTest&) = delete;
- ~AnimationThroughputReporterTest() override = default;
-
- // testing::Test:
- void SetUp() override {
- context_factories_ = std::make_unique<TestContextFactories>(false);
-
- const gfx::Rect bounds(100, 100);
- host_.reset(TestCompositorHost::Create(
- bounds, context_factories_->GetContextFactory()));
- host_->Show();
-
- compositor()->SetRootLayer(&root_);
-
- frame_generation_timer_.Start(
- FROM_HERE, base::TimeDelta::FromMilliseconds(50), this,
- &AnimationThroughputReporterTest::GenerateOneFrame);
- }
-
- void TearDown() override {
- frame_generation_timer_.Stop();
- host_.reset();
- context_factories_.reset();
- }
-
- void GenerateOneFrame() { compositor()->ScheduleFullRedraw(); }
-
- Compositor* compositor() { return host_->GetCompositor(); }
- Layer* root_layer() { return &root_; }
-
- private:
- base::test::TaskEnvironment task_environment_;
-
- std::unique_ptr<TestContextFactories> context_factories_;
- std::unique_ptr<TestCompositorHost> host_;
- Layer root_;
-
- // A timer to generate continuous compositor frames to trigger throughput
- // data being transferred back.
- base::RepeatingTimer frame_generation_timer_;
-};
+using AnimationThroughputReporterTest = AnimationThroughputReporterTestBase;
// Tests animation throughput collection with implicit animation scenario.
TEST_F(AnimationThroughputReporterTest, ImplicitAnimation) {
@@ -80,20 +28,18 @@ TEST_F(AnimationThroughputReporterTest, ImplicitAnimation) {
layer.SetOpacity(0.5f);
root_layer()->Add(&layer);
- base::RunLoop run_loop;
+ ThroughputReportChecker checker(this);
{
LayerAnimator* animator = layer.GetAnimator();
- AnimationThroughputReporter reporter(
- animator, base::BindLambdaForTesting(
- [&](const cc::FrameSequenceMetrics::CustomReportData&) {
- run_loop.Quit();
- }));
+ AnimationThroughputReporter reporter(animator,
+ checker.repeating_callback());
ScopedLayerAnimationSettings settings(animator);
- settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
layer.SetOpacity(1.0f);
}
- run_loop.Run();
+ // The animation starts in next frame (16ms) and ends 48 ms later.
+ EXPECT_TRUE(checker.WaitUntilReported());
}
// Tests animation throughput collection with implicit animation setup before
@@ -102,24 +48,20 @@ TEST_F(AnimationThroughputReporterTest, ImplicitAnimationLateAttach) {
Layer layer;
layer.SetOpacity(0.5f);
- base::RunLoop run_loop;
+ ThroughputReportChecker checker(this);
{
LayerAnimator* animator = layer.GetAnimator();
- AnimationThroughputReporter reporter(
- animator, base::BindLambdaForTesting(
- [&](const cc::FrameSequenceMetrics::CustomReportData&) {
- run_loop.Quit();
- }));
+ AnimationThroughputReporter reporter(animator,
+ checker.repeating_callback());
ScopedLayerAnimationSettings settings(animator);
- settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
layer.SetOpacity(1.0f);
}
// Attach to root after animation setup.
root_layer()->Add(&layer);
-
- run_loop.Run();
+ EXPECT_TRUE(checker.WaitUntilReported());
}
// Tests animation throughput collection with explicitly created animation
@@ -129,20 +71,15 @@ TEST_F(AnimationThroughputReporterTest, ExplicitAnimation) {
layer.SetOpacity(0.5f);
root_layer()->Add(&layer);
- base::RunLoop run_loop;
- {
- LayerAnimator* animator = layer.GetAnimator();
- AnimationThroughputReporter reporter(
- animator, base::BindLambdaForTesting(
- [&](const cc::FrameSequenceMetrics::CustomReportData&) {
- run_loop.Quit();
- }));
-
- animator->ScheduleAnimation(
- new LayerAnimationSequence(LayerAnimationElement::CreateOpacityElement(
- 1.0f, base::TimeDelta::FromMilliseconds(50))));
- }
- run_loop.Run();
+ ThroughputReportChecker checker(this);
+ LayerAnimator* animator = layer.GetAnimator();
+ AnimationThroughputReporter reporter(animator, checker.repeating_callback());
+
+ animator->ScheduleAnimation(
+ new LayerAnimationSequence(LayerAnimationElement::CreateOpacityElement(
+ 1.0f, base::TimeDelta::FromMilliseconds(48))));
+
+ EXPECT_TRUE(checker.WaitUntilReported());
}
// Tests animation throughput collection for a persisted animator of a Layer.
@@ -153,25 +90,21 @@ TEST_F(AnimationThroughputReporterTest, PersistedAnimation) {
// Set a persisted animator to |layer|.
LayerAnimator* animator =
- new LayerAnimator(base::TimeDelta::FromMilliseconds(50));
+ new LayerAnimator(base::TimeDelta::FromMilliseconds(48));
layer->SetAnimator(animator);
- std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
// |reporter| keeps reporting as long as it is alive.
- AnimationThroughputReporter reporter(
- animator, base::BindLambdaForTesting(
- [&](const cc::FrameSequenceMetrics::CustomReportData&) {
- run_loop->Quit();
- }));
+ ThroughputReportChecker checker(this);
+ AnimationThroughputReporter reporter(animator, checker.repeating_callback());
// Report data for animation of opacity goes to 1.
layer->SetOpacity(1.0f);
- run_loop->Run();
+ EXPECT_TRUE(checker.WaitUntilReported());
// Report data for animation of opacity goes to 0.5.
- run_loop = std::make_unique<base::RunLoop>();
+ checker.reset();
layer->SetOpacity(0.5f);
- run_loop->Run();
+ EXPECT_TRUE(checker.WaitUntilReported());
}
// Tests animation throughput not reported when animation is aborted.
@@ -180,16 +113,17 @@ TEST_F(AnimationThroughputReporterTest, AbortedAnimation) {
layer->SetOpacity(0.5f);
root_layer()->Add(layer.get());
+ ThroughputReportChecker checker(this, /*fail_if_reported=*/true);
+
+ // Reporter started monitoring animation, then deleted, which should be
+ // reported when the animation ends.
{
LayerAnimator* animator = layer->GetAnimator();
- AnimationThroughputReporter reporter(
- animator, base::BindLambdaForTesting(
- [&](const cc::FrameSequenceMetrics::CustomReportData&) {
- ADD_FAILURE() << "No report for aborted animations.";
- }));
+ AnimationThroughputReporter reporter(animator,
+ checker.repeating_callback());
ScopedLayerAnimationSettings settings(animator);
- settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
layer->SetOpacity(1.0f);
}
@@ -197,11 +131,32 @@ TEST_F(AnimationThroughputReporterTest, AbortedAnimation) {
layer.reset();
// Wait a bit to ensure that report does not happen.
- base::RunLoop run_loop;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, run_loop.QuitClosure(),
- base::TimeDelta::FromMilliseconds(100));
- run_loop.Run();
+ Advance(base::TimeDelta::FromMilliseconds(100));
+
+ // TODO(crbug.com/1158510): Test the scenario where the report exists when the
+ // layer is removed.
+}
+
+// Tests no report and no leak when underlying layer is gone before reporter.
+TEST_F(AnimationThroughputReporterTest, LayerDestroyedBeforeReporter) {
+ auto layer = std::make_unique<Layer>();
+ layer->SetOpacity(0.5f);
+ root_layer()->Add(layer.get());
+
+ ThroughputReportChecker checker(this, /*fail_if_reported=*/true);
+ LayerAnimator* animator = layer->GetAnimator();
+ AnimationThroughputReporter reporter(animator, checker.repeating_callback());
+ {
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+ layer->SetOpacity(1.0f);
+ }
+
+ // Delete |layer| to before the reporter.
+ layer.reset();
+
+ // Wait a bit to ensure that report does not happen.
+ Advance(base::TimeDelta::FromMilliseconds(100));
}
// Tests animation throughput not reported when detached from timeline.
@@ -210,16 +165,13 @@ TEST_F(AnimationThroughputReporterTest, NoReportOnDetach) {
layer->SetOpacity(0.5f);
root_layer()->Add(layer.get());
+ ThroughputReportChecker checker(this, /*fail_if_reported=*/true);
{
LayerAnimator* animator = layer->GetAnimator();
- AnimationThroughputReporter reporter(
- animator, base::BindLambdaForTesting(
- [&](const cc::FrameSequenceMetrics::CustomReportData&) {
- ADD_FAILURE() << "No report for aborted animations.";
- }));
-
+ AnimationThroughputReporter reporter(animator,
+ checker.repeating_callback());
ScopedLayerAnimationSettings settings(animator);
- settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
layer->SetOpacity(1.0f);
}
@@ -228,11 +180,7 @@ TEST_F(AnimationThroughputReporterTest, NoReportOnDetach) {
root_layer()->Add(layer.get());
// Wait a bit to ensure that report does not happen.
- base::RunLoop run_loop;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, run_loop.QuitClosure(),
- base::TimeDelta::FromMilliseconds(100));
- run_loop.Run();
+ Advance(base::TimeDelta::FromMilliseconds(100));
}
// Tests animation throughput not reported and no leak when animation is stopped
@@ -241,16 +189,12 @@ TEST_F(AnimationThroughputReporterTest, EndDetachedNoReportNoLeak) {
auto layer = std::make_unique<Layer>();
layer->SetOpacity(0.5f);
+ ThroughputReportChecker checker(this, /*fail_if_reported=*/true);
LayerAnimator* animator = layer->GetAnimator();
-
// Schedule an animation without being attached to a root.
{
- AnimationThroughputReporter reporter(
- animator, base::BindLambdaForTesting(
- [&](const cc::FrameSequenceMetrics::CustomReportData&) {
- ADD_FAILURE() << "No report for aborted animations.";
- }));
-
+ AnimationThroughputReporter reporter(animator,
+ checker.repeating_callback());
ScopedLayerAnimationSettings settings(animator);
settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
layer->SetOpacity(1.0f);
@@ -260,11 +204,7 @@ TEST_F(AnimationThroughputReporterTest, EndDetachedNoReportNoLeak) {
animator->StopAnimating();
// Wait a bit to ensure that report does not happen.
- base::RunLoop run_loop;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, run_loop.QuitClosure(),
- base::TimeDelta::FromMilliseconds(100));
- run_loop.Run();
+ Advance(base::TimeDelta::FromMilliseconds(100));
// AnimationTracker in |reporter| should not leak in asan.
}
@@ -277,16 +217,12 @@ TEST_F(AnimationThroughputReporterTest, ReportForAnimateToNewTarget) {
layer->SetBounds(gfx::Rect(0, 0, 1, 2));
root_layer()->Add(layer.get());
+ ThroughputReportChecker checker(this, /*fail_if_reported=*/true);
LayerAnimator* animator = layer->GetAnimator();
-
// Schedule an animation that will be preempted. No report should happen.
{
- AnimationThroughputReporter reporter(
- animator, base::BindLambdaForTesting(
- [&](const cc::FrameSequenceMetrics::CustomReportData&) {
- ADD_FAILURE() << "No report for aborted animations.";
- }));
-
+ AnimationThroughputReporter reporter(animator,
+ checker.repeating_callback());
ScopedLayerAnimationSettings settings(animator);
settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
layer->SetOpacity(0.5f);
@@ -294,22 +230,18 @@ TEST_F(AnimationThroughputReporterTest, ReportForAnimateToNewTarget) {
}
// Animate to new target. Report should happen.
- base::RunLoop run_loop;
+ ThroughputReportChecker checker2(this);
{
- AnimationThroughputReporter reporter(
- animator, base::BindLambdaForTesting(
- [&](const cc::FrameSequenceMetrics::CustomReportData&) {
- run_loop.Quit();
- }));
-
+ AnimationThroughputReporter reporter(animator,
+ checker2.repeating_callback());
ScopedLayerAnimationSettings settings(animator);
settings.SetPreemptionStrategy(
LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
- settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
layer->SetOpacity(1.0f);
layer->SetBounds(gfx::Rect(0, 0, 5, 6));
}
- run_loop.Run();
+ EXPECT_TRUE(checker2.WaitUntilReported());
}
} // namespace ui
diff --git a/chromium/ui/compositor/compositor.cc b/chromium/ui/compositor/compositor.cc
index 7d498732553..8272ff517f1 100644
--- a/chromium/ui/compositor/compositor.cc
+++ b/chromium/ui/compositor/compositor.cc
@@ -11,14 +11,15 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/metrics/histogram_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"
#include "base/system/sys_info.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/animation_timeline.h"
@@ -28,6 +29,7 @@
#include "cc/layers/layer.h"
#include "cc/metrics/begin_main_frame_metrics.h"
#include "cc/metrics/frame_sequence_tracker.h"
+#include "cc/metrics/web_vital_metrics.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_settings.h"
#include "components/viz/common/features.h"
@@ -81,7 +83,8 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
bool enable_pixel_canvas,
bool use_external_begin_frame_control,
- bool force_software_compositor)
+ bool force_software_compositor,
+ bool enable_compositing_based_throttling)
: context_factory_(context_factory),
frame_sink_id_(frame_sink_id),
task_runner_(task_runner),
@@ -220,6 +223,9 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id,
settings.percent_based_scrolling = true;
}
+ settings.enable_compositing_based_throttling =
+ enable_compositing_based_throttling;
+
#if DCHECK_IS_ON()
if (command_line->HasSwitch(cc::switches::kLogOnUIDoubleBackgroundBlur))
settings.log_on_ui_double_background_blur = true;
@@ -574,13 +580,23 @@ bool Compositor::HasObserver(const CompositorObserver* observer) const {
}
void Compositor::AddAnimationObserver(CompositorAnimationObserver* observer) {
+ if (animation_observer_list_.empty()) {
+ for (auto& obs : observer_list_)
+ obs.OnFirstAnimationStarted(this);
+ }
animation_observer_list_.AddObserver(observer);
host_->SetNeedsAnimate();
}
void Compositor::RemoveAnimationObserver(
CompositorAnimationObserver* observer) {
+ if (!animation_observer_list_.HasObserver(observer))
+ return;
animation_observer_list_.RemoveObserver(observer);
+ if (animation_observer_list_.empty()) {
+ for (auto& obs : observer_list_)
+ obs.OnLastAnimationEnded(this);
+ }
}
bool Compositor::HasAnimationObserver(
@@ -623,7 +639,7 @@ void Compositor::BeginMainFrame(const viz::BeginFrameArgs& args) {
DCHECK(!IsLocked());
for (auto& observer : animation_observer_list_)
observer.OnAnimationStep(args.frame_time);
- if (animation_observer_list_.might_have_observers())
+ if (!animation_observer_list_.empty())
host_->SetNeedsAnimate();
}
@@ -671,6 +687,10 @@ Compositor::GetBeginMainFrameMetrics() {
return nullptr;
}
+std::unique_ptr<cc::WebVitalMetrics> Compositor::GetWebVitalMetrics() {
+ return nullptr;
+}
+
void Compositor::NotifyThroughputTrackerResults(
cc::CustomTrackerResults results) {
for (auto& pair : results)
@@ -703,12 +723,20 @@ void Compositor::FrameIntervalUpdated(base::TimeDelta interval) {
refresh_rate_ = interval.ToHz();
}
+void Compositor::FrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& ids) {
+ for (auto& observer : observer_list_) {
+ observer.OnFrameSinksToThrottleUpdated(ids);
+ }
+}
+
void Compositor::OnFirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {
NOTREACHED();
}
-void Compositor::OnFrameTokenChanged(uint32_t frame_token) {
+void Compositor::OnFrameTokenChanged(uint32_t frame_token,
+ base::TimeTicks activation_time) {
// TODO(yiyix, fsamuel): Implement frame token propagation for Compositor.
NOTREACHED();
}
@@ -732,7 +760,9 @@ void Compositor::CancelThroughtputTracker(TrackerId tracker_id) {
throughput_tracker_map_.erase(tracker_id);
}
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
void Compositor::OnCompleteSwapWithNewSize(const gfx::Size& size) {
for (auto& observer : observer_list_)
observer.OnCompositingCompleteSwapWithNewSize(this, size);
@@ -766,8 +796,11 @@ void Compositor::ReportMetricsForTracker(
if (it == throughput_tracker_map_.end())
return;
- std::move(it->second).Run(data);
+ // Callback may modify `throughput_tracker_map_` so update the map first.
+ // See https://crbug.com/1193382.
+ auto callback = std::move(it->second);
throughput_tracker_map_.erase(it);
+ std::move(callback).Run(data);
}
void Compositor::SetDelegatedInkPointRenderer(
diff --git a/chromium/ui/compositor/compositor.h b/chromium/ui/compositor/compositor.h
index dc011fe48e2..e4ff4cb0a2e 100644
--- a/chromium/ui/compositor/compositor.h
+++ b/chromium/ui/compositor/compositor.h
@@ -12,12 +12,14 @@
#include "base/callback_forward.h"
#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "cc/metrics/frame_sequence_tracker.h"
#include "cc/paint/element_id.h"
#include "cc/trees/layer_tree_host.h"
@@ -25,6 +27,7 @@
#include "cc/trees/layer_tree_host_single_thread_client.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "components/viz/host/host_frame_sink_client.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/viz/privileged/mojom/compositing/vsync_parameter_observer.mojom-forward.h"
@@ -78,7 +81,7 @@ class ContextProvider;
class HostFrameSinkManager;
class LocalSurfaceId;
class RasterContextProvider;
-}
+} // namespace viz
namespace ui {
class Compositor;
@@ -124,6 +127,9 @@ class COMPOSITOR_EXPORT ContextFactory {
// Allocate a new client ID for the display compositor.
virtual viz::FrameSinkId AllocateFrameSinkId() = 0;
+ // Allocates a new capture ID for a layer subtree within a frame sink.
+ virtual viz::SubtreeCaptureId AllocateSubtreeCaptureId() = 0;
+
// Gets the frame sink manager host instance.
virtual viz::HostFrameSinkManager* GetHostFrameSinkManager() = 0;
};
@@ -143,7 +149,8 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
bool enable_pixel_canvas,
bool use_external_begin_frame_control = false,
- bool force_software_compositor = false);
+ bool force_software_compositor = false,
+ bool enable_compositing_based_throttling = false);
~Compositor() override;
ui::ContextFactory* context_factory() { return context_factory_; }
@@ -321,12 +328,8 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
void UpdateLayerTreeHost() override;
void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) override {
}
- void RecordManipulationTypeCounts(cc::ManipulationInfo info) 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 UpdateCompositorScrollState(
+ const cc::CompositorCommitData& commit_data) override {}
void RequestNewLayerTreeFrameSink() override;
void DidInitializeLayerTreeFrameSink() override {}
void DidFailToInitializeLayerTreeFrameSink() override;
@@ -344,6 +347,7 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
cc::ActiveFrameSequenceTrackers trackers) override {}
std::unique_ptr<cc::BeginMainFrameMetrics> GetBeginMainFrameMetrics()
override;
+ std::unique_ptr<cc::WebVitalMetrics> GetWebVitalMetrics() override;
void NotifyThroughputTrackerResults(
cc::CustomTrackerResults results) override;
void DidObserveFirstScrollDelay(
@@ -354,10 +358,13 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
void DidSubmitCompositorFrame() override;
void DidLoseLayerTreeFrameSink() override {}
void FrameIntervalUpdated(base::TimeDelta interval) override;
+ void FrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& ids) override;
// viz::HostFrameSinkClient implementation.
void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
- void OnFrameTokenChanged(uint32_t frame_token) override;
+ void OnFrameTokenChanged(uint32_t frame_token,
+ base::TimeTicks activation_time) override;
// ThroughputTrackerHost implementation.
void StartThroughputTracker(
@@ -366,7 +373,9 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
void StopThroughtputTracker(TrackerId tracker_id) override;
void CancelThroughtputTracker(TrackerId tracker_id) override;
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
void OnCompleteSwapWithNewSize(const gfx::Size& size);
#endif
@@ -405,6 +414,7 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
private:
friend class base::RefCounted<Compositor>;
+ friend class TotalAnimationThroughputReporter;
// Called when collected metrics for the tracker of |tracker_id| is ready.
void ReportMetricsForTracker(
diff --git a/chromium/ui/compositor/compositor_observer.h b/chromium/ui/compositor/compositor_observer.h
index 5855c94b799..afef8731de3 100644
--- a/chromium/ui/compositor/compositor_observer.h
+++ b/chromium/ui/compositor/compositor_observer.h
@@ -5,8 +5,11 @@
#ifndef UI_COMPOSITOR_COMPOSITOR_OBSERVER_H_
#define UI_COMPOSITOR_COMPOSITOR_OBSERVER_H_
+#include "base/containers/flat_set.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
#include "ui/compositor/compositor_export.h"
namespace gfx {
@@ -43,7 +46,9 @@ class COMPOSITOR_EXPORT CompositorObserver {
// Called when a child of the compositor is resizing.
virtual void OnCompositingChildResizing(Compositor* compositor) {}
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Called when a swap with new size is completed.
virtual void OnCompositingCompleteSwapWithNewSize(ui::Compositor* compositor,
const gfx::Size& size) {}
@@ -57,6 +62,12 @@ class COMPOSITOR_EXPORT CompositorObserver {
virtual void OnDidPresentCompositorFrame(
uint32_t frame_token,
const gfx::PresentationFeedback& feedback) {}
+
+ virtual void OnFirstAnimationStarted(Compositor* compositor) {}
+ virtual void OnLastAnimationEnded(Compositor* compositor) {}
+
+ virtual void OnFrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& ids) {}
};
} // namespace ui
diff --git a/chromium/ui/compositor/compositor_switches.cc b/chromium/ui/compositor/compositor_switches.cc
index 7cd81cfafc9..adf348c6cbc 100644
--- a/chromium/ui/compositor/compositor_switches.cc
+++ b/chromium/ui/compositor/compositor_switches.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
namespace switches {
@@ -35,7 +36,7 @@ namespace features {
// to be done via corner points. See https://crbug.com/720596 for details.
const base::Feature kEnablePixelCanvasRecording {
"enable-pixel-canvas-recording",
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/chromium/ui/compositor/compositor_unittest.cc b/chromium/ui/compositor/compositor_unittest.cc
index 242a508436d..7eaa8bbe4ab 100644
--- a/chromium/ui/compositor/compositor_unittest.cc
+++ b/chromium/ui/compositor/compositor_unittest.cc
@@ -283,6 +283,51 @@ TEST_F(CompositorTestWithMessageLoop, ThroughputTrackerOutliveCompositor) {
tracker.Stop();
}
+TEST_F(CompositorTestWithMessageLoop, ThroughputTrackerCallbackStateChange) {
+ 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),
+ allocator.GetCurrentLocalSurfaceId());
+ ASSERT_TRUE(compositor()->IsVisible());
+
+ ThroughputTracker tracker = compositor()->RequestNewThroughputTracker();
+
+ base::RunLoop run_loop;
+ tracker.Start(base::BindLambdaForTesting(
+ [&](const cc::FrameSequenceMetrics::CustomReportData& data) {
+ // The following Cancel() call should not DCHECK or crash.
+ tracker.Cancel();
+
+ // Starting another tracker should not DCHECK or crash.
+ ThroughputTracker another_tracker =
+ compositor()->RequestNewThroughputTracker();
+ another_tracker.Start(base::DoNothing());
+
+ run_loop.Quit();
+ }));
+
+ // Generates a few frames after tracker starts to have some data collected.
+ for (int i = 0; i < 5; ++i) {
+ compositor()->ScheduleFullRedraw();
+ DrawWaiterForTest::WaitForCompositingEnded(compositor());
+ }
+
+ tracker.Stop();
+
+ // Generates a few frames after tracker stops. Note the number of frames
+ // must be at least two: one to trigger underlying cc::FrameSequenceTracker to
+ // be scheduled for termination and one to report data.
+ for (int i = 0; i < 5; ++i) {
+ compositor()->ScheduleFullRedraw();
+ DrawWaiterForTest::WaitForCompositingEnded(compositor());
+ }
+
+ run_loop.Run();
+}
+
#if defined(OS_WIN)
// TODO(crbug.com/608436): Flaky on windows trybots
#define MAYBE_CreateAndReleaseOutputSurface \
diff --git a/chromium/ui/compositor/float_animation_curve_adapter.cc b/chromium/ui/compositor/float_animation_curve_adapter.cc
index 1ae6bd14c93..d4aac1e13a0 100644
--- a/chromium/ui/compositor/float_animation_curve_adapter.cc
+++ b/chromium/ui/compositor/float_animation_curve_adapter.cc
@@ -23,7 +23,7 @@ base::TimeDelta FloatAnimationCurveAdapter::Duration() const {
return duration_;
}
-std::unique_ptr<cc::AnimationCurve> FloatAnimationCurveAdapter::Clone() const {
+std::unique_ptr<gfx::AnimationCurve> FloatAnimationCurveAdapter::Clone() const {
return base::WrapUnique(new FloatAnimationCurveAdapter(
tween_type_, initial_value_, target_value_, duration_));
}
diff --git a/chromium/ui/compositor/float_animation_curve_adapter.h b/chromium/ui/compositor/float_animation_curve_adapter.h
index b6337061748..0687b80c69d 100644
--- a/chromium/ui/compositor/float_animation_curve_adapter.h
+++ b/chromium/ui/compositor/float_animation_curve_adapter.h
@@ -8,12 +8,12 @@
#include <memory>
#include "base/time/time.h"
-#include "cc/animation/animation_curve.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
#include "ui/gfx/animation/tween.h"
namespace ui {
-class FloatAnimationCurveAdapter : public cc::FloatAnimationCurve {
+class FloatAnimationCurveAdapter : public gfx::FloatAnimationCurve {
public:
FloatAnimationCurveAdapter(gfx::Tween::Type tween_type,
float initial_value,
@@ -24,7 +24,7 @@ class FloatAnimationCurveAdapter : public cc::FloatAnimationCurve {
// FloatAnimationCurve implementation.
base::TimeDelta Duration() const override;
- std::unique_ptr<cc::AnimationCurve> Clone() const override;
+ std::unique_ptr<gfx::AnimationCurve> Clone() const override;
float GetValue(base::TimeDelta t) const override;
private:
diff --git a/chromium/ui/compositor/layer.cc b/chromium/ui/compositor/layer.cc
index 2013423958d..e6217f583f0 100644
--- a/chromium/ui/compositor/layer.cc
+++ b/chromium/ui/compositor/layer.cc
@@ -459,6 +459,14 @@ LayerAnimator* Layer::GetAnimator() {
return animator_.get();
}
+void Layer::SetSubtreeCaptureId(viz::SubtreeCaptureId subtree_id) {
+ cc_layer_->SetSubtreeCaptureId(subtree_id);
+}
+
+viz::SubtreeCaptureId Layer::GetSubtreeCaptureId() const {
+ return cc_layer_->subtree_capture_id();
+}
+
void Layer::SetTransform(const gfx::Transform& transform) {
GetAnimator()->SetTransform(transform);
}
@@ -628,8 +636,8 @@ void Layer::SetLayerFilters() {
if (layer_inverted_)
filters.Append(cc::FilterOperation::CreateInvertFilter(1.0));
if (layer_blur_sigma_) {
- filters.Append(cc::FilterOperation::CreateBlurFilter(
- layer_blur_sigma_, SkBlurImageFilter::kClamp_TileMode));
+ filters.Append(cc::FilterOperation::CreateBlurFilter(layer_blur_sigma_,
+ SkTileMode::kClamp));
}
// Brightness goes last, because the resulting colors neeed clamping, which
// cause further color matrix filters to be applied separately. In this order,
@@ -652,8 +660,8 @@ void Layer::SetLayerBackgroundFilters() {
filters.Append(cc::FilterOperation::CreateZoomFilter(zoom_, zoom_inset_));
if (background_blur_sigma_) {
- filters.Append(cc::FilterOperation::CreateBlurFilter(
- background_blur_sigma_, SkBlurImageFilter::kClamp_TileMode));
+ filters.Append(cc::FilterOperation::CreateBlurFilter(background_blur_sigma_,
+ SkTileMode::kClamp));
}
cc_layer_->SetBackdropFilters(filters);
}
@@ -781,6 +789,7 @@ bool Layer::SwitchToLayer(scoped_refptr<cc::Layer> new_layer) {
new_layer->SetBackgroundColor(cc_layer_->background_color());
new_layer->SetSafeOpaqueBackgroundColor(
cc_layer_->SafeOpaqueBackgroundColor());
+ new_layer->SetSubtreeCaptureId(cc_layer_->subtree_capture_id());
new_layer->SetCacheRenderSurface(cc_layer_->cache_render_surface());
new_layer->SetTrilinearFiltering(cc_layer_->trilinear_filtering());
new_layer->SetRoundedCorner(cc_layer_->corner_radii());
@@ -1299,7 +1308,7 @@ void Layer::RequestCopyOfOutput(
cc_layer_->RequestCopyOfOutput(std::move(request));
}
-gfx::Rect Layer::PaintableRegion() {
+gfx::Rect Layer::PaintableRegion() const {
return gfx::Rect(size());
}
diff --git a/chromium/ui/compositor/layer.h b/chromium/ui/compositor/layer.h
index 62d5959a60a..e82ad7e1692 100644
--- a/chromium/ui/compositor/layer.h
+++ b/chromium/ui/compositor/layer.h
@@ -23,6 +23,7 @@
#include "cc/layers/surface_layer.h"
#include "cc/layers/texture_layer_client.h"
#include "components/viz/common/resources/transferable_resource.h"
+#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer_animation_delegate.h"
@@ -169,6 +170,23 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
// been set. Will not return NULL.
LayerAnimator* GetAnimator();
+ // Sets the given |subtree_id| on the cc::Layer associated with this, so that
+ // the layer subtree rooted here can be uniquely identified by a
+ // FrameSinkVideoCapturer. The existence of a valid SubtreeCaptureId on this
+ // layer will force it to be drawn into a separate CompositorRenderPass.
+ // Setting a non-valid (i.e. default-constructed SubtreeCaptureId) will clear
+ // this property.
+ // It is not allowed to change this ID from a valid ID to another valid ID,
+ // since a client might already using the existing valid ID to make this layer
+ // subtree identifiable by a capturer.
+ //
+ // Note that this is useful when it's desired to video record a layer subtree
+ // of a non-root layer using a FrameSinkVideoCapturer, since non-root layers
+ // are usually not drawn into their own CompositorRenderPass, while the ui
+ // compositor's root layer always is.
+ void SetSubtreeCaptureId(viz::SubtreeCaptureId subtree_id);
+ viz::SubtreeCaptureId GetSubtreeCaptureId() const;
+
// The transform, relative to the parent.
void SetTransform(const gfx::Transform& transform);
const gfx::Transform& transform() const { return cc_layer_->transform(); }
@@ -440,7 +458,7 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
void SetScrollOffset(const gfx::ScrollOffset& offset);
// ContentLayerClient implementation.
- gfx::Rect PaintableRegion() override;
+ gfx::Rect PaintableRegion() const override;
scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList() override;
bool FillsBoundsCompletely() const override;
diff --git a/chromium/ui/compositor/layer_animation_element.cc b/chromium/ui/compositor/layer_animation_element.cc
index c8aac298abb..9a9054a4a05 100644
--- a/chromium/ui/compositor/layer_animation_element.cc
+++ b/chromium/ui/compositor/layer_animation_element.cc
@@ -447,12 +447,12 @@ class ThreadedOpacityTransition : public ThreadedLayerAnimationElement {
}
std::unique_ptr<cc::KeyframeModel> CreateCCKeyframeModel() override {
- std::unique_ptr<cc::AnimationCurve> animation_curve(
+ std::unique_ptr<gfx::AnimationCurve> animation_curve(
new FloatAnimationCurveAdapter(tween_type(), start_, target_,
duration()));
std::unique_ptr<cc::KeyframeModel> keyframe_model(cc::KeyframeModel::Create(
std::move(animation_curve), keyframe_model_id(), animation_group_id(),
- cc::TargetProperty::OPACITY));
+ cc::KeyframeModel::TargetPropertyId(cc::TargetProperty::OPACITY)));
return keyframe_model;
}
@@ -517,12 +517,12 @@ class ThreadedTransformTransition : public ThreadedLayerAnimationElement {
}
std::unique_ptr<cc::KeyframeModel> CreateCCKeyframeModel() override {
- std::unique_ptr<cc::AnimationCurve> animation_curve(
+ std::unique_ptr<gfx::AnimationCurve> animation_curve(
new TransformAnimationCurveAdapter(tween_type(), start_, target_,
duration()));
std::unique_ptr<cc::KeyframeModel> keyframe_model(cc::KeyframeModel::Create(
std::move(animation_curve), keyframe_model_id(), animation_group_id(),
- cc::TargetProperty::TRANSFORM));
+ cc::KeyframeModel::TargetPropertyId(cc::TargetProperty::TRANSFORM)));
return keyframe_model;
}
diff --git a/chromium/ui/compositor/layer_animation_observer.cc b/chromium/ui/compositor/layer_animation_observer.cc
index 043176d6ccd..e6580c2b081 100644
--- a/chromium/ui/compositor/layer_animation_observer.cc
+++ b/chromium/ui/compositor/layer_animation_observer.cc
@@ -58,13 +58,9 @@ void LayerAnimationObserver::DetachedFromSequence(
////////////////////////////////////////////////////////////////////////////////
// ImplicitAnimationObserver
-ImplicitAnimationObserver::ImplicitAnimationObserver()
- : active_(false), destroyed_(nullptr), first_sequence_scheduled_(false) {}
+ImplicitAnimationObserver::ImplicitAnimationObserver() = default;
-ImplicitAnimationObserver::~ImplicitAnimationObserver() {
- if (destroyed_)
- *destroyed_ = true;
-}
+ImplicitAnimationObserver::~ImplicitAnimationObserver() = default;
void ImplicitAnimationObserver::SetActive(bool active) {
active_ = active;
@@ -89,12 +85,10 @@ bool ImplicitAnimationObserver::WasAnimationCompletedForProperty(
void ImplicitAnimationObserver::OnLayerAnimationEnded(
LayerAnimationSequence* sequence) {
UpdatePropertyAnimationStatus(sequence, ANIMATION_STATUS_COMPLETED);
- bool destroyed = false;
- destroyed_ = &destroyed;
+ auto weak_this = weak_factory_.GetWeakPtr();
sequence->RemoveObserver(this);
- if (destroyed)
+ if (!weak_this)
return;
- destroyed_ = nullptr;
DCHECK(attached_sequences().find(sequence) == attached_sequences().end());
CheckCompleted();
}
@@ -102,12 +96,10 @@ void ImplicitAnimationObserver::OnLayerAnimationEnded(
void ImplicitAnimationObserver::OnLayerAnimationAborted(
LayerAnimationSequence* sequence) {
UpdatePropertyAnimationStatus(sequence, ANIMATION_STATUS_ABORTED);
- bool destroyed = false;
- destroyed_ = &destroyed;
+ auto weak_this = weak_factory_.GetWeakPtr();
sequence->RemoveObserver(this);
- if (destroyed)
+ if (!weak_this)
return;
- destroyed_ = nullptr;
DCHECK(attached_sequences().find(sequence) == attached_sequences().end());
CheckCompleted();
}
diff --git a/chromium/ui/compositor/layer_animation_observer.h b/chromium/ui/compositor/layer_animation_observer.h
index eb460da8533..c58f37a079c 100644
--- a/chromium/ui/compositor/layer_animation_observer.h
+++ b/chromium/ui/compositor/layer_animation_observer.h
@@ -9,6 +9,7 @@
#include <set>
#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
#include "ui/compositor/compositor_export.h"
#include "ui/compositor/layer_animation_element.h"
@@ -33,6 +34,10 @@ class COMPOSITOR_EXPORT LayerAnimationObserver {
virtual void OnLayerAnimationEnded(
LayerAnimationSequence* sequence) = 0;
+ // Called when a |sequence| repetition ends and will repeat. Not called if
+ // |sequence| is aborted.
+ virtual void OnLayerAnimationWillRepeat(LayerAnimationSequence* sequence) {}
+
// Called if |sequence| is aborted for any reason. Should never do anything
// that may cause another animation to be started.
virtual void OnLayerAnimationAborted(
@@ -162,18 +167,17 @@ class COMPOSITOR_EXPORT ImplicitAnimationObserver
AnimationStatus AnimationStatusForProperty(
LayerAnimationElement::AnimatableProperty property) const;
- bool active_;
-
- // Set to true in the destructor (if non-NULL). Used to detect deletion while
- // calling out.
- bool* destroyed_;
+ bool active_ = false;
typedef std::map<LayerAnimationElement::AnimatableProperty,
AnimationStatus> PropertyAnimationStatusMap;
PropertyAnimationStatusMap property_animation_status_;
// True if OnLayerAnimationScheduled() has been called at least once.
- bool first_sequence_scheduled_;
+ bool first_sequence_scheduled_ = false;
+
+ // For tracking whether this object has been destroyed. Must be last.
+ base::WeakPtrFactory<ImplicitAnimationObserver> weak_factory_{this};
};
} // namespace ui
diff --git a/chromium/ui/compositor/layer_animation_sequence.cc b/chromium/ui/compositor/layer_animation_sequence.cc
index 25d73903cb8..13f8b14d219 100644
--- a/chromium/ui/compositor/layer_animation_sequence.cc
+++ b/chromium/ui/compositor/layer_animation_sequence.cc
@@ -18,7 +18,7 @@ namespace ui {
LayerAnimationSequence::LayerAnimationSequence()
: properties_(LayerAnimationElement::UNKNOWN),
- is_cyclic_(false),
+ is_repeating_(false),
last_element_(0),
waiting_for_group_start_(false),
animation_group_id_(0),
@@ -27,7 +27,7 @@ LayerAnimationSequence::LayerAnimationSequence()
LayerAnimationSequence::LayerAnimationSequence(
std::unique_ptr<LayerAnimationElement> element)
: properties_(LayerAnimationElement::UNKNOWN),
- is_cyclic_(false),
+ is_repeating_(false),
last_element_(0),
waiting_for_group_start_(false),
animation_group_id_(0),
@@ -66,8 +66,9 @@ void LayerAnimationSequence::Progress(base::TimeTicks now,
last_start_ = start_time_;
size_t current_index = last_element_ % elements_.size();
+ bool just_completed_sequence = false;
base::TimeDelta element_duration;
- while (is_cyclic_ || last_element_ < elements_.size()) {
+ while (is_repeating_ || last_element_ < elements_.size()) {
elements_[current_index]->set_requested_start_time(last_start_);
if (!elements_[current_index]->IsFinished(now, &element_duration))
break;
@@ -80,9 +81,11 @@ void LayerAnimationSequence::Progress(base::TimeTicks now,
last_progressed_fraction_ =
elements_[current_index]->last_progressed_fraction();
current_index = last_element_ % elements_.size();
+ DCHECK_GT(last_element_, 0u);
+ just_completed_sequence = current_index == 0;
}
- if (is_cyclic_ || last_element_ < elements_.size()) {
+ if (is_repeating_ || last_element_ < elements_.size()) {
if (!elements_[current_index]->Started()) {
animation_group_id_ = cc::AnimationIdProvider::NextGroupId();
elements_[current_index]->Start(delegate, animation_group_id_);
@@ -101,16 +104,20 @@ void LayerAnimationSequence::Progress(base::TimeTicks now,
if (redraw_required)
delegate->ScheduleDrawForAnimation();
- if (!is_cyclic_ && last_element_ == elements_.size()) {
- last_element_ = 0;
- waiting_for_group_start_ = false;
- animation_group_id_ = 0;
- NotifyEnded();
+ if (just_completed_sequence) {
+ if (!is_repeating_) {
+ last_element_ = 0;
+ waiting_for_group_start_ = false;
+ animation_group_id_ = 0;
+ NotifyEnded();
+ } else {
+ NotifyWillRepeat();
+ }
}
}
bool LayerAnimationSequence::IsFinished(base::TimeTicks time) {
- if (is_cyclic_ || waiting_for_group_start_)
+ if (is_repeating_ || waiting_for_group_start_)
return false;
if (elements_.empty())
@@ -153,17 +160,19 @@ void LayerAnimationSequence::ProgressToEnd(LayerAnimationDelegate* delegate) {
if (redraw_required)
delegate->ScheduleDrawForAnimation();
- if (!is_cyclic_) {
+ if (!is_repeating_) {
last_element_ = 0;
waiting_for_group_start_ = false;
animation_group_id_ = 0;
NotifyEnded();
+ } else {
+ NotifyWillRepeat();
}
}
void LayerAnimationSequence::GetTargetValue(
LayerAnimationElement::TargetValue* target) const {
- if (is_cyclic_)
+ if (is_repeating_)
return;
for (size_t i = last_element_; i < elements_.size(); ++i)
@@ -280,6 +289,11 @@ void LayerAnimationSequence::NotifyEnded() {
observer.OnLayerAnimationEnded(this);
}
+void LayerAnimationSequence::NotifyWillRepeat() {
+ for (auto& observer : observers_)
+ observer.OnLayerAnimationWillRepeat(this);
+}
+
void LayerAnimationSequence::NotifyAborted() {
for (auto& observer : observers_)
observer.OnLayerAnimationAborted(this);
@@ -306,10 +320,10 @@ std::string LayerAnimationSequence::ElementsToString() const {
std::string LayerAnimationSequence::ToString() const {
return base::StringPrintf(
"LayerAnimationSequence{size=%zu, properties=%s, "
- "elements=[%s], is_cyclic=%d, group_id=%d}",
+ "elements=[%s], is_repeating=%d, group_id=%d}",
size(),
LayerAnimationElement::AnimatablePropertiesToString(properties_).c_str(),
- ElementsToString().c_str(), is_cyclic_, animation_group_id_);
+ ElementsToString().c_str(), is_repeating_, animation_group_id_);
}
} // namespace ui
diff --git a/chromium/ui/compositor/layer_animation_sequence.h b/chromium/ui/compositor/layer_animation_sequence.h
index 88208f1e4e7..08b8f8389f8 100644
--- a/chromium/ui/compositor/layer_animation_sequence.h
+++ b/chromium/ui/compositor/layer_animation_sequence.h
@@ -74,11 +74,12 @@ class COMPOSITOR_EXPORT LayerAnimationSequence
bool IsFinished(base::TimeTicks time);
// Updates the delegate to the end of the animation; if this sequence is
- // cyclic, updates the delegate to the end of one cycle of the sequence.
+ // repeating, updates the delegate to the end of one repetition of the
+ // sequence.
void ProgressToEnd(LayerAnimationDelegate* delegate);
// Sets the target value to the value that would have been set had
- // the sequence completed. Does nothing if the sequence is cyclic.
+ // the sequence completed. Does nothing if the sequence is repeating.
void GetTargetValue(LayerAnimationElement::TargetValue* target) const;
// Aborts the given animation.
@@ -93,9 +94,9 @@ class COMPOSITOR_EXPORT LayerAnimationSequence
// element.
void AddElement(std::unique_ptr<LayerAnimationElement> element);
- // Sequences can be looped indefinitely.
- void set_is_cyclic(bool is_cyclic) { is_cyclic_ = is_cyclic; }
- bool is_cyclic() const { return is_cyclic_; }
+ // Sequences can repeat indefinitely.
+ void set_is_repeating(bool is_repeating) { is_repeating_ = is_repeating; }
+ bool is_repeating() const { return is_repeating_; }
// Returns true if this sequence has at least one element conflicting with a
// property in |other|.
@@ -160,6 +161,9 @@ class COMPOSITOR_EXPORT LayerAnimationSequence
// Notifies the observers that this sequence has ended.
void NotifyEnded();
+ // Notifies the observers that this sequence has ended and will repeat.
+ void NotifyWillRepeat();
+
// Notifies the observers that this sequence has been aborted.
void NotifyAborted();
@@ -173,7 +177,7 @@ class COMPOSITOR_EXPORT LayerAnimationSequence
Elements elements_;
// True if the sequence should be looped forever.
- bool is_cyclic_;
+ bool is_repeating_;
// These are used when animating to efficiently find the next element.
size_t last_element_;
diff --git a/chromium/ui/compositor/layer_animation_sequence_unittest.cc b/chromium/ui/compositor/layer_animation_sequence_unittest.cc
index 40585016387..61ce039f820 100644
--- a/chromium/ui/compositor/layer_animation_sequence_unittest.cc
+++ b/chromium/ui/compositor/layer_animation_sequence_unittest.cc
@@ -112,7 +112,8 @@ TEST(LayerAnimationSequenceTest, SingleThreadedElement) {
}
// Check that the sequences progresses the delegate as expected when it contains
-// multiple elements. Note, see the layer animator tests for cyclic sequences.
+// multiple elements. Note, see the layer animator tests for repeating
+// sequences.
TEST(LayerAnimationSequenceTest, MultipleElement) {
LayerAnimationSequence sequence;
TestLayerAnimationDelegate delegate;
@@ -197,8 +198,8 @@ TEST(LayerAnimationSequenceTest, MultipleElement) {
sequence.properties());
}
-// Check that a sequence can still be aborted if it has cycled many times.
-TEST(LayerAnimationSequenceTest, AbortingCyclicSequence) {
+// Check that a sequence can still be aborted if it has repeated many times.
+TEST(LayerAnimationSequenceTest, AbortingRepeatingSequence) {
LayerAnimationSequence sequence;
TestLayerAnimationDelegate delegate;
float start_brightness = 0.0f;
@@ -211,7 +212,7 @@ TEST(LayerAnimationSequenceTest, AbortingCyclicSequence) {
sequence.AddElement(
LayerAnimationElement::CreateBrightnessElement(start_brightness, delta));
- sequence.set_is_cyclic(true);
+ sequence.set_is_repeating(true);
delegate.SetBrightnessFromAnimation(start_brightness,
PropertyChangeReason::NOT_FROM_ANIMATION);
@@ -235,7 +236,7 @@ TEST(LayerAnimationSequenceTest, AbortingCyclicSequence) {
}
// Check that a sequence can be 'fast-forwarded' to the end and the target set.
-// Also check that this has no effect if the sequence is cyclic.
+// Also check that this has no effect if the sequence is repeating.
TEST(LayerAnimationSequenceTest, SetTarget) {
LayerAnimationSequence sequence;
TestLayerAnimationDelegate delegate;
@@ -250,7 +251,7 @@ TEST(LayerAnimationSequenceTest, SetTarget) {
sequence.GetTargetValue(&target_value);
EXPECT_FLOAT_EQ(target_opacity, target_value.opacity);
- sequence.set_is_cyclic(true);
+ sequence.set_is_repeating(true);
target_value.opacity = start_opacity;
sequence.GetTargetValue(&target_value);
EXPECT_FLOAT_EQ(start_opacity, target_value.opacity);
@@ -279,7 +280,8 @@ TEST(LayerAnimationSequenceTest, ToString) {
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
LayerAnimationSequence sequence;
EXPECT_EQ(
- "LayerAnimationSequence{size=0, properties=, elements=[], is_cyclic=0, "
+ "LayerAnimationSequence{size=0, properties=, elements=[], "
+ "is_repeating=0, "
"group_id=0}",
sequence.ToString());
@@ -292,7 +294,7 @@ TEST(LayerAnimationSequenceTest, ToString) {
"LayerAnimationSequence{size=1, properties=BRIGHTNESS, "
"elements=[LayerAnimationElement{name=BrightnessTransition, id=%d, "
"group=0, last_progressed_fraction=0.00}], "
- "is_cyclic=0, group_id=0}",
+ "is_repeating=0, group_id=0}",
brightness_id),
sequence.ToString());
@@ -300,7 +302,7 @@ TEST(LayerAnimationSequenceTest, ToString) {
LayerAnimationElement::CreateOpacityElement(1.0f, delta);
int opacity_id = opacity->keyframe_model_id();
sequence.AddElement(std::move(opacity));
- sequence.set_is_cyclic(true);
+ sequence.set_is_repeating(true);
sequence.set_animation_group_id(1973);
EXPECT_EQ(
base::StringPrintf(
@@ -309,7 +311,7 @@ TEST(LayerAnimationSequenceTest, ToString) {
"group=0, last_progressed_fraction=0.00}, "
"LayerAnimationElement{name=ThreadedOpacityTransition, id=%d, "
"group=0, "
- "last_progressed_fraction=0.00}], is_cyclic=1, "
+ "last_progressed_fraction=0.00}], is_repeating=1, "
"group_id=1973}",
brightness_id, opacity_id),
sequence.ToString());
diff --git a/chromium/ui/compositor/layer_animator.cc b/chromium/ui/compositor/layer_animator.cc
index c200f61ebe0..a5795296ca1 100644
--- a/chromium/ui/compositor/layer_animator.cc
+++ b/chromium/ui/compositor/layer_animator.cc
@@ -91,6 +91,8 @@ LayerAnimator* LayerAnimator::CreateImplicitAnimator() {
if (duration.is_zero() && delegate() && \
(preemption_strategy_ != ENQUEUE_NEW_ANIMATION)) { \
StopAnimatingProperty(LayerAnimationElement::property); \
+ if (!delegate()) \
+ return; \
delegate()->Set##name##FromAnimation( \
value, PropertyChangeReason::NOT_FROM_ANIMATION); \
return; \
diff --git a/chromium/ui/compositor/layer_animator.h b/chromium/ui/compositor/layer_animator.h
index 8c02356a38a..80020984c1d 100644
--- a/chromium/ui/compositor/layer_animator.h
+++ b/chromium/ui/compositor/layer_animator.h
@@ -29,6 +29,7 @@ class Layer;
namespace gfx {
class Animation;
+class AnimationCurve;
class Rect;
class Transform;
}
@@ -375,7 +376,7 @@ class COMPOSITOR_EXPORT LayerAnimator : public base::RefCounted<LayerAnimator>,
base::TimeTicks monotonic_time,
int target_property,
base::TimeTicks animation_start_time,
- std::unique_ptr<cc::AnimationCurve> curve) override {}
+ std::unique_ptr<gfx::AnimationCurve> curve) override {}
void NotifyLocalTimeUpdated(
base::Optional<base::TimeDelta> local_time) override {}
diff --git a/chromium/ui/compositor/layer_animator_unittest.cc b/chromium/ui/compositor/layer_animator_unittest.cc
index 3e86fb5ac66..f801537c29e 100644
--- a/chromium/ui/compositor/layer_animator_unittest.cc
+++ b/chromium/ui/compositor/layer_animator_unittest.cc
@@ -1563,7 +1563,7 @@ TEST(LayerAnimatorTest, CyclicSequences) {
sequence->AddElement(
LayerAnimationElement::CreateBrightnessElement(start_brightness, delta));
- sequence->set_is_cyclic(true);
+ sequence->set_is_repeating(true);
animator->StartAnimation(sequence.release());
@@ -1622,7 +1622,7 @@ TEST(LayerAnimatorTest, ThreadedCyclicSequences) {
sequence->AddElement(
LayerAnimationElement::CreateOpacityElement(start_opacity, delta));
- sequence->set_is_cyclic(true);
+ sequence->set_is_repeating(true);
test_controller.animator()->StartAnimation(sequence.release());
@@ -2476,13 +2476,13 @@ TEST(LayerAnimatorTest, ObserverReleasedBeforeAnimationSequenceEnds) {
animator->StartAnimation(sequence);
// |observer| should be attached to |sequence|.
- EXPECT_TRUE(sequence->observers_.might_have_observers());
+ EXPECT_TRUE(!sequence->observers_.empty());
// Now, release |observer|
observer.reset();
// And |sequence| should no longer be attached to |observer|.
- EXPECT_FALSE(sequence->observers_.might_have_observers());
+ EXPECT_FALSE(!sequence->observers_.empty());
}
TEST(LayerAnimatorTest, ObserverAttachedAfterAnimationStarted) {
@@ -3433,49 +3433,129 @@ TEST(LayerAnimatorTest, ObserverDeletesLayerInStopAnimating) {
EXPECT_TRUE(animator->is_animating());
}
+TEST(LayerAnimatorTest,
+ SetPropertyWithObserverThatDeletesLayerInStopAnimating) {
+ scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator());
+ LayerOwnerAnimationObserver observer(animator.get());
+ LayerAnimationDelegate* delegate = observer.animator_layer();
+
+ const double target_opacity = 1.0;
+ delegate->SetOpacityFromAnimation(0.0f,
+ PropertyChangeReason::NOT_FROM_ANIMATION);
+
+ base::TimeDelta time_delta = base::TimeDelta::FromSeconds(1);
+ LayerAnimationSequence* opacity = new LayerAnimationSequence(
+ LayerAnimationElement::CreateOpacityElement(target_opacity, time_delta));
+ opacity->AddObserver(&observer);
+ animator->ScheduleAnimation(opacity);
+ animator->Step(animator->last_step_time() +
+ base::TimeDelta::FromMilliseconds(500));
+ EXPECT_TRUE(animator->is_animating());
+
+ animator->SetOpacity(1.0f);
+ EXPECT_EQ(nullptr, observer.animator_layer());
+ EXPECT_FALSE(animator->is_animating());
+}
+
+class CountCyclesObserver : public LayerAnimationObserver {
+ public:
+ explicit CountCyclesObserver(ui::LayerAnimator* animator)
+ : animator_(animator) {
+ animator_->AddObserver(this);
+ }
+ ~CountCyclesObserver() override { animator_->RemoveObserver(this); }
+ CountCyclesObserver(const CountCyclesObserver&) = delete;
+ CountCyclesObserver& operator=(const CountCyclesObserver&) = delete;
+
+ void OnLayerAnimationEnded(LayerAnimationSequence* sequence) override {}
+
+ void OnLayerAnimationAborted(LayerAnimationSequence* sequence) override {}
+
+ void OnLayerAnimationWillRepeat(LayerAnimationSequence* sequence) override {
+ cycles_count_++;
+ }
+
+ void OnLayerAnimationScheduled(LayerAnimationSequence* sequence) override {}
+
+ int cycles_count() { return cycles_count_; }
+
+ private:
+ ui::LayerAnimator* animator_;
+ int cycles_count_ = 0;
+};
+
+// Verifies that an observer is notified each time a LayerAnimationSequence's
+// cycle has ended.
+TEST(LayerAnimatorTest, ObserverGetsNotifiedOnCycleEnded) {
+ TestLayerAnimationDelegate delegate;
+ scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
+ CountCyclesObserver observer(animator.get());
+
+ constexpr base::TimeDelta kAnimationDuration =
+ base::TimeDelta::FromSeconds(1);
+ LayerAnimationSequence* sequence = new LayerAnimationSequence(
+ LayerAnimationElement::CreateBrightnessElement(1.0f, kAnimationDuration));
+ sequence->set_is_repeating(true);
+ animator->StartAnimation(sequence);
+
+ for (int i = 0; i < 3; i++) {
+ EXPECT_EQ(observer.cycles_count(), i);
+ const base::TimeTicks last_time = animator->last_step_time();
+ animator->Step(last_time + kAnimationDuration);
+ }
+}
+
// Verifies the LayerAnimatorObserver notification order for an animation
// sequence that completes successfully.
TEST(LayerAnimatorObserverNotificationOrderTest,
SuccessfulCompletionOfSequence) {
- TestLayerAnimationObserver observer;
- TestLayerAnimationDelegate delegate;
- scoped_refptr<LayerAnimator> animator(
- CreateDefaultTestAnimator(&delegate, &observer));
- observer.set_requires_notification_when_animator_destroyed(true);
+ for (int is_cyclic = 0; is_cyclic <= 0; is_cyclic++) {
+ TestLayerAnimationObserver observer;
+ TestLayerAnimationDelegate delegate;
+ scoped_refptr<LayerAnimator> animator(
+ CreateDefaultTestAnimator(&delegate, &observer));
+ observer.set_requires_notification_when_animator_destroyed(true);
- const base::TimeDelta animation_duration = base::TimeDelta::FromSeconds(100);
+ const base::TimeDelta animation_duration =
+ base::TimeDelta::FromSeconds(100);
- LayerAnimationSequence* sequence = new LayerAnimationSequence(
- LayerAnimationElement::CreateBrightnessElement(1.0f, animation_duration));
+ LayerAnimationSequence* sequence = new LayerAnimationSequence(
+ LayerAnimationElement::CreateBrightnessElement(1.0f,
+ animation_duration));
+ sequence->set_is_repeating(is_cyclic);
- EXPECT_TRUE(observer.NoEventsObserved());
+ EXPECT_TRUE(observer.NoEventsObserved());
- animator->StartAnimation(sequence);
+ animator->StartAnimation(sequence);
- EXPECT_EQ(observer.last_attached_sequence(), sequence);
- EXPECT_EQ(observer.last_scheduled_sequence(), sequence);
- EXPECT_EQ(observer.last_started_sequence(), sequence);
- EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
- EXPECT_EQ(observer.last_ended_sequence(), nullptr);
- EXPECT_EQ(observer.last_detached_sequence(), nullptr);
+ EXPECT_EQ(observer.last_attached_sequence(), sequence);
+ EXPECT_EQ(observer.last_scheduled_sequence(), sequence);
+ EXPECT_EQ(observer.last_started_sequence(), sequence);
+ EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
+ EXPECT_EQ(observer.last_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_repetition_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_detached_sequence(), nullptr);
- EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
- EXPECT_TRUE(observer.ScheduledEpochIsBeforeStartedEpoch());
+ EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
+ EXPECT_TRUE(observer.ScheduledEpochIsBeforeStartedEpoch());
- observer.ResetLayerAnimationObserverations();
+ observer.ResetLayerAnimationObserverations();
- const base::TimeTicks start_time = animator->last_step_time();
+ const base::TimeTicks start_time = animator->last_step_time();
- animator->Step(start_time + animation_duration);
+ animator->Step(start_time + animation_duration);
- EXPECT_EQ(observer.last_attached_sequence(), nullptr);
- EXPECT_EQ(observer.last_scheduled_sequence(), nullptr);
- EXPECT_EQ(observer.last_started_sequence(), nullptr);
- EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
- EXPECT_EQ(observer.last_ended_sequence(), sequence);
- EXPECT_EQ(observer.last_detached_sequence(), sequence);
+ EXPECT_EQ(observer.last_attached_sequence(), nullptr);
+ EXPECT_EQ(observer.last_scheduled_sequence(), nullptr);
+ EXPECT_EQ(observer.last_started_sequence(), nullptr);
+ EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
+ EXPECT_EQ(observer.last_ended_sequence(), is_cyclic ? nullptr : sequence);
+ EXPECT_EQ(observer.last_repetition_ended_sequence(),
+ is_cyclic ? sequence : nullptr);
+ EXPECT_EQ(observer.last_detached_sequence(), sequence);
- EXPECT_TRUE(observer.EndedEpochIsBeforeDetachedEpoch());
+ EXPECT_TRUE(observer.EndedEpochIsBeforeDetachedEpoch());
+ }
}
// Verifies the LayerAnimatorObserver notification order for an animation
@@ -3501,6 +3581,7 @@ TEST(LayerAnimatorObserverNotificationOrderTest, AbortingAScheduledSequence) {
EXPECT_EQ(observer.last_started_sequence(), sequence);
EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
EXPECT_EQ(observer.last_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_repetition_ended_sequence(), nullptr);
EXPECT_EQ(observer.last_detached_sequence(), nullptr);
EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
@@ -3515,6 +3596,7 @@ TEST(LayerAnimatorObserverNotificationOrderTest, AbortingAScheduledSequence) {
EXPECT_EQ(observer.last_started_sequence(), nullptr);
EXPECT_EQ(observer.last_aborted_sequence(), sequence);
EXPECT_EQ(observer.last_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_repetition_ended_sequence(), nullptr);
EXPECT_EQ(observer.last_detached_sequence(), sequence);
EXPECT_TRUE(observer.AbortedEpochIsBeforeDetachedEpoch());
@@ -3525,63 +3607,75 @@ TEST(LayerAnimatorObserverNotificationOrderTest, AbortingAScheduledSequence) {
// completes successfully.
TEST(LayerAnimatorObserverNotificationOrderTest,
RunningASequenceThatIsQueuedForLaterStartTime) {
- TestLayerAnimationObserver observer;
- TestLayerAnimationDelegate delegate;
- scoped_refptr<LayerAnimator> animator(
- CreateDefaultTestAnimator(&delegate, &observer));
- observer.set_requires_notification_when_animator_destroyed(true);
+ for (int is_cyclic = 0; is_cyclic <= 0; is_cyclic++) {
+ TestLayerAnimationObserver observer;
+ TestLayerAnimationDelegate delegate;
+ scoped_refptr<LayerAnimator> animator(
+ CreateDefaultTestAnimator(&delegate, &observer));
+ observer.set_requires_notification_when_animator_destroyed(true);
- const base::TimeDelta animation_duration = base::TimeDelta::FromSeconds(100);
+ const base::TimeDelta animation_duration =
+ base::TimeDelta::FromSeconds(100);
- LayerAnimationSequence* first_sequence = new LayerAnimationSequence(
- LayerAnimationElement::CreateBrightnessElement(1.0f, animation_duration));
+ LayerAnimationSequence* first_sequence = new LayerAnimationSequence(
+ LayerAnimationElement::CreateBrightnessElement(1.0f,
+ animation_duration));
+ first_sequence->set_is_repeating(is_cyclic);
- LayerAnimationSequence* queued_sequence = new LayerAnimationSequence(
- LayerAnimationElement::CreateBrightnessElement(1.0f, animation_duration));
+ LayerAnimationSequence* queued_sequence = new LayerAnimationSequence(
+ LayerAnimationElement::CreateBrightnessElement(1.0f,
+ animation_duration));
+ queued_sequence->set_is_repeating(is_cyclic);
- EXPECT_TRUE(observer.NoEventsObserved());
+ EXPECT_TRUE(observer.NoEventsObserved());
- animator->StartAnimation(first_sequence);
+ animator->StartAnimation(first_sequence);
- EXPECT_EQ(observer.last_attached_sequence(), first_sequence);
- EXPECT_EQ(observer.last_scheduled_sequence(), first_sequence);
- EXPECT_EQ(observer.last_started_sequence(), first_sequence);
- EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
- EXPECT_EQ(observer.last_ended_sequence(), nullptr);
- EXPECT_EQ(observer.last_detached_sequence(), nullptr);
+ EXPECT_EQ(observer.last_attached_sequence(), first_sequence);
+ EXPECT_EQ(observer.last_scheduled_sequence(), first_sequence);
+ EXPECT_EQ(observer.last_started_sequence(), first_sequence);
+ EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
+ EXPECT_EQ(observer.last_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_repetition_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_detached_sequence(), nullptr);
- EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
- EXPECT_TRUE(observer.ScheduledEpochIsBeforeStartedEpoch());
+ EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
+ EXPECT_TRUE(observer.ScheduledEpochIsBeforeStartedEpoch());
- observer.ResetLayerAnimationObserverations();
+ observer.ResetLayerAnimationObserverations();
- animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);
- animator->StartAnimation(queued_sequence);
+ animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);
+ animator->StartAnimation(queued_sequence);
- EXPECT_EQ(observer.last_attached_sequence(), queued_sequence);
- EXPECT_EQ(observer.last_scheduled_sequence(), queued_sequence);
- EXPECT_EQ(observer.last_started_sequence(), nullptr);
- EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
- EXPECT_EQ(observer.last_ended_sequence(), nullptr);
- EXPECT_EQ(observer.last_detached_sequence(), nullptr);
+ EXPECT_EQ(observer.last_attached_sequence(), queued_sequence);
+ EXPECT_EQ(observer.last_scheduled_sequence(), queued_sequence);
+ EXPECT_EQ(observer.last_started_sequence(), nullptr);
+ EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
+ EXPECT_EQ(observer.last_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_repetition_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_detached_sequence(), nullptr);
- EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
+ EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
- observer.ResetLayerAnimationObserverations();
+ observer.ResetLayerAnimationObserverations();
- base::TimeTicks start_time = animator->last_step_time();
+ base::TimeTicks start_time = animator->last_step_time();
- animator->Step(start_time + animation_duration);
+ animator->Step(start_time + animation_duration);
- EXPECT_EQ(observer.last_attached_sequence(), nullptr);
- EXPECT_EQ(observer.last_scheduled_sequence(), nullptr);
- EXPECT_EQ(observer.last_started_sequence(), queued_sequence);
- EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
- EXPECT_EQ(observer.last_ended_sequence(), first_sequence);
- EXPECT_EQ(observer.last_detached_sequence(), first_sequence);
+ EXPECT_EQ(observer.last_attached_sequence(), nullptr);
+ EXPECT_EQ(observer.last_scheduled_sequence(), nullptr);
+ EXPECT_EQ(observer.last_started_sequence(), queued_sequence);
+ EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
+ EXPECT_EQ(observer.last_ended_sequence(),
+ is_cyclic ? nullptr : first_sequence);
+ EXPECT_EQ(observer.last_repetition_ended_sequence(),
+ is_cyclic ? first_sequence : nullptr);
+ EXPECT_EQ(observer.last_detached_sequence(), first_sequence);
- EXPECT_TRUE(observer.EndedEpochIsBeforeDetachedEpoch());
- EXPECT_TRUE(observer.EndedEpochIsBeforeStartedEpoch());
+ EXPECT_TRUE(observer.EndedEpochIsBeforeDetachedEpoch());
+ EXPECT_TRUE(observer.EndedEpochIsBeforeStartedEpoch());
+ }
}
// Verifies the LayerAnimatorObserver notification order for an animation
@@ -3611,6 +3705,7 @@ TEST(LayerAnimatorObserverNotificationOrderTest,
EXPECT_EQ(observer.last_started_sequence(), first_sequence);
EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
EXPECT_EQ(observer.last_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_repetition_ended_sequence(), nullptr);
EXPECT_EQ(observer.last_detached_sequence(), nullptr);
EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
@@ -3627,6 +3722,7 @@ TEST(LayerAnimatorObserverNotificationOrderTest,
EXPECT_EQ(observer.last_started_sequence(), queued_sequence);
EXPECT_EQ(observer.last_aborted_sequence(), first_sequence);
EXPECT_EQ(observer.last_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_repetition_ended_sequence(), nullptr);
EXPECT_EQ(observer.last_detached_sequence(), first_sequence);
EXPECT_TRUE(observer.AbortedEpochIsBeforeDetachedEpoch());
@@ -3639,36 +3735,43 @@ TEST(LayerAnimatorObserverNotificationOrderTest,
// has already been scheduled.
TEST(LayerAnimatorObserverNotificationOrderTest,
ObserverAddedAfterAnimationStarts) {
- TestLayerAnimationDelegate delegate;
- scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
+ for (int is_cyclic = 0; is_cyclic <= 0; is_cyclic++) {
+ TestLayerAnimationDelegate delegate;
+ scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
- constexpr base::TimeDelta kAnimationDuration =
- base::TimeDelta::FromSeconds(1);
- LayerAnimationSequence* sequence = new LayerAnimationSequence(
- LayerAnimationElement::CreateBrightnessElement(1.0f, kAnimationDuration));
- animator->StartAnimation(sequence);
+ constexpr base::TimeDelta kAnimationDuration =
+ base::TimeDelta::FromSeconds(1);
+ LayerAnimationSequence* sequence = new LayerAnimationSequence(
+ LayerAnimationElement::CreateBrightnessElement(1.0f,
+ kAnimationDuration));
+ sequence->set_is_repeating(is_cyclic);
+ animator->StartAnimation(sequence);
- TestLayerAnimationObserver observer;
- observer.set_requires_notification_when_animator_destroyed(true);
- animator->AddObserver(&observer);
+ TestLayerAnimationObserver observer;
+ observer.set_requires_notification_when_animator_destroyed(true);
+ animator->AddObserver(&observer);
- EXPECT_EQ(observer.last_attached_sequence(), sequence);
- EXPECT_EQ(observer.last_scheduled_sequence(), nullptr);
- EXPECT_EQ(observer.last_started_sequence(), nullptr);
- EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
- EXPECT_EQ(observer.last_ended_sequence(), nullptr);
- EXPECT_EQ(observer.last_detached_sequence(), nullptr);
+ EXPECT_EQ(observer.last_attached_sequence(), sequence);
+ EXPECT_EQ(observer.last_scheduled_sequence(), nullptr);
+ EXPECT_EQ(observer.last_started_sequence(), nullptr);
+ EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
+ EXPECT_EQ(observer.last_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_repetition_ended_sequence(), nullptr);
+ EXPECT_EQ(observer.last_detached_sequence(), nullptr);
- animator->StopAnimating();
+ animator->StopAnimating();
- EXPECT_EQ(observer.last_attached_sequence(), sequence);
- EXPECT_EQ(observer.last_scheduled_sequence(), nullptr);
- EXPECT_EQ(observer.last_started_sequence(), nullptr);
- EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
- EXPECT_EQ(observer.last_ended_sequence(), sequence);
- EXPECT_EQ(observer.last_detached_sequence(), sequence);
+ EXPECT_EQ(observer.last_attached_sequence(), sequence);
+ EXPECT_EQ(observer.last_scheduled_sequence(), nullptr);
+ EXPECT_EQ(observer.last_started_sequence(), nullptr);
+ EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
+ EXPECT_EQ(observer.last_ended_sequence(), is_cyclic ? nullptr : sequence);
+ EXPECT_EQ(observer.last_repetition_ended_sequence(),
+ is_cyclic ? sequence : nullptr);
+ EXPECT_EQ(observer.last_detached_sequence(), sequence);
- animator->RemoveObserver(&observer);
+ animator->RemoveObserver(&observer);
+ }
}
} // namespace ui
diff --git a/chromium/ui/compositor/layer_owner.h b/chromium/ui/compositor/layer_owner.h
index c541ca919c8..f3ea42e7eb8 100644
--- a/chromium/ui/compositor/layer_owner.h
+++ b/chromium/ui/compositor/layer_owner.h
@@ -44,7 +44,7 @@ class COMPOSITOR_EXPORT LayerOwner {
std::unique_ptr<Layer> AcquireLayer();
// Similar to AcquireLayer(), but layer() will be set to nullptr immediately.
- std::unique_ptr<Layer> ReleaseLayer();
+ virtual std::unique_ptr<Layer> ReleaseLayer();
// Releases the ownership of the current layer, and takes ownership of
// |layer|.
@@ -63,7 +63,7 @@ class COMPOSITOR_EXPORT LayerOwner {
bool OwnsLayer() const;
protected:
- void SetLayer(std::unique_ptr<Layer> layer);
+ virtual void SetLayer(std::unique_ptr<Layer> layer);
void DestroyLayer();
private:
diff --git a/chromium/ui/compositor/layer_unittest.cc b/chromium/ui/compositor/layer_unittest.cc
index b4db7e46388..4f2d5240c4a 100644
--- a/chromium/ui/compositor/layer_unittest.cc
+++ b/chromium/ui/compositor/layer_unittest.cc
@@ -39,6 +39,7 @@
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
+#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -755,6 +756,7 @@ TEST_F(LayerWithDelegateTest, Cloning) {
layer->SetClipRect(clip_rect);
layer->SetRoundedCornerRadius({1, 2, 4, 5});
layer->SetIsFastRoundedCorner(true);
+ layer->SetSubtreeCaptureId(viz::SubtreeCaptureId(1));
auto clone = layer->Clone();
@@ -773,6 +775,10 @@ TEST_F(LayerWithDelegateTest, Cloning) {
EXPECT_EQ(layer->rounded_corner_radii(), clone->rounded_corner_radii());
EXPECT_EQ(layer->is_fast_rounded_corner(), clone->is_fast_rounded_corner());
+ // However, the SubtreeCaptureId is not cloned.
+ EXPECT_TRUE(layer->GetSubtreeCaptureId().is_valid());
+ EXPECT_FALSE(clone->GetSubtreeCaptureId().is_valid());
+
layer->SetTransform(gfx::Transform());
layer->SetColor(SK_ColorGREEN);
layer->SetLayerInverted(false);
@@ -1018,6 +1024,8 @@ TEST_F(LayerWithNullDelegateTest, SwitchLayerPreservesCCLayerState) {
constexpr gfx::RoundedCornersF kCornerRadii(1, 2, 3, 4);
l1->SetRoundedCornerRadius(kCornerRadii);
l1->SetIsFastRoundedCorner(true);
+ constexpr viz::SubtreeCaptureId kSubtreeCaptureId(22);
+ l1->SetSubtreeCaptureId(kSubtreeCaptureId);
EXPECT_EQ(gfx::Point3F(), l1->cc_layer_for_testing()->transform_origin());
EXPECT_TRUE(l1->cc_layer_for_testing()->DrawsContent());
@@ -1027,6 +1035,9 @@ TEST_F(LayerWithNullDelegateTest, SwitchLayerPreservesCCLayerState) {
EXPECT_TRUE(l1->cc_layer_for_testing()->HasRoundedCorner());
EXPECT_EQ(l1->cc_layer_for_testing()->corner_radii(), kCornerRadii);
EXPECT_TRUE(l1->cc_layer_for_testing()->is_fast_rounded_corner());
+ EXPECT_EQ(kSubtreeCaptureId,
+ l1->cc_layer_for_testing()->subtree_capture_id());
+ EXPECT_EQ(kSubtreeCaptureId, l1->GetSubtreeCaptureId());
cc::Layer* before_layer = l1->cc_layer_for_testing();
@@ -1050,6 +1061,9 @@ TEST_F(LayerWithNullDelegateTest, SwitchLayerPreservesCCLayerState) {
EXPECT_TRUE(l1->cc_layer_for_testing()->HasRoundedCorner());
EXPECT_EQ(l1->cc_layer_for_testing()->corner_radii(), kCornerRadii);
EXPECT_TRUE(l1->cc_layer_for_testing()->is_fast_rounded_corner());
+ EXPECT_EQ(kSubtreeCaptureId,
+ l1->cc_layer_for_testing()->subtree_capture_id());
+ EXPECT_EQ(kSubtreeCaptureId, l1->GetSubtreeCaptureId());
EXPECT_FALSE(callback1_run);
bool callback2_run = false;
@@ -1867,7 +1881,13 @@ TEST_P(LayerWithRealCompositorTest, ModifyHierarchy) {
}
// Checks that basic background blur is working.
-TEST_P(LayerWithRealCompositorTest, BackgroundBlur) {
+// TODO(crbug.com/1174372) Flaky on Windows
+#if defined(OS_WIN)
+#define MAYBE_BackgroundBlur DISABLED_BackgroundBlur
+#else
+#define MAYBE_BackgroundBlur BackgroundBlur
+#endif
+TEST_P(LayerWithRealCompositorTest, MAYBE_BackgroundBlur) {
viz::ParentLocalSurfaceIdAllocator allocator;
allocator.GenerateId();
GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(200, 200),
diff --git a/chromium/ui/compositor/throughput_tracker.cc b/chromium/ui/compositor/throughput_tracker.cc
index 50e379fdc3f..95bcb01cd2a 100644
--- a/chromium/ui/compositor/throughput_tracker.cc
+++ b/chromium/ui/compositor/throughput_tracker.cc
@@ -55,7 +55,10 @@ void ThroughputTracker::Stop() {
}
void ThroughputTracker::Cancel() {
- DCHECK(started_);
+ // Some code calls Cancel() indirectly after receiving report. Allow this to
+ // happen and make it a no-op. See https://crbug.com/1193382.
+ if (!started_)
+ return;
started_ = false;
if (host_)
diff --git a/chromium/ui/compositor/throughput_tracker_unittest.cc b/chromium/ui/compositor/throughput_tracker_unittest.cc
new file mode 100644
index 00000000000..8036264de13
--- /dev/null
+++ b/chromium/ui/compositor/throughput_tracker_unittest.cc
@@ -0,0 +1,39 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/bind.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/test/animation_throughput_reporter_test_base.h"
+#include "ui/compositor/test/throughput_report_checker.h"
+
+namespace ui {
+
+using ThroughputReporterTest = AnimationThroughputReporterTestBase;
+
+TEST_F(ThroughputReporterTest, ThreadCheck) {
+ Layer layer;
+ root_layer()->Add(&layer);
+
+ LayerAnimator* animator =
+ new LayerAnimator(base::TimeDelta::FromMilliseconds(32));
+ layer.SetAnimator(animator);
+
+ ThroughputReportChecker checker(this);
+ auto once_callback = checker.once_callback();
+
+ ui::Compositor* c = compositor();
+ auto callback = [&](const cc::FrameSequenceMetrics::CustomReportData& data) {
+ c->ScheduleDraw();
+ std::move(once_callback).Run(data);
+ };
+
+ auto tracker = c->RequestNewThroughputTracker();
+ tracker.Start(base::BindLambdaForTesting(callback));
+ tracker.Stop();
+ EXPECT_TRUE(checker.WaitUntilReported());
+}
+
+} // namespace ui
diff --git a/chromium/ui/compositor/total_animation_throughput_reporter.cc b/chromium/ui/compositor/total_animation_throughput_reporter.cc
new file mode 100644
index 00000000000..7f9e80126dd
--- /dev/null
+++ b/chromium/ui/compositor/total_animation_throughput_reporter.cc
@@ -0,0 +1,91 @@
+// Copyright 2020 The Chromium 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/total_animation_throughput_reporter.h"
+
+#include "base/logging.h"
+#include "ui/compositor/compositor.h"
+
+namespace ui {
+
+TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
+ ui::Compositor* compositor,
+ ReportOnceCallback once_callback,
+ bool should_delete)
+ : TotalAnimationThroughputReporter(compositor,
+ ReportRepeatingCallback(),
+ std::move(once_callback),
+ should_delete) {}
+
+TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
+ ui::Compositor* compositor,
+ ReportRepeatingCallback repeating_callback)
+ : TotalAnimationThroughputReporter(compositor,
+ repeating_callback,
+ ReportOnceCallback(),
+ /*should_delete=*/false) {}
+
+TotalAnimationThroughputReporter::~TotalAnimationThroughputReporter() {
+ if (throughput_tracker_)
+ throughput_tracker_->Cancel();
+ if (compositor_)
+ compositor_->RemoveObserver(this);
+}
+
+void TotalAnimationThroughputReporter::OnFirstAnimationStarted(
+ ui::Compositor* compositor) {
+ throughput_tracker_ = compositor->RequestNewThroughputTracker();
+ throughput_tracker_->Start(base::BindRepeating(
+ &TotalAnimationThroughputReporter::Report, ptr_factory_.GetWeakPtr()));
+}
+
+void TotalAnimationThroughputReporter::OnLastAnimationEnded(
+ ui::Compositor* compositor) {
+ throughput_tracker_->Stop();
+ throughput_tracker_.reset();
+}
+
+void TotalAnimationThroughputReporter::OnCompositingShuttingDown(
+ ui::Compositor* compositor) {
+ if (throughput_tracker_) {
+ throughput_tracker_->Cancel();
+ throughput_tracker_.reset();
+ }
+ compositor->RemoveObserver(this);
+ compositor_ = nullptr;
+ if (should_delete_)
+ delete this;
+}
+
+TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
+ ui::Compositor* compositor,
+ ReportRepeatingCallback repeating_callback,
+ ReportOnceCallback once_callback,
+ bool should_delete)
+ : compositor_(compositor),
+ report_repeating_callback_(repeating_callback),
+ report_once_callback_(std::move(once_callback)),
+ should_delete_(should_delete) {
+ DCHECK_NE(report_repeating_callback_.is_null(),
+ report_once_callback_.is_null());
+
+ compositor_->AddObserver(this);
+ if (!compositor->animation_observer_list_.empty())
+ OnFirstAnimationStarted(compositor_);
+}
+
+void TotalAnimationThroughputReporter::Report(
+ const cc::FrameSequenceMetrics::CustomReportData& data) {
+ if (!report_once_callback_.is_null()) {
+ compositor_->RemoveObserver(this);
+ std::move(report_once_callback_).Run(data);
+ if (should_delete_)
+ delete this;
+ return;
+ }
+ if (!report_repeating_callback_.is_null())
+ report_repeating_callback_.Run(data);
+}
+
+} // namespace ui
diff --git a/chromium/ui/compositor/total_animation_throughput_reporter.h b/chromium/ui/compositor/total_animation_throughput_reporter.h
new file mode 100644
index 00000000000..6edc347a7bc
--- /dev/null
+++ b/chromium/ui/compositor/total_animation_throughput_reporter.h
@@ -0,0 +1,89 @@
+// Copyright 2020 The Chromium 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_TOTAL_ANIMATION_THROUGHPUT_REPORTER_H_
+#define UI_COMPOSITOR_TOTAL_ANIMATION_THROUGHPUT_REPORTER_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "cc/metrics/frame_sequence_metrics.h"
+#include "ui/compositor/compositor_export.h"
+#include "ui/compositor/compositor_observer.h"
+#include "ui/compositor/throughput_tracker.h"
+
+namespace ui {
+
+// Reports cc::FrameSequenceMetrics::ThroughputData between the first animation
+// start and the last animation ends on a compositor.
+//
+// Please see AnimationThroughputReporter for the definition of the throughput
+// and jack metrics.
+//
+// See also docs/speed/graphics_metrics_definitions.md.
+//
+// cc::FrameSequenceMetrics::CustomReportData contains the numbers of produced
+// frames, expected frames and jank count.
+//
+// The tracking starts when the first animation observer is added to the
+// compositor, then stopped when the last animation observer is removed. The
+// report callback is invoked on the next begin frame if there is enough data.
+// Since this observes multiple animations, aborting one of animations will
+// not cancel the tracking, and the data will be reported as normal.
+class COMPOSITOR_EXPORT TotalAnimationThroughputReporter
+ : public CompositorObserver {
+ public:
+ using ReportOnceCallback = base::OnceCallback<void(
+ const cc::FrameSequenceMetrics::CustomReportData& data)>;
+ using ReportRepeatingCallback = base::RepeatingCallback<void(
+ const cc::FrameSequenceMetrics::CustomReportData& data)>;
+
+ // Create a TotalAnimationThroughputReporter that observes
+ // the total animation throughput just once. If |should_delete|
+ // is true, then the object will be deleted after callback is
+ // invoked.
+ TotalAnimationThroughputReporter(Compositor* compositor,
+ ReportOnceCallback callback,
+ bool should_delete);
+
+ // Create a persistent TotalAnimationThroughputReporter, which
+ // will call the callback every time the last animation is finished.
+ TotalAnimationThroughputReporter(Compositor* compositor,
+ ReportRepeatingCallback callback);
+
+ TotalAnimationThroughputReporter(const TotalAnimationThroughputReporter&) =
+ delete;
+ TotalAnimationThroughputReporter& operator=(
+ const TotalAnimationThroughputReporter&) = delete;
+ ~TotalAnimationThroughputReporter() override;
+
+ // CompositorObserver:
+ void OnFirstAnimationStarted(Compositor* compositor) override;
+ void OnLastAnimationEnded(Compositor* compositor) override;
+ void OnCompositingShuttingDown(Compositor* compositor) override;
+
+ bool IsMeasuringForTesting() const { return bool{throughput_tracker_}; }
+
+ private:
+ TotalAnimationThroughputReporter(Compositor* compositor,
+ ReportRepeatingCallback repeating_callback,
+ ReportOnceCallback once_callback,
+ bool should_delete);
+
+ void Report(const cc::FrameSequenceMetrics::CustomReportData& data);
+
+ Compositor* compositor_;
+ ReportRepeatingCallback report_repeating_callback_;
+ ReportOnceCallback report_once_callback_;
+ bool should_delete_ = false;
+ base::Optional<ThroughputTracker> throughput_tracker_;
+
+ base::WeakPtrFactory<TotalAnimationThroughputReporter> ptr_factory_{this};
+};
+
+} // namespace ui
+
+#endif // UI_COMPOSITOR_TOTAL_ANIMATION_THROUGHPUT_REPORTER_H_
diff --git a/chromium/ui/compositor/total_animation_throughput_reporter_unittest.cc b/chromium/ui/compositor/total_animation_throughput_reporter_unittest.cc
new file mode 100644
index 00000000000..e62fba30182
--- /dev/null
+++ b/chromium/ui/compositor/total_animation_throughput_reporter_unittest.cc
@@ -0,0 +1,356 @@
+// Copyright 2020 The Chromium 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/total_animation_throughput_reporter.h"
+
+#include <memory>
+
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "cc/metrics/frame_sequence_metrics.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animation_sequence.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/compositor/test/animation_throughput_reporter_test_base.h"
+#include "ui/compositor/test/throughput_report_checker.h"
+
+namespace ui {
+
+using TotalAnimationThroughputReporterTest =
+ AnimationThroughputReporterTestBase;
+
+TEST_F(TotalAnimationThroughputReporterTest, SingleAnimation) {
+ Layer layer;
+ layer.SetOpacity(0.5f);
+ root_layer()->Add(&layer);
+
+ ThroughputReportChecker checker(this);
+ TotalAnimationThroughputReporter reporter(compositor(),
+ checker.repeating_callback());
+ {
+ LayerAnimator* animator = layer.GetAnimator();
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+ layer.SetOpacity(1.0f);
+ }
+ Advance(base::TimeDelta::FromMilliseconds(32));
+ EXPECT_FALSE(checker.reported());
+ EXPECT_TRUE(checker.WaitUntilReported());
+}
+
+// Tests the stopping last animation will trigger the animation.
+TEST_F(TotalAnimationThroughputReporterTest, StopAnimation) {
+ Layer layer;
+ layer.SetOpacity(0.5f);
+ root_layer()->Add(&layer);
+
+ ThroughputReportChecker checker(this);
+ TotalAnimationThroughputReporter reporter(compositor(),
+ checker.repeating_callback());
+ {
+ LayerAnimator* animator = layer.GetAnimator();
+
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(64));
+ layer.SetOpacity(1.0f);
+ }
+ Advance(base::TimeDelta::FromMilliseconds(32));
+ EXPECT_FALSE(checker.reported());
+ layer.GetAnimator()->StopAnimating();
+ EXPECT_TRUE(checker.WaitUntilReported());
+}
+
+// Tests the longest animation will trigger the report.
+TEST_F(TotalAnimationThroughputReporterTest, MultipleAnimations) {
+ Layer layer1;
+ layer1.SetOpacity(0.5f);
+ root_layer()->Add(&layer1);
+
+ ThroughputReportChecker checker(this);
+ TotalAnimationThroughputReporter reporter(compositor(),
+ checker.repeating_callback());
+ {
+ LayerAnimator* animator = layer1.GetAnimator();
+
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+ layer1.SetOpacity(1.0f);
+ }
+ Layer layer2;
+ layer2.SetOpacity(0.5f);
+ root_layer()->Add(&layer2);
+
+ {
+ LayerAnimator* animator = layer2.GetAnimator();
+
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(96));
+ layer2.SetOpacity(1.0f);
+ }
+
+ Advance(base::TimeDelta::FromMilliseconds(32));
+ EXPECT_FALSE(checker.reported());
+ Advance(base::TimeDelta::FromMilliseconds(32));
+ EXPECT_FALSE(checker.reported());
+ EXPECT_TRUE(checker.WaitUntilReported());
+}
+
+// Tests the longest animation on a single layer will triger the report.
+TEST_F(TotalAnimationThroughputReporterTest, MultipleAnimationsOnSingleLayer) {
+ Layer layer;
+ layer.SetOpacity(0.5f);
+ layer.SetLayerBrightness(0.5f);
+ root_layer()->Add(&layer);
+
+ ThroughputReportChecker checker(this);
+ TotalAnimationThroughputReporter reporter(compositor(),
+ checker.repeating_callback());
+ {
+ LayerAnimator* animator = layer.GetAnimator();
+
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+ layer.SetOpacity(1.0f);
+ }
+ {
+ LayerAnimator* animator = layer.GetAnimator();
+
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(96));
+ layer.SetLayerBrightness(1.0f);
+ }
+
+ Advance(base::TimeDelta::FromMilliseconds(64));
+ EXPECT_FALSE(checker.reported());
+ EXPECT_TRUE(checker.WaitUntilReported());
+}
+
+// Tests adding new animation will extends the duration.
+TEST_F(TotalAnimationThroughputReporterTest, AddAnimationWhileAnimating) {
+ Layer layer1;
+ layer1.SetOpacity(0.5f);
+ root_layer()->Add(&layer1);
+
+ ThroughputReportChecker checker(this);
+ TotalAnimationThroughputReporter reporter(compositor(),
+ checker.repeating_callback());
+ {
+ LayerAnimator* animator = layer1.GetAnimator();
+
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+ layer1.SetOpacity(1.0f);
+ }
+
+ Advance(base::TimeDelta::FromMilliseconds(32));
+ EXPECT_FALSE(checker.reported());
+
+ // Add new animation while animating.
+ Layer layer2;
+ layer2.SetOpacity(0.5f);
+ root_layer()->Add(&layer2);
+
+ {
+ LayerAnimator* animator = layer2.GetAnimator();
+
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+ layer2.SetOpacity(1.0f);
+ }
+
+ // The animation time is extended.
+ Advance(base::TimeDelta::FromMilliseconds(32));
+ EXPECT_FALSE(checker.reported());
+
+ EXPECT_TRUE(checker.WaitUntilReported());
+}
+
+// Tests removing last animation will call report callback.
+TEST_F(TotalAnimationThroughputReporterTest, RemoveWhileAnimating) {
+ auto layer1 = std::make_unique<Layer>();
+ layer1->SetOpacity(0.5f);
+ root_layer()->Add(layer1.get());
+
+ ThroughputReportChecker checker(this);
+ TotalAnimationThroughputReporter reporter(compositor(),
+ checker.repeating_callback());
+ {
+ LayerAnimator* animator = layer1->GetAnimator();
+
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(100));
+ layer1->SetOpacity(1.0f);
+ }
+
+ Layer layer2;
+ layer2.SetOpacity(0.5f);
+ root_layer()->Add(&layer2);
+
+ {
+ LayerAnimator* animator = layer2.GetAnimator();
+
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+ layer2.SetOpacity(1.0f);
+ }
+ Advance(base::TimeDelta::FromMilliseconds(48));
+ EXPECT_FALSE(checker.reported());
+ layer1.reset();
+ // Aborting will be processed in next frame.
+ EXPECT_TRUE(checker.WaitUntilReported());
+}
+
+// Make sure the reporter can start measuring even if the animation
+// has started.
+TEST_F(TotalAnimationThroughputReporterTest, StartWhileAnimating) {
+ Layer layer;
+ layer.SetOpacity(0.5f);
+ root_layer()->Add(&layer);
+
+ {
+ LayerAnimator* animator = layer.GetAnimator();
+
+ ScopedLayerAnimationSettings settings(animator);
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(96));
+ layer.SetOpacity(1.0f);
+ }
+ Advance(base::TimeDelta::FromMilliseconds(32));
+ ThroughputReportChecker checker(this);
+ TotalAnimationThroughputReporter reporter(compositor(),
+ checker.repeating_callback());
+ EXPECT_TRUE(reporter.IsMeasuringForTesting());
+ EXPECT_TRUE(checker.WaitUntilReported());
+}
+
+// Tests the reporter is called multiple times for persistent animation.
+TEST_F(TotalAnimationThroughputReporterTest, PersistedAnimation) {
+ Layer layer;
+ layer.SetOpacity(0.5f);
+ root_layer()->Add(&layer);
+
+ // Set a persisted animator to |layer|.
+ LayerAnimator* animator =
+ new LayerAnimator(base::TimeDelta::FromMilliseconds(48));
+ layer.SetAnimator(animator);
+
+ // |reporter| keeps reporting as long as it is alive.
+ ThroughputReportChecker checker(this);
+ TotalAnimationThroughputReporter reporter(compositor(),
+ checker.repeating_callback());
+
+ // Report data for animation of opacity goes to 1.
+ layer.SetOpacity(1.0f);
+ EXPECT_TRUE(checker.WaitUntilReported());
+
+ // Report data for animation of opacity goes to 0.5.
+ checker.reset();
+ layer.SetOpacity(0.5f);
+ EXPECT_TRUE(checker.WaitUntilReported());
+}
+
+// Make sure the once reporter is called only once.
+TEST_F(TotalAnimationThroughputReporterTest, OnceReporter) {
+ Layer layer;
+ layer.SetOpacity(0.5f);
+ root_layer()->Add(&layer);
+
+ // Set a persisted animator to |layer|.
+ LayerAnimator* animator =
+ new LayerAnimator(base::TimeDelta::FromMilliseconds(32));
+ layer.SetAnimator(animator);
+
+ ThroughputReportChecker checker(this);
+ TotalAnimationThroughputReporter reporter(
+ compositor(), checker.once_callback(), /*should_delete=*/false);
+
+ // Report data for animation of opacity goes to 1.
+ layer.SetOpacity(1.0f);
+ EXPECT_TRUE(checker.WaitUntilReported());
+
+ // Report data for animation of opacity goes to 0.5.
+ checker.reset();
+ layer.SetOpacity(1.0f);
+ Advance(base::TimeDelta::FromMilliseconds(100));
+ EXPECT_FALSE(checker.reported());
+}
+
+// One reporter marked as "should_delete" should be deleted when
+// reported.
+TEST_F(TotalAnimationThroughputReporterTest, OnceReporterShouldDelete) {
+ class DeleteTestReporter : public TotalAnimationThroughputReporter {
+ public:
+ DeleteTestReporter(Compositor* compositor,
+ ReportOnceCallback callback,
+ bool* deleted)
+ : TotalAnimationThroughputReporter(compositor,
+ std::move(callback),
+ true),
+ deleted_(deleted) {}
+ ~DeleteTestReporter() override { *deleted_ = true; }
+
+ private:
+ bool* deleted_;
+ };
+
+ Layer layer;
+ layer.SetOpacity(0.5f);
+ root_layer()->Add(&layer);
+
+ // Set a persisted animator to |layer|.
+ LayerAnimator* animator =
+ new LayerAnimator(base::TimeDelta::FromMilliseconds(32));
+ layer.SetAnimator(animator);
+
+ // |reporter| keeps reporting as long as it is alive.
+ base::RunLoop run_loop;
+
+ bool deleted = false;
+ new DeleteTestReporter(
+ compositor(),
+ base::BindLambdaForTesting(
+ [&](const cc::FrameSequenceMetrics::CustomReportData&) {
+ run_loop.Quit();
+ }),
+ &deleted);
+
+ // Report data for animation of opacity goes to 1.
+ layer.SetOpacity(1.0f);
+ run_loop.Run();
+ EXPECT_TRUE(deleted);
+}
+
+TEST_F(TotalAnimationThroughputReporterTest, ThreadCheck) {
+ Layer layer;
+ layer.SetOpacity(0.5f);
+ root_layer()->Add(&layer);
+
+ // Set a persisted animator to |layer|.
+ LayerAnimator* animator =
+ new LayerAnimator(base::TimeDelta::FromMilliseconds(32));
+ layer.SetAnimator(animator);
+
+ ui::Compositor* c = compositor();
+
+ ThroughputReportChecker checker(this);
+ auto once_callback = checker.once_callback();
+ ThroughputReportChecker::ReportOnceCallback callback =
+ base::BindLambdaForTesting(
+ [&](const cc::FrameSequenceMetrics::CustomReportData& data) {
+ // This call with fail if this is called on impl thread.
+ c->ScheduleDraw();
+ std::move(once_callback).Run(data);
+ });
+
+ TotalAnimationThroughputReporter reporter(c, std::move(callback),
+ /*should_delete=*/false);
+
+ // Report data for animation of opacity goes to 1.
+ layer.SetOpacity(1.0f);
+ EXPECT_TRUE(checker.WaitUntilReported());
+}
+
+} // namespace ui
diff --git a/chromium/ui/compositor/transform_animation_curve_adapter.cc b/chromium/ui/compositor/transform_animation_curve_adapter.cc
index 9a871abab33..df979bebfb8 100644
--- a/chromium/ui/compositor/transform_animation_curve_adapter.cc
+++ b/chromium/ui/compositor/transform_animation_curve_adapter.cc
@@ -10,8 +10,8 @@ namespace ui {
namespace {
-static cc::TransformOperations WrapTransform(const gfx::Transform& transform) {
- cc::TransformOperations operations;
+static gfx::TransformOperations WrapTransform(const gfx::Transform& transform) {
+ gfx::TransformOperations operations;
operations.AppendMatrix(transform);
return operations;
}
@@ -43,13 +43,13 @@ base::TimeDelta TransformAnimationCurveAdapter::Duration() const {
return duration_;
}
-std::unique_ptr<cc::AnimationCurve> TransformAnimationCurveAdapter::Clone()
+std::unique_ptr<gfx::AnimationCurve> TransformAnimationCurveAdapter::Clone()
const {
return base::WrapUnique(new TransformAnimationCurveAdapter(
tween_type_, initial_value_, target_value_, duration_));
}
-cc::TransformOperations TransformAnimationCurveAdapter::GetValue(
+gfx::TransformOperations TransformAnimationCurveAdapter::GetValue(
base::TimeDelta t) const {
if (t >= duration_)
return target_wrapped_value_;
@@ -62,90 +62,21 @@ cc::TransformOperations TransformAnimationCurveAdapter::GetValue(
return WrapTransform(gfx::ComposeTransform(to_return));
}
-bool TransformAnimationCurveAdapter::IsTranslation() const {
- return initial_value_.IsIdentityOrTranslation() &&
- target_value_.IsIdentityOrTranslation();
-}
-
bool TransformAnimationCurveAdapter::PreservesAxisAlignment() const {
return (initial_value_.IsIdentity() ||
initial_value_.IsScaleOrTranslation()) &&
(target_value_.IsIdentity() || target_value_.IsScaleOrTranslation());
}
-bool TransformAnimationCurveAdapter::AnimationStartScale(
- bool forward_direction,
- float* start_scale) const {
- return false;
-}
-
-bool TransformAnimationCurveAdapter::MaximumTargetScale(
- bool forward_direction,
- float* max_scale) const {
- return false;
-}
-
-InverseTransformCurveAdapter::InverseTransformCurveAdapter(
- TransformAnimationCurveAdapter base_curve,
- gfx::Transform initial_value,
- base::TimeDelta duration)
- : base_curve_(base_curve),
- initial_value_(initial_value),
- initial_wrapped_value_(WrapTransform(initial_value)),
- duration_(duration) {
- effective_initial_value_ =
- base_curve_.GetValue(base::TimeDelta()).Apply() * initial_value_;
-}
-
-InverseTransformCurveAdapter::~InverseTransformCurveAdapter() {
-}
-
-base::TimeDelta InverseTransformCurveAdapter::Duration() const {
- return duration_;
-}
-
-std::unique_ptr<cc::AnimationCurve> InverseTransformCurveAdapter::Clone()
- const {
- return base::WrapUnique(
- new InverseTransformCurveAdapter(base_curve_, initial_value_, duration_));
-}
-
-cc::TransformOperations InverseTransformCurveAdapter::GetValue(
- base::TimeDelta t) const {
- if (t <= base::TimeDelta())
- return initial_wrapped_value_;
-
- gfx::Transform base_transform = base_curve_.GetValue(t).Apply();
- // Invert base
- gfx::Transform to_return(gfx::Transform::kSkipInitialization);
- bool is_invertible = base_transform.GetInverse(&to_return);
- DCHECK(is_invertible);
-
- to_return.PreconcatTransform(effective_initial_value_);
-
- return WrapTransform(to_return);
-}
-
-bool InverseTransformCurveAdapter::IsTranslation() const {
- return initial_value_.IsIdentityOrTranslation() &&
- base_curve_.IsTranslation();
-}
-
-bool InverseTransformCurveAdapter::PreservesAxisAlignment() const {
- return (initial_value_.IsIdentity() ||
- initial_value_.IsScaleOrTranslation()) &&
- (base_curve_.PreservesAxisAlignment());
-}
-
-bool InverseTransformCurveAdapter::AnimationStartScale(
- bool forward_direction,
- float* start_scale) const {
- return false;
-}
-
-bool InverseTransformCurveAdapter::MaximumTargetScale(bool forward_direction,
- float* max_scale) const {
- return false;
+bool TransformAnimationCurveAdapter::MaximumScale(float* max_scale) const {
+ constexpr float kInvalidScale = 0.f;
+ gfx::Vector2dF initial_scales =
+ gfx::ComputeTransform2dScaleComponents(initial_value_, kInvalidScale);
+ gfx::Vector2dF target_scales =
+ gfx::ComputeTransform2dScaleComponents(target_value_, kInvalidScale);
+ *max_scale = std::max({initial_scales.x(), initial_scales.y(),
+ target_scales.x(), target_scales.y()});
+ return *max_scale != kInvalidScale;
}
} // namespace ui
diff --git a/chromium/ui/compositor/transform_animation_curve_adapter.h b/chromium/ui/compositor/transform_animation_curve_adapter.h
index bc03f418fb0..6f12dd3dfff 100644
--- a/chromium/ui/compositor/transform_animation_curve_adapter.h
+++ b/chromium/ui/compositor/transform_animation_curve_adapter.h
@@ -9,17 +9,17 @@
#include "base/macros.h"
#include "base/time/time.h"
-#include "cc/animation/animation_curve.h"
-#include "cc/animation/transform_operations.h"
#include "ui/compositor/compositor_export.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/transform.h"
+#include "ui/gfx/transform_operations.h"
#include "ui/gfx/transform_util.h"
namespace ui {
class COMPOSITOR_EXPORT TransformAnimationCurveAdapter
- : public cc::TransformAnimationCurve {
+ : public gfx::TransformAnimationCurve {
public:
TransformAnimationCurveAdapter(gfx::Tween::Type tween_type,
gfx::Transform intial_value,
@@ -32,21 +32,17 @@ class COMPOSITOR_EXPORT TransformAnimationCurveAdapter
// TransformAnimationCurve implementation.
base::TimeDelta Duration() const override;
- std::unique_ptr<AnimationCurve> Clone() const override;
- cc::TransformOperations GetValue(base::TimeDelta t) const override;
- bool IsTranslation() const override;
+ std::unique_ptr<gfx::AnimationCurve> Clone() const override;
+ gfx::TransformOperations GetValue(base::TimeDelta t) const override;
bool PreservesAxisAlignment() const override;
- bool AnimationStartScale(bool forward_direction,
- float* start_scale) const override;
- bool MaximumTargetScale(bool forward_direction,
- float* max_scale) const override;
+ bool MaximumScale(float* max_scale) const override;
private:
gfx::Tween::Type tween_type_;
gfx::Transform initial_value_;
- cc::TransformOperations initial_wrapped_value_;
+ gfx::TransformOperations initial_wrapped_value_;
gfx::Transform target_value_;
- cc::TransformOperations target_wrapped_value_;
+ gfx::TransformOperations target_wrapped_value_;
gfx::DecomposedTransform decomposed_initial_value_;
gfx::DecomposedTransform decomposed_target_value_;
base::TimeDelta duration_;
@@ -54,35 +50,6 @@ class COMPOSITOR_EXPORT TransformAnimationCurveAdapter
DISALLOW_ASSIGN(TransformAnimationCurveAdapter);
};
-class COMPOSITOR_EXPORT InverseTransformCurveAdapter
- : public cc::TransformAnimationCurve {
- public:
- InverseTransformCurveAdapter(TransformAnimationCurveAdapter base_curve,
- gfx::Transform initial_value,
- base::TimeDelta duration);
-
- ~InverseTransformCurveAdapter() override;
-
- base::TimeDelta Duration() const override;
- std::unique_ptr<AnimationCurve> Clone() const override;
- cc::TransformOperations GetValue(base::TimeDelta t) const override;
- bool IsTranslation() const override;
- bool PreservesAxisAlignment() const override;
- bool AnimationStartScale(bool forward_direction,
- float* start_scale) const override;
- bool MaximumTargetScale(bool forward_direction,
- float* max_scale) const override;
-
- private:
- TransformAnimationCurveAdapter base_curve_;
- gfx::Transform initial_value_;
- cc::TransformOperations initial_wrapped_value_;
- gfx::Transform effective_initial_value_;
- base::TimeDelta duration_;
-
- DISALLOW_ASSIGN(InverseTransformCurveAdapter);
-};
-
} // namespace ui
#endif // UI_COMPOSITOR_TRANSFORM_ANIMATION_CURVE_ADAPTER_H_
diff --git a/chromium/ui/compositor/transform_animation_curve_adapter_unittest.cc b/chromium/ui/compositor/transform_animation_curve_adapter_unittest.cc
index 7c80133bb28..e042faa5c52 100644
--- a/chromium/ui/compositor/transform_animation_curve_adapter_unittest.cc
+++ b/chromium/ui/compositor/transform_animation_curve_adapter_unittest.cc
@@ -4,52 +4,58 @@
#include "ui/compositor/transform_animation_curve_adapter.h"
-#include <sstream>
-
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/compositor/test/test_utils.h"
namespace ui {
namespace {
-// Check that the inverse transform curve gives the gives a transform that when
-// applied on top of the parent transform gives the original transform
-TEST(InverseTransformCurveAdapterTest, InversesTransform) {
- gfx::Transform parent_start, parent_target;
- parent_start.Scale(0.5, 3.0);
- parent_start.Translate(-20.0, 30.0);
- parent_target.Translate(0, 100);
-
- gfx::Transform child_transform;
- child_transform.Rotate(-30.0);
-
- base::TimeDelta duration = base::TimeDelta::FromSeconds(1);
-
- const gfx::Transform effective_child_transform =
- parent_start * child_transform;
-
- TransformAnimationCurveAdapter parent_curve(gfx::Tween::LINEAR, parent_start,
- parent_target, duration);
-
- InverseTransformCurveAdapter child_curve(parent_curve, child_transform,
- duration);
- static const int kSteps = 1000;
- double step = 1.0 / kSteps;
- for (int i = 0; i <= kSteps; ++i) {
- base::TimeDelta time_step = duration * (i * step);
- std::ostringstream message;
- message << "Step " << i << " of " << kSteps;
- SCOPED_TRACE(message.str());
- gfx::Transform progress_parent_transform =
- parent_curve.GetValue(time_step).Apply();
- gfx::Transform progress_child_transform =
- child_curve.GetValue(time_step).Apply();
- CheckApproximatelyEqual(
- effective_child_transform,
- progress_parent_transform * progress_child_transform);
- }
+TEST(TransformAnimationCurveAdapterTest, MaximumAnimationScale) {
+ auto duration = base::TimeDelta::FromSeconds(1);
+ float kArbitraryScale = 123.f;
+ float scale = kArbitraryScale;
+ EXPECT_TRUE(TransformAnimationCurveAdapter(gfx::Tween::LINEAR,
+ gfx::Transform(), gfx::Transform(),
+ duration)
+ .MaximumScale(&scale));
+ EXPECT_EQ(1.0f, scale);
+
+ gfx::Transform initial;
+ gfx::Transform target;
+ initial.Scale(1.0f, 2.0f);
+ target.Scale(3.0f, 4.0f);
+ scale = kArbitraryScale;
+ EXPECT_TRUE(TransformAnimationCurveAdapter(gfx::Tween::LINEAR, initial,
+ target, duration)
+ .MaximumScale(&scale));
+ EXPECT_EQ(4.0f, scale);
+
+ scale = kArbitraryScale;
+ EXPECT_TRUE(TransformAnimationCurveAdapter(gfx::Tween::LINEAR, target,
+ initial, duration)
+ .MaximumScale(&scale));
+ EXPECT_EQ(4.0f, scale);
+
+ target.ApplyPerspectiveDepth(2.0f);
+ scale = kArbitraryScale;
+ EXPECT_TRUE(TransformAnimationCurveAdapter(gfx::Tween::LINEAR, initial,
+ target, duration)
+ .MaximumScale(&scale));
+ EXPECT_EQ(2.0f, scale);
+ scale = kArbitraryScale;
+ EXPECT_TRUE(TransformAnimationCurveAdapter(gfx::Tween::LINEAR, target,
+ initial, duration)
+ .MaximumScale(&scale));
+ EXPECT_EQ(2.0f, scale);
+
+ initial.ApplyPerspectiveDepth(3.0f);
+ EXPECT_FALSE(TransformAnimationCurveAdapter(gfx::Tween::LINEAR, initial,
+ target, duration)
+ .MaximumScale(&scale));
+ EXPECT_FALSE(TransformAnimationCurveAdapter(gfx::Tween::LINEAR, target,
+ initial, duration)
+ .MaximumScale(&scale));
}
} // namespace
diff --git a/chromium/ui/compositor/transform_recorder.cc b/chromium/ui/compositor/transform_recorder.cc
index 4175f1e4fbc..faa4a52371d 100644
--- a/chromium/ui/compositor/transform_recorder.cc
+++ b/chromium/ui/compositor/transform_recorder.cc
@@ -29,7 +29,7 @@ void TransformRecorder::Transform(const gfx::Transform& transform) {
context_.list_->StartPaint();
context_.list_->push<cc::SaveOp>();
- context_.list_->push<cc::ConcatOp>(static_cast<SkMatrix>(transform.matrix()));
+ context_.list_->push<cc::ConcatOp>(transform.GetMatrixAsSkM44());
context_.list_->EndPaintOfPairedBegin();
transformed_ = true;
diff --git a/chromium/ui/compositor_extra/DIR_METADATA b/chromium/ui/compositor_extra/DIR_METADATA
new file mode 100644
index 00000000000..c311a557762
--- /dev/null
+++ b/chromium/ui/compositor_extra/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals>Compositing"
+}
diff --git a/chromium/ui/compositor_extra/OWNERS b/chromium/ui/compositor_extra/OWNERS
deleted file mode 100644
index 0b97d4ba6fa..00000000000
--- a/chromium/ui/compositor_extra/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# COMPONENT: Internals>Compositing
diff --git a/chromium/ui/content_accelerators/BUILD.gn b/chromium/ui/content_accelerators/BUILD.gn
index ce101e75fa5..11977a1ebd9 100644
--- a/chromium/ui/content_accelerators/BUILD.gn
+++ b/chromium/ui/content_accelerators/BUILD.gn
@@ -9,6 +9,7 @@ source_set("content_accelerators") {
]
deps = [
+ "//build:chromeos_buildflags",
"//third_party/blink/public:blink_headers",
"//ui/base",
"//ui/events",
diff --git a/chromium/ui/content_accelerators/DIR_METADATA b/chromium/ui/content_accelerators/DIR_METADATA
new file mode 100644
index 00000000000..22ea90db18f
--- /dev/null
+++ b/chromium/ui/content_accelerators/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals>Input"
+}
diff --git a/chromium/ui/content_accelerators/OWNERS b/chromium/ui/content_accelerators/OWNERS
deleted file mode 100644
index 40114ac1e8e..00000000000
--- a/chromium/ui/content_accelerators/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# COMPONENT: Internals>Input
diff --git a/chromium/ui/content_accelerators/accelerator_util.cc b/chromium/ui/content_accelerators/accelerator_util.cc
index 027c6e802e0..223df257be0 100644
--- a/chromium/ui/content_accelerators/accelerator_util.cc
+++ b/chromium/ui/content_accelerators/accelerator_util.cc
@@ -5,6 +5,7 @@
#include "ui/content_accelerators/accelerator_util.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/blink/blink_event_util.h"
@@ -15,7 +16,7 @@ namespace ui {
ui::Accelerator GetAcceleratorFromNativeWebKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
if (::features::IsNewShortcutMappingEnabled()) {
// TODO: This must be the same as below and it's simpler.
// Cleanup if this change sticks.
diff --git a/chromium/ui/display/BUILD.gn b/chromium/ui/display/BUILD.gn
index 429cb8f30b8..db0a7cf668b 100644
--- a/chromium/ui/display/BUILD.gn
+++ b/chromium/ui/display/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
import("//testing/test.gni")
import("//ui/display/display.gni")
@@ -91,6 +92,7 @@ component("display") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//mojo/public/cpp/bindings:struct_traits",
"//ui/display/util",
"//ui/gfx",
@@ -128,6 +130,7 @@ component("display_manager_test_api") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//ui/display",
"//ui/display/types",
]
@@ -232,6 +235,7 @@ test("display_unittests") {
":test_support",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//cc/base",
"//mojo/core/test:run_all_unittests",
"//testing/gmock",
@@ -253,7 +257,7 @@ test("display_unittests") {
sources += [ "display_change_notifier_unittest.cc" ]
}
- if (is_chromeos) {
- deps += [ "//chromeos/constants" ]
+ if (is_chromeos_ash) {
+ deps += [ "//ash/constants" ]
}
}
diff --git a/chromium/ui/display/DIR_METADATA b/chromium/ui/display/DIR_METADATA
new file mode 100644
index 00000000000..bfbb363da3d
--- /dev/null
+++ b/chromium/ui/display/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI>Systems>Display"
+}
diff --git a/chromium/ui/display/OWNERS b/chromium/ui/display/OWNERS
index 40316a60e69..c22653fca63 100644
--- a/chromium/ui/display/OWNERS
+++ b/chromium/ui/display/OWNERS
@@ -5,5 +5,3 @@ oshima@chromium.org
# Legacy OWNER(s)
marcheu@chromium.org
-
-# COMPONENT: UI>Systems>Display
diff --git a/chromium/ui/display/display.gni b/chromium/ui/display/display.gni
index 3c2d327107f..22197b6d868 100644
--- a/chromium/ui/display/display.gni
+++ b/chromium/ui/display/display.gni
@@ -2,7 +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/chromeos/ui_mode.gni")
+
declare_args() {
# Build Chrome OS display configuration code.
- build_display_configuration = is_chromeos
+ build_display_configuration = is_chromeos_ash
}
diff --git a/chromium/ui/display/display_features.cc b/chromium/ui/display/display_features.cc
index 3b9e4de733c..ccb6f6b6bbb 100644
--- a/chromium/ui/display/display_features.cc
+++ b/chromium/ui/display/display_features.cc
@@ -5,11 +5,12 @@
#include "ui/display/display_features.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
namespace display {
namespace features {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Enables using HDR transfer function if the monitor says it supports it.
const base::Feature kUseHDRTransferFunction {
"UseHDRTransferFunction",
diff --git a/chromium/ui/display/display_features.h b/chromium/ui/display/display_features.h
index 5a67c49c068..d999b1f425d 100644
--- a/chromium/ui/display/display_features.h
+++ b/chromium/ui/display/display_features.h
@@ -6,12 +6,13 @@
#define UI_DISPLAY_DISPLAY_FEATURES_H_
#include "base/feature_list.h"
+#include "build/chromeos_buildflags.h"
#include "ui/display/display_export.h"
namespace display {
namespace features {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
DISPLAY_EXPORT extern const base::Feature kUseHDRTransferFunction;
#endif
diff --git a/chromium/ui/display/display_switches.cc b/chromium/ui/display/display_switches.cc
index f2c0f562448..46b41ae10e7 100644
--- a/chromium/ui/display/display_switches.cc
+++ b/chromium/ui/display/display_switches.cc
@@ -4,6 +4,7 @@
#include "ui/display/display_switches.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
namespace switches {
@@ -53,7 +54,7 @@ const char kScreenConfig[] = "screen-config";
// This is for debugging on linux desktop.
const char kUseFirstDisplayAsInternal[] = "use-first-display-as-internal";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Enables unified desktop mode.
const char kEnableUnifiedDesktop[] = "ash-enable-unified-desktop";
#endif
diff --git a/chromium/ui/display/display_switches.h b/chromium/ui/display/display_switches.h
index ff76d749d0f..17cea1ee459 100644
--- a/chromium/ui/display/display_switches.h
+++ b/chromium/ui/display/display_switches.h
@@ -8,6 +8,7 @@
#include "base/compiler_specific.h"
#include "base/feature_list.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/display/display_export.h"
namespace switches {
@@ -24,7 +25,7 @@ DISPLAY_EXPORT extern const char kScreenConfig[];
DISPLAY_EXPORT extern const char kSecondaryDisplayLayout[];
DISPLAY_EXPORT extern const char kUseFirstDisplayAsInternal[];
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
DISPLAY_EXPORT extern const char kEnableUnifiedDesktop[];
#endif
diff --git a/chromium/ui/display/fake/fake_display_delegate.cc b/chromium/ui/display/fake/fake_display_delegate.cc
index c8f6251c594..2932ce31fd9 100644
--- a/chromium/ui/display/fake/fake_display_delegate.cc
+++ b/chromium/ui/display/fake/fake_display_delegate.cc
@@ -132,9 +132,9 @@ void FakeDisplayDelegate::GetDisplays(GetDisplaysCallback callback) {
void FakeDisplayDelegate::Configure(
const std::vector<display::DisplayConfigurationParams>& config_requests,
ConfigureCallback callback) {
- base::flat_map<int64_t, bool> statuses;
+ bool config_success = true;
for (const auto& config : config_requests) {
- bool configure_success = false;
+ bool request_success = false;
if (config.mode.has_value()) {
// Find display snapshot of display ID.
@@ -147,19 +147,20 @@ void FakeDisplayDelegate::Configure(
// Check that config mode is appropriate for the display snapshot.
for (const auto& existing_mode : snapshot->get()->modes()) {
if (AreModesEqual(*existing_mode.get(), *config.mode.value().get())) {
- configure_success = true;
+ request_success = true;
break;
}
}
}
} else {
// This is a request to turn off the display.
- configure_success = true;
+ request_success = true;
}
- statuses.insert(std::make_pair(config.id, configure_success));
+ config_success &= request_success;
}
- configure_callbacks_.push(base::BindOnce(std::move(callback), statuses));
+ configure_callbacks_.push(
+ base::BindOnce(std::move(callback), config_success));
// Start the timer if it's not already running. If there are multiple queued
// configuration requests then ConfigureDone() will handle starting the
diff --git a/chromium/ui/display/fake/fake_display_snapshot.cc b/chromium/ui/display/fake/fake_display_snapshot.cc
index 98c8b875022..f91f4baea51 100644
--- a/chromium/ui/display/fake/fake_display_snapshot.cc
+++ b/chromium/ui/display/fake/fake_display_snapshot.cc
@@ -5,6 +5,7 @@
#include "ui/display/fake/fake_display_snapshot.h"
#include <inttypes.h>
+#include <stdint.h>
#include <utility>
#include <vector>
@@ -162,11 +163,11 @@ std::unique_ptr<FakeDisplaySnapshot> Builder::Build() {
gfx::ScaleToRoundedSize(native_mode_->size(), PixelPitchMmFromDPI(dpi_));
return std::make_unique<FakeDisplaySnapshot>(
- id_, origin_, physical_size, type_, is_aspect_preserving_scaling_,
- has_overscan_, privacy_screen_state_, has_color_correction_matrix_,
- color_correction_in_linear_space_, name_, std::move(modes_),
- current_mode_, native_mode_, product_code_, maximum_cursor_size_,
- color_space_, bits_per_channel_);
+ id_, origin_, physical_size, type_, base_connector_id_, path_topology_,
+ is_aspect_preserving_scaling_, has_overscan_, privacy_screen_state_,
+ has_color_correction_matrix_, color_correction_in_linear_space_, name_,
+ std::move(modes_), current_mode_, native_mode_, product_code_,
+ maximum_cursor_size_, color_space_, bits_per_channel_);
}
Builder& Builder::SetId(int64_t id) {
@@ -214,6 +215,16 @@ Builder& Builder::SetType(DisplayConnectionType type) {
return *this;
}
+Builder& Builder::SetBaseConnectorId(uint64_t base_connector_id) {
+ base_connector_id_ = base_connector_id;
+ return *this;
+}
+
+Builder& Builder::SetPathTopology(const std::vector<uint64_t>& path_topology) {
+ path_topology_ = path_topology;
+ return *this;
+}
+
Builder& Builder::SetIsAspectPerservingScaling(bool val) {
is_aspect_preserving_scaling_ = val;
return *this;
@@ -308,6 +319,8 @@ FakeDisplaySnapshot::FakeDisplaySnapshot(
const gfx::Point& origin,
const gfx::Size& physical_size,
DisplayConnectionType type,
+ uint64_t base_connector_id,
+ const std::vector<uint64_t>& path_topology,
bool is_aspect_preserving_scaling,
bool has_overscan,
PrivacyScreenState privacy_screen_state,
@@ -325,6 +338,8 @@ FakeDisplaySnapshot::FakeDisplaySnapshot(
origin,
physical_size,
type,
+ base_connector_id,
+ path_topology,
is_aspect_preserving_scaling,
has_overscan,
privacy_screen_state,
diff --git a/chromium/ui/display/fake/fake_display_snapshot.h b/chromium/ui/display/fake/fake_display_snapshot.h
index d521fb34078..5b7eea6bc54 100644
--- a/chromium/ui/display/fake/fake_display_snapshot.h
+++ b/chromium/ui/display/fake/fake_display_snapshot.h
@@ -55,6 +55,8 @@ class FAKE_DISPLAY_EXPORT FakeDisplaySnapshot : public DisplaySnapshot {
Builder& AddMode(std::unique_ptr<DisplayMode> mode);
Builder& SetOrigin(const gfx::Point& origin);
Builder& SetType(DisplayConnectionType type);
+ Builder& SetBaseConnectorId(uint64_t base_connector_id);
+ Builder& SetPathTopology(const std::vector<uint64_t>& path_topology);
Builder& SetIsAspectPerservingScaling(bool is_aspect_preserving_scaling);
Builder& SetHasOverscan(bool has_overscan);
Builder& SetHasColorCorrectionMatrix(bool val);
@@ -85,6 +87,8 @@ class FAKE_DISPLAY_EXPORT FakeDisplaySnapshot : public DisplaySnapshot {
gfx::Point origin_;
float dpi_ = 96.0;
DisplayConnectionType type_ = DISPLAY_CONNECTION_TYPE_UNKNOWN;
+ uint64_t base_connector_id_ = 1u;
+ std::vector<uint64_t> path_topology_ = {};
bool is_aspect_preserving_scaling_ = false;
bool has_overscan_ = false;
PrivacyScreenState privacy_screen_state_ = kNotSupported;
@@ -106,6 +110,8 @@ class FAKE_DISPLAY_EXPORT FakeDisplaySnapshot : public DisplaySnapshot {
const gfx::Point& origin,
const gfx::Size& physical_size,
DisplayConnectionType type,
+ uint64_t base_connector_id,
+ const std::vector<uint64_t>& path_topology,
bool is_aspect_preserving_scaling,
bool has_overscan,
PrivacyScreenState privacy_screen_state,
diff --git a/chromium/ui/display/manager/BUILD.gn b/chromium/ui/display/manager/BUILD.gn
index a243223e044..189edadd577 100644
--- a/chromium/ui/display/manager/BUILD.gn
+++ b/chromium/ui/display/manager/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
import("//ui/display/display.gni")
@@ -55,6 +56,7 @@ component("manager") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//ui/base",
"//ui/display/mojom:mojom",
"//ui/display/util",
@@ -65,7 +67,7 @@ component("manager") {
defines = [ "DISPLAY_MANAGER_IMPLEMENTATION" ]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//chromeos/system" ]
}
}
diff --git a/chromium/ui/display/manager/DEPS b/chromium/ui/display/manager/DEPS
index a135804efd6..7b9c54bd5d1 100644
--- a/chromium/ui/display/manager/DEPS
+++ b/chromium/ui/display/manager/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+ash/constants",
"+chromeos",
"+third_party/skia",
"+ui/base",
diff --git a/chromium/ui/display/manager/configure_displays_task.cc b/chromium/ui/display/manager/configure_displays_task.cc
index 57eba9997e4..b679a30ad1b 100644
--- a/chromium/ui/display/manager/configure_displays_task.cc
+++ b/chromium/ui/display/manager/configure_displays_task.cc
@@ -4,14 +4,21 @@
#include "ui/display/manager/configure_displays_task.h"
+#include <cstddef>
+
#include "base/auto_reset.h"
#include "base/bind.h"
+#include "base/containers/flat_set.h"
#include "base/containers/queue.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
#include "base/stl_util.h"
#include "ui/display/manager/display_util.h"
#include "ui/display/types/display_configuration_params.h"
+#include "ui/display/types/display_constants.h"
+#include "ui/display/types/display_mode.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/native_display_delegate.h"
@@ -19,10 +26,23 @@ namespace display {
namespace {
+// Because we do not offer hardware mirroring, the maximal number of external
+// displays that can be configured is limited by the number of available CRTCs,
+// which is usually three. Since the lifetime of the UMA using this value is one
+// year (exp. Nov. 2021), five buckets are more than enough for
+// its histogram (between 0 to 4 external monitors).
+constexpr int kMaxDisplaysCount = 5;
+
// Find the next best mode after |display_mode|. If none can be found return
// nullptr.
const DisplayMode* FindNextMode(const DisplaySnapshot& display_state,
const DisplayMode* display_mode) {
+ // Internal displays are restricted to their native mode. We do not attempt to
+ // downgrade their modes upon failure.
+ if (display_state.type() == DISPLAY_CONNECTION_TYPE_INTERNAL) {
+ return nullptr;
+ }
+
if (!display_mode)
return nullptr;
@@ -40,6 +60,28 @@ const DisplayMode* FindNextMode(const DisplaySnapshot& display_state,
return best_mode;
}
+void LogIfInvalidRequestForInternalDisplay(
+ const DisplayConfigureRequest& request) {
+ if (request.display->type() != DISPLAY_CONNECTION_TYPE_INTERNAL)
+ return;
+
+ if (request.mode == nullptr)
+ return;
+
+ if (request.mode == request.display->native_mode())
+ return;
+
+ LOG(ERROR) << "A mode other than the preferred mode was requested for the "
+ "internal display: preferred="
+ << request.display->native_mode()->ToString()
+ << " vs. requested=" << request.mode->ToString()
+ << ". Current mode="
+ << (request.display->current_mode()
+ ? request.display->current_mode()->ToString()
+ : "nullptr (disabled)")
+ << ".";
+}
+
// Samples used to define buckets used by DisplayResolution enum.
// The enum is used to record screen resolution statistics.
const int32_t kDisplayResolutionSamples[] = {1024, 1280, 1440, 1920,
@@ -73,13 +115,81 @@ int ComputeDisplayResolutionEnum(const DisplayMode* mode) {
return width_idx * base::size(kDisplayResolutionSamples) + height_idx + 1;
}
-std::__wrap_iter<const DisplayConfigureRequest*> GetRequestForDisplayId(
- int64_t display_id,
- const std::vector<DisplayConfigureRequest>& requests) {
- return find_if(requests.begin(), requests.end(),
- [display_id](const DisplayConfigureRequest& request) {
- return request.display->display_id() == display_id;
- });
+void UpdateResolutionAndRefreshRateUma(const DisplayConfigureRequest& request) {
+ const bool internal =
+ request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
+
+ base::UmaHistogramExactLinear(
+ internal ? "ConfigureDisplays.Internal.Modeset.Resolution"
+ : "ConfigureDisplays.External.Modeset.Resolution",
+ ComputeDisplayResolutionEnum(request.mode),
+ base::size(kDisplayResolutionSamples) *
+ base::size(kDisplayResolutionSamples) +
+ 2);
+
+ base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
+ internal ? "ConfigureDisplays.Internal.Modeset.RefreshRate"
+ : "ConfigureDisplays.External.Modeset.RefreshRate",
+ 1, 240, 18, base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(request.mode ? std::round(request.mode->refresh_rate()) : 0);
+}
+
+void UpdateAttemptSucceededUma(
+ const std::vector<DisplayConfigureRequest>& requests,
+ bool display_success) {
+ for (const auto& request : requests) {
+ const bool internal =
+ request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
+ base::UmaHistogramBoolean(
+ internal ? "ConfigureDisplays.Internal.Modeset.AttemptSucceeded"
+ : "ConfigureDisplays.External.Modeset.AttemptSucceeded",
+ display_success);
+
+ VLOG(2) << "Configured status=" << display_success
+ << " display=" << request.display->display_id()
+ << " origin=" << request.origin.ToString()
+ << " mode=" << (request.mode ? request.mode->ToString() : "null");
+ }
+}
+
+void UpdateFinalStatusUma(
+ const std::vector<RequestAndStatusList>& requests_and_statuses) {
+ int mst_external_displays = 0;
+ size_t total_external_displays = requests_and_statuses.size();
+ for (auto& request_and_status : requests_and_statuses) {
+ const DisplayConfigureRequest& request = request_and_status.first;
+
+ // Is this display SST (single-stream vs. MST multi-stream).
+ bool sst_display = request.display->base_connector_id() &&
+ request.display->path_topology().empty();
+ if (!sst_display)
+ mst_external_displays++;
+
+ bool internal = request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
+ if (internal)
+ total_external_displays--;
+
+ base::UmaHistogramBoolean(
+ internal ? "ConfigureDisplays.Internal.Modeset.FinalStatus"
+ : "ConfigureDisplays.External.Modeset.FinalStatus",
+ request_and_status.second);
+ }
+
+ base::UmaHistogramExactLinear(
+ "ConfigureDisplays.Modeset.TotalExternalDisplaysCount",
+ base::checked_cast<int>(total_external_displays), kMaxDisplaysCount);
+
+ base::UmaHistogramExactLinear(
+ "ConfigureDisplays.Modeset.MstExternalDisplaysCount",
+ mst_external_displays, kMaxDisplaysCount);
+
+ if (total_external_displays > 0) {
+ const int mst_displays_percentage =
+ 100.0 * mst_external_displays / total_external_displays;
+ UMA_HISTOGRAM_PERCENTAGE(
+ "ConfigureDisplays.Modeset.MstExternalDisplaysPercentage",
+ mst_displays_percentage);
+ }
}
} // namespace
@@ -109,28 +219,22 @@ void ConfigureDisplaysTask::Run() {
std::vector<display::DisplayConfigurationParams> config_requests;
for (const auto& request : requests_) {
+ LogIfInvalidRequestForInternalDisplay(request);
+
config_requests.emplace_back(request.display->display_id(), request.origin,
request.mode);
- const bool internal =
- request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
- base::UmaHistogramExactLinear(
- internal ? "ConfigureDisplays.Internal.Modeset.Resolution"
- : "ConfigureDisplays.External.Modeset.Resolution",
- ComputeDisplayResolutionEnum(request.mode),
- base::size(kDisplayResolutionSamples) *
- base::size(kDisplayResolutionSamples) +
- 2);
- base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
- internal ? "ConfigureDisplays.Internal.Modeset.RefreshRate"
- : "ConfigureDisplays.External.Modeset.RefreshRate",
- 1, 240, 18, base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(request.mode ? std::round(request.mode->refresh_rate()) : 0);
- }
-
- delegate_->Configure(config_requests,
- base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
- weak_ptr_factory_.GetWeakPtr()));
+ UpdateResolutionAndRefreshRateUma(request);
+ }
+
+ const auto& on_configured =
+ pending_display_group_requests_.empty()
+ ? &ConfigureDisplaysTask::OnFirstAttemptConfigured
+ : &ConfigureDisplaysTask::OnRetryConfigured;
+
+ delegate_->Configure(
+ config_requests,
+ base::BindOnce(on_configured, weak_ptr_factory_.GetWeakPtr()));
}
void ConfigureDisplaysTask::OnConfigurationChanged() {}
@@ -142,74 +246,128 @@ void ConfigureDisplaysTask::OnDisplaySnapshotsInvalidated() {
std::move(callback_).Run(task_status_);
}
-void ConfigureDisplaysTask::OnConfigured(
- const base::flat_map<int64_t, bool>& statuses) {
- bool config_success = true;
- // Check if all displays are successfully configured.
- for (const auto& status : statuses) {
- int64_t display_id = status.first;
- bool display_success = status.second;
- config_success &= display_success;
+void ConfigureDisplaysTask::OnFirstAttemptConfigured(bool config_success) {
+ UpdateAttemptSucceededUma(requests_, config_success);
- auto request = GetRequestForDisplayId(display_id, requests_);
- DCHECK(request != requests_.end());
+ if (!config_success) {
+ // Partition |requests_| into smaller groups, update the task's state, and
+ // initiate the retry logic. The next time |delegate_|->Configure()
+ // terminates OnRetryConfigured() will be executed instead.
+ PartitionRequests();
+ DCHECK(!pending_display_group_requests_.empty());
+ requests_ = pending_display_group_requests_.front();
+ task_status_ = PARTIAL_SUCCESS;
+ Run();
+ return;
+ }
- VLOG(2) << "Configured status=" << display_success
- << " display=" << request->display->display_id()
- << " origin=" << request->origin.ToString()
- << " mode=" << (request->mode ? request->mode->ToString() : "null");
+ // This code execute only when the first modeset attempt fully succeeds.
+ // Update the displays' status and report success.
+ for (const auto& request : requests_) {
+ request.display->set_current_mode(request.mode);
+ request.display->set_origin(request.origin);
+ final_requests_status_.emplace_back(std::make_pair(request, true));
+ }
- bool internal =
- request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
- base::UmaHistogramBoolean(
- internal ? "ConfigureDisplays.Internal.Modeset.AttemptSucceeded"
- : "ConfigureDisplays.External.Modeset.AttemptSucceeded",
- display_success);
+ UpdateFinalStatusUma(final_requests_status_);
+ std::move(callback_).Run(task_status_);
+}
+
+void ConfigureDisplaysTask::OnRetryConfigured(bool config_success) {
+ UpdateAttemptSucceededUma(requests_, config_success);
+
+ if (!config_success) {
+ // If one of the largest display request can be downgraded, try again.
+ // Otherwise this configuration task is a failure.
+ if (DowngradeLargestRequestWithAlternativeModes()) {
+ Run();
+ return;
+ } else {
+ task_status_ = ERROR;
+ }
}
- // Update displays upon success or prep |requests_| for reconfiguration.
- if (config_success) {
- for (auto& request : requests_) {
+ // This code executes only when this display group request fully succeeds or
+ // fails to modeset. Update the final status of this group.
+ for (const auto& request : requests_) {
+ final_requests_status_.emplace_back(
+ std::make_pair(request, config_success));
+ if (config_success) {
request.display->set_current_mode(request.mode);
request.display->set_origin(request.origin);
}
- } else {
- bool should_reconfigure = false;
- // For the failing config, check if there is another mode to be requested.
- // If there is one, attempt to reconfigure everything again.
- for (const auto& status : statuses) {
- int64_t display_id = status.first;
- bool display_success = status.second;
- if (!display_success) {
- const DisplayConfigureRequest* request =
- GetRequestForDisplayId(display_id, requests_).base();
- const DisplayMode* next_mode =
- FindNextMode(*request->display, request->mode);
- if (next_mode) {
- const_cast<DisplayConfigureRequest*>(request)->mode = next_mode;
- should_reconfigure = true;
- }
- }
- }
- if (should_reconfigure) {
- task_status_ = PARTIAL_SUCCESS;
- Run();
- return;
+ }
+
+ // Subsequent modeset attempts will be done on the next pending display group,
+ // if one exists.
+ pending_display_group_requests_.pop();
+ requests_.clear();
+ if (!pending_display_group_requests_.empty()) {
+ requests_ = pending_display_group_requests_.front();
+ Run();
+ return;
+ }
+
+ // No more display groups to retry.
+ UpdateFinalStatusUma(final_requests_status_);
+ std::move(callback_).Run(task_status_);
+}
+
+void ConfigureDisplaysTask::PartitionRequests() {
+ pending_display_group_requests_ = PartitionedRequestsQueue();
+ base::flat_set<uint64_t> handled_connectors;
+
+ for (size_t i = 0; i < requests_.size(); ++i) {
+ uint64_t connector_id = requests_[i].display->base_connector_id();
+ if (handled_connectors.find(connector_id) != handled_connectors.end())
+ continue;
+
+ std::vector<DisplayConfigureRequest> request_group;
+ for (size_t j = i; j < requests_.size(); ++j) {
+ if (connector_id == requests_[j].display->base_connector_id())
+ request_group.push_back(requests_[j]);
}
+
+ pending_display_group_requests_.push(request_group);
+ handled_connectors.insert(connector_id);
}
+}
+
+bool ConfigureDisplaysTask::DowngradeLargestRequestWithAlternativeModes() {
+ auto cmp = [](DisplayConfigureRequest* lhs, DisplayConfigureRequest* rhs) {
+ return *lhs->mode < *rhs->mode;
+ };
+ std::priority_queue<DisplayConfigureRequest*,
+ std::vector<DisplayConfigureRequest*>, decltype(cmp)>
+ sorted_requests(cmp);
- // Update the final state.
for (auto& request : requests_) {
- bool internal = request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
- base::UmaHistogramBoolean(
- internal ? "ConfigureDisplays.Internal.Modeset.FinalStatus"
- : "ConfigureDisplays.External.Modeset.FinalStatus",
- config_success);
+ if (request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
+ continue;
+
+ if (!request.mode)
+ continue;
+
+ sorted_requests.push(&request);
}
- if (!config_success)
- task_status_ = ERROR;
- std::move(callback_).Run(task_status_);
+ // Fail if there are no viable candidates to downgrade
+ if (sorted_requests.empty())
+ return false;
+
+ while (!sorted_requests.empty()) {
+ DisplayConfigureRequest* next_request = sorted_requests.top();
+ sorted_requests.pop();
+
+ const DisplayMode* next_mode =
+ FindNextMode(*next_request->display, next_request->mode);
+ if (next_mode) {
+ next_request->mode = next_mode;
+ return true;
+ }
+ }
+
+ return false;
}
} // namespace display
diff --git a/chromium/ui/display/manager/configure_displays_task.h b/chromium/ui/display/manager/configure_displays_task.h
index 2c09b932317..f9084cc8843 100644
--- a/chromium/ui/display/manager/configure_displays_task.h
+++ b/chromium/ui/display/manager/configure_displays_task.h
@@ -11,7 +11,6 @@
#include <vector>
#include "base/callback.h"
-#include "base/containers/flat_map.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
@@ -35,7 +34,25 @@ struct DISPLAY_MANAGER_EXPORT DisplayConfigureRequest {
gfx::Point origin;
};
-// Applies the display configuration asynchronously.
+using RequestAndStatusList = std::pair<DisplayConfigureRequest, bool>;
+
+// ConfigureDisplaysTask is in charge of applying the display configuration as
+// requested by Ash. If the original request fails, the task will attempt to
+// modify the request by downgrading the resolution of one or more of the
+// displays and try again until it either succeeds a modeset or exhaust all
+// available options.
+//
+// Displays are bandwidth constrained in 2 ways: (1) system memory bandwidth
+// (ie: scanning pixels from memory), and (2) link bandwidth (ie: scanning
+// pixels from the SoC to the display). Naturally all displays share (1),
+// however with DisplayPort Multi-stream Transport (DP MST), displays may also
+// share (2). The introduction of MST support drastically increases the
+// likelihood of modeset failures due to (2) since multiple displays will all be
+// sharing the same physical connection.
+//
+// If we're constrained by (1), reducing the resolution of any display will
+// relieve pressure. However if we're constrained by (2), only those displays on
+// the saturated link can relieve pressure.
class DISPLAY_MANAGER_EXPORT ConfigureDisplaysTask
: public NativeDisplayObserver {
public:
@@ -52,6 +69,8 @@ class DISPLAY_MANAGER_EXPORT ConfigureDisplaysTask
};
using ResponseCallback = base::OnceCallback<void(Status)>;
+ using PartitionedRequestsQueue =
+ std::queue<std::vector<DisplayConfigureRequest>>;
ConfigureDisplaysTask(NativeDisplayDelegate* delegate,
const std::vector<DisplayConfigureRequest>& requests,
@@ -66,12 +85,49 @@ class DISPLAY_MANAGER_EXPORT ConfigureDisplaysTask
void OnDisplaySnapshotsInvalidated() override;
private:
- void OnConfigured(const base::flat_map<int64_t, bool>& statuses);
+ // Deals with the aftermath of the initial configuration, which attempts to
+ // configure all displays together.
+ // Upon failure, partitions the original request from Ash into smaller
+ // requests where the displays are grouped by the physical connector they
+ // connect to and initiates the retry sequence.
+ void OnFirstAttemptConfigured(bool config_status);
+
+ // Deals with the aftermath of a configuration retry, which attempts to
+ // configure a subset of the displays grouped together by the physical
+ // connector they connect to.
+ // Upon success, initiates the retry sequence on the next group of displays.
+ // Otherwise, downgrades the display with the largest bandwidth requirement
+ // and tries again.
+ // If any of the display groups entirely fail to modeset (i.e. exhaust all
+ // available modes during retry), the configuration will fail as a whole, but
+ // will continue to try to modeset the remaining display groups.
+ void OnRetryConfigured(bool config_status);
+
+ // Partition |requests_| by their base connector id (i.e. the physical
+ // connector the displays are connected to) and populate the result in
+ // |pending_display_group_requests_|. We assume the order of requests
+ // submitted by Ash is important, so the partitioning is done in order.
+ void PartitionRequests();
+
+ // Downgrade the request with the highest bandwidth requirement AND
+ // alternative modes in |requests_| (excluding internal displays and disable
+ // requests). Return false if no request was downgraded.
+ bool DowngradeLargestRequestWithAlternativeModes();
NativeDisplayDelegate* delegate_; // Not owned.
+ // Initially, |requests_| holds the configuration request submitted by Ash.
+ // During retry, |requests_| will represent a group of displays that are
+ // currently attempting configuration.
std::vector<DisplayConfigureRequest> requests_;
+ // A queue of display requests grouped by their
+ // |requests_[index]->display->base_connector_id()|.
+ PartitionedRequestsQueue pending_display_group_requests_;
+
+ // The final requests and their configuration status for UMA.
+ std::vector<RequestAndStatusList> final_requests_status_;
+
// When the task finishes executing it runs the callback to notify that the
// task is done and the task status.
ResponseCallback callback_;
diff --git a/chromium/ui/display/manager/configure_displays_task_unittest.cc b/chromium/ui/display/manager/configure_displays_task_unittest.cc
index 92c8ee4efa6..ff33395f1bf 100644
--- a/chromium/ui/display/manager/configure_displays_task_unittest.cc
+++ b/chromium/ui/display/manager/configure_displays_task_unittest.cc
@@ -14,31 +14,46 @@
#include "ui/display/manager/configure_displays_task.h"
#include "ui/display/manager/test/action_logger_util.h"
#include "ui/display/manager/test/test_native_display_delegate.h"
+#include "ui/display/types/display_constants.h"
namespace display {
namespace test {
namespace {
+// Non-zero generic connector IDs.
+constexpr uint64_t kEdpConnectorId = 71u;
+constexpr uint64_t kSecondConnectorId = kEdpConnectorId + 10u;
+constexpr uint64_t kThirdConnectorId = kEdpConnectorId + 20u;
+
+// Invalid PATH topology parse connector ID.
+constexpr uint64_t kInvalidConnectorId = 0u;
+
class ConfigureDisplaysTaskTest : public testing::Test {
public:
ConfigureDisplaysTaskTest()
: delegate_(&log_),
small_mode_(gfx::Size(1366, 768), false, 60.0f),
+ medium_mode_(gfx::Size(1920, 1080), false, 60.0f),
big_mode_(gfx::Size(2560, 1600), false, 60.0f) {}
~ConfigureDisplaysTaskTest() override = default;
void SetUp() override {
displays_.push_back(FakeDisplaySnapshot::Builder()
.SetId(123)
- .SetNativeMode(small_mode_.Clone())
- .SetCurrentMode(small_mode_.Clone())
+ .SetNativeMode(medium_mode_.Clone())
+ .SetCurrentMode(medium_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_INTERNAL)
+ .SetBaseConnectorId(kEdpConnectorId)
.Build());
displays_.push_back(FakeDisplaySnapshot::Builder()
.SetId(456)
.SetNativeMode(big_mode_.Clone())
.SetCurrentMode(big_mode_.Clone())
.AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
.Build());
}
@@ -56,6 +71,7 @@ class ConfigureDisplaysTaskTest : public testing::Test {
ConfigureDisplaysTask::Status status_ = ConfigureDisplaysTask::ERROR;
const DisplayMode small_mode_;
+ const DisplayMode medium_mode_;
const DisplayMode big_mode_;
std::vector<std::unique_ptr<DisplaySnapshot>> displays_;
@@ -66,24 +82,30 @@ class ConfigureDisplaysTaskTest : public testing::Test {
} // namespace
-TEST_F(ConfigureDisplaysTaskTest, ConfigureWithOneDisplay) {
+/**************************************************
+ * Cases that report ConfigureDisplaysTask::SUCCESS
+ **************************************************/
+
+TEST_F(ConfigureDisplaysTaskTest, ConfigureInternalDisplay) {
ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
&ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
std::vector<DisplayConfigureRequest> requests(
- 1,
- DisplayConfigureRequest(displays_[0].get(), &small_mode_, gfx::Point()));
+ 1, DisplayConfigureRequest(displays_[0].get(),
+ displays_[0]->native_mode(), gfx::Point()));
ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
task.Run();
EXPECT_TRUE(callback_called_);
EXPECT_EQ(ConfigureDisplaysTask::SUCCESS, status_);
- EXPECT_EQ(
- GetCrtcAction({displays_[0]->display_id(), gfx::Point(), &small_mode_}),
- log_.GetActionsAndClear());
+ EXPECT_EQ(GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()}),
+ log_.GetActionsAndClear());
}
-TEST_F(ConfigureDisplaysTaskTest, ConfigureWithTwoDisplay) {
+// Tests that and an internal + one external display pass modeset. Note that
+// this case covers an external display connected via MST as well.
+TEST_F(ConfigureDisplaysTaskTest, ConfigureInternalAndOneExternalDisplays) {
ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
&ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
@@ -98,7 +120,7 @@ TEST_F(ConfigureDisplaysTaskTest, ConfigureWithTwoDisplay) {
EXPECT_TRUE(callback_called_);
EXPECT_EQ(ConfigureDisplaysTask::SUCCESS, status_);
EXPECT_EQ(JoinActions(GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
- &small_mode_})
+ displays_[0]->native_mode()})
.c_str(),
GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
&big_mode_})
@@ -107,7 +129,128 @@ TEST_F(ConfigureDisplaysTaskTest, ConfigureWithTwoDisplay) {
log_.GetActionsAndClear());
}
-TEST_F(ConfigureDisplaysTaskTest, DisableDisplayFails) {
+// Tests that one external display (with no internal display present;
+// e.g. chromebox) pass modeset. Note that this case covers an external display
+// connected via MST as well.
+TEST_F(ConfigureDisplaysTaskTest, ConfigureOneExternalDisplay) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ std::vector<DisplayConfigureRequest> requests(
+ 1, DisplayConfigureRequest(displays_[1].get(),
+ displays_[1]->native_mode(), gfx::Point()));
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::SUCCESS, status_);
+ EXPECT_EQ(GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
+ displays_[1]->native_mode()}),
+ log_.GetActionsAndClear());
+}
+
+// Tests that two external MST displays (with no internal display present; e.g.
+// chromebox) pass modeset.
+TEST_F(ConfigureDisplaysTaskTest, ConfigureTwoMstDisplays) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ // Two displays sharing the same base connector via MST.
+ displays_[0] = FakeDisplaySnapshot::Builder()
+ .SetId(456)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build();
+ displays_[1] = FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build();
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::SUCCESS, status_);
+ EXPECT_EQ(
+ JoinActions(
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Although most devices do not support more than three displays in total
+// (including the internal display), this tests that this configuration can pass
+// all displays in a single request.
+TEST_F(ConfigureDisplaysTaskTest, ConfigureInternalAndTwoMstAndHdmiDisplays) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ // Add an additional display to base connector kSecondConnectorId via MST.
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build());
+
+ // Additional independent HDMI display (has its own connector).
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(101112)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(medium_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_HDMI)
+ .SetBaseConnectorId(kThirdConnectorId)
+ .Build());
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::SUCCESS, status_);
+ EXPECT_EQ(
+ JoinActions(
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+/************************************************
+ * Cases that report ConfigureDisplaysTask::ERROR
+ ************************************************/
+
+TEST_F(ConfigureDisplaysTaskTest, DisableInternalDisplayFails) {
ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
&ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
@@ -120,14 +263,55 @@ TEST_F(ConfigureDisplaysTaskTest, DisableDisplayFails) {
EXPECT_TRUE(callback_called_);
EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
- EXPECT_EQ(JoinActions(GetCrtcAction(
- {displays_[0]->display_id(), gfx::Point(), nullptr})
- .c_str(),
- nullptr),
+ EXPECT_EQ(
+ JoinActions(
+ // Initial modeset fails. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(), nullptr})
+ .c_str(),
+ // There is no way to downgrade a disable request. Configuration
+ // fails.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(), nullptr})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests that the internal display does not attempt to fallback to alternative
+// modes upon failure to modeset with preferred mode.
+TEST_F(ConfigureDisplaysTaskTest, NoModeChangeAttemptWhenInternalDisplayFails) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ delegate_.set_max_configurable_pixels(1);
+
+ std::vector<DisplayConfigureRequest> requests(
+ 1, DisplayConfigureRequest(displays_[0].get(),
+ displays_[0]->native_mode(), gfx::Point()));
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
+ EXPECT_EQ(JoinActions(
+ // Initial modeset fails. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // Retry logic fails to modeset internal display. Since internal
+ // displays are restricted to their preferred mode, there are no
+ // other modes to try. The configuration fails completely.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ nullptr),
log_.GetActionsAndClear());
}
-TEST_F(ConfigureDisplaysTaskTest, ConfigureWithOneDisplayFails) {
+// Tests that an external display (with no internal display present; e.g.
+// chromebox) attempts to fallback to alternative modes upon failure to modeset
+// to the original request before completely failing. Note that this case
+// applies to a single external display over MST as well.
+TEST_F(ConfigureDisplaysTaskTest, ConfigureOneExternalNoInternalDisplayFails) {
ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
&ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
@@ -140,20 +324,106 @@ TEST_F(ConfigureDisplaysTaskTest, ConfigureWithOneDisplayFails) {
EXPECT_TRUE(callback_called_);
EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
- EXPECT_EQ(JoinActions(GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
- &big_mode_})
- .c_str(),
- GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- nullptr),
- log_.GetActionsAndClear());
+ EXPECT_EQ(
+ JoinActions(
+ // Initial modeset fails. Initiate retry logic.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // External display will fail, downgrade once, and fail completely.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
}
-TEST_F(ConfigureDisplaysTaskTest, ConfigureWithTwoDisplayFails) {
+// Tests that two external non-MST displays (with no internal display present;
+// e.g. chromebox) attempt to fallback to alternative modes upon failure to
+// modeset to the original request before completely failing.
+TEST_F(ConfigureDisplaysTaskTest, ConfigureTwoNoneMstDisplaysNoInternalFail) {
ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
&ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+ displays_[0] = FakeDisplaySnapshot::Builder()
+ .SetId(456)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build();
+ displays_[1] = FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(medium_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kThirdConnectorId)
+ .Build();
+
+ delegate_.set_max_configurable_pixels(small_mode_.size().GetArea());
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // |displays_[0]| will fail, downgrade once, and pass.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[0]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ // |displays_[1]| will fail, downgrade once, and fail completely.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests that two external MST displays (with no internal display present; e.g.
+// chromebox) attempt to fallback to alternative modes upon failure to modeset
+// to the original request before completely failing.
+TEST_F(ConfigureDisplaysTaskTest, ConfigureTwoMstDisplaysNoInternalFail) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ // Two displays sharing the same base connector.
+ displays_[0] = FakeDisplaySnapshot::Builder()
+ .SetId(456)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build();
+ displays_[1] = FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(medium_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build();
+
delegate_.set_max_configurable_pixels(1);
std::vector<DisplayConfigureRequest> requests;
@@ -166,26 +436,114 @@ TEST_F(ConfigureDisplaysTaskTest, ConfigureWithTwoDisplayFails) {
EXPECT_TRUE(callback_called_);
EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
- EXPECT_EQ(JoinActions(GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
- &big_mode_})
- .c_str(),
- GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- nullptr),
- log_.GetActionsAndClear());
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // MST displays will be tested (and fail) together.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // |displays_[0]| will downgrade first. Configuration will fail.
+ GetCrtcAction(
+ {displays_[0]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // |displays_[1] will downgrade next. Configuration still fails.
+ GetCrtcAction(
+ {displays_[0]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ // Since |displays_[1]| is still the largest and has one more mode, it
+ // downgrades again. Configuration fails completely.
+ GetCrtcAction(
+ {displays_[0]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
}
-TEST_F(ConfigureDisplaysTaskTest, ReconfigureLastDisplayPartialSuccess) {
+// Tests that the internal display does not attempt to fallback to alternative
+// modes upon failure to modeset with preferred mode while an external display
+// is present. Note that this case applies for an internal + a single external
+// display over MST as well.
+TEST_F(ConfigureDisplaysTaskTest,
+ ConfigureInternalAndOneExternalDisplaysFailsDueToInternal) {
ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
&ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+ delegate_.set_max_configurable_pixels(1);
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Retry logic fails to modeset internal display. Since internal
+ // displays are restricted to their preferred mode, there are no other
+ // modes to try. The configuration will fail completely, but the
+ // external display will attempt to modeset as well.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // External display will fail, downgrade once, and fail again.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests that an external display attempts to fallback to alternative modes upon
+// failure to modeset to the original request after the internal display modeset
+// successfully. Note that this case applies for an internal + a single MST
+// display as well.
+TEST_F(ConfigureDisplaysTaskTest,
+ ConfigureInternalAndOneExternalDisplaysFailsDueToExternal) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ displays_[0] = FakeDisplaySnapshot::Builder()
+ .SetId(123)
+ .SetNativeMode(small_mode_.Clone())
+ .SetCurrentMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_INTERNAL)
+ .SetBaseConnectorId(kEdpConnectorId)
+ .Build();
+ displays_[1] = FakeDisplaySnapshot::Builder()
+ .SetId(456)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(medium_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build();
+
delegate_.set_max_configurable_pixels(small_mode_.size().GetArea());
std::vector<DisplayConfigureRequest> requests;
@@ -197,24 +555,676 @@ TEST_F(ConfigureDisplaysTaskTest, ReconfigureLastDisplayPartialSuccess) {
task.Run();
EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Internal display will succeed to modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // External display fails, downgrades once, and fails completely.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests that the internal display does not attempt to fallback to alternative
+// modes upon failure to modeset with preferred mode while two external MST
+// displays are present.
+TEST_F(ConfigureDisplaysTaskTest,
+ ConfigureInternalAndTwoMstExternalDisplaysFailsDueToInternal) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ // Add an additional display to base connector kSecondConnectorId via MST.
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build());
+
+ delegate_.set_max_configurable_pixels(1);
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Retry logic fails to modeset internal display. Since internal
+ // displays are restricted to their preferred mode, there are no other
+ // modes to try. The configuration will fail completely. The external
+ // displays will attempt to modeset next.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // MST displays will be tested (and fail) together.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // |displays_[1]| will downgrade first. Configuration will fail.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // |displays_[2] will downgrade next and configuration fails
+ // completely.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests that two external MST displays attempt to fallback to alternative modes
+// upon failure to modeset to the original request after the internal display
+// succeeded to modeset
+TEST_F(ConfigureDisplaysTaskTest,
+ ConfigureInternalAndTwoMstExternalDisplaysFailsDueToExternals) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ displays_[0] = FakeDisplaySnapshot::Builder()
+ .SetId(123)
+ .SetNativeMode(small_mode_.Clone())
+ .SetCurrentMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_INTERNAL)
+ .SetBaseConnectorId(kEdpConnectorId)
+ .Build();
+ // Two MST displays sharing the same base connector.
+ displays_[1] = FakeDisplaySnapshot::Builder()
+ .SetId(456)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build();
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(medium_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build());
+
+ delegate_.set_max_configurable_pixels(small_mode_.size().GetArea());
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Internal display will succeed to modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // MST displays will be tested (and fail) together.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // |displays_[1]| will downgrade first. Configuration will fail.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // |displays_[2] will downgrade next and configuration fails
+ // completely.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests that the internal display does not attempt to fallback to alternative
+// modes upon failure to modeset with preferred mode while two MST and one HDMI
+// displays are present.
+TEST_F(ConfigureDisplaysTaskTest,
+ ConfigureInternalAndTwoMstAndHdmiDisplaysFailsDueToInternal) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ // Add an additional display to kSecondConnectorId (via MST).
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build());
+
+ // Additional independent HDMI display (has its own connector).
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(101112)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(medium_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_HDMI)
+ .SetBaseConnectorId(kThirdConnectorId)
+ .Build());
+
+ delegate_.set_max_configurable_pixels(1);
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Retry logic fails to modeset internal display. Since internal
+ // displays are restricted to their preferred mode, there are no other
+ // modes to try. The configuration will fail completely, but the
+ // external displays will still attempt to configure.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // MST displays_[1,2] will be tested (and fail) together. displays_[1]
+ // downgrades first and fails, Then displays_[2], and the process will
+ // repeat once more before the group fails to modeset.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ // Finally, HDMI display will attempt to modeset and cycle through its
+ // three available modes.
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests that two external MST displays attempt to fallback to alternative modes
+// upon failure to modeset to the original request after the internal display
+// succeeded to modeset.
+TEST_F(ConfigureDisplaysTaskTest,
+ ConfigureInternalAndTwoMstAndHdmiDisplaysFailsDueToMst) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ // Add an additional display to kSecondConnectorId (via MST).
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build());
+
+ // Additional independent HDMI display (has its own connector).
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(101112)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(medium_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_HDMI)
+ .SetBaseConnectorId(kThirdConnectorId)
+ .Build());
+
+ delegate_.set_max_configurable_pixels(medium_mode_.size().GetArea());
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Internal display will succeed to modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // MST displays will be tested (and fail) together. displays_[1]
+ // downgrade first. Modeset fails.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // displays_[2] downgrade next, but there are no other modes available
+ // for displays_[2], so configuration fails completely for the MST
+ // group. The HDMI display will attempt to modeset nest.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // HDMI display attempts to modeset, fails, downgrades once, and
+ // passes modeset.
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests that the HDMI display attempts to fallback to alternative modes upon
+// failure to modeset to the original request after the internal and two MST
+// displays succeeded to modeset.
+TEST_F(ConfigureDisplaysTaskTest,
+ ConfigureInternalAndTwoMstAndHdmiDisplaysFailsDueToHDMI) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ // Two displays sharing the same base connector.
+ displays_[1] = FakeDisplaySnapshot::Builder()
+ .SetId(456)
+ .SetNativeMode(medium_mode_.Clone())
+ .SetCurrentMode(medium_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build();
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(medium_mode_.Clone())
+ .SetCurrentMode(medium_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build());
+
+ // Additional independent HDMI display (has its own connector).
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(101112)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_HDMI)
+ .SetBaseConnectorId(kThirdConnectorId)
+ .Build());
+
+ delegate_.set_max_configurable_pixels(medium_mode_.size().GetArea());
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Internal display will succeed modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // MST displays will be tested and pass together.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ // HDMI display will fail modeset, but since there are no other modes
+ // available for fallback configuration fails completely.
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests that two external displays that share a bad MST hub are tested and fail
+// together, since they are grouped under kInvalidConnectorId. Also test that
+// this does not affect the internal display's ability configured separately
+// during retry and passes modeset.
+TEST_F(ConfigureDisplaysTaskTest,
+ ConfigureInternalAndOneBadMstHubWithTwoDisplaysFails) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ // Two displays sharing a bad MST Hub that did not report its PATH topology
+ // correctly.
+ displays_[1] = FakeDisplaySnapshot::Builder()
+ .SetId(456)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kInvalidConnectorId)
+ .Build();
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kInvalidConnectorId)
+ .Build());
+
+ delegate_.set_max_configurable_pixels(medium_mode_.size().GetArea());
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Internal display will succeed modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // displays_[1] and displays_[2] will be tested and fail together
+ // under connector kInvalidConnectorId. Since neither expose any
+ // alternative modes to try, configuration completely fails.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests that four external displays that share two separate bad MST hubs are
+// tested and fail together, since they are grouped under kInvalidConnectorId.
+// Also test that this does not affect the internal display's ability configured
+// separately during retry and passes modeset.
+TEST_F(ConfigureDisplaysTaskTest,
+ ConfigureInternalAndTwoBadMstHubsWithFourDisplaysFails) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ // Four displays sharing two bad MST Hubs that did not report their PATH
+ // topology correctly. First two:
+ displays_[1] = FakeDisplaySnapshot::Builder()
+ .SetId(456)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kInvalidConnectorId)
+ .Build();
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(medium_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kInvalidConnectorId)
+ .Build());
+
+ // Last two:
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(101112)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(medium_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kInvalidConnectorId)
+ .Build());
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(131415)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kInvalidConnectorId)
+ .Build());
+
+ delegate_.set_max_configurable_pixels(medium_mode_.size().GetArea());
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::ERROR, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[4]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Internal display will succeed modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // displays_[1-4] will be tested and downgraded as a group, since they
+ // share kInvalidConnectorId due to bad MST hubs.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[4]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // displays_[2] will downgrade first, since it is the next largest
+ // display with available alternative modes.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[4]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // displays_[3] will downgrade next, and fail.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[4]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Same downgrade process as above will repeat for displays_[2] and
+ // displays_[3] before failing completely.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[4]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[4]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+/**********************************************************
+ * Cases that report ConfigureDisplaysTask::PARTIAL_SUCCESS
+ **********************************************************/
+
+// Tests that the last display (in order of available displays) attempts and
+// succeeds to fallback after it fails to modeset the initial request.
+TEST_F(ConfigureDisplaysTaskTest, ConfigureLastDisplayPartialSuccess) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ delegate_.set_max_configurable_pixels(medium_mode_.size().GetArea());
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
EXPECT_EQ(ConfigureDisplaysTask::PARTIAL_SUCCESS, status_);
- EXPECT_EQ(JoinActions(GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
- &big_mode_})
- .c_str(),
- GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- nullptr),
- log_.GetActionsAndClear());
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Internal display will succeed to modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // Last display will fail once, downgrade, and pass.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
}
-TEST_F(ConfigureDisplaysTaskTest, ReconfigureMiddleDisplayPartialSuccess) {
+// Tests that the second display (in order of available displays) attempts and
+// succeeds to fallback after it fails to modeset the initial request.
+TEST_F(ConfigureDisplaysTaskTest, ConfigureMiddleDisplayPartialSuccess) {
ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
&ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
@@ -222,9 +1232,11 @@ TEST_F(ConfigureDisplaysTaskTest, ReconfigureMiddleDisplayPartialSuccess) {
.SetId(789)
.SetNativeMode(small_mode_.Clone())
.SetCurrentMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_HDMI)
+ .SetBaseConnectorId(kThirdConnectorId)
.Build());
- delegate_.set_max_configurable_pixels(small_mode_.size().GetArea());
+ delegate_.set_max_configurable_pixels(medium_mode_.size().GetArea());
std::vector<DisplayConfigureRequest> requests;
for (const auto& display : displays_) {
@@ -236,34 +1248,338 @@ TEST_F(ConfigureDisplaysTaskTest, ReconfigureMiddleDisplayPartialSuccess) {
EXPECT_TRUE(callback_called_);
EXPECT_EQ(ConfigureDisplaysTask::PARTIAL_SUCCESS, status_);
- EXPECT_EQ(JoinActions(GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
- &big_mode_})
- .c_str(),
- GetCrtcAction({displays_[2]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[2]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- nullptr),
- log_.GetActionsAndClear());
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ // Internal display will succeed to modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // Second display will fail once, downgrade, and pass.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ // Third external display will succeed to modeset on first attempt.
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
}
+// Tests that both MST displays fail initial configuration and are tested,
+// downgraded, and eventually pass modeset as a group and separately from the
+// internal display.
+TEST_F(ConfigureDisplaysTaskTest, ConfigureTwoMstDisplaysPartialSuccess) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ // Add an additional display to the base connector kSecondConnectorId via MST.
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build());
+
+ delegate_.set_max_configurable_pixels(medium_mode_.size().GetArea());
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::PARTIAL_SUCCESS, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Internal display will succeed modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // MST displays will be tested (and fail) together.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // |displays_[1]| will downgrade first. Configuration will fail.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // |displays_[2] will downgrade next. Configuration succeeds.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests that the two MST displays, and then the HDMI display fail initial
+// configuration, are tested, downgraded, and eventually pass modeset as
+// separate groups.
+TEST_F(ConfigureDisplaysTaskTest,
+ ConfigureInternalAndTwoMstAndHdmiDisplaysPartialSuccess) {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ // Add an additional display to the base connector kSecondConnectorId via MST.
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build());
+
+ // Additional independent HDMI display (has its own connector).
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(101112)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(medium_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_HDMI)
+ .SetBaseConnectorId(kThirdConnectorId)
+ .Build());
+
+ delegate_.set_max_configurable_pixels(medium_mode_.size().GetArea());
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(), gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::PARTIAL_SUCCESS, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Internal display will succeed modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // Both MST displays will be tested (and fail) together.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // |displays_[1]| will downgrade first. Configuration will fail.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // |displays_[2] will downgrade next. Configuration succeeds.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ // HDMI display will fail modeset and downgrade once. Configuration
+ // will then succeed.
+ GetCrtcAction({displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &medium_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+}
+
+// Tests a nested MST configuration in which after a successful modset on the
+// root branch device (i.e. two external displays connected to a single MST hub)
+// one display is removed from the original MST hub, connected to a second MST
+// hub together with a third display, and then the second MST hub is connected
+// to the first. The tests ensures that the three MST displays are grouped,
+// tested, and fallback together appropriately before passing modeset.
+TEST_F(ConfigureDisplaysTaskTest,
+ ConfigureInternalAndMstThenNestAnotherMstForThreeExternalDisplays) {
+ // We now have one internal display + two external displays connected via MST.
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(789)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build());
+
+ // Initial configuration succeeds modeset.
+ {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(),
+ gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::SUCCESS, status_);
+ EXPECT_EQ(
+ JoinActions(GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+ }
+
+ // Add an additional display to kSecondConnectorId. This is akin to unplugging
+ // One display from the first MST hub, attaching it to a second one, together
+ // with a third display, and plugging the second MST hub to the first.
+ displays_.push_back(FakeDisplaySnapshot::Builder()
+ .SetId(101112)
+ .SetNativeMode(big_mode_.Clone())
+ .SetCurrentMode(big_mode_.Clone())
+ .AddMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kSecondConnectorId)
+ .Build());
+
+ // Simulate bandwidth pressure by reducing configurable pixels.
+ delegate_.set_max_configurable_pixels(medium_mode_.size().GetArea());
+
+ // This configuration requires that all displays connected via the nested
+ // MST setup downgrade, so we test that all three displays are grouped,
+ // fallback appropriately, and eventually succeed modeset.
+ {
+ ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
+ &ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
+
+ std::vector<DisplayConfigureRequest> requests;
+ for (const auto& display : displays_) {
+ requests.emplace_back(display.get(), display->native_mode(),
+ gfx::Point());
+ }
+
+ ConfigureDisplaysTask task(&delegate_, requests, std::move(callback));
+ task.Run();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(ConfigureDisplaysTask::PARTIAL_SUCCESS, status_);
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Internal display will succeed to modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // All MST displays will fail modeset together.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // displays_[1] will downgrade first, then displays_[2], followed by
+ // displays_[3]. Then the configuration will pass modeset.
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[2]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[3]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
+ }
+}
+
+// Tests that an internal display with one external display pass modeset
+// asynchronously after the external display fallback once.
TEST_F(ConfigureDisplaysTaskTest, AsyncConfigureWithTwoDisplaysPartialSuccess) {
ConfigureDisplaysTask::ResponseCallback callback = base::BindOnce(
&ConfigureDisplaysTaskTest::ConfigureCallback, base::Unretained(this));
delegate_.set_run_async(true);
- delegate_.set_max_configurable_pixels(small_mode_.size().GetArea());
+ delegate_.set_max_configurable_pixels(medium_mode_.size().GetArea());
std::vector<DisplayConfigureRequest> requests;
for (const auto& display : displays_) {
@@ -278,20 +1594,26 @@ TEST_F(ConfigureDisplaysTaskTest, AsyncConfigureWithTwoDisplaysPartialSuccess) {
EXPECT_TRUE(callback_called_);
EXPECT_EQ(ConfigureDisplaysTask::PARTIAL_SUCCESS, status_);
- EXPECT_EQ(JoinActions(GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
- &big_mode_})
- .c_str(),
- GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[1]->display_id(), gfx::Point(),
- &small_mode_})
- .c_str(),
- nullptr),
- log_.GetActionsAndClear());
+ EXPECT_EQ(
+ JoinActions(
+ // All displays will fail to modeset together.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ // Internal display will succeed to modeset.
+ GetCrtcAction({displays_[0]->display_id(), gfx::Point(),
+ displays_[0]->native_mode()})
+ .c_str(),
+ // External display will fail once, downgrade, and pass.
+ GetCrtcAction({displays_[1]->display_id(), gfx::Point(), &big_mode_})
+ .c_str(),
+ GetCrtcAction(
+ {displays_[1]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ nullptr),
+ log_.GetActionsAndClear());
}
} // namespace test
diff --git a/chromium/ui/display/manager/display_change_observer.cc b/chromium/ui/display/manager/display_change_observer.cc
index 249c7e49278..059ed70eabe 100644
--- a/chromium/ui/display/manager/display_change_observer.cc
+++ b/chromium/ui/display/manager/display_change_observer.cc
@@ -14,9 +14,8 @@
#include "base/check_op.h"
#include "base/command_line.h"
-#include "base/cpu.h"
-#include "base/no_destructor.h"
#include "base/stl_util.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/user_activity/user_activity_detector.h"
#include "ui/display/display.h"
@@ -78,7 +77,7 @@ ManagedDisplayInfo::ManagedDisplayModeList GetModeListWithAllRefreshRates(
return display_mode_list;
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Constructs the raster DisplayColorSpaces out of |snapshot_color_space|,
// including the HDR ones if present and |allow_high_bit_depth| is set.
gfx::DisplayColorSpaces FillDisplayColorSpaces(
@@ -110,13 +109,6 @@ gfx::DisplayColorSpaces FillDisplayColorSpaces(
gfx::DisplayColorSpaces display_color_spaces = gfx::DisplayColorSpaces(
sdr_color_space, DisplaySnapshot::PrimaryFormat());
- // AMD Chromebooks have issues playing back and scanning out high bit depth
- // content. TODO(b/169576243, b/165825264): remove this provision when fixed.
- static const base::NoDestructor<base::CPU> cpuid;
- static const bool is_amd = cpuid->vendor_name() == "AuthenticAMD";
- if (is_amd)
- return display_color_spaces;
-
if (allow_high_bit_depth && snapshot_color_space.IsHDR()) {
constexpr float kSDRJoint = 0.75;
constexpr float kHDRLevel = 4.0;
@@ -393,7 +385,7 @@ ManagedDisplayInfo DisplayChangeObserver::CreateManagedDisplayInfo(
if (dpi)
new_info.set_device_dpi(dpi);
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(crbug.com/1012846): This should configure the HDR color spaces.
gfx::DisplayColorSpaces display_color_spaces(
snapshot->color_space(), DisplaySnapshot::PrimaryFormat());
diff --git a/chromium/ui/display/manager/display_change_observer_unittest.cc b/chromium/ui/display/manager/display_change_observer_unittest.cc
index 8e17c1b80ee..04b41e627ed 100644
--- a/chromium/ui/display/manager/display_change_observer_unittest.cc
+++ b/chromium/ui/display/manager/display_change_observer_unittest.cc
@@ -9,6 +9,7 @@
#include "base/strings/stringprintf.h"
#include "base/test/scoped_feature_list.h"
+#include "build/chromeos_buildflags.h"
#include "cc/base/math_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/display_features.h"
@@ -190,8 +191,9 @@ TEST_P(DisplayChangeObserverTest, GetExternalManagedDisplayModeList) {
TEST_P(DisplayChangeObserverTest, GetEmptyExternalManagedDisplayModeList) {
FakeDisplaySnapshot display_snapshot(
- 123, gfx::Point(), gfx::Size(), DISPLAY_CONNECTION_TYPE_UNKNOWN, false,
- false, PrivacyScreenState::kNotSupported, false, false, std::string(), {},
+ 123, gfx::Point(), gfx::Size(), DISPLAY_CONNECTION_TYPE_UNKNOWN,
+ /*base_connector_id=*/1u, /*path_topology=*/{}, false, false,
+ PrivacyScreenState::kNotSupported, false, false, std::string(), {},
nullptr, nullptr, 0, gfx::Size(), gfx::ColorSpace(),
/*bits_per_channel=*/8u);
@@ -419,7 +421,7 @@ TEST_P(DisplayChangeObserverTest, WCGDisplayColorSpaces) {
gfx::ColorSpace::TransferID::IEC61966_2_1);
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_P(DisplayChangeObserverTest, HDRDisplayColorSpaces) {
// TODO(crbug.com/1012846): Remove this flag and provision when HDR is fully
// supported on ChromeOS.
@@ -481,7 +483,7 @@ INSTANTIATE_TEST_SUITE_P(All,
DisplayChangeObserverTest,
::testing::Values(false, true));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
using DisplayResolutionTest = testing::Test;
TEST_F(DisplayResolutionTest, CheckEffectiveResoutionUMAIndex) {
diff --git a/chromium/ui/display/manager/display_configurator.cc b/chromium/ui/display/manager/display_configurator.cc
index aade5924df2..3965eace337 100644
--- a/chromium/ui/display/manager/display_configurator.cc
+++ b/chromium/ui/display/manager/display_configurator.cc
@@ -12,6 +12,7 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/syslog_logging.h"
#include "base/time/time.h"
#include "chromeos/system/devicemode.h"
#include "ui/display/display.h"
@@ -330,8 +331,9 @@ bool DisplayConfigurator::DisplayLayoutManagerImpl::GetDisplayLayout(
const DisplayMode* mode_info = states[0].mirror_mode;
if (!mode_info) {
- LOG(WARNING) << "No mirror mode when configuring display: "
- << states[0].display->ToString();
+ SYSLOG(INFO) << "Either hardware mirroring was disabled or no common "
+ "mode between the available displays was found to "
+ "support it. Using software mirroring instead.";
return false;
}
size = mode_info->size();
diff --git a/chromium/ui/display/manager/display_configurator_unittest.cc b/chromium/ui/display/manager/display_configurator_unittest.cc
index 958d00425c4..2d6436d3947 100644
--- a/chromium/ui/display/manager/display_configurator_unittest.cc
+++ b/chromium/ui/display/manager/display_configurator_unittest.cc
@@ -7,18 +7,19 @@
#include <stddef.h>
#include <stdint.h>
+#include "ash/constants/ash_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
-#include "chromeos/constants/chromeos_switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/display_features.h"
#include "ui/display/fake/fake_display_snapshot.h"
#include "ui/display/manager/test/action_logger_util.h"
#include "ui/display/manager/test/test_native_display_delegate.h"
+#include "ui/display/types/display_constants.h"
#include "ui/display/util/display_util.h"
namespace display {
@@ -28,6 +29,11 @@ namespace {
constexpr int64_t kDisplayIds[3] = {123, 456, 789};
+// Non-zero generic connector IDs.
+constexpr uint64_t kEdpConnectorId = 71u;
+constexpr uint64_t kSecondConnectorId = kEdpConnectorId + 10u;
+constexpr uint64_t kThirdConnectorId = kEdpConnectorId + 20u;
+
std::unique_ptr<DisplayMode> MakeDisplayMode(int width,
int height,
bool is_interlaced,
@@ -242,6 +248,7 @@ class DisplayConfiguratorTest : public testing::Test {
.SetNativeMode(small_mode_.Clone())
.SetCurrentMode(small_mode_.Clone())
.SetType(DISPLAY_CONNECTION_TYPE_INTERNAL)
+ .SetBaseConnectorId(kEdpConnectorId)
.SetIsAspectPerservingScaling(true)
.Build();
@@ -251,6 +258,7 @@ class DisplayConfiguratorTest : public testing::Test {
.SetCurrentMode(big_mode_.Clone())
.AddMode(small_mode_.Clone())
.SetType(DISPLAY_CONNECTION_TYPE_HDMI)
+ .SetBaseConnectorId(kSecondConnectorId)
.SetIsAspectPerservingScaling(true)
.Build();
@@ -259,6 +267,7 @@ class DisplayConfiguratorTest : public testing::Test {
.SetNativeMode(small_mode_.Clone())
.SetCurrentMode(small_mode_.Clone())
.SetType(DISPLAY_CONNECTION_TYPE_HDMI)
+ .SetBaseConnectorId(kThirdConnectorId)
.SetIsAspectPerservingScaling(true)
.Build();
@@ -961,29 +970,79 @@ TEST_F(DisplayConfiguratorTest, HandleConfigureCrtcFailure) {
.AddMode(modes[3]->Clone())
.AddMode(modes[4]->Clone())
.SetType(DISPLAY_CONNECTION_TYPE_INTERNAL)
+ .SetBaseConnectorId(kEdpConnectorId)
.SetIsAspectPerservingScaling(true)
.Build();
- // First test simply fails in MULTIPLE_DISPLAY_STATE_SINGLE mode. This is
- // probably unrealistic but we want to make sure any assumptions don't creep
- // in.
+ // Since Chrome restricts the internal display to its native mode it should
+ // not attempt other available modes. The likelihood of an internal display
+ // failing to pass a modeset test is low, but we cover this case here.
native_display_delegate_->set_max_configurable_pixels(
modes[2]->size().GetArea());
state_controller_.set_state(MULTIPLE_DISPLAY_STATE_SINGLE);
UpdateOutputs(1, true);
- EXPECT_EQ(JoinActions(GetCrtcAction({outputs_[0]->display_id(),
- gfx::Point(0, 0), modes[0].get()})
- .c_str(),
- GetCrtcAction({outputs_[0]->display_id(),
- gfx::Point(0, 0), modes[3].get()})
- .c_str(),
- GetCrtcAction({outputs_[0]->display_id(),
- gfx::Point(0, 0), modes[2].get()})
- .c_str(),
- nullptr),
+ EXPECT_EQ(JoinActions(
+ // Initial attempt fails. Initiate retry logic.
+ GetCrtcAction({outputs_[0]->display_id(), gfx::Point(0, 0),
+ outputs_[0]->native_mode()})
+ .c_str(),
+ // Retry fails since it cannot downgrade the internal display.
+ GetCrtcAction({outputs_[0]->display_id(), gfx::Point(0, 0),
+ outputs_[0]->native_mode()})
+ .c_str(),
+ nullptr),
log_->GetActionsAndClear());
+ outputs_[0] = FakeDisplaySnapshot::Builder()
+ .SetId(kDisplayIds[0])
+ .SetNativeMode(modes[0]->Clone())
+ .SetCurrentMode(modes[0]->Clone())
+ .AddMode(modes[1]->Clone())
+ .AddMode(modes[2]->Clone())
+ .AddMode(modes[3]->Clone())
+ .AddMode(modes[4]->Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
+ .SetBaseConnectorId(kEdpConnectorId)
+ .SetIsAspectPerservingScaling(true)
+ .Build();
+
+ // This test simply fails in MULTIPLE_DISPLAY_STATE_SINGLE mode for an
+ // external display (assuming the internal display is disabled; e.g. the lid
+ // is closed).
+ UpdateOutputs(1, true);
+
+ EXPECT_EQ(JoinActions(
+ // Initial attempt fails. Initiate retry logic.
+ GetCrtcAction({outputs_[0]->display_id(), gfx::Point(0, 0),
+ modes[0].get()})
+ .c_str(),
+ // Retry attempts trying all available modes.
+ GetCrtcAction({outputs_[0]->display_id(), gfx::Point(0, 0),
+ modes[0].get()})
+ .c_str(),
+ GetCrtcAction({outputs_[0]->display_id(), gfx::Point(0, 0),
+ modes[3].get()})
+ .c_str(),
+ GetCrtcAction({outputs_[0]->display_id(), gfx::Point(0, 0),
+ modes[2].get()})
+ .c_str(),
+ nullptr),
+ log_->GetActionsAndClear());
+
+ outputs_[0] = FakeDisplaySnapshot::Builder()
+ .SetId(kDisplayIds[0])
+ .SetNativeMode(modes[0]->Clone())
+ .SetCurrentMode(modes[0]->Clone())
+ .AddMode(modes[1]->Clone())
+ .AddMode(modes[2]->Clone())
+ .AddMode(modes[3]->Clone())
+ .AddMode(modes[4]->Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_INTERNAL)
+ .SetBaseConnectorId(kEdpConnectorId)
+ .SetIsAspectPerservingScaling(true)
+ .Build();
+
outputs_[1] = FakeDisplaySnapshot::Builder()
.SetId(kDisplayIds[1])
.SetNativeMode(modes[0]->Clone())
@@ -993,53 +1052,84 @@ TEST_F(DisplayConfiguratorTest, HandleConfigureCrtcFailure) {
.AddMode(modes[3]->Clone())
.AddMode(modes[4]->Clone())
.SetType(DISPLAY_CONNECTION_TYPE_HDMI)
+ .SetBaseConnectorId(kSecondConnectorId)
.SetIsAspectPerservingScaling(true)
.Build();
// This test should attempt to configure a mirror mode that will not succeed
// and should end up in extended mode.
native_display_delegate_->set_max_configurable_pixels(
- modes[3]->size().GetArea());
+ modes[1]->size().GetArea());
state_controller_.set_state(MULTIPLE_DISPLAY_STATE_MULTI_MIRROR);
UpdateOutputs(2, true);
EXPECT_EQ(
JoinActions(
- GetCrtcAction(
- {outputs_[0]->display_id(), gfx::Point(0, 0), modes[0].get()})
+ // Initial attempt fails. Initiate retry logic.
+ GetCrtcAction({outputs_[0]->display_id(), gfx::Point(0, 0),
+ outputs_[0]->native_mode()})
.c_str(),
- // Then attempt to configure crtc1 with the first mode.
GetCrtcAction(
{outputs_[1]->display_id(), gfx::Point(0, 0), modes[0].get()})
.c_str(),
- // First mode tried is expected to fail and it will
- // retry wil the 4th mode in the list.
+ // Retry logic fails to modeset internal display. Since internal
+ // displays are restricted to their preferred mode, there are no other
+ // modes to try. The configuration fails completely, but the external
+ // display will still try to modeset.
+ GetCrtcAction({outputs_[0]->display_id(), gfx::Point(0, 0),
+ outputs_[0]->native_mode()})
+ .c_str(),
+ // The external display will cycle through all its available modes
+ // before failing completely.
GetCrtcAction(
- {outputs_[0]->display_id(), gfx::Point(0, 0), modes[3].get()})
+ {outputs_[1]->display_id(), gfx::Point(0, 0), modes[0].get()})
.c_str(),
GetCrtcAction(
{outputs_[1]->display_id(), gfx::Point(0, 0), modes[3].get()})
.c_str(),
- // Since it was requested to go into mirror mode
- // and the configured modes were different, it
- // should now try and setup a valid configurable
- // extended mode.
GetCrtcAction(
- {outputs_[0]->display_id(), gfx::Point(0, 0), modes[0].get()})
+ {outputs_[1]->display_id(), gfx::Point(0, 0), modes[2].get()})
+ .c_str(),
+ GetCrtcAction(
+ {outputs_[1]->display_id(), gfx::Point(0, 0), modes[1].get()})
+ .c_str(),
+ // Since mirror mode configuration failed it should now attempt to
+ // configure in extended mode. However, initial attempt fails.
+ // Initiate retry logic.
+ GetCrtcAction({outputs_[0]->display_id(), gfx::Point(0, 0),
+ outputs_[0]->native_mode()})
.c_str(),
GetCrtcAction({outputs_[1]->display_id(),
gfx::Point(0, modes[0]->size().height() +
DisplayConfigurator::kVerticalGap),
modes[0].get()})
.c_str(),
- GetCrtcAction(
- {outputs_[0]->display_id(), gfx::Point(0, 0), modes[3].get()})
+ // Just as above, retry logic fails to modeset internal display.
+ GetCrtcAction({outputs_[0]->display_id(), gfx::Point(0, 0),
+ outputs_[0]->native_mode()})
+ .c_str(),
+ // The configuration fails completely but still attempts to modeset
+ // the external display.
+ GetCrtcAction({outputs_[1]->display_id(),
+ gfx::Point(0, modes[0]->size().height() +
+ DisplayConfigurator::kVerticalGap),
+ modes[0].get()})
.c_str(),
GetCrtcAction({outputs_[1]->display_id(),
gfx::Point(0, modes[0]->size().height() +
DisplayConfigurator::kVerticalGap),
modes[3].get()})
.c_str(),
+ GetCrtcAction({outputs_[1]->display_id(),
+ gfx::Point(0, modes[0]->size().height() +
+ DisplayConfigurator::kVerticalGap),
+ modes[2].get()})
+ .c_str(),
+ GetCrtcAction({outputs_[1]->display_id(),
+ gfx::Point(0, modes[0]->size().height() +
+ DisplayConfigurator::kVerticalGap),
+ modes[1].get()})
+ .c_str(),
nullptr),
log_->GetActionsAndClear());
}
@@ -1240,8 +1330,12 @@ TEST_F(DisplayConfiguratorTest,
EXPECT_EQ(0, observer_.num_changes());
EXPECT_EQ(1, observer_.num_failures());
- EXPECT_EQ(GetCrtcActions(DisplayConfig::kOff, &small_mode_, &big_mode_),
- log_->GetActionsAndClear());
+ EXPECT_EQ(
+ JoinActions(
+ GetCrtcActions(DisplayConfig::kOff, &small_mode_, &big_mode_).c_str(),
+ GetCrtcActions(DisplayConfig::kOff, &small_mode_, &big_mode_).c_str(),
+ nullptr),
+ log_->GetActionsAndClear());
// This configuration should trigger a display configuration since the
// previous configuration failed.
@@ -1260,6 +1354,11 @@ TEST_F(DisplayConfiguratorTest,
GetCrtcAction({outputs_[1]->display_id(),
gfx::Point(0, small_mode_.size().height() +
DisplayConfigurator::kVerticalGap),
+ &big_mode_})
+ .c_str(),
+ GetCrtcAction({outputs_[1]->display_id(),
+ gfx::Point(0, small_mode_.size().height() +
+ DisplayConfigurator::kVerticalGap),
&small_mode_})
.c_str(),
nullptr),
diff --git a/chromium/ui/display/manager/display_manager.cc b/chromium/ui/display/manager/display_manager.cc
index b153abdf165..9b6c151b30b 100644
--- a/chromium/ui/display/manager/display_manager.cc
+++ b/chromium/ui/display/manager/display_manager.cc
@@ -16,16 +16,17 @@
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/run_loop.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/display/display.h"
#include "ui/display/display_features.h"
@@ -43,7 +44,7 @@
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/strings/grit/ui_strings.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/system/sys_info.h"
#include "base/time/time.h"
#include "chromeos/system/devicemode.h"
@@ -73,7 +74,7 @@ const char kMirrorModeTypesHistogram[] = "DisplayManager.MirrorModeTypes";
const char kMirroringDisplayCountRangesHistogram[] =
"DisplayManager.MirroringDisplayCountRanges";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// The UMA historgram that logs the zoom percentage level of the intenral
// display.
constexpr char kInternalDisplayZoomPercentageHistogram[] =
@@ -82,7 +83,7 @@ constexpr char kInternalDisplayZoomPercentageHistogram[] =
// Timeout in seconds after which we consider the change to the display zoom
// is not temporary.
constexpr int kDisplayZoomModifyTimeoutSec = 15;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
struct DisplaySortFunctor {
bool operator()(const Display& a, const Display& b) {
@@ -147,7 +148,7 @@ bool ContainsDisplayWithId(const std::vector<Display>& displays,
return false;
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Gets the next mode in |modes| in the direction marked by |up|. If trying to
// move past either end of |modes|, returns the same.
@@ -293,7 +294,7 @@ enum class MirrorModeTypes {
kCount,
};
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void OnInternalDisplayZoomChanged(float zoom_factor) {
constexpr static int kMaxValue = 300;
constexpr static int kBucketSize = 5;
@@ -304,7 +305,7 @@ void OnInternalDisplayZoomChanged(float zoom_factor) {
kNumBuckets, base::HistogramBase::kUmaTargetedHistogramFlag)
->Add(std::round(zoom_factor * 100));
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace
@@ -326,7 +327,7 @@ DisplayManager::BeginEndNotifier::~BeginEndNotifier() {
DisplayManager::DisplayManager(std::unique_ptr<Screen> screen)
: screen_(std::move(screen)), layout_store_(new DisplayLayoutStore) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
configure_displays_ = chromeos::IsRunningAsSystemCompositor();
change_display_upon_host_resize_ = !configure_displays_;
unified_desktop_enabled_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -336,7 +337,7 @@ DisplayManager::DisplayManager(std::unique_ptr<Screen> screen)
}
DisplayManager::~DisplayManager() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Reset the font params.
gfx::SetFontRenderParamsDeviceScaleFactor(1.0f);
on_display_zoom_modify_timeout_.Cancel();
@@ -376,7 +377,7 @@ void DisplayManager::UpdateInternalDisplay(
}
void DisplayManager::RefreshFontParams() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Use the largest device scale factor among currently active displays. Non
// internal display may have bigger scale factor in case the external display
// is an 4K display.
@@ -387,7 +388,7 @@ void DisplayManager::RefreshFontParams() {
largest_device_scale_factor, info.GetEffectiveDeviceScaleFactor());
}
gfx::SetFontRenderParamsDeviceScaleFactor(largest_device_scale_factor);
-#endif // OS_CHROMEOS
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
const DisplayLayout& DisplayManager::GetCurrentDisplayLayout() const {
@@ -620,10 +621,10 @@ bool DisplayManager::SetDisplayMode(int64_t display_id,
if (resolution_changed && IsInUnifiedMode())
ReconfigureDisplays();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
else if (resolution_changed && configure_displays_)
display_configurator_->OnConfigurationChanged();
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
return resolution_changed || display_property_changed;
}
@@ -841,7 +842,7 @@ void DisplayManager::OnNativeDisplaysChanged(
}
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
if (!configure_displays_ && new_display_info_list.size() > 1 &&
hardware_mirroring_display_id_list.empty()) {
DisplayIdList list = GenerateDisplayIdList(
@@ -1369,7 +1370,7 @@ void DisplayManager::SetMirrorMode(
}
const bool enabled = mode != MirrorMode::kOff;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
if (configure_displays_) {
MultipleDisplayState new_state =
enabled ? MULTIPLE_DISPLAY_STATE_MULTI_MIRROR
@@ -1444,7 +1445,7 @@ void DisplayManager::ToggleDisplayScaleFactor() {
UpdateDisplaysWith(new_display_info_list);
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void DisplayManager::InitConfigurator(
std::unique_ptr<NativeDisplayDelegate> delegate) {
display_configurator_ = std::make_unique<display::DisplayConfigurator>();
@@ -1570,7 +1571,7 @@ void DisplayManager::UpdateZoomFactor(int64_t display_id, float zoom_factor) {
if (Display::IsInternalDisplayId(display_id)) {
on_display_zoom_modify_timeout_.Cancel();
on_display_zoom_modify_timeout_.Reset(
- base::BindRepeating(&OnInternalDisplayZoomChanged, zoom_factor));
+ base::BindOnce(&OnInternalDisplayZoomChanged, zoom_factor));
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, on_display_zoom_modify_timeout_.callback(),
base::TimeDelta::FromSeconds(kDisplayZoomModifyTimeoutSec));
@@ -1670,7 +1671,7 @@ void DisplayManager::UpdateInternalManagedDisplayModeListForTest() {
}
bool DisplayManager::ZoomDisplay(int64_t display_id, bool up) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
if (IsInUnifiedMode()) {
DCHECK_EQ(display_id, kUnifiedDisplayId);
const ManagedDisplayInfo& display_info = GetDisplayInfo(display_id);
diff --git a/chromium/ui/display/manager/display_manager.h b/chromium/ui/display/manager/display_manager.h
index f681a3ebf02..585980f52ff 100644
--- a/chromium/ui/display/manager/display_manager.h
+++ b/chromium/ui/display/manager/display_manager.h
@@ -23,6 +23,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "build/chromeos_buildflags.h"
#include "ui/display/display.h"
#include "ui/display/display_layout.h"
#include "ui/display/display_observer.h"
@@ -32,7 +33,7 @@
#include "ui/display/types/display_constants.h"
#include "ui/display/unified_desktop_utils.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/cancelable_callback.h"
#include "base/optional.h"
#include "ui/display/manager/display_configurator.h"
@@ -59,7 +60,7 @@ class DisplayManagerTestApi;
// DisplayManager maintains the current display configurations,
// and notifies observers when configuration changes.
class DISPLAY_MANAGER_EXPORT DisplayManager
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
: public DisplayConfigurator::SoftwareMirroringController
#endif
{
@@ -108,7 +109,7 @@ class DISPLAY_MANAGER_EXPORT DisplayManager
};
explicit DisplayManager(std::unique_ptr<Screen> screen);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
~DisplayManager() override;
#else
~DisplayManager();
@@ -135,7 +136,7 @@ class DISPLAY_MANAGER_EXPORT DisplayManager
// Returns the display id of the first display in the outupt list.
int64_t first_display_id() const { return first_display_id_; }
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
TouchDeviceManager* touch_device_manager() const {
return touch_device_manager_.get();
}
@@ -434,7 +435,7 @@ class DISPLAY_MANAGER_EXPORT DisplayManager
ManagedDisplayInfo::ManagedDisplayModeList display_modes = {});
void ToggleDisplayScaleFactor();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void InitConfigurator(std::unique_ptr<NativeDisplayDelegate> delegate);
void ForceInitialConfigureWithObservers(
display::DisplayChangeObserver* display_change_observer,
@@ -689,7 +690,7 @@ class DISPLAY_MANAGER_EXPORT DisplayManager
// OnWillProcessDisplayChanges() and OnDidProcessDisplayChanges().
int notify_depth_ = 0;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<display::DisplayConfigurator> display_configurator_;
std::unique_ptr<TouchDeviceManager> touch_device_manager_;
@@ -699,7 +700,7 @@ class DISPLAY_MANAGER_EXPORT DisplayManager
// to record UMA metrics for changes to the display zoom that are temporary.
// Temporary changes may include things like the user trying out different
// zoom levels before making the final decision.
- base::CancelableCallback<void()> on_display_zoom_modify_timeout_;
+ base::CancelableOnceClosure on_display_zoom_modify_timeout_;
#endif
base::WeakPtrFactory<DisplayManager> weak_ptr_factory_{this};
diff --git a/chromium/ui/display/manager/display_manager_utilities.cc b/chromium/ui/display/manager/display_manager_utilities.cc
index e5bda9d98dc..b88349a89da 100644
--- a/chromium/ui/display/manager/display_manager_utilities.cc
+++ b/chromium/ui/display/manager/display_manager_utilities.cc
@@ -12,12 +12,13 @@
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "base/system/sys_info.h"
+#include "build/chromeos_buildflags.h"
#include "ui/display/display_switches.h"
#include "ui/display/manager/managed_display_info.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/size_f.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chromeos/system/statistics_provider.h"
#endif
@@ -64,7 +65,7 @@ ManagedDisplayInfo::ManagedDisplayModeList CreateUnifiedManagedDisplayModeList(
bool ForceFirstDisplayInternal() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
bool ret = command_line->HasSwitch(::switches::kUseFirstDisplayAsInternal);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Touch view mode is only available to internal display. We force the
// display as internal for emulator to test touch view mode.
ret = ret ||
diff --git a/chromium/ui/display/manager/display_util.cc b/chromium/ui/display/manager/display_util.cc
index 59a4401f49d..23881ec2d10 100644
--- a/chromium/ui/display/manager/display_util.cc
+++ b/chromium/ui/display/manager/display_util.cc
@@ -13,12 +13,13 @@
#include "base/notreached.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
+#include "build/chromeos_buildflags.h"
#include "ui/display/manager/managed_display_info.h"
#include "ui/display/types/display_snapshot.h"
namespace display {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
std::string DisplayPowerStateToString(chromeos::DisplayPowerState state) {
switch (state) {
case chromeos::DISPLAY_POWER_ALL_ON:
@@ -56,7 +57,7 @@ int GetDisplayPower(const std::vector<DisplaySnapshot*>& displays,
return num_on_displays;
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
bool WithinEpsilon(float a, float b) {
return std::abs(a - b) < std::numeric_limits<float>::epsilon();
diff --git a/chromium/ui/display/manager/display_util.h b/chromium/ui/display/manager/display_util.h
index a51c684318d..33dc3167b74 100644
--- a/chromium/ui/display/manager/display_util.h
+++ b/chromium/ui/display/manager/display_util.h
@@ -8,19 +8,20 @@
#include <string>
#include <vector>
+#include "build/chromeos_buildflags.h"
#include "ui/display/manager/display_manager_export.h"
#include "ui/display/types/display_constants.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "third_party/cros_system_api/dbus/service_constants.h"
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace display {
class DisplaySnapshot;
class ManagedDisplayMode;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Returns a string describing |state|.
std::string DisplayPowerStateToString(chromeos::DisplayPowerState state);
@@ -32,7 +33,7 @@ GetDisplayPower(const std::vector<DisplaySnapshot*>& displays,
chromeos::DisplayPowerState state,
std::vector<bool>* display_power);
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Determines whether |a| is within an epsilon of |b|.
bool WithinEpsilon(float a, float b);
diff --git a/chromium/ui/display/manager/managed_display_info_unittest.cc b/chromium/ui/display/manager/managed_display_info_unittest.cc
index b2ad47f724e..c744029bff0 100644
--- a/chromium/ui/display/manager/managed_display_info_unittest.cc
+++ b/chromium/ui/display/manager/managed_display_info_unittest.cc
@@ -4,10 +4,11 @@
#include "ui/display/manager/managed_display_info.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/display_switches.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/display/manager/touch_device_manager.h"
#endif
diff --git a/chromium/ui/display/manager/touch_device_manager.cc b/chromium/ui/display/manager/touch_device_manager.cc
index 4b2766bd236..474c95d5b1c 100644
--- a/chromium/ui/display/manager/touch_device_manager.cc
+++ b/chromium/ui/display/manager/touch_device_manager.cc
@@ -9,10 +9,10 @@
#include <string>
#include <tuple>
+#include "base/containers/contains.h"
#include "base/files/file_util.h"
#include "base/hash/hash.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "ui/display/manager/managed_display_info.h"
@@ -29,6 +29,39 @@ using DeviceList = std::vector<ui::TouchscreenDevice>;
constexpr char kFallbackTouchDeviceName[] = "fallback_touch_device_name";
constexpr char kFallbackTouchDevicePhys[] = "fallback_touch_device_phys";
+base::FilePath GetDisplaySysPath(const ManagedDisplayInfo* display) {
+ std::vector<base::FilePath::StringType> components;
+ display->sys_path().GetComponents(&components);
+ base::FilePath path_thus_far;
+
+ for (const auto& component : components) {
+ if (path_thus_far.empty()) {
+ path_thus_far = base::FilePath(component);
+ } else {
+ path_thus_far = path_thus_far.Append(component);
+ }
+
+ // Newer versions of the EVDI kernel driver include a symlink to the USB
+ // device in the sysfs EVDI directory (e.g.
+ // /sys/devices/platform/evdi.0/device) for EVDI displays that are USB. If
+ // that symlink exists, read it, and use that path as the sysfs path for the
+ // display when calculating the association score to match it with a
+ // corresponding USB touch device. If the symlink doesn't exist, use the
+ // normal sysfs path.
+ if (base::StartsWith(component, "evdi", base::CompareCase::SENSITIVE)) {
+ base::FilePath usb_device_path;
+ if (base::ReadSymbolicLink(path_thus_far.Append("device"),
+ &usb_device_path)) {
+ return base::MakeAbsoluteFilePath(
+ path_thus_far.Append(usb_device_path));
+ }
+ break;
+ }
+ }
+
+ return display->sys_path();
+}
+
// Returns true if |path| is likely a USB device.
bool IsDeviceConnectedViaUsb(const base::FilePath& path) {
std::vector<base::FilePath::StringType> components;
@@ -50,13 +83,13 @@ bool IsDeviceConnectedViaUsb(const base::FilePath& path) {
return false;
}
-// Returns the UDL association score between |display| and |device|. A score <=
+// Returns the USB association score between |display| and |device|. A score <=
// 0 means that there is no association.
-int GetUdlAssociationScore(const ManagedDisplayInfo* display,
+int GetUsbAssociationScore(const ManagedDisplayInfo* display,
const ui::TouchscreenDevice& device) {
- // If the devices are not both connected via USB, then there cannot be a UDL
+ // If the devices are not both connected via USB, then there cannot be a USB
// association score.
- if (!IsDeviceConnectedViaUsb(display->sys_path()) ||
+ if (!IsDeviceConnectedViaUsb(GetDisplaySysPath(display)) ||
!IsDeviceConnectedViaUsb(device.sys_path))
return 0;
@@ -64,7 +97,7 @@ int GetUdlAssociationScore(const ManagedDisplayInfo* display,
// sysfs paths have in common.
std::vector<base::FilePath::StringType> display_components;
std::vector<base::FilePath::StringType> device_components;
- display->sys_path().GetComponents(&display_components);
+ GetDisplaySysPath(display).GetComponents(&display_components);
device.sys_path.GetComponents(&device_components);
std::size_t largest_idx = 0;
@@ -76,16 +109,16 @@ int GetUdlAssociationScore(const ManagedDisplayInfo* display,
return largest_idx;
}
-// Tries to find a UDL device that best matches |display|. Returns
+// Tries to find a USB device that best matches |display|. Returns
// |devices.end()| if one is not found.
-DeviceList::const_iterator GuessBestUdlDevice(const ManagedDisplayInfo* display,
+DeviceList::const_iterator GuessBestUsbDevice(const ManagedDisplayInfo* display,
const DeviceList& devices) {
int best_score = 0;
DeviceList::const_iterator best_device_it = devices.end();
// TODO(malaykeshav): Migrate to std::max_element in the future.
for (auto it = devices.begin(); it != devices.end(); it++) {
- int score = GetUdlAssociationScore(display, *it);
+ int score = GetUsbAssociationScore(display, *it);
if (score > best_score) {
best_score = score;
best_device_it = it;
@@ -318,7 +351,8 @@ void TouchDeviceManager::AssociateTouchscreens(
for (const ManagedDisplayInfo* display : displays) {
VLOG(2) << "Received display " << display->name()
<< " (size: " << display->GetNativeModeSize().ToString() << ", "
- << "sys_path: " << display->sys_path().LossyDisplayName() << ")";
+ << "sys_path: " << GetDisplaySysPath(display).LossyDisplayName()
+ << ")";
}
for (const ui::TouchscreenDevice& device : devices) {
VLOG(2) << "Received device " << device.name
@@ -330,7 +364,7 @@ void TouchDeviceManager::AssociateTouchscreens(
AssociateInternalDevices(&displays, &devices);
AssociateDevicesWithCollision(&displays, &devices);
AssociateFromHistoricalData(&displays, &devices);
- AssociateUdlDevices(&displays, &devices);
+ AssociateUsbDevices(&displays, &devices);
AssociateSameSizeDevices(&displays, &devices);
AssociateToSingleDisplay(&displays, &devices);
AssociateAnyRemainingDevices(&displays, &devices);
@@ -457,21 +491,21 @@ void TouchDeviceManager::AssociateFromHistoricalData(
}
}
-void TouchDeviceManager::AssociateUdlDevices(ManagedDisplayInfoList* displays,
+void TouchDeviceManager::AssociateUsbDevices(ManagedDisplayInfoList* displays,
DeviceList* devices) {
- VLOG(2) << "Trying to match udl devices (" << displays->size()
+ VLOG(2) << "Trying to match usb devices (" << displays->size()
<< " displays and " << devices->size() << " devices to match)";
for (auto display_it = displays->begin(); display_it != displays->end();
display_it++) {
ManagedDisplayInfo* display = *display_it;
- auto device_it = GuessBestUdlDevice(display, *devices);
+ auto device_it = GuessBestUsbDevice(display, *devices);
if (device_it != devices->end()) {
const ui::TouchscreenDevice& device = *device_it;
VLOG(2) << "=> Matched device " << device.name << " to display "
<< display->name()
- << " (score=" << GetUdlAssociationScore(display, device) << ")";
+ << " (score=" << GetUsbAssociationScore(display, device) << ")";
Associate(display, device);
devices->erase(device_it);
}
diff --git a/chromium/ui/display/manager/touch_device_manager.h b/chromium/ui/display/manager/touch_device_manager.h
index d45757516b4..084917ec4ef 100644
--- a/chromium/ui/display/manager/touch_device_manager.h
+++ b/chromium/ui/display/manager/touch_device_manager.h
@@ -216,7 +216,7 @@ class DISPLAY_MANAGER_EXPORT TouchDeviceManager {
void AssociateFromHistoricalData(std::vector<ManagedDisplayInfo*>* displays,
std::vector<ui::TouchscreenDevice>* devices);
- void AssociateUdlDevices(std::vector<ManagedDisplayInfo*>* displays,
+ void AssociateUsbDevices(std::vector<ManagedDisplayInfo*>* displays,
std::vector<ui::TouchscreenDevice>* devices);
void AssociateSameSizeDevices(std::vector<ManagedDisplayInfo*>* displays,
diff --git a/chromium/ui/display/manager/update_display_configuration_task_unittest.cc b/chromium/ui/display/manager/update_display_configuration_task_unittest.cc
index f8cfce6c231..bb3e92df27c 100644
--- a/chromium/ui/display/manager/update_display_configuration_task_unittest.cc
+++ b/chromium/ui/display/manager/update_display_configuration_task_unittest.cc
@@ -16,12 +16,17 @@
#include "ui/display/manager/display_layout_manager.h"
#include "ui/display/manager/test/action_logger_util.h"
#include "ui/display/manager/test/test_native_display_delegate.h"
+#include "ui/display/types/display_constants.h"
namespace display {
namespace test {
namespace {
+// Non-zero generic connector IDs.
+constexpr uint64_t kEdpConnectorId = 71u;
+constexpr uint64_t kSecondConnectorId = kEdpConnectorId + 10u;
+
class TestSoftwareMirroringController
: public DisplayConfigurator::SoftwareMirroringController {
public:
@@ -153,13 +158,17 @@ class UpdateDisplayConfigurationTaskTest : public testing::Test {
.SetId(123)
.SetNativeMode(small_mode_.Clone())
.SetCurrentMode(small_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_INTERNAL)
+ .SetBaseConnectorId(kEdpConnectorId)
.Build();
displays_[1] = FakeDisplaySnapshot::Builder()
.SetId(456)
.SetNativeMode(big_mode_.Clone())
.SetCurrentMode(big_mode_.Clone())
+ .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
.AddMode(small_mode_.Clone())
+ .SetBaseConnectorId(kSecondConnectorId)
.Build();
}
~UpdateDisplayConfigurationTaskTest() override = default;
@@ -340,21 +349,33 @@ TEST_F(UpdateDisplayConfigurationTaskTest, FailExtendedConfiguration) {
EXPECT_TRUE(configured_);
EXPECT_FALSE(configuration_status_);
EXPECT_EQ(
- JoinActions(GetCrtcAction(
- {displays_[0]->display_id(), gfx::Point(), &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[1]->display_id(),
- gfx::Point(0, small_mode_.size().height()),
- &big_mode_})
- .c_str(),
- GetCrtcAction(
- {displays_[0]->display_id(), gfx::Point(), &small_mode_})
- .c_str(),
- GetCrtcAction({displays_[1]->display_id(),
- gfx::Point(0, small_mode_.size().height()),
- &small_mode_})
- .c_str(),
- nullptr),
+ JoinActions(
+ // All displays will fail to modeset together. Initiate retry logic.
+ GetCrtcAction(
+ {displays_[0]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(),
+ gfx::Point(0, small_mode_.size().height()),
+ &big_mode_})
+ .c_str(),
+ // Retry logic fails to modeset internal display. Since internal
+ // displays are restricted to their preferred mode, there are no other
+ // modes to try. The configuration will fail, but the external display
+ // will still try to modeset.
+ GetCrtcAction(
+ {displays_[0]->display_id(), gfx::Point(), &small_mode_})
+ .c_str(),
+ // External display fail modeset, downgrade once, and then fail
+ // completely.
+ GetCrtcAction({displays_[1]->display_id(),
+ gfx::Point(0, small_mode_.size().height()),
+ &big_mode_})
+ .c_str(),
+ GetCrtcAction({displays_[1]->display_id(),
+ gfx::Point(0, small_mode_.size().height()),
+ &small_mode_})
+ .c_str(),
+ nullptr),
log_.GetActionsAndClear());
}
diff --git a/chromium/ui/display/mojom/display_mojom_traits_unittest.cc b/chromium/ui/display/mojom/display_mojom_traits_unittest.cc
index dd4e5f96469..e16684eb0a5 100644
--- a/chromium/ui/display/mojom/display_mojom_traits_unittest.cc
+++ b/chromium/ui/display/mojom/display_mojom_traits_unittest.cc
@@ -80,6 +80,8 @@ void CheckDisplaySnapShotMojoEqual(const DisplaySnapshot& input,
EXPECT_EQ(input.origin(), output.origin());
EXPECT_EQ(input.physical_size(), output.physical_size());
EXPECT_EQ(input.type(), output.type());
+ EXPECT_EQ(input.base_connector_id(), output.base_connector_id());
+ EXPECT_EQ(input.path_topology(), output.path_topology());
EXPECT_EQ(input.is_aspect_preserving_scaling(),
output.is_aspect_preserving_scaling());
EXPECT_EQ(input.has_overscan(), output.has_overscan());
@@ -255,6 +257,8 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotCurrentAndNativeModesNull) {
const gfx::Size physical_size(5, 9);
const gfx::Size maximum_cursor_size(3, 5);
const DisplayConnectionType type = DISPLAY_CONNECTION_TYPE_DISPLAYPORT;
+ const uint64_t base_connector_id = 1u;
+ const std::vector<uint64_t> path_topology{};
const bool is_aspect_preserving_scaling = true;
const bool has_overscan = true;
const PrivacyScreenState privacy_screen_state = kEnabled;
@@ -277,12 +281,12 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotCurrentAndNativeModesNull) {
const std::vector<uint8_t> edid = {1};
std::unique_ptr<DisplaySnapshot> input = std::make_unique<DisplaySnapshot>(
- display_id, origin, physical_size, type, is_aspect_preserving_scaling,
- has_overscan, privacy_screen_state, has_color_correction_matrix,
- color_correction_in_linear_space, display_color_space, bits_per_channel,
- display_name, sys_path, std::move(modes), PanelOrientation::kNormal, edid,
- current_mode, native_mode, product_code, year_of_manufacture,
- maximum_cursor_size);
+ display_id, origin, physical_size, type, base_connector_id, path_topology,
+ is_aspect_preserving_scaling, has_overscan, privacy_screen_state,
+ has_color_correction_matrix, color_correction_in_linear_space,
+ display_color_space, bits_per_channel, display_name, sys_path,
+ std::move(modes), PanelOrientation::kNormal, edid, current_mode,
+ native_mode, product_code, year_of_manufacture, maximum_cursor_size);
std::unique_ptr<DisplaySnapshot> output;
SerializeAndDeserialize<mojom::DisplaySnapshot>(input->Clone(), &output);
@@ -298,6 +302,8 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotCurrentModeNull) {
const gfx::Size physical_size(55, 49);
const gfx::Size maximum_cursor_size(13, 95);
const DisplayConnectionType type = DISPLAY_CONNECTION_TYPE_VGA;
+ const uint64_t base_connector_id = 1u;
+ const std::vector<uint64_t> path_topology{};
const bool is_aspect_preserving_scaling = true;
const bool has_overscan = true;
const PrivacyScreenState privacy_screen_state = kEnabled;
@@ -320,12 +326,12 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotCurrentModeNull) {
const std::vector<uint8_t> edid = {1};
std::unique_ptr<DisplaySnapshot> input = std::make_unique<DisplaySnapshot>(
- display_id, origin, physical_size, type, is_aspect_preserving_scaling,
- has_overscan, privacy_screen_state, has_color_correction_matrix,
- color_correction_in_linear_space, display_color_space, bits_per_channel,
- display_name, sys_path, std::move(modes), PanelOrientation::kNormal, edid,
- current_mode, native_mode, product_code, year_of_manufacture,
- maximum_cursor_size);
+ display_id, origin, physical_size, type, base_connector_id, path_topology,
+ is_aspect_preserving_scaling, has_overscan, privacy_screen_state,
+ has_color_correction_matrix, color_correction_in_linear_space,
+ display_color_space, bits_per_channel, display_name, sys_path,
+ std::move(modes), PanelOrientation::kNormal, edid, current_mode,
+ native_mode, product_code, year_of_manufacture, maximum_cursor_size);
std::unique_ptr<DisplaySnapshot> output;
SerializeAndDeserialize<mojom::DisplaySnapshot>(input->Clone(), &output);
@@ -341,6 +347,8 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotExternal) {
const gfx::Size physical_size(520, 320);
const gfx::Size maximum_cursor_size(4, 5);
const DisplayConnectionType type = DISPLAY_CONNECTION_TYPE_HDMI;
+ const uint64_t base_connector_id = 1u;
+ const std::vector<uint64_t> path_topology{};
const bool is_aspect_preserving_scaling = false;
const bool has_overscan = false;
const PrivacyScreenState privacy_screen_state = kDisabled;
@@ -367,12 +375,12 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotExternal) {
const std::vector<uint8_t> edid = {2, 3, 4, 5};
std::unique_ptr<DisplaySnapshot> input = std::make_unique<DisplaySnapshot>(
- display_id, origin, physical_size, type, is_aspect_preserving_scaling,
- has_overscan, privacy_screen_state, has_color_correction_matrix,
- color_correction_in_linear_space, display_color_space, bits_per_channel,
- display_name, sys_path, std::move(modes), PanelOrientation::kLeftUp, edid,
- current_mode, native_mode, product_code, year_of_manufacture,
- maximum_cursor_size);
+ display_id, origin, physical_size, type, base_connector_id, path_topology,
+ is_aspect_preserving_scaling, has_overscan, privacy_screen_state,
+ has_color_correction_matrix, color_correction_in_linear_space,
+ display_color_space, bits_per_channel, display_name, sys_path,
+ std::move(modes), PanelOrientation::kLeftUp, edid, current_mode,
+ native_mode, product_code, year_of_manufacture, maximum_cursor_size);
std::unique_ptr<DisplaySnapshot> output;
SerializeAndDeserialize<mojom::DisplaySnapshot>(input->Clone(), &output);
@@ -387,6 +395,8 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotInternal) {
const gfx::Size physical_size(270, 180);
const gfx::Size maximum_cursor_size(64, 64);
const DisplayConnectionType type = DISPLAY_CONNECTION_TYPE_INTERNAL;
+ const uint64_t base_connector_id = 1u;
+ const std::vector<uint64_t> path_topology{};
const bool is_aspect_preserving_scaling = true;
const bool has_overscan = false;
const PrivacyScreenState privacy_screen_state = kNotSupported;
@@ -410,12 +420,12 @@ TEST(DisplayStructTraitsTest, DisplaySnapshotInternal) {
const std::vector<uint8_t> edid = {2, 3};
std::unique_ptr<DisplaySnapshot> input = std::make_unique<DisplaySnapshot>(
- display_id, origin, physical_size, type, is_aspect_preserving_scaling,
- has_overscan, privacy_screen_state, has_color_correction_matrix,
- color_correction_in_linear_space, display_color_space, bits_per_channel,
- display_name, sys_path, std::move(modes), PanelOrientation::kRightUp,
- edid, current_mode, native_mode, product_code, year_of_manufacture,
- maximum_cursor_size);
+ display_id, origin, physical_size, type, base_connector_id, path_topology,
+ is_aspect_preserving_scaling, has_overscan, privacy_screen_state,
+ has_color_correction_matrix, color_correction_in_linear_space,
+ display_color_space, bits_per_channel, display_name, sys_path,
+ std::move(modes), PanelOrientation::kRightUp, edid, current_mode,
+ native_mode, product_code, year_of_manufacture, maximum_cursor_size);
std::unique_ptr<DisplaySnapshot> output;
SerializeAndDeserialize<mojom::DisplaySnapshot>(input->Clone(), &output);
diff --git a/chromium/ui/display/mojom/display_snapshot.mojom b/chromium/ui/display/mojom/display_snapshot.mojom
index e540e3cd849..6d7d17c3fb3 100644
--- a/chromium/ui/display/mojom/display_snapshot.mojom
+++ b/chromium/ui/display/mojom/display_snapshot.mojom
@@ -16,6 +16,8 @@ struct DisplaySnapshot {
gfx.mojom.Point origin;
gfx.mojom.Size physical_size;
display.mojom.DisplayConnectionType type;
+ uint64 base_connector_id;
+ array<uint64> path_topology;
bool is_aspect_preserving_scaling;
bool has_overscan;
display.mojom.PrivacyScreenState privacy_screen_state;
diff --git a/chromium/ui/display/mojom/display_snapshot_mojom_traits.cc b/chromium/ui/display/mojom/display_snapshot_mojom_traits.cc
index 56662c095cf..3a4ec61e4df 100644
--- a/chromium/ui/display/mojom/display_snapshot_mojom_traits.cc
+++ b/chromium/ui/display/mojom/display_snapshot_mojom_traits.cc
@@ -4,6 +4,8 @@
#include "ui/display/mojom/display_snapshot_mojom_traits.h"
+#include <cstdint>
+
#include "mojo/public/cpp/base/file_path_mojom_traits.h"
#include "ui/display/types/display_constants.h"
#include "ui/gfx/color_space.h"
@@ -81,6 +83,10 @@ bool StructTraits<display::mojom::DisplaySnapshotDataView,
if (!data.ReadType(&type))
return false;
+ std::vector<uint64_t> path_topology;
+ if (!data.ReadPathTopology(&path_topology))
+ return false;
+
display::PrivacyScreenState privacy_screen_state;
if (!data.ReadPrivacyScreenState(&privacy_screen_state))
return false;
@@ -138,8 +144,8 @@ bool StructTraits<display::mojom::DisplaySnapshotDataView,
return false;
*out = std::make_unique<display::DisplaySnapshot>(
- data.display_id(), origin, physical_size, type,
- data.is_aspect_preserving_scaling(), data.has_overscan(),
+ data.display_id(), origin, physical_size, type, data.base_connector_id(),
+ path_topology, data.is_aspect_preserving_scaling(), data.has_overscan(),
privacy_screen_state, data.has_color_correction_matrix(),
data.color_correction_in_linear_space(), color_space,
data.bits_per_channel(), display_name, file_path, std::move(modes),
diff --git a/chromium/ui/display/mojom/display_snapshot_mojom_traits.h b/chromium/ui/display/mojom/display_snapshot_mojom_traits.h
index 8745cd2b623..5ae471d6aa5 100644
--- a/chromium/ui/display/mojom/display_snapshot_mojom_traits.h
+++ b/chromium/ui/display/mojom/display_snapshot_mojom_traits.h
@@ -39,6 +39,16 @@ struct StructTraits<display::mojom::DisplaySnapshotDataView,
return snapshot->type();
}
+ static uint64_t base_connector_id(
+ const std::unique_ptr<display::DisplaySnapshot>& snapshot) {
+ return snapshot->base_connector_id();
+ }
+
+ static const std::vector<uint64_t>& path_topology(
+ const std::unique_ptr<display::DisplaySnapshot>& snapshot) {
+ return snapshot->path_topology();
+ }
+
static display::PanelOrientation panel_orientation(
const std::unique_ptr<display::DisplaySnapshot>& snapshot) {
return snapshot->panel_orientation();
diff --git a/chromium/ui/display/screen.h b/chromium/ui/display/screen.h
index 046c2cd2873..d670bfde658 100644
--- a/chromium/ui/display/screen.h
+++ b/chromium/ui/display/screen.h
@@ -41,7 +41,7 @@ class DISPLAY_EXPORT Screen {
Screen();
virtual ~Screen();
- // Retrieves the single Screen object.
+ // Retrieves the single Screen object; this may be null (e.g. in some tests).
static Screen* GetScreen();
// Sets the global screen. Returns the previously installed screen, if any.
diff --git a/chromium/ui/display/types/display_mode.cc b/chromium/ui/display/types/display_mode.cc
index 2258d2419ba..2c586c2104f 100644
--- a/chromium/ui/display/types/display_mode.cc
+++ b/chromium/ui/display/types/display_mode.cc
@@ -21,6 +21,18 @@ std::unique_ptr<DisplayMode> DisplayMode::Clone() const {
new DisplayMode(size_, is_interlaced_, refresh_rate_));
}
+bool DisplayMode::operator<(const DisplayMode& other) const {
+ if (size_.GetArea() < other.size_.GetArea())
+ return true;
+ if (size_.GetArea() > other.size_.GetArea())
+ return false;
+ if (size_.width() < other.size_.width())
+ return true;
+ if (size_.width() > other.size_.width())
+ return false;
+ return refresh_rate_ < other.refresh_rate_;
+}
+
std::string DisplayMode::ToString() const {
return base::StringPrintf("[%s %srate=%f]", size_.ToString().c_str(),
is_interlaced_ ? "interlaced " : "", refresh_rate_);
diff --git a/chromium/ui/display/types/display_mode.h b/chromium/ui/display/types/display_mode.h
index d171b72288a..187c2b80f6f 100644
--- a/chromium/ui/display/types/display_mode.h
+++ b/chromium/ui/display/types/display_mode.h
@@ -27,6 +27,8 @@ class DISPLAY_TYPES_EXPORT DisplayMode {
bool is_interlaced() const { return is_interlaced_; }
float refresh_rate() const { return refresh_rate_; }
+ bool operator<(const DisplayMode& other) const;
+
std::string ToString() const;
private:
diff --git a/chromium/ui/display/types/display_snapshot.cc b/chromium/ui/display/types/display_snapshot.cc
index ff90d89a8f1..6d3fba3839b 100644
--- a/chromium/ui/display/types/display_snapshot.cc
+++ b/chromium/ui/display/types/display_snapshot.cc
@@ -65,6 +65,8 @@ DisplaySnapshot::DisplaySnapshot(int64_t display_id,
const gfx::Point& origin,
const gfx::Size& physical_size,
DisplayConnectionType type,
+ uint64_t base_connector_id,
+ const std::vector<uint64_t>& path_topology,
bool is_aspect_preserving_scaling,
bool has_overscan,
PrivacyScreenState privacy_screen_state,
@@ -86,6 +88,8 @@ DisplaySnapshot::DisplaySnapshot(int64_t display_id,
origin_(origin),
physical_size_(physical_size),
type_(type),
+ base_connector_id_(base_connector_id),
+ path_topology_(path_topology),
is_aspect_preserving_scaling_(is_aspect_preserving_scaling),
has_overscan_(has_overscan),
privacy_screen_state_(privacy_screen_state),
@@ -129,29 +133,37 @@ std::unique_ptr<DisplaySnapshot> DisplaySnapshot::Clone() {
}
return std::make_unique<DisplaySnapshot>(
- display_id_, origin_, physical_size_, type_,
- is_aspect_preserving_scaling_, has_overscan_, privacy_screen_state_,
- has_color_correction_matrix_, color_correction_in_linear_space_,
- color_space_, bits_per_channel_, display_name_, sys_path_,
- std::move(clone_modes), panel_orientation_, edid_, cloned_current_mode,
- cloned_native_mode, product_code_, year_of_manufacture_,
- maximum_cursor_size_);
+ display_id_, origin_, physical_size_, type_, base_connector_id_,
+ path_topology_, is_aspect_preserving_scaling_, has_overscan_,
+ privacy_screen_state_, has_color_correction_matrix_,
+ color_correction_in_linear_space_, color_space_, bits_per_channel_,
+ display_name_, sys_path_, std::move(clone_modes), panel_orientation_,
+ edid_, cloned_current_mode, cloned_native_mode, product_code_,
+ year_of_manufacture_, maximum_cursor_size_);
}
std::string DisplaySnapshot::ToString() const {
+ std::string sharing_connector;
+ if (base_connector_id_) {
+ sharing_connector = path_topology_.empty() ? "NO" : "YES";
+ } else {
+ sharing_connector = "parsing_error";
+ }
+
return base::StringPrintf(
"id=%" PRId64
" current_mode=%s native_mode=%s origin=%s"
" panel_orientation=%d"
- " physical_size=%s, type=%s name=\"%s\" (year:%d) "
- "modes=(%s)",
+ " physical_size=%s, type=%s sharing_base_connector=%s name=\"%s\" "
+ "(year:%d) modes=(%s)",
display_id_,
current_mode_ ? current_mode_->ToString().c_str() : "nullptr",
native_mode_ ? native_mode_->ToString().c_str() : "nullptr",
origin_.ToString().c_str(), panel_orientation_,
physical_size_.ToString().c_str(),
- DisplayConnectionTypeString(type_).c_str(), display_name_.c_str(),
- year_of_manufacture_, ModeListString(modes_).c_str());
+ DisplayConnectionTypeString(type_).c_str(), sharing_connector.c_str(),
+ display_name_.c_str(), year_of_manufacture_,
+ ModeListString(modes_).c_str());
}
// static
diff --git a/chromium/ui/display/types/display_snapshot.h b/chromium/ui/display/types/display_snapshot.h
index fc552e50f4e..6aaff6015e0 100644
--- a/chromium/ui/display/types/display_snapshot.h
+++ b/chromium/ui/display/types/display_snapshot.h
@@ -33,6 +33,8 @@ class DISPLAY_TYPES_EXPORT DisplaySnapshot {
const gfx::Point& origin,
const gfx::Size& physical_size,
DisplayConnectionType type,
+ uint64_t base_connector_id,
+ const std::vector<uint64_t>& path_topology,
bool is_aspect_preserving_scaling,
bool has_overscan,
PrivacyScreenState privacy_screen_state,
@@ -57,6 +59,8 @@ class DISPLAY_TYPES_EXPORT DisplaySnapshot {
void set_origin(const gfx::Point& origin) { origin_ = origin; }
const gfx::Size& physical_size() const { return physical_size_; }
DisplayConnectionType type() const { return type_; }
+ uint64_t base_connector_id() const { return base_connector_id_; }
+ const std::vector<uint64_t>& path_topology() const { return path_topology_; }
bool is_aspect_preserving_scaling() const {
return is_aspect_preserving_scaling_;
}
@@ -109,6 +113,53 @@ class DISPLAY_TYPES_EXPORT DisplaySnapshot {
const DisplayConnectionType type_;
+ // The next two private members represent the connection path between the
+ // source device and this display. Consider the following three-display setup:
+ // +-------------+
+ // | Source | +-------------+
+ // | (Device) | | BranchX |
+ // | | | (MST) |
+ // | [conn6]--->| [port1]--->DisplayA
+ // +-------------+ | |
+ // | | +-------------+
+ // | | | BranchY |
+ // | | | (MST) |
+ // | [port2]--->| [port1]----->DisplayB
+ // +-------------+ | |
+ // | [port2]----->DisplayC
+ // +-------------+
+ // [conn6]: is the root of the topology tree (a.k.a. the base connector),
+ // which maps to a physical connector on the device. This value can be used to
+ // determine if two or more external displays are sharing the same physical
+ // port.
+ // Important: Do not confuse this value with a display's connector ID!
+ // The base connector will be listed as disconnected when a branch device is
+ // attached to it to signal that it is not available for use, while new
+ // connector IDs are spawned for connected monitors down the path. A display's
+ // connector ID will be equal to the base connector ID only when the display
+ // is connected directly to the source device.
+ // [BranchX|port1]: is an output port to which DisplayA is connected.
+ // [BranchX|port2]: is an output port to which BranchY is connected.
+ // The ports on BranchY follow the same logic. Notice that port numbers across
+ // branch devices are NOT unique.
+ //
+ // Example 1: if |this| represents DisplayB:
+ // |base_connector_id_| == 6
+ // |path_topology_| == {2, 1}
+ // |base_connector_id_| != |this| connector id.
+ //
+ // Example 2: if |this| represents a display that is connected directly to the
+ // source device above:
+ // |base_connector_id_| == 6
+ // |path_topology_| == {}
+ // |base_connector_id_| == |this| connector id.
+ //
+ // The path is in a failed/error state if |base_connector_id_| == 0. This
+ // indicates that the display is connected to one or more branch devices, but
+ // the path could not be parsed.
+ const uint64_t base_connector_id_;
+ const std::vector<uint64_t> path_topology_;
+
const bool is_aspect_preserving_scaling_;
const bool has_overscan_;
diff --git a/chromium/ui/display/types/native_display_delegate.h b/chromium/ui/display/types/native_display_delegate.h
index 56375f94e3f..0c04497b981 100644
--- a/chromium/ui/display/types/native_display_delegate.h
+++ b/chromium/ui/display/types/native_display_delegate.h
@@ -25,8 +25,7 @@ struct DisplayConfigurationParams;
using GetDisplaysCallback =
base::OnceCallback<void(const std::vector<DisplaySnapshot*>&)>;
-using ConfigureCallback =
- base::OnceCallback<void(const base::flat_map<int64_t, bool>&)>;
+using ConfigureCallback = base::OnceCallback<void(bool)>;
using GetHDCPStateCallback =
base::OnceCallback<void(bool, HDCPState, ContentProtectionMethod)>;
using SetHDCPStateCallback = base::OnceCallback<void(bool)>;
diff --git a/chromium/ui/display/unified_desktop_utils.cc b/chromium/ui/display/unified_desktop_utils.cc
index 5016514dc67..feed2f88c16 100644
--- a/chromium/ui/display/unified_desktop_utils.cc
+++ b/chromium/ui/display/unified_desktop_utils.cc
@@ -7,9 +7,9 @@
#include <map>
#include <set>
+#include "base/containers/contains.h"
#include "base/containers/stack.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "ui/display/types/display_constants.h"
namespace display {
diff --git a/chromium/ui/display/util/BUILD.gn b/chromium/ui/display/util/BUILD.gn
index a3449ca93c2..cdd6988ef1a 100644
--- a/chromium/ui/display/util/BUILD.gn
+++ b/chromium/ui/display/util/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
@@ -27,7 +28,7 @@ component("util") {
"//ui/gfx/geometry",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//ui/display/types" ]
} else if (is_mac) {
frameworks = [ "IOSurface.framework" ]
diff --git a/chromium/ui/display/util/DIR_METADATA b/chromium/ui/display/util/DIR_METADATA
new file mode 100644
index 00000000000..0ff67f3550e
--- /dev/null
+++ b/chromium/ui/display/util/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "OS>Kernel>Graphics"
+}
diff --git a/chromium/ui/display/util/OWNERS b/chromium/ui/display/util/OWNERS
index 3fd44a4deeb..5b7f5316e65 100644
--- a/chromium/ui/display/util/OWNERS
+++ b/chromium/ui/display/util/OWNERS
@@ -1,4 +1,2 @@
dcastagna@chromium.org
mcasas@chromium.org
-
-# COMPONENT: OS>Kernel>Graphics
diff --git a/chromium/ui/display/util/display_util.cc b/chromium/ui/display/util/display_util.cc
index 8ca876e83d2..2db1522b87c 100644
--- a/chromium/ui/display/util/display_util.cc
+++ b/chromium/ui/display/util/display_util.cc
@@ -6,9 +6,9 @@
#include <stddef.h>
+#include "base/containers/contains.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
-#include "base/stl_util.h"
#include "ui/display/util/edid_parser.h"
namespace display {
diff --git a/chromium/ui/display/win/color_profile_reader.cc b/chromium/ui/display/win/color_profile_reader.cc
index f24a8309033..2a577844692 100644
--- a/chromium/ui/display/win/color_profile_reader.cc
+++ b/chromium/ui/display/win/color_profile_reader.cc
@@ -68,9 +68,11 @@ void ColorProfileReader::UpdateIfNeeded() {
// Enumerate device profile paths on a background thread. When this
// completes it will run another task on a background thread to read
- // the profiles.
+ // the profiles. This can impact the color of the browser so we want
+ // to set this to a higher priority to complete the task earlier
+ // during startup.
base::ThreadPool::PostTaskAndReplyWithResult(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(
&ColorProfileReader::BuildDeviceToPathMapOnBackgroundThread),
base::BindOnce(&ColorProfileReader::BuildDeviceToPathMapCompleted,
@@ -100,7 +102,7 @@ void ColorProfileReader::BuildDeviceToPathMapCompleted(
device_to_path_map_ = new_device_to_path_map;
base::ThreadPool::PostTaskAndReplyWithResult(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(&ColorProfileReader::ReadProfilesOnBackgroundThread,
new_device_to_path_map),
base::BindOnce(&ColorProfileReader::ReadProfilesCompleted,
diff --git a/chromium/ui/display/win/local_process_window_finder_win.cc b/chromium/ui/display/win/local_process_window_finder_win.cc
index d4be1b9f346..5e02cb2c33e 100644
--- a/chromium/ui/display/win/local_process_window_finder_win.cc
+++ b/chromium/ui/display/win/local_process_window_finder_win.cc
@@ -16,7 +16,7 @@ gfx::NativeWindow LocalProcessWindowFinder::GetProcessWindowAtPoint(
const gfx::Point& screen_loc,
const std::set<HWND>& ignore,
ScreenWin* screen_win) {
- LocalProcessWindowFinder finder(screen_loc, ignore);
+ LocalProcessWindowFinder finder(screen_loc, screen_win, ignore);
// Windows 8 has a window that appears first in the list of iterated
// windows, yet is not visually on top of everything.
// TODO(sky): figure out a better way to ignore this window.
@@ -44,15 +44,22 @@ bool LocalProcessWindowFinder::ShouldStopIterating(HWND hwnd) {
if (IsWindowVisible(hwnd) && GetWindowRect(hwnd, &r) &&
PtInRect(&r, screen_loc_.ToPOINT())) {
- result_ = hwnd;
+ // Don't set result_ if the window is occluded, because there is at least
+ // one window covering the browser window. E.g., tab drag drop shouldn't
+ // drop on an occluded browser window.
+ gfx::NativeWindow native_window =
+ screen_win_->GetNativeWindowFromHWND(hwnd);
+ if (!native_window || !screen_win_->IsNativeWindowOccluded(native_window))
+ result_ = hwnd;
return true;
}
return false;
}
LocalProcessWindowFinder::LocalProcessWindowFinder(const gfx::Point& screen_loc,
+ ScreenWin* screen_win,
const std::set<HWND>& ignore)
- : BaseWindowFinderWin(ignore), result_(nullptr) {
+ : BaseWindowFinderWin(ignore), result_(nullptr), screen_win_(screen_win) {
if (base::win::GetVersion() >= base::win::Version::WIN10) {
::CoCreateInstance(__uuidof(VirtualDesktopManager), nullptr, CLSCTX_ALL,
IID_PPV_ARGS(&virtual_desktop_manager_));
diff --git a/chromium/ui/display/win/local_process_window_finder_win.h b/chromium/ui/display/win/local_process_window_finder_win.h
index 13f14ca70c7..2ee7af54eaa 100644
--- a/chromium/ui/display/win/local_process_window_finder_win.h
+++ b/chromium/ui/display/win/local_process_window_finder_win.h
@@ -32,6 +32,7 @@ class LocalProcessWindowFinder : public BaseWindowFinderWin {
private:
LocalProcessWindowFinder(const gfx::Point& screen_loc,
+ ScreenWin* screen_win,
const std::set<HWND>& ignore);
LocalProcessWindowFinder(const LocalProcessWindowFinder& finder) = delete;
LocalProcessWindowFinder& operator=(const LocalProcessWindowFinder& finder) =
@@ -45,6 +46,10 @@ class LocalProcessWindowFinder : public BaseWindowFinderWin {
// ShouldStopIterating if an appropriate window is found.
HWND result_;
+ // ScreenWin we're looking on. Used to access WindowTreeHost, which
+ // ui/display code can't access directly.
+ ScreenWin* screen_win_;
+
// Only used on Win10+.
Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager_;
};
diff --git a/chromium/ui/display/win/screen_win.cc b/chromium/ui/display/win/screen_win.cc
index 4b6c82f9877..9fe7bb96703 100644
--- a/chromium/ui/display/win/screen_win.cc
+++ b/chromium/ui/display/win/screen_win.cc
@@ -11,11 +11,11 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
#include "base/metrics/histogram_functions.h"
#include "base/numerics/ranges.h"
#include "base/numerics/safe_conversions.h"
#include "base/optional.h"
-#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
@@ -662,6 +662,11 @@ gfx::NativeWindow ScreenWin::GetNativeWindowFromHWND(HWND hwnd) const {
return nullptr;
}
+bool ScreenWin::IsNativeWindowOccluded(gfx::NativeWindow window) const {
+ NOTREACHED();
+ return false;
+}
+
ScreenWin::ScreenWin(bool initialize) {
DCHECK(!g_instance);
g_instance = this;
@@ -775,7 +780,7 @@ void ScreenWin::Initialize() {
// We want to remember that we've observed a screen metrics object so that we
// can remove ourselves as an observer at some later point (either when the
// metrics object notifies us it's going away or when we are destructed).
- scale_factor_observer_.Add(UwpTextScaleFactor::Instance());
+ scale_factor_observation_.Observe(UwpTextScaleFactor::Instance());
}
MONITORINFOEX ScreenWin::MonitorInfoFromScreenPoint(
@@ -948,8 +953,7 @@ void ScreenWin::OnUwpTextScaleFactorChanged() {
}
void ScreenWin::OnUwpTextScaleFactorCleanup(UwpTextScaleFactor* source) {
- if (scale_factor_observer_.IsObserving(source))
- scale_factor_observer_.Remove(source);
+ scale_factor_observation_.Reset();
UwpTextScaleFactor::Observer::OnUwpTextScaleFactorCleanup(source);
}
diff --git a/chromium/ui/display/win/screen_win.h b/chromium/ui/display/win/screen_win.h
index dfffbeff3f5..0e8f30f7ab4 100644
--- a/chromium/ui/display/win/screen_win.h
+++ b/chromium/ui/display/win/screen_win.h
@@ -11,7 +11,7 @@
#include <vector>
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/display/display_change_notifier.h"
#include "ui/display/display_export.h"
#include "ui/display/screen.h"
@@ -154,6 +154,9 @@ class DISPLAY_EXPORT ScreenWin : public Screen,
// Returns the NativeWindow associated with the HWND.
virtual gfx::NativeWindow GetNativeWindowFromHWND(HWND hwnd) const;
+ // Returns true if the native window is occluded.
+ virtual bool IsNativeWindowOccluded(gfx::NativeWindow window) const;
+
protected:
ScreenWin(bool initialize);
@@ -263,8 +266,8 @@ class DISPLAY_EXPORT ScreenWin : public Screen,
// advanced color" setting.
bool hdr_enabled_ = false;
- ScopedObserver<UwpTextScaleFactor, UwpTextScaleFactor::Observer>
- scale_factor_observer_{this};
+ base::ScopedObservation<UwpTextScaleFactor, UwpTextScaleFactor::Observer>
+ scale_factor_observation_{this};
DISALLOW_COPY_AND_ASSIGN(ScreenWin);
};
diff --git a/chromium/ui/events/BUILD.gn b/chromium/ui/events/BUILD.gn
index f5fc2f2c48d..5ebdb369a37 100644
--- a/chromium/ui/events/BUILD.gn
+++ b/chromium/ui/events/BUILD.gn
@@ -146,6 +146,7 @@ component("events_base") {
deps = [
":dom_keycode_converter",
"//base/third_party/dynamic_annotations",
+ "//build:chromeos_buildflags",
]
public_deps = [
@@ -228,6 +229,8 @@ component("events") {
if (is_win) {
public += [
"win/events_win_utils.h",
+ "win/keyboard_hook_monitor.h",
+ "win/keyboard_hook_observer.h",
"win/system_event_state_lookup.h",
]
@@ -236,6 +239,8 @@ component("events") {
"keycodes/platform_key_map_win.h",
"win/events_win.cc",
"win/events_win_utils.cc",
+ "win/keyboard_hook_monitor_impl.cc",
+ "win/keyboard_hook_monitor_impl.h",
"win/keyboard_hook_win_base.cc",
"win/keyboard_hook_win_base.h",
"win/media_keyboard_hook_win.cc",
@@ -346,6 +351,8 @@ component("events") {
"gestures/gesture_recognizer_impl.cc",
"gestures/motion_event_aura.cc",
]
+
+ deps += [ "//build:chromeos_buildflags" ]
}
if (is_win || is_mac || use_x11 || use_ozone) {
@@ -437,6 +444,7 @@ component("gesture_detection") {
":events_base",
"//base",
"//base/third_party/dynamic_annotations",
+ "//build:chromeos_buildflags",
"//ui/display",
"//ui/gfx",
"//ui/gfx/geometry",
@@ -483,7 +491,11 @@ static_library("test_support") {
]
if (is_win) {
- sources += [ "test/keyboard_layout_win.cc" ]
+ sources += [
+ "test/keyboard_hook_monitor_utils.cc",
+ "test/keyboard_hook_monitor_utils.h",
+ "test/keyboard_layout_win.cc",
+ ]
}
if (is_mac) {
@@ -503,6 +515,7 @@ static_library("test_support") {
]
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//skia",
"//ui/events/platform",
"//ui/gfx",
diff --git a/chromium/ui/events/android/OWNERS b/chromium/ui/events/android/OWNERS
index 6e91dc0e07c..343711b35e9 100644
--- a/chromium/ui/events/android/OWNERS
+++ b/chromium/ui/events/android/OWNERS
@@ -1,2 +1 @@
-tdresser@chromium.org
-nzolghadr@chromium.org
+flackr@chromium.org
diff --git a/chromium/ui/events/base_event_utils.cc b/chromium/ui/events/base_event_utils.cc
index f5c709d2e65..f6a14c100b4 100644
--- a/chromium/ui/events/base_event_utils.cc
+++ b/chromium/ui/events/base_event_utils.cc
@@ -10,6 +10,7 @@
#include "base/lazy_instance.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_switches.h"
@@ -17,14 +18,14 @@ namespace ui {
namespace {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
const int kSystemKeyModifierMask = EF_ALT_DOWN | EF_COMMAND_DOWN;
#elif defined(OS_APPLE)
// Alt modifier is used to input extended characters on Mac.
const int kSystemKeyModifierMask = EF_COMMAND_DOWN;
#else
const int kSystemKeyModifierMask = EF_ALT_DOWN;
-#endif // !defined(OS_CHROMEOS) && !defined(OS_APPLE)
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_APPLE)
bool IsValidTimebase(base::TimeTicks now, base::TimeTicks timestamp) {
int64_t delta = (now - timestamp).InMilliseconds();
diff --git a/chromium/ui/events/blink/OWNERS b/chromium/ui/events/blink/OWNERS
index 8968c2d706a..9468b22325f 100644
--- a/chromium/ui/events/blink/OWNERS
+++ b/chromium/ui/events/blink/OWNERS
@@ -1,4 +1,3 @@
dtapuska@chromium.org
-tdresser@chromium.org
bokan@chromium.org
-nzolghadr@chromium.org
+flackr@chromium.org
diff --git a/chromium/ui/events/blink/blink_event_util.cc b/chromium/ui/events/blink/blink_event_util.cc
index 4a632bfd8da..882781c40b4 100644
--- a/chromium/ui/events/blink/blink_event_util.cc
+++ b/chromium/ui/events/blink/blink_event_util.cc
@@ -490,9 +490,7 @@ std::unique_ptr<blink::WebInputEvent> TranslateAndScaleWebInputEvent(
float x = (wheel_event->PositionInWidget().x() + delta.x()) * scale;
float y = (wheel_event->PositionInWidget().y() + delta.y()) * scale;
wheel_event->SetPositionInWidget(x, y);
- if (wheel_event->delta_units != ui::ScrollGranularity::kScrollByPage &&
- wheel_event->delta_units !=
- ui::ScrollGranularity::kScrollByPercentage) {
+ if (wheel_event->delta_units != ui::ScrollGranularity::kScrollByPage) {
wheel_event->delta_x *= scale;
wheel_event->delta_y *= scale;
wheel_event->wheel_ticks_x *= scale;
diff --git a/chromium/ui/events/blink/blink_event_util_unittest.cc b/chromium/ui/events/blink/blink_event_util_unittest.cc
index ad0238a80f3..4f77db7531a 100644
--- a/chromium/ui/events/blink/blink_event_util_unittest.cc
+++ b/chromium/ui/events/blink/blink_event_util_unittest.cc
@@ -31,12 +31,12 @@ TEST(BlinkEventUtilTest, NoScalingWith1DSF) {
EXPECT_TRUE(ScaleWebInputEvent(event, 2.f));
}
-TEST(BlinkEventUtilTest, NonPaginatedWebMouseWheelEvent) {
+void RunTest(ui::ScrollGranularity granularity) {
blink::WebMouseWheelEvent event(
blink::WebInputEvent::Type::kMouseWheel,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
- event.delta_units = ui::ScrollGranularity::kScrollByPixel;
+ event.delta_units = granularity;
event.delta_x = 1.f;
event.delta_y = 1.f;
event.wheel_ticks_x = 1.f;
@@ -52,6 +52,14 @@ TEST(BlinkEventUtilTest, NonPaginatedWebMouseWheelEvent) {
EXPECT_EQ(2.f, mouseWheelEvent->wheel_ticks_y);
}
+TEST(BlinkEventUtilTest, NonPaginatedWebMouseWheelEvent) {
+ RunTest(ui::ScrollGranularity::kScrollByPixel);
+}
+
+TEST(BlinkEventUtilTest, NonPaginatedWebMouseWheelEventPercentBased) {
+ RunTest(ui::ScrollGranularity::kScrollByPercentage);
+}
+
TEST(BlinkEventUtilTest, PaginatedWebMouseWheelEvent) {
blink::WebMouseWheelEvent event(
blink::WebInputEvent::Type::kMouseWheel,
diff --git a/chromium/ui/events/devices/device_data_manager_unittest.cc b/chromium/ui/events/devices/device_data_manager_unittest.cc
index 7f22dd56e46..3b73e9dd857 100644
--- a/chromium/ui/events/devices/device_data_manager_unittest.cc
+++ b/chromium/ui/events/devices/device_data_manager_unittest.cc
@@ -4,7 +4,7 @@
#include "ui/events/devices/device_data_manager.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/types/display_constants.h"
#include "ui/events/devices/device_hotplug_event_observer.h"
@@ -83,9 +83,9 @@ TEST_F(DeviceDataManagerTest, AreTouchscreenTargetDisplaysValid) {
DeviceDataManager* device_data_manager = DeviceDataManager::GetInstance();
EXPECT_FALSE(device_data_manager->AreTouchscreenTargetDisplaysValid());
TestInputDeviceEventObserver observer;
- ScopedObserver<DeviceDataManager, InputDeviceEventObserver> scoped_observer(
- &observer);
- scoped_observer.Add(device_data_manager);
+ base::ScopedObservation<DeviceDataManager, InputDeviceEventObserver>
+ scoped_obaservation(&observer);
+ scoped_obaservation.Observe(device_data_manager);
CallOnDeviceListsComplete();
EXPECT_FALSE(device_data_manager->AreTouchscreenTargetDisplaysValid());
EXPECT_EQ(0, observer.on_touch_device_associations_changed_call_count());
diff --git a/chromium/ui/events/devices/x11/BUILD.gn b/chromium/ui/events/devices/x11/BUILD.gn
index 2777382cdfd..6db5a3908b2 100644
--- a/chromium/ui/events/devices/x11/BUILD.gn
+++ b/chromium/ui/events/devices/x11/BUILD.gn
@@ -26,6 +26,7 @@ component("x11") {
deps = [
"//base",
"//base/third_party/dynamic_annotations",
+ "//build:chromeos_buildflags",
"//skia",
"//ui/display",
"//ui/events:events_base",
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 274c07950db..78624862dd8 100644
--- a/chromium/ui/events/devices/x11/device_data_manager_x11.cc
+++ b/chromium/ui/events/devices/x11/device_data_manager_x11.cc
@@ -25,6 +25,7 @@
#include "ui/events/event_switches.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
#include "ui/gfx/geometry/point3_f.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/x11_atom_cache.h"
// XIScrollClass was introduced in XI 2.1 so we need to define it here
@@ -261,7 +262,7 @@ void DeviceDataManagerX11::UpdateDeviceList(x11::Connection* connection) {
// Find all the touchpad devices.
const XDeviceList& dev_list =
ui::DeviceListCacheX11::GetInstance()->GetXDeviceList(connection);
- x11::Atom xi_touchpad = gfx::GetAtom("TOUCHPAD");
+ x11::Atom xi_touchpad = x11::GetAtom("TOUCHPAD");
for (const auto& device : dev_list) {
if (device.device_type == xi_touchpad)
touchpads_[device.device_id] = true;
@@ -275,7 +276,7 @@ void DeviceDataManagerX11::UpdateDeviceList(x11::Connection* connection) {
ui::DeviceListCacheX11::GetInstance()->GetXI2DeviceList(connection);
x11::Atom atoms[DT_LAST_ENTRY];
for (int data_type = 0; data_type < DT_LAST_ENTRY; ++data_type)
- atoms[data_type] = gfx::GetAtom(kCachedAtoms[data_type]);
+ atoms[data_type] = x11::GetAtom(kCachedAtoms[data_type]);
for (const auto& info : info_list) {
if (info.type == x11::Input::DeviceType::MasterPointer)
@@ -655,7 +656,7 @@ int DeviceDataManagerX11::GetMappedButton(int button) {
}
void DeviceDataManagerX11::UpdateButtonMap() {
- if (auto reply = x11::Connection::Get()->GetPointerMapping({}).Sync())
+ if (auto reply = x11::Connection::Get()->GetPointerMapping().Sync())
button_map_ = std::move(reply->map);
}
diff --git a/chromium/ui/events/devices/x11/device_list_cache_x11.cc b/chromium/ui/events/devices/x11/device_list_cache_x11.cc
index 49fe471d79e..7b16b762626 100644
--- a/chromium/ui/events/devices/x11/device_list_cache_x11.cc
+++ b/chromium/ui/events/devices/x11/device_list_cache_x11.cc
@@ -9,6 +9,7 @@
#include "base/memory/singleton.h"
#include "ui/events/devices/x11/device_data_manager_x11.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
namespace ui {
@@ -21,8 +22,8 @@ DeviceListCacheX11* DeviceListCacheX11::GetInstance() {
}
void DeviceListCacheX11::UpdateDeviceList(x11::Connection* connection) {
- auto x_future = connection->xinput().ListInputDevices({});
- auto xi_future = connection->xinput().XIQueryDevice({});
+ auto x_future = connection->xinput().ListInputDevices();
+ auto xi_future = connection->xinput().XIQueryDevice();
connection->Flush();
if (auto reply = x_future.Sync())
x_dev_list_ = reply->devices;
diff --git a/chromium/ui/events/devices/x11/touch_factory_x11.cc b/chromium/ui/events/devices/x11/touch_factory_x11.cc
index 6a811d1a8ff..c6670959664 100644
--- a/chromium/ui/events/devices/x11/touch_factory_x11.cc
+++ b/chromium/ui/events/devices/x11/touch_factory_x11.cc
@@ -14,12 +14,14 @@
#include "base/strings/string_split.h"
#include "base/system/sys_info.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/devices/x11/device_data_manager_x11.h"
#include "ui/events/devices/x11/device_list_cache_x11.h"
#include "ui/events/devices/x11/xinput_util.h"
#include "ui/events/event_switches.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
namespace ui {
namespace {
@@ -221,7 +223,7 @@ void TouchFactory::SetupXI2ForXWindow(x11::Window window) {
// these events.
SetXinputMask(mask_data, x11::Input::HierarchyEvent::opcode);
SetXinputMask(mask_data, x11::Input::DeviceChangedEvent::opcode);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
if (base::SysInfo::IsRunningOnChromeOS()) {
SetXinputMask(mask_data, x11::Input::DeviceEvent::KeyPress);
SetXinputMask(mask_data, x11::Input::DeviceEvent::KeyRelease);
diff --git a/chromium/ui/events/event.cc b/chromium/ui/events/event.cc
index 58b71ae62d9..e02c15865d6 100644
--- a/chromium/ui/events/event.cc
+++ b/chromium/ui/events/event.cc
@@ -16,8 +16,11 @@
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
+#include "base/strings/strcat.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event_utils.h"
@@ -200,7 +203,7 @@ void Event::SetNativeEvent(const PlatformEvent& event) {
}
const char* Event::GetName() const {
- return EventTypeName(type_);
+ return EventTypeName(type_).data();
}
void Event::SetProperties(const Properties& properties) {
@@ -310,23 +313,16 @@ void Event::SetHandled() {
}
std::string Event::ToString() const {
- std::string s = GetName();
- s += " time_stamp ";
- s += base::NumberToString(time_stamp_.since_origin().InSecondsF());
- return s;
+ return base::StrCat(
+ {GetName(), " time_stamp ",
+ base::NumberToString(time_stamp_.since_origin().InSecondsF())});
}
Event::Event(EventType type, base::TimeTicks time_stamp, int flags)
: type_(type),
time_stamp_(time_stamp.is_null() ? EventTimeForNow() : time_stamp),
flags_(flags),
- native_event_(PlatformEvent()),
- delete_native_event_(false),
- cancelable_(true),
- target_(nullptr),
- phase_(EP_PREDISPATCH),
- result_(ER_UNHANDLED),
- source_device_id_(ED_UNKNOWN_DEVICE) {
+ native_event_(PlatformEvent()) {
if (type_ < ET_LAST)
latency()->set_source_event_type(EventTypeToLatencySourceEventType(type));
}
@@ -335,13 +331,7 @@ Event::Event(const PlatformEvent& native_event, EventType type, int flags)
: type_(type),
time_stamp_(EventTimeFromNative(native_event)),
flags_(flags),
- native_event_(native_event),
- delete_native_event_(false),
- cancelable_(true),
- target_(nullptr),
- phase_(EP_PREDISPATCH),
- result_(ER_UNHANDLED),
- source_device_id_(ED_UNKNOWN_DEVICE) {
+ native_event_(native_event) {
if (type_ < ET_LAST)
latency()->set_source_event_type(EventTypeToLatencySourceEventType(type));
ComputeEventLatencyOS(native_event);
@@ -362,10 +352,6 @@ Event::Event(const Event& copy)
flags_(copy.flags_),
native_event_(CopyNativeEvent(copy.native_event_)),
delete_native_event_(true),
- cancelable_(true),
- target_(nullptr),
- phase_(EP_PREDISPATCH),
- result_(ER_UNHANDLED),
source_device_id_(copy.source_device_id_),
properties_(copy.properties_
? std::make_unique<Properties>(*copy.properties_)
@@ -455,12 +441,8 @@ void LocatedEvent::UpdateForRootTransform(
}
std::string LocatedEvent::ToString() const {
- std::string s = Event::ToString();
- s += " location ";
- s += location_.ToString();
- s += " root_location ";
- s += root_location_.ToString();
- return s;
+ return base::StrCat({Event::ToString(), " location ", location_.ToString(),
+ " root_location ", root_location_.ToString()});
}
////////////////////////////////////////////////////////////////////////////////
@@ -634,6 +616,12 @@ void MouseEvent::SetClickCount(int click_count) {
set_flags(f);
}
+std::string MouseEvent::ToString() const {
+ return base::StrCat(
+ {LocatedEvent::ToString(), " flags ",
+ base::JoinString(make_span(MouseEventFlagsNames(flags())), " | ")});
+}
+
////////////////////////////////////////////////////////////////////////////////
// MouseWheelEvent
@@ -724,8 +712,6 @@ const int MouseWheelEvent::kWheelDelta = 53;
TouchEvent::TouchEvent(const PlatformEvent& native_event)
: LocatedEvent(native_event),
unique_event_id_(ui::GetNextTouchEventId()),
- may_cause_scrolling_(false),
- hovering_(false),
pointer_details_(GetTouchPointerDetailsFromNative(native_event)) {
latency()->AddLatencyNumberWithTimestamp(
INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, time_stamp());
@@ -740,8 +726,6 @@ TouchEvent::TouchEvent(EventType type,
int flags)
: LocatedEvent(type, location, root_location, time_stamp, flags),
unique_event_id_(ui::GetNextTouchEventId()),
- may_cause_scrolling_(false),
- hovering_(false),
pointer_details_(pointer_details) {
latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT);
}
@@ -1117,6 +1101,13 @@ void KeyEvent::NormalizeFlags() {
set_flags(flags() & ~mask);
}
+std::string KeyEvent::ToString() const {
+ return base::StrCat(
+ {Event::ToString(), " key ", base::StringPrintf("(0x%.4x)", key_code_),
+ " flags ",
+ base::JoinString(make_span(KeyEventFlagsNames(flags())), " | ")});
+}
+
KeyboardCode KeyEvent::GetLocatedWindowsKeyboardCode() const {
return NonLocatedToLocatedKeyboardCode(key_code_, code_);
}
@@ -1222,14 +1213,11 @@ void ScrollEvent::Scale(const float factor) {
}
std::string ScrollEvent::ToString() const {
- std::string s = MouseEvent::ToString();
- s += " offset " + base::NumberToString(x_offset_) + "," +
- base::NumberToString(y_offset_);
- s += " offset_ordinal " + base::NumberToString(x_offset_ordinal_) + "," +
- base::NumberToString(y_offset_ordinal_);
- s += " momentum_phase " + MomentumPhaseToString(momentum_phase_);
- s += " event_phase " + ScrollEventPhaseToString(scroll_event_phase_);
- return s;
+ return base::StringPrintf(
+ "%s offset %g,%g offset_ordinal %g,%g momentum_phase %s event_phase %s",
+ MouseEvent::ToString().c_str(), x_offset_, y_offset_, x_offset_ordinal_,
+ y_offset_ordinal_, MomentumPhaseToString(momentum_phase_).c_str(),
+ ScrollEventPhaseToString(scroll_event_phase_).c_str());
}
////////////////////////////////////////////////////////////////////////////////
@@ -1260,4 +1248,10 @@ GestureEvent::GestureEvent(const GestureEvent& other) = default;
GestureEvent::~GestureEvent() = default;
+std::string GestureEvent::ToString() const {
+ return base::StringPrintf("%s touch_event_id %d",
+ LocatedEvent::ToString().c_str(),
+ unique_touch_event_id_);
+}
+
} // namespace ui
diff --git a/chromium/ui/events/event.h b/chromium/ui/events/event.h
index 4224c1bb6b2..2c9c0bda582 100644
--- a/chromium/ui/events/event.h
+++ b/chromium/ui/events/event.h
@@ -312,15 +312,15 @@ class EVENTS_EXPORT Event {
LatencyInfo latency_;
int flags_;
PlatformEvent native_event_;
- bool delete_native_event_;
- bool cancelable_;
- EventTarget* target_;
- EventPhase phase_;
- EventResult result_;
+ bool delete_native_event_ = false;
+ bool cancelable_ = true;
+ EventTarget* target_ = nullptr;
+ EventPhase phase_ = EP_PREDISPATCH;
+ EventResult result_ = ER_UNHANDLED;
// The device id the event came from, or ED_UNKNOWN_DEVICE if the information
// is not available.
- int source_device_id_;
+ int source_device_id_ = ED_UNKNOWN_DEVICE;
std::unique_ptr<Properties> properties_;
};
@@ -377,7 +377,7 @@ class EVENTS_EXPORT LocatedEvent : public Event {
location_ = location_ - diff;
}
- // Event:
+ // Event overrides.
std::string ToString() const override;
protected:
@@ -550,6 +550,9 @@ class EVENTS_EXPORT MouseEvent : public LocatedEvent {
const PointerDetails& pointer_details() const { return pointer_details_; }
+ // Event overides.
+ std::string ToString() const override;
+
private:
FRIEND_TEST_ALL_PREFIXES(EventTest, DoubleClickRequiresUniqueTimestamp);
FRIEND_TEST_ALL_PREFIXES(EventTest, SingleClickRightLeft);
@@ -703,11 +706,11 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent {
// Whether the (unhandled) touch event will produce a scroll event (e.g., a
// touchmove that exceeds the platform slop region, or a touchend that
// causes a fling). Defaults to false.
- bool may_cause_scrolling_;
+ bool may_cause_scrolling_ = false;
// True for devices like some pens when they support hovering over
// digitizer and they send events while hovering.
- bool hovering_;
+ bool hovering_ = false;
// Structure for holding pointer details for implementing PointerEvents API.
PointerDetails pointer_details_;
@@ -873,6 +876,9 @@ class EVENTS_EXPORT KeyEvent : public Event {
// (Native X11 event flags describe the state before the event.)
void NormalizeFlags();
+ // Event overrides.
+ std::string ToString() const override;
+
protected:
friend class KeyEventTestApi;
@@ -984,7 +990,7 @@ class EVENTS_EXPORT ScrollEvent : public MouseEvent {
EventMomentumPhase momentum_phase() const { return momentum_phase_; }
ScrollEventPhase scroll_event_phase() const { return scroll_event_phase_; }
- // Event:
+ // Event overrides.
std::string ToString() const override;
private:
@@ -1029,6 +1035,9 @@ class EVENTS_EXPORT GestureEvent : public LocatedEvent {
uint32_t unique_touch_event_id() const { return unique_touch_event_id_; }
+ // Event overrides.
+ std::string ToString() const override;
+
private:
GestureEventDetails details_;
diff --git a/chromium/ui/events/event_handler.cc b/chromium/ui/events/event_handler.cc
index f674e88b53f..68321ed555e 100644
--- a/chromium/ui/events/event_handler.cc
+++ b/chromium/ui/events/event_handler.cc
@@ -4,6 +4,9 @@
#include "ui/events/event_handler.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "ui/events/event.h"
#include "ui/events/event_dispatcher.h"
@@ -27,6 +30,7 @@ EventHandler::~EventHandler() {
}
void EventHandler::OnEvent(Event* event) {
+ VLOG(5) << GetLogContext() << "::OnEvent(" << event->ToString() << ")";
if (event->IsKeyEvent())
OnKeyEvent(event->AsKeyEvent());
else if (event->IsMouseEvent())
@@ -59,4 +63,8 @@ void EventHandler::OnGestureEvent(GestureEvent* event) {
void EventHandler::OnCancelMode(CancelModeEvent* event) {
}
+base::StringPiece EventHandler::GetLogContext() const {
+ return "(Unknown EventHandler)"; // Please override
+}
+
} // namespace ui
diff --git a/chromium/ui/events/event_handler.h b/chromium/ui/events/event_handler.h
index 60a50755b24..4feb49155d6 100644
--- a/chromium/ui/events/event_handler.h
+++ b/chromium/ui/events/event_handler.h
@@ -9,6 +9,7 @@
#include "base/containers/stack.h"
#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "ui/events/event_constants.h"
#include "ui/events/events_export.h"
@@ -54,6 +55,10 @@ class EVENTS_EXPORT EventHandler {
virtual void OnCancelMode(CancelModeEvent* event);
+ // Returns information about the implementing class or scope for diagnostic
+ // logging purposes.
+ virtual base::StringPiece GetLogContext() const;
+
private:
friend class EventDispatcher;
friend class EventTarget;
diff --git a/chromium/ui/events/event_utils.cc b/chromium/ui/events/event_utils.cc
index 3d0fc645fd0..487991a97f6 100644
--- a/chromium/ui/events/event_utils.cc
+++ b/chromium/ui/events/event_utils.cc
@@ -4,6 +4,7 @@
#include "ui/events/event_utils.h"
+#include <map>
#include <vector>
#include "base/check.h"
@@ -147,7 +148,7 @@ void ConvertEventLocationToTargetWindowLocation(
located_event->set_location_f(location_in_pixel_in_host);
}
-const char* EventTypeName(EventType type) {
+base::StringPiece EventTypeName(EventType type) {
if (type >= ET_LAST)
return "";
@@ -206,4 +207,92 @@ const char* EventTypeName(EventType type) {
return "";
}
+std::vector<base::StringPiece> EventFlagsNames(int event_flags) {
+ std::vector<base::StringPiece> names;
+ names.reserve(5); // Seems like a good starting point.
+ if (!event_flags) {
+ names.push_back("NONE");
+ return names;
+ }
+
+ if (event_flags & EF_IS_SYNTHESIZED)
+ names.push_back("IS_SYNTHESIZED");
+ if (event_flags & EF_SHIFT_DOWN)
+ names.push_back("SHIFT_DOWN");
+ if (event_flags & EF_CONTROL_DOWN)
+ names.push_back("CONTROL_DOWN");
+ if (event_flags & EF_ALT_DOWN)
+ names.push_back("ALT_DOWN");
+ if (event_flags & EF_COMMAND_DOWN)
+ names.push_back("COMMAND_DOWN");
+ if (event_flags & EF_ALTGR_DOWN)
+ names.push_back("ALTGR_DOWN");
+ if (event_flags & EF_MOD3_DOWN)
+ names.push_back("MOD3_DOWN");
+ if (event_flags & EF_NUM_LOCK_ON)
+ names.push_back("NUM_LOCK_ON");
+ if (event_flags & EF_CAPS_LOCK_ON)
+ names.push_back("CAPS_LOCK_ON");
+ if (event_flags & EF_SCROLL_LOCK_ON)
+ names.push_back("SCROLL_LOCK_ON");
+ if (event_flags & EF_LEFT_MOUSE_BUTTON)
+ names.push_back("LEFT_MOUSE_BUTTON");
+ if (event_flags & EF_MIDDLE_MOUSE_BUTTON)
+ names.push_back("MIDDLE_MOUSE_BUTTON");
+ if (event_flags & EF_RIGHT_MOUSE_BUTTON)
+ names.push_back("RIGHT_MOUSE_BUTTON");
+ if (event_flags & EF_BACK_MOUSE_BUTTON)
+ names.push_back("BACK_MOUSE_BUTTON");
+ if (event_flags & EF_FORWARD_MOUSE_BUTTON)
+ names.push_back("FORWARD_MOUSE_BUTTON");
+
+ return names;
+}
+
+std::vector<base::StringPiece> KeyEventFlagsNames(int event_flags) {
+ std::vector<base::StringPiece> names = EventFlagsNames(event_flags);
+ if (!event_flags)
+ return names;
+
+ if (event_flags & EF_IME_FABRICATED_KEY)
+ names.push_back("IME_FABRICATED_KEY");
+ if (event_flags & EF_IS_REPEAT)
+ names.push_back("IS_REPEAT");
+ if (event_flags & EF_FINAL)
+ names.push_back("FINAL");
+ if (event_flags & EF_IS_EXTENDED_KEY)
+ names.push_back("IS_EXTENDED_KEY");
+ if (event_flags & EF_IS_STYLUS_BUTTON)
+ names.push_back("IS_STYLUS_BUTTON");
+
+ return names;
+}
+
+std::vector<base::StringPiece> MouseEventFlagsNames(int event_flags) {
+ std::vector<base::StringPiece> names = EventFlagsNames(event_flags);
+ if (!event_flags)
+ return names;
+
+ if (event_flags & EF_IS_DOUBLE_CLICK)
+ names.push_back("IS_DOUBLE_CLICK");
+ if (event_flags & EF_IS_TRIPLE_CLICK)
+ names.push_back("IS_TRIPLE_CLICK");
+ if (event_flags & EF_IS_NON_CLIENT)
+ names.push_back("IS_NON_CLIENT");
+ if (event_flags & EF_FROM_TOUCH)
+ names.push_back("FROM_TOUCH");
+ if (event_flags & EF_TOUCH_ACCESSIBILITY)
+ names.push_back("TOUCH_ACCESSIBILITY");
+ if (event_flags & EF_CURSOR_HIDE)
+ names.push_back("CURSOR_HIDE");
+ if (event_flags & EF_PRECISION_SCROLLING_DELTA)
+ names.push_back("PRECISION_SCROLLING_DELTA");
+ if (event_flags & EF_SCROLL_BY_PAGE)
+ names.push_back("SCROLL_BY_PAGE");
+ if (event_flags & EF_UNADJUSTED_MOUSE)
+ names.push_back("UNADJUSTED_MOUSE");
+
+ return names;
+}
+
} // namespace ui
diff --git a/chromium/ui/events/event_utils.h b/chromium/ui/events/event_utils.h
index 7fc01174d5a..63bc53eeabb 100644
--- a/chromium/ui/events/event_utils.h
+++ b/chromium/ui/events/event_utils.h
@@ -8,8 +8,10 @@
#include <stdint.h>
#include <memory>
+#include <vector>
#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
#include "build/build_config.h"
#include "ui/display/display.h"
#include "ui/events/base_event_utils.h"
@@ -189,9 +191,21 @@ EVENTS_EXPORT void ConvertEventLocationToTargetWindowLocation(
const gfx::Point& current_window_origin,
ui::LocatedEvent* located_event);
-// Returns a string description of an event type. Useful for debugging.
-EVENTS_EXPORT const char* EventTypeName(EventType type);
+// The following utilities are useful for debugging and tracing.
+// Returns a string description of an event type.
+EVENTS_EXPORT base::StringPiece EventTypeName(EventType type);
+
+// Returns a vector of string representations of EventFlags.
+EVENTS_EXPORT std::vector<base::StringPiece> EventFlagsNames(int event_flags);
+
+// Returns a a vector of string representations of KeyEventFlags.
+EVENTS_EXPORT std::vector<base::StringPiece> KeyEventFlagsNames(
+ int event_flags);
+
+// Returns a a vector of string representations of MouseEventFlags.
+EVENTS_EXPORT std::vector<base::StringPiece> MouseEventFlagsNames(
+ int event_flags);
} // namespace ui
#endif // UI_EVENTS_EVENT_UTILS_H_
diff --git a/chromium/ui/events/gesture_detection/OWNERS b/chromium/ui/events/gesture_detection/OWNERS
index 234d0596f10..dd1be913f39 100644
--- a/chromium/ui/events/gesture_detection/OWNERS
+++ b/chromium/ui/events/gesture_detection/OWNERS
@@ -1,5 +1,4 @@
-tdresser@chromium.org
-nzolghadr@chromium.org
+flackr@chromium.org
per-file gesture_configuration_cast.cc=alexst@chromium.org
per-file gesture_configuration_cast.cc=kpschoedel@chromium.org
diff --git a/chromium/ui/events/gesture_detection/gesture_configuration.cc b/chromium/ui/events/gesture_detection/gesture_configuration.cc
index 70e15714e9d..d91d90a29ff 100644
--- a/chromium/ui/events/gesture_detection/gesture_configuration.cc
+++ b/chromium/ui/events/gesture_detection/gesture_configuration.cc
@@ -5,6 +5,8 @@
#include "build/build_config.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
+#include "build/chromeos_buildflags.h"
+
namespace ui {
namespace {
@@ -49,16 +51,16 @@ GestureConfiguration::GestureConfiguration()
// See crbug.com/357237 for details.
min_scaling_span_in_pixels_(125),
min_swipe_velocity_(20),
- // TODO(jdduke): Disable and remove entirely when issues with intermittent
- // scroll end detection on the Pixel are resolved, crbug.com/353702.
-#if defined(OS_CHROMEOS)
+// TODO(jdduke): Disable and remove entirely when issues with intermittent
+// scroll end detection on the Pixel are resolved, crbug.com/353702.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
scroll_debounce_interval_in_ms_(30),
#else
scroll_debounce_interval_in_ms_(0),
#endif
semi_long_press_time_in_ms_(400),
show_press_delay_in_ms_(150),
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
single_pointer_cancel_enabled_(true),
#else
single_pointer_cancel_enabled_(false),
diff --git a/chromium/ui/events/gesture_detection/gesture_configuration_aura.cc b/chromium/ui/events/gesture_detection/gesture_configuration_aura.cc
index e973ea88dfb..49af0a4f2c9 100644
--- a/chromium/ui/events/gesture_detection/gesture_configuration_aura.cc
+++ b/chromium/ui/events/gesture_detection/gesture_configuration_aura.cc
@@ -7,16 +7,17 @@
#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/event_switches.h"
namespace ui {
namespace {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
constexpr bool kDoubleTapAuraSupport = true;
#else
constexpr bool kDoubleTapAuraSupport = false;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
class GestureConfigurationAura : public GestureConfiguration {
public:
@@ -29,7 +30,7 @@ class GestureConfigurationAura : public GestureConfiguration {
private:
GestureConfigurationAura() : GestureConfiguration() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// On ChromeOS, use 6 which is derived from the android's default(8),
// multiplied by base dpi ratio(0.75). See crbug.com/1083120 for more
// details.
diff --git a/chromium/ui/events/gesture_detection/gesture_detector.cc b/chromium/ui/events/gesture_detection/gesture_detector.cc
index f44ea90523f..1520c6980af 100644
--- a/chromium/ui/events/gesture_detection/gesture_detector.cc
+++ b/chromium/ui/events/gesture_detection/gesture_detector.cc
@@ -11,6 +11,7 @@
#include "base/numerics/ranges.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/event_constants.h"
#include "ui/events/gesture_detection/gesture_listeners.h"
#include "ui/events/gesture_detection/motion_event.h"
@@ -52,7 +53,7 @@ GestureDetector::Config::Config()
two_finger_tap_max_separation(300),
two_finger_tap_timeout(base::TimeDelta::FromMilliseconds(700)),
single_tap_repeat_interval(1),
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
stylus_button_accelerated_longpress_enabled(true),
#else
stylus_button_accelerated_longpress_enabled(false),
diff --git a/chromium/ui/events/gestures/OWNERS b/chromium/ui/events/gestures/OWNERS
index 7ac1c376701..85a182d6324 100644
--- a/chromium/ui/events/gestures/OWNERS
+++ b/chromium/ui/events/gestures/OWNERS
@@ -1,4 +1,3 @@
rjkroege@chromium.org
sadrul@chromium.org
-tdresser@chromium.org
-nzolghadr@chromium.org
+flackr@chromium.org \ No newline at end of file
diff --git a/chromium/ui/events/gestures/gesture_provider_aura.cc b/chromium/ui/events/gestures/gesture_provider_aura.cc
index 8a1ffa2507e..eb43a56ceda 100644
--- a/chromium/ui/events/gestures/gesture_provider_aura.cc
+++ b/chromium/ui/events/gestures/gesture_provider_aura.cc
@@ -8,6 +8,7 @@
#include "base/auto_reset.h"
#include "base/check.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
@@ -18,11 +19,11 @@ namespace ui {
namespace {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
constexpr bool kDoubleTapPlatformSupport = true;
#else
constexpr bool kDoubleTapPlatformSupport = false;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace
diff --git a/chromium/ui/events/gestures/gesture_recognizer_impl.cc b/chromium/ui/events/gestures/gesture_recognizer_impl.cc
index 7be72d3f10d..85912f5ad4e 100644
--- a/chromium/ui/events/gestures/gesture_recognizer_impl.cc
+++ b/chromium/ui/events/gestures/gesture_recognizer_impl.cc
@@ -11,8 +11,8 @@
#include "base/check.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
#include "base/time/time.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
diff --git a/chromium/ui/events/keyboard_hook_base.cc b/chromium/ui/events/keyboard_hook_base.cc
index 909b112f2c5..da356f91b59 100644
--- a/chromium/ui/events/keyboard_hook_base.cc
+++ b/chromium/ui/events/keyboard_hook_base.cc
@@ -6,8 +6,8 @@
#include <utility>
+#include "base/containers/contains.h"
#include "base/macros.h"
-#include "base/stl_util.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/dom/dom_code.h"
diff --git a/chromium/ui/events/keycodes/BUILD.gn b/chromium/ui/events/keycodes/BUILD.gn
index 4a2d0348cae..86bbf620ff0 100644
--- a/chromium/ui/events/keycodes/BUILD.gn
+++ b/chromium/ui/events/keycodes/BUILD.gn
@@ -21,6 +21,7 @@ source_set("xkb") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//ui/events:dom_keycode_converter",
]
}
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_xkb.cc b/chromium/ui/events/keycodes/keyboard_code_conversion_xkb.cc
index cd1135eae87..ee40330275f 100644
--- a/chromium/ui/events/keycodes/keyboard_code_conversion_xkb.cc
+++ b/chromium/ui/events/keycodes/keyboard_code_conversion_xkb.cc
@@ -5,6 +5,7 @@
#include "ui/events/keycodes/keyboard_code_conversion_xkb.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_code_conversion_xkb.h"
#include "ui/gfx/x/keysyms/keysyms.h"
@@ -202,7 +203,7 @@ DomKey NonPrintableXKeySymToDomKey(xkb_keysym_t keysym) {
return DomKey::CONTROL;
case XKB_KEY_Caps_Lock:
return DomKey::CAPS_LOCK;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
case XKB_KEY_Meta_L:
case XKB_KEY_Meta_R:
case XKB_KEY_Alt_L:
@@ -217,7 +218,7 @@ DomKey NonPrintableXKeySymToDomKey(xkb_keysym_t keysym) {
case XKB_KEY_Alt_L:
case XKB_KEY_Alt_R:
return DomKey::ALT;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
case XKB_KEY_Super_L:
case XKB_KEY_Super_R:
return DomKey::META;
diff --git a/chromium/ui/events/mojom/mojom_traits_unittest.cc b/chromium/ui/events/mojom/mojom_traits_unittest.cc
index a9e15a53b4a..d147efbd9d0 100644
--- a/chromium/ui/events/mojom/mojom_traits_unittest.cc
+++ b/chromium/ui/events/mojom/mojom_traits_unittest.cc
@@ -114,8 +114,8 @@ TEST(StructTraitsTest, KeyEvent) {
for (size_t i = 0; i < base::size(kTestData); i++) {
std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]);
std::unique_ptr<Event> output;
- ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(
- &expected_copy, &output));
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy,
+ output));
EXPECT_TRUE(output->IsKeyEvent());
const KeyEvent* output_key_event = output->AsKeyEvent();
@@ -155,8 +155,8 @@ TEST(StructTraitsTest, MouseEvent) {
for (size_t i = 0; i < base::size(kTestData); i++) {
std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]);
std::unique_ptr<Event> output;
- ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(
- &expected_copy, &output));
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy,
+ output));
ASSERT_TRUE(output->IsMouseEvent());
ExpectEventsEqual(kTestData[i], *output);
@@ -181,8 +181,8 @@ TEST(StructTraitsTest, MouseWheelEvent) {
for (size_t i = 0; i < base::size(kTestData); i++) {
std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]);
std::unique_ptr<Event> output;
- ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(
- &expected_copy, &output));
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy,
+ output));
ASSERT_EQ(ET_MOUSEWHEEL, output->type());
const MouseWheelEvent* output_event = output->AsMouseWheelEvent();
@@ -211,8 +211,8 @@ TEST(StructTraitsTest, FloatingPointLocations) {
for (Event* event : test_data) {
std::unique_ptr<Event> event_copy = Event::Clone(*event);
std::unique_ptr<Event> output;
- ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(&event_copy,
- &output));
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::Event>(event_copy, output));
EXPECT_EQ(location, output->AsLocatedEvent()->location_f());
EXPECT_EQ(root_location, output->AsLocatedEvent()->root_location_f());
}
@@ -267,8 +267,8 @@ TEST(StructTraitsTest, GestureEvent) {
for (size_t i = 0; i < base::size(kTestData); i++) {
std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]);
std::unique_ptr<Event> output;
- ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(
- &expected_copy, &output));
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy,
+ output));
ASSERT_TRUE(output->IsGestureEvent());
const GestureEvent* output_ptr_event = output->AsGestureEvent();
@@ -314,8 +314,8 @@ TEST(StructTraitsTest, ScrollEvent) {
for (size_t i = 0; i < base::size(kTestData); i++) {
std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]);
std::unique_ptr<Event> output;
- ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(
- &expected_copy, &output));
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy,
+ output));
EXPECT_TRUE(output->IsScrollEvent());
const ScrollEvent* output_ptr_event = output->AsScrollEvent();
@@ -348,7 +348,7 @@ TEST(StructTraitsTest, PointerDetails) {
PointerDetails output;
ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::PointerDetails>(
- &input, &output));
+ input, output));
EXPECT_EQ(input, output);
}
}
@@ -367,8 +367,8 @@ TEST(StructTraitsTest, TouchEvent) {
for (size_t i = 0; i < base::size(kTestData); i++) {
std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]);
std::unique_ptr<Event> output;
- ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(
- &expected_copy, &output));
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(expected_copy,
+ output));
ExpectEventsEqual(*expected_copy, *output);
}
@@ -381,7 +381,7 @@ TEST(StructTraitsTest, TouchEvent) {
std::unique_ptr<Event> expected = std::move(touch_event);
std::unique_ptr<Event> output;
ASSERT_TRUE(
- mojo::test::SerializeAndDeserialize<mojom::Event>(&expected, &output));
+ mojo::test::SerializeAndDeserialize<mojom::Event>(expected, output));
ExpectEventsEqual(*expected, *output);
}
@@ -392,7 +392,7 @@ TEST(StructTraitsTest, UnserializedTouchEventFields) {
std::unique_ptr<Event> expected = std::move(touch_event);
std::unique_ptr<Event> output;
ASSERT_TRUE(
- mojo::test::SerializeAndDeserialize<mojom::Event>(&expected, &output));
+ mojo::test::SerializeAndDeserialize<mojom::Event>(expected, output));
ExpectEventsEqual(*expected, *output);
EXPECT_NE(expected->AsTouchEvent()->unique_event_id(),
output->AsTouchEvent()->unique_event_id());
@@ -430,7 +430,7 @@ TEST(StructTraitsTest, DifferentKeyboardLayout) {
std::unique_ptr<Event> expected = std::move(key_event);
std::unique_ptr<Event> output;
ASSERT_TRUE(
- mojo::test::SerializeAndDeserialize<mojom::Event>(&expected, &output));
+ mojo::test::SerializeAndDeserialize<mojom::Event>(expected, output));
ExpectEventsEqual(*expected, *output);
}
diff --git a/chromium/ui/events/ozone/BUILD.gn b/chromium/ui/events/ozone/BUILD.gn
index 02e39676536..544447815e4 100644
--- a/chromium/ui/events/ozone/BUILD.gn
+++ b/chromium/ui/events/ozone/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/features.gni")
import("//build/config/ui.gni")
@@ -32,6 +33,7 @@ component("ozone") {
deps = [
"//base",
"//base/third_party/dynamic_annotations",
+ "//build:chromeos_buildflags",
"//ui/display",
"//ui/events",
"//ui/events/devices",
@@ -40,7 +42,7 @@ component("ozone") {
defines = [ "IS_EVENTS_OZONE_IMPL" ]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [
"chromeos/cursor_controller.cc",
"chromeos/cursor_controller.h",
@@ -71,7 +73,7 @@ source_set("unittests") {
"//ui/gfx/geometry",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [ "chromeos/cursor_controller_unittest.cc" ]
}
diff --git a/chromium/ui/events/ozone/device/device_manager_manual.cc b/chromium/ui/events/ozone/device/device_manager_manual.cc
index 5262df1b50c..422a44cb1b9 100644
--- a/chromium/ui/events/ozone/device/device_manager_manual.cc
+++ b/chromium/ui/events/ozone/device/device_manager_manual.cc
@@ -68,11 +68,8 @@ void DeviceManagerManual::StartWatching() {
base::PostTaskAndReplyWithResult(
blocking_task_runner_.get(), FROM_HERE,
base::BindOnce(
- static_cast<bool (base::FilePathWatcher::*)(
- const base::FilePath&, bool,
- const base::FilePathWatcher::Callback&)>(
- &base::FilePathWatcher::Watch),
- base::Unretained(watcher_.get()), base::FilePath(kDevInput), false,
+ &base::FilePathWatcher::Watch, base::Unretained(watcher_.get()),
+ base::FilePath(kDevInput), base::FilePathWatcher::Type::kNonRecursive,
base::BindRepeating(&DeviceManagerManual::OnWatcherEventOnUiSequence,
base::SequencedTaskRunnerHandle::Get(),
weak_ptr_factory_.GetWeakPtr())),
diff --git a/chromium/ui/events/ozone/evdev/BUILD.gn b/chromium/ui/events/ozone/evdev/BUILD.gn
index ce0d32fc928..74ce8cb434a 100644
--- a/chromium/ui/events/ozone/evdev/BUILD.gn
+++ b/chromium/ui/events/ozone/evdev/BUILD.gn
@@ -107,6 +107,7 @@ component("evdev") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//ui/display",
"//ui/events",
"//ui/events:dom_keycode_converter",
@@ -167,6 +168,7 @@ source_set("unittests") {
"event_device_test_util.h",
"event_factory_evdev_unittest.cc",
"gamepad_event_converter_evdev_unittest.cc",
+ "input_controller_evdev_unittest.cc",
"input_injector_evdev_unittest.cc",
"stylus_button_event_converter_evdev_unittest.cc",
"tablet_event_converter_evdev_unittest.cc",
@@ -185,6 +187,7 @@ source_set("unittests") {
":evdev",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//testing/gmock",
"//testing/gtest",
"//ui/events",
diff --git a/chromium/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc b/chromium/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc
index efb4c217bb5..66e8e2c5ce1 100644
--- a/chromium/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc
@@ -51,7 +51,7 @@ MouseButtonEventParams::MouseButtonEventParams(int device_id,
const gfx::PointF& location,
unsigned int button,
bool down,
- bool allow_remap,
+ MouseButtonMapType map_type,
const PointerDetails& details,
base::TimeTicks timestamp)
: device_id(device_id),
@@ -59,7 +59,7 @@ MouseButtonEventParams::MouseButtonEventParams(int device_id,
location(location),
button(button),
down(down),
- allow_remap(allow_remap),
+ map_type(map_type),
pointer_details(details),
timestamp(timestamp) {}
diff --git a/chromium/ui/events/ozone/evdev/device_event_dispatcher_evdev.h b/chromium/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
index de352cbf2ff..2f168e1323c 100644
--- a/chromium/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
+++ b/chromium/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
@@ -64,13 +64,20 @@ struct COMPONENT_EXPORT(EVDEV) MouseMoveEventParams {
base::TimeTicks timestamp;
};
+enum class COMPONENT_EXPORT(EVDEV) MouseButtonMapType : int {
+ kNone,
+ kMouse,
+ kPointingStick,
+ kMaxValue = kPointingStick,
+};
+
struct COMPONENT_EXPORT(EVDEV) MouseButtonEventParams {
MouseButtonEventParams(int device_id,
int flags,
const gfx::PointF& location,
unsigned int button,
bool down,
- bool allow_remap,
+ MouseButtonMapType map_type,
const PointerDetails& details,
base::TimeTicks timestamp);
MouseButtonEventParams(const MouseButtonEventParams& other);
@@ -82,7 +89,7 @@ struct COMPONENT_EXPORT(EVDEV) MouseButtonEventParams {
gfx::PointF location;
unsigned int button;
bool down;
- bool allow_remap;
+ MouseButtonMapType map_type;
PointerDetails pointer_details;
base::TimeTicks timestamp;
};
diff --git a/chromium/ui/events/ozone/evdev/event_converter_evdev_impl.cc b/chromium/ui/events/ozone/evdev/event_converter_evdev_impl.cc
index 3ed449cce5a..c54eebe573e 100644
--- a/chromium/ui/events/ozone/evdev/event_converter_evdev_impl.cc
+++ b/chromium/ui/events/ozone/evdev/event_converter_evdev_impl.cc
@@ -25,7 +25,7 @@ const int kKeyReleaseValue = 0;
const int kKeyRepeatValue = 2;
// Values for the EV_SW code.
-const int kSwitchStylusInserted = 15;
+const int kSwitchStylusInserted = SW_PEN_INSERTED;
} // namespace
@@ -243,7 +243,7 @@ void EventConverterEvdevImpl::OnButtonChange(int code,
dispatcher_->DispatchMouseButtonEvent(MouseButtonEventParams(
input_device_.id, EF_NONE, cursor_->GetLocation(), code, down,
- /* allow_remap */ true, PointerDetails(EventPointerType::kMouse),
+ MouseButtonMapType::kMouse, PointerDetails(EventPointerType::kMouse),
timestamp));
}
diff --git a/chromium/ui/events/ozone/evdev/event_device_info.cc b/chromium/ui/events/ozone/evdev/event_device_info.cc
index e0ffefc4fc4..797489b3f7f 100644
--- a/chromium/ui/events/ozone/evdev/event_device_info.cc
+++ b/chromium/ui/events/ozone/evdev/event_device_info.cc
@@ -47,7 +47,13 @@ constexpr struct {
{0x056e, 0x0159}, // Elecom Blue LED Mouse 203
{0x05e0, 0x1200}, // Zebra LS2208 barcode scanner
{0x0c45, 0x7403}, // RDing FootSwitch1F1
+ {0x1050, 0x0010}, // Yubico.com Yubikey
+ {0x1050, 0x0407}, // Yubico.com Yubikey 4 OTP+U2F+CCID
{0x1bcf, 0x08a0}, // Kensington Pro Fit Full-size
+ {0x256c, 0x006d}, // Huion HS64
+ {0x28bd, 0x0914}, // XP-Pen Star G640
+ {0x28bd, 0x091f}, // XP-Pen Artist 12 Pro
+ {0x28bd, 0x0928}, // XP-Pen Deco mini7W
};
constexpr struct {
diff --git a/chromium/ui/events/ozone/evdev/event_factory_evdev.cc b/chromium/ui/events/ozone/evdev/event_factory_evdev.cc
index bbaa5a775fe..519cadda1c1 100644
--- a/chromium/ui/events/ozone/evdev/event_factory_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/event_factory_evdev.cc
@@ -195,7 +195,9 @@ EventFactoryEvdev::EventFactoryEvdev(CursorDelegateEvdev* cursor,
base::BindRepeating(&EventFactoryEvdev::DispatchUiEvent,
base::Unretained(this))),
cursor_(cursor),
- input_controller_(&keyboard_, &button_map_),
+ input_controller_(&keyboard_,
+ &mouse_button_map_,
+ &pointing_stick_button_map_),
touch_id_generator_(0) {
DCHECK(device_manager_);
}
@@ -263,8 +265,11 @@ void EventFactoryEvdev::DispatchMouseButtonEvent(
// Mouse buttons can be remapped, touchpad taps & clicks cannot.
unsigned int button = params.button;
- if (params.allow_remap)
- button = button_map_.GetMappedButton(button);
+ if (params.map_type == MouseButtonMapType::kMouse) {
+ button = mouse_button_map_.GetMappedButton(button);
+ } else if (params.map_type == MouseButtonMapType::kPointingStick) {
+ button = pointing_stick_button_map_.GetMappedButton(button);
+ }
int modifier = MODIFIER_NONE;
switch (button) {
diff --git a/chromium/ui/events/ozone/evdev/event_factory_evdev.h b/chromium/ui/events/ozone/evdev/event_factory_evdev.h
index 6cffa902e4c..de4498f447e 100644
--- a/chromium/ui/events/ozone/evdev/event_factory_evdev.h
+++ b/chromium/ui/events/ozone/evdev/event_factory_evdev.h
@@ -132,7 +132,10 @@ class COMPONENT_EXPORT(EVDEV) EventFactoryEvdev : public DeviceEventObserver,
EventModifiers modifiers_;
// Mouse button map.
- MouseButtonMapEvdev button_map_;
+ MouseButtonMapEvdev mouse_button_map_;
+
+ // Pointing stick (a.k.a. TrackPoint) button map.
+ MouseButtonMapEvdev pointing_stick_button_map_;
// Keyboard state.
KeyboardEvdev keyboard_;
diff --git a/chromium/ui/events/ozone/evdev/input_controller_evdev.cc b/chromium/ui/events/ozone/evdev/input_controller_evdev.cc
index e96c2ea6767..a039ca65db5 100644
--- a/chromium/ui/events/ozone/evdev/input_controller_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/input_controller_evdev.cc
@@ -7,6 +7,7 @@
#include <linux/input.h>
#include <algorithm>
+#include <memory>
#include <utility>
#include "base/bind.h"
@@ -19,9 +20,13 @@
namespace ui {
-InputControllerEvdev::InputControllerEvdev(KeyboardEvdev* keyboard,
- MouseButtonMapEvdev* button_map)
- : keyboard_(keyboard), button_map_(button_map) {}
+InputControllerEvdev::InputControllerEvdev(
+ KeyboardEvdev* keyboard,
+ MouseButtonMapEvdev* mouse_button_map,
+ MouseButtonMapEvdev* pointing_stick_button_map)
+ : keyboard_(keyboard),
+ mouse_button_map_(mouse_button_map),
+ pointing_stick_button_map_(pointing_stick_button_map) {}
InputControllerEvdev::~InputControllerEvdev() {
}
@@ -167,8 +172,26 @@ void InputControllerEvdev::SetMouseScrollSensitivity(int value) {
ScheduleUpdateDeviceSettings();
}
+void InputControllerEvdev::SetPointingStickSensitivity(int value) {
+ input_device_settings_.pointing_stick_sensitivity = value;
+ ScheduleUpdateDeviceSettings();
+}
+
+void InputControllerEvdev::SetPointingStickAcceleration(bool enabled) {
+ if (is_mouse_acceleration_suspended()) {
+ stored_acceleration_settings_->pointing_stick = enabled;
+ return;
+ }
+ input_device_settings_.pointing_stick_acceleration_enabled = enabled;
+ ScheduleUpdateDeviceSettings();
+}
+
void InputControllerEvdev::SetPrimaryButtonRight(bool right) {
- button_map_->SetPrimaryButtonRight(right);
+ mouse_button_map_->SetPrimaryButtonRight(right);
+}
+
+void InputControllerEvdev::SetPointingStickPrimaryButtonRight(bool right) {
+ pointing_stick_button_map_->SetPrimaryButtonRight(right);
}
void InputControllerEvdev::SetMouseReverseScroll(bool enabled) {
@@ -177,8 +200,8 @@ void InputControllerEvdev::SetMouseReverseScroll(bool enabled) {
}
void InputControllerEvdev::SetMouseAcceleration(bool enabled) {
- if (mouse_acceleration_suspended_) {
- stored_mouse_acceleration_setting_ = enabled;
+ if (is_mouse_acceleration_suspended()) {
+ stored_acceleration_settings_->mouse = enabled;
return;
}
input_device_settings_.mouse_acceleration_enabled = enabled;
@@ -187,17 +210,22 @@ void InputControllerEvdev::SetMouseAcceleration(bool enabled) {
void InputControllerEvdev::SuspendMouseAcceleration() {
// multiple calls to suspend are currently not supported.
- DCHECK(!mouse_acceleration_suspended_);
- stored_mouse_acceleration_setting_ =
+ DCHECK(!is_mouse_acceleration_suspended());
+ stored_acceleration_settings_ =
+ std::make_unique<StoredAccelerationSettings>();
+ stored_acceleration_settings_->mouse =
input_device_settings_.mouse_acceleration_enabled;
- mouse_acceleration_suspended_ = true;
+ stored_acceleration_settings_->pointing_stick =
+ input_device_settings_.pointing_stick_acceleration_enabled;
input_device_settings_.mouse_acceleration_enabled = false;
+ input_device_settings_.pointing_stick_acceleration_enabled = false;
ScheduleUpdateDeviceSettings();
}
void InputControllerEvdev::EndMouseAccelerationSuspension() {
- mouse_acceleration_suspended_ = false;
- SetMouseAcceleration(stored_mouse_acceleration_setting_);
+ auto stored_settings = std::move(stored_acceleration_settings_);
+ SetMouseAcceleration(stored_settings->mouse);
+ SetPointingStickAcceleration(stored_settings->pointing_stick);
}
void InputControllerEvdev::SetMouseScrollAcceleration(bool enabled) {
diff --git a/chromium/ui/events/ozone/evdev/input_controller_evdev.h b/chromium/ui/events/ozone/evdev/input_controller_evdev.h
index 414f0fb5a6d..49ece6de5f4 100644
--- a/chromium/ui/events/ozone/evdev/input_controller_evdev.h
+++ b/chromium/ui/events/ozone/evdev/input_controller_evdev.h
@@ -24,7 +24,8 @@ class MouseButtonMapEvdev;
class COMPONENT_EXPORT(EVDEV) InputControllerEvdev : public InputController {
public:
InputControllerEvdev(KeyboardEvdev* keyboard,
- MouseButtonMapEvdev* button_map);
+ MouseButtonMapEvdev* mouse_button_map,
+ MouseButtonMapEvdev* pointing_stick_button_map);
~InputControllerEvdev() override;
// Initialize device factory. This would be in the constructor if it was
@@ -67,6 +68,9 @@ class COMPONENT_EXPORT(EVDEV) InputControllerEvdev : public InputController {
void SuspendMouseAcceleration() override;
void EndMouseAccelerationSuspension() override;
void SetMouseScrollAcceleration(bool enabled) override;
+ void SetPointingStickSensitivity(int value) override;
+ void SetPointingStickPrimaryButtonRight(bool right) override;
+ void SetPointingStickAcceleration(bool enabled) override;
void SetTouchpadAcceleration(bool enabled) override;
void SetTouchpadScrollAcceleration(bool enabled) override;
void SetTapToClickPaused(bool state) override;
@@ -87,6 +91,15 @@ class COMPONENT_EXPORT(EVDEV) InputControllerEvdev : public InputController {
void StopVibration(int id) override;
private:
+ FRIEND_TEST_ALL_PREFIXES(InputControllerEvdevTest, AccelerationSuspension);
+ FRIEND_TEST_ALL_PREFIXES(InputControllerEvdevTest,
+ AccelerationChangeDuringSuspension);
+
+ struct StoredAccelerationSettings {
+ bool mouse = false;
+ bool pointing_stick = false;
+ };
+
// Post task to update settings.
void ScheduleUpdateDeviceSettings();
@@ -96,15 +109,17 @@ class COMPONENT_EXPORT(EVDEV) InputControllerEvdev : public InputController {
// Send caps lock update to input_device_factory_.
void UpdateCapsLockLed();
+ // Indicates whether the mouse acceleration is turned off for PointerLock.
+ bool is_mouse_acceleration_suspended() {
+ return stored_acceleration_settings_.get() != nullptr;
+ }
+
// Configuration that needs to be passed on to InputDeviceFactory.
InputDeviceSettingsEvdev input_device_settings_;
- // Indicates when the mouse acceleration is turned off for PointerLock.
- bool mouse_acceleration_suspended_ = false;
- // Holds mouse acceleration setting while suspended.
- // Should only be considered a valid setting while
- // |mouse_acceleration_suspended| is true.
- bool stored_mouse_acceleration_setting_ = false;
+ // Holds acceleration settings while suspended. Should only be considered
+ // valid while |mouse_acceleration_suspended| is true.
+ std::unique_ptr<StoredAccelerationSettings> stored_acceleration_settings_;
// Task to update config from input_device_settings_ is pending.
bool settings_update_pending_ = false;
@@ -116,7 +131,10 @@ class COMPONENT_EXPORT(EVDEV) InputControllerEvdev : public InputController {
KeyboardEvdev* const keyboard_;
// Mouse button map.
- MouseButtonMapEvdev* const button_map_;
+ MouseButtonMapEvdev* const mouse_button_map_;
+
+ // Pointing stick button map.
+ MouseButtonMapEvdev* const pointing_stick_button_map_;
// Device presence.
bool has_mouse_ = false;
diff --git a/chromium/ui/events/ozone/evdev/input_controller_evdev_unittest.cc b/chromium/ui/events/ozone/evdev/input_controller_evdev_unittest.cc
new file mode 100644
index 00000000000..02e8fa374de
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/input_controller_evdev_unittest.cc
@@ -0,0 +1,60 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/ozone/evdev/input_controller_evdev.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+
+TEST(InputControllerEvdevTest, AccelerationSuspension) {
+ InputControllerEvdev controller(nullptr, nullptr, nullptr);
+ controller.SetMouseAcceleration(true);
+ controller.SetPointingStickAcceleration(true);
+
+ EXPECT_TRUE(controller.input_device_settings_.mouse_acceleration_enabled);
+ EXPECT_TRUE(
+ controller.input_device_settings_.pointing_stick_acceleration_enabled);
+
+ // Suspending should disable the acceleration temporarily.
+ controller.SuspendMouseAcceleration();
+ EXPECT_FALSE(controller.input_device_settings_.mouse_acceleration_enabled);
+ EXPECT_FALSE(
+ controller.input_device_settings_.pointing_stick_acceleration_enabled);
+
+ // Resuming should enable it again.
+ controller.EndMouseAccelerationSuspension();
+ EXPECT_TRUE(controller.input_device_settings_.mouse_acceleration_enabled);
+ EXPECT_TRUE(
+ controller.input_device_settings_.pointing_stick_acceleration_enabled);
+}
+
+TEST(InputControllerEvdevTest, AccelerationChangeDuringSuspension) {
+ InputControllerEvdev controller(nullptr, nullptr, nullptr);
+ controller.SetMouseAcceleration(true);
+ controller.SetPointingStickAcceleration(true);
+
+ // Suspending should disable the acceleration temporarily.
+ controller.SuspendMouseAcceleration();
+ EXPECT_FALSE(controller.input_device_settings_.mouse_acceleration_enabled);
+ EXPECT_FALSE(
+ controller.input_device_settings_.pointing_stick_acceleration_enabled);
+
+ // Settings changes while suspended should not take effect immediately...
+ controller.SetMouseAcceleration(true);
+ controller.SetPointingStickAcceleration(true);
+ EXPECT_FALSE(controller.input_device_settings_.mouse_acceleration_enabled);
+ EXPECT_FALSE(
+ controller.input_device_settings_.pointing_stick_acceleration_enabled);
+
+ // ...instead being applied when the suspension ends.
+ controller.SetMouseAcceleration(false);
+ controller.SetPointingStickAcceleration(false);
+ controller.EndMouseAccelerationSuspension();
+ EXPECT_FALSE(controller.input_device_settings_.mouse_acceleration_enabled);
+ EXPECT_FALSE(
+ controller.input_device_settings_.pointing_stick_acceleration_enabled);
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc b/chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc
index 7e06c24d8cc..c75707baf58 100644
--- a/chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -342,7 +342,16 @@ void InputDeviceFactoryEvdev::ApplyInputDeviceSettings() {
SetBoolPropertyForOneType(DT_MULTITOUCH, "Australian Scrolling",
input_device_settings_.natural_scroll_enabled);
+ SetIntPropertyForOneType(DT_MOUSE, "Pointer Sensitivity",
+ input_device_settings_.mouse_sensitivity);
+ SetBoolPropertyForOneType(DT_MOUSE, "Pointer Acceleration",
+ input_device_settings_.mouse_acceleration_enabled);
ApplyRelativePointingDeviceSettings(DT_MOUSE);
+ SetIntPropertyForOneType(DT_POINTING_STICK, "Pointer Sensitivity",
+ input_device_settings_.pointing_stick_sensitivity);
+ SetBoolPropertyForOneType(
+ DT_POINTING_STICK, "Pointer Acceleration",
+ input_device_settings_.pointing_stick_acceleration_enabled);
ApplyRelativePointingDeviceSettings(DT_POINTING_STICK);
SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Paused",
@@ -377,12 +386,8 @@ void InputDeviceFactoryEvdev::ApplyInputDeviceSettings() {
void InputDeviceFactoryEvdev::ApplyRelativePointingDeviceSettings(
EventDeviceType type) {
- SetIntPropertyForOneType(type, "Pointer Sensitivity",
- input_device_settings_.mouse_sensitivity);
SetIntPropertyForOneType(type, "Mouse Scroll Sensitivity",
input_device_settings_.mouse_scroll_sensitivity);
- SetBoolPropertyForOneType(type, "Pointer Acceleration",
- input_device_settings_.mouse_acceleration_enabled);
SetBoolPropertyForOneType(
type, "Mouse Scroll Acceleration",
input_device_settings_.mouse_scroll_acceleration_enabled);
diff --git a/chromium/ui/events/ozone/evdev/input_device_settings_evdev.h b/chromium/ui/events/ozone/evdev/input_device_settings_evdev.h
index 4e9c2b76d81..da64293342a 100644
--- a/chromium/ui/events/ozone/evdev/input_device_settings_evdev.h
+++ b/chromium/ui/events/ozone/evdev/input_device_settings_evdev.h
@@ -25,10 +25,11 @@ struct InputDeviceSettingsEvdev {
bool tap_dragging_enabled = false;
bool natural_scroll_enabled = false;
bool tap_to_click_paused = false;
- bool touch_event_logging_enabled = true;
+ bool touch_event_logging_enabled = false;
bool mouse_reverse_scroll_enabled = false;
bool mouse_acceleration_enabled = true;
bool mouse_scroll_acceleration_enabled = true;
+ bool pointing_stick_acceleration_enabled = true;
bool touchpad_acceleration_enabled = true;
bool touchpad_scroll_acceleration_enabled = true;
@@ -36,6 +37,7 @@ struct InputDeviceSettingsEvdev {
int touchpad_scroll_sensitivity = kDefaultSensitivity;
int mouse_sensitivity = kDefaultSensitivity;
int mouse_scroll_sensitivity = kDefaultSensitivity;
+ int pointing_stick_sensitivity = kDefaultSensitivity;
bool enable_devices = true; // If false, all input is disabled.
bool enable_internal_touchpad = true;
diff --git a/chromium/ui/events/ozone/evdev/input_injector_evdev.cc b/chromium/ui/events/ozone/evdev/input_injector_evdev.cc
index dc19ad4607e..a31d507669b 100644
--- a/chromium/ui/events/ozone/evdev/input_injector_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/input_injector_evdev.cc
@@ -50,7 +50,7 @@ void InputInjectorEvdev::InjectMouseButton(EventFlags button, bool down) {
dispatcher_->DispatchMouseButtonEvent(MouseButtonEventParams(
kDeviceIdForInjection, EF_NONE, cursor_->GetLocation(), code, down,
- false /* allow_remap */, PointerDetails(EventPointerType::kMouse),
+ MouseButtonMapType::kNone, PointerDetails(EventPointerType::kMouse),
EventTimeForNow()));
}
diff --git a/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_feedback.cc b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_feedback.cc
index b1d4e9ead74..441361643d2 100644
--- a/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_feedback.cc
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_feedback.cc
@@ -17,6 +17,7 @@
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h"
namespace ui {
@@ -226,13 +227,13 @@ void DumpTouchEventLog(
if (converter->HasTouchscreen()) {
std::string touch_evdev_log_filename = GenerateEventLogName(
out_dir, "evdev_input_events_", now, converter->id());
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
converter->DumpTouchEventLog(touch_evdev_log_filename.c_str());
#else
converter->DumpTouchEventLog(kInputEventsLogFile);
base::Move(base::FilePath(kInputEventsLogFile),
base::FilePath(touch_evdev_log_filename));
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
log_paths.push_back(base::FilePath(touch_evdev_log_filename));
}
}
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 6908d97b82f..f16a1e5277f 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
@@ -523,9 +523,14 @@ void GestureInterpreterLibevdevCros::DispatchMouseButton(unsigned int button,
if (!SetMouseButtonState(button, down))
return; // No change.
- bool allow_remap = is_mouse_ || is_pointing_stick_;
+ MouseButtonMapType map_type = MouseButtonMapType::kNone;
+ if (is_mouse_)
+ map_type = MouseButtonMapType::kMouse;
+ else if (is_pointing_stick_)
+ map_type = MouseButtonMapType::kPointingStick;
+
dispatcher_->DispatchMouseButtonEvent(MouseButtonEventParams(
- id_, EF_NONE, cursor_->GetLocation(), button, down, allow_remap,
+ id_, EF_NONE, cursor_->GetLocation(), button, down, map_type,
PointerDetails(EventPointerType::kMouse), StimeToTimeTicks(time)));
}
diff --git a/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.cc b/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.cc
index 9289a7a5a9d..ebb6e2e5631 100644
--- a/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.cc
+++ b/chromium/ui/events/ozone/evdev/tablet_event_converter_evdev.cc
@@ -196,7 +196,7 @@ void TabletEventConverterEvdev::DispatchMouseButton(const input_event& input) {
dispatcher_->DispatchMouseButtonEvent(MouseButtonEventParams(
input_device_.id, EF_NONE, cursor_->GetLocation(), button, down,
- false /* allow_remap */,
+ MouseButtonMapType::kNone,
PointerDetails(GetToolType(stylus_), /* pointer_id*/ 0,
/* radius_x */ 0.0f, /* radius_y */ 0.0f, pressure_,
/* twist */ 0.0f, tilt_x_, tilt_y_),
diff --git a/chromium/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc b/chromium/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc
index f5a321b437a..6fe5273585c 100644
--- a/chromium/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc
+++ b/chromium/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc
@@ -14,6 +14,7 @@
#include "base/strings/string_split.h"
#include "base/system/sys_info.h"
#include "base/time/time.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/ozone/evdev/event_device_info.h"
#include "ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.h"
#include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter.h"
@@ -62,7 +63,7 @@ std::string FetchNeuralPalmRadiusPolynomial(const EventDeviceInfo& devinfo,
}
// TODO(robsc): Remove this when comfortable.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// We should really only be running in chromeos anyway; We do a check here
// temporarily for hatch and reef. These numbers should live in config on
// chromeos side but for now during experiment are hard-coded here.
diff --git a/chromium/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc b/chromium/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc
index eb014db6a66..be6af2e6459 100644
--- a/chromium/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc
+++ b/chromium/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc
@@ -6,8 +6,10 @@
#include <linux/input.h>
-#include "base/system/sys_info.h"
+#include "base/test/gtest_util.h"
+#include "base/test/scoped_chromeos_version_info.h"
#include "base/test/scoped_feature_list.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/ozone/evdev/event_device_info.h"
#include "ui/events/ozone/evdev/event_device_test_util.h"
@@ -51,22 +53,28 @@ class PalmDetectionFilterFactoryTest : public testing::Test {
class PalmDetectionFilterFactoryDeathTest
: public PalmDetectionFilterFactoryTest {};
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(PalmDetectionFilterFactoryTest, RadiusesFromLSBRelease) {
- std::string lsb_release = "CHROMEOS_RELEASE_BOARD=hatch\n";
- base::SysInfo::SetChromeOSVersionInfoForTest(lsb_release, base::Time());
- EXPECT_EQ("0.1010944, 3.51837568", internal::FetchNeuralPalmRadiusPolynomial(
- kohaku_touchscreen_info_, ""));
-
- lsb_release = "CHROMEOS_RELEASE_BOARD=reef\n";
- base::SysInfo::SetChromeOSVersionInfoForTest(lsb_release, base::Time());
- EXPECT_EQ("0.17889799, 4.22584412", internal::FetchNeuralPalmRadiusPolynomial(
- kohaku_touchscreen_info_, ""));
-
- lsb_release = "CHROMEOS_RELEASE_BOARD=octopus\n";
- base::SysInfo::SetChromeOSVersionInfoForTest(lsb_release, base::Time());
- EXPECT_EQ("", internal::FetchNeuralPalmRadiusPolynomial(
- kohaku_touchscreen_info_, ""));
+ {
+ base::test::ScopedChromeOSVersionInfo version(
+ "CHROMEOS_RELEASE_BOARD=hatch\n", base::Time());
+ EXPECT_EQ("0.1010944, 3.51837568",
+ internal::FetchNeuralPalmRadiusPolynomial(
+ kohaku_touchscreen_info_, ""));
+ }
+ {
+ base::test::ScopedChromeOSVersionInfo version(
+ "CHROMEOS_RELEASE_BOARD=reef\n", base::Time());
+ EXPECT_EQ("0.17889799, 4.22584412",
+ internal::FetchNeuralPalmRadiusPolynomial(
+ kohaku_touchscreen_info_, ""));
+ }
+ {
+ base::test::ScopedChromeOSVersionInfo version(
+ "CHROMEOS_RELEASE_BOARD=octopus\n", base::Time());
+ EXPECT_EQ("", internal::FetchNeuralPalmRadiusPolynomial(
+ kohaku_touchscreen_info_, ""));
+ }
}
#endif
@@ -186,10 +194,10 @@ TEST_F(PalmDetectionFilterFactoryTest, ParseTest) {
}
TEST_F(PalmDetectionFilterFactoryDeathTest, BadParseRecovery) {
- // in debug, die. In non debug, expect {}
- EXPECT_DEBUG_DEATH(EXPECT_EQ(std::vector<float>(),
- internal::ParseRadiusPolynomial("cheese")),
- "Unable to parse.*cheese");
+ // In DCHECK builds, die. Otherwise, expect {}
+ EXPECT_DCHECK_DEATH_WITH(EXPECT_EQ(std::vector<float>(),
+ internal::ParseRadiusPolynomial("cheese")),
+ "Unable to parse.*cheese");
}
TEST_F(PalmDetectionFilterFactoryDeathTest, BadNeuralParamParse) {
@@ -200,9 +208,9 @@ TEST_F(PalmDetectionFilterFactoryDeathTest, BadNeuralParamParse) {
{"neural_palm_radius_polynomial", "1.0,chicken"},
})},
{ui::kEnableHeuristicPalmDetectionFilter});
- EXPECT_DEBUG_DEATH(CreatePalmDetectionFilter(nocturne_touchscreen_info_,
- &shared_palm_state_),
- "Unable to parse.*chicken");
+ EXPECT_DCHECK_DEATH_WITH(CreatePalmDetectionFilter(nocturne_touchscreen_info_,
+ &shared_palm_state_),
+ "Unable to parse.*chicken");
}
} // namespace ui
diff --git a/chromium/ui/events/ozone/layout/BUILD.gn b/chromium/ui/events/ozone/layout/BUILD.gn
index 905e742aaa5..987498b00cf 100644
--- a/chromium/ui/events/ozone/layout/BUILD.gn
+++ b/chromium/ui/events/ozone/layout/BUILD.gn
@@ -48,7 +48,10 @@ component("layout") {
"xkb/xkb_keyboard_layout_engine.h",
]
- deps += [ "//ui/events/keycodes:xkb" ]
+ deps += [
+ "//build:chromeos_buildflags",
+ "//ui/events/keycodes:xkb",
+ ]
}
}
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 fa06e4ce6d0..7f256e057af 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
@@ -21,6 +21,7 @@
#include "base/task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_key.h"
@@ -610,7 +611,7 @@ const PrintableSimpleEntry kSimpleMap[] = {
{0x0259, VKEY_OEM_3}, // schwa
};
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void LoadKeymap(const std::string& layout_name,
scoped_refptr<base::SingleThreadTaskRunner> reply_runner,
LoadKeymapCallback reply_callback) {
@@ -669,7 +670,7 @@ XkbKeyboardLayoutEngine::~XkbKeyboardLayoutEngine() {
}
bool XkbKeyboardLayoutEngine::CanSetCurrentLayout() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return true;
#else
return false;
@@ -678,7 +679,7 @@ bool XkbKeyboardLayoutEngine::CanSetCurrentLayout() const {
bool XkbKeyboardLayoutEngine::SetCurrentLayoutByName(
const std::string& layout_name) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
current_layout_name_ = layout_name;
for (const auto& entry : xkb_keymaps_) {
if (entry.layout_name == layout_name) {
@@ -696,7 +697,7 @@ bool XkbKeyboardLayoutEngine::SetCurrentLayoutByName(
std::move(reply_callback)));
#else
NOTIMPLEMENTED();
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
return true;
}
@@ -877,7 +878,7 @@ void XkbKeyboardLayoutEngine::SetKeymap(xkb_keymap* keymap) {
}
layout_index_ = 0;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Update num lock mask.
num_lock_mod_mask_ = num_lock_mask;
#endif
@@ -892,7 +893,7 @@ xkb_mod_mask_t XkbKeyboardLayoutEngine::EventFlagsToXkbFlags(
if (ui_flags & entry.ui_flag)
xkb_flags |= entry.xkb_flag;
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// In ChromeOS NumLock is always on.
xkb_flags |= num_lock_mod_mask_;
#endif
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 25e2e35d07d..f6a6e7b95fd 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
@@ -19,6 +19,7 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/task_runner.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/keycodes/scoped_xkb.h"
#include "ui/events/ozone/layout/keyboard_layout_engine.h"
#include "ui/events/ozone/layout/xkb/xkb_key_code_converter.h"
@@ -75,7 +76,7 @@ class COMPONENT_EXPORT(EVENTS_OZONE_LAYOUT) XkbKeyboardLayoutEngine
// kept.
base::flat_map<uint32_t, uint32_t> xkb_keysym_map_;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Flag mask for num lock, which is always considered enabled in ChromeOS.
xkb_mod_mask_t num_lock_mod_mask_ = 0;
#endif
diff --git a/chromium/ui/events/platform/x11/BUILD.gn b/chromium/ui/events/platform/x11/BUILD.gn
index 559a1fbe7db..46ccb75c71b 100644
--- a/chromium/ui/events/platform/x11/BUILD.gn
+++ b/chromium/ui/events/platform/x11/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ozone.gni")
import("//build/config/ui.gni")
@@ -33,11 +34,12 @@ component("x11") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//ui/base:features",
"//ui/events/keycodes:x11",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//ui/events/ozone" ]
}
diff --git a/chromium/ui/events/platform/x11/x11_event_source.cc b/chromium/ui/events/platform/x11/x11_event_source.cc
index e23b03b8c9d..63f5fefdaf8 100644
--- a/chromium/ui/events/platform/x11/x11_event_source.cc
+++ b/chromium/ui/events/platform/x11/x11_event_source.cc
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/events/platform/x11/x11_event_source.h"
-
#include <algorithm>
#include <memory>
#include <type_traits>
@@ -13,6 +11,7 @@
#include "base/memory/free_deleter.h"
#include "base/memory/ref_counted_memory.h"
#include "base/metrics/histogram_macros.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/devices/x11/device_data_manager_x11.h"
#include "ui/events/devices/x11/touch_factory_x11.h"
#include "ui/events/event_utils.h"
@@ -21,10 +20,11 @@
#include "ui/events/platform/x11/x11_hotplug_event_handler.h"
#include "ui/events/x/events_x_utils.h"
#include "ui/events/x/x11_event_translation.h"
-#include "ui/events/x/x11_window_event_manager.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/extension_manager.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
#include "ui/gfx/x/xkb.h"
#include "ui/gfx/x/xproto.h"
@@ -34,7 +34,7 @@
#include "ui/events/platform/x11/x11_event_watcher_fdwatch.h"
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/events/ozone/chromeos/cursor_controller.h"
#endif
@@ -47,9 +47,6 @@ namespace ui {
namespace {
void InitializeXkb(x11::Connection* connection) {
- if (!connection)
- return;
-
auto& xkb = connection->xkb();
// Ask the server not to send KeyRelease event when the user holds down a key.
@@ -122,10 +119,10 @@ using X11EventWatcherImpl = X11EventWatcherFdWatch;
X11EventSource::X11EventSource(x11::Connection* connection)
: watcher_(std::make_unique<X11EventWatcherImpl>(this)),
connection_(connection),
- dispatching_event_(nullptr),
- dummy_initialized_(false),
- distribution_(0, 999) {
+ dummy_initialized_(false) {
DCHECK(connection_);
+ connection_->AddEventObserver(this);
+
DeviceDataManagerX11::CreateInstance();
InitializeXkb(connection_);
@@ -135,6 +132,7 @@ X11EventSource::X11EventSource(x11::Connection* connection)
X11EventSource::~X11EventSource() {
if (dummy_initialized_)
connection_->DestroyWindow({dummy_window_});
+ connection_->RemoveEventObserver(this);
}
// static
@@ -152,7 +150,10 @@ X11EventSource* X11EventSource::GetInstance() {
void X11EventSource::DispatchXEvents() {
continue_stream_ = true;
- connection_->Dispatch(this);
+ do {
+ connection_->Flush();
+ connection_->ReadResponses();
+ } while (connection_->Dispatch() && continue_stream_);
}
x11::Time X11EventSource::GetCurrentServerTime() {
@@ -168,20 +169,12 @@ x11::Time X11EventSource::GetCurrentServerTime() {
.height = 1,
.override_redirect = x11::Bool32(true),
});
- dummy_atom_ = gfx::GetAtom("CHROMIUM_TIMESTAMP");
- dummy_window_events_ = std::make_unique<XScopedEventSelector>(
+ dummy_atom_ = x11::GetAtom("CHROMIUM_TIMESTAMP");
+ dummy_window_events_ = std::make_unique<x11::XScopedEventSelector>(
dummy_window_, x11::EventMask::PropertyChange);
dummy_initialized_ = true;
}
- // No need to measure Linux.X11.ServerRTT on every call.
- // base::TimeTicks::Now() itself has non-trivial overhead.
- bool measure_rtt = distribution_(generator_) == 0;
-
- base::TimeTicks start;
- if (measure_rtt)
- start = base::TimeTicks::Now();
-
// Make a no-op property change on |dummy_window_|.
std::vector<uint8_t> data{0};
connection_->ChangeProperty(x11::ChangePropertyRequest{
@@ -195,12 +188,6 @@ x11::Time X11EventSource::GetCurrentServerTime() {
// Observe the resulting PropertyNotify event to obtain the timestamp.
connection_->Sync();
- if (measure_rtt) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Linux.X11.ServerRTT",
- (base::TimeTicks::Now() - start).InMicroseconds(), 1,
- base::TimeDelta::FromMilliseconds(50).InMicroseconds(), 50);
- }
connection_->ReadResponses();
auto time = x11::Time::CurrentTime;
@@ -221,8 +208,8 @@ x11::Time X11EventSource::GetCurrentServerTime() {
}
x11::Time X11EventSource::GetTimestamp() {
- if (dispatching_event_) {
- auto timestamp = ExtractTimeFromXEvent(*dispatching_event_);
+ if (auto* dispatching_event = connection_->dispatching_event()) {
+ auto timestamp = ExtractTimeFromXEvent(*dispatching_event);
if (timestamp != x11::Time::CurrentTime)
return timestamp;
}
@@ -232,12 +219,10 @@ x11::Time X11EventSource::GetTimestamp() {
base::Optional<gfx::Point>
X11EventSource::GetRootCursorLocationFromCurrentEvent() const {
- if (!dispatching_event_)
+ auto* event = connection_->dispatching_event();
+ if (!event)
return base::nullopt;
- DCHECK(dispatching_event_);
- x11::Event* event = dispatching_event_;
-
auto* device = event->As<x11::Input::DeviceEvent>();
auto* crossing = event->As<x11::Input::CrossingEvent>();
auto* touch_factory = ui::TouchFactory::GetInstance();
@@ -258,140 +243,19 @@ X11EventSource::GetRootCursorLocationFromCurrentEvent() const {
}
if (is_valid_event)
- return ui::EventSystemLocationFromXEvent(*dispatching_event_);
+ return ui::EventSystemLocationFromXEvent(*event);
return base::nullopt;
}
-void X11EventSource::AddXEventDispatcher(XEventDispatcher* dispatcher) {
- dispatchers_xevent_.AddObserver(dispatcher);
- PlatformEventDispatcher* event_dispatcher =
- dispatcher->GetPlatformEventDispatcher();
- if (event_dispatcher)
- AddPlatformEventDispatcher(event_dispatcher);
-}
-
-void X11EventSource::RemoveXEventDispatcher(XEventDispatcher* dispatcher) {
- dispatchers_xevent_.RemoveObserver(dispatcher);
- PlatformEventDispatcher* event_dispatcher =
- dispatcher->GetPlatformEventDispatcher();
- if (event_dispatcher)
- RemovePlatformEventDispatcher(event_dispatcher);
-}
-
-void X11EventSource::AddXEventObserver(XEventObserver* observer) {
- CHECK(observer);
- observers_.AddObserver(observer);
-}
-
-void X11EventSource::RemoveXEventObserver(XEventObserver* observer) {
- CHECK(observer);
- observers_.RemoveObserver(observer);
-}
-
-std::unique_ptr<ScopedXEventDispatcher>
-X11EventSource::OverrideXEventDispatcher(XEventDispatcher* dispatcher) {
- CHECK(dispatcher);
- overridden_dispatcher_restored_ = false;
- return std::make_unique<ScopedXEventDispatcher>(&overridden_dispatcher_,
- dispatcher);
-}
-
-void X11EventSource::RestoreOverridenXEventDispatcher() {
- CHECK(overridden_dispatcher_);
- overridden_dispatcher_restored_ = true;
-}
-
-void X11EventSource::DispatchPlatformEvent(const PlatformEvent& event,
- x11::Event* xevent) {
- DCHECK(event);
-
- // First, tell the XEventDispatchers, which can have PlatformEventDispatcher,
- // an ui::Event is going to be sent next. It must make a promise to handle
- // next translated |event| sent by PlatformEventSource based on a XID in
- // |xevent| tested in CheckCanDispatchNextPlatformEvent(). This is needed
- // because it is not possible to access |event|'s associated NativeEvent* and
- // check if it is the event's target window (XID).
- for (XEventDispatcher& dispatcher : dispatchers_xevent_)
- dispatcher.CheckCanDispatchNextPlatformEvent(xevent);
-
- DispatchEvent(event);
-
- // Explicitly reset a promise to handle next translated event.
- for (XEventDispatcher& dispatcher : dispatchers_xevent_)
- dispatcher.PlatformEventDispatchFinished();
-}
-
-void X11EventSource::DispatchXEventToXEventDispatchers(x11::Event* xevent) {
- bool stop_dispatching = false;
-
- for (auto& observer : observers_)
- observer.WillProcessXEvent(xevent);
-
- if (overridden_dispatcher_) {
- stop_dispatching = overridden_dispatcher_->DispatchXEvent(xevent);
- }
-
- if (!stop_dispatching) {
- for (XEventDispatcher& dispatcher : dispatchers_xevent_) {
- if (dispatcher.DispatchXEvent(xevent))
- break;
- }
- }
-
- for (auto& observer : observers_)
- observer.DidProcessXEvent(xevent);
-
- // If an overridden dispatcher has been destroyed, then the event source
- // should halt dispatching the current stream of events, and wait until the
- // next message-loop iteration for dispatching events. This lets any nested
- // message-loop to unwind correctly and any new dispatchers to receive the
- // correct sequence of events.
- if (overridden_dispatcher_restored_)
- StopCurrentEventStream();
-
- overridden_dispatcher_restored_ = false;
-}
-
-void XEventDispatcher::CheckCanDispatchNextPlatformEvent(x11::Event* xev) {}
-
-void XEventDispatcher::PlatformEventDispatchFinished() {}
-
-PlatformEventDispatcher* XEventDispatcher::GetPlatformEventDispatcher() {
- return nullptr;
-}
-
-void X11EventSource::ProcessXEvent(x11::Event* xevent) {
- auto translated_event = ui::BuildEventFromXEvent(*xevent);
- // Ignore native platform-events only if they correspond to mouse events.
- // Allow other types of events to still be handled
- if (ui::PlatformEventSource::ShouldIgnoreNativePlatformEvents() &&
- translated_event && translated_event->IsMouseEvent()) {
- return;
- }
- if (translated_event && translated_event->type() != ET_UNKNOWN) {
-#if defined(OS_CHROMEOS)
- if (translated_event->IsLocatedEvent()) {
- ui::CursorController::GetInstance()->SetCursorLocation(
- translated_event->AsLocatedEvent()->location_f());
- }
-#endif
- DispatchPlatformEvent(translated_event.get(), xevent);
- } else {
- // Only if we can't translate XEvent into ui::Event, try to dispatch XEvent
- // directly to XEventDispatchers.
- DispatchXEventToXEventDispatchers(xevent);
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
// X11EventSource, protected
-void X11EventSource::PostDispatchEvent(x11::Event* x11_event) {
+void X11EventSource::OnEvent(const x11::Event& x11_event) {
bool should_update_device_list = false;
- if (x11_event->As<x11::Input::HierarchyEvent>()) {
+ if (x11_event.As<x11::Input::HierarchyEvent>()) {
should_update_device_list = true;
- } else if (auto* device = x11_event->As<x11::Input::DeviceChangedEvent>()) {
+ } else if (auto* device = x11_event.As<x11::Input::DeviceChangedEvent>()) {
if (device->reason == x11::Input::ChangeReason::DeviceChange) {
should_update_device_list = true;
} else if (device->reason == x11::Input::ChangeReason::SlaveSwitch) {
@@ -405,7 +269,7 @@ void X11EventSource::PostDispatchEvent(x11::Event* x11_event) {
hotplug_event_handler_->OnHotplugEvent();
}
- auto* crossing = x11_event->As<x11::CrossingEvent>();
+ auto* crossing = x11_event.As<x11::CrossingEvent>();
if (crossing && crossing->opcode == x11::CrossingEvent::EnterNotify &&
crossing->detail != x11::NotifyDetail::Inferior &&
crossing->mode != x11::NotifyMode::Ungrab) {
@@ -414,9 +278,26 @@ void X11EventSource::PostDispatchEvent(x11::Event* x11_event) {
DeviceDataManagerX11::kAllDevices);
}
- auto* mapping = x11_event->As<x11::MappingNotifyEvent>();
+ auto* mapping = x11_event.As<x11::MappingNotifyEvent>();
if (mapping && mapping->request == x11::Mapping::Pointer)
DeviceDataManagerX11::GetInstance()->UpdateButtonMap();
+
+ auto translated_event = ui::BuildEventFromXEvent(x11_event);
+ // Ignore native platform-events only if they correspond to mouse events.
+ // Allow other types of events to still be handled
+ if (ui::PlatformEventSource::ShouldIgnoreNativePlatformEvents() &&
+ translated_event && translated_event->IsMouseEvent()) {
+ return;
+ }
+ if (translated_event && translated_event->type() != ET_UNKNOWN) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ if (translated_event->IsLocatedEvent()) {
+ ui::CursorController::GetInstance()->SetCursorLocation(
+ translated_event->AsLocatedEvent()->location_f());
+ }
+#endif
+ DispatchEvent(translated_event.get());
+ }
}
void X11EventSource::StopCurrentEventStream() {
@@ -433,35 +314,6 @@ void X11EventSource::OnDispatcherListChanged() {
}
}
-bool X11EventSource::ShouldContinueStream() const {
- return continue_stream_;
-}
-
-void X11EventSource::DispatchXEvent(x11::Event* event) {
- // NB: The event should be reset to nullptr when this function
- // returns, not to its initial value, otherwise nested message loops
- // will incorrectly think that the current event being dispatched is
- // an old event. This means base::AutoReset should not be used.
- dispatching_event_ = event;
-
- ProcessXEvent(event);
- PostDispatchEvent(event);
-
- dispatching_event_ = nullptr;
-}
-
-// ScopedXEventDispatcher implementation
-ScopedXEventDispatcher::ScopedXEventDispatcher(
- XEventDispatcher** scoped_dispatcher,
- XEventDispatcher* new_dispatcher)
- : original_(*scoped_dispatcher),
- restore_(scoped_dispatcher, new_dispatcher) {}
-
-ScopedXEventDispatcher::~ScopedXEventDispatcher() {
- DCHECK(X11EventSource::HasInstance());
- X11EventSource::GetInstance()->RestoreOverridenXEventDispatcher();
-}
-
// static
#if defined(USE_X11)
std::unique_ptr<PlatformEventSource> PlatformEventSource::CreateDefault() {
diff --git a/chromium/ui/events/platform/x11/x11_event_source.h b/chromium/ui/events/platform/x11/x11_event_source.h
index b9fc9a0794f..1d12649d512 100644
--- a/chromium/ui/events/platform/x11/x11_event_source.h
+++ b/chromium/ui/events/platform/x11/x11_event_source.h
@@ -8,7 +8,6 @@
#include <stdint.h>
#include <memory>
-#include <random>
#include "base/auto_reset.h"
#include "base/callback.h"
@@ -23,56 +22,13 @@ namespace gfx {
class Point;
}
-namespace ui {
-
-class X11HotplugEventHandler;
+namespace x11 {
class XScopedEventSelector;
-class PlatformEventDispatcher;
-class ScopedXEventDispatcher;
-
-// The XEventDispatcher interface is used in two different ways: the first is
-// when classes want to receive x11::Event directly and second is to say if
-// classes, which also implement the PlatformEventDispatcher interface, are able
-// to process next translated from x11::Event to ui::Event events.
-class EVENTS_EXPORT XEventDispatcher {
- public:
- // Sends x11::Event to XEventDispatcher for handling. Returns true if the
- // x11::Event was dispatched, otherwise false. After the first
- // XEventDispatcher returns true x11::Event dispatching stops.
- virtual bool DispatchXEvent(x11::Event* xevent) = 0;
-
- // XEventDispatchers can be used to test if they are able to process next
- // translated event sent by a PlatformEventSource. If so, they must make a
- // promise internally to process next event sent by PlatformEventSource.
- virtual void CheckCanDispatchNextPlatformEvent(x11::Event* xev);
-
- // Tells that an event has been dispatched and an event handling promise must
- // be removed.
- virtual void PlatformEventDispatchFinished();
-
- // Returns PlatformEventDispatcher if this XEventDispatcher is associated with
- // a PlatformEventDispatcher as well. Used to explicitly add a
- // PlatformEventDispatcher during a call from an XEventDispatcher to
- // AddXEventDispatcher.
- virtual PlatformEventDispatcher* GetPlatformEventDispatcher();
-
- protected:
- virtual ~XEventDispatcher() = default;
-};
-
-// XEventObserver can be installed on a X11EventSource, and it
-// receives all events that are dispatched to the dispatchers.
-class EVENTS_EXPORT XEventObserver {
- public:
- // Called before the dispatchers receive the event.
- virtual void WillProcessXEvent(x11::Event* event) = 0;
+}
- // Called after the event has been dispatched.
- virtual void DidProcessXEvent(x11::Event* event) = 0;
+namespace ui {
- protected:
- virtual ~XEventObserver() = default;
-};
+class X11HotplugEventHandler;
// Responsible for notifying X11EventSource when new x11::Events are available
// to be processed/dispatched.
@@ -92,32 +48,12 @@ class X11EventWatcher {
DISALLOW_COPY_AND_ASSIGN(X11EventWatcher);
};
-// A temporary XEventDispatcher can be installed on a X11EventSource that
-// overrides all installed event dispatchers, and always gets a chance to
-// dispatch the event first, similar to what PlatformEventSource does with
-// ScopedEventDispatcher. When this object is destroyed, it removes the
-// override-dispatcher, and restores the previous override-dispatcher.
-class EVENTS_EXPORT ScopedXEventDispatcher {
- public:
- ScopedXEventDispatcher(XEventDispatcher** scoped_dispatcher,
- XEventDispatcher* new_dispatcher);
- ~ScopedXEventDispatcher();
-
- operator XEventDispatcher*() const { return original_; }
-
- private:
- XEventDispatcher* original_;
- base::AutoReset<XEventDispatcher*> restore_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedXEventDispatcher);
-};
-
// PlatformEventSource implementation for X11, both Ozone and non-Ozone.
// Receives X11 events from X11EventWatcher and sends them to registered
-// {Platform,X}EventDispatchers. Handles receiving, pre-process, translation
-// and post-processing of XEvents.
+// PlatformEventDispatchers/x11::EventObservers. Handles receiving, pre-process,
+// translation and post-processing of x11::Events.
class EVENTS_EXPORT X11EventSource : public PlatformEventSource,
- public x11::Connection::Delegate {
+ x11::EventObserver {
public:
explicit X11EventSource(x11::Connection* connection);
~X11EventSource() override;
@@ -144,75 +80,24 @@ class EVENTS_EXPORT X11EventSource : public PlatformEventSource,
// |last_seen_server_time_| with this value.
x11::Time GetCurrentServerTime();
- // Adds a x11::Event dispatcher to the x11::Event dispatcher list.
- // Also calls XEventDispatcher::GetPlatformEventDispatcher
- // to explicitly add this |dispatcher| to a list of PlatformEventDispatchers
- // in case if XEventDispatcher has a PlatformEventDispatcher. Thus,
- // there is no need to separately add self to the list of
- // PlatformEventDispatchers. This is needed because XEventDispatchers are
- // tested if they can receive an x11::Event based on a x11::Window target. If
- // so, the translated x11::Event into a PlatformEvent is sent to that
- // PlatformEventDispatcher.
- void AddXEventDispatcher(XEventDispatcher* dispatcher);
-
- // Removes an x11::Event dispatcher from the x11::Event dispatcher list.
- // Also explicitly removes an XEventDispatcher from a PlatformEventDispatcher
- // list if the XEventDispatcher has a PlatformEventDispatcher.
- void RemoveXEventDispatcher(XEventDispatcher* dispatcher);
-
- void AddXEventObserver(XEventObserver* observer);
- void RemoveXEventObserver(XEventObserver* observer);
-
- // Installs a XEventDispatcher that receives all the events. The dispatcher
- // can process the event, or request that the default dispatchers be invoked
- // by returning false from its DispatchXEvent() override. The returned
- // ScopedXEventDispatcher object is a handler for the overridden dispatcher.
- // When this handler is destroyed, it removes the overridden dispatcher, and
- // restores the previous override-dispatcher (or null if there wasn't any).
- std::unique_ptr<ScopedXEventDispatcher> OverrideXEventDispatcher(
- XEventDispatcher* dispatcher);
-
- void ProcessXEvent(x11::Event* xevent);
-
- // x11::Connection::Delegate:
- bool ShouldContinueStream() const override;
- void DispatchXEvent(x11::Event* event) override;
-
- protected:
- // Handles updates after event has been dispatched.
- void PostDispatchEvent(x11::Event* xevent);
-
private:
- friend class ScopedXEventDispatcher;
-
- // Tells XEventDispatchers, which can also have PlatformEventDispatchers, that
- // a translated event is going to be sent next, then dispatches the event and
- // notifies XEventDispatchers the event has been sent out and, most probably,
- // consumed.
- void DispatchPlatformEvent(const PlatformEvent& event, x11::Event* xevent);
-
- // Sends XEvent to registered XEventDispatchers.
- void DispatchXEventToXEventDispatchers(x11::Event* xevent);
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& event) override;
// PlatformEventSource:
void StopCurrentEventStream() override;
void OnDispatcherListChanged() override;
- void RestoreOverridenXEventDispatcher();
-
std::unique_ptr<X11EventWatcher> watcher_;
// The connection to the X11 server used to receive the events.
x11::Connection* connection_;
- // Event currently being dispatched.
- x11::Event* dispatching_event_;
-
// State necessary for UpdateLastSeenServerTime
bool dummy_initialized_;
x11::Window dummy_window_;
x11::Atom dummy_atom_;
- std::unique_ptr<XScopedEventSelector> dummy_window_events_;
+ std::unique_ptr<x11::XScopedEventSelector> dummy_window_events_;
// Keeps track of whether this source should continue to dispatch all the
// available events.
@@ -220,18 +105,6 @@ class EVENTS_EXPORT X11EventSource : public PlatformEventSource,
std::unique_ptr<X11HotplugEventHandler> hotplug_event_handler_;
- // Used to sample RTT measurements, with frequency 1/1000.
- std::default_random_engine generator_;
- std::uniform_int_distribution<int> distribution_;
-
- // Keep track of all XEventDispatcher to send XEvents directly to.
- base::ObserverList<XEventDispatcher>::Unchecked dispatchers_xevent_;
-
- base::ObserverList<XEventObserver>::Unchecked observers_;
-
- XEventDispatcher* overridden_dispatcher_ = nullptr;
- bool overridden_dispatcher_restored_ = false;
-
DISALLOW_COPY_AND_ASSIGN(X11EventSource);
};
diff --git a/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc b/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
index 6a4da33776a..d70361932b6 100644
--- a/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
+++ b/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
@@ -32,6 +32,7 @@
#include "ui/events/devices/touchscreen_device.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/extension_manager.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/x11_atom_cache.h"
namespace ui {
@@ -184,7 +185,7 @@ base::FilePath GetDevicePath(x11::Connection* connection,
// Input device has a property "Device Node" pointing to its dev input node,
// e.g. Device Node (250): "/dev/input/event8"
- x11::Atom device_node = gfx::GetAtom("Device Node");
+ x11::Atom device_node = x11::GetAtom("Device Node");
if (device_node == x11::Atom::None)
return base::FilePath();
@@ -408,13 +409,13 @@ void X11HotplugEventHandler::OnHotplugEvent() {
continue;
x11::Atom type = device.device_type;
- if (type == gfx::GetAtom("KEYBOARD"))
+ if (type == x11::GetAtom("KEYBOARD"))
device_types[id] = DEVICE_TYPE_KEYBOARD;
- else if (type == gfx::GetAtom("MOUSE"))
+ else if (type == x11::GetAtom("MOUSE"))
device_types[id] = DEVICE_TYPE_MOUSE;
- else if (type == gfx::GetAtom("TOUCHPAD"))
+ else if (type == x11::GetAtom("TOUCHPAD"))
device_types[id] = DEVICE_TYPE_TOUCHPAD;
- else if (type == gfx::GetAtom("TOUCHSCREEN"))
+ else if (type == x11::GetAtom("TOUCHSCREEN"))
device_types[id] = DEVICE_TYPE_TOUCHSCREEN;
}
@@ -432,8 +433,8 @@ void X11HotplugEventHandler::OnHotplugEvent() {
// X11 is not thread safe, so first get all the required state.
DisplayState display_state;
- display_state.mt_position_x = gfx::GetAtom("Abs MT Position X");
- display_state.mt_position_y = gfx::GetAtom("Abs MT Position Y");
+ display_state.mt_position_x = x11::GetAtom("Abs MT Position X");
+ display_state.mt_position_y = x11::GetAtom("Abs MT Position Y");
UiCallbacks callbacks;
callbacks.keyboard_callback = base::BindOnce(&OnKeyboardDevices);
diff --git a/chromium/ui/events/scoped_target_handler.cc b/chromium/ui/events/scoped_target_handler.cc
index f5ee457e077..1145c20f572 100644
--- a/chromium/ui/events/scoped_target_handler.cc
+++ b/chromium/ui/events/scoped_target_handler.cc
@@ -12,31 +12,23 @@ namespace ui {
ScopedTargetHandler::ScopedTargetHandler(EventTarget* target,
EventHandler* handler)
- : destroyed_flag_(nullptr), target_(target), new_handler_(handler) {
+ : target_(target), new_handler_(handler) {
original_handler_ = target_->SetTargetHandler(this);
}
ScopedTargetHandler::~ScopedTargetHandler() {
EventHandler* handler = target_->SetTargetHandler(original_handler_);
DCHECK_EQ(this, handler);
- if (destroyed_flag_)
- *destroyed_flag_ = true;
}
void ScopedTargetHandler::OnEvent(Event* event) {
if (original_handler_) {
- bool destroyed = false;
- bool* old_destroyed_flag = destroyed_flag_;
- destroyed_flag_ = &destroyed;
+ auto weak_this = weak_factory_.GetWeakPtr();
original_handler_->OnEvent(event);
- if (destroyed) {
- if (old_destroyed_flag)
- *old_destroyed_flag = true;
+ if (!weak_this)
return;
- }
- destroyed_flag_ = old_destroyed_flag;
}
// This check is needed due to nested event loops when starting DragDrop.
@@ -46,4 +38,8 @@ void ScopedTargetHandler::OnEvent(Event* event) {
new_handler_->OnEvent(event);
}
+base::StringPiece ScopedTargetHandler::GetLogContext() const {
+ return "ScopedTargetHandler";
+}
+
} // namespace ui
diff --git a/chromium/ui/events/scoped_target_handler.h b/chromium/ui/events/scoped_target_handler.h
index babc68c81b2..917fa4a6c83 100644
--- a/chromium/ui/events/scoped_target_handler.h
+++ b/chromium/ui/events/scoped_target_handler.h
@@ -6,6 +6,8 @@
#define UI_EVENTS_SCOPED_TARGET_HANDLER_H_
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
#include "ui/events/event_handler.h"
#include "ui/events/events_export.h"
@@ -25,11 +27,9 @@ class EVENTS_EXPORT ScopedTargetHandler : public EventHandler {
// EventHandler:
void OnEvent(Event* event) override;
+ base::StringPiece GetLogContext() const override;
private:
- // If non-null the destructor sets this to true. This is set while handling
- // an event and used to detect if |this| has been deleted.
- bool* destroyed_flag_;
// An EventTarget that has its target handler replaced with |this| for a life
// time of |this|.
@@ -41,6 +41,10 @@ class EVENTS_EXPORT ScopedTargetHandler : public EventHandler {
// A new handler that gets events in addition to the |original_handler_|.
EventHandler* new_handler_;
+ // Used to detect if handling an event has caused |this| to be deleted. Must
+ // be last.
+ base::WeakPtrFactory<ScopedTargetHandler> weak_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(ScopedTargetHandler);
};
diff --git a/chromium/ui/events/win/keyboard_hook_monitor.h b/chromium/ui/events/win/keyboard_hook_monitor.h
new file mode 100644
index 00000000000..2e9bc9dc504
--- /dev/null
+++ b/chromium/ui/events/win/keyboard_hook_monitor.h
@@ -0,0 +1,42 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_WIN_KEYBOARD_HOOK_MONITOR_H_
+#define UI_EVENTS_WIN_KEYBOARD_HOOK_MONITOR_H_
+
+#include "ui/events/events_export.h"
+
+namespace ui {
+
+class KeyboardHookObserver;
+
+// Provides a way to receive notifications when a low-level keyboard hook is
+// registered or unregistered and to query hook registration status.
+// Note that the KeyboardHookMonitor impl is bound to the thread which creates
+// it. In the browser process, this will be the UI thread. All methods should
+// be called on that thread and all observer methods will be run on that thread.
+class EVENTS_EXPORT KeyboardHookMonitor {
+ public:
+ static KeyboardHookMonitor* GetInstance();
+
+ // Add an observer which will receive keyboard hook event notifications. All
+ // |observer| methods are called on the thread which creates the
+ // KeyboardHookMonitor instance.
+ virtual void AddObserver(KeyboardHookObserver* observer) = 0;
+
+ // Remove an observer so that it will no longer receive keyboard hook event
+ // notifications.
+ virtual void RemoveObserver(KeyboardHookObserver* observer) = 0;
+
+ // Indicates whether a keyboard hook has been registered and is ready to
+ // receive keyboard events.
+ virtual bool IsActive() = 0;
+
+ protected:
+ virtual ~KeyboardHookMonitor() = default;
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_WIN_KEYBOARD_HOOK_MONITOR_H_
diff --git a/chromium/ui/events/win/keyboard_hook_monitor_impl.cc b/chromium/ui/events/win/keyboard_hook_monitor_impl.cc
new file mode 100644
index 00000000000..293b0d8256b
--- /dev/null
+++ b/chromium/ui/events/win/keyboard_hook_monitor_impl.cc
@@ -0,0 +1,60 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/win/keyboard_hook_monitor_impl.h"
+
+namespace ui {
+
+KeyboardHookMonitorImpl::KeyboardHookMonitorImpl() = default;
+
+KeyboardHookMonitorImpl::~KeyboardHookMonitorImpl() = default;
+
+void KeyboardHookMonitorImpl::AddObserver(KeyboardHookObserver* observer) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ observers_.AddObserver(observer);
+}
+
+void KeyboardHookMonitorImpl::RemoveObserver(KeyboardHookObserver* observer) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ observers_.RemoveObserver(observer);
+}
+
+bool KeyboardHookMonitorImpl::IsActive() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return is_hook_active_;
+}
+
+void KeyboardHookMonitorImpl::NotifyHookRegistered() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(!is_hook_active_);
+
+ is_hook_active_ = true;
+ for (auto& observer : observers_) {
+ observer.OnHookRegistered();
+ }
+}
+
+void KeyboardHookMonitorImpl::NotifyHookUnregistered() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(is_hook_active_);
+
+ is_hook_active_ = false;
+ for (auto& observer : observers_) {
+ observer.OnHookUnregistered();
+ }
+}
+
+// static
+KeyboardHookMonitor* KeyboardHookMonitor::GetInstance() {
+ return reinterpret_cast<KeyboardHookMonitor*>(
+ KeyboardHookMonitorImpl::GetInstance());
+}
+
+// static
+KeyboardHookMonitorImpl* KeyboardHookMonitorImpl::GetInstance() {
+ static base::NoDestructor<KeyboardHookMonitorImpl> instance;
+ return instance.get();
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/win/keyboard_hook_monitor_impl.h b/chromium/ui/events/win/keyboard_hook_monitor_impl.h
new file mode 100644
index 00000000000..53b87b56235
--- /dev/null
+++ b/chromium/ui/events/win/keyboard_hook_monitor_impl.h
@@ -0,0 +1,57 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_WIN_KEYBOARD_HOOK_MONITOR_IMPL_H_
+#define UI_EVENTS_WIN_KEYBOARD_HOOK_MONITOR_IMPL_H_
+
+#include "base/no_destructor.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/threading/thread_checker.h"
+#include "ui/events/events_export.h"
+#include "ui/events/win/keyboard_hook_monitor.h"
+#include "ui/events/win/keyboard_hook_observer.h"
+
+namespace ui {
+
+// An implementation of the KeyboardHookMonitor interface which is used to
+// notify listeners of KeyboardHook registration events and provide status.
+// Note that this class is bound to the thread which creates it. In the browser
+// process, this will be the UI thread. All methods should be called on that
+// thread and all observer methods will be run on that thread.
+class EVENTS_EXPORT KeyboardHookMonitorImpl : public KeyboardHookMonitor {
+ public:
+ static KeyboardHookMonitorImpl* GetInstance();
+
+ KeyboardHookMonitorImpl(const KeyboardHookMonitorImpl&) = delete;
+ KeyboardHookMonitorImpl& operator=(const KeyboardHookMonitorImpl&) = delete;
+ KeyboardHookMonitorImpl(KeyboardHookMonitorImpl&&) = delete;
+ KeyboardHookMonitorImpl& operator=(KeyboardHookMonitorImpl&&) = delete;
+ ~KeyboardHookMonitorImpl() override;
+
+ // KeyboardHookMonitor implementation.
+ void AddObserver(KeyboardHookObserver* observer) override;
+ void RemoveObserver(KeyboardHookObserver* observer) override;
+ bool IsActive() override;
+
+ // Send a notification to all listeners in |observers_| to indicate that a
+ // keyboard hook has been registered and is listening for key events.
+ void NotifyHookRegistered();
+
+ // Send a notification to all listeners in |observers_| to indicate that a
+ // keyboard hook has been removed and is no longer listening to key events.
+ void NotifyHookUnregistered();
+
+ private:
+ friend base::NoDestructor<KeyboardHookMonitorImpl>;
+ KeyboardHookMonitorImpl();
+
+ bool is_hook_active_ = false;
+ base::ObserverList<KeyboardHookObserver> observers_;
+
+ THREAD_CHECKER(thread_checker_);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_WIN_KEYBOARD_HOOK_MONITOR_IMPL_H_
diff --git a/chromium/ui/events/win/keyboard_hook_observer.h b/chromium/ui/events/win/keyboard_hook_observer.h
new file mode 100644
index 00000000000..abdc3224574
--- /dev/null
+++ b/chromium/ui/events/win/keyboard_hook_observer.h
@@ -0,0 +1,28 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_WIN_KEYBOARD_HOOK_OBSERVER_H_
+#define UI_EVENTS_WIN_KEYBOARD_HOOK_OBSERVER_H_
+
+#include "ui/events/events_export.h"
+
+namespace ui {
+
+// Used in conjunction with the KeyboardHookMonitor class to receive
+// notifications when a low-level keyboard hook is registered or unregistered.
+class EVENTS_EXPORT KeyboardHookObserver : public base::CheckedObserver {
+ public:
+ // Called when a low-level keyboard hook is registered.
+ virtual void OnHookRegistered() {}
+
+ // Called when a low-level keyboard hook is unregistered.
+ virtual void OnHookUnregistered() {}
+
+ protected:
+ ~KeyboardHookObserver() override = default;
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_WIN_KEYBOARD_HOOK_OBSERVER_H_
diff --git a/chromium/ui/events/win/modifier_keyboard_hook_win.cc b/chromium/ui/events/win/modifier_keyboard_hook_win.cc
index f1f5af47a7a..7277f39ae43 100644
--- a/chromium/ui/events/win/modifier_keyboard_hook_win.cc
+++ b/chromium/ui/events/win/modifier_keyboard_hook_win.cc
@@ -15,6 +15,7 @@
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/events/win/events_win_utils.h"
+#include "ui/events/win/keyboard_hook_monitor_impl.h"
#include "ui/gfx/native_widget_types.h"
namespace ui {
@@ -131,6 +132,8 @@ class ModifierKeyboardHookWinImpl : public KeyboardHookWinBase {
void ClearModifierStates();
+ KeyboardHookMonitorImpl* GetKeyboardHookMonitor();
+
static ModifierKeyboardHookWinImpl* instance_;
// Tracks the last non-located key down seen in order to determine if the
@@ -165,6 +168,8 @@ ModifierKeyboardHookWinImpl::~ModifierKeyboardHookWinImpl() {
DCHECK_EQ(instance_, this);
instance_ = nullptr;
+
+ KeyboardHookMonitorImpl::GetInstance()->NotifyHookUnregistered();
}
bool ModifierKeyboardHookWinImpl::Register() {
@@ -172,6 +177,8 @@ bool ModifierKeyboardHookWinImpl::Register() {
DCHECK(!instance_);
instance_ = this;
+ KeyboardHookMonitorImpl::GetInstance()->NotifyHookRegistered();
+
return KeyboardHookWinBase::Register(reinterpret_cast<HOOKPROC>(
&ModifierKeyboardHookWinImpl::ProcessKeyEvent));
}
@@ -320,6 +327,7 @@ std::unique_ptr<KeyboardHook> KeyboardHook::CreateModifierKeyboardHook(
return keyboard_hook;
}
+// static
std::unique_ptr<KeyboardHookWinBase>
KeyboardHookWinBase::CreateModifierKeyboardHookForTesting(
base::Optional<base::flat_set<DomCode>> dom_codes,
diff --git a/chromium/ui/events/x/BUILD.gn b/chromium/ui/events/x/BUILD.gn
index 2abef26141a..03ef2825fed 100644
--- a/chromium/ui/events/x/BUILD.gn
+++ b/chromium/ui/events/x/BUILD.gn
@@ -13,12 +13,11 @@ component("x") {
"events_x_export.h",
"events_x_utils.cc",
"events_x_utils.h",
- "x11_window_event_manager.cc",
- "x11_window_event_manager.h",
]
defines = [ "EVENTS_X_IMPLEMENTATION" ]
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//skia",
"//ui/base:features",
"//ui/display",
diff --git a/chromium/ui/events/x/events_x_utils.cc b/chromium/ui/events/x/events_x_utils.cc
index e9a4f6f0596..f5a5c1949fa 100644
--- a/chromium/ui/events/x/events_x_utils.cc
+++ b/chromium/ui/events/x/events_x_utils.cc
@@ -14,6 +14,7 @@
#include "base/memory/singleton.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/base_event_utils.h"
@@ -161,7 +162,7 @@ int GetEventFlagsFromXKeyEvent(const x11::Event& xev) {
DCHECK(key);
const auto state = static_cast<int>(key->state);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
const int ime_fabricated_flag = 0;
#else
// XIM fabricates key events for the character compositions by XK_Multi_key.
@@ -563,7 +564,7 @@ gfx::Point EventLocationFromXEvent(const x11::Event& xev) {
if (auto* xievent = xev.As<x11::Input::DeviceEvent>()) {
float x = Fp1616ToDouble(xievent->event_x);
float y = Fp1616ToDouble(xievent->event_y);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
switch (xievent->opcode) {
case x11::Input::DeviceEvent::TouchBegin:
case x11::Input::DeviceEvent::TouchUpdate:
@@ -574,7 +575,7 @@ gfx::Point EventLocationFromXEvent(const x11::Event& xev) {
default:
break;
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
return gfx::Point(static_cast<int>(x), static_cast<int>(y));
}
return gfx::Point();
diff --git a/chromium/ui/events/x/keyboard_hook_x11.cc b/chromium/ui/events/x/keyboard_hook_x11.cc
index dee0e1d0f63..60f0348c2a5 100644
--- a/chromium/ui/events/x/keyboard_hook_x11.cc
+++ b/chromium/ui/events/x/keyboard_hook_x11.cc
@@ -14,6 +14,7 @@
#include "ui/events/event.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/xproto.h"
namespace ui {
diff --git a/chromium/ui/file_manager/BUILD.gn b/chromium/ui/file_manager/BUILD.gn
index fb6ec9b6785..70f3a083ae2 100644
--- a/chromium/ui/file_manager/BUILD.gn
+++ b/chromium/ui/file_manager/BUILD.gn
@@ -5,7 +5,7 @@
import("//chrome/common/features.gni")
import("//third_party/closure_compiler/compile_js.gni")
import("//tools/grit/grit_rule.gni")
-import("//tools/grit/preprocess_grit.gni")
+import("//tools/grit/preprocess_if_expr.gni")
import("//ui/webui/resources/tools/generate_grd.gni")
grit("resources") {
@@ -58,48 +58,337 @@ group("unit_test_data") {
testonly = true
deps = [
"base/js:js_test_gen_html",
- "file_manager/background/js:js_test_gen_html",
- "file_manager/common/js:js_test_gen_html",
+ "file_manager/background/js:js_test_gen_html_modules",
"file_manager/common/js:js_test_gen_html_modules",
- "file_manager/foreground/elements:js_test_gen_html",
- "file_manager/foreground/js:js_test_gen_html",
- "file_manager/foreground/js/metadata:js_test_gen_html",
+ "file_manager/foreground/elements:js_test_gen_html_modules",
+ "file_manager/foreground/js:js_test_gen_html_modules",
"file_manager/foreground/js/metadata:js_test_gen_html_modules",
- "file_manager/foreground/js/ui:js_test_gen_html",
+ "file_manager/foreground/js/ui:js_test_gen_html_modules",
"gallery/js:js_test_gen_html",
"gallery/js/image_editor:js_test_gen_html",
- "image_loader:js_test_gen_html",
+ "gallery/js/image_editor:js_test_gen_html_modules",
"image_loader:js_test_gen_html_modules",
- "video_player/js:js_test_gen_html",
+ "video_player/js:js_test_gen_html_modules",
]
}
preprocess_folder = "$target_gen_dir/preprocessed"
-# Inline images and move files to the preprocessed folder to combine all
-# resources in the same folder to be able to generate the JS bundle.
+# Move files to the preprocessed folder to combine all resources in the same
+# folder for JS bundling with rollup.
# This is for files direct from the src/: input_folder="./".
-preprocess_grit("preprocess_static") {
+preprocess_if_expr("preprocess_static") {
in_folder = "./"
out_folder = preprocess_folder
- in_files = [ "audio_player/js/main.m.js" ]
+ in_files = [
+ "audio_player/js/main.m.js",
+ "audio_player/js/main_background.m.js",
+ "file_manager/background/js/main_background.m.js",
+ "file_manager/foreground/js/deferred_elements.m.js",
+ "file_manager/foreground/js/elements_importer.m.js",
+ "file_manager/foreground/js/main.m.js",
+ "image_loader/background.m.js",
+ "video_player/js/main.m.js",
+ "video_player/js/main_background.m.js",
+ ]
- deps = [ "//ui/file_manager/audio_player/js:main.m" ]
+ deps = [
+ "//ui/file_manager/audio_player/js:main.m",
+ "//ui/file_manager/audio_player/js:main_background.m",
+ "//ui/file_manager/file_manager/background/js:main_background.m",
+ "//ui/file_manager/file_manager/foreground/js:deferred_elements.m",
+ "//ui/file_manager/file_manager/foreground/js:main.m",
+ "//ui/file_manager/image_loader:background.m",
+ "//ui/file_manager/video_player/js:main.m",
+ "//ui/file_manager/video_player/js:main_background.m",
+ ]
}
# This is for files that are generated in "gen/": input_folder=target_gen_dir.
-preprocess_grit("preprocess_generated") {
+preprocess_if_expr("preprocess_generated") {
in_folder = target_gen_dir
out_folder = preprocess_folder
in_files = [
+ # Audio Player:
+ "audio_player/js/error_util.m.js",
+ "audio_player/js/test_util.m.js",
+ "audio_player/js/background.m.js",
+ "audio_player/js/audio_player.m.js",
+ "audio_player/js/metadata_worker.m.js",
+ "audio_player/elements/audio_player.m.js",
+ "audio_player/elements/track_info_panel.m.js",
+ "audio_player/elements/track_list.m.js",
+ "audio_player/elements/control_panel.m.js",
+ "audio_player/elements/repeat_button.m.js",
+
+ # Base:
"base/js/app_util.m.js",
- "base/js/volume_manager_types.m.js",
+ "base/js/error_counter.m.js",
+ "base/js/filtered_volume_manager.m.js",
"base/js/mediasession_types.m.js",
+ "base/js/volume_manager_types.m.js",
+
+ # Common:
+ "file_manager/common/js/async_util.m.js",
+ "file_manager/common/js/file_operation_common.m.js",
+ "file_manager/common/js/file_type.m.js",
+ "file_manager/common/js/files_app_entry_types.m.js",
+ "file_manager/common/js/importer_common.m.js",
+ "file_manager/common/js/lru_cache.m.js",
+ "file_manager/common/js/metrics.m.js",
+ "file_manager/common/js/metrics_base.m.js",
+ "file_manager/common/js/progress_center_common.m.js",
+ "file_manager/common/js/storage_adapter.m.js",
+ "file_manager/common/js/trash.m.js",
+ "file_manager/common/js/util.m.js",
+
+ # Externs:
+ "externs/background/background_base.m.js",
+ "externs/background/crostini.m.js",
+ "externs/background/drive_sync_handler.m.js",
+ "externs/background/duplicate_finder.m.js",
+ "externs/background/file_browser_background_full.m.js",
+ "externs/background/file_operation_manager.m.js",
+ "externs/background/import_history.m.js",
+ "externs/background/media_import_handler.m.js",
+ "externs/background/media_scanner.m.js",
+ "externs/background/progress_center.m.js",
+ "externs/background/task_queue.m.js",
+ "externs/background_window.m.js",
+ "externs/command_handler_deps.m.js",
+ "externs/directory_change_event.m.js",
+ "externs/drive_dialog_controller.m.js",
+ "externs/entry_location.m.js",
+ "externs/entries_changed_event.m.js",
+ "externs/exif_entry.m.js",
+ "externs/files_app_entry_interfaces.m.js",
+ "externs/metadata_worker_window.m.js",
+ "externs/progress_center_panel.m.js",
+ "externs/volume_info.m.js",
+ "externs/volume_info_list.m.js",
+ "externs/volume_manager.m.js",
+
+ # Files app Background:
+ "file_manager/background/js/app_window_wrapper.m.js",
+ "file_manager/background/js/app_windows.m.js",
+ "file_manager/background/js/background.m.js",
+ "file_manager/background/js/background_base.m.js",
+ "file_manager/background/js/crostini.m.js",
+ "file_manager/background/js/device_handler.m.js",
+ "file_manager/background/js/drive_sync_handler.m.js",
+ "file_manager/background/js/duplicate_finder.m.js",
+ "file_manager/background/js/entry_location_impl.m.js",
+ "file_manager/background/js/file_operation_handler.m.js",
+ "file_manager/background/js/file_operation_manager.m.js",
+ "file_manager/background/js/file_operation_util.m.js",
+ "file_manager/background/js/import_history.m.js",
+ "file_manager/background/js/launcher.m.js",
+ "file_manager/background/js/launcher_search.m.js",
+ "file_manager/background/js/media_import_handler.m.js",
+ "file_manager/background/js/media_scanner.m.js",
+ "file_manager/background/js/metadata_proxy.m.js",
+ "file_manager/background/js/metrics_start.m.js",
+ "file_manager/background/js/mount_metrics.m.js",
+ "file_manager/background/js/progress_center.m.js",
+ "file_manager/background/js/task_queue.m.js",
+ "file_manager/background/js/test_util.m.js",
+ "file_manager/background/js/test_util_base.m.js",
+ "file_manager/background/js/trash.m.js",
+ "file_manager/background/js/volume_info_impl.m.js",
+ "file_manager/background/js/volume_info_list_impl.m.js",
+ "file_manager/background/js/volume_manager_factory.m.js",
+ "file_manager/background/js/volume_manager_impl.m.js",
+ "file_manager/background/js/volume_manager_util.m.js",
+
+ # Files app Foreground:
+ "file_manager/foreground/js/actions_controller.m.js",
+ "file_manager/foreground/js/actions_model.m.js",
+ "file_manager/foreground/js/android_app_list_model.m.js",
+ "file_manager/foreground/js/app_state_controller.m.js",
+ "file_manager/foreground/js/column_visibility_controller.m.js",
+ "file_manager/foreground/js/constants.m.js",
+ "file_manager/foreground/js/crossover_search_utils.m.js",
+ "file_manager/foreground/js/crostini_controller.m.js",
+ "file_manager/foreground/js/dialog_action_controller.m.js",
+ "file_manager/foreground/js/dialog_type.m.js",
+ "file_manager/foreground/js/directory_contents.m.js",
+ "file_manager/foreground/js/directory_model.m.js",
+ "file_manager/foreground/js/directory_tree_naming_controller.m.js",
+ "file_manager/foreground/js/drive_dialog_controller.m.js",
+ "file_manager/foreground/js/drop_effect_and_label.m.js",
+ "file_manager/foreground/js/empty_folder_controller.m.js",
+ "file_manager/foreground/js/file_list_model.m.js",
+ "file_manager/foreground/js/file_manager.m.js",
+ "file_manager/foreground/js/file_manager_commands.m.js",
+ "file_manager/foreground/js/file_selection.m.js",
+ "file_manager/foreground/js/file_tasks.m.js",
+ "file_manager/foreground/js/file_transfer_controller.m.js",
+ "file_manager/foreground/js/file_type_filters_controller.m.js",
+ "file_manager/foreground/js/file_watcher.m.js",
+ "file_manager/foreground/js/folder_shortcuts_data_model.m.js",
+ "file_manager/foreground/js/gear_menu_controller.m.js",
+ "file_manager/foreground/js/holding_space_util.m.js",
+ "file_manager/foreground/js/import_controller.m.js",
+ "file_manager/foreground/js/last_modified_controller.m.js",
+ "file_manager/foreground/js/launch_param.m.js",
+ "file_manager/foreground/js/list_thumbnail_loader.m.js",
+ "file_manager/foreground/js/main_window_component.m.js",
+ "file_manager/foreground/js/metadata_box_controller.m.js",
+ "file_manager/foreground/js/metadata_update_controller.m.js",
+ "file_manager/foreground/js/metrics_start.m.js",
+ "file_manager/foreground/js/naming_controller.m.js",
+ "file_manager/foreground/js/navigation_list_model.m.js",
+ "file_manager/foreground/js/navigation_uma.m.js",
+ "file_manager/foreground/js/path_component.m.js",
+ "file_manager/foreground/js/providers_model.m.js",
+ "file_manager/foreground/js/quick_view_controller.m.js",
+ "file_manager/foreground/js/quick_view_model.m.js",
+ "file_manager/foreground/js/quick_view_uma.m.js",
+ "file_manager/foreground/js/scan_controller.m.js",
+ "file_manager/foreground/js/search_controller.m.js",
+ "file_manager/foreground/js/selection_menu_controller.m.js",
+ "file_manager/foreground/js/sort_menu_controller.m.js",
+ "file_manager/foreground/js/spinner_controller.m.js",
+ "file_manager/foreground/js/task_controller.m.js",
+ "file_manager/foreground/js/task_history.m.js",
+ "file_manager/foreground/js/thumbnail_loader.m.js",
+ "file_manager/foreground/js/toolbar_controller.m.js",
+ "file_manager/foreground/js/web_store_utils.m.js",
+ "file_manager/foreground/js/webui_command_extender.m.js",
+
+ # Files app Elements:
+ "file_manager/foreground/elements/icons.m.js",
+ "file_manager/foreground/elements/files_format_dialog.m.js",
+ "file_manager/foreground/elements/files_icon_button.m.js",
+ "file_manager/foreground/elements/files_message.m.js",
+ "file_manager/foreground/elements/files_metadata_box.m.js",
+ "file_manager/foreground/elements/files_metadata_entry.m.js",
+ "file_manager/foreground/elements/files_password_dialog.m.js",
+ "file_manager/foreground/elements/files_quick_view.m.js",
+ "file_manager/foreground/elements/files_ripple.m.js",
+ "file_manager/foreground/elements/files_safe_media.m.js",
+ "file_manager/foreground/elements/files_spinner.m.js",
+ "file_manager/foreground/elements/files_toast.m.js",
+ "file_manager/foreground/elements/files_toggle_ripple.m.js",
+ "file_manager/foreground/elements/files_tooltip.m.js",
+ "file_manager/foreground/elements/xf_button.m.js",
+ "file_manager/foreground/elements/xf_circular_progress.m.js",
+ "file_manager/foreground/elements/xf_display_panel.m.js",
+ "file_manager/foreground/elements/xf_panel_item.m.js",
+
+ # Files app UI:
+ "file_manager/foreground/js/ui/a11y_announce.m.js",
+ "file_manager/foreground/js/ui/action_model_ui.m.js",
+ "file_manager/foreground/js/ui/actions_submenu.m.js",
+ "file_manager/foreground/js/ui/autocomplete_list.m.js",
+ "file_manager/foreground/js/ui/banners.m.js",
+ "file_manager/foreground/js/ui/breadcrumb.m.js",
+ "file_manager/foreground/js/ui/combobutton.m.js",
+ "file_manager/foreground/js/ui/commandbutton.m.js",
+ "file_manager/foreground/js/ui/default_task_dialog.m.js",
+ "file_manager/foreground/js/ui/dialog_footer.m.js",
+ "file_manager/foreground/js/ui/directory_tree.m.js",
+ "file_manager/foreground/js/ui/drag_selector.m.js",
+ "file_manager/foreground/js/ui/import_crostini_image_dialog.m.js",
+ "file_manager/foreground/js/ui/install_linux_package_dialog.m.js",
+ "file_manager/foreground/js/ui/empty_folder.m.js",
+ "file_manager/foreground/js/ui/file_grid.m.js",
+ "file_manager/foreground/js/ui/file_list_selection_model.m.js",
+ "file_manager/foreground/js/ui/file_manager_dialog_base.m.js",
+ "file_manager/foreground/js/ui/file_manager_ui.m.js",
+ "file_manager/foreground/js/ui/file_metadata_formatter.m.js",
+ "file_manager/foreground/js/ui/file_table.m.js",
+ "file_manager/foreground/js/ui/file_table_list.m.js",
+ "file_manager/foreground/js/ui/file_tap_handler.m.js",
+ "file_manager/foreground/js/ui/files_alert_dialog.m.js",
+ "file_manager/foreground/js/ui/files_confirm_dialog.m.js",
+ "file_manager/foreground/js/ui/files_menu.m.js",
+ "file_manager/foreground/js/ui/gear_menu.m.js",
+ "file_manager/foreground/js/ui/list_container.m.js",
+ "file_manager/foreground/js/ui/location_line.m.js",
+ "file_manager/foreground/js/ui/multi_menu.m.js",
+ "file_manager/foreground/js/ui/multi_menu_button.m.js",
+ "file_manager/foreground/js/ui/progress_center_panel.m.js",
+ "file_manager/foreground/js/ui/providers_menu.m.js",
+ "file_manager/foreground/js/ui/search_box.m.js",
+ "file_manager/foreground/js/ui/table/table.m.js",
+ "file_manager/foreground/js/ui/table/table_column.m.js",
+ "file_manager/foreground/js/ui/table/table_column_model.m.js",
+ "file_manager/foreground/js/ui/table/table_header.m.js",
+ "file_manager/foreground/js/ui/table/table_list.m.js",
+ "file_manager/foreground/js/ui/table/table_splitter.m.js",
+
+ # CWS:
+ "file_manager/cws_widget/app_installer.m.js",
+ "file_manager/cws_widget/cws_webview_client.m.js",
+ "file_manager/cws_widget/cws_widget_container.m.js",
+ "file_manager/cws_widget/cws_widget_container_error_dialog.m.js",
+ "file_manager/cws_widget/cws_widget_container_platform_delegate.m.js",
+
+ # Image Loader:
+ "image_loader/cache.m.js",
+ "image_loader/image_loader.m.js",
+ "image_loader/image_loader_client.m.js",
+ "image_loader/image_loader_util.m.js",
+ "image_loader/image_request_task.m.js",
+ "image_loader/load_image_request.m.js",
+ "image_loader/piex_loader.m.js",
+ "image_loader/scheduler.m.js",
+
+ # Metadata:
+ "file_manager/foreground/js/metadata/byte_reader.m.js",
+ "file_manager/foreground/js/metadata/content_metadata_provider.m.js",
+ "file_manager/foreground/js/metadata/exif_constants.m.js",
+ "file_manager/foreground/js/metadata/exif_parser.m.js",
+ "file_manager/foreground/js/metadata/external_metadata_provider.m.js",
+ "file_manager/foreground/js/metadata/file_system_metadata_provider.m.js",
+ "file_manager/foreground/js/metadata/function_parallel.m.js",
+ "file_manager/foreground/js/metadata/function_sequence.m.js",
+ "file_manager/foreground/js/metadata/id3_parser.m.js",
+ "file_manager/foreground/js/metadata/image_orientation.m.js",
+ "file_manager/foreground/js/metadata/image_parsers.m.js",
+ "file_manager/foreground/js/metadata/metadata_cache_item.m.js",
+ "file_manager/foreground/js/metadata/metadata_cache_set.m.js",
+ "file_manager/foreground/js/metadata/metadata_dispatcher.m.js",
+ "file_manager/foreground/js/metadata/metadata_item.m.js",
+ "file_manager/foreground/js/metadata/metadata_model.m.js",
+ "file_manager/foreground/js/metadata/metadata_parser.m.js",
+ "file_manager/foreground/js/metadata/metadata_provider.m.js",
+ "file_manager/foreground/js/metadata/metadata_request.m.js",
+ "file_manager/foreground/js/metadata/mpeg_parser.m.js",
+ "file_manager/foreground/js/metadata/multi_metadata_provider.m.js",
+ "file_manager/foreground/js/metadata/thumbnail_model.m.js",
+
+ # Video Player:
+ "video_player/js/error_util.m.js",
+ "video_player/js/test_util.m.js",
+ "video_player/js/background.m.js",
+ "video_player/js/video_player.m.js",
+ "video_player/js/video_player_native_controls.m.js",
+ "video_player/js/video_player_metrics.m.js",
]
- deps = [ "//ui/file_manager/base/js:modulize" ]
+ deps = [
+ "//ui/file_manager/audio_player/elements:elements",
+ "//ui/file_manager/audio_player/js:modulize",
+ "//ui/file_manager/base/js:modulize",
+ "//ui/file_manager/externs:modulize",
+ "//ui/file_manager/externs/background:modulize",
+ "//ui/file_manager/file_manager:gen_main_html",
+ "//ui/file_manager/file_manager/background/js:modulize",
+ "//ui/file_manager/file_manager/common/js:modulize",
+ "//ui/file_manager/file_manager/cws_widget:modulize",
+ "//ui/file_manager/file_manager/foreground/elements:elements",
+ "//ui/file_manager/file_manager/foreground/elements:modulize",
+ "//ui/file_manager/file_manager/foreground/js:modulize",
+ "//ui/file_manager/file_manager/foreground/js/metadata:modulize",
+ "//ui/file_manager/file_manager/foreground/js/ui:modulize",
+ "//ui/file_manager/file_manager/foreground/js/ui/table:modulize",
+ "//ui/file_manager/image_loader:modulize",
+ "//ui/file_manager/video_player/js:modulize",
+ ]
}
grd_prefix = "file_manager_gen"
@@ -108,31 +397,73 @@ generated_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
generate_grd("build_grd") {
out_grd = generated_grd
- input_files_base_dir =
- rebase_path("$target_gen_dir/preprocessed", root_gen_dir)
- input_files = [ "../audio_player/js/main.m.rollup.js" ]
+ input_files_base_dir = rebase_path(target_gen_dir, root_build_dir)
+ input_files = [
+ "audio_player/js/main.m.rollup.js",
+ "audio_player/js/main_background.m.rollup.js",
+ "audio_player/js/metadata_worker.m.rollup.js",
+
+ "image_loader/background.m.rollup.js",
- resource_path_rewrites =
- [ "../audio_player/js/main.m.rollup.js|audio_player/js/main.m.js" ]
+ # Fix broken images:
+ "file_manager/images/files/ui/arrow_right.svg",
+ "file_manager/images/files/ui/menu_ng.svg",
- deps = [ "//ui/file_manager/audio_player/js:build" ]
+ "file_manager/background/js/main_background.m.rollup.js",
+ "file_manager/foreground/elements/files_icon_button.m.js",
+ "file_manager/foreground/elements/files_ripple.m.js",
+ "file_manager/foreground/elements/files_toggle_ripple.m.js",
+ "file_manager/foreground/js/deferred_elements.m.rollup.js",
+ "file_manager/foreground/js/main.m.rollup.js",
+ "file_manager/foreground/js/metadata_dispatcher.m.rollup.js",
+ "file_manager/foreground/js/shared.m.rollup.js",
+ "file_manager/main_modules.html",
+
+ "video_player/js/main.m.rollup.js",
+ "video_player/js/main_background.m.rollup.js",
+ ]
+
+ resource_path_rewrites = [
+ "audio_player/js/main.m.rollup.js|audio_player/js/main.m.js",
+ "audio_player/js/main_background.m.rollup.js|audio_player/js/main_background.m.js",
+ "audio_player/js/metadata_worker.m.rollup.js|audio_player/js/metadata_worker.m.js",
+ "image_loader/background.m.rollup.js|image_loader/background.m.js",
+ "file_manager/background/js/main_background.m.rollup.js|file_manager/background/js/main_background.m.js",
+ "file_manager/foreground/js/deferred_elements.m.rollup.js|file_manager/foreground/js/deferred_elements.m.js",
+ "file_manager/foreground/js/main.m.rollup.js|file_manager/foreground/js/main.m.js",
+ "file_manager/foreground/js/metadata_dispatcher.m.rollup.js|file_manager/foreground/js/metadata_dispatcher.m.js",
+ "video_player/js/main.m.rollup.js|video_player/js/main.m.js",
+ "video_player/js/main_background.m.rollup.js|video_player/js/main_background.m.js",
+ ]
+
+ grdp_files = [
+ "$target_gen_dir/audio_player/static_resources.grdp",
+ "$target_gen_dir/file_manager/static_resources.grdp",
+ ]
+
+ deps = [
+ "audio_player:build_static_grdp",
+ "file_manager:build_static_grdp",
+ "//ui/file_manager/audio_player/js:build",
+ "//ui/file_manager/audio_player/js:build_background",
+ "//ui/file_manager/audio_player/js:build_worker",
+ "//ui/file_manager/file_manager:fix_broken_images",
+ "//ui/file_manager/file_manager/background/js:build",
+ "//ui/file_manager/file_manager/foreground/elements:elements",
+ "//ui/file_manager/file_manager/foreground/js:build",
+ "//ui/file_manager/file_manager/foreground/js:build_worker",
+ "//ui/file_manager/image_loader:build",
+ "//ui/file_manager/video_player/js:build",
+ "//ui/file_manager/video_player/js:build_background",
+ ]
}
# Resources for the JS modules.
grit("file_manager_gen_resources") {
- grit_flags = [
- "-E",
- "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
- "-E",
- "root_src_dir=" + rebase_path(root_gen_dir, root_build_dir),
- ]
-
defines = chrome_grit_defines
# These arguments are needed since the grd is generated at build time.
enable_input_discovery_for_gn_analyze = false
- defines +=
- [ "SHARED_INTERMEDIATE_DIR=" + rebase_path(root_gen_dir, root_build_dir) ]
source = generated_grd
deps = [ ":build_grd" ]
@@ -143,5 +474,5 @@ grit("file_manager_gen_resources") {
"grit/file_manager_gen_resources_map.h",
"file_manager_gen_resources.pak",
]
- output_dir = "$root_gen_dir/ui/file_manager"
+ output_dir = target_gen_dir
}
diff --git a/chromium/ui/file_manager/audio_player/BUILD.gn b/chromium/ui/file_manager/audio_player/BUILD.gn
new file mode 100644
index 00000000000..7f7a2ad0dca
--- /dev/null
+++ b/chromium/ui/file_manager/audio_player/BUILD.gn
@@ -0,0 +1,50 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//ui/webui/resources/tools/generate_grd.gni")
+
+generated_static_grdp = "$target_gen_dir/static_resources.grdp"
+
+generate_grd("build_static_grdp") {
+ out_grd = generated_static_grdp
+ grd_prefix = "audio_player"
+
+ resource_path_prefix = "audio_player"
+
+ input_files_base_dir = rebase_path(".", "//")
+
+ input_files = [
+ # Images:
+ "assets/100/player_button_next.png",
+ "assets/100/player_button_pause.png",
+ "assets/100/player_button_playlist.png",
+ "assets/100/player_button_play.png",
+ "assets/100/player_button_previous.png",
+ "assets/100/player_button_repeat_one.png",
+ "assets/100/player_button_repeat.png",
+ "assets/100/player_button_shuffle.png",
+ "assets/100/player_button_volume_muted.png",
+ "assets/100/player_button_volume.png",
+ "assets/100/player_cover_close.png",
+ "assets/100/player_cover_open.png",
+ "assets/100/player_no_artwork.png",
+ "assets/100/playlist_now_playing.png",
+ "assets/100/playlist_play.png",
+ "assets/200/player_button_next.png",
+ "assets/200/player_button_pause.png",
+ "assets/200/player_button_playlist.png",
+ "assets/200/player_button_play.png",
+ "assets/200/player_button_previous.png",
+ "assets/200/player_button_repeat_one.png",
+ "assets/200/player_button_repeat.png",
+ "assets/200/player_button_shuffle.png",
+ "assets/200/player_button_volume_muted.png",
+ "assets/200/player_button_volume.png",
+ "assets/200/player_cover_close.png",
+ "assets/200/player_cover_open.png",
+ "assets/200/player_no_artwork.png",
+ "assets/200/playlist_now_playing.png",
+ "assets/200/playlist_play.png",
+ ]
+}
diff --git a/chromium/ui/file_manager/audio_player/elements/BUILD.gn b/chromium/ui/file_manager/audio_player/elements/BUILD.gn
index a23e22779a2..f9a97403560 100644
--- a/chromium/ui/file_manager/audio_player/elements/BUILD.gn
+++ b/chromium/ui/file_manager/audio_player/elements/BUILD.gn
@@ -5,6 +5,16 @@
import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
+group("elements") {
+ public_deps = [
+ "//ui/file_manager/audio_player/elements:audio_player_module",
+ "//ui/file_manager/audio_player/elements:control_panel_module",
+ "//ui/file_manager/audio_player/elements:repeat_button_module",
+ "//ui/file_manager/audio_player/elements:track_info_panel_module",
+ "//ui/file_manager/audio_player/elements:track_list_module",
+ ]
+}
+
group("closure_compile") {
deps = [
":closure_compile_internal",
@@ -13,6 +23,7 @@ group("closure_compile") {
}
js_type_check("closure_compile_internal") {
+ uses_legacy_modules = true
deps = [
":audio_player",
":control_panel",
@@ -81,9 +92,9 @@ js_library("control_panel.m") {
":repeat_button.m",
"//third_party/polymer/v3_0/components-chromium/font-roboto:roboto",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ "//ui/file_manager/file_manager/foreground/elements:files_icon_button.m",
"//ui/webui/resources/cr_elements/cr_slider:cr_slider.m",
"//ui/webui/resources/js:assert.m",
- "//ui/file_manager/file_manager/foreground/elements:files_icon_button.m",
]
extra_deps = [ ":control_panel_module" ]
}
diff --git a/chromium/ui/file_manager/audio_player/js/BUILD.gn b/chromium/ui/file_manager/audio_player/js/BUILD.gn
index 2f9e191896e..c47dae2b016 100644
--- a/chromium/ui/file_manager/audio_player/js/BUILD.gn
+++ b/chromium/ui/file_manager/audio_player/js/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//chrome/browser/resources/optimize_webui.gni")
+import("//chrome/browser/resources/tools/optimize_webui.gni")
import("//third_party/closure_compiler/compile_js.gni")
import("//ui/webui/resources/tools/js_modulizer.gni")
@@ -11,10 +11,12 @@ group("closure_compile") {
deps = [
":closure_compile_jsmodules",
":closure_compile_legacy",
+ ":closure_compile_polymer",
]
}
js_type_check("closure_compile_legacy") {
+ uses_legacy_modules = true
deps = [
":audio_player",
":background",
@@ -25,10 +27,18 @@ js_type_check("closure_compile_legacy") {
}
js_type_check("closure_compile_jsmodules") {
- uses_js_modules = true
deps = [
":background.m",
":error_util.m",
+ ":metadata_worker.m",
+ ]
+}
+
+js_type_check("closure_compile_polymer") {
+ is_polymer3 = true
+ closure_flags = default_closure_args + [ "browser_resolver_prefix_replacements=\"chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/=../../ui/file_manager/file_manager/\"" ]
+ deps = [
+ ":audio_player.m",
":main.m",
]
}
@@ -56,6 +66,32 @@ js_library("audio_player") {
]
}
+js_library("audio_player.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/audio_player/js/audio_player.m.js" ]
+ deps = [
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ "//ui/file_manager/audio_player/elements:audio_player.m",
+ "//ui/file_manager/base/js:app_util.m",
+ "//ui/file_manager/base/js:filtered_volume_manager.m",
+ "//ui/file_manager/base/js:mediasession_types.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:content_metadata_provider.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model.m",
+ "//ui/webui/resources/js:load_time_data",
+ ]
+
+ externs_list = [
+ "//ui/file_manager/externs/audio_player_foreground.js",
+ "$externs_path/mediasession.js",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("background") {
deps = [
"//ui/file_manager/file_manager/background/js:app_window_wrapper",
@@ -91,35 +127,52 @@ js_library("metadata_worker") {
]
}
+js_library("metadata_worker.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/audio_player/js/metadata_worker.m.js" ]
+ deps = [ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_dispatcher.m" ]
+ extra_deps = [ ":modulize" ]
+}
+
js_library("test_util") {
}
js_library("test_util.m") {
sources = [ "$root_gen_dir/ui/file_manager/audio_player/js/test_util.m.js" ]
+ deps = [
+ ":background.m",
+ "//ui/file_manager/file_manager/background/js:test_util_base.m",
+ ]
extra_deps = [ ":modulize" ]
}
js_library("main.m") {
- deps = [
- "//ui/file_manager/base/js:app_util.m",
- "//ui/file_manager/base/js:volume_manager_types.m",
- ]
+ deps = [ ":audio_player.m" ]
}
js_library("main_background.m") {
deps = [
":background.m",
":error_util.m",
- "//ui/file_manager/file_manager/background/js:test_util_base.m",
+ ":test_util.m",
]
}
js_modulizer("modulize") {
input_files = [
+ "audio_player.js",
"background.js",
"error_util.js",
+ "metadata_worker.js",
"test_util.js",
]
+
+ namespace_rewrites = [
+ # initializeAudioPlayer uses HTMLImports, so rewriting to bypass it.
+ "initializeAudioPlayer|moduleInitializeAudioPlayer",
+
+ "Polymer.CaseMap.dashToCamelCase|dashToCamelCase",
+ ]
}
preprocess_folder =
@@ -141,3 +194,35 @@ optimize_webui("build") {
"//ui/webui/resources:preprocess",
]
}
+
+optimize_webui("build_worker") {
+ host = "audio_player"
+
+ input = preprocess_folder
+ js_module_in_files = [ "metadata_worker.m.js" ]
+
+ js_out_files = [ "metadata_worker.m.rollup.js" ]
+
+ deps = [
+ ":metadata_worker.m",
+ "//ui/file_manager:preprocess_generated",
+ "//ui/file_manager:preprocess_static",
+ "//ui/webui/resources:preprocess",
+ ]
+}
+
+optimize_webui("build_background") {
+ host = "audio_player"
+
+ input = preprocess_folder
+ js_module_in_files = [ "main_background.m.js" ]
+
+ js_out_files = [ "main_background.m.rollup.js" ]
+
+ deps = [
+ ":main_background.m",
+ "//ui/file_manager:preprocess_generated",
+ "//ui/file_manager:preprocess_static",
+ "//ui/webui/resources:preprocess",
+ ]
+}
diff --git a/chromium/ui/file_manager/base/gn/js_test_gen_html.gni b/chromium/ui/file_manager/base/gn/js_test_gen_html.gni
index bd07dfba102..c601384e92c 100644
--- a/chromium/ui/file_manager/base/gn/js_test_gen_html.gni
+++ b/chromium/ui/file_manager/base/gn/js_test_gen_html.gni
@@ -32,6 +32,9 @@ import("//third_party/closure_compiler/js_unit_tests.gni")
# contain <script type="module" src="..._unittest.m.js"> and traditional
# <script>s for mocks.
#
+# is_polymer3:
+# Boolean indicating that it's a test for a Polymer 3 element.
+#
#
# Non-Polymer example:
# js_test_gen_html("folder_tests") {
@@ -77,6 +80,7 @@ template("js_test_gen_html") {
"mocks",
"html_import",
"js_module",
+ "is_polymer3",
])
testonly = true
sources = []
@@ -105,6 +109,11 @@ template("js_test_gen_html") {
args += [ "--js_module" ]
}
+ # Polymer3 implies --js_module for the generated HTML.
+ if (defined(is_polymer3) && is_polymer3) {
+ args += [ "--js_module" ]
+ }
+
if (defined(mocks)) {
args += [ "--mocks" ] + rebase_path(mocks, root_build_dir)
data = mocks
@@ -116,7 +125,10 @@ template("js_test_gen_html") {
type_check_deps += [ ":$type_check_target_name" ]
js_type_check(type_check_target_name) {
if (defined(invoker.js_module) && invoker.js_module) {
- uses_js_modules = true
+ } else if (defined(invoker.is_polymer3) && invoker.is_polymer3) {
+ is_polymer3 = true
+ } else {
+ uses_legacy_modules = true
}
testonly = true
forward_variables_from(invoker, [ "closure_flags" ])
diff --git a/chromium/ui/file_manager/base/js/BUILD.gn b/chromium/ui/file_manager/base/js/BUILD.gn
index a059200b9f6..c60eeb677a1 100644
--- a/chromium/ui/file_manager/base/js/BUILD.gn
+++ b/chromium/ui/file_manager/base/js/BUILD.gn
@@ -22,15 +22,21 @@ group("closure_compile") {
}
js_type_check("closure_compile_jsmodules") {
- uses_js_modules = true
deps = [
":app_util.m",
+ ":error_counter.m",
":filtered_volume_manager.m",
":volume_manager_types.m",
]
+
+ closure_flags = strict_error_checking_closure_args + [
+ "js_module_root=./gen/ui/",
+ "js_module_root=../../ui/",
+ ]
}
js_type_check("closure_compile_module") {
+ uses_legacy_modules = true
deps = [
":app_util",
":error_counter",
@@ -47,7 +53,6 @@ js_type_check("test_support_type_check") {
}
js_type_check("test_support_type_check_jsmodules") {
- uses_js_modules = true
testonly = true
deps = [
":mock_chrome.m",
@@ -56,12 +61,23 @@ js_type_check("test_support_type_check_jsmodules") {
}
js_library("app_util") {
- externs_list = [ "//ui/file_manager/externs/app_window_common.js" ]
+ deps = [
+ ":volume_manager_types",
+ "//ui/file_manager/externs:volume_manager",
+ ]
+ externs_list = [
+ "//ui/file_manager/externs/app_window_common.js",
+ "//ui/file_manager/externs/background/background_base.js",
+ ]
}
js_library("app_util.m") {
sources = [ "$root_gen_dir/ui/file_manager/base/js/app_util.m.js" ]
- deps = [ "//ui/file_manager/externs:file_manager_private" ]
+ deps = [
+ "//ui/file_manager/externs:file_manager_private",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:background_base.m",
+ ]
externs_list = [ "//ui/file_manager/externs/app_window_common.js" ]
extra_deps = [ ":modulize" ]
@@ -70,6 +86,12 @@ js_library("app_util.m") {
js_library("error_counter") {
}
+js_library("error_counter.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/base/js/error_counter.m.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("filtered_volume_manager") {
deps = [
"//ui/file_manager/base/js:volume_manager_types",
@@ -184,6 +206,7 @@ js_modulizer("modulize") {
"mock_chrome.js",
"test_error_reporting.js",
"volume_manager_types.js",
+ "error_counter.js",
]
namespace_rewrites = cr_namespace_rewrites
diff --git a/chromium/ui/file_manager/base/tools/tests/empty_dependency_list.gn b/chromium/ui/file_manager/base/tools/tests/empty_dependency_list.gn
new file mode 100644
index 00000000000..7cc9ca1db3d
--- /dev/null
+++ b/chromium/ui/file_manager/base/tools/tests/empty_dependency_list.gn
@@ -0,0 +1,4 @@
+
+js_unittest("importer_common_unittest.m") {
+ deps = []
+}
diff --git a/chromium/ui/file_manager/base/tools/tests/empty_dependency_list_expected.gn b/chromium/ui/file_manager/base/tools/tests/empty_dependency_list_expected.gn
new file mode 100644
index 00000000000..6538a5492e9
--- /dev/null
+++ b/chromium/ui/file_manager/base/tools/tests/empty_dependency_list_expected.gn
@@ -0,0 +1,6 @@
+
+js_unittest("importer_common_unittest.m") {
+ deps = [
+ "//ui/file_manager/base/js:mock_chrome",
+ ]
+}
diff --git a/chromium/ui/file_manager/base/tools/tests/single_line_dependency_list.gn b/chromium/ui/file_manager/base/tools/tests/single_line_dependency_list.gn
new file mode 100644
index 00000000000..18ecac470eb
--- /dev/null
+++ b/chromium/ui/file_manager/base/tools/tests/single_line_dependency_list.gn
@@ -0,0 +1,4 @@
+
+js_unittest("importer_common_unittest.m") {
+ deps = [ ":mock_entry" ]
+}
diff --git a/chromium/ui/file_manager/base/tools/tests/single_line_dependency_list_expected.gn b/chromium/ui/file_manager/base/tools/tests/single_line_dependency_list_expected.gn
new file mode 100644
index 00000000000..ee0eadde89f
--- /dev/null
+++ b/chromium/ui/file_manager/base/tools/tests/single_line_dependency_list_expected.gn
@@ -0,0 +1,7 @@
+
+js_unittest("importer_common_unittest.m") {
+ deps = [
+ "//ui/file_manager/base/js:mock_chrome",
+ ":mock_entry",
+ ]
+}
diff --git a/chromium/ui/file_manager/externs/BUILD.gn b/chromium/ui/file_manager/externs/BUILD.gn
index 209cd367ddd..7d53f228b52 100644
--- a/chromium/ui/file_manager/externs/BUILD.gn
+++ b/chromium/ui/file_manager/externs/BUILD.gn
@@ -18,6 +18,66 @@ js_library("file_manager_private") {
]
}
+js_library("background_window.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/externs/background_window.m.js" ]
+
+ deps = [ "//ui/file_manager/externs/background:background_base.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("command_handler_deps.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/externs/command_handler_deps.m.js" ]
+ deps = [
+ ":files_app_entry_interfaces.m",
+ ":volume_manager.m",
+ "background:crostini.m",
+ "background:file_operation_manager.m",
+ "background:progress_center.m",
+ "//ui/file_manager/file_manager/foreground/js:actions_controller.m",
+ "//ui/file_manager/file_manager/foreground/js:dialog_type.m",
+ "//ui/file_manager/file_manager/foreground/js:directory_contents.m",
+ "//ui/file_manager/file_manager/foreground/js:directory_model.m",
+ "//ui/file_manager/file_manager/foreground/js:directory_tree_naming_controller.m",
+ "//ui/file_manager/file_manager/foreground/js:file_selection.m",
+ "//ui/file_manager/file_manager/foreground/js:file_transfer_controller.m",
+ "//ui/file_manager/file_manager/foreground/js:naming_controller.m",
+ "//ui/file_manager/file_manager/foreground/js:providers_model.m",
+ "//ui/file_manager/file_manager/foreground/js:spinner_controller.m",
+ "//ui/file_manager/file_manager/foreground/js:task_controller.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model.m",
+ "//ui/file_manager/file_manager/foreground/js/ui:directory_tree.m",
+ "//ui/file_manager/file_manager/foreground/js/ui:file_manager_ui.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("directory_change_event.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/externs/directory_change_event.m.js" ]
+ deps = [ ":files_app_entry_interfaces.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("drive_dialog_controller.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/externs/drive_dialog_controller.m.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("entries_changed_event.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/externs/entries_changed_event.m.js" ]
+
+ deps = [ "//ui/file_manager/file_manager/common/js:util.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("entry_location.m") {
sources = [ "$root_gen_dir/ui/file_manager/externs/entry_location.m.js" ]
@@ -29,6 +89,16 @@ js_library("entry_location.m") {
extra_deps = [ ":modulize" ]
}
+js_library("exif_entry.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/externs/exif_entry.m.js" ]
+
+ deps = [
+ "//ui/file_manager/file_manager/foreground/js/metadata:exif_constants.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("files_app_entry_interfaces.m") {
sources = [
"$root_gen_dir/ui/file_manager/externs/files_app_entry_interfaces.m.js",
@@ -46,6 +116,14 @@ js_library("metadata_worker_window.m") {
extra_deps = [ ":modulize" ]
}
+js_library("progress_center_panel.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/externs/progress_center_panel.m.js" ]
+
+ deps = [ "//ui/file_manager/file_manager/common/js:progress_center_common.m" ]
+ extra_deps = [ ":modulize" ]
+}
+
js_library("volume_manager") {
sources = []
@@ -95,9 +173,16 @@ js_library("volume_info_list.m") {
js_modulizer("modulize") {
input_files = [
+ "background_window.js",
+ "command_handler_deps.js",
+ "directory_change_event.js",
+ "drive_dialog_controller.js",
+ "entries_changed_event.js",
"entry_location.js",
+ "exif_entry.js",
"files_app_entry_interfaces.js",
"metadata_worker_window.js",
+ "progress_center_panel.js",
"volume_info.js",
"volume_info_list.js",
"volume_manager.js",
diff --git a/chromium/ui/file_manager/externs/background/BUILD.gn b/chromium/ui/file_manager/externs/background/BUILD.gn
new file mode 100644
index 00000000000..a8485738a66
--- /dev/null
+++ b/chromium/ui/file_manager/externs/background/BUILD.gn
@@ -0,0 +1,158 @@
+# Copyright 2020 The Chromium 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")
+import("//ui/webui/resources/tools/js_modulizer.gni")
+
+js_library("file_browser_background_full") {
+ sources = []
+
+ externs_list = [
+ "background_base.js",
+ "crostini.js",
+ "../drive_dialog_controller.js",
+ "drive_sync_handler.js",
+ "duplicate_finder.js",
+ "file_browser_background_full.js",
+ "file_operation_manager.js",
+ "import_history.js",
+ "media_import_handler.js",
+ "media_scanner.js",
+ "progress_center.js",
+ "../progress_center_panel.js",
+ "task_queue.js",
+ ]
+}
+
+js_library("file_browser_background_full.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/externs/background/file_browser_background_full.m.js" ]
+ deps = [
+ ":background_base.m",
+ ":crostini.m",
+ ":drive_sync_handler.m",
+ ":file_operation_manager.m",
+ ":import_history.m",
+ ":media_import_handler.m",
+ ":media_scanner.m",
+ ":progress_center.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("background_base.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/externs/background/background_base.m.js",
+ ]
+
+ deps = [ "..:volume_manager.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("drive_sync_handler.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/externs/background/drive_sync_handler.m.js",
+ ]
+
+ deps = [ "..:drive_dialog_controller.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("duplicate_finder.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/externs/background/duplicate_finder.m.js",
+ ]
+ deps = [
+ ":import_history.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("crostini.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/externs/background/crostini.m.js" ]
+ deps = [ "..:volume_manager.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("file_operation_manager.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/externs/background/file_operation_manager.m.js" ]
+ deps = [
+ "..:files_app_entry_interfaces.m",
+ "..:volume_manager.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("import_history.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/externs/background/import_history.m.js" ]
+ deps = [ "//ui/file_manager/file_manager/common/js:importer_common.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("media_import_handler.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/externs/background/media_import_handler.m.js" ]
+ deps = [
+ ":drive_sync_handler.m",
+ ":duplicate_finder.m",
+ ":import_history.m",
+ ":media_scanner.m",
+ ":progress_center.m",
+ ":task_queue.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("media_scanner.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/externs/background/media_scanner.m.js" ]
+ deps = [ "//ui/file_manager/file_manager/common/js:importer_common.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("progress_center.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/externs/background/progress_center.m.js",
+ ]
+ deps = [
+ "..:progress_center_panel.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("task_queue.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/externs/background/task_queue.m.js" ]
+ deps = [ "//ui/file_manager/file_manager/common/js:importer_common.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_modulizer("modulize") {
+ input_files = [
+ "file_browser_background_full.js",
+ "background_base.js",
+ "crostini.js",
+ "drive_sync_handler.js",
+ "duplicate_finder.js",
+ "file_operation_manager.js",
+ "import_history.js",
+ "media_import_handler.js",
+ "media_scanner.js",
+ "progress_center.js",
+ "task_queue.js",
+ ]
+}
diff --git a/chromium/ui/file_manager/file_manager/BUILD.gn b/chromium/ui/file_manager/file_manager/BUILD.gn
new file mode 100644
index 00000000000..8a8a131f088
--- /dev/null
+++ b/chromium/ui/file_manager/file_manager/BUILD.gn
@@ -0,0 +1,165 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//ui/webui/resources/tools/generate_grd.gni")
+
+action("gen_main_html") {
+ inputs = [ "main.html" ]
+
+ script = "//ui/file_manager/base/gn/gen_main_html.py"
+
+ args = [
+ "--source",
+ rebase_path("//ui/file_manager/file_manager/main.html", root_build_dir),
+ "--target",
+ rebase_path("$target_gen_dir/main_modules.html", root_build_dir),
+ ]
+
+ outputs = [
+ "$target_gen_dir/main_modules.html",
+ "$target_gen_dir/main_modules.html.stamp",
+ ]
+}
+
+# TODO: Remove this file copy when breadcrumb.js supports only JS modules.
+copy("fix_broken_images") {
+ sources = [
+ "foreground/images/files/ui/arrow_right.svg",
+ "foreground/images/files/ui/menu_ng.svg",
+ ]
+ outputs = [ "$target_gen_dir/images/files/ui/{{source_file_part}}" ]
+}
+
+generated_static_grdp = "$target_gen_dir/static_resources.grdp"
+
+generate_grd("build_static_grdp") {
+ out_grd = generated_static_grdp
+ grd_prefix = "file_manager"
+
+ resource_path_prefix = "file_manager"
+
+ input_files_base_dir = rebase_path(".", "//")
+
+ input_files = [
+ # CSS:
+ "cws_widget/cws_widget_container.css",
+ "foreground/css/combobutton.css",
+ "foreground/css/common.css",
+ "foreground/css/file_manager.css",
+ "foreground/css/file_status.css",
+ "foreground/css/file_types.css",
+ "foreground/css/list.css",
+ "foreground/css/menu.css",
+ "foreground/css/table.css",
+ "foreground/css/tree.css",
+
+ # Images:
+ "foreground/images/common/check_no_box.png",
+ "foreground/images/common/2x/check_no_box.png",
+ "foreground/images/common/disclosure_arrow_dk_grey_down.png",
+ "foreground/images/common/2x/disclosure_arrow_dk_grey_down.png",
+ "foreground/images/common/dragger.svg",
+ "foreground/images/common/ic_close.svg",
+ "foreground/images/common/ic_selected.svg",
+ "foreground/images/files/ui/2x/person_add.png",
+ "foreground/images/files/ui/2x/search.png",
+ "foreground/images/files/ui/2x/service_drive.png",
+ "foreground/images/files/ui/arrow_right.svg",
+ "foreground/images/files/ui/arrow_right_white.png",
+ "foreground/images/files/ui/2x/arrow_right_white.png",
+ "foreground/images/files/ui/back.svg",
+ "foreground/images/files/ui/cloud_import_syncing.png",
+ "foreground/images/files/ui/2x/cloud_import_syncing.png",
+ "foreground/images/files/ui/delete.svg",
+ "foreground/images/files/ui/delete_ng.svg",
+ "foreground/images/files/ui/drive_logo.svg",
+ "foreground/images/files/ui/external_link.svg",
+ "foreground/images/files/ui/filetype_placeholder_audio.png",
+ "foreground/images/files/ui/2x/filetype_placeholder_audio.png",
+ "foreground/images/files/ui/filetype_placeholder_generic.png",
+ "foreground/images/files/ui/2x/filetype_placeholder_generic.png",
+ "foreground/images/files/ui/filetype_placeholder_generic.svg",
+ "foreground/images/files/ui/filetype_placeholder_image.png",
+ "foreground/images/files/ui/2x/filetype_placeholder_image.png",
+ "foreground/images/files/ui/filetype_placeholder_video.png",
+ "foreground/images/files/ui/2x/filetype_placeholder_video.png",
+ "foreground/images/files/ui/holding_space_welcome_image.svg",
+ "foreground/images/files/ui/info.svg",
+ "foreground/images/files/ui/list_check.svg",
+ "foreground/images/files/ui/menu_ng.svg",
+ "foreground/images/files/ui/offline.svg",
+ "foreground/images/files/ui/person_add.png",
+ "foreground/images/files/ui/quick_view/filetype_audio.png",
+ "foreground/images/files/ui/quick_view/2x/filetype_audio.png",
+ "foreground/images/files/ui/quick_view/filetype_folder.png",
+ "foreground/images/files/ui/quick_view/2x/filetype_folder.png",
+ "foreground/images/files/ui/quick_view/filetype_generic.png",
+ "foreground/images/files/ui/quick_view/2x/filetype_generic.png",
+ "foreground/images/files/ui/quick_view/filetype_image.png",
+ "foreground/images/files/ui/quick_view/2x/filetype_image.png",
+ "foreground/images/files/ui/quick_view/filetype_video.png",
+ "foreground/images/files/ui/quick_view/2x/filetype_video.png",
+ "foreground/images/files/ui/refresh.svg",
+ "foreground/images/files/ui/restore.svg",
+ "foreground/images/files/ui/search.png",
+ "foreground/images/files/ui/search.svg",
+ "foreground/images/files/ui/search_clear_filled.svg",
+ "foreground/images/files/ui/service_drive.png",
+ "foreground/images/files/ui/share_ng.svg",
+ "foreground/images/files/ui/sort_desc.svg",
+ "foreground/images/files/ui/sorting_ng.svg",
+ "foreground/images/files/ui/view_list.svg",
+ "foreground/images/files/ui/view_thumbnail.svg",
+ "foreground/images/files/ui/visibility_ng.svg",
+ "foreground/images/files/ui/warning.svg",
+ "foreground/images/filetype/filetype_archive.svg",
+ "foreground/images/filetype/filetype_audio.svg",
+ "foreground/images/filetype/filetype_excel.svg",
+ "foreground/images/filetype/filetype_folder.svg",
+ "foreground/images/filetype/filetype_folder_shared.svg",
+ "foreground/images/filetype/filetype_gdoc.svg",
+ "foreground/images/filetype/filetype_gdraw.svg",
+ "foreground/images/filetype/filetype_generic.svg",
+ "foreground/images/filetype/filetype_gform.svg",
+ "foreground/images/filetype/filetype_gmap.svg",
+ "foreground/images/filetype/filetype_gsheet.svg",
+ "foreground/images/filetype/filetype_gsite.svg",
+ "foreground/images/filetype/filetype_gslides.svg",
+ "foreground/images/filetype/filetype_gtable.svg",
+ "foreground/images/filetype/filetype_image.svg",
+ "foreground/images/filetype/filetype_pdf.svg",
+ "foreground/images/filetype/filetype_ppt.svg",
+ "foreground/images/filetype/filetype_script.svg",
+ "foreground/images/filetype/filetype_sites.svg",
+ "foreground/images/filetype/filetype_team_drive.svg",
+ "foreground/images/filetype/filetype_tini.svg",
+ "foreground/images/filetype/filetype_video.svg",
+ "foreground/images/filetype/filetype_word.svg",
+ "foreground/images/volumes/android.svg",
+ "foreground/images/volumes/archive.svg",
+ "foreground/images/volumes/audio.svg",
+ "foreground/images/volumes/camera.svg",
+ "foreground/images/volumes/cd.svg",
+ "foreground/images/volumes/computer.svg",
+ "foreground/images/volumes/devices.svg",
+ "foreground/images/volumes/downloads.svg",
+ "foreground/images/volumes/drive.svg",
+ "foreground/images/volumes/hard_drive.svg",
+ "foreground/images/volumes/images.svg",
+ "foreground/images/volumes/linux_files.svg",
+ "foreground/images/volumes/my_files.svg",
+ "foreground/images/volumes/offline.svg",
+ "foreground/images/volumes/phone.svg",
+ "foreground/images/volumes/plugin_vm_ng.svg",
+ "foreground/images/volumes/recent.svg",
+ "foreground/images/volumes/sd.svg",
+ "foreground/images/volumes/service_drive.svg",
+ "foreground/images/volumes/shared.svg",
+ "foreground/images/volumes/shortcut.svg",
+ "foreground/images/volumes/smb.svg",
+ "foreground/images/volumes/team_drive.svg",
+ "foreground/images/volumes/usb.svg",
+ "foreground/images/volumes/videos.svg",
+ ]
+}
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 80bb182d621..86bbc354e0b 100644
--- a/chromium/ui/file_manager/file_manager/background/js/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/background/js/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//chrome/browser/resources/tools/optimize_webui.gni")
import("//third_party/closure_compiler/compile_js.gni")
import("//third_party/closure_compiler/js_unit_tests.gni")
import("//ui/file_manager/base/gn/js_test_gen_html.gni")
@@ -26,7 +27,7 @@ group("closure_compile") {
deps = [
":closure_compile_jsmodules",
":closure_compile_module",
- ":js_test_gen_html_type_check_auto",
+ ":js_test_gen_html_modules_type_check_auto",
":test_support_modules_type_check",
":test_support_type_check",
]
@@ -36,6 +37,7 @@ group("closure_compile") {
visibility = [ ":*" ]
js_type_check("closure_compile_module") {
+ uses_legacy_modules = true
deps = [
":app_window_wrapper",
":app_windows",
@@ -70,28 +72,69 @@ js_type_check("closure_compile_module") {
}
js_type_check("closure_compile_jsmodules") {
- uses_js_modules = true
deps = [
":app_window_wrapper.m",
":app_windows.m",
+ ":background.m",
":background_base.m",
+ ":crostini.m",
+ ":device_handler.m",
+ ":drive_sync_handler.m",
+ ":duplicate_finder.m",
":entry_location_impl.m",
+ ":file_operation_handler.m",
+ ":file_operation_manager.m",
+ ":file_operation_util.m",
+ ":import_history.m",
+ ":launcher.m",
+ ":launcher_search.m",
+ ":media_import_handler.m",
+ ":media_scanner.m",
+ ":metadata_proxy.m",
+ ":metrics_start.m",
+ ":mock_drive_sync_handler.m",
+ ":mock_file_operation_manager.m",
+ ":mock_progress_center.m",
+ ":mount_metrics.m",
+ ":progress_center.m",
+ ":task_queue.m",
":test_util_base.m",
+ ":trash.m",
":volume_info_impl.m",
":volume_info_list_impl.m",
":volume_manager_factory.m",
":volume_manager_impl.m",
":volume_manager_util.m",
]
+
+ closure_flags =
+ strict_error_checking_closure_args + [
+ "js_module_root=./gen/ui",
+ "js_module_root=../../ui",
+ "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
+ "hide_warnings_for=third_party/",
+ ]
}
js_type_check("test_support_modules_type_check") {
testonly = true
- uses_js_modules = true
- deps = [ ":mock_volume_manager.m" ]
+ deps = [
+ ":mock_crostini.m",
+ ":mock_media_scanner.m",
+ ":mock_volume_manager.m",
+ ":test_import_history.m",
+ ]
+ closure_flags =
+ strict_error_checking_closure_args + [
+ "js_module_root=./gen/ui",
+ "js_module_root=../../ui",
+ "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
+ "hide_warnings_for=third_party/",
+ ]
}
js_type_check("test_support_type_check") {
+ uses_legacy_modules = true
testonly = true
deps = [
":mock_crostini",
@@ -110,17 +153,16 @@ js_library("closure_compile_externs") {
"$externs_path/metrics_private.js",
"//ui/file_manager/externs/background/crostini.js",
"//ui/file_manager/externs/background/drive_sync_handler.js",
- "//ui/file_manager/externs/background/file_browser_background.js",
+ "//ui/file_manager/externs/background/background_base.js",
"//ui/file_manager/externs/background/file_browser_background_full.js",
"//ui/file_manager/externs/background/file_operation_manager.js",
"//ui/file_manager/externs/background/import_history.js",
- "//ui/file_manager/externs/background/import_runner.js",
"//ui/file_manager/externs/background/media_import_handler.js",
"//ui/file_manager/externs/background/media_scanner.js",
"//ui/file_manager/externs/background/progress_center.js",
"//ui/file_manager/externs/background_window.js",
"//ui/file_manager/externs/css_rule.js",
- "//ui/file_manager/externs/file_operation_progress_event.js",
+ "//ui/file_manager/externs/drive_dialog_controller.js",
"//ui/file_manager/externs/launcher_search_provider.js",
"//ui/file_manager/externs/platform.js",
"//ui/file_manager/externs/progress_center_panel.js",
@@ -186,6 +228,62 @@ js_library("background") {
]
}
+js_library("background.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/background/js/background.m.js",
+ ]
+ deps = [
+ ":background_base.m",
+ ":crostini.m",
+ ":device_handler.m",
+ ":drive_sync_handler.m",
+ ":duplicate_finder.m",
+ ":file_operation_handler.m",
+ ":file_operation_manager.m",
+ ":file_operation_util.m",
+ ":import_history.m",
+ ":launcher.m",
+ ":launcher_search.m",
+ ":media_import_handler.m",
+ ":media_scanner.m",
+ ":mount_metrics.m",
+ ":progress_center.m",
+ ":volume_manager_factory.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:crostini.m",
+ "//ui/file_manager/externs/background:drive_sync_handler.m",
+ "//ui/file_manager/externs/background:duplicate_finder.m",
+ "//ui/file_manager/externs/background:file_browser_background_full.m",
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/file_manager/externs/background:import_history.m",
+ "//ui/file_manager/externs/background:media_import_handler.m",
+ "//ui/file_manager/externs/background:media_scanner.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("main_background.m") {
+ visibility = []
+ visibility = [
+ ":*",
+ "//ui/file_manager:preprocess_static",
+ ]
+
+ deps = [
+ ":background.m",
+ ":metrics_start.m",
+ ":test_util.m",
+ "//ui/file_manager/base/js:error_counter.m",
+ ]
+}
+
js_library("background_base") {
visibility += related_apps
deps = [
@@ -195,6 +293,7 @@ js_library("background_base") {
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:load_time_data",
]
+ externs_list = [ "//ui/file_manager/externs/background/background_base.js" ]
}
js_library("background_base.m") {
@@ -202,6 +301,8 @@ js_library("background_base.m") {
sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/background_base.m.js" ]
deps = [
":volume_manager_factory.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:background_base.m",
"//ui/file_manager/file_manager/common/js:util.m",
"//ui/webui/resources/js:assert.m",
"//ui/webui/resources/js:load_time_data.m",
@@ -219,6 +320,21 @@ js_library("crostini") {
externs_list = [ "//ui/file_manager/externs/background/crostini.js" ]
}
+js_library("crostini.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/background/js/crostini.m.js",
+ ]
+ deps = [
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:crostini.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("mock_crostini") {
testonly = true
deps = [ ":crostini" ]
@@ -227,11 +343,31 @@ js_library("mock_crostini") {
visibility = [ "//ui/file_manager/file_manager/*" ]
}
-js_unittest("crostini_unittest") {
+js_library("mock_crostini.m") {
+ testonly = true
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/mock_crostini.m.js" ]
deps = [
- ":mock_crostini",
- "//ui/file_manager/file_manager/common/js:mock_entry",
- "//ui/webui/resources/js:webui_resource_test",
+ ":crostini.m",
+ "//ui/file_manager/externs/background:crostini.m",
+ ]
+ visibility += [
+ "//ui/file_manager/file_manager/foreground/js:file_tasks_unittest.m",
+ "//ui/file_manager/file_manager/foreground/js:task_controller_unittest.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("crostini_unittest.m") {
+ deps = [
+ ":mock_crostini.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:entry_location.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:crostini.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
}
@@ -247,43 +383,104 @@ js_library("device_handler") {
]
}
-js_unittest("device_handler_unittest") {
+js_library("device_handler.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/device_handler.m.js" ]
deps = [
- ":device_handler",
- ":mock_progress_center",
- ":mock_volume_manager",
- "//ui/file_manager/base/js:mock_chrome",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/file_manager/common/js:test_importer_common",
+ ":volume_manager_factory.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("device_handler_unittest.m") {
+ deps = [
+ ":device_handler.m",
+ ":mock_progress_center.m",
+ ":mock_volume_manager.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
}
js_library("mock_drive_sync_handler") {
testonly = true
deps = [ "//ui/webui/resources/js/cr:event_target" ]
- externs_list =
- [ "//ui/file_manager/externs/background/drive_sync_handler.js" ]
+ externs_list = [
+ "//ui/file_manager/externs/background/drive_sync_handler.js",
+ "//ui/file_manager/externs/drive_dialog_controller.js",
+ ]
visibility = []
visibility = [ "//ui/file_manager/file_manager/*" ]
}
+js_library("mock_drive_sync_handler.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/mock_drive_sync_handler.m.js" ]
+ deps = [
+ "//ui/file_manager/externs:drive_dialog_controller.m",
+ "//ui/file_manager/externs/background:drive_sync_handler.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+ visibility += [
+ "//ui/file_manager/file_manager/foreground/js:actions_model_unittest.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("drive_sync_handler") {
deps = [
+ ":launcher",
":progress_center",
"//ui/file_manager/file_manager/common/js:async_util",
"//ui/webui/resources/js/cr:event_target",
]
- externs_list =
- [ "//ui/file_manager/externs/background/drive_sync_handler.js" ]
+ externs_list = [
+ "//ui/file_manager/externs/background/drive_sync_handler.js",
+ "//ui/file_manager/externs/drive_dialog_controller.js",
+ ]
}
-js_unittest("drive_sync_handler_unittest") {
+js_library("drive_sync_handler.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/drive_sync_handler.m.js" ]
deps = [
- ":drive_sync_handler",
- ":file_operation_util",
- ":mock_progress_center",
- "//ui/file_manager/base/js:mock_chrome",
- "//ui/file_manager/base/js:test_error_reporting",
+ ":file_operation_util.m",
+ ":launcher.m",
+ "//ui/file_manager/externs:drive_dialog_controller.m",
+ "//ui/file_manager/externs/background:drive_sync_handler.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("drive_sync_handler_unittest.m") {
+ deps = [
+ ":drive_sync_handler.m",
+ ":mock_progress_center.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
}
@@ -298,14 +495,36 @@ js_library("duplicate_finder") {
externs_list = [ "//ui/file_manager/externs/background/duplicate_finder.js" ]
}
-js_unittest("duplicate_finder_unittest") {
+js_library("duplicate_finder.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/duplicate_finder.m.js" ]
deps = [
- ":duplicate_finder",
- ":mock_volume_manager",
- ":test_import_history",
- "//ui/file_manager/base/js:mock_chrome",
- "//ui/file_manager/file_manager/common/js:mock_entry",
- "//ui/file_manager/file_manager/common/js:test_importer_common",
+ ":import_history.m",
+ ":volume_manager_factory.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:duplicate_finder.m",
+ "//ui/file_manager/externs/background:import_history.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:lru_cache.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("duplicate_finder_unittest.m") {
+ deps = [
+ ":duplicate_finder.m",
+ ":mock_volume_manager.m",
+ ":test_import_history.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs/background:duplicate_finder.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
]
}
@@ -333,12 +552,29 @@ js_library("file_operation_handler") {
]
}
-js_unittest("file_operation_handler_unittest") {
+js_library("file_operation_handler.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/file_operation_handler.m.js" ]
deps = [
- ":file_operation_handler",
- ":mock_file_operation_manager",
- ":mock_progress_center",
- "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/common/js:file_operation_common.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_operation_handler_unittest.m") {
+ deps = [
+ ":file_operation_handler.m",
+ ":file_operation_util.m",
+ ":mock_file_operation_manager.m",
+ ":mock_progress_center.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/file_manager/common/js:file_operation_common.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
]
}
@@ -352,11 +588,23 @@ js_library("mock_file_operation_manager") {
[ "//ui/file_manager/externs/background/file_operation_manager.js" ]
}
+js_library("mock_file_operation_manager.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/mock_file_operation_manager.m.js" ]
+ deps = [
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("file_operation_manager") {
deps = [
":file_operation_util",
":trash",
":volume_manager_factory",
+ "//ui/file_manager/file_manager/common/js:file_operation_common",
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js/cr:event_target",
]
@@ -364,13 +612,41 @@ js_library("file_operation_manager") {
[ "//ui/file_manager/externs/background/file_operation_manager.js" ]
}
-js_unittest("file_operation_manager_unittest") {
+js_library("file_operation_manager.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/file_operation_manager.m.js" ]
deps = [
- ":file_operation_manager",
- ":metadata_proxy",
- "//ui/file_manager/base/js:mock_chrome",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/file_manager/common/js:mock_entry",
+ ":file_operation_util.m",
+ ":metadata_proxy.m",
+ ":trash.m",
+ ":volume_manager_factory.m",
+ "//ui/file_manager/externs:entry_location.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:file_operation_common.m",
+ "//ui/file_manager/file_manager/common/js:trash.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_operation_manager_unittest.m") {
+ deps = [
+ ":file_operation_manager.m",
+ ":file_operation_util.m",
+ ":volume_manager_factory.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/externs:entry_location.m",
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/file_manager/file_manager/common/js:file_operation_common.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
}
@@ -378,24 +654,54 @@ js_library("file_operation_util") {
deps = [
":metadata_proxy",
"//ui/file_manager/file_manager/common/js:async_util",
+ "//ui/file_manager/file_manager/common/js:file_operation_common",
+ "//ui/file_manager/file_manager/common/js:trash",
"//ui/file_manager/file_manager/common/js:util",
]
- externs_list =
- [ "//ui/file_manager/externs/file_operation_progress_event.js" ]
+}
+
+js_library("file_operation_util.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/file_operation_util.m.js" ]
+ deps = [
+ ":metadata_proxy.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:file_operation_common.m",
+ "//ui/file_manager/file_manager/common/js:trash.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
}
js_library("metadata_proxy") {
deps = [ "//ui/file_manager/file_manager/common/js:lru_cache" ]
}
-js_unittest("metadata_proxy_unittest") {
+js_library("metadata_proxy.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/metadata_proxy.m.js" ]
+ deps = [ "//ui/file_manager/file_manager/common/js:lru_cache.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("metadata_proxy_unittest.m") {
deps = [
- ":metadata_proxy",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/file_manager/common/js:mock_entry",
+ ":metadata_proxy.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
]
}
+js_library("metrics_start.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/metrics_start.m.js" ]
+ deps = [ "//ui/file_manager/file_manager/common/js:metrics.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("import_history") {
deps = [
":metadata_proxy",
@@ -405,11 +711,30 @@ js_library("import_history") {
externs_list = [ "//ui/file_manager/externs/background/import_history.js" ]
}
-js_unittest("import_history_unittest") {
+js_library("import_history.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/import_history.m.js" ]
deps = [
- ":import_history",
- "//ui/file_manager/file_manager/common/js:mock_entry",
- "//ui/file_manager/file_manager/common/js:test_importer_common",
+ ":metadata_proxy.m",
+ "//ui/file_manager/externs/background:import_history.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("import_history_unittest.m") {
+ deps = [
+ ":import_history.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/externs/background:import_history.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/file_manager/file_manager/common/js:test_importer_common.m",
+ "//ui/file_manager/file_manager/common/js:unittest_util.m",
]
}
@@ -420,6 +745,18 @@ js_library("launcher") {
]
}
+js_library("launcher.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/background/js/launcher.m.js",
+ ]
+ deps = [
+ ":app_window_wrapper.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("launcher_search") {
deps = [
":launcher",
@@ -429,6 +766,20 @@ js_library("launcher_search") {
]
}
+js_library("launcher_search.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/launcher_search.m.js" ]
+ deps = [
+ ":launcher.m",
+ ":volume_manager_factory.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ externs_list = [ "//ui/file_manager/externs/launcher_search_provider.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("media_import_handler") {
deps = [
":drive_sync_handler",
@@ -440,26 +791,55 @@ js_library("media_import_handler") {
"//ui/file_manager/file_manager/common/js:metrics",
]
externs_list = [
- "//ui/file_manager/externs/background/import_runner.js",
"//ui/file_manager/externs/background/duplicate_finder.js",
"//ui/file_manager/externs/background/task_queue.js",
"//ui/file_manager/externs/background/media_import_handler.js",
]
}
-js_unittest("media_import_handler_unittest") {
+js_library("media_import_handler.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/media_import_handler.m.js" ]
deps = [
- ":file_operation_util",
- ":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",
+ ":file_operation_util.m",
+ ":task_queue.m",
+ "//ui/file_manager/externs/background:drive_sync_handler.m",
+ "//ui/file_manager/externs/background:duplicate_finder.m",
+ "//ui/file_manager/externs/background:import_history.m",
+ "//ui/file_manager/externs/background:media_import_handler.m",
+ "//ui/file_manager/externs/background:media_scanner.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/externs/background:task_queue.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("media_import_handler_unittest.m") {
+ deps = [
+ ":file_operation_util.m",
+ ":media_import_handler.m",
+ ":mock_drive_sync_handler.m",
+ ":mock_media_scanner.m",
+ ":mock_progress_center.m",
+ ":mock_volume_manager.m",
+ ":test_import_history.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs/background:duplicate_finder.m",
+ "//ui/file_manager/externs/background:import_history.m",
+ "//ui/file_manager/externs/background:media_import_handler.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/file_manager/file_manager/common/js:test_importer_common.m",
]
}
@@ -474,6 +854,21 @@ js_library("mock_media_scanner") {
visibility = [ "//ui/file_manager/file_manager/*" ]
}
+js_library("mock_media_scanner.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/mock_media_scanner.m.js" ]
+ deps = [
+ ":media_scanner.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/externs/background:media_scanner.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ ]
+ visibility += [
+ "//ui/file_manager/file_manager/foreground/js:import_controller_unittest.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("media_scanner") {
deps = [
":file_operation_util",
@@ -482,11 +877,33 @@ js_library("media_scanner") {
externs_list = [ "//ui/file_manager/externs/background/media_scanner.js" ]
}
-js_unittest("media_scanner_unittest") {
+js_library("media_scanner.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/media_scanner.m.js" ]
deps = [
- ":media_scanner",
- ":mock_media_scanner",
- "//ui/file_manager/file_manager/common/js:test_importer_common",
+ ":file_operation_util.m",
+ ":metadata_proxy.m",
+ "//ui/file_manager/externs/background:media_scanner.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+ visibility += [
+ "//ui/file_manager/file_manager/foreground/js:import_controller_unittest.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("media_scanner_unittest.m") {
+ deps = [
+ ":file_operation_util.m",
+ ":media_scanner.m",
+ ":mock_media_scanner.m",
+ ":test_import_history.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/externs/background:media_scanner.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:unittest_util.m",
]
}
@@ -534,6 +951,18 @@ js_library("mock_progress_center") {
[ "//ui/file_manager/file_manager/foreground/js:file_tasks_unittest" ]
}
+js_library("mock_progress_center.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/mock_progress_center.m.js" ]
+ deps = [
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ ]
+ visibility +=
+ [ "//ui/file_manager/file_manager/foreground/js:file_tasks_unittest.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("progress_center") {
deps = [
"//ui/file_manager/file_manager/common/js:async_util",
@@ -547,6 +976,19 @@ js_library("progress_center") {
]
}
+js_library("progress_center.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/progress_center.m.js" ]
+ deps = [
+ "//ui/file_manager/externs:progress_center_panel.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("runtime_loaded_test_util") {
# TODO(tapted): Move this target to //ui/file_manager/base. It is used in the
# background page of all |related_apps|, but loaded at runtime by
@@ -579,11 +1021,11 @@ js_library("runtime_loaded_test_util") {
"//ui/file_manager/externs/progress_center_panel.js",
"//ui/file_manager/externs/background/media_scanner.js",
"//ui/file_manager/externs/background/drive_sync_handler.js",
+ "//ui/file_manager/externs/drive_dialog_controller.js",
"//ui/file_manager/externs/background_window.js",
"//ui/file_manager/externs/background/file_operation_manager.js",
"//ui/file_manager/externs/background/import_history.js",
- "//ui/file_manager/externs/background/import_runner.js",
- "//ui/file_manager/externs/background/file_browser_background.js",
+ "//ui/file_manager/externs/background/background_base.js",
"//ui/file_manager/externs/background/file_browser_background_full.js",
]
}
@@ -603,6 +1045,10 @@ js_library("volume_info_impl.m") {
"//ui/file_manager/file_manager/common/js:util.m",
"//ui/webui/resources/js:assert.m",
]
+ visibility += [
+ "//ui/file_manager/file_manager/foreground/js:navigation_list_model_unittest.m",
+ "//ui/file_manager/file_manager/foreground/js:providers_model_unittest.m",
+ ]
extra_deps = [ ":modulize" ]
}
@@ -612,18 +1058,26 @@ js_library("task_queue") {
externs_list = [ "//ui/file_manager/externs/background/task_queue.js" ]
}
-js_unittest("task_queue_unittest") {
+js_unittest("task_queue_unittest.m") {
deps = [
- ":task_queue",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/base/js:volume_manager_types",
- "//ui/file_manager/file_manager/common/js:importer_common",
- "//ui/file_manager/file_manager/common/js:progress_center_common",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js/cr:event_target",
+ ":task_queue.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/externs/background:task_queue.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
]
- externs_list = [ "//ui/file_manager/externs/background/task_queue.js" ]
+}
+
+js_library("task_queue.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/background/js/task_queue.m.js",
+ ]
+
+ deps = [
+ "//ui/file_manager/externs/background:task_queue.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ ]
+ extra_deps = [ ":modulize" ]
}
js_library("test_util_base") {
@@ -632,6 +1086,28 @@ js_library("test_util_base") {
js_library("test_util_base.m") {
visibility += related_apps
sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/test_util_base.m.js" ]
+ deps = [
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("test_util.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/background/js/test_util.m.js",
+ ]
+
+ deps = [
+ ":background.m",
+ ":launcher.m",
+ ":test_util_base.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
extra_deps = [ ":modulize" ]
}
@@ -643,20 +1119,50 @@ js_library("test_import_history") {
]
}
+js_library("test_import_history.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/test_import_history.m.js" ]
+ deps = [
+ ":import_history.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("trash") {
deps = [
":file_operation_util",
"//ui/file_manager/base/js:volume_manager_types",
"//ui/file_manager/externs:volume_manager",
+ "//ui/file_manager/file_manager/common/js:trash",
]
}
-js_unittest("trash_unittest") {
+js_library("trash.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/file_manager/background/js/trash.m.js" ]
deps = [
- ":mock_volume_manager",
- ":trash",
- "//ui/file_manager/file_manager/common/js:mock_entry",
- "//ui/webui/resources/js:webui_resource_test",
+ ":file_operation_util.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:trash.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("trash_unittest.m") {
+ deps = [
+ ":mock_volume_manager.m",
+ ":trash.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/file_manager/file_manager/common/js:trash.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
}
@@ -686,15 +1192,23 @@ js_library("mount_metrics") {
deps = [ "//ui/file_manager/file_manager/common/js:metrics" ]
}
-js_unittest("mount_metrics_unittest") {
+js_unittest("mount_metrics_unittest.m") {
deps = [
- ":mount_metrics",
- "//ui/file_manager/base/js:mock_chrome",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/base/js:volume_manager_types",
+ ":mount_metrics.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
]
}
+js_library("mount_metrics.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/mount_metrics.m.js" ]
+ deps = [ "//ui/file_manager/file_manager/common/js:metrics.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("volume_manager_impl") {
deps = [
":entry_location_impl",
@@ -738,12 +1252,18 @@ js_library("volume_manager_factory.m") {
extra_deps = [ ":modulize" ]
}
-js_unittest("volume_manager_unittest") {
+js_unittest("volume_manager_unittest.m") {
deps = [
- ":volume_manager_factory",
- "//ui/file_manager/base/js:mock_chrome",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/file_manager/common/js:mock_entry",
+ ":volume_info_impl.m",
+ ":volume_manager_factory.m",
+ ":volume_manager_impl.m",
+ ":volume_manager_util.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
}
@@ -768,27 +1288,37 @@ js_library("volume_manager_util.m") {
extra_deps = [ ":modulize" ]
}
-js_test_gen_html("js_test_gen_html") {
+js_test_gen_html("js_test_gen_html_modules") {
deps = [
- ":crostini_unittest",
- ":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",
- ":metadata_proxy_unittest",
- ":mount_metrics_unittest",
- ":task_queue_unittest",
- ":trash_unittest",
- ":volume_manager_unittest",
+ ":crostini_unittest.m",
+ ":device_handler_unittest.m",
+ ":drive_sync_handler_unittest.m",
+ ":duplicate_finder_unittest.m",
+ ":file_operation_handler_unittest.m",
+ ":file_operation_manager_unittest.m",
+ ":import_history_unittest.m",
+ ":media_import_handler_unittest.m",
+ ":media_scanner_unittest.m",
+ ":metadata_proxy_unittest.m",
+ ":mount_metrics_unittest.m",
+ ":task_queue_unittest.m",
+ ":trash_unittest.m",
+ ":volume_manager_unittest.m",
]
+ js_module = true
+
+ closure_flags =
+ strict_error_checking_closure_args + [
+ "js_module_root=./gen/ui",
+ "js_module_root=../../ui",
+ "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
+ "hide_warnings_for=third_party/",
+ ]
}
js_modulizer("modulize") {
input_files = [
+ "metadata_proxy.js",
"app_windows.js",
"app_window_wrapper.js",
"background_base.js",
@@ -800,7 +1330,53 @@ js_modulizer("modulize") {
"volume_manager_factory.js",
"volume_manager_impl.js",
"volume_manager_util.js",
+ "file_operation_util.js",
+ "mock_drive_sync_handler.js",
+ "mock_crostini.js",
+ "crostini.js",
+ "mock_file_operation_manager.js",
+ "mock_progress_center.js",
+ "mount_metrics.js",
+ "metrics_start.js",
+ "task_queue.js",
+ "test_import_history.js",
+ "test_util.js",
+ "import_history.js",
+ "drive_sync_handler.js",
+ "media_scanner.js",
+ "mock_media_scanner.js",
+ "duplicate_finder.js",
+ "media_import_handler.js",
+ "file_operation_handler.js",
+ "file_operation_manager.js",
+ "trash.js",
+ "progress_center.js",
+ "device_handler.js",
+ "launcher.js",
+ "launcher_search.js",
+ "background.js",
]
namespace_rewrites = cr_namespace_rewrites
}
+
+preprocess_folder =
+ rebase_path(
+ "$target_gen_dir/../../../preprocessed/file_manager/background/js",
+ root_build_dir)
+
+optimize_webui("build") {
+ host = "file_manager"
+
+ input = preprocess_folder
+ js_module_in_files = [ "main_background.m.js" ]
+
+ js_out_files = [ "main_background.m.rollup.js" ]
+
+ deps = [
+ ":main_background.m",
+ "//ui/file_manager:preprocess_generated",
+ "//ui/file_manager:preprocess_static",
+ "//ui/webui/resources:preprocess",
+ ]
+}
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 25c4c6e75ff..3e42f821bbe 100644
--- a/chromium/ui/file_manager/file_manager/common/js/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/common/js/BUILD.gn
@@ -9,7 +9,10 @@ import("//ui/webui/resources/js/cr.gni")
import("//ui/webui/resources/tools/js_modulizer.gni")
# TODO(tapted): This entire folder should move to //ui/file_manager/base.
-visibility = [ "//ui/file_manager/*" ]
+visibility = [
+ "//chromeos/components/file_manager/resources/*",
+ "//ui/file_manager/*",
+]
group("closure_compile") {
testonly = true
@@ -17,14 +20,16 @@ group("closure_compile") {
":closure_compile_jsmodules",
":closure_compile_module",
":js_test_gen_html_modules_type_check_auto",
- ":js_test_gen_html_type_check_auto",
+ ":test_support_modules_type_check",
":test_support_type_check",
]
}
js_type_check("closure_compile_module") {
+ uses_legacy_modules = true
deps = [
":async_util",
+ ":file_operation_common",
":file_type",
":files_app_entry_types",
":importer_common",
@@ -33,26 +38,39 @@ js_type_check("closure_compile_module") {
":metrics_base",
":mock_entry",
":progress_center_common",
+ ":storage_adapter",
+ ":trash",
":util",
"//ui/file_manager/base/js:volume_manager_types",
]
}
js_type_check("closure_compile_jsmodules") {
- uses_js_modules = true
deps = [
":async_util.m",
+ ":file_operation_common.m",
":file_type.m",
":files_app_entry_types.m",
+ ":importer_common.m",
":lru_cache.m",
":metrics.m",
":metrics_base.m",
":mock_entry.m",
+ ":progress_center_common.m",
+ ":storage_adapter.m",
+ ":trash.m",
":util.m",
]
+
+ closure_flags = strict_error_checking_closure_args + [
+ "js_module_root=./gen/ui",
+ "js_module_root=../../ui",
+ "hide_warnings_for=third_party/",
+ ]
}
js_type_check("test_support_type_check") {
+ uses_legacy_modules = true
testonly = true
deps = [
":test_importer_common",
@@ -60,6 +78,18 @@ js_type_check("test_support_type_check") {
]
}
+js_type_check("test_support_modules_type_check") {
+ testonly = true
+ deps = [
+ ":test_importer_common.m",
+ ":unittest_util.m",
+ ]
+
+ closure_flags =
+ strict_error_checking_closure_args +
+ [ "browser_resolver_prefix_replacements=\"chrome://test/=./\"" ]
+}
+
js_library("async_util") {
}
@@ -128,6 +158,21 @@ js_unittest("file_type_unittest.m") {
]
}
+js_library("file_operation_common") {
+ deps = [ ":util" ]
+ externs_list = [ "//ui/file_manager/externs/files_app_entry_interfaces.js" ]
+}
+
+js_library("file_operation_common.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/common/js/file_operation_common.m.js" ]
+ deps = [
+ ":util.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
# 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.
@@ -141,6 +186,21 @@ js_library("importer_common") {
]
}
+js_library("importer_common.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/common/js/importer_common.m.js",
+ ]
+ deps = [
+ ":file_type.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("test_importer_common") {
testonly = true
deps = [
@@ -153,13 +213,27 @@ js_library("test_importer_common") {
visibility = [ "//ui/file_manager/file_manager/*" ]
}
-js_unittest("importer_common_unittest") {
+js_library("test_importer_common.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/common/js/test_importer_common.m.js" ]
deps = [
- ":mock_entry",
- ":test_importer_common",
- ":util",
- "//ui/file_manager/base/js:mock_chrome",
- "//ui/file_manager/file_manager/background/js:mock_volume_manager",
+ ":importer_common.m",
+ ":unittest_util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("importer_common_unittest.m") {
+ deps = [
+ ":importer_common.m",
+ ":mock_entry.m",
+ ":test_importer_common.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
]
}
@@ -231,6 +305,50 @@ js_library("mock_entry.m") {
js_library("progress_center_common") {
}
+js_library("progress_center_common.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/common/js/progress_center_common.m.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("storage_adapter") {
+}
+
+js_library("storage_adapter.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/common/js/storage_adapter.m.js",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("trash") {
+ deps = [
+ "//ui/file_manager/base/js:volume_manager_types",
+ "//ui/file_manager/file_manager/common/js:files_app_entry_types",
+ ]
+ externs_list = [
+ "//ui/file_manager/externs/files_app_entry_interfaces.js",
+ "//ui/file_manager/externs/volume_info.js",
+ "//ui/file_manager/externs/volume_manager.js",
+ ]
+}
+
+js_library("trash.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/file_manager/common/js/trash.m.js" ]
+ deps = [
+ ":files_app_entry_types.m",
+ ":util.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("unittest_util") {
testonly = true
@@ -241,6 +359,15 @@ js_library("unittest_util") {
externs_list = [ "$externs_path/command_line_private.js" ]
}
+js_library("unittest_util.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/common/js/unittest_util.m.js",
+ ]
+ deps = [ "//chrome/test/data/webui:chai_assert" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("util") {
deps = [
":files_app_entry_types",
@@ -307,6 +434,7 @@ js_test_gen_html("js_test_gen_html_modules") {
deps = [
":file_type_unittest.m",
":files_app_entry_types_unittest.m",
+ ":importer_common_unittest.m",
":lru_cache_unittest.m",
":util_unittest.m",
]
@@ -320,19 +448,22 @@ js_test_gen_html("js_test_gen_html_modules") {
]
}
-js_test_gen_html("js_test_gen_html") {
- deps = [ ":importer_common_unittest" ]
-}
-
js_modulizer("modulize") {
input_files = [
"async_util.js",
+ "file_operation_common.js",
"file_type.js",
"files_app_entry_types.js",
+ "importer_common.js",
"lru_cache.js",
"metrics.js",
"metrics_base.js",
"mock_entry.js",
+ "progress_center_common.js",
+ "storage_adapter.js",
+ "test_importer_common.js",
+ "trash.js",
+ "unittest_util.js",
"util.js",
]
diff --git a/chromium/ui/file_manager/file_manager/cws_widget/BUILD.gn b/chromium/ui/file_manager/file_manager/cws_widget/BUILD.gn
index 32d3948712f..d2a1b7ddc2d 100644
--- a/chromium/ui/file_manager/file_manager/cws_widget/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/cws_widget/BUILD.gn
@@ -3,8 +3,28 @@
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
+import("//ui/webui/resources/js/cr.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
-js_type_check("closure_compile") {
+group("closure_compile") {
+ testonly = true
+ deps = [
+ ":closure_compile_jsmodules",
+ ":closure_compile_module",
+ ]
+}
+
+js_type_check("closure_compile_jsmodules") {
+ deps = [
+ ":app_installer.m",
+ ":cws_webview_client.m",
+ ":cws_widget_container.m",
+ ":cws_widget_container_error_dialog.m",
+ ":cws_widget_container_platform_delegate.m",
+ ]
+}
+
+js_type_check("closure_compile_module") {
deps = [
":app_installer",
":cws_webview_client",
@@ -18,6 +38,15 @@ js_library("app_installer") {
deps = [ ":cws_widget_container_platform_delegate" ]
}
+js_library("app_installer.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/cws_widget/app_installer.m.js",
+ ]
+ deps = [ ":cws_widget_container_platform_delegate.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("cws_widget_container") {
deps = [
":app_installer",
@@ -26,13 +55,47 @@ js_library("cws_widget_container") {
]
}
+js_library("cws_widget_container.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/cws_widget/cws_widget_container.m.js" ]
+ deps = [
+ ":app_installer.m",
+ ":cws_webview_client.m",
+ ":cws_widget_container_error_dialog.m",
+ ":cws_widget_container_platform_delegate.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+ externs_list = [ "$externs_path/webview_tag.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("cws_widget_container_error_dialog") {
- deps = [ "//ui/webui/resources/js/cr/ui:dialogs" ]
+ deps = [
+ "../common/js:util",
+ "//ui/webui/resources/js/cr/ui:dialogs",
+ ]
+}
+
+js_library("cws_widget_container_error_dialog.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/cws_widget/cws_widget_container_error_dialog.m.js" ]
+
+ deps = [
+ "../common/js:util.m",
+ "//ui/webui/resources/js/cr/ui:dialogs.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
}
js_library("cws_widget_container_platform_delegate") {
}
+js_library("cws_widget_container_platform_delegate.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/cws_widget/cws_widget_container_platform_delegate.m.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("cws_webview_client") {
deps = [
":cws_widget_container_platform_delegate",
@@ -44,3 +107,27 @@ js_library("cws_webview_client") {
"$externs_path/webview_tag.js",
]
}
+
+js_library("cws_webview_client.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/cws_widget/cws_webview_client.m.js" ]
+ deps = [
+ ":cws_widget_container_platform_delegate.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+ externs_list = [ "$externs_path/webview_tag.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_modulizer("modulize") {
+ input_files = [
+ "cws_widget_container_error_dialog.js",
+ "cws_widget_container.js",
+ "cws_webview_client.js",
+ "app_installer.js",
+ "cws_widget_container_platform_delegate.js",
+ ]
+
+ namespace_rewrites = cr_namespace_rewrites
+}
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 bdd5bef84af..acd4f7f4c10 100644
--- a/chromium/ui/file_manager/file_manager/foreground/elements/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/foreground/elements/BUILD.gn
@@ -4,22 +4,42 @@
import("//third_party/closure_compiler/compile_js.gni")
import("//third_party/closure_compiler/js_unit_tests.gni")
-import("//ui/file_manager/base/gn/js_test_gen_html.gni")
import("//tools/polymer/polymer.gni")
+import("//ui/file_manager/base/gn/js_test_gen_html.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
visibility = [ "//ui/file_manager/file_manager/foreground/*" ]
+group("elements") {
+ visibility += [ "//ui/file_manager/*" ]
+ public_deps = [
+ "//ui/file_manager/file_manager/foreground/elements:files_format_dialog_module",
+ "//ui/file_manager/file_manager/foreground/elements:files_icon_button_module",
+ "//ui/file_manager/file_manager/foreground/elements:files_metadata_box_module",
+ "//ui/file_manager/file_manager/foreground/elements:files_metadata_entry_module",
+ "//ui/file_manager/file_manager/foreground/elements:files_quick_view_module",
+ "//ui/file_manager/file_manager/foreground/elements:files_ripple_module",
+ "//ui/file_manager/file_manager/foreground/elements:files_safe_media_module",
+ "//ui/file_manager/file_manager/foreground/elements:files_spinner",
+ "//ui/file_manager/file_manager/foreground/elements:files_toast_module",
+ "//ui/file_manager/file_manager/foreground/elements:files_toggle_ripple_module",
+ "//ui/file_manager/file_manager/foreground/elements:files_tooltip_module",
+ "//ui/file_manager/file_manager/foreground/elements:icons_module",
+ ]
+}
+
group("closure_compile") {
testonly = true
visibility += [ "//ui/file_manager:closure_compile" ]
deps = [
":closure_compile_internal",
":closure_compile_jsmodules",
- ":js_test_gen_html_type_check_auto",
+ ":js_test_gen_html_modules_type_check_auto",
]
}
js_type_check("closure_compile_internal") {
+ uses_legacy_modules = true
deps = [
":files_format_dialog",
":files_icon_button",
@@ -45,9 +65,23 @@ js_type_check("closure_compile_internal") {
js_type_check("closure_compile_jsmodules") {
is_polymer3 = true
deps = [
+ ":files_format_dialog.m",
":files_icon_button.m",
- ":files_toggle_ripple.m",
+ ":files_message.m",
+ ":files_metadata_box.m",
+ ":files_metadata_entry.m",
+ ":files_password_dialog.m",
+ ":files_quick_view.m",
":files_ripple.m",
+ ":files_safe_media.m",
+ ":files_spinner.m",
+ ":files_toast.m",
+ ":files_toggle_ripple.m",
+ ":files_tooltip.m",
+ ":xf_button.m",
+ ":xf_circular_progress.m",
+ ":xf_display_panel.m",
+ ":xf_panel_item.m",
]
}
@@ -61,6 +95,38 @@ js_library("files_format_dialog") {
]
}
+polymer_modulizer("files_format_dialog") {
+ js_file = "files_format_dialog.js"
+ html_file = "files_format_dialog.html"
+ html_type = "dom-module"
+ preserve_url_scheme = true
+
+ auto_imports = [
+ "ui/file_manager/file_manager/common/js/util.html|util",
+ "ui/file_manager/file_manager/common/js/files_app_entry_types.html|EntryList,VolumeEntry",
+ "ui/file_manager/base/js/volume_manager_types.html|VolumeManagerCommon",
+ "ui/file_manager/externs/volume_info.html|VolumeInfo",
+ ]
+}
+
+js_library("files_format_dialog.m") {
+ visibility += [ "//ui/file_manager/audio_player/*" ]
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_format_dialog.m.js" ]
+ deps = [
+ "//third_party/polymer/v3_0/components-chromium/iron-icon:iron-icon",
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
+ "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
+ "//ui/webui/resources/js:i18n_behavior.m",
+ ]
+ extra_deps = [ ":files_format_dialog_module" ]
+}
+
js_library("files_icon_button") {
deps = [
"//third_party/polymer/v1_0/components-chromium/iron-behaviors:iron-button-state-extracted",
@@ -87,14 +153,12 @@ polymer_modulizer("files_icon_button") {
js_library("files_icon_button.m") {
visibility += [ "//ui/file_manager/audio_player/*" ]
- sources = [
- "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_icon_button.m.js",
- ]
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_icon_button.m.js" ]
deps = [
+ ":files_toggle_ripple.m",
"//third_party/polymer/v3_0/components-chromium/iron-behaviors:iron-button-state",
"//third_party/polymer/v3_0/components-chromium/iron-behaviors:iron-control-state",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
- ":files_toggle_ripple.m",
]
extra_deps = [ ":files_icon_button_module" ]
}
@@ -107,20 +171,62 @@ js_library("files_message") {
]
}
-js_unittest("files_message_unittest") {
+js_unittest("files_message_unittest.m") {
deps = [
- ":files_message",
- "//ui/webui/resources/js:webui_resource_test",
+ ":files_message.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/webui/resources/js:assert.m",
]
}
+js_library("files_message.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_message.m.js" ]
+ deps = [
+ "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
+ "//ui/webui/resources/cr_elements/cr_icon_button:cr_icon_button.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("files_metadata_box") {
externs_list = [ "$externs_path/pending_polymer.js" ]
}
+polymer_modulizer("files_metadata_box") {
+ js_file = "files_metadata_box.js"
+ html_file = "files_metadata_box.html"
+ html_type = "dom-module"
+ preserve_url_scheme = true
+}
+
+js_library("files_metadata_box.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_metadata_box.m.js" ]
+ deps = [
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ ]
+ extra_deps = [ ":files_metadata_box_module" ]
+}
+
js_library("files_metadata_entry") {
}
+polymer_modulizer("files_metadata_entry") {
+ js_file = "files_metadata_entry.js"
+ html_file = "files_metadata_entry.html"
+ html_type = "dom-module"
+ preserve_url_scheme = true
+}
+
+js_library("files_metadata_entry.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.m.js" ]
+ deps = [
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ ]
+ extra_deps = [ ":files_metadata_entry_module" ]
+}
+
js_library("files_password_dialog") {
deps = [
"//ui/file_manager/file_manager/common/js:async_util",
@@ -131,12 +237,26 @@ js_library("files_password_dialog") {
]
}
-js_unittest("files_password_dialog_unittest") {
+js_unittest("files_password_dialog_unittest.m") {
deps = [
- ":files_password_dialog",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/webui/resources/js:webui_resource_test",
+ ":files_password_dialog.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+}
+
+js_library("files_password_dialog.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_password_dialog.m.js" ]
+ deps = [
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
+ "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
+
+ extra_deps = [ ":modulize" ]
}
js_library("files_quick_view") {
@@ -148,6 +268,28 @@ js_library("files_quick_view") {
]
}
+polymer_modulizer("files_quick_view") {
+ js_file = "files_quick_view.js"
+ html_file = "files_quick_view.html"
+ html_type = "dom-module"
+ preserve_url_scheme = true
+
+ auto_imports = [ "ui/webui/resources/html/assert.html|assert" ]
+}
+
+js_library("files_quick_view.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_quick_view.m.js" ]
+ deps = [
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ "//ui/webui/resources/js:assert.m",
+ ]
+ externs_list = [
+ "$externs_path/chrome_extensions.js",
+ "$externs_path/webview_tag.js",
+ ]
+ extra_deps = [ ":files_quick_view_module" ]
+}
+
js_library("files_ripple") {
deps = [ "//ui/webui/resources/js:assert" ]
}
@@ -158,13 +300,12 @@ polymer_modulizer("files_ripple") {
html_type = "dom-module"
preserve_url_scheme = true
- auto_imports = [ "ui/webui/resources/html/assert.html|assert,assertInstanceof" ]
+ auto_imports =
+ [ "ui/webui/resources/html/assert.html|assert,assertInstanceof" ]
}
js_library("files_ripple.m") {
- sources = [
- "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_ripple.m.js",
- ]
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_ripple.m.js" ]
deps = [
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/js:assert.m",
@@ -175,12 +316,37 @@ js_library("files_ripple.m") {
js_library("files_safe_media") {
}
+polymer_modulizer("files_safe_media") {
+ js_file = "files_safe_media.js"
+ html_file = "files_safe_media.html"
+ html_type = "dom-module"
+ preserve_url_scheme = true
+
+ auto_imports =
+ [ "ui/webui/resources/html/assert.html|assert,assertInstanceof" ]
+}
+
+js_library("files_safe_media.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_safe_media.m.js" ]
+ deps = [
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ "//ui/webui/resources/js:assert.m",
+ ]
+ extra_deps = [ ":files_safe_media_module" ]
+}
+
js_library("files_safe_media_webview_content") {
}
js_library("files_spinner") {
}
+js_library("files_spinner.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_spinner.m.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
# TODO(tapted): Move this to //ui/file_manager/base.
js_library("files_toast") {
visibility += [ "//ui/file_manager/gallery/*" ]
@@ -190,6 +356,23 @@ js_library("files_toast") {
]
}
+polymer_modulizer("files_toast") {
+ js_file = "files_toast.js"
+ html_file = "files_toast.html"
+ html_type = "dom-module"
+ preserve_url_scheme = true
+}
+
+js_library("files_toast.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_toast.m.js" ]
+ deps = [
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
+ "//ui/webui/resources/cr_elements/cr_toast:cr_toast.m",
+ ]
+ extra_deps = [ ":files_toast_module" ]
+}
+
# TODO(tapted): Move this to //ui/file_manager/base.
js_library("files_toggle_ripple") {
visibility += [ "//ui/file_manager/gallery/*" ]
@@ -204,9 +387,7 @@ polymer_modulizer("files_toggle_ripple") {
js_library("files_toggle_ripple.m") {
visibility += [ "//ui/file_manager/audio_player/*" ]
- sources = [
- "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_toggle_ripple.m.js",
- ]
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_toggle_ripple.m.js" ]
deps = [
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
]
@@ -219,38 +400,53 @@ js_library("files_tooltip") {
deps = [ "//ui/file_manager/file_manager/common/js:util" ]
}
-js_unittest("files_tooltip_unittest") {
+js_unittest("files_tooltip_unittest.m") {
deps = [
- ":files_tooltip",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/webui/resources/js:webui_resource_test",
+ ":files_tooltip.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
]
}
-js_unittest("files_toast_unittest") {
+polymer_modulizer("files_tooltip") {
+ js_file = "files_tooltip.js"
+ html_file = "files_tooltip.html"
+ html_type = "dom-module"
+ preserve_url_scheme = true
+}
+
+js_library("files_tooltip.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/files_tooltip.m.js" ]
deps = [
- ":files_toast",
- "//ui/webui/resources/js:webui_resource_test",
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
]
+ extra_deps = [ ":files_tooltip_module" ]
}
-js_unittest("files_xf_elements_unittest") {
+js_unittest("files_toast_unittest.m") {
deps = [
- ":xf_display_panel",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:webui_resource_test",
+ ":files_toast.m",
+ "//chrome/test/data/webui:chai_assert",
]
}
-js_test_gen_html("js_test_gen_html") {
+js_unittest("files_xf_elements_unittest.m") {
deps = [
- ":files_message_unittest",
- ":files_password_dialog_unittest",
- ":files_toast_unittest",
- ":files_tooltip_unittest",
- ":files_xf_elements_unittest",
+ ":xf_display_panel.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
- html_import = true
+
+ externs_list = [ "$externs_path/file_manager_private.js" ]
+}
+
+polymer_modulizer("icons") {
+ js_file = "icons.m.js"
+ html_file = "icons.html"
+ html_type = "iron-iconset"
+ preserve_url_scheme = true
}
js_library("xf_button") {
@@ -260,9 +456,26 @@ js_library("xf_button") {
]
}
+js_library("xf_button.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/xf_button.m.js" ]
+ deps = [
+ "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
+ "//ui/webui/resources/cr_elements/cr_icon_button:cr_icon_button.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("xf_circular_progress") {
}
+js_library("xf_circular_progress.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/xf_circular_progress.m.js" ]
+
+ deps = [ "//ui/webui/resources/js:assert.m" ]
+ extra_deps = [ ":modulize" ]
+}
+
js_library("xf_display_panel") {
deps = [
":xf_panel_item",
@@ -270,9 +483,63 @@ js_library("xf_display_panel") {
]
}
+js_library("xf_display_panel.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/xf_display_panel.m.js" ]
+ deps = [
+ ":xf_panel_item.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_modulizer("modulize") {
+ input_files = [
+ "files_message.js",
+ "files_spinner.js",
+ "files_password_dialog.js",
+ "xf_button.js",
+ "xf_circular_progress.js",
+ "xf_panel_item.js",
+ "xf_display_panel.js",
+ ]
+}
+
+js_test_gen_html("js_test_gen_html_modules") {
+ is_polymer3 = true
+ deps = [
+ ":files_message_unittest.m",
+ ":files_password_dialog_unittest.m",
+ ":files_toast_unittest.m",
+ ":files_tooltip_unittest.m",
+ ":files_xf_elements_unittest.m",
+ ]
+
+ closure_flags =
+ strict_error_checking_closure_args + [
+ "generate_exports=false",
+ "js_module_root=./gen/ui",
+ "js_module_root=../../ui",
+ "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
+ "hide_warnings_for=third_party/",
+ ]
+}
+
js_library("xf_panel_item") {
deps = [
":xf_button",
":xf_circular_progress",
]
}
+
+js_library("xf_panel_item.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/elements/xf_panel_item.m.js" ]
+ deps = [
+ ":xf_button.m",
+ ":xf_circular_progress.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
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 14880668adc..58c917fde2b 100644
--- a/chromium/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -2,11 +2,15 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//chrome/browser/resources/tools/optimize_webui.gni")
import("//third_party/closure_compiler/compile_js.gni")
import("//third_party/closure_compiler/js_unit_tests.gni")
import("//ui/file_manager/base/gn/js_test_gen_html.gni")
+import("//ui/webui/resources/js/cr.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
visibility = [
+ "//ui/file_manager/externs/*",
"//ui/file_manager/file_manager/foreground/*",
"//ui/file_manager/file_manager/test/*",
]
@@ -15,13 +19,83 @@ group("closure_compile") {
testonly = true
visibility += [ "//ui/file_manager:closure_compile" ]
deps = [
+ ":closure_compile_jsmodules",
":closure_compile_module",
- ":js_test_gen_html_type_check_auto",
+ ":js_test_gen_html_modules_type_check_auto",
":test_support_type_check",
]
}
+js_type_check("closure_compile_jsmodules") {
+ is_polymer3 = true
+ deps = [
+ ":actions_controller.m",
+ ":actions_model.m",
+ ":android_app_list_model.m",
+ ":app_state_controller.m",
+ ":column_visibility_controller.m",
+ ":constants.m",
+ ":crossover_search_utils.m",
+ ":crostini_controller.m",
+ ":deferred_elements.m",
+ ":dialog_action_controller.m",
+ ":dialog_type.m",
+ ":directory_contents.m",
+ ":directory_model.m",
+ ":directory_tree_naming_controller.m",
+ ":drive_dialog_controller.m",
+ ":drop_effect_and_label.m",
+ ":elements_importer.m",
+ ":empty_folder_controller.m",
+ ":fake_android_app_list_model.m",
+ ":fake_file_selection_handler.m",
+ ":file_list_model.m",
+ ":file_manager.m",
+ ":file_manager_commands.m",
+ ":file_selection.m",
+ ":file_tasks.m",
+ ":file_transfer_controller.m",
+ ":file_type_filters_controller.m",
+ ":file_watcher.m",
+ ":folder_shortcuts_data_model.m",
+ ":gear_menu_controller.m",
+ ":holding_space_util.m",
+ ":import_controller.m",
+ ":last_modified_controller.m",
+ ":launch_param.m",
+ ":list_thumbnail_loader.m",
+ ":main.m",
+ ":main_window_component.m",
+ ":metadata_box_controller.m",
+ ":metadata_update_controller.m",
+ ":mock_directory_model.m",
+ ":mock_folder_shortcut_data_model.m",
+ ":mock_navigation_list_model.m",
+ ":mock_thumbnail_loader.m",
+ ":naming_controller.m",
+ ":navigation_list_model.m",
+ ":navigation_uma.m",
+ ":path_component.m",
+ ":providers_model.m",
+ ":quick_view_controller.m",
+ ":quick_view_model.m",
+ ":quick_view_uma.m",
+ ":scan_controller.m",
+ ":search_controller.m",
+ ":selection_menu_controller.m",
+ ":sort_menu_controller.m",
+ ":spinner_controller.m",
+ ":task_controller.m",
+ ":task_history.m",
+ ":thumbnail_loader.m",
+ ":toolbar_controller.m",
+ ":web_store_utils.m",
+ ":webui_command_extender.m",
+ ]
+}
+
js_type_check("closure_compile_module") {
+ uses_legacy_modules = true
deps = [
":actions_controller",
":actions_model",
@@ -37,6 +111,7 @@ js_type_check("closure_compile_module") {
":directory_contents",
":directory_model",
":directory_tree_naming_controller",
+ ":drive_dialog_controller",
":drop_effect_and_label",
":elements_importer",
":empty_folder_controller",
@@ -63,7 +138,6 @@ js_type_check("closure_compile_module") {
":navigation_list_model",
":navigation_uma",
":path_component",
- ":progress_center_item_group",
":providers_model",
":quick_view_controller",
":quick_view_model",
@@ -89,10 +163,9 @@ js_library("closure_compile_externs") {
"$externs_path/metrics_private.js",
"//ui/file_manager/externs/background/crostini.js",
"//ui/file_manager/externs/background/drive_sync_handler.js",
- "//ui/file_manager/externs/background/file_browser_background.js",
+ "//ui/file_manager/externs/background/background_base.js",
"//ui/file_manager/externs/background/file_browser_background_full.js",
"//ui/file_manager/externs/background/file_operation_manager.js",
- "//ui/file_manager/externs/background/import_runner.js",
"//ui/file_manager/externs/background/media_import_handler.js",
"//ui/file_manager/externs/background/task_queue.js",
"//ui/file_manager/externs/background/duplicate_finder.js",
@@ -104,6 +177,7 @@ js_library("closure_compile_externs") {
"//ui/file_manager/externs/command_handler_deps.js",
"//ui/file_manager/externs/css_rule.js",
"//ui/file_manager/externs/directory_change_event.js",
+ "//ui/file_manager/externs/drive_dialog_controller.js",
"//ui/file_manager/externs/entries_changed_event.js",
"//ui/file_manager/externs/gallery_foreground.js",
"//ui/file_manager/externs/menu_item_update_event.js",
@@ -114,6 +188,7 @@ js_library("closure_compile_externs") {
}
js_type_check("test_support_type_check") {
+ uses_legacy_modules = true
testonly = true
deps = [
":fake_android_app_list_model",
@@ -137,6 +212,23 @@ js_library("actions_controller") {
]
}
+js_library("actions_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/actions_controller.m.js" ]
+ deps = [
+ ":actions_model.m",
+ ":directory_model.m",
+ ":file_selection.m",
+ ":folder_shortcuts_data_model.m",
+ "metadata:metadata_model.m",
+ "ui:file_manager_ui.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:drive_sync_handler.m",
+ "//ui/webui/resources/js/cr/ui:context_menu_handler.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("actions_model") {
deps = [
":folder_shortcuts_data_model",
@@ -151,6 +243,25 @@ js_library("actions_model") {
[ "//ui/file_manager/externs/background/drive_sync_handler.js" ]
}
+js_library("actions_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/actions_model.m.js" ]
+ deps = [
+ ":folder_shortcuts_data_model.m",
+ "metadata:metadata_model.m",
+ "ui:action_model_ui.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:drive_sync_handler.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("mock_actions_model") {
testonly = true
deps = [
@@ -159,6 +270,16 @@ js_library("mock_actions_model") {
]
}
+js_library("mock_actions_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/mock_actions_model.m.js" ]
+ deps = [
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("fake_file_selection_handler") {
testonly = true
deps = [
@@ -167,15 +288,34 @@ js_library("fake_file_selection_handler") {
]
}
-js_unittest("actions_model_unittest") {
+js_library("fake_file_selection_handler.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.m.js" ]
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",
- "//ui/file_manager/file_manager/foreground/js/ui:action_model_ui",
+ ":file_selection.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("actions_model_unittest.m") {
+ deps = [
+ ":actions_model.m",
+ ":folder_shortcuts_data_model.m",
+ "metadata:mock_metadata.m",
+ "ui:action_model_ui.m",
+ "ui:files_alert_dialog.m",
+ "ui:list_container.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/file_manager/background/js:mock_drive_sync_handler.m",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr:event_target.m",
]
}
@@ -184,6 +324,16 @@ js_library("fake_android_app_list_model") {
deps = [ ":android_app_list_model" ]
}
+js_library("fake_android_app_list_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/fake_android_app_list_model.m.js" ]
+ deps = [
+ ":android_app_list_model.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("mock_directory_model") {
testonly = true
deps = [
@@ -194,6 +344,18 @@ js_library("mock_directory_model") {
]
}
+js_library("mock_directory_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/mock_directory_model.m.js" ]
+ deps = [
+ ":directory_contents.m",
+ ":directory_model.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("mock_folder_shortcut_data_model") {
testonly = true
deps = [
@@ -203,20 +365,57 @@ js_library("mock_folder_shortcut_data_model") {
]
}
+js_library("mock_folder_shortcut_data_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/mock_folder_shortcut_data_model.m.js" ]
+ deps = [
+ ":folder_shortcuts_data_model.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/webui/resources/js/cr/ui:array_data_model.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("mock_navigation_list_model") {
testonly = true
deps = [ ":navigation_list_model" ]
}
+js_library("mock_navigation_list_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/mock_navigation_list_model.m.js" ]
+ deps = [
+ ":navigation_list_model.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("mock_thumbnail_loader") {
testonly = true
deps = [ ":thumbnail_loader" ]
}
+js_library("mock_thumbnail_loader.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/mock_thumbnail_loader.m.js" ]
+ deps = [ ":thumbnail_loader.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("android_app_list_model") {
deps = [ "//ui/webui/resources/js/cr:event_target" ]
}
+js_library("android_app_list_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/android_app_list_model.m.js" ]
+
+ deps = [ "//ui/webui/resources/js/cr:event_target.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("app_state_controller") {
deps = [
":dialog_type",
@@ -225,6 +424,21 @@ js_library("app_state_controller") {
]
}
+js_library("app_state_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/app_state_controller.m.js" ]
+ deps = [
+ ":dialog_type.m",
+ ":directory_model.m",
+ "ui:file_manager_ui.m",
+ "ui:list_container.m",
+ "//ui/file_manager/base/js:app_util.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("column_visibility_controller") {
deps = [
":directory_model",
@@ -233,12 +447,43 @@ js_library("column_visibility_controller") {
]
}
+js_library("column_visibility_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/column_visibility_controller.m.js" ]
+ deps = [
+ ":directory_model.m",
+ "ui:file_manager_ui.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("constants") {
}
+js_library("constants.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/constants.m.js",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("crossover_search_utils") {
}
+js_library("crossover_search_utils.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/crossover_search_utils.m.js" ]
+ deps = [
+ ":directory_model.m",
+ ":navigation_list_model.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("crostini_controller") {
deps = [
":directory_model",
@@ -248,6 +493,26 @@ js_library("crostini_controller") {
]
}
+js_library("crostini_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/crostini_controller.m.js" ]
+ deps = [
+ ":constants.m",
+ ":directory_model.m",
+ ":file_manager_commands.m",
+ ":navigation_list_model.m",
+ "ui:directory_tree.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs/background:crostini.m",
+ "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_message.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_toast.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("dialog_action_controller") {
deps = [
":dialog_type",
@@ -263,9 +528,40 @@ js_library("dialog_action_controller") {
]
}
+js_library("dialog_action_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/dialog_action_controller.m.js" ]
+ deps = [
+ ":dialog_type.m",
+ ":directory_contents.m",
+ ":directory_model.m",
+ ":file_selection.m",
+ ":launch_param.m",
+ ":naming_controller.m",
+ "metadata:metadata_model.m",
+ "ui:dialog_footer.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("dialog_type") {
}
+js_library("dialog_type.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/dialog_type.m.js",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("directory_contents") {
deps = [
":constants",
@@ -281,13 +577,33 @@ js_library("directory_contents") {
]
}
-js_unittest("directory_contents_unittest") {
+js_library("directory_contents.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/directory_contents.m.js" ]
deps = [
- ":directory_contents",
- ":directory_model",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/base/js:volume_manager_types",
- "//ui/file_manager/externs:volume_manager",
+ ":constants.m",
+ ":file_list_model.m",
+ "metadata:metadata_model.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("directory_contents_unittest.m") {
+ deps = [
+ ":directory_contents.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:entry_location.m",
+ "//ui/file_manager/externs:volume_manager.m",
]
}
@@ -304,6 +620,34 @@ js_library("directory_model") {
]
}
+js_library("directory_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/directory_model.m.js" ]
+ deps = [
+ ":constants.m",
+ ":directory_contents.m",
+ ":file_list_model.m",
+ ":file_watcher.m",
+ "metadata:metadata_model.m",
+ "ui:file_list_selection_model.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:entries_changed_event.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ "//ui/webui/resources/js/cr/ui:list_selection_model.m",
+ "//ui/webui/resources/js/cr/ui:list_single_selection_model.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("navigation_uma") {
deps = [
":dialog_type",
@@ -311,6 +655,17 @@ js_library("navigation_uma") {
]
}
+js_library("navigation_uma.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/navigation_uma.m.js" ]
+ deps = [
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("directory_tree_naming_controller") {
deps = [
":directory_model",
@@ -320,12 +675,75 @@ js_library("directory_tree_naming_controller") {
]
}
+js_library("directory_tree_naming_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/directory_tree_naming_controller.m.js" ]
+ deps = [
+ ":directory_model.m",
+ "ui:directory_tree.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr/ui:dialogs.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("drive_dialog_controller") {
+ deps = [
+ "ui:file_manager_ui",
+ "ui:files_confirm_dialog",
+ ]
+ externs_list = [ "//ui/file_manager/externs/drive_dialog_controller.js" ]
+}
+
+js_library("drive_dialog_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/drive_dialog_controller.m.js" ]
+ deps = [
+ "ui:file_manager_ui.m",
+ "ui:files_confirm_dialog.m",
+ "//ui/file_manager/externs:drive_dialog_controller.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("drop_effect_and_label") {
}
+js_library("drop_effect_and_label.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/drop_effect_and_label.m.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("elements_importer") {
}
+js_library("elements_importer.m") {
+ deps = [ ":deferred_elements.m" ]
+}
+
+js_library("deferred_elements.m") {
+ visibility += [ "//ui/file_manager:*" ]
+ deps = [
+ "//ui/file_manager/file_manager/foreground/elements:files_format_dialog.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_message.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_password_dialog.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_ripple.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_spinner.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_toast.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_toggle_ripple.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_tooltip.m",
+ "//ui/file_manager/file_manager/foreground/elements:xf_button.m",
+ "//ui/file_manager/file_manager/foreground/elements:xf_circular_progress.m",
+ "//ui/file_manager/file_manager/foreground/elements:xf_display_panel.m",
+ "//ui/file_manager/file_manager/foreground/elements:xf_panel_item.m",
+ "//ui/webui/resources/cr_elements/cr_toggle:cr_toggle.m",
+ ]
+}
+
js_library("empty_folder_controller") {
deps = [
":directory_model",
@@ -334,6 +752,21 @@ js_library("empty_folder_controller") {
]
}
+js_library("empty_folder_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/empty_folder_controller.m.js" ]
+ deps = [
+ ":constants.m",
+ ":directory_model.m",
+ ":file_list_model.m",
+ "ui:empty_folder.m",
+ "ui:files_alert_dialog.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("file_list_model") {
deps = [
"metadata:metadata_model",
@@ -343,10 +776,25 @@ js_library("file_list_model") {
]
}
-js_unittest("file_list_model_unittest") {
+js_library("file_list_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/file_list_model.m.js" ]
deps = [
- ":file_list_model",
- "//ui/webui/resources/js:webui_resource_test",
+ "metadata:metadata_model.m",
+ "//ui/file_manager/externs:entry_location.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js/cr/ui:array_data_model.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_list_model_unittest.m") {
+ deps = [
+ ":file_list_model.m",
+ "metadata:metadata_model.m",
+ "//chrome/test/data/webui:chai_assert",
]
}
@@ -359,6 +807,7 @@ js_library("file_manager") {
":dialog_action_controller",
":dialog_type",
":directory_model",
+ ":drive_dialog_controller",
":elements_importer",
":empty_folder_controller",
":file_selection",
@@ -388,10 +837,98 @@ js_library("file_manager") {
"ui:directory_tree",
"ui:file_manager_ui",
"//ui/file_manager/base/js:filtered_volume_manager",
+ "//ui/file_manager/file_manager/common/js:storage_adapter",
"//ui/webui/resources/js/cr/ui:list_selection_model",
]
}
+js_library("file_manager.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/file_manager.m.js" ]
+ deps = [
+ ":actions_controller.m",
+ ":android_app_list_model.m",
+ ":app_state_controller.m",
+ ":column_visibility_controller.m",
+ ":crossover_search_utils.m",
+ ":crostini_controller.m",
+ ":dialog_action_controller.m",
+ ":dialog_type.m",
+ ":directory_contents.m",
+ ":directory_model.m",
+ ":directory_tree_naming_controller.m",
+ ":drive_dialog_controller.m",
+ ":empty_folder_controller.m",
+ ":file_manager_commands.m",
+ ":file_selection.m",
+ ":file_tasks.m",
+ ":file_transfer_controller.m",
+ ":file_type_filters_controller.m",
+ ":folder_shortcuts_data_model.m",
+ ":gear_menu_controller.m",
+ ":import_controller.m",
+ ":last_modified_controller.m",
+ ":launch_param.m",
+ ":list_thumbnail_loader.m",
+ ":main_window_component.m",
+ ":metadata_box_controller.m",
+ ":metadata_update_controller.m",
+ ":naming_controller.m",
+ ":navigation_list_model.m",
+ ":navigation_uma.m",
+ ":providers_model.m",
+ ":quick_view_controller.m",
+ ":quick_view_model.m",
+ ":quick_view_uma.m",
+ ":scan_controller.m",
+ ":search_controller.m",
+ ":selection_menu_controller.m",
+ ":sort_menu_controller.m",
+ ":spinner_controller.m",
+ ":task_controller.m",
+ ":toolbar_controller.m",
+ "metadata:content_metadata_provider.m",
+ "metadata:metadata_model.m",
+ "metadata:thumbnail_model.m",
+ "ui:a11y_announce.m",
+ "ui:banners.m",
+ "ui:commandbutton.m",
+ "ui:directory_tree.m",
+ "ui:file_grid.m",
+ "ui:file_list_selection_model.m",
+ "ui:file_manager_ui.m",
+ "ui:file_metadata_formatter.m",
+ "ui:file_table.m",
+ "//ui/file_manager/base/js:filtered_volume_manager.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:background_window.m",
+ "//ui/file_manager/externs:command_handler_deps.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs/background:crostini.m",
+ "//ui/file_manager/externs/background:file_browser_background_full.m",
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/file_manager/externs/background:import_history.m",
+ "//ui/file_manager/externs/background:media_import_handler.m",
+ "//ui/file_manager/externs/background:media_scanner.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:storage_adapter.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_message.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ "//ui/webui/resources/js/cr/ui:array_data_model.m",
+ "//ui/webui/resources/js/cr/ui:context_menu_handler.m",
+ "//ui/webui/resources/js/cr/ui:list.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("file_manager_commands") {
deps = [
":actions_controller",
@@ -402,29 +939,71 @@ js_library("file_manager_commands") {
":file_selection",
":file_tasks",
":file_transfer_controller",
+ ":holding_space_util",
":naming_controller",
":providers_model",
":spinner_controller",
":task_controller",
"ui:directory_tree",
"ui:file_manager_ui",
+ "//ui/file_manager/file_manager/common/js:file_operation_common",
"//ui/file_manager/file_manager/common/js:progress_center_common",
+ "//ui/file_manager/file_manager/common/js:storage_adapter",
"//ui/webui/resources/cr_elements/cr_input:cr_input",
]
externs_list = [
"//ui/file_manager/externs/background/file_operation_manager.js",
"//ui/file_manager/externs/background/progress_center.js",
"//ui/file_manager/externs/command_handler_deps.js",
- "//ui/file_manager/externs/file_operation_progress_event.js",
- "//ui/file_manager/externs/file_operation_util.js",
]
}
-js_unittest("file_manager_commands_unittest") {
- deps = [
- ":file_manager_commands",
- "//ui/file_manager/file_manager/background/js:mock_volume_manager",
- "//ui/webui/resources/js:webui_resource_test",
+js_library("file_manager_commands.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/file_manager_commands.m.js" ]
+ deps = [
+ ":actions_model.m",
+ ":constants.m",
+ ":dialog_type.m",
+ ":directory_model.m",
+ ":file_selection.m",
+ ":file_tasks.m",
+ ":holding_space_util.m",
+ ":path_component.m",
+ ":webui_command_extender.m",
+ "ui:directory_tree.m",
+ "ui:files_confirm_dialog.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:command_handler_deps.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:file_operation_common.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:trash.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_format_dialog.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
+ "//ui/webui/resources/js/cr/ui:context_menu_handler.m",
+ "//ui/webui/resources/js/cr/ui:list.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_manager_commands_unittest.m") {
+ deps = [
+ ":file_manager_commands.m",
+ ":file_tasks.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
}
@@ -442,6 +1021,26 @@ js_library("file_selection") {
]
}
+js_library("file_selection.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/file_selection.m.js" ]
+ deps = [
+ ":constants.m",
+ ":directory_model.m",
+ "metadata:metadata_model.m",
+ "ui:list_container.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("file_tasks") {
deps = [
":directory_model",
@@ -458,15 +1057,65 @@ js_library("file_tasks") {
]
}
-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/background/js:mock_progress_center",
- "//ui/file_manager/file_manager/common/js:mock_entry",
+js_library("file_tasks.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/file_tasks.m.js",
+ ]
+ deps = [
+ ":constants.m",
+ ":directory_model.m",
+ ":file_transfer_controller.m",
+ ":naming_controller.m",
+ ":task_history.m",
+ ":web_store_utils.m",
+ "metadata:metadata_model.m",
+ "ui:combobutton.m",
+ "ui:default_task_dialog.m",
+ "ui:file_manager_ui.m",
+ "ui:files_confirm_dialog.m",
+ "ui:files_menu.m",
+ "ui:multi_menu_button.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:crostini.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_password_dialog.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ "//ui/webui/resources/js/cr:ui.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_tasks_unittest.m") {
+ deps = [
+ ":directory_model.m",
+ ":file_tasks.m",
+ ":file_transfer_controller.m",
+ ":naming_controller.m",
+ ":task_history.m",
+ "metadata:metadata_model.m",
+ "ui:file_manager_ui.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:entry_location.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/background/js:mock_crostini.m",
+ "//ui/file_manager/file_manager/background/js:mock_progress_center.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_password_dialog.m",
]
}
@@ -483,19 +1132,71 @@ js_library("file_transfer_controller") {
"ui:list_container",
"ui:progress_center_panel",
"//ui/file_manager/file_manager/common/js:progress_center_common",
+ "//ui/file_manager/file_manager/common/js:storage_adapter",
]
externs_list = [ "//ui/file_manager/externs/background/progress_center.js" ]
}
-js_unittest("file_transfer_controller_unittest") {
- deps = [
- ":fake_file_selection_handler",
- ":file_transfer_controller",
- "//ui/file_manager/base/js:mock_chrome",
- "//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/metadata:mock_metadata",
- "//ui/webui/resources/js:webui_resource_test",
+js_library("file_transfer_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/file_transfer_controller.m.js" ]
+ deps = [
+ ":directory_model.m",
+ ":drop_effect_and_label.m",
+ ":file_selection.m",
+ ":thumbnail_loader.m",
+ "metadata:metadata_model.m",
+ "metadata:thumbnail_model.m",
+ "ui:directory_tree.m",
+ "ui:drag_selector.m",
+ "ui:list_container.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:entry_location.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
+ "//ui/webui/resources/js/cr/ui:list.m",
+ "//ui/webui/resources/js/cr/ui:tree.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_transfer_controller_unittest.m") {
+ deps = [
+ ":dialog_type.m",
+ ":fake_file_selection_handler.m",
+ ":file_list_model.m",
+ ":file_selection.m",
+ ":file_transfer_controller.m",
+ ":mock_directory_model.m",
+ "metadata:mock_metadata.m",
+ "metadata:thumbnail_model.m",
+ "ui:a11y_announce.m",
+ "ui:directory_tree.m",
+ "ui:file_grid.m",
+ "ui:file_table.m",
+ "ui:list_container.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/file_manager/externs/background:import_history.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr:ui.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
+ "//ui/webui/resources/js/cr/ui:list_selection_model.m",
]
}
@@ -506,10 +1207,28 @@ js_library("file_type_filters_controller") {
]
}
-js_unittest("file_type_filters_controller_unittest") {
+js_library("file_type_filters_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/file_type_filters_controller.m.js" ]
deps = [
- ":file_type_filters_controller",
- "//ui/webui/resources/js:webui_resource_test",
+ ":directory_model.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_type_filters_controller_unittest.m") {
+ deps = [
+ ":directory_model.m",
+ ":file_type_filters_controller.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ "//ui/webui/resources/js/cr:event_target.m",
]
}
@@ -522,6 +1241,19 @@ js_library("file_watcher") {
]
}
+js_library("file_watcher.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/file_watcher.m.js" ]
+ deps = [
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("folder_shortcuts_data_model") {
deps = [
"//ui/file_manager/base/js:filtered_volume_manager",
@@ -533,6 +1265,20 @@ js_library("folder_shortcuts_data_model") {
]
}
+js_library("folder_shortcuts_data_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.m.js" ]
+ deps = [
+ "//ui/file_manager/base/js:filtered_volume_manager.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("gear_menu_controller") {
deps = [
":directory_model",
@@ -542,6 +1288,42 @@ js_library("gear_menu_controller") {
]
}
+js_library("gear_menu_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/gear_menu_controller.m.js" ]
+ deps = [
+ ":directory_model.m",
+ ":file_manager_commands.m",
+ ":providers_model.m",
+ "ui:gear_menu.m",
+ "ui:multi_menu_button.m",
+ "ui:providers_menu.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:directory_change_event.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("holding_space_util") {
+ deps = [
+ "//ui/file_manager/base/js:volume_manager_types",
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:load_time_data",
+ ]
+}
+
+js_library("holding_space_util.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/holding_space_util.m.js" ]
+ deps = [
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("import_controller") {
deps = [
":actions_controller",
@@ -558,7 +1340,6 @@ js_library("import_controller") {
"//ui/file_manager/file_manager/common/js:importer_common",
]
externs_list = [
- "//ui/file_manager/externs/background/import_runner.js",
"//ui/file_manager/externs/background/media_import_handler.js",
"//ui/file_manager/externs/background/duplicate_finder.js",
"//ui/file_manager/externs/background/task_queue.js",
@@ -566,14 +1347,43 @@ js_library("import_controller") {
]
}
-js_unittest("import_controller_unittest") {
+js_library("import_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/import_controller.m.js" ]
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",
+ ":file_selection.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:command_handler_deps.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:media_import_handler.m",
+ "//ui/file_manager/externs/background:media_scanner.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("import_controller_unittest.m") {
+ deps = [
+ ":import_controller.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:media_import_handler.m",
+ "//ui/file_manager/externs/background:media_scanner.m",
+ "//ui/file_manager/file_manager/background/js:mock_media_scanner.m",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/webui/resources/js:assert.m",
]
}
@@ -584,6 +1394,17 @@ js_library("last_modified_controller") {
]
}
+js_library("last_modified_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/last_modified_controller.m.js" ]
+ deps = [
+ ":directory_model.m",
+ "ui:file_table.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("launch_param") {
deps = [
":dialog_type",
@@ -591,6 +1412,16 @@ js_library("launch_param") {
]
}
+js_library("launch_param.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/launch_param.m.js" ]
+ deps = [
+ ":dialog_type.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("list_thumbnail_loader") {
deps = [
":directory_model",
@@ -601,12 +1432,38 @@ js_library("list_thumbnail_loader") {
]
}
-js_unittest("list_thumbnail_loader_unittest") {
+js_library("list_thumbnail_loader.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.m.js" ]
deps = [
- ":list_thumbnail_loader",
- ":mock_thumbnail_loader",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/file_manager/common/js:mock_entry",
+ ":directory_model.m",
+ ":file_list_model.m",
+ ":thumbnail_loader.m",
+ "metadata:thumbnail_model.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:lru_cache.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("list_thumbnail_loader_unittest.m") {
+ deps = [
+ ":directory_model.m",
+ ":file_list_model.m",
+ ":list_thumbnail_loader.m",
+ ":mock_thumbnail_loader.m",
+ "metadata:metadata_model.m",
+ "metadata:thumbnail_model.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr:event_target.m",
]
}
@@ -619,6 +1476,15 @@ js_library("main") {
]
}
+js_library("main.m") {
+ visibility += [ "//ui/file_manager:*" ]
+ deps = [
+ ":file_manager.m",
+ ":metrics_start.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+}
+
js_library("main_window_component") {
deps = [
":app_state_controller",
@@ -632,6 +1498,29 @@ js_library("main_window_component") {
]
}
+js_library("main_window_component.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/main_window_component.m.js" ]
+ deps = [
+ ":app_state_controller.m",
+ ":dialog_type.m",
+ ":directory_contents.m",
+ ":directory_model.m",
+ ":file_selection.m",
+ ":naming_controller.m",
+ ":task_controller.m",
+ "ui:file_manager_ui.m",
+ "ui:file_tap_handler.m",
+ "ui:list_container.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:directory_change_event.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("metadata_box_controller") {
deps = [
":quick_view_model",
@@ -643,6 +1532,25 @@ js_library("metadata_box_controller") {
]
}
+js_library("metadata_box_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metadata_box_controller.m.js" ]
+ deps = [
+ ":path_component.m",
+ ":quick_view_model.m",
+ "metadata:metadata_item.m",
+ "metadata:metadata_model.m",
+ "ui:file_metadata_formatter.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_metadata_box.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_quick_view.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("metadata_update_controller") {
deps = [
":directory_model",
@@ -652,10 +1560,30 @@ js_library("metadata_update_controller") {
]
}
+js_library("metadata_update_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metadata_update_controller.m.js" ]
+ deps = [
+ ":directory_model.m",
+ "metadata:metadata_model.m",
+ "ui:file_metadata_formatter.m",
+ "ui:list_container.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("metrics_start") {
deps = [ "//ui/file_manager/file_manager/common/js:metrics" ]
}
+js_library("metrics_start.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metrics_start.m.js" ]
+ deps = [ "//ui/file_manager/file_manager/common/js:metrics.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("naming_controller") {
deps = [
":directory_contents",
@@ -666,56 +1594,114 @@ js_library("naming_controller") {
]
}
+js_library("naming_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/naming_controller.m.js" ]
+ deps = [
+ ":directory_contents.m",
+ ":directory_model.m",
+ ":file_selection.m",
+ "ui:list_container.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr/ui:dialogs.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("navigation_list_model") {
deps = [
":android_app_list_model",
":folder_shortcuts_data_model",
+ "//ui/file_manager/file_manager/common/js:trash",
"//ui/webui/resources/js/cr:event_target",
"//ui/webui/resources/js/cr/ui:array_data_model",
]
}
-js_unittest("navigation_list_model_unittest") {
+js_library("navigation_list_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/navigation_list_model.m.js" ]
deps = [
- ":fake_android_app_list_model",
- ":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",
+ ":android_app_list_model.m",
+ ":directory_model.m",
+ ":folder_shortcuts_data_model.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+ "//ui/file_manager/file_manager/common/js:trash.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ "//ui/webui/resources/js/cr:event_target.m",
]
-}
-js_library("path_component") {
- deps = [ "//ui/file_manager/base/js:volume_manager_types" ]
+ extra_deps = [ ":modulize" ]
}
-js_library("progress_center_item_group") {
+js_unittest("navigation_list_model_unittest.m") {
deps = [
- "//ui/file_manager/file_manager/common/js:progress_center_common",
- "//ui/file_manager/file_manager/common/js:util",
+ ":android_app_list_model.m",
+ ":directory_model.m",
+ ":fake_android_app_list_model.m",
+ ":mock_directory_model.m",
+ ":mock_folder_shortcut_data_model.m",
+ ":navigation_list_model.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+ "//ui/file_manager/file_manager/background/js:volume_info_impl.m",
+ "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
]
}
-js_unittest("progress_center_item_group_unittest") {
+js_library("path_component") {
+ deps = [ "//ui/file_manager/base/js:volume_manager_types" ]
+}
+
+js_library("path_component.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/path_component.m.js" ]
deps = [
- ":progress_center_item_group",
- "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
]
+
+ extra_deps = [ ":modulize" ]
}
js_library("providers_model") {
deps = [ "//ui/webui/resources/js:assert" ]
}
-js_unittest("providers_model_unittest") {
+js_library("providers_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/providers_model.m.js" ]
deps = [
- ":providers_model",
- "//ui/file_manager/base/js:mock_chrome",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/file_manager/background/js:mock_volume_manager",
- "//ui/webui/resources/js:load_time_data",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("providers_model_unittest.m") {
+ deps = [
+ ":providers_model.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+ "//ui/file_manager/file_manager/background/js:volume_info_impl.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
]
}
@@ -733,6 +1719,39 @@ js_library("quick_view_controller") {
]
}
+js_library("quick_view_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/quick_view_controller.m.js" ]
+ deps = [
+ ":constants.m",
+ ":dialog_type.m",
+ ":file_manager_commands.m",
+ ":file_selection.m",
+ ":file_tasks.m",
+ ":metadata_box_controller.m",
+ ":quick_view_model.m",
+ ":quick_view_uma.m",
+ ":task_controller.m",
+ ":thumbnail_loader.m",
+ "metadata:metadata_item.m",
+ "metadata:metadata_model.m",
+ "ui:file_list_selection_model.m",
+ "ui:files_confirm_dialog.m",
+ "ui:list_container.m",
+ "ui:multi_menu_button.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:command_handler_deps.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_quick_view.m",
+ "//ui/file_manager/image_loader:image_loader_client.m",
+ "//ui/file_manager/image_loader:load_image_request.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("quick_view_model") {
deps = [
"//ui/webui/resources/js:cr",
@@ -740,6 +1759,16 @@ js_library("quick_view_model") {
]
}
+js_library("quick_view_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/quick_view_model.m.js" ]
+ deps = [
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("quick_view_uma") {
deps = [
":dialog_type",
@@ -748,6 +1777,21 @@ js_library("quick_view_uma") {
]
}
+js_library("quick_view_uma.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/quick_view_uma.m.js" ]
+ deps = [
+ ":dialog_type.m",
+ ":file_tasks.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("scan_controller") {
deps = [
":directory_model",
@@ -758,6 +1802,19 @@ js_library("scan_controller") {
]
}
+js_library("scan_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/scan_controller.m.js" ]
+ deps = [
+ ":directory_model.m",
+ ":file_manager_commands.m",
+ ":file_selection.m",
+ ":spinner_controller.m",
+ "ui:list_container.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("search_controller") {
deps = [
":directory_model",
@@ -767,6 +1824,23 @@ js_library("search_controller") {
]
}
+js_library("search_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/search_controller.m.js" ]
+ deps = [
+ ":directory_model.m",
+ ":task_controller.m",
+ "ui:file_manager_ui.m",
+ "ui:location_line.m",
+ "ui:search_box.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:entry_location.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("selection_menu_controller") {
deps = [
":directory_model",
@@ -775,6 +1849,19 @@ js_library("selection_menu_controller") {
]
}
+js_library("selection_menu_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/selection_menu_controller.m.js" ]
+ deps = [
+ "ui:multi_menu_button.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_toggle_ripple.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_tooltip.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("sort_menu_controller") {
deps = [
":file_list_model",
@@ -782,15 +1869,33 @@ js_library("sort_menu_controller") {
]
}
+js_library("sort_menu_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/sort_menu_controller.m.js" ]
+ deps = [
+ ":file_list_model.m",
+ "ui:multi_menu_button.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_toggle_ripple.m",
+ "//ui/webui/resources/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("spinner_controller") {
}
-js_unittest("spinner_controller_unittest") {
+js_library("spinner_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/spinner_controller.m.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("spinner_controller_unittest.m") {
deps = [
- ":spinner_controller",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:util",
+ ":spinner_controller.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/webui/resources/js:assert.m",
]
}
@@ -808,15 +1913,55 @@ js_library("task_controller") {
externs_list = [ "//ui/file_manager/externs/background/progress_center.js" ]
}
-js_unittest("task_controller_unittest") {
- deps = [
- ":fake_file_selection_handler",
- ":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_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/task_controller.m.js" ]
+ deps = [
+ ":dialog_type.m",
+ ":directory_model.m",
+ ":file_selection.m",
+ ":file_tasks.m",
+ ":file_transfer_controller.m",
+ ":metadata_update_controller.m",
+ ":naming_controller.m",
+ ":task_history.m",
+ "metadata:metadata_model.m",
+ "ui:file_manager_ui.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:crostini.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("task_controller_unittest.m") {
+ deps = [
+ ":dialog_type.m",
+ ":directory_model.m",
+ ":fake_file_selection_handler.m",
+ ":file_selection.m",
+ ":metadata_update_controller.m",
+ ":naming_controller.m",
+ ":task_controller.m",
+ "metadata:mock_metadata.m",
+ "ui:file_manager_ui.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:progress_center.m",
+ "//ui/file_manager/file_manager/background/js:mock_crostini.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr:ui.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
]
}
@@ -824,6 +1969,16 @@ js_library("task_history") {
deps = [ "//ui/webui/resources/js/cr:event_target" ]
}
+js_library("task_history.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/task_history.m.js" ]
+ deps = [
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
# TODO(tapted): Move this into //ui/file_manager/base.
js_library("thumbnail_loader") {
visibility += [ "//ui/file_manager/gallery/*" ]
@@ -835,11 +1990,27 @@ js_library("thumbnail_loader") {
]
}
-js_unittest("thumbnail_loader_unittest") {
+js_library("thumbnail_loader.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/thumbnail_loader.m.js" ]
deps = [
- ":thumbnail_loader",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/file_manager/common/js:mock_entry",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:image_orientation.m",
+ "//ui/file_manager/image_loader:image_loader_client.m",
+ "//ui/file_manager/image_loader:load_image_request.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("thumbnail_loader_unittest.m") {
+ deps = [
+ ":thumbnail_loader.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/file_manager/image_loader:image_loader_client.m",
+ "//ui/file_manager/image_loader:load_image_request.m",
]
}
@@ -853,10 +2024,37 @@ js_library("toolbar_controller") {
]
}
+js_library("toolbar_controller.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/toolbar_controller.m.js" ]
+ deps = [
+ ":directory_model.m",
+ ":file_selection.m",
+ "ui:a11y_announce.m",
+ "ui:file_list_selection_model.m",
+ "ui:list_container.m",
+ "ui:location_line.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("web_store_utils") {
deps = [ ":constants" ]
}
+js_library("web_store_utils.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/web_store_utils.m.js" ]
+ deps = [ ":constants.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("webui_command_extender") {
deps = [
"//ui/webui/resources/js:cr",
@@ -864,23 +2062,160 @@ js_library("webui_command_extender") {
]
}
-js_test_gen_html("js_test_gen_html") {
- deps = [
- ":actions_model_unittest",
- ":directory_contents_unittest",
- ":file_list_model_unittest",
- ":file_manager_commands_unittest",
- ":file_tasks_unittest",
- ":file_transfer_controller_unittest",
- ":file_type_filters_controller_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",
+js_library("webui_command_extender.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/webui_command_extender.m.js" ]
+ deps = [
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_test_gen_html("js_test_gen_html_modules") {
+ is_polymer3 = true
+ deps = [
+ ":actions_model_unittest.m",
+ ":directory_contents_unittest.m",
+ ":file_list_model_unittest.m",
+ ":file_manager_commands_unittest.m",
+ ":file_tasks_unittest.m",
+ ":file_transfer_controller_unittest.m",
+ ":file_type_filters_controller_unittest.m",
+ ":import_controller_unittest.m",
+ ":list_thumbnail_loader_unittest.m",
+ ":navigation_list_model_unittest.m",
+ ":providers_model_unittest.m",
+ ":spinner_controller_unittest.m",
+ ":task_controller_unittest.m",
+ ":thumbnail_loader_unittest.m",
+ ]
+
+ closure_flags =
+ strict_error_checking_closure_args + [
+ "generate_exports=false",
+ "js_module_root=./gen/ui",
+ "js_module_root=../../ui",
+ "jscomp_off=duplicate",
+ "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
+ "hide_warnings_for=third_party/",
+ "hide_warnings_for=third_party/",
+ ]
+}
+
+js_modulizer("modulize") {
+ input_files = [
+ "actions_controller.js",
+ "actions_model.js",
+ "android_app_list_model.js",
+ "app_state_controller.js",
+ "constants.js",
+ "crossover_search_utils.js",
+ "crostini_controller.js",
+ "column_visibility_controller.js",
+ "dialog_action_controller.js",
+ "dialog_type.js",
+ "directory_contents.js",
+ "directory_model.js",
+ "directory_tree_naming_controller.js",
+ "drive_dialog_controller.js",
+ "drop_effect_and_label.js",
+ "empty_folder_controller.js",
+ "fake_android_app_list_model.js",
+ "fake_file_selection_handler.js",
+ "file_list_model.js",
+ "file_manager.js",
+ "file_manager_commands.js",
+ "file_selection.js",
+ "file_tasks.js",
+ "file_transfer_controller.js",
+ "file_type_filters_controller.js",
+ "file_watcher.js",
+ "folder_shortcuts_data_model.js",
+ "gear_menu_controller.js",
+ "holding_space_util.js",
+ "import_controller.js",
+ "last_modified_controller.js",
+ "launch_param.js",
+ "list_thumbnail_loader.js",
+ "main_window_component.js",
+ "metadata_box_controller.js",
+ "metadata_update_controller.js",
+ "metrics_start.js",
+ "mock_actions_model.js",
+ "mock_directory_model.js",
+ "mock_folder_shortcut_data_model.js",
+ "mock_navigation_list_model.js",
+ "mock_thumbnail_loader.js",
+ "naming_controller.js",
+ "navigation_list_model.js",
+ "navigation_uma.js",
+ "path_component.js",
+ "providers_model.js",
+ "quick_view_controller.js",
+ "quick_view_model.js",
+ "quick_view_uma.js",
+ "scan_controller.js",
+ "search_controller.js",
+ "selection_menu_controller.js",
+ "sort_menu_controller.js",
+ "spinner_controller.js",
+ "task_controller.js",
+ "task_history.js",
+ "thumbnail_loader.js",
+ "toolbar_controller.js",
+ "web_store_utils.js",
+ "webui_command_extender.js",
+ ]
+
+ namespace_rewrites = cr_namespace_rewrites + [
+ "cr.ui.FilesMenuItem|FilesMenuItem",
+ "cr.ui.MultiMenu|MultiMenu",
+ "cr.ui.ComboButton|ComboButton",
+ "cr.filebrowser.DefaultTaskDialog|DefaultTaskDialog",
+ ]
+}
+
+preprocess_folder =
+ rebase_path(
+ "$target_gen_dir/../../../preprocessed/file_manager/foreground/js",
+ root_build_dir)
+
+optimize_webui("build") {
+ host = "file_manager"
+
+ input = preprocess_folder
+ js_module_in_files = [
+ "main.m.js",
+ "deferred_elements.m.js",
+ ]
+
+ js_out_files = [
+ "main.m.rollup.js",
+ "deferred_elements.m.rollup.js",
+ "shared.m.rollup.js",
+ ]
+
+ deps = [
+ ":main.m",
+ "//ui/file_manager:preprocess_generated",
+ "//ui/file_manager:preprocess_static",
+ "//ui/webui/resources:preprocess",
+ ]
+}
+
+optimize_webui("build_worker") {
+ host = "file_manager"
+
+ input = preprocess_folder
+ js_module_in_files = [ "metadata/metadata_dispatcher.m.js" ]
+
+ js_out_files = [ "metadata_dispatcher.m.rollup.js" ]
+
+ deps = [
+ "metadata:metadata_dispatcher.m",
+ "//ui/file_manager:preprocess_generated",
+ "//ui/file_manager:preprocess_static",
+ "//ui/webui/resources:preprocess",
]
- mocks = [ "$externs_path/file_manager_private.js" ]
}
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 6d32dd0f1c0..5205e2bbbcd 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
@@ -5,6 +5,7 @@
import("//third_party/closure_compiler/compile_js.gni")
import("//third_party/closure_compiler/js_unit_tests.gni")
import("//ui/file_manager/base/gn/js_test_gen_html.gni")
+import("//ui/webui/resources/js/cr.gni")
import("//ui/webui/resources/tools/js_modulizer.gni")
# TODO(tapted): This entire folder should move to //ui/file_manager/base.
@@ -16,31 +17,39 @@ group("closure_compile") {
":closure_compile_jsmodules",
":closure_compile_module",
":js_test_gen_html_modules_type_check_auto",
- ":js_test_gen_html_type_check_auto",
]
}
js_type_check("closure_compile_jsmodules") {
- uses_js_modules = true
deps = [
":byte_reader.m",
+ ":content_metadata_provider.m",
":exif_constants.m",
+ ":exif_parser.m",
":external_metadata_provider.m",
":file_system_metadata_provider.m",
":function_parallel.m",
":function_sequence.m",
+ ":id3_parser.m",
":image_orientation.m",
":image_parsers.m",
":metadata_cache_item.m",
+ ":metadata_cache_set.m",
+ ":metadata_dispatcher.m",
":metadata_item.m",
+ ":metadata_model.m",
":metadata_parser.m",
":metadata_provider.m",
":metadata_request.m",
+ ":mock_metadata.m",
":mpeg_parser.m",
+ ":multi_metadata_provider.m",
+ ":thumbnail_model.m",
]
}
js_type_check("closure_compile_module") {
+ uses_legacy_modules = true
deps = [
":byte_reader",
":content_metadata_provider",
@@ -85,10 +94,28 @@ js_library("content_metadata_provider") {
]
}
-js_unittest("content_metadata_provider_unittest") {
+js_library("content_metadata_provider.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.m.js" ]
deps = [
- ":content_metadata_provider",
- "//ui/file_manager/base/js:test_error_reporting",
+ ":metadata_item.m",
+ ":metadata_provider.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js:thumbnail_loader.m",
+ "//ui/file_manager/image_loader:image_loader_client.m",
+ "//ui/file_manager/image_loader:load_image_request.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("content_metadata_provider_unittest.m") {
+ deps = [
+ ":content_metadata_provider.m",
+ ":metadata_request.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
]
}
@@ -109,11 +136,27 @@ js_library("exif_parser") {
externs_list = [ "//ui/file_manager/externs/exif_entry.js" ]
}
-js_unittest("exif_parser_unittest") {
+js_library("exif_parser.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metadata/exif_parser.m.js" ]
deps = [
- ":exif_parser",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/gallery/js/image_editor:exif_encoder",
+ ":byte_reader.m",
+ ":exif_constants.m",
+ ":metadata_parser.m",
+ "//ui/file_manager/externs:exif_entry.m",
+ "//ui/file_manager/externs:metadata_worker_window.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("exif_parser_unittest.m") {
+ deps = [
+ ":byte_reader.m",
+ ":exif_constants.m",
+ ":exif_parser.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/externs:exif_entry.m",
+ "//ui/file_manager/externs:metadata_worker_window.m",
]
}
@@ -201,6 +244,19 @@ js_library("id3_parser") {
]
}
+js_library("id3_parser.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metadata/id3_parser.m.js" ]
+ deps = [
+ ":byte_reader.m",
+ ":function_parallel.m",
+ ":function_sequence.m",
+ ":metadata_parser.m",
+ "//ui/file_manager/externs:metadata_worker_window.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("image_orientation") {
}
@@ -269,10 +325,23 @@ js_library("metadata_cache_set") {
]
}
-js_unittest("metadata_cache_set_unittest") {
+js_library("metadata_cache_set.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set.m.js" ]
deps = [
- ":metadata_cache_set",
- "//ui/file_manager/base/js:test_error_reporting",
+ ":metadata_cache_item.m",
+ ":metadata_item.m",
+ ":metadata_request.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("metadata_cache_set_unittest.m") {
+ deps = [
+ ":metadata_cache_set.m",
+ "//chrome/test/data/webui:chai_assert",
]
}
@@ -288,6 +357,21 @@ js_library("metadata_dispatcher") {
externs_list = [ "//ui/file_manager/externs/platform.js" ]
}
+js_library("metadata_dispatcher.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metadata/metadata_dispatcher.m.js" ]
+ deps = [
+ ":exif_parser.m",
+ ":id3_parser.m",
+ ":image_parsers.m",
+ ":metadata_parser.m",
+ ":mpeg_parser.m",
+ "//ui/file_manager/externs:metadata_worker_window.m",
+ ]
+ externs_list = [ "//ui/file_manager/externs/platform.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("metadata_item") {
}
@@ -311,10 +395,29 @@ js_library("metadata_model") {
]
}
-js_unittest("metadata_model_unittest") {
+js_library("metadata_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metadata/metadata_model.m.js" ]
deps = [
- ":metadata_model",
- "//ui/file_manager/base/js:test_error_reporting",
+ ":content_metadata_provider.m",
+ ":external_metadata_provider.m",
+ ":file_system_metadata_provider.m",
+ ":metadata_cache_set.m",
+ ":metadata_item.m",
+ ":metadata_provider.m",
+ ":multi_metadata_provider.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("metadata_model_unittest.m") {
+ deps = [
+ ":metadata_model.m",
+ ":metadata_provider.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
]
}
@@ -364,6 +467,13 @@ js_library("mock_metadata") {
deps = [ ":metadata_model" ]
}
+js_library("mock_metadata.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metadata/mock_metadata.m.js" ]
+ deps = [ ":metadata_model.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("mpeg_parser") {
deps = [ ":metadata_parser" ]
}
@@ -389,10 +499,34 @@ js_library("multi_metadata_provider") {
]
}
-js_unittest("multi_metadata_provider_unittest") {
+js_library("multi_metadata_provider.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.m.js" ]
deps = [
- ":multi_metadata_provider",
- "//ui/file_manager/base/js:test_error_reporting",
+ ":content_metadata_provider.m",
+ ":external_metadata_provider.m",
+ ":file_system_metadata_provider.m",
+ ":metadata_item.m",
+ ":metadata_provider.m",
+ ":metadata_request.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("multi_metadata_provider_unittest.m") {
+ deps = [
+ ":content_metadata_provider.m",
+ ":external_metadata_provider.m",
+ ":file_system_metadata_provider.m",
+ ":metadata_request.m",
+ ":multi_metadata_provider.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
]
}
@@ -400,57 +534,76 @@ js_library("thumbnail_model") {
deps = [ ":metadata_model" ]
}
-js_unittest("thumbnail_model_unittest") {
+js_library("thumbnail_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.m.js" ]
deps = [
- ":thumbnail_model",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/webui/resources/js:webui_resource_test",
+ ":metadata_model.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("thumbnail_model_unittest.m") {
+ deps = [
+ ":metadata_item.m",
+ ":metadata_model.m",
+ ":thumbnail_model.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
]
}
js_test_gen_html("js_test_gen_html_modules") {
deps = [
+ ":content_metadata_provider_unittest.m",
+ ":exif_parser_unittest.m",
":external_metadata_provider_unittest.m",
":file_system_metadata_provider_unittest.m",
":image_orientation_unittest.m",
":metadata_cache_item_unittest.m",
+ ":metadata_cache_set_unittest.m",
+ ":metadata_model_unittest.m",
+ ":multi_metadata_provider_unittest.m",
+ ":thumbnail_model_unittest.m",
]
js_module = true
- closure_flags = strict_error_checking_closure_args + [
- "js_module_root=./gen/ui/file_manager/file_manager/foreground/js/metadata",
- "js_module_root=../../ui/file_manager/file_manager/foreground/js/metadata",
- "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
- ]
-}
-
-js_test_gen_html("js_test_gen_html") {
- deps = [
- ":content_metadata_provider_unittest",
- ":exif_parser_unittest",
- ":metadata_cache_set_unittest",
- ":metadata_model_unittest",
- ":multi_metadata_provider_unittest",
- ":thumbnail_model_unittest",
- ]
- mocks = [ "metadata_dispatcher_mock_deps.js" ]
+ closure_flags =
+ strict_error_checking_closure_args + [
+ "js_module_root=./gen/ui",
+ "js_module_root=../../ui",
+ "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
+ "hide_warnings_for=third_party/",
+ ]
}
js_modulizer("modulize") {
input_files = [
"byte_reader.js",
+ "content_metadata_provider.js",
"exif_constants.js",
+ "exif_parser.js",
"external_metadata_provider.js",
"file_system_metadata_provider.js",
"function_parallel.js",
"function_sequence.js",
+ "id3_parser.js",
+ "image_orientation.js",
"image_parsers.js",
"metadata_cache_item.js",
+ "metadata_cache_set.js",
+ "metadata_dispatcher.js",
"metadata_item.js",
+ "metadata_model.js",
"metadata_parser.js",
"metadata_request.js",
- "image_orientation.js",
"metadata_provider.js",
"mpeg_parser.js",
+ "multi_metadata_provider.js",
+ "mock_metadata.js",
+ "thumbnail_model.js",
]
+
+ namespace_rewrites = cr_namespace_rewrites
}
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 78ac8375f9e..dabe1d6c23b 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
@@ -5,6 +5,8 @@
import("//third_party/closure_compiler/compile_js.gni")
import("//third_party/closure_compiler/js_unit_tests.gni")
import("//ui/file_manager/base/gn/js_test_gen_html.gni")
+import("//ui/webui/resources/js/cr.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
visibility = [ "//ui/file_manager/file_manager/foreground/*" ]
@@ -12,12 +14,60 @@ group("closure_compile") {
testonly = true
visibility += [ "//ui/file_manager:closure_compile" ]
deps = [
+ ":closure_compile_jsmodules",
":closure_compile_module",
- ":js_test_gen_html_type_check_auto",
+ ":js_test_gen_html_modules_type_check_auto",
+ ]
+}
+
+js_type_check("closure_compile_jsmodules") {
+ is_polymer3 = true
+ deps = [
+ ":a11y_announce.m",
+ ":action_model_ui.m",
+ ":actions_submenu.m",
+ ":autocomplete_list.m",
+ ":banners.m",
+ ":breadcrumb.m",
+ ":combobutton.m",
+ ":commandbutton.m",
+ ":default_task_dialog.m",
+ ":dialog_footer.m",
+ ":directory_tree.m",
+ ":drag_selector.m",
+ ":empty_folder.m",
+ ":file_grid.m",
+ ":file_list_selection_model.m",
+ ":file_manager_dialog_base.m",
+ ":file_manager_ui.m",
+ ":file_metadata_formatter.m",
+ ":file_table.m",
+ ":file_table_list.m",
+ ":file_tap_handler.m",
+ ":files_alert_dialog.m",
+ ":files_confirm_dialog.m",
+ ":files_menu.m",
+ ":gear_menu.m",
+ ":import_crostini_image_dialog.m",
+ ":install_linux_package_dialog.m",
+ ":list_container.m",
+ ":location_line.m",
+ ":multi_menu.m",
+ ":multi_menu_button.m",
+ ":progress_center_panel.m",
+ ":providers_menu.m",
+ ":search_box.m",
+ "table:table.m",
+ "table:table_column.m",
+ "table:table_column_model.m",
+ "table:table_header.m",
+ "table:table_list.m",
+ "table:table_splitter.m",
]
}
js_type_check("closure_compile_module") {
+ uses_legacy_modules = true
deps = [
":action_model_ui",
":actions_submenu",
@@ -52,7 +102,6 @@ js_type_check("closure_compile_module") {
":progress_center_panel",
":providers_menu",
":search_box",
- ":suggest_apps_dialog",
"table:table",
"table:table_column",
"table:table_column_model",
@@ -68,7 +117,7 @@ js_library("closure_compile_externs") {
"$externs_path/metrics_private.js",
"//ui/file_manager/externs/background/crostini.js",
"//ui/file_manager/externs/background/drive_sync_handler.js",
- "//ui/file_manager/externs/background/file_browser_background.js",
+ "//ui/file_manager/externs/background/background_base.js",
"//ui/file_manager/externs/background/file_operation_manager.js",
"//ui/file_manager/externs/background/import_history.js",
"//ui/file_manager/externs/background_window.js",
@@ -76,6 +125,7 @@ js_library("closure_compile_externs") {
"//ui/file_manager/externs/chrome_webstore_widget_private.js",
"//ui/file_manager/externs/css_rule.js",
"//ui/file_manager/externs/drag_target.js",
+ "//ui/file_manager/externs/drive_dialog_controller.js",
"//ui/file_manager/externs/entries_changed_event.js",
"//ui/file_manager/externs/gallery_foreground.js",
"//ui/file_manager/externs/menu_item_update_event.js",
@@ -88,6 +138,12 @@ js_library("closure_compile_externs") {
js_library("a11y_announce") {
}
+js_library("a11y_announce.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/a11y_announce.m.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("action_model_ui") {
deps = [
":files_alert_dialog",
@@ -95,6 +151,16 @@ js_library("action_model_ui") {
]
}
+js_library("action_model_ui.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/action_model_ui.m.js" ]
+ deps = [
+ ":files_alert_dialog.m",
+ ":list_container.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("actions_submenu") {
deps = [
"//ui/file_manager/file_manager/foreground/js:actions_model",
@@ -104,11 +170,28 @@ js_library("actions_submenu") {
]
}
-js_unittest("actions_submenu_unittest") {
+js_library("actions_submenu.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/actions_submenu.m.js" ]
deps = [
- ":actions_submenu",
- "//ui/file_manager/file_manager/foreground/js:mock_actions_model",
- "//ui/webui/resources/js:webui_resource_test",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js:actions_model.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
+ "//ui/webui/resources/js/cr/ui:menu_item.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("actions_submenu_unittest.m") {
+ deps = [
+ ":actions_submenu.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js:mock_actions_model.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
]
}
@@ -117,21 +200,51 @@ js_library("banners") {
"//ui/file_manager/base/js:volume_manager_types",
"//ui/file_manager/file_manager/common/js:util",
"//ui/file_manager/file_manager/foreground/js:directory_model",
+ "//ui/file_manager/file_manager/foreground/js:holding_space_util",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js/cr:event_target",
]
externs_list = [ "//ui/file_manager/externs/chrome_echo_private.js" ]
}
+js_library("banners.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/banners.m.js",
+ ]
+ deps = [
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js:constants.m",
+ "//ui/file_manager/file_manager/foreground/js:directory_model.m",
+ "//ui/file_manager/file_manager/foreground/js:holding_space_util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("breadcrumb") {
deps = [ "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu" ]
}
-js_unittest("breadcrumb_unittest") {
+js_library("breadcrumb.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.m.js" ]
+
+ deps = [ "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("breadcrumb_unittest.m") {
deps = [
- ":breadcrumb",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:webui_resource_test",
+ ":breadcrumb.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/webui/resources/js:assert.m",
]
}
@@ -145,6 +258,21 @@ js_library("combobutton") {
externs_list = [ "//ui/file_manager/externs/paper_elements.js" ]
}
+js_library("combobutton.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/combobutton.m.js" ]
+ deps = [
+ ":files_menu.m",
+ ":multi_menu_button.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js/cr:ui.m",
+ "//ui/webui/resources/js/cr/ui:menu_item.m",
+ ]
+
+ externs_list = [ "//ui/file_manager/externs/paper_elements.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("commandbutton") {
deps = [
"//ui/webui/resources/js:assert",
@@ -153,6 +281,18 @@ js_library("commandbutton") {
]
}
+js_library("commandbutton.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/commandbutton.m.js" ]
+ deps = [
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:ui.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("default_task_dialog") {
deps = [
":file_manager_dialog_base",
@@ -162,6 +302,19 @@ js_library("default_task_dialog") {
]
}
+js_library("default_task_dialog.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/default_task_dialog.m.js" ]
+
+ deps = [
+ ":file_manager_dialog_base.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr/ui:array_data_model.m",
+ "//ui/webui/resources/js/cr/ui:list.m",
+ "//ui/webui/resources/js/cr/ui:list_single_selection_model.m",
+ ]
+ extra_deps = [ ":modulize" ]
+}
+
js_library("dialog_footer") {
deps = [
"//ui/file_manager/file_manager/common/js:file_type",
@@ -172,6 +325,20 @@ js_library("dialog_footer") {
]
}
+js_library("dialog_footer.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/dialog_footer.m.js" ]
+ deps = [
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js:dialog_type.m",
+ "//ui/file_manager/file_manager/foreground/js:file_list_model.m",
+ "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
+ "//ui/webui/resources/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("directory_tree") {
deps = [
"//ui/file_manager/base/js:volume_manager_types",
@@ -185,16 +352,54 @@ js_library("directory_tree") {
]
}
-js_unittest("directory_tree_unittest") {
+js_library("directory_tree.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/directory_tree.m.js" ]
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:fake_android_app_list_model",
- "//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",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_info.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js:constants.m",
+ "//ui/file_manager/file_manager/foreground/js:directory_contents.m",
+ "//ui/file_manager/file_manager/foreground/js:directory_model.m",
+ "//ui/file_manager/file_manager/foreground/js:navigation_list_model.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
+ "//ui/webui/resources/js/cr/ui:context_menu_handler.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
+ "//ui/webui/resources/js/cr/ui:tree.m",
+ ]
+ visibility += [ "//ui/file_manager/externs:command_handler_deps.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("directory_tree_unittest.m") {
+ deps = [
+ ":directory_tree.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs/background:file_operation_manager.m",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+ "//ui/file_manager/file_manager/common/js:mock_entry.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js:directory_model.m",
+ "//ui/file_manager/file_manager/foreground/js:fake_android_app_list_model.m",
+ "//ui/file_manager/file_manager/foreground/js:mock_directory_model.m",
+ "//ui/file_manager/file_manager/foreground/js:mock_folder_shortcut_data_model.m",
+ "//ui/file_manager/file_manager/foreground/js:mock_navigation_list_model.m",
+ "//ui/file_manager/file_manager/foreground/js:navigation_list_model.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model.m",
+ "//ui/webui/resources/js:assert.m",
]
}
@@ -206,10 +411,25 @@ js_library("drag_selector") {
externs_list = [ "//ui/file_manager/externs/drag_target.js" ]
}
+js_library("drag_selector.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/drag_selector.m.js" ]
+ deps = [ "//ui/webui/resources/js/cr/ui:list.m" ]
+ externs_list = [ "//ui/file_manager/externs/drag_target.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("empty_folder") {
deps = [ "//ui/webui/resources/js:util" ]
}
+js_library("empty_folder.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/empty_folder.m.js" ]
+ deps = [ "//ui/webui/resources/js:util.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("file_grid") {
deps = [
":drag_selector",
@@ -225,6 +445,34 @@ js_library("file_grid") {
externs_list = [ "//ui/file_manager/externs/background/import_history.js" ]
}
+js_library("file_grid.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/file_grid.m.js" ]
+ deps = [
+ ":a11y_announce.m",
+ ":drag_selector.m",
+ ":file_table_list.m",
+ ":file_tap_handler.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:import_history.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js:list_thumbnail_loader.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr/ui:grid.m",
+ "//ui/webui/resources/js/cr/ui:list.m",
+ "//ui/webui/resources/js/cr/ui:list_item.m",
+ "//ui/webui/resources/js/cr/ui:list_selection_model.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("file_list_selection_model") {
deps = [
"//ui/webui/resources/js/cr/ui:list_selection_model",
@@ -232,10 +480,20 @@ js_library("file_list_selection_model") {
]
}
-js_unittest("file_list_selection_model_unittest") {
+js_library("file_list_selection_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model.m.js" ]
deps = [
- ":file_list_selection_model",
- "//ui/webui/resources/js:webui_resource_test",
+ "//ui/webui/resources/js/cr/ui:list_selection_model.m",
+ "//ui/webui/resources/js/cr/ui:list_single_selection_model.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_list_selection_model_unittest.m") {
+ deps = [
+ ":file_list_selection_model.m",
+ "//chrome/test/data/webui:chai_assert",
]
}
@@ -249,11 +507,22 @@ js_library("file_manager_dialog_base") {
externs_list = [ "$externs_path/chrome_extensions.js" ]
}
-js_unittest("file_manager_dialog_base_unittest") {
+js_library("file_manager_dialog_base.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base.m.js" ]
deps = [
- ":file_manager_dialog_base",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/webui/resources/js:webui_resource_test",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js/cr/ui:dialogs.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_manager_dialog_base_unittest.m") {
+ deps = [
+ ":file_manager_dialog_base.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/webui/resources/js:assert.m",
]
}
@@ -283,7 +552,6 @@ js_library("file_manager_ui") {
":progress_center_panel",
":providers_menu",
":search_box",
- ":suggest_apps_dialog",
"//ui/file_manager/file_manager/common/js:util",
"//ui/file_manager/file_manager/foreground/elements:files_format_dialog",
"//ui/file_manager/file_manager/foreground/elements:files_message",
@@ -304,6 +572,56 @@ js_library("file_manager_ui") {
]
}
+js_library("file_manager_ui.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.m.js" ]
+ deps = [
+ ":a11y_announce.m",
+ ":action_model_ui.m",
+ ":actions_submenu.m",
+ ":banners.m",
+ ":combobutton.m",
+ ":default_task_dialog.m",
+ ":dialog_footer.m",
+ ":directory_tree.m",
+ ":empty_folder.m",
+ ":file_grid.m",
+ ":file_table.m",
+ ":files_alert_dialog.m",
+ ":files_confirm_dialog.m",
+ ":files_menu.m",
+ ":gear_menu.m",
+ ":import_crostini_image_dialog.m",
+ ":install_linux_package_dialog.m",
+ ":list_container.m",
+ ":location_line.m",
+ ":multi_menu.m",
+ ":multi_menu_button.m",
+ ":progress_center_panel.m",
+ ":providers_menu.m",
+ ":search_box.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_password_dialog.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_toast.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_tooltip.m",
+ "//ui/file_manager/file_manager/foreground/js:dialog_type.m",
+ "//ui/file_manager/file_manager/foreground/js:launch_param.m",
+ "//ui/file_manager/file_manager/foreground/js:providers_model.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr:ui.m",
+ "//ui/webui/resources/js/cr/ui:context_menu_handler.m",
+ "//ui/webui/resources/js/cr/ui:dialogs.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
+ "//ui/webui/resources/js/cr/ui:menu_item.m",
+ "//ui/webui/resources/js/cr/ui:splitter.m",
+ ]
+ visibility += [ "//ui/file_manager/externs:command_handler_deps.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("file_metadata_formatter") {
deps = [
"//ui/file_manager/file_manager/common/js:util",
@@ -311,6 +629,17 @@ js_library("file_metadata_formatter") {
]
}
+js_library("file_metadata_formatter.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/file_metadata_formatter.m.js" ]
+ deps = [
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("file_table") {
deps = [
":a11y_announce",
@@ -325,10 +654,44 @@ js_library("file_table") {
externs_list = [ "//ui/file_manager/externs/background/import_history.js" ]
}
-js_unittest("file_table_unittest") {
+js_library("file_table.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/file_table.m.js" ]
deps = [
- ":file_table",
- "//ui/webui/resources/js:webui_resource_test",
+ ":a11y_announce.m",
+ ":drag_selector.m",
+ ":file_list_selection_model.m",
+ ":file_metadata_formatter.m",
+ ":file_table_list.m",
+ "table:table.m",
+ "table:table_column.m",
+ "table:table_column_model.m",
+ "table:table_list.m",
+ "//ui/file_manager/externs:entry_location.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/externs/background:import_history.m",
+ "//ui/file_manager/file_manager/common/js:async_util.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:importer_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js:file_list_model.m",
+ "//ui/file_manager/file_manager/foreground/js:list_thumbnail_loader.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr/ui:list.m",
+ "//ui/webui/resources/js/cr/ui:list_item.m",
+ "//ui/webui/resources/js/cr/ui:list_selection_model.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_table_unittest.m") {
+ deps = [
+ ":file_table.m",
+ "table:table_column.m",
+ "//chrome/test/data/webui:chai_assert",
]
}
@@ -344,15 +707,44 @@ js_library("file_table_list") {
]
}
-js_unittest("file_table_list_unittest") {
+js_library("file_table_list.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/file_table_list.m.js" ]
deps = [
- ":file_table",
- ":file_table_list",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/file_manager/background/js:mock_volume_manager",
- "//ui/file_manager/file_manager/common/js:util",
- "//ui/file_manager/file_manager/foreground/js/metadata:mock_metadata",
- "//ui/webui/resources/js:webui_resource_test",
+ ":a11y_announce.m",
+ ":file_list_selection_model.m",
+ ":file_tap_handler.m",
+ "table:table_list.m",
+ "//ui/file_manager/externs:entry_location.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr/ui:list.m",
+ "//ui/webui/resources/js/cr/ui:list_item.m",
+ "//ui/webui/resources/js/cr/ui:list_selection_controller.m",
+ "//ui/webui/resources/js/cr/ui:list_selection_model.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_table_list_unittest.m") {
+ deps = [
+ ":a11y_announce.m",
+ ":file_list_selection_model.m",
+ ":file_table.m",
+ ":file_table_list.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/externs/background:import_history.m",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+ "//ui/file_manager/file_manager/foreground/js:directory_model.m",
+ "//ui/file_manager/file_manager/foreground/js:file_list_model.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:mock_metadata.m",
]
}
@@ -360,11 +752,18 @@ js_library("file_tap_handler") {
deps = [ "//ui/file_manager/file_manager/common/js:util" ]
}
-js_unittest("file_tap_handler_unittest") {
+js_library("file_tap_handler.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler.m.js" ]
+ deps = [ "//ui/webui/resources/js:assert.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_tap_handler_unittest.m") {
deps = [
- ":file_tap_handler",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/webui/resources/js:webui_resource_test",
+ ":file_tap_handler.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
]
}
@@ -374,12 +773,32 @@ js_library("files_alert_dialog") {
deps = [ "//ui/webui/resources/js/cr/ui:dialogs" ]
}
+js_library("files_alert_dialog.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/files_alert_dialog.m.js" ]
+ deps = [
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js/cr/ui:dialogs.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
# TODO(tapted): Move this into //ui/file_manager/base.
js_library("files_confirm_dialog") {
visibility += [ "//ui/file_manager/gallery/*" ]
deps = [ "//ui/webui/resources/js/cr/ui:dialogs" ]
}
+js_library("files_confirm_dialog.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/files_confirm_dialog.m.js" ]
+ deps = [
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js/cr/ui:dialogs.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("files_menu") {
deps = [
"//ui/webui/resources/js:assert",
@@ -389,10 +808,34 @@ js_library("files_menu") {
externs_list = [ "//ui/file_manager/externs/paper_elements.js" ]
}
+js_library("files_menu.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/files_menu.m.js" ]
+ deps = [
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
+ "//ui/webui/resources/js/cr/ui:menu_item.m",
+ ]
+ externs_list = [ "//ui/file_manager/externs/paper_elements.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("gear_menu") {
deps = [ "//ui/file_manager/file_manager/common/js:util" ]
}
+js_library("gear_menu.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/gear_menu.m.js" ]
+ deps = [
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ "//ui/webui/resources/js:util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("install_linux_package_dialog") {
deps = [
":file_manager_dialog_base",
@@ -400,11 +843,23 @@ js_library("install_linux_package_dialog") {
]
}
-js_unittest("install_linux_package_dialog_unittest") {
+js_library("install_linux_package_dialog.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/install_linux_package_dialog.m.js" ]
deps = [
- ":install_linux_package_dialog",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/webui/resources/js:webui_resource_test",
+ ":file_manager_dialog_base.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("install_linux_package_dialog_unittest.m") {
+ deps = [
+ ":install_linux_package_dialog.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
}
@@ -416,6 +871,16 @@ js_library("import_crostini_image_dialog") {
]
}
+js_library("import_crostini_image_dialog.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/import_crostini_image_dialog.m.js" ]
+ deps = [
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js/cr/ui:dialogs.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("list_container") {
deps = [
":file_grid",
@@ -426,6 +891,27 @@ js_library("list_container") {
]
}
+js_library("list_container.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/list_container.m.js" ]
+ deps = [
+ ":file_grid.m",
+ ":file_table.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js:dialog_type.m",
+ "//ui/file_manager/file_manager/foreground/js:file_list_model.m",
+ "//ui/file_manager/file_manager/foreground/js:list_thumbnail_loader.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr/ui:list.m",
+ "//ui/webui/resources/js/cr/ui:list_item.m",
+ "//ui/webui/resources/js/cr/ui:list_selection_model.m",
+ "//ui/webui/resources/js/cr/ui:list_single_selection_model.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("location_line") {
deps = [
"//ui/file_manager/base/js:volume_manager_types",
@@ -437,6 +923,23 @@ js_library("location_line") {
]
}
+js_library("location_line.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/location_line.m.js" ]
+ deps = [
+ ":breadcrumb.m",
+ ":list_container.m",
+ "//ui/file_manager/externs:files_app_entry_interfaces.m",
+ "//ui/file_manager/externs:volume_manager.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_tooltip.m",
+ "//ui/file_manager/file_manager/foreground/js:path_component.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("multi_menu") {
deps = [
# TODO(files-ng): remove util dep when the files-ng flag is removed.
@@ -449,6 +952,20 @@ js_library("multi_menu") {
externs_list = [ "$externs_path/pending.js" ]
}
+js_library("multi_menu.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/multi_menu.m.js" ]
+
+ deps = [
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:event_tracker.m",
+ "//ui/webui/resources/js/cr:ui.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
+ "//ui/webui/resources/js/cr/ui:menu_item.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("multi_menu_button") {
deps = [
# TODO(files-ng): remove util dep when the files-ng flag is removed.
@@ -462,13 +979,32 @@ js_library("multi_menu_button") {
externs_list = [ "$externs_path/pending.js" ]
}
-js_unittest("multi_menu_unittest") {
+js_library("multi_menu_button.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/multi_menu_button.m.js" ]
deps = [
- ":multi_menu",
- ":multi_menu_button",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/file_manager/common/js:util",
- "//ui/webui/resources/js:webui_resource_test",
+ ":multi_menu.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:event_tracker.m",
+ "//ui/webui/resources/js/cr:ui.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
+ "//ui/webui/resources/js/cr/ui:menu_button.m",
+ "//ui/webui/resources/js/cr/ui:menu_item.m",
+ "//ui/webui/resources/js/cr/ui:position_util.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("multi_menu_unittest.m") {
+ deps = [
+ ":multi_menu_button.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr:ui.m",
+ "//ui/webui/resources/js/cr/ui:command.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
]
}
@@ -476,11 +1012,20 @@ js_library("progress_center_panel") {
# The progress_center on the background page maintains a list of panels.
visibility += [ "//ui/file_manager/file_manager/background/*" ]
+ deps = [ "//ui/file_manager/file_manager/common/js:progress_center_common" ]
+ externs_list = [ "//ui/file_manager/externs/progress_center_panel.js" ]
+}
+
+js_library("progress_center_panel.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.m.js" ]
deps = [
- "//ui/file_manager/file_manager/common/js:progress_center_common",
- "//ui/file_manager/file_manager/foreground/js:progress_center_item_group",
+ "//ui/file_manager/externs:progress_center_panel.m",
+ "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
]
- externs_list = [ "//ui/file_manager/externs/progress_center_panel.js" ]
+
+ extra_deps = [ ":modulize" ]
}
js_library("providers_menu") {
@@ -494,6 +1039,20 @@ js_library("providers_menu") {
externs_list = [ "//ui/file_manager/externs/menu_item_update_event.js" ]
}
+js_library("providers_menu.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/providers_menu.m.js" ]
+ deps = [
+ ":files_menu.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/js:providers_model.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js/cr:ui.m",
+ "//ui/webui/resources/js/cr/ui:menu.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("search_box") {
deps = [
":autocomplete_list",
@@ -509,6 +1068,25 @@ js_library("search_box") {
externs_list = [ "//ui/file_manager/externs/search_item.js" ]
}
+js_library("search_box.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/search_box.m.js" ]
+ deps = [
+ ":autocomplete_list.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/common/js:metrics.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/file_manager/file_manager/foreground/elements:files_toggle_ripple.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ "//ui/webui/resources/js/cr/ui:list_item.m",
+ ]
+ externs_list = [ "//ui/file_manager/externs/search_item.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("autocomplete_list") {
deps = [
"//ui/webui/resources/js/cr/ui:list",
@@ -517,33 +1095,93 @@ js_library("autocomplete_list") {
]
}
-js_library("suggest_apps_dialog") {
+js_library("autocomplete_list.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/autocomplete_list.m.js" ]
deps = [
- ":file_manager_dialog_base",
- "//ui/file_manager/base/js:volume_manager_types",
- "//ui/file_manager/file_manager/common/js:metrics",
- "//ui/file_manager/file_manager/common/js:util",
- "//ui/file_manager/file_manager/cws_widget:cws_widget_container",
- "//ui/file_manager/file_manager/foreground/js:constants",
- "//ui/file_manager/file_manager/foreground/js:launch_param",
- "//ui/file_manager/file_manager/foreground/js:providers_model",
- "//ui/file_manager/file_manager/foreground/js:web_store_utils",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr/ui:array_data_model.m",
+ "//ui/webui/resources/js/cr/ui:list.m",
+ "//ui/webui/resources/js/cr/ui:list_item.m",
+ "//ui/webui/resources/js/cr/ui:list_single_selection_model.m",
+ "//ui/webui/resources/js/cr/ui:position_util.m",
]
- externs_list =
- [ "//ui/file_manager/externs/chrome_webstore_widget_private.js" ]
+
+ extra_deps = [ ":modulize" ]
}
-js_test_gen_html("js_test_gen_html") {
+js_test_gen_html("js_test_gen_html_modules") {
deps = [
- ":actions_submenu_unittest",
- ":breadcrumb_unittest",
- ":directory_tree_unittest",
- ":file_list_selection_model_unittest",
- ":file_manager_dialog_base_unittest",
- ":file_table_list_unittest",
- ":file_table_unittest",
- ":file_tap_handler_unittest",
- ":install_linux_package_dialog_unittest",
- ":multi_menu_unittest",
+ ":actions_submenu_unittest.m",
+ ":breadcrumb_unittest.m",
+ ":directory_tree_unittest.m",
+ ":file_list_selection_model_unittest.m",
+ ":file_manager_dialog_base_unittest.m",
+ ":file_table_list_unittest.m",
+ ":file_table_unittest.m",
+ ":file_tap_handler_unittest.m",
+ ":install_linux_package_dialog_unittest.m",
+ ":multi_menu_unittest.m",
+ ]
+ is_polymer3 = true
+
+ closure_flags =
+ strict_error_checking_closure_args + [
+ "generate_exports=false",
+ "js_module_root=./gen/ui",
+ "js_module_root=../../ui",
+ "jscomp_off=duplicate",
+ "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
+ "hide_warnings_for=third_party/",
+ ]
+}
+
+js_modulizer("modulize") {
+ input_files = [
+ "a11y_announce.js",
+ "action_model_ui.js",
+ "actions_submenu.js",
+ "autocomplete_list.js",
+ "banners.js",
+ "breadcrumb.js",
+ "combobutton.js",
+ "commandbutton.js",
+ "default_task_dialog.js",
+ "dialog_footer.js",
+ "directory_tree.js",
+ "drag_selector.js",
+ "empty_folder.js",
+ "file_grid.js",
+ "file_list_selection_model.js",
+ "file_manager_dialog_base.js",
+ "file_manager_ui.js",
+ "file_metadata_formatter.js",
+ "file_table.js",
+ "file_table_list.js",
+ "file_tap_handler.js",
+ "files_alert_dialog.js",
+ "files_confirm_dialog.js",
+ "files_menu.js",
+ "gear_menu.js",
+ "import_crostini_image_dialog.js",
+ "install_linux_package_dialog.js",
+ "list_container.js",
+ "location_line.js",
+ "multi_menu.js",
+ "multi_menu_button.js",
+ "progress_center_panel.js",
+ "providers_menu.js",
+ "search_box.js",
+ ]
+
+ namespace_rewrites = cr_namespace_rewrites
+ namespace_rewrites += [
+ "cr.ui.ComboButton|ComboButton",
+ "cr.ui.FilesMenuItem|FilesMenuItem",
+ "cr.ui.MultiMenu|MultiMenu",
+ "cr.ui.table.Table|Table",
+ "cr.ui.AutocompleteList|AutocompleteList",
+ "cr.filebrowser.DefaultTaskDialog|DefaultTaskDialog",
+ "cr.filebrowser.InstallLinuxPackageDialog|InstallLinuxPackageDialog",
+ "cr.filebrowser.ImportCrostiniImageDialog|ImportCrostiniImageDialog",
]
}
diff --git a/chromium/ui/file_manager/file_manager/foreground/js/ui/table/BUILD.gn b/chromium/ui/file_manager/file_manager/foreground/js/ui/table/BUILD.gn
index 04c89fe79ca..062336829e7 100644
--- a/chromium/ui/file_manager/file_manager/foreground/js/ui/table/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/foreground/js/ui/table/BUILD.gn
@@ -3,6 +3,8 @@
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
+import("//ui/webui/resources/js/cr.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
js_library("table_column") {
deps = [
@@ -11,6 +13,16 @@ js_library("table_column") {
]
}
+js_library("table_column.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/table/table_column.m.js" ]
+ deps = [
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("table") {
deps = [
":table_column_model",
@@ -21,6 +33,23 @@ js_library("table") {
]
}
+js_library("table.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/table/table.m.js" ]
+ deps = [
+ ":table_column.m",
+ ":table_column_model.m",
+ ":table_header.m",
+ ":table_list.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr/ui:array_data_model.m",
+ "//ui/webui/resources/js/cr/ui:list.m",
+ "//ui/webui/resources/js/cr/ui:list_item.m",
+ "//ui/webui/resources/js/cr/ui:list_single_selection_model.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("table_column_model") {
deps = [
":table_column",
@@ -28,6 +57,17 @@ js_library("table_column_model") {
]
}
+js_library("table_column_model.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/table/table_column_model.m.js" ]
+ deps = [
+ ":table_column.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("table_header") {
deps = [
":table_splitter",
@@ -35,6 +75,16 @@ js_library("table_header") {
]
}
+js_library("table_header.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/table/table_header.m.js" ]
+ deps = [
+ ":table_splitter.m",
+ "//ui/webui/resources/js:cr.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("table_list") {
deps = [
":table_column_model",
@@ -43,6 +93,17 @@ js_library("table_list") {
]
}
+js_library("table_list.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/table/table_list.m.js" ]
+ deps = [
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr/ui:list.m",
+ "//ui/webui/resources/js/cr/ui:list_item.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("table_splitter") {
deps = [
":table_column_model",
@@ -50,3 +111,27 @@ js_library("table_splitter") {
"//ui/webui/resources/js/cr/ui:splitter",
]
}
+
+js_library("table_splitter.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/table/table_splitter.m.js" ]
+ deps = [
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js/cr:event_target.m",
+ "//ui/webui/resources/js/cr/ui:splitter.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_modulizer("modulize") {
+ input_files = [
+ "table.js",
+ "table_column.js",
+ "table_column_model.js",
+ "table_header.js",
+ "table_list.js",
+ "table_splitter.js",
+ ]
+
+ namespace_rewrites = cr_namespace_rewrites + [ "cr.ui.table.Table|Table" ]
+}
diff --git a/chromium/ui/file_manager/file_manager/test/BUILD.gn b/chromium/ui/file_manager/file_manager/test/BUILD.gn
index 2a77eecf911..e0e1a18ab7b 100644
--- a/chromium/ui/file_manager/file_manager/test/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/test/BUILD.gn
@@ -25,7 +25,6 @@ action("create_test_main") {
"crostini_tasks.js",
"js/strings.js",
"menu.js",
- "progress_center.js",
]
deps = [ "//ui/resources:webui_resources_grd" ]
args = [ "--output=" + rebase_path(output, root_build_dir) ]
@@ -33,6 +32,7 @@ action("create_test_main") {
}
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [
":check_select",
":closure_compile_externs",
@@ -41,7 +41,6 @@ js_type_check("closure_compile") {
":crostini_tasks",
":menu",
":plugin_vm",
- ":progress_center",
]
}
@@ -54,9 +53,8 @@ js_library("closure_compile_externs") {
"js/externs.js",
"$externs_path/command_line_private.js",
"$externs_path/metrics_private.js",
- "//ui/file_manager/externs/background/file_browser_background.js",
+ "//ui/file_manager/externs/background/background_base.js",
"//ui/file_manager/externs/background/progress_center.js",
- "//ui/file_manager/externs/progress_center_panel.js",
"//ui/file_manager/externs/background/crostini.js",
"//ui/file_manager/externs/entry_location.js",
"//ui/file_manager/externs/volume_info.js",
@@ -106,11 +104,3 @@ js_library("plugin_vm") {
"//ui/webui/resources/js:webui_resource_test",
]
}
-
-js_library("progress_center") {
- deps = [
- "js:test_util",
- "//ui/file_manager/file_manager/common/js:progress_center_common",
- "//ui/webui/resources/js:webui_resource_test",
- ]
-}
diff --git a/chromium/ui/file_manager/gallery/js/BUILD.gn b/chromium/ui/file_manager/gallery/js/BUILD.gn
index e854367ed1c..4d1f700bdcb 100644
--- a/chromium/ui/file_manager/gallery/js/BUILD.gn
+++ b/chromium/ui/file_manager/gallery/js/BUILD.gn
@@ -7,6 +7,7 @@ import("//third_party/closure_compiler/js_unit_tests.gni")
import("//ui/file_manager/base/gn/js_test_gen_html.gni")
js_type_check("closure_compile_module") {
+ uses_legacy_modules = true
deps = [
":background",
":dimmable_ui_controller",
@@ -39,8 +40,12 @@ js_library("dimmable_ui_controller") {
"//ui/webui/resources/js:assert",
]
externs_list = [
+ # We need both chrome_extensions.js and accessibility_features.js to support
+ # chrome.accessibilityFeatures, since accessibility_features.js uses the
+ # ChromeSetting type (only defined in chrome_extensions.js).
+ "$externs_path/accessibility_features.js",
"$externs_path/chrome.js",
- "$externs_path/chrome_extensions.js", # For chrome.accessibilityFeatures.
+ "$externs_path/chrome_extensions.js",
]
}
@@ -76,6 +81,7 @@ js_library("gallery") {
":gallery_constants",
":gallery_item",
":thumbnail_mode",
+ "//ui/file_manager/base/js:app_util",
"//ui/file_manager/base/js:filtered_volume_manager",
"//ui/file_manager/file_manager/common/js:util",
"//ui/file_manager/file_manager/foreground/js/ui:files_confirm_dialog",
diff --git a/chromium/ui/file_manager/gallery/js/image_editor/BUILD.gn b/chromium/ui/file_manager/gallery/js/image_editor/BUILD.gn
index 0467e35c6c5..e85237742a1 100644
--- a/chromium/ui/file_manager/gallery/js/image_editor/BUILD.gn
+++ b/chromium/ui/file_manager/gallery/js/image_editor/BUILD.gn
@@ -5,8 +5,19 @@
import("//third_party/closure_compiler/compile_js.gni")
import("//third_party/closure_compiler/js_unit_tests.gni")
import("//ui/file_manager/base/gn/js_test_gen_html.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
+
+js_type_check("closure_compile_jsmodules") {
+ deps = [
+ ":exif_encoder.m",
+ ":image_encoder.m",
+ ":image_util.m",
+ ":test_util.m",
+ ]
+}
js_type_check("closure_compile_module") {
+ uses_legacy_modules = true
deps = [
":commands",
":exif_encoder",
@@ -48,12 +59,31 @@ js_library("exif_encoder") {
externs_list = [ "//ui/file_manager/externs/exif_entry.js" ]
}
-js_unittest("exif_encoder_unittest") {
+js_library("exif_encoder.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/gallery/js/image_editor/exif_encoder.m.js",
+ ]
deps = [
- ":exif_encoder",
- ":test_util",
- "//ui/file_manager/file_manager/foreground/js/metadata:exif_parser",
- "//ui/webui/resources/js:webui_resource_test",
+ ":image_encoder.m",
+ "//ui/file_manager/externs:exif_entry.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:exif_constants.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_item.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("exif_encoder_unittest.m") {
+ deps = [
+ ":exif_encoder.m",
+ ":image_encoder.m",
+ ":test_util.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/externs:metadata_worker_window.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:byte_reader.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:exif_parser.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_item.m",
]
}
@@ -117,12 +147,26 @@ js_library("image_encoder") {
]
}
-js_unittest("image_encoder_unittest") {
+js_library("image_encoder.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/gallery/js/image_editor/image_encoder.m.js",
+ ]
deps = [
- ":image_encoder",
- ":test_util",
- "//ui/file_manager/base/js:test_error_reporting",
- "//ui/file_manager/file_manager/foreground/js/metadata:metadata_parser",
+ ":image_util.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_item.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("image_encoder_unittest.m") {
+ deps = [
+ ":image_encoder.m",
+ ":test_util.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:test_error_reporting.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:metadata_item.m",
]
externs_list = [ "//ui/file_manager/externs/metadata_worker_window.js" ]
}
@@ -161,6 +205,15 @@ js_library("image_util") {
deps = [ "//ui/webui/resources/js:assert" ]
}
+js_library("image_util.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/gallery/js/image_editor/image_util.m.js",
+ ]
+ deps = [ "//ui/webui/resources/js:assert.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("image_view") {
deps = [
":image_buffer",
@@ -185,6 +238,14 @@ js_unittest("image_view_unittest") {
js_library("test_util") {
}
+js_library("test_util.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/gallery/js/image_editor/test_util.m.js" ]
+ deps = [ "//ui/webui/resources/js:assert.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("viewport") {
deps = [
":image_util",
@@ -192,19 +253,41 @@ js_library("viewport") {
]
}
-js_test_gen_html("js_test_gen_html") {
+js_test_gen_html("js_test_gen_html_modules") {
deps = [
- ":exif_encoder_unittest",
- ":image_encoder_unittest",
- ":image_view_unittest",
+ ":exif_encoder_unittest.m",
+ ":image_encoder_unittest.m",
]
+ js_module = true
+
+ closure_flags =
+ strict_error_checking_closure_args + [
+ "js_module_root=./gen/ui",
+ "js_module_root=../../ui",
+ "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
+ ]
+}
+
+js_test_gen_html("js_test_gen_html") {
+ deps = [ ":image_view_unittest" ]
mocks = [ "//ui/file_manager/file_manager/foreground/js/metadata/metadata_dispatcher_mock_deps.js" ]
}
group("closure_compile") {
testonly = true
deps = [
+ ":closure_compile_jsmodules",
":closure_compile_module",
+ ":js_test_gen_html_modules_type_check_auto",
":js_test_gen_html_type_check_auto",
]
}
+
+js_modulizer("modulize") {
+ input_files = [
+ "exif_encoder.js",
+ "image_encoder.js",
+ "image_util.js",
+ "test_util.js",
+ ]
+}
diff --git a/chromium/ui/file_manager/image_loader/BUILD.gn b/chromium/ui/file_manager/image_loader/BUILD.gn
index 2ed6c6df646..41c22b230aa 100644
--- a/chromium/ui/file_manager/image_loader/BUILD.gn
+++ b/chromium/ui/file_manager/image_loader/BUILD.gn
@@ -2,23 +2,29 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//chrome/browser/resources/tools/optimize_webui.gni")
import("//third_party/closure_compiler/compile_js.gni")
import("//third_party/closure_compiler/js_unit_tests.gni")
import("//ui/file_manager/base/gn/js_test_gen_html.gni")
import("//ui/webui/resources/tools/js_modulizer.gni")
js_type_check("closure_compile_jsmodules") {
- uses_js_modules = true
deps = [
+ ":background.m",
+ ":cache.m",
+ ":image_loader.m",
":image_loader_client.m",
+ ":image_loader_util.m",
+ ":image_request_task.m",
":load_image_request.m",
+ ":piex_loader.m",
+ ":scheduler.m",
]
}
js_type_check("closure_compile_module") {
closure_flags = default_closure_args + [ "jscomp_error=strictCheckTypes" ]
deps = [
- ":background",
":cache",
":image_loader",
":image_loader_client",
@@ -30,18 +36,23 @@ js_type_check("closure_compile_module") {
]
}
-js_library("background") {
- deps = [ ":image_loader" ]
+js_library("background.m") {
+ deps = [ ":image_loader.m" ]
}
js_library("cache") {
}
-js_unittest("cache_unittest") {
+js_library("cache.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/image_loader/cache.m.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("cache_unittest.m") {
deps = [
- ":cache",
- ":load_image_request",
- "//ui/webui/resources/js:webui_resource_test",
+ ":load_image_request.m",
+ "//chrome/test/data/webui:chai_assert",
]
}
@@ -55,10 +66,26 @@ js_library("image_loader") {
]
}
-js_unittest("image_loader_unittest") {
+js_library("image_loader.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/image_loader/image_loader.m.js" ]
deps = [
- ":image_loader",
- "//ui/webui/resources/js:webui_resource_test",
+ ":cache.m",
+ ":image_request_task.m",
+ ":load_image_request.m",
+ ":scheduler.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:image_orientation.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("image_loader_unittest.m") {
+ deps = [
+ ":image_loader_util.m",
+ ":load_image_request.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/file_manager/foreground/js/metadata:image_orientation.m",
]
}
@@ -69,6 +96,17 @@ js_library("image_loader_util") {
]
}
+js_library("image_loader_util.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/image_loader/image_loader_util.m.js" ]
+ deps = [
+ ":load_image_request.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("load_image_request") {
deps = [
"//ui/file_manager/file_manager/foreground/js/metadata:image_orientation",
@@ -131,6 +169,13 @@ js_library("piex_loader") {
externs_list = [ "//ui/file_manager/externs/platform.js" ]
}
+js_library("piex_loader.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/image_loader/piex_loader.m.js" ]
+ externs_list = [ "//ui/file_manager/externs/platform.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("image_request_task") {
deps = [
":cache",
@@ -142,19 +187,48 @@ js_library("image_request_task") {
externs_list = [ "//ui/file_manager/externs/platform.js" ]
}
+js_library("image_request_task.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/image_loader/image_request_task.m.js" ]
+ deps = [
+ ":cache.m",
+ ":image_loader_util.m",
+ ":load_image_request.m",
+ ":piex_loader.m",
+ "//ui/file_manager/file_manager/common/js:file_type.m",
+ "//ui/file_manager/file_manager/foreground/js/metadata:image_orientation.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("scheduler") {
deps = [ ":image_request_task" ]
}
-js_unittest("scheduler_unittest") {
+js_library("scheduler.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/image_loader/scheduler.m.js" ]
+ deps = [ ":image_request_task.m" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("scheduler_unittest.m") {
deps = [
- ":scheduler",
- "//ui/webui/resources/js:webui_resource_test",
+ ":image_request_task.m",
+ ":scheduler.m",
+ "//chrome/test/data/webui:chai_assert",
]
}
js_test_gen_html("js_test_gen_html_modules") {
- deps = [ ":image_loader_client_unittest.m" ]
+ deps = [
+ ":cache_unittest.m",
+ ":image_loader_client_unittest.m",
+ ":image_loader_unittest.m",
+ ":scheduler_unittest.m",
+ ]
js_module = true
closure_flags =
@@ -165,22 +239,12 @@ js_test_gen_html("js_test_gen_html_modules") {
]
}
-js_test_gen_html("js_test_gen_html") {
- closure_flags = default_closure_args + [ "jscomp_error=strictCheckTypes" ]
- deps = [
- ":cache_unittest",
- ":image_loader_unittest",
- ":scheduler_unittest",
- ]
-}
-
group("closure_compile") {
testonly = true
deps = [
":closure_compile_jsmodules",
":closure_compile_module",
":js_test_gen_html_modules_type_check_auto",
- ":js_test_gen_html_type_check_auto",
]
}
@@ -188,5 +252,30 @@ js_modulizer("modulize") {
input_files = [
"image_loader_client.js",
"load_image_request.js",
+ "cache.js",
+ "piex_loader.js",
+ "image_loader_util.js",
+ "scheduler.js",
+ "image_request_task.js",
+ "image_loader.js",
+ ]
+}
+
+preprocess_folder =
+ rebase_path("$target_gen_dir/../preprocessed/image_loader", root_build_dir)
+
+optimize_webui("build") {
+ host = "image_loader"
+
+ input = preprocess_folder
+ js_module_in_files = [ "background.m.js" ]
+
+ js_out_files = [ "background.m.rollup.js" ]
+
+ deps = [
+ ":background.m",
+ "//ui/file_manager:preprocess_generated",
+ "//ui/file_manager:preprocess_static",
+ "//ui/webui/resources:preprocess",
]
}
diff --git a/chromium/ui/file_manager/integration_tests/BUILD.gn b/chromium/ui/file_manager/integration_tests/BUILD.gn
index c294aeea41d..60f6800ddcc 100644
--- a/chromium/ui/file_manager/integration_tests/BUILD.gn
+++ b/chromium/ui/file_manager/integration_tests/BUILD.gn
@@ -5,6 +5,7 @@
import("//third_party/closure_compiler/compile_js.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
testonly = true
deps = [
":remote_call",
diff --git a/chromium/ui/file_manager/integration_tests/file_manager/BUILD.gn b/chromium/ui/file_manager/integration_tests/file_manager/BUILD.gn
index 2c5e1da744d..96280284ca7 100644
--- a/chromium/ui/file_manager/integration_tests/file_manager/BUILD.gn
+++ b/chromium/ui/file_manager/integration_tests/file_manager/BUILD.gn
@@ -5,6 +5,7 @@
import("//third_party/closure_compiler/compile_js.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
testonly = true
deps = [
":background",
@@ -41,7 +42,6 @@ js_type_check("closure_compile") {
":search",
":share_and_manage_dialog",
":sort_columns",
- ":suggest_app_dialog",
":tab_index",
":tasks",
":toolbar",
@@ -231,11 +231,6 @@ js_library("sort_columns") {
deps = []
}
-js_library("suggest_app_dialog") {
- testonly = true
- deps = []
-}
-
js_library("tab_index") {
testonly = true
deps = []
diff --git a/chromium/ui/file_manager/video_player/js/BUILD.gn b/chromium/ui/file_manager/video_player/js/BUILD.gn
index 166f658b8ff..ad25c71b9d9 100644
--- a/chromium/ui/file_manager/video_player/js/BUILD.gn
+++ b/chromium/ui/file_manager/video_player/js/BUILD.gn
@@ -2,11 +2,36 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//chrome/browser/resources/tools/optimize_webui.gni")
import("//third_party/closure_compiler/compile_js.gni")
import("//third_party/closure_compiler/js_unit_tests.gni")
import("//ui/file_manager/base/gn/js_test_gen_html.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
+
+group("closure_compile") {
+ testonly = true
+ deps = [
+ ":closure_compile_jsmodules",
+ ":closure_compile_module",
+ ":js_test_gen_html_modules_type_check_auto",
+ ]
+}
+
+js_type_check("closure_compile_jsmodules") {
+ is_polymer3 = true
+ deps = [
+ ":background.m",
+ ":error_util.m",
+ ":main.m",
+ ":test_util.m",
+ ":video_player.m",
+ ":video_player_metrics.m",
+ ":video_player_native_controls.m",
+ ]
+}
js_type_check("closure_compile_module") {
+ uses_legacy_modules = true
deps = [
":background",
":closure_compile_externs",
@@ -37,9 +62,41 @@ js_library("background") {
]
}
+js_library("background.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/video_player/js/background.m.js" ]
+ deps = [
+ "//ui/file_manager/externs/background:background_base.m",
+ "//ui/file_manager/file_manager/background/js:app_window_wrapper.m",
+ "//ui/file_manager/file_manager/background/js:background_base.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("error_util") {
}
+js_library("error_util.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/video_player/js/error_util.m.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("test_util") {
+}
+
+js_library("test_util.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/video_player/js/test_util.m.js" ]
+ deps = [
+ ":background.m",
+ "//ui/file_manager/file_manager/background/js:test_util_base.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("video_player_native_controls") {
deps = [
"//ui/file_manager/base/js:app_util",
@@ -50,12 +107,26 @@ js_library("video_player_native_controls") {
externs_list = [ "//ui/file_manager/externs/platform.js" ]
}
-js_unittest("video_player_native_controls_unittest") {
+js_library("video_player_native_controls.m") {
+ sources = [ "$root_gen_dir/ui/file_manager/video_player/js/video_player_native_controls.m.js" ]
deps = [
- ":video_player_native_controls",
- "//ui/file_manager/base/js:app_util",
- "//ui/file_manager/base/js:mock_chrome",
- "//ui/webui/resources/js:webui_resource_test",
+ "//ui/file_manager/base/js:app_util.m",
+ "//ui/webui/resources/cr_elements/cr_toast:cr_toast.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ "//ui/webui/resources/js:util.m",
+ ]
+
+ externs_list = [ "//ui/file_manager/externs/platform.js" ]
+
+ extra_deps = [ ":modulize" ]
+}
+
+js_unittest("video_player_native_controls_unittest.m") {
+ deps = [
+ ":video_player_native_controls.m",
+ "//chrome/test/data/webui:chai_assert",
+ "//ui/file_manager/base/js:mock_chrome.m",
]
}
@@ -64,6 +135,7 @@ js_library("video_player") {
":error_util",
":video_player_metrics",
":video_player_native_controls",
+ "//ui/file_manager/base/js:app_util",
"//ui/file_manager/base/js:filtered_volume_manager",
"//ui/file_manager/file_manager/common/js:metrics_base",
"//ui/file_manager/file_manager/common/js:util",
@@ -72,18 +144,107 @@ js_library("video_player") {
]
}
+js_library("video_player.m") {
+ sources =
+ [ "$root_gen_dir/ui/file_manager/video_player/js/video_player.m.js" ]
+ deps = [
+ ":error_util.m",
+ ":video_player_metrics.m",
+ ":video_player_native_controls.m",
+ "//ui/file_manager/base/js:app_util.m",
+ "//ui/file_manager/base/js:filtered_volume_manager.m",
+ "//ui/file_manager/base/js:volume_manager_types.m",
+ "//ui/file_manager/file_manager/common/js:util.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ ]
+
+ extra_deps = [ ":modulize" ]
+}
+
js_library("video_player_metrics") {
deps = [ "//ui/file_manager/file_manager/common/js:metrics_base" ]
}
-js_test_gen_html("js_test_gen_html") {
- deps = [ ":video_player_native_controls_unittest" ]
+js_library("video_player_metrics.m") {
+ sources = [
+ "$root_gen_dir/ui/file_manager/video_player/js/video_player_metrics.m.js",
+ ]
+ deps = [ "//ui/file_manager/file_manager/common/js:metrics_base.m" ]
+
+ extra_deps = [ ":modulize" ]
}
-group("closure_compile") {
- testonly = true
+js_test_gen_html("js_test_gen_html_modules") {
+ deps = [ ":video_player_native_controls_unittest.m" ]
+ is_polymer3 = true
+
+ closure_flags =
+ strict_error_checking_closure_args + [
+ "generate_exports=false",
+ "js_module_root=./gen/ui",
+ "js_module_root=../../ui",
+ "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
+ "hide_warnings_for=third_party/",
+ ]
+}
+
+js_library("main.m") {
+ deps = [ ":video_player.m" ]
+}
+
+js_library("main_background.m") {
deps = [
- ":closure_compile_module",
- ":js_test_gen_html_type_check_auto",
+ ":background.m",
+ ":error_util.m",
+ ":test_util.m",
+ ":video_player_metrics.m",
+ ]
+}
+
+js_modulizer("modulize") {
+ input_files = [
+ "video_player_native_controls.js",
+ "video_player_metrics.js",
+ "error_util.js",
+ "test_util.js",
+ "background.js",
+ "video_player.js",
+ ]
+}
+
+preprocess_folder =
+ rebase_path("$target_gen_dir/../../preprocessed/video_player/js",
+ root_build_dir)
+
+optimize_webui("build") {
+ host = "video_player"
+
+ input = preprocess_folder
+ js_module_in_files = [ "main.m.js" ]
+
+ js_out_files = [ "main.m.rollup.js" ]
+
+ deps = [
+ ":main.m",
+ "//ui/file_manager:preprocess_generated",
+ "//ui/file_manager:preprocess_static",
+ "//ui/webui/resources:preprocess",
+ ]
+}
+
+optimize_webui("build_background") {
+ host = "video_player"
+
+ input = preprocess_folder
+ js_module_in_files = [ "main_background.m.js" ]
+
+ js_out_files = [ "main_background.m.rollup.js" ]
+
+ deps = [
+ ":main_background.m",
+ "//ui/file_manager:preprocess_generated",
+ "//ui/file_manager:preprocess_static",
+ "//ui/webui/resources:preprocess",
]
}
diff --git a/chromium/ui/gfx/BUILD.gn b/chromium/ui/gfx/BUILD.gn
index 052789a9577..76622085d42 100644
--- a/chromium/ui/gfx/BUILD.gn
+++ b/chromium/ui/gfx/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/ozone.gni")
import("//build/config/ui.gni")
import("//device/vr/buildflags/buildflags.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
@@ -49,6 +50,10 @@ component("geometry_skia") {
"skia_util.h",
"transform.cc",
"transform.h",
+ "transform_operation.cc",
+ "transform_operation.h",
+ "transform_operations.cc",
+ "transform_operations.h",
"transform_util.cc",
"transform_util.h",
]
@@ -114,6 +119,10 @@ component("gfx") {
"overlay_transform_utils.cc",
"overlay_transform_utils.h",
"platform_font.h",
+ "rendering_pipeline.cc",
+ "rendering_pipeline.h",
+ "rendering_stage_scheduler.cc",
+ "rendering_stage_scheduler.h",
"scrollbar_size.cc",
"scrollbar_size.h",
"selection_model.cc",
@@ -299,6 +308,7 @@ component("gfx") {
"//base:base_static",
"//base:i18n",
"//base/third_party/dynamic_annotations",
+ "//build:chromeos_buildflags",
"//device/vr/buildflags",
"//skia",
"//third_party/zlib",
@@ -406,7 +416,11 @@ component("gfx") {
]
}
- if (use_x11) {
+ if (use_ozone) {
+ deps += [ "//ui/ozone:buildflags" ]
+ }
+
+ if (ozone_platform_x11 || use_x11) {
deps += [ "//ui/gfx/x" ]
}
}
@@ -430,6 +444,7 @@ component("color_space") {
]
}
deps = [
+ "//build:chromeos_buildflags",
"//skia:skcms",
"//ui/gfx:buffer_types",
]
@@ -467,6 +482,8 @@ source_set("native_widget_types") {
":gfx_export",
"//base",
]
+
+ deps = [ "//build:chromeos_buildflags" ]
}
group("selection_bound") {
@@ -564,6 +581,7 @@ source_set("memory_buffer_sources") {
":native_widget_types",
"//base",
"//build:chromecast_buildflags",
+ "//build:chromeos_buildflags",
"//ui/gfx/geometry",
]
@@ -623,9 +641,14 @@ static_library("test_support") {
sources = [
"animation/animation_test_api.cc",
"animation/animation_test_api.h",
+ "animation/keyframe/test/animation_utils.cc",
+ "animation/keyframe/test/animation_utils.h",
"animation/test_animation_delegate.h",
"geometry/test/rect_test_util.cc",
"geometry/test/rect_test_util.h",
+ "geometry/test/size_test_util.h",
+ "geometry/test/transform_test_util.cc",
+ "geometry/test/transform_test_util.h",
"image/image_unittest_util.cc",
"image/image_unittest_util.h",
"test/font_fallback_test_data.cc",
@@ -650,6 +673,7 @@ static_library("test_support") {
"//skia",
"//testing/gtest",
"//ui/gfx/animation",
+ "//ui/gfx/animation/keyframe",
"//ui/gfx/geometry",
]
@@ -660,18 +684,44 @@ static_library("test_support") {
}
}
+if (is_mac) {
+ component("gfx_io_surface_hdr_metadata") {
+ sources = [
+ "mac/io_surface_hdr_metadata.cc",
+ "mac/io_surface_hdr_metadata.h",
+ ]
+ defines = [ "IS_GFX_IO_SURFACE_HDR_METADATA_IMPL" ]
+
+ # This is a separate component from the other sources because it depends on
+ # the mojo serialize and deserialize methods.
+ deps = [
+ ":gfx",
+ "//ui/gfx/mojom:mojom",
+ ]
+ frameworks = [
+ "CoreFoundation.framework",
+ "IOSurface.framework",
+ ]
+ }
+}
+
test("gfx_unittests") {
sources = [
+ "animation/keyframe/keyframe_animation_unittest.cc",
+ "animation/keyframe/keyframed_animation_curve_unittest.cc",
"font_names_testing.cc",
"font_names_testing.h",
"font_unittest.cc",
"image/image_family_unittest.cc",
"image/image_skia_unittest.cc",
"image/image_unittest.cc",
+ "interpolated_transform_unittest.cc",
"rrect_f_unittest.cc",
"test/run_all_unittests.cc",
"text_elider_unittest.cc",
"text_utils_unittest.cc",
+ "transform_operations_unittest.cc",
+ "transform_unittest.cc",
]
if (is_linux || is_chromeos) {
sources += [
@@ -684,6 +734,7 @@ test("gfx_unittests") {
"font_fallback_mac_unittest.cc",
"image/image_mac_unittest.mm",
"mac/coordinate_conversion_unittest.mm",
+ "mac/io_surface_unittest.cc",
"path_mac_unittest.mm",
"platform_font_mac_unittest.mm",
"range/range_mac_unittest.mm",
@@ -733,6 +784,7 @@ test("gfx_unittests") {
"geometry/quad_unittest.cc",
"geometry/quaternion_unittest.cc",
"geometry/rect_unittest.cc",
+ "geometry/resize_utils_unittest.cc",
"geometry/rounded_corners_f_unittest.cc",
"geometry/scroll_offset_unittest.cc",
"geometry/size_unittest.cc",
@@ -740,6 +792,7 @@ test("gfx_unittests") {
"geometry/vector3d_unittest.cc",
"half_float_unittest.cc",
"icc_profile_unittest.cc",
+ "image/image_skia_operations_unittest.cc",
"image/image_util_unittest.cc",
"mojom/mojom_traits_unittest.cc",
"nine_image_painter_unittest.cc",
@@ -772,6 +825,7 @@ test("gfx_unittests") {
":test_support",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//skia",
"//skia:skcms",
"//testing/gtest",
@@ -780,6 +834,7 @@ test("gfx_unittests") {
"//third_party/zlib",
"//ui/base",
"//ui/gfx/animation",
+ "//ui/gfx/animation/keyframe",
"//ui/gfx/geometry",
"//ui/gfx/range",
]
@@ -798,11 +853,8 @@ test("gfx_unittests") {
deps += [ "//ui/resources:ui_test_pak_bundle_data" ]
}
- if (!is_apple) {
- sources += [
- "interpolated_transform_unittest.cc",
- "transform_unittest.cc",
- ]
+ if (is_mac) {
+ deps += [ ":gfx_io_surface_hdr_metadata" ]
}
if (is_android) {
@@ -913,6 +965,7 @@ fuzzer_test("render_text_api_fuzzer") {
":gfx",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
]
dict = "test/data/render_text/unicode_text_fuzzer.dict"
diff --git a/chromium/ui/gfx/DEPS b/chromium/ui/gfx/DEPS
index 1fa634730b4..b58bc04323c 100644
--- a/chromium/ui/gfx/DEPS
+++ b/chromium/ui/gfx/DEPS
@@ -7,6 +7,7 @@ include_rules = [
"+third_party/harfbuzz-ng",
"+third_party/skia",
"+ui/ios",
+ "+ui/ozone/buildflags.h",
"-testing/gmock",
]
diff --git a/chromium/ui/gfx/OWNERS b/chromium/ui/gfx/OWNERS
index e34675cbcb8..4bbf63bc8b2 100644
--- a/chromium/ui/gfx/OWNERS
+++ b/chromium/ui/gfx/OWNERS
@@ -25,7 +25,6 @@ per-file canvas*=danakj@chromium.org
# Overlay transforms.
per-file overlay*=alexst@chromium.org
-per-file overlay*=khushalsagar@chromium.org
per-file overlay*=spang@chromium.org
# Transform, interpolated transform and transform util.
diff --git a/chromium/ui/gfx/android/android_surface_control_compat.cc b/chromium/ui/gfx/android/android_surface_control_compat.cc
index c22ee52a33f..fea4bd261ed 100644
--- a/chromium/ui/gfx/android/android_surface_control_compat.cc
+++ b/chromium/ui/gfx/android/android_surface_control_compat.cc
@@ -11,6 +11,7 @@
#include "base/atomic_sequence_num.h"
#include "base/bind.h"
#include "base/debug/crash_logging.h"
+#include "base/hash/md5_constexpr.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
@@ -84,7 +85,9 @@ using pASurfaceTransaction_setFrameRate =
ASurfaceControl* surface_control,
float frameRate,
int8_t compatibility);
-
+using pASurfaceTransaction_reparent = void (*)(ASurfaceTransaction*,
+ ASurfaceControl* surface_control,
+ ASurfaceControl* new_parent);
// ASurfaceTransactionStats
using pASurfaceTransactionStats_getPresentFenceFd =
int (*)(ASurfaceTransactionStats* stats);
@@ -144,6 +147,7 @@ struct SurfaceControlMethods {
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_reparent);
LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setVisibility);
LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setZOrder);
LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setBuffer);
@@ -175,6 +179,7 @@ struct SurfaceControlMethods {
pASurfaceTransaction_delete ASurfaceTransaction_deleteFn;
pASurfaceTransaction_apply ASurfaceTransaction_applyFn;
pASurfaceTransaction_setOnComplete ASurfaceTransaction_setOnCompleteFn;
+ pASurfaceTransaction_reparent ASurfaceTransaction_reparentFn;
pASurfaceTransaction_setVisibility ASurfaceTransaction_setVisibilityFn;
pASurfaceTransaction_setZOrder ASurfaceTransaction_setZOrderFn;
pASurfaceTransaction_setBuffer ASurfaceTransaction_setBufferFn;
@@ -282,6 +287,12 @@ struct TransactionAckCtx {
SurfaceControl::Transaction::OnCompleteCb callback;
};
+uint64_t GetTraceIdForTransaction(int transaction_id) {
+ constexpr uint64_t kMask =
+ base::MD5Hash64Constexpr("SurfaceControl::Transaction");
+ return kMask ^ transaction_id;
+}
+
// Note that the framework API states that this callback can be dispatched on
// any thread (in practice it should be the binder thread).
void OnTransactionCompletedOnAnyThread(void* context,
@@ -290,6 +301,9 @@ void OnTransactionCompletedOnAnyThread(void* context,
auto transaction_stats = ToTransactionStats(stats);
TRACE_EVENT_NESTABLE_ASYNC_END0("gpu,benchmark", "SurfaceControlTransaction",
ack_ctx->id);
+ TRACE_EVENT_WITH_FLOW0(
+ "toplevel.flow", "gfx::SurfaceControlTransaction completed",
+ GetTraceIdForTransaction(ack_ctx->id), TRACE_EVENT_FLAG_FLOW_IN);
if (ack_ctx->task_runner) {
ack_ctx->task_runner->PostTask(
@@ -301,11 +315,19 @@ void OnTransactionCompletedOnAnyThread(void* context,
delete ack_ctx;
}
+
} // namespace
// static
bool SurfaceControl::IsSupported() {
- if (!base::android::BuildInfo::GetInstance()->is_at_least_q())
+ const auto* build_info = base::android::BuildInfo::GetInstance();
+
+ // Disabled on Samsung devices due to a platform bug fixed in R.
+ int min_sdk_version = base::android::SDK_VERSION_Q;
+ if (base::EqualsCaseInsensitiveASCII(build_info->manufacturer(), "samsung"))
+ min_sdk_version = base::android::SDK_VERSION_R;
+
+ if (build_info->sdk_int() < min_sdk_version)
return false;
CHECK(SurfaceControlMethods::Get().supported);
@@ -333,6 +355,10 @@ bool SurfaceControl::SupportsSetFrameRate() {
nullptr;
}
+void SurfaceControl::ApplyTransaction(ASurfaceTransaction* transaction) {
+ SurfaceControlMethods::Get().ASurfaceTransaction_applyFn(transaction);
+}
+
SurfaceControl::Surface::Surface() = default;
SurfaceControl::Surface::Surface(const Surface& parent, const char* name) {
@@ -469,9 +495,19 @@ void SurfaceControl::Transaction::SetFrameRate(const Surface& surface,
ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE);
}
+void SurfaceControl::Transaction::SetParent(const Surface& surface,
+ Surface* new_parent) {
+ SurfaceControlMethods::Get().ASurfaceTransaction_reparentFn(
+ transaction_, surface.surface(),
+ new_parent ? new_parent->surface() : nullptr);
+}
+
void SurfaceControl::Transaction::SetOnCompleteCb(
OnCompleteCb cb,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ TRACE_EVENT_WITH_FLOW0(
+ "toplevel.flow", "gfx::SurfaceControl::Transaction::SetOnCompleteCb",
+ GetTraceIdForTransaction(id_), TRACE_EVENT_FLAG_FLOW_OUT);
TransactionAckCtx* ack_ctx = new TransactionAckCtx;
ack_ctx->callback = std::move(cb);
ack_ctx->task_runner = std::move(task_runner);
diff --git a/chromium/ui/gfx/android/android_surface_control_compat.h b/chromium/ui/gfx/android/android_surface_control_compat.h
index e6d3dcb592c..4dc22573195 100644
--- a/chromium/ui/gfx/android/android_surface_control_compat.h
+++ b/chromium/ui/gfx/android/android_surface_control_compat.h
@@ -47,6 +47,11 @@ class GFX_EXPORT SurfaceControl {
// Returns true if tagging a surface with a frame rate value is supported.
static bool SupportsSetFrameRate();
+ // Applies transaction. Used to emulate webview functor interface, where we
+ // pass raw ASurfaceTransaction object. For use inside Chromium use
+ // Transaction class below instead.
+ static void ApplyTransaction(ASurfaceTransaction* transaction);
+
class GFX_EXPORT Surface : public base::RefCounted<Surface> {
public:
Surface();
@@ -118,6 +123,7 @@ class GFX_EXPORT SurfaceControl {
void SetColorSpace(const Surface& surface,
const gfx::ColorSpace& color_space);
void SetFrameRate(const Surface& surface, float frame_rate);
+ void SetParent(const Surface& surface, Surface* new_parent);
// Sets the callback which will be dispatched when the transaction is acked
// by the framework.
diff --git a/chromium/ui/gfx/animation/BUILD.gn b/chromium/ui/gfx/animation/BUILD.gn
index 34625ed2fdb..e544b0972f9 100644
--- a/chromium/ui/gfx/animation/BUILD.gn
+++ b/chromium/ui/gfx/animation/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
if (is_android) {
@@ -44,7 +45,7 @@ component("animation") {
sources += [ "animation_win.cc" ]
}
- if (is_linux) {
+ if (is_linux || is_chromeos_lacros) {
sources += [
"animation_linux.cc",
"animation_settings_provider_linux.cc",
@@ -71,6 +72,7 @@ component("animation") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//skia",
"//ui/gfx:geometry_skia",
"//ui/gfx:gfx_export",
diff --git a/chromium/ui/gfx/animation/animation.cc b/chromium/ui/gfx/animation/animation.cc
index 0b1d4f22cc5..1056018cffa 100644
--- a/chromium/ui/gfx/animation/animation.cc
+++ b/chromium/ui/gfx/animation/animation.cc
@@ -8,6 +8,7 @@
#include "base/command_line.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/animation/animation_container.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/gfx/animation/tween.h"
@@ -111,7 +112,7 @@ bool Animation::ShouldRenderRichAnimation() {
RichAnimationRenderMode::FORCE_ENABLED;
}
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_IOS) || \
+#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_IOS) || \
defined(OS_FUCHSIA)
// static
bool Animation::ShouldRenderRichAnimationImpl() {
@@ -136,8 +137,8 @@ void Animation::UpdatePrefersReducedMotion() {
prefers_reduced_motion_ = false;
}
#endif // !defined(OS_ANDROID)
-#endif // defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_IOS) ||
- // defined(OS_FUCHSIA)
+#endif // defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_IOS)
+ // || defined(OS_FUCHSIA)
// static
bool Animation::PrefersReducedMotion() {
diff --git a/chromium/ui/gfx/animation/keyframe/BUILD.gn b/chromium/ui/gfx/animation/keyframe/BUILD.gn
new file mode 100644
index 00000000000..d49e3855f78
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/BUILD.gn
@@ -0,0 +1,50 @@
+# Copyright 2021 The Chromium 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/ui.gni")
+
+keyframe_animation_remove_configs = []
+keyframe_animation_add_configs = [
+ "//build/config:precompiled_headers",
+ "//build/config/compiler:noshadowing",
+ "//build/config/compiler:wexit_time_destructors",
+]
+
+if (!is_debug) {
+ keyframe_animation_remove_configs +=
+ [ "//build/config/compiler:default_optimization" ]
+ keyframe_animation_add_configs += [ "//build/config/compiler:optimize_max" ]
+}
+
+component("keyframe") {
+ sources = [
+ "animation_curve.cc",
+ "animation_curve.h",
+ "keyframe_animation_export.h",
+ "keyframe_effect.cc",
+ "keyframe_effect.h",
+ "keyframe_model.cc",
+ "keyframe_model.h",
+ "keyframed_animation_curve.cc",
+ "keyframed_animation_curve.h",
+ "target_property.h",
+ "timing_function.cc",
+ "timing_function.h",
+ "transition.cc",
+ "transition.h",
+ ]
+
+ defines = [ "GFX_KEYFRAME_ANIMATION_IMPLEMENTATION=1" ]
+
+ deps = [
+ "//base",
+ "//skia",
+ "//ui/gfx:geometry_skia",
+ "//ui/gfx/animation",
+ "//ui/gfx/geometry",
+ ]
+
+ configs += keyframe_animation_add_configs
+ configs -= keyframe_animation_remove_configs
+}
diff --git a/chromium/ui/gfx/animation/keyframe/animation_curve.cc b/chromium/ui/gfx/animation/keyframe/animation_curve.cc
new file mode 100644
index 00000000000..645225d6031
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/animation_curve.cc
@@ -0,0 +1,48 @@
+// Copyright 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/animation/keyframe/animation_curve.h"
+
+#include "base/check.h"
+
+namespace gfx {
+
+bool AnimationCurve::PreservesAxisAlignment() const {
+ return true;
+}
+
+bool AnimationCurve::MaximumScale(float* max_scale) const {
+ return false;
+}
+
+base::TimeDelta AnimationCurve::TickInterval() const {
+ return base::TimeDelta();
+}
+
+#define DEFINE_ANIMATION_CURVE(Name, CurveType) \
+ void Name##AnimationCurve::Tick(base::TimeDelta t, int property_id, \
+ KeyframeModel* keyframe_model) const { \
+ if (target_) { \
+ target_->On##Name##Animated(GetValue(t), property_id, keyframe_model); \
+ } \
+ } \
+ int Name##AnimationCurve::Type() const { return AnimationCurve::CurveType; } \
+ const char* Name##AnimationCurve::TypeName() const { return #Name; } \
+ const Name##AnimationCurve* Name##AnimationCurve::To##Name##AnimationCurve( \
+ const AnimationCurve* c) { \
+ DCHECK_EQ(AnimationCurve::CurveType, c->Type()); \
+ return static_cast<const Name##AnimationCurve*>(c); \
+ } \
+ Name##AnimationCurve* Name##AnimationCurve::To##Name##AnimationCurve( \
+ AnimationCurve* c) { \
+ DCHECK_EQ(AnimationCurve::CurveType, c->Type()); \
+ return static_cast<Name##AnimationCurve*>(c); \
+ }
+
+DEFINE_ANIMATION_CURVE(Transform, TRANSFORM)
+DEFINE_ANIMATION_CURVE(Float, FLOAT)
+DEFINE_ANIMATION_CURVE(Size, SIZE)
+DEFINE_ANIMATION_CURVE(Color, COLOR)
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/animation/keyframe/animation_curve.h b/chromium/ui/gfx/animation/keyframe/animation_curve.h
new file mode 100644
index 00000000000..8d119bf8862
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/animation_curve.h
@@ -0,0 +1,109 @@
+// Copyright 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_ANIMATION_KEYFRAME_ANIMATION_CURVE_H_
+#define UI_GFX_ANIMATION_KEYFRAME_ANIMATION_CURVE_H_
+
+#include <memory>
+
+#include "base/time/time.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/animation/keyframe/keyframe_animation_export.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/transform.h"
+#include "ui/gfx/transform_operations.h"
+
+namespace gfx {
+class TransformOperations;
+class KeyframeModel;
+
+// An animation curve is a function that returns a value given a time.
+class GFX_KEYFRAME_ANIMATION_EXPORT AnimationCurve {
+ public:
+ // TODO(crbug.com/1176334): we shouldn't need the curve type, long term.
+ //
+ // In the meanime, external clients of the animation machinery will have
+ // other curve types and should be added to this enum to ensure uniqueness
+ // (eg, there are serveral cc-specific types here, presently).
+ enum CurveType {
+ COLOR = 0,
+ FLOAT,
+ TRANSFORM,
+ SIZE,
+
+ // cc:: curve types.
+ FILTER,
+ SCROLL_OFFSET,
+
+ // This must be last
+ LAST_CURVE_TYPE = SIZE,
+ };
+
+ virtual ~AnimationCurve() = default;
+
+ virtual base::TimeDelta Duration() const = 0;
+ virtual int Type() const = 0;
+ virtual const char* TypeName() const = 0;
+ virtual std::unique_ptr<AnimationCurve> Clone() const = 0;
+ virtual void Tick(base::TimeDelta t,
+ int property_id,
+ KeyframeModel* keyframe_model) const = 0;
+
+ // Returns true if this animation preserves axis alignment.
+ virtual bool PreservesAxisAlignment() const;
+
+ // Set |max_scale| to the maximum scale along any dimension during the
+ // animation, of all steps (keyframes) with calculatable scale. Returns
+ // false if none of the steps can calculate a scale.
+ virtual bool MaximumScale(float* max_scale) const;
+
+ // Returns step interval if it's step animation. Returns 0 otherwise.
+ virtual base::TimeDelta TickInterval() const;
+};
+
+#define DECLARE_ANIMATION_CURVE_BODY(T, Name) \
+ public: \
+ static const Name##AnimationCurve* To##Name##AnimationCurve( \
+ const AnimationCurve* c); \
+ static Name##AnimationCurve* To##Name##AnimationCurve(AnimationCurve* c); \
+ class Target { \
+ public: \
+ virtual ~Target() = default; \
+ virtual void On##Name##Animated(const T& value, \
+ int target_property_id, \
+ gfx::KeyframeModel* keyframe_model) = 0; \
+ }; \
+ ~Name##AnimationCurve() override = default; \
+ virtual T GetValue(base::TimeDelta t) const = 0; \
+ void Tick(base::TimeDelta t, int property_id, \
+ gfx::KeyframeModel* keyframe_model) const override; \
+ void set_target(Target* target) { target_ = target; } \
+ int Type() const override; \
+ const char* TypeName() const override; \
+ \
+ private: \
+ Target* target_ = nullptr;
+
+class GFX_KEYFRAME_ANIMATION_EXPORT ColorAnimationCurve
+ : public AnimationCurve {
+ DECLARE_ANIMATION_CURVE_BODY(SkColor, Color)
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT FloatAnimationCurve
+ : public AnimationCurve {
+ DECLARE_ANIMATION_CURVE_BODY(float, Float)
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT SizeAnimationCurve : public AnimationCurve {
+ DECLARE_ANIMATION_CURVE_BODY(gfx::SizeF, Size)
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT TransformAnimationCurve
+ : public AnimationCurve {
+ DECLARE_ANIMATION_CURVE_BODY(gfx::TransformOperations, Transform)
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_ANIMATION_KEYFRAME_ANIMATION_CURVE_H_
diff --git a/chromium/ui/gfx/animation/keyframe/keyframe_animation_export.h b/chromium/ui/gfx/animation/keyframe/keyframe_animation_export.h
new file mode 100644
index 00000000000..db0f21ec1ab
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/keyframe_animation_export.h
@@ -0,0 +1,29 @@
+// Copyright 2021 The Chromium 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_ANIMATION_KEYFRAME_KEYFRAME_ANIMATION_EXPORT_H_
+#define UI_GFX_ANIMATION_KEYFRAME_KEYFRAME_ANIMATION_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(GFX_KEYFRAME_ANIMATION_IMPLEMENTATION)
+#define GFX_KEYFRAME_ANIMATION_EXPORT __declspec(dllexport)
+#else
+#define GFX_KEYFRAME_ANIMATION_EXPORT __declspec(dllimport)
+#endif // defined(CC_ANIMATION_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(GFX_KEYFRAME_ANIMATION_IMPLEMENTATION)
+#define GFX_KEYFRAME_ANIMATION_EXPORT __attribute__((visibility("default")))
+#else
+#define GFX_KEYFRAME_ANIMATION_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define GFX_KEYFRAME_ANIMATION_EXPORT
+#endif
+
+#endif // UI_GFX_ANIMATION_KEYFRAME_KEYFRAME_ANIMATION_EXPORT_H_
diff --git a/chromium/ui/gfx/animation/keyframe/keyframe_animation_unittest.cc b/chromium/ui/gfx/animation/keyframe/keyframe_animation_unittest.cc
new file mode 100644
index 00000000000..7646d94f99f
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/keyframe_animation_unittest.cc
@@ -0,0 +1,695 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/animation/keyframe/keyframe_effect.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
+#include "ui/gfx/animation/keyframe/test/animation_utils.h"
+#include "ui/gfx/geometry/test/size_test_util.h"
+#include "ui/gfx/test/gfx_util.h"
+
+namespace gfx {
+
+static constexpr float kNoise = 1e-6f;
+static constexpr float kEpsilon = 1e-5f;
+
+// Tests client-specific property ids.
+static constexpr int kLayoutOffsetPropertId = 19;
+static constexpr int kBackgroundColorPropertId = 20;
+static constexpr int kOpacityPropertId = 21;
+static constexpr int kBoundsPropertId = 22;
+static constexpr int kTransformPropertId = 23;
+
+class TestAnimationTarget : public SizeAnimationCurve::Target,
+ public TransformAnimationCurve::Target,
+ public FloatAnimationCurve::Target,
+ public ColorAnimationCurve::Target {
+ public:
+ TestAnimationTarget() {
+ layout_offset_.AppendTranslate(0, 0, 0);
+ operations_.AppendTranslate(0, 0, 0);
+ operations_.AppendRotate(1, 0, 0, 0);
+ operations_.AppendScale(1, 1, 1);
+ }
+
+ const SizeF& size() const { return size_; }
+ const TransformOperations& operations() const { return operations_; }
+ const TransformOperations& layout_offset() const { return layout_offset_; }
+ float opacity() const { return opacity_; }
+ SkColor background_color() const { return background_color_; }
+
+ void OnSizeAnimated(const SizeF& size,
+ int target_property_id,
+ KeyframeModel* keyframe_model) override {
+ size_ = size;
+ }
+
+ void OnTransformAnimated(const TransformOperations& operations,
+ int target_property_id,
+ KeyframeModel* keyframe_model) override {
+ if (target_property_id == kLayoutOffsetPropertId) {
+ layout_offset_ = operations;
+ } else {
+ operations_ = operations;
+ }
+ }
+
+ void OnFloatAnimated(const float& opacity,
+ int target_property_id,
+ KeyframeModel* keyframe_model) override {
+ opacity_ = opacity;
+ }
+
+ void OnColorAnimated(const SkColor& color,
+ int target_property_id,
+ KeyframeModel* keyframe_model) override {
+ background_color_ = color;
+ }
+
+ private:
+ TransformOperations layout_offset_;
+ TransformOperations operations_;
+ SizeF size_ = {10.0f, 10.0f};
+ float opacity_ = 1.0f;
+ SkColor background_color_ = SK_ColorRED;
+};
+
+TEST(KeyframeAnimationTest, AddRemoveKeyframeModels) {
+ KeyframeEffect animator;
+ EXPECT_TRUE(animator.keyframe_models().empty());
+ TestAnimationTarget target;
+
+ animator.AddKeyframeModel(CreateSizeAnimation(&target, 1, kBoundsPropertId,
+ SizeF(10, 100), SizeF(20, 200),
+ MicrosecondsToDelta(10000)));
+ EXPECT_EQ(1ul, animator.keyframe_models().size());
+ EXPECT_EQ(kBoundsPropertId, animator.keyframe_models()[0]->TargetProperty());
+
+ TransformOperations from_operations;
+ from_operations.AppendTranslate(10, 100, 1000);
+ TransformOperations to_operations;
+ to_operations.AppendTranslate(20, 200, 2000);
+ animator.AddKeyframeModel(
+ CreateTransformAnimation(&target, 2, kTransformPropertId, from_operations,
+ to_operations, MicrosecondsToDelta(10000)));
+
+ EXPECT_EQ(2ul, animator.keyframe_models().size());
+ EXPECT_EQ(kTransformPropertId,
+ animator.keyframe_models()[1]->TargetProperty());
+
+ animator.AddKeyframeModel(
+ CreateTransformAnimation(&target, 3, kTransformPropertId, from_operations,
+ to_operations, MicrosecondsToDelta(10000)));
+ EXPECT_EQ(3ul, animator.keyframe_models().size());
+ EXPECT_EQ(kTransformPropertId,
+ animator.keyframe_models()[2]->TargetProperty());
+
+ animator.RemoveKeyframeModels(kTransformPropertId);
+ EXPECT_EQ(1ul, animator.keyframe_models().size());
+ EXPECT_EQ(kBoundsPropertId, animator.keyframe_models()[0]->TargetProperty());
+
+ animator.RemoveKeyframeModel(animator.keyframe_models()[0]->id());
+ EXPECT_TRUE(animator.keyframe_models().empty());
+}
+
+TEST(KeyframeAnimationTest, AnimationLifecycle) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+
+ animator.AddKeyframeModel(CreateSizeAnimation(&target, 1, kBoundsPropertId,
+ SizeF(10, 100), SizeF(20, 200),
+ MicrosecondsToDelta(10000)));
+ EXPECT_EQ(1ul, animator.keyframe_models().size());
+ EXPECT_EQ(kBoundsPropertId, animator.keyframe_models()[0]->TargetProperty());
+ EXPECT_EQ(KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY,
+ animator.keyframe_models()[0]->run_state());
+
+ base::TimeTicks start_time = MicrosecondsToTicks(1);
+ animator.Tick(start_time);
+ EXPECT_EQ(KeyframeModel::RUNNING, animator.keyframe_models()[0]->run_state());
+
+ EXPECT_SIZEF_EQ(SizeF(10, 100), target.size());
+
+ // Tick beyond the animation
+ animator.Tick(start_time + MicrosecondsToDelta(20000));
+
+ EXPECT_TRUE(animator.keyframe_models().empty());
+
+ // Should have assumed the final value.
+ EXPECT_SIZEF_EQ(SizeF(20, 200), target.size());
+}
+
+TEST(KeyframeAnimationTest, AnimationQueue) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+
+ animator.AddKeyframeModel(CreateSizeAnimation(&target, 1, kBoundsPropertId,
+ SizeF(10, 100), SizeF(20, 200),
+ MicrosecondsToDelta(10000)));
+ EXPECT_EQ(1ul, animator.keyframe_models().size());
+ EXPECT_EQ(kBoundsPropertId, animator.keyframe_models()[0]->TargetProperty());
+ EXPECT_EQ(KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY,
+ animator.keyframe_models()[0]->run_state());
+
+ base::TimeTicks start_time = MicrosecondsToTicks(1);
+ animator.Tick(start_time);
+ EXPECT_EQ(KeyframeModel::RUNNING, animator.keyframe_models()[0]->run_state());
+ EXPECT_SIZEF_EQ(SizeF(10, 100), target.size());
+
+ animator.AddKeyframeModel(CreateSizeAnimation(&target, 2, kBoundsPropertId,
+ SizeF(10, 100), SizeF(20, 200),
+ MicrosecondsToDelta(10000)));
+
+ TransformOperations from_operations;
+ from_operations.AppendTranslate(10, 100, 1000);
+ TransformOperations to_operations;
+ to_operations.AppendTranslate(20, 200, 2000);
+ animator.AddKeyframeModel(
+ CreateTransformAnimation(&target, 3, kTransformPropertId, from_operations,
+ to_operations, MicrosecondsToDelta(10000)));
+
+ EXPECT_EQ(3ul, animator.keyframe_models().size());
+ EXPECT_EQ(kBoundsPropertId, animator.keyframe_models()[1]->TargetProperty());
+ EXPECT_EQ(kTransformPropertId,
+ animator.keyframe_models()[2]->TargetProperty());
+ int id1 = animator.keyframe_models()[1]->id();
+
+ animator.Tick(start_time + MicrosecondsToDelta(1));
+
+ // Only the transform animation should have started (since there's no
+ // conflicting animation).
+ EXPECT_EQ(KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY,
+ animator.keyframe_models()[1]->run_state());
+ EXPECT_EQ(KeyframeModel::RUNNING, animator.keyframe_models()[2]->run_state());
+
+ // Tick beyond the first animator. This should cause it (and the transform
+ // animation) to get removed and for the second bounds animation to start.
+ animator.Tick(start_time + MicrosecondsToDelta(15000));
+
+ EXPECT_EQ(1ul, animator.keyframe_models().size());
+ EXPECT_EQ(KeyframeModel::RUNNING, animator.keyframe_models()[0]->run_state());
+ EXPECT_EQ(id1, animator.keyframe_models()[0]->id());
+
+ // Tick beyond all animations. There should be none remaining.
+ animator.Tick(start_time + MicrosecondsToDelta(30000));
+ EXPECT_TRUE(animator.keyframe_models().empty());
+}
+
+TEST(KeyframeAnimationTest, FinishedTransition) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kOpacityPropertId};
+ transition.duration = MsToDelta(10);
+ animator.set_transition(transition);
+
+ base::TimeTicks start_time = MsToTicks(1000);
+ animator.Tick(start_time);
+
+ float from = 1.0f;
+ float to = 0.0f;
+ animator.TransitionFloatTo(&target, start_time, kOpacityPropertId, from, to);
+
+ animator.Tick(start_time);
+ EXPECT_EQ(from, target.opacity());
+
+ // We now simulate a long pause where the element hasn't been ticked (eg, it
+ // may have been hidden). If this happens, the unticked transition must still
+ // be treated as having finished.
+ animator.TransitionFloatTo(&target, start_time + MsToDelta(1000),
+ kOpacityPropertId, target.opacity(), 1.0f);
+
+ animator.Tick(start_time + MsToDelta(1000));
+ EXPECT_EQ(to, target.opacity());
+}
+
+TEST(KeyframeAnimationTest, OpacityTransitions) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kOpacityPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ float from = 1.0f;
+ float to = 0.5f;
+ animator.TransitionFloatTo(&target, start_time, kOpacityPropertId, from, to);
+
+ EXPECT_EQ(from, target.opacity());
+ animator.Tick(start_time);
+
+ // Scheduling a redundant, approximately equal transition should be ignored.
+ int keyframe_model_id = animator.keyframe_models().front()->id();
+ float nearby = to + kNoise;
+ animator.TransitionFloatTo(&target, start_time, kOpacityPropertId, from,
+ nearby);
+ EXPECT_EQ(keyframe_model_id, animator.keyframe_models().front()->id());
+
+ animator.Tick(start_time + MicrosecondsToDelta(5000));
+ EXPECT_GT(from, target.opacity());
+ EXPECT_LT(to, target.opacity());
+
+ animator.Tick(start_time + MicrosecondsToDelta(10000));
+ EXPECT_EQ(to, target.opacity());
+}
+
+TEST(KeyframeAnimationTest, ReversedOpacityTransitions) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kOpacityPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ float from = 1.0f;
+ float to = 0.5f;
+ animator.TransitionFloatTo(&target, start_time, kOpacityPropertId, from, to);
+
+ EXPECT_EQ(from, target.opacity());
+ animator.Tick(start_time);
+
+ animator.Tick(start_time + MicrosecondsToDelta(1000));
+ float value_before_reversing = target.opacity();
+ EXPECT_GT(from, value_before_reversing);
+ EXPECT_LT(to, value_before_reversing);
+
+ animator.TransitionFloatTo(&target, start_time + MicrosecondsToDelta(1000),
+ kOpacityPropertId, target.opacity(), from);
+ animator.Tick(start_time + MicrosecondsToDelta(1000));
+ EXPECT_FLOAT_EQ(value_before_reversing, target.opacity());
+
+ animator.Tick(start_time + MicrosecondsToDelta(2000));
+ EXPECT_EQ(from, target.opacity());
+}
+
+TEST(KeyframeAnimationTest, LayoutOffsetTransitions) {
+ // In this test, we do expect exact equality.
+ float tolerance = 0.0f;
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kLayoutOffsetPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ TransformOperations from = target.layout_offset();
+
+ TransformOperations to;
+ to.AppendTranslate(8, 0, 0);
+
+ animator.TransitionTransformOperationsTo(&target, start_time,
+ kLayoutOffsetPropertId, from, to);
+
+ EXPECT_TRUE(from.ApproximatelyEqual(target.layout_offset(), tolerance));
+ animator.Tick(start_time);
+
+ // Scheduling a redundant, approximately equal transition should be ignored.
+ int keyframe_model_id = animator.keyframe_models().front()->id();
+ TransformOperations nearby = to;
+ nearby.at(0).translate.x += kNoise;
+ animator.TransitionTransformOperationsTo(
+ &target, start_time, kLayoutOffsetPropertId, from, nearby);
+ EXPECT_EQ(keyframe_model_id, animator.keyframe_models().front()->id());
+
+ animator.Tick(start_time + MicrosecondsToDelta(5000));
+ EXPECT_LT(from.at(0).translate.x, target.layout_offset().at(0).translate.x);
+ EXPECT_GT(to.at(0).translate.x, target.layout_offset().at(0).translate.x);
+
+ animator.Tick(start_time + MicrosecondsToDelta(10000));
+ EXPECT_TRUE(to.ApproximatelyEqual(target.layout_offset(), tolerance));
+}
+
+TEST(KeyframeAnimationTest, TransformTransitions) {
+ // In this test, we do expect exact equality.
+ float tolerance = 0.0f;
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kTransformPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ TransformOperations from = target.operations();
+
+ TransformOperations to;
+ to.AppendTranslate(8, 0, 0);
+ to.AppendRotate(1, 0, 0, 0);
+ to.AppendScale(1, 1, 1);
+
+ animator.TransitionTransformOperationsTo(&target, start_time,
+ kTransformPropertId, from, to);
+
+ EXPECT_TRUE(from.ApproximatelyEqual(target.operations(), tolerance));
+ animator.Tick(start_time);
+
+ // Scheduling a redundant, approximately equal transition should be ignored.
+ int keyframe_model_id = animator.keyframe_models().front()->id();
+ TransformOperations nearby = to;
+ nearby.at(0).translate.x += kNoise;
+ animator.TransitionTransformOperationsTo(&target, start_time,
+ kTransformPropertId, from, nearby);
+ EXPECT_EQ(keyframe_model_id, animator.keyframe_models().front()->id());
+
+ animator.Tick(start_time + MicrosecondsToDelta(5000));
+ EXPECT_LT(from.at(0).translate.x, target.operations().at(0).translate.x);
+ EXPECT_GT(to.at(0).translate.x, target.operations().at(0).translate.x);
+
+ animator.Tick(start_time + MicrosecondsToDelta(10000));
+ EXPECT_TRUE(to.ApproximatelyEqual(target.operations(), tolerance));
+}
+
+TEST(KeyframeAnimationTest, ReversedTransformTransitions) {
+ // In this test, we do expect exact equality.
+ float tolerance = 0.0f;
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kTransformPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ TransformOperations from = target.operations();
+
+ TransformOperations to;
+ to.AppendTranslate(8, 0, 0);
+ to.AppendRotate(1, 0, 0, 0);
+ to.AppendScale(1, 1, 1);
+
+ animator.TransitionTransformOperationsTo(&target, start_time,
+ kTransformPropertId, from, to);
+
+ EXPECT_TRUE(from.ApproximatelyEqual(target.operations(), tolerance));
+ animator.Tick(start_time);
+
+ animator.Tick(start_time + MicrosecondsToDelta(1000));
+ TransformOperations value_before_reversing = target.operations();
+ EXPECT_LT(from.at(0).translate.x, target.operations().at(0).translate.x);
+ EXPECT_GT(to.at(0).translate.x, target.operations().at(0).translate.x);
+
+ animator.TransitionTransformOperationsTo(
+ &target, start_time + MicrosecondsToDelta(1000), kTransformPropertId,
+ target.operations(), from);
+ animator.Tick(start_time + MicrosecondsToDelta(1000));
+ EXPECT_TRUE(value_before_reversing.ApproximatelyEqual(target.operations(),
+ tolerance));
+
+ animator.Tick(start_time + MicrosecondsToDelta(2000));
+ EXPECT_TRUE(from.ApproximatelyEqual(target.operations(), tolerance));
+}
+
+TEST(KeyframeAnimationTest, BoundsTransitions) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kBoundsPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ SizeF from = target.size();
+ SizeF to(20.0f, 20.0f);
+
+ animator.TransitionSizeTo(&target, start_time, kBoundsPropertId, from, to);
+
+ EXPECT_FLOAT_SIZE_EQ(from, target.size());
+ animator.Tick(start_time);
+
+ // Scheduling a redundant, approximately equal transition should be ignored.
+ int keyframe_model_id = animator.keyframe_models().front()->id();
+ SizeF nearby = to;
+ nearby.set_width(to.width() + kNoise);
+ animator.TransitionSizeTo(&target, start_time, kBoundsPropertId, from,
+ nearby);
+ EXPECT_EQ(keyframe_model_id, animator.keyframe_models().front()->id());
+
+ animator.Tick(start_time + MicrosecondsToDelta(5000));
+ EXPECT_LT(from.width(), target.size().width());
+ EXPECT_GT(to.width(), target.size().width());
+ EXPECT_LT(from.height(), target.size().height());
+ EXPECT_GT(to.height(), target.size().height());
+
+ animator.Tick(start_time + MicrosecondsToDelta(10000));
+ EXPECT_FLOAT_SIZE_EQ(to, target.size());
+}
+
+TEST(KeyframeAnimationTest, ReversedBoundsTransitions) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kBoundsPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ SizeF from = target.size();
+ SizeF to(20.0f, 20.0f);
+
+ animator.TransitionSizeTo(&target, start_time, kBoundsPropertId, from, to);
+
+ EXPECT_FLOAT_SIZE_EQ(from, target.size());
+ animator.Tick(start_time);
+
+ animator.Tick(start_time + MicrosecondsToDelta(1000));
+ SizeF value_before_reversing = target.size();
+ EXPECT_LT(from.width(), target.size().width());
+ EXPECT_GT(to.width(), target.size().width());
+ EXPECT_LT(from.height(), target.size().height());
+ EXPECT_GT(to.height(), target.size().height());
+
+ animator.TransitionSizeTo(&target, start_time + MicrosecondsToDelta(1000),
+ kBoundsPropertId, target.size(), from);
+ animator.Tick(start_time + MicrosecondsToDelta(1000));
+ EXPECT_FLOAT_SIZE_EQ(value_before_reversing, target.size());
+
+ animator.Tick(start_time + MicrosecondsToDelta(2000));
+ EXPECT_FLOAT_SIZE_EQ(from, target.size());
+}
+
+TEST(KeyframeAnimationTest, BackgroundColorTransitions) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kBackgroundColorPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ SkColor from = SK_ColorRED;
+ SkColor to = SK_ColorGREEN;
+
+ animator.TransitionColorTo(&target, start_time, kBackgroundColorPropertId,
+ from, to);
+
+ EXPECT_EQ(from, target.background_color());
+ animator.Tick(start_time);
+
+ animator.Tick(start_time + MicrosecondsToDelta(5000));
+ EXPECT_GT(SkColorGetR(from), SkColorGetR(target.background_color()));
+ EXPECT_LT(SkColorGetR(to), SkColorGetR(target.background_color()));
+ EXPECT_LT(SkColorGetG(from), SkColorGetG(target.background_color()));
+ EXPECT_GT(SkColorGetG(to), SkColorGetG(target.background_color()));
+ EXPECT_EQ(0u, SkColorGetB(target.background_color()));
+ EXPECT_EQ(255u, SkColorGetA(target.background_color()));
+
+ animator.Tick(start_time + MicrosecondsToDelta(10000));
+ EXPECT_EQ(to, target.background_color());
+}
+
+TEST(KeyframeAnimationTest, ReversedBackgroundColorTransitions) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kBackgroundColorPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ SkColor from = SK_ColorRED;
+ SkColor to = SK_ColorGREEN;
+
+ animator.TransitionColorTo(&target, start_time, kBackgroundColorPropertId,
+ from, to);
+
+ EXPECT_EQ(from, target.background_color());
+ animator.Tick(start_time);
+
+ animator.Tick(start_time + MicrosecondsToDelta(1000));
+ SkColor value_before_reversing = target.background_color();
+ EXPECT_GT(SkColorGetR(from), SkColorGetR(target.background_color()));
+ EXPECT_LT(SkColorGetR(to), SkColorGetR(target.background_color()));
+ EXPECT_LT(SkColorGetG(from), SkColorGetG(target.background_color()));
+ EXPECT_GT(SkColorGetG(to), SkColorGetG(target.background_color()));
+ EXPECT_EQ(0u, SkColorGetB(target.background_color()));
+ EXPECT_EQ(255u, SkColorGetA(target.background_color()));
+
+ animator.TransitionColorTo(&target, start_time + MicrosecondsToDelta(1000),
+ kBackgroundColorPropertId,
+ target.background_color(), from);
+ animator.Tick(start_time + MicrosecondsToDelta(1000));
+ EXPECT_EQ(value_before_reversing, target.background_color());
+
+ animator.Tick(start_time + MicrosecondsToDelta(2000));
+ EXPECT_EQ(from, target.background_color());
+}
+
+TEST(KeyframeAnimationTest, DoubleReversedTransitions) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kOpacityPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ float from = 1.0f;
+ float to = 0.5f;
+ animator.TransitionFloatTo(&target, start_time, kOpacityPropertId, from, to);
+
+ EXPECT_EQ(from, target.opacity());
+ animator.Tick(start_time);
+
+ animator.Tick(start_time + MicrosecondsToDelta(1000));
+ float value_before_reversing = target.opacity();
+ EXPECT_GT(from, value_before_reversing);
+ EXPECT_LT(to, value_before_reversing);
+
+ animator.TransitionFloatTo(&target, start_time + MicrosecondsToDelta(1000),
+ kOpacityPropertId, target.opacity(), from);
+ animator.Tick(start_time + MicrosecondsToDelta(1000));
+ EXPECT_FLOAT_EQ(value_before_reversing, target.opacity());
+
+ animator.Tick(start_time + MicrosecondsToDelta(1500));
+ value_before_reversing = target.opacity();
+ // If the code for reversing transitions does not account for an existing time
+ // offset, then reversing a second time will give incorrect values.
+ animator.TransitionFloatTo(&target, start_time + MicrosecondsToDelta(1500),
+ kOpacityPropertId, target.opacity(), to);
+ animator.Tick(start_time + MicrosecondsToDelta(1500));
+ EXPECT_FLOAT_EQ(value_before_reversing, target.opacity());
+}
+
+TEST(KeyframeAnimationTest, RedundantTransition) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kOpacityPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ float from = 1.0f;
+ float to = 0.5f;
+ animator.TransitionFloatTo(&target, start_time, kOpacityPropertId, from, to);
+
+ EXPECT_EQ(from, target.opacity());
+ animator.Tick(start_time);
+
+ animator.Tick(start_time + MicrosecondsToDelta(1000));
+ float value_before_redundant_transition = target.opacity();
+
+ // While an existing transition is in progress to the same value, we should
+ // not start a new transition.
+ animator.TransitionFloatTo(&target, start_time, kOpacityPropertId,
+ target.opacity(), to);
+
+ EXPECT_EQ(1lu, animator.keyframe_models().size());
+ EXPECT_EQ(value_before_redundant_transition, target.opacity());
+}
+
+TEST(KeyframeAnimationTest, TransitionToSameValue) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ Transition transition;
+ transition.target_properties = {kOpacityPropertId};
+ transition.duration = MicrosecondsToDelta(10000);
+ animator.set_transition(transition);
+
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ // Transitioning to the same value should be a no-op.
+ float from = 1.0f;
+ float to = 1.0f;
+ animator.TransitionFloatTo(&target, start_time, kOpacityPropertId, from, to);
+ EXPECT_EQ(from, target.opacity());
+ EXPECT_TRUE(animator.keyframe_models().empty());
+}
+
+TEST(KeyframeAnimationTest, CorrectTargetValue) {
+ TestAnimationTarget target;
+ KeyframeEffect animator;
+ base::TimeDelta duration = MicrosecondsToDelta(10000);
+
+ float from_opacity = 1.0f;
+ float to_opacity = 0.5f;
+ SizeF from_bounds = SizeF(10, 200);
+ SizeF to_bounds = SizeF(20, 200);
+ SkColor from_color = SK_ColorRED;
+ SkColor to_color = SK_ColorGREEN;
+ TransformOperations from_transform;
+ from_transform.AppendTranslate(10, 100, 1000);
+ TransformOperations to_transform;
+ to_transform.AppendTranslate(20, 200, 2000);
+
+ // Verify the default value is returned if there's no running animations.
+ EXPECT_EQ(from_opacity,
+ animator.GetTargetFloatValue(kOpacityPropertId, from_opacity));
+ EXPECT_SIZEF_EQ(from_bounds,
+ animator.GetTargetSizeValue(kBoundsPropertId, from_bounds));
+ EXPECT_EQ(from_color, animator.GetTargetColorValue(kBackgroundColorPropertId,
+ from_color));
+ EXPECT_TRUE(from_transform.ApproximatelyEqual(
+ animator.GetTargetTransformOperationsValue(kTransformPropertId,
+ from_transform),
+ kEpsilon));
+
+ // Add keyframe_models.
+ animator.AddKeyframeModel(CreateFloatAnimation(
+ &target, 2, kOpacityPropertId, from_opacity, to_opacity, duration));
+ animator.AddKeyframeModel(CreateSizeAnimation(
+ &target, 1, kBoundsPropertId, from_bounds, to_bounds, duration));
+ animator.AddKeyframeModel(CreateColorAnimation(
+ &target, 3, kBackgroundColorPropertId, from_color, to_color, duration));
+ animator.AddKeyframeModel(CreateTransformAnimation(
+ &target, 4, kTransformPropertId, from_transform, to_transform, duration));
+
+ base::TimeTicks start_time = MicrosecondsToTicks(1000000);
+ animator.Tick(start_time);
+
+ // Verify target value.
+ EXPECT_EQ(to_opacity,
+ animator.GetTargetFloatValue(kOpacityPropertId, from_opacity));
+ EXPECT_SIZEF_EQ(to_bounds,
+ animator.GetTargetSizeValue(kBoundsPropertId, from_bounds));
+ EXPECT_EQ(to_color, animator.GetTargetColorValue(kBackgroundColorPropertId,
+ from_color));
+ EXPECT_TRUE(to_transform.ApproximatelyEqual(
+ animator.GetTargetTransformOperationsValue(kTransformPropertId,
+ from_transform),
+ kEpsilon));
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/animation/keyframe/keyframe_effect.cc b/chromium/ui/gfx/animation/keyframe/keyframe_effect.cc
new file mode 100644
index 00000000000..84b0f11327e
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/keyframe_effect.cc
@@ -0,0 +1,418 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/animation/keyframe/keyframe_effect.h"
+
+#include <algorithm>
+
+#include "base/numerics/ranges.h"
+#include "base/stl_util.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
+
+namespace gfx {
+
+namespace {
+
+static constexpr float kTolerance = 1e-5f;
+
+static int s_next_keyframe_model_id = 1;
+static int s_next_group_id = 1;
+
+void ReverseKeyframeModel(base::TimeTicks monotonic_time,
+ KeyframeModel* keyframe_model) {
+ keyframe_model->set_direction(keyframe_model->direction() ==
+ KeyframeModel::Direction::NORMAL
+ ? KeyframeModel::Direction::REVERSE
+ : KeyframeModel::Direction::NORMAL);
+ // Our goal here is to reverse the given keyframe_model. That is, if
+ // we're 20% of the way through the keyframe_model in the forward direction,
+ // we'd like to be 80% of the way of the reversed keyframe model (so it will
+ // end quickly).
+ //
+ // We can modify our "progress" through an animation by modifying the "time
+ // offset", a value added to the current time by the animation system before
+ // applying any other adjustments.
+ //
+ // Let our start time be s, our current time be t, and our final time (or
+ // duration) be d. After reversing the keyframe_model, we would like to start
+ // sampling from d - t as depicted below.
+ //
+ // Forward:
+ // s t d
+ // |----|-------------------------|
+ //
+ // Reversed:
+ // s t d
+ // |----|--------------------|----|
+ // -----time-offset----->
+ //
+ // Now, if we let o represent our desired offset, we need to ensure that
+ // t = d - (o + t)
+ //
+ // That is, sampling at the current time in either the forward or reverse
+ // curves must result in the same value, otherwise we'll get jank.
+ //
+ // This implies that,
+ // 0 = d - o - 2t
+ // o = d - 2t
+ //
+ // Now if there was a previous offset, we must adjust d by that offset before
+ // performing this computation, so it becomes d - o_old - 2t:
+ keyframe_model->set_time_offset(
+ keyframe_model->curve()->Duration() - keyframe_model->time_offset() -
+ (2 * (monotonic_time - keyframe_model->start_time())));
+}
+
+std::unique_ptr<CubicBezierTimingFunction> CreateTransitionTimingFunction() {
+ return CubicBezierTimingFunction::CreatePreset(
+ CubicBezierTimingFunction::EaseType::EASE);
+}
+
+base::TimeDelta GetStartTime(KeyframeModel* keyframe_model) {
+ if (keyframe_model->direction() == KeyframeModel::Direction::NORMAL) {
+ return base::TimeDelta();
+ }
+ return keyframe_model->curve()->Duration();
+}
+
+base::TimeDelta GetEndTime(KeyframeModel* keyframe_model) {
+ if (keyframe_model->direction() == KeyframeModel::Direction::REVERSE) {
+ return base::TimeDelta();
+ }
+ return keyframe_model->curve()->Duration();
+}
+
+bool SufficientlyEqual(float lhs, float rhs) {
+ return base::IsApproximatelyEqual(lhs, rhs, kTolerance);
+}
+
+bool SufficientlyEqual(const gfx::TransformOperations& lhs,
+ const gfx::TransformOperations& rhs) {
+ return lhs.ApproximatelyEqual(rhs, kTolerance);
+}
+
+bool SufficientlyEqual(const gfx::SizeF& lhs, const gfx::SizeF& rhs) {
+ return base::IsApproximatelyEqual(lhs.width(), rhs.width(), kTolerance) &&
+ base::IsApproximatelyEqual(lhs.height(), rhs.height(), kTolerance);
+}
+
+bool SufficientlyEqual(SkColor lhs, SkColor rhs) {
+ return lhs == rhs;
+}
+
+template <typename T>
+struct AnimationTraits {};
+
+#define DEFINE_ANIMATION_TRAITS(value_type, name) \
+ template <> \
+ struct AnimationTraits<value_type> { \
+ typedef value_type ValueType; \
+ typedef name##AnimationCurve::Target TargetType; \
+ typedef name##AnimationCurve CurveType; \
+ typedef Keyframed##name##AnimationCurve KeyframedCurveType; \
+ typedef name##Keyframe KeyframeType; \
+ static const CurveType* ToDerivedCurve(const AnimationCurve* curve) { \
+ return name##AnimationCurve::To##name##AnimationCurve(curve); \
+ } \
+ static void OnValueAnimated(name##AnimationCurve::Target* target, \
+ const ValueType& target_value, \
+ int target_property) { \
+ target->On##name##Animated(target_value, target_property, nullptr); \
+ } \
+ }
+
+DEFINE_ANIMATION_TRAITS(float, Float);
+DEFINE_ANIMATION_TRAITS(gfx::TransformOperations, Transform);
+DEFINE_ANIMATION_TRAITS(gfx::SizeF, Size);
+DEFINE_ANIMATION_TRAITS(SkColor, Color);
+
+#undef DEFINE_ANIMATION_TRAITS
+
+template <typename ValueType>
+void TransitionValueTo(KeyframeEffect* animator,
+ typename AnimationTraits<ValueType>::TargetType* target,
+ base::TimeTicks monotonic_time,
+ int target_property,
+ const ValueType& from,
+ const ValueType& to) {
+ DCHECK(target);
+
+ if (animator->transition().target_properties.find(target_property) ==
+ animator->transition().target_properties.end()) {
+ AnimationTraits<ValueType>::OnValueAnimated(target, to, target_property);
+ return;
+ }
+
+ KeyframeModel* running_keyframe_model =
+ animator->GetRunningKeyframeModelForProperty(target_property);
+
+ ValueType effective_current = from;
+
+ if (running_keyframe_model) {
+ const auto* curve = AnimationTraits<ValueType>::ToDerivedCurve(
+ running_keyframe_model->curve());
+
+ if (running_keyframe_model->IsFinishedAt(monotonic_time)) {
+ effective_current = curve->GetValue(GetEndTime(running_keyframe_model));
+ } else {
+ if (SufficientlyEqual(
+ to, curve->GetValue(GetEndTime(running_keyframe_model)))) {
+ return;
+ }
+ if (SufficientlyEqual(
+ to, curve->GetValue(GetStartTime(running_keyframe_model)))) {
+ ReverseKeyframeModel(monotonic_time, running_keyframe_model);
+ return;
+ }
+ }
+ } else if (SufficientlyEqual(to, from)) {
+ return;
+ }
+
+ animator->RemoveKeyframeModels(target_property);
+
+ std::unique_ptr<typename AnimationTraits<ValueType>::KeyframedCurveType>
+ curve(AnimationTraits<ValueType>::KeyframedCurveType::Create());
+
+ curve->AddKeyframe(AnimationTraits<ValueType>::KeyframeType::Create(
+ base::TimeDelta(), effective_current, CreateTransitionTimingFunction()));
+
+ curve->AddKeyframe(AnimationTraits<ValueType>::KeyframeType::Create(
+ animator->transition().duration, to, CreateTransitionTimingFunction()));
+
+ curve->set_target(target);
+
+ animator->AddKeyframeModel(KeyframeModel::Create(
+ std::move(curve), KeyframeEffect::GetNextKeyframeModelId(),
+ target_property));
+}
+
+} // namespace
+
+int KeyframeEffect::GetNextKeyframeModelId() {
+ return s_next_keyframe_model_id++;
+}
+
+int KeyframeEffect::GetNextGroupId() {
+ return s_next_group_id++;
+}
+
+KeyframeEffect::KeyframeEffect() {}
+KeyframeEffect::~KeyframeEffect() {}
+
+void KeyframeEffect::AddKeyframeModel(
+ std::unique_ptr<KeyframeModel> keyframe_model) {
+ keyframe_models_.push_back(std::move(keyframe_model));
+}
+
+void KeyframeEffect::RemoveKeyframeModel(int keyframe_model_id) {
+ base::EraseIf(keyframe_models_,
+ [keyframe_model_id](
+ const std::unique_ptr<KeyframeModel>& keyframe_model) {
+ return keyframe_model->id() == keyframe_model_id;
+ });
+}
+
+void KeyframeEffect::RemoveKeyframeModels(int target_property) {
+ base::EraseIf(
+ keyframe_models_,
+ [target_property](const std::unique_ptr<KeyframeModel>& keyframe_model) {
+ return keyframe_model->TargetProperty() == target_property;
+ });
+}
+
+void KeyframeEffect::Tick(base::TimeTicks monotonic_time) {
+ TickInternal(monotonic_time, true);
+}
+
+void KeyframeEffect::TickKeyframeModel(base::TimeTicks monotonic_time,
+ KeyframeModel* keyframe_model) {
+ if ((keyframe_model->run_state() != KeyframeModel::STARTING &&
+ keyframe_model->run_state() != KeyframeModel::RUNNING &&
+ keyframe_model->run_state() != KeyframeModel::PAUSED) ||
+ !keyframe_model->HasActiveTime(monotonic_time)) {
+ return;
+ }
+
+ AnimationCurve* curve = keyframe_model->curve();
+ base::TimeDelta trimmed =
+ keyframe_model->TrimTimeToCurrentIteration(monotonic_time);
+ curve->Tick(trimmed, keyframe_model->TargetProperty(), keyframe_model);
+}
+
+void KeyframeEffect::TickInternal(base::TimeTicks monotonic_time,
+ bool include_infinite_animations) {
+ StartKeyframeModels(monotonic_time, include_infinite_animations);
+
+ for (auto& keyframe_model : keyframe_models_) {
+ if (!include_infinite_animations &&
+ keyframe_model->iterations() == std::numeric_limits<double>::infinity())
+ continue;
+ TickKeyframeModel(monotonic_time, keyframe_model.get());
+ }
+
+ // Remove finished keyframe_models.
+ base::EraseIf(
+ keyframe_models_,
+ [monotonic_time](const std::unique_ptr<KeyframeModel>& keyframe_model) {
+ return !keyframe_model->is_finished() &&
+ keyframe_model->IsFinishedAt(monotonic_time);
+ });
+
+ StartKeyframeModels(monotonic_time, include_infinite_animations);
+}
+
+void KeyframeEffect::FinishAll() {
+ base::TimeTicks now = base::TimeTicks::Now();
+ const bool include_infinite_animations = false;
+ TickInternal(now, include_infinite_animations);
+ TickInternal(base::TimeTicks::Max(), include_infinite_animations);
+#ifndef NDEBUG
+ for (auto& keyframe_model : keyframe_models_) {
+ DCHECK_EQ(std::numeric_limits<double>::infinity(),
+ keyframe_model->iterations());
+ }
+#endif
+}
+
+void KeyframeEffect::SetTransitionedProperties(
+ const std::set<int>& properties) {
+ transition_.target_properties = properties;
+}
+
+void KeyframeEffect::SetTransitionDuration(base::TimeDelta delta) {
+ transition_.duration = delta;
+}
+
+void KeyframeEffect::TransitionFloatTo(FloatAnimationCurve::Target* target,
+ base::TimeTicks monotonic_time,
+ int target_property,
+ float from,
+ float to) {
+ TransitionValueTo<float>(this, target, monotonic_time, target_property, from,
+ to);
+}
+
+void KeyframeEffect::TransitionTransformOperationsTo(
+ TransformAnimationCurve::Target* target,
+ base::TimeTicks monotonic_time,
+ int target_property,
+ const gfx::TransformOperations& from,
+ const gfx::TransformOperations& to) {
+ TransitionValueTo<gfx::TransformOperations>(this, target, monotonic_time,
+ target_property, from, to);
+}
+
+void KeyframeEffect::TransitionSizeTo(SizeAnimationCurve::Target* target,
+ base::TimeTicks monotonic_time,
+ int target_property,
+ const gfx::SizeF& from,
+ const gfx::SizeF& to) {
+ TransitionValueTo<gfx::SizeF>(this, target, monotonic_time, target_property,
+ from, to);
+}
+
+void KeyframeEffect::TransitionColorTo(ColorAnimationCurve::Target* target,
+ base::TimeTicks monotonic_time,
+ int target_property,
+ SkColor from,
+ SkColor to) {
+ TransitionValueTo<SkColor>(this, target, monotonic_time, target_property,
+ from, to);
+}
+
+bool KeyframeEffect::IsAnimatingProperty(int property) const {
+ for (auto& keyframe_model : keyframe_models_) {
+ if (keyframe_model->TargetProperty() == property)
+ return true;
+ }
+ return false;
+}
+
+float KeyframeEffect::GetTargetFloatValue(int target_property,
+ float default_value) const {
+ return GetTargetValue<float>(target_property, default_value);
+}
+
+gfx::TransformOperations KeyframeEffect::GetTargetTransformOperationsValue(
+ int target_property,
+ const gfx::TransformOperations& default_value) const {
+ return GetTargetValue<gfx::TransformOperations>(target_property,
+ default_value);
+}
+
+gfx::SizeF KeyframeEffect::GetTargetSizeValue(
+ int target_property,
+ const gfx::SizeF& default_value) const {
+ return GetTargetValue<gfx::SizeF>(target_property, default_value);
+}
+
+SkColor KeyframeEffect::GetTargetColorValue(int target_property,
+ SkColor default_value) const {
+ return GetTargetValue<SkColor>(target_property, default_value);
+}
+
+void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time,
+ bool include_infinite_animations) {
+ TargetProperties animated_properties;
+ for (auto& keyframe_model : keyframe_models_) {
+ if (!include_infinite_animations &&
+ keyframe_model->iterations() == std::numeric_limits<double>::infinity())
+ continue;
+ if (keyframe_model->run_state() == KeyframeModel::RUNNING ||
+ keyframe_model->run_state() == KeyframeModel::PAUSED) {
+ animated_properties[keyframe_model->TargetProperty()] = true;
+ }
+ }
+ for (auto& keyframe_model : keyframe_models_) {
+ if (!include_infinite_animations &&
+ keyframe_model->iterations() == std::numeric_limits<double>::infinity())
+ continue;
+ if (!animated_properties[keyframe_model->TargetProperty()] &&
+ keyframe_model->run_state() ==
+ KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY) {
+ animated_properties[keyframe_model->TargetProperty()] = true;
+ keyframe_model->SetRunState(KeyframeModel::RUNNING, monotonic_time);
+ keyframe_model->set_start_time(monotonic_time);
+ }
+ }
+}
+
+KeyframeModel* KeyframeEffect::GetRunningKeyframeModelForProperty(
+ int target_property) const {
+ for (auto& keyframe_model : keyframe_models_) {
+ if ((keyframe_model->run_state() == KeyframeModel::RUNNING ||
+ keyframe_model->run_state() == KeyframeModel::PAUSED) &&
+ keyframe_model->TargetProperty() == target_property) {
+ return keyframe_model.get();
+ }
+ }
+ return nullptr;
+}
+
+KeyframeModel* KeyframeEffect::GetKeyframeModelForProperty(
+ int target_property) const {
+ for (auto& keyframe_model : keyframe_models_) {
+ if (keyframe_model->TargetProperty() == target_property) {
+ return keyframe_model.get();
+ }
+ }
+ return nullptr;
+}
+
+template <typename ValueType>
+ValueType KeyframeEffect::GetTargetValue(int target_property,
+ const ValueType& default_value) const {
+ KeyframeModel* running_keyframe_model =
+ GetKeyframeModelForProperty(target_property);
+ if (!running_keyframe_model) {
+ return default_value;
+ }
+ const auto* curve = AnimationTraits<ValueType>::ToDerivedCurve(
+ running_keyframe_model->curve());
+ return curve->GetValue(GetEndTime(running_keyframe_model));
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/animation/keyframe/keyframe_effect.h b/chromium/ui/gfx/animation/keyframe/keyframe_effect.h
new file mode 100644
index 00000000000..6894cadaa93
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/keyframe_effect.h
@@ -0,0 +1,119 @@
+// 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_GFX_ANIMATION_KEYFRAME_KEYFRAME_EFFECT_H_
+#define UI_GFX_ANIMATION_KEYFRAME_KEYFRAME_EFFECT_H_
+
+#include <bitset>
+#include <set>
+#include <vector>
+
+#include "base/macros.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
+#include "ui/gfx/animation/keyframe/keyframe_animation_export.h"
+#include "ui/gfx/animation/keyframe/keyframe_model.h"
+#include "ui/gfx/animation/keyframe/transition.h"
+
+namespace gfx {
+class SizeF;
+class TransformOperations;
+
+static constexpr size_t kMaxTargetPropertyId = 32u;
+using TargetProperties = std::bitset<kMaxTargetPropertyId>;
+
+// This is a simplified version of cc::KeyframeEffect. Its sole purpose is the
+// management of its collection of KeyframeModels. Ticking them, updating their
+// state, and deleting them as required.
+//
+// For background on the name of this class, please refer to the WebAnimations
+// spec: https://www.w3.org/TR/web-animations-1/#the-keyframeeffect-interface
+//
+// TODO(crbug.com/747185): Make cc::KeyframeEffect a subclass of KeyframeEffect
+// and share common code.
+class GFX_KEYFRAME_ANIMATION_EXPORT KeyframeEffect {
+ public:
+ static int GetNextKeyframeModelId();
+ static int GetNextGroupId();
+
+ KeyframeEffect();
+ ~KeyframeEffect();
+
+ KeyframeEffect(const KeyframeEffect&) = delete;
+ KeyframeEffect& operator=(const KeyframeEffect&) = delete;
+
+ void AddKeyframeModel(std::unique_ptr<KeyframeModel> keyframe_model);
+ void RemoveKeyframeModel(int keyframe_model_id);
+ void RemoveKeyframeModels(int target_property);
+
+ void Tick(base::TimeTicks monotonic_time);
+
+ // This ticks all keyframe models until they are complete.
+ void FinishAll();
+
+ using KeyframeModels = std::vector<std::unique_ptr<KeyframeModel>>;
+ const KeyframeModels& keyframe_models() { return keyframe_models_; }
+
+ // The transition is analogous to CSS transitions. When configured, the
+ // transition object will cause subsequent calls the corresponding
+ // TransitionXXXTo functions to induce transition animations.
+ const Transition& transition() const { return transition_; }
+ void set_transition(const Transition& transition) {
+ transition_ = transition;
+ }
+
+ void SetTransitionedProperties(const std::set<int>& properties);
+ void SetTransitionDuration(base::TimeDelta delta);
+
+ void TransitionFloatTo(FloatAnimationCurve::Target* target,
+ base::TimeTicks monotonic_time,
+ int target_property,
+ float from,
+ float to);
+ void TransitionTransformOperationsTo(TransformAnimationCurve::Target* target,
+ base::TimeTicks monotonic_time,
+ int target_property,
+ const gfx::TransformOperations& from,
+ const gfx::TransformOperations& to);
+ void TransitionSizeTo(SizeAnimationCurve::Target* target,
+ base::TimeTicks monotonic_time,
+ int target_property,
+ const gfx::SizeF& from,
+ const gfx::SizeF& to);
+ void TransitionColorTo(ColorAnimationCurve::Target* target,
+ base::TimeTicks monotonic_time,
+ int target_property,
+ SkColor from,
+ SkColor to);
+
+ bool IsAnimatingProperty(int property) const;
+
+ float GetTargetFloatValue(int target_property, float default_value) const;
+ gfx::TransformOperations GetTargetTransformOperationsValue(
+ int target_property,
+ const gfx::TransformOperations& default_value) const;
+ gfx::SizeF GetTargetSizeValue(int target_property,
+ const gfx::SizeF& default_value) const;
+ SkColor GetTargetColorValue(int target_property, SkColor default_value) const;
+ KeyframeModel* GetRunningKeyframeModelForProperty(int target_property) const;
+
+ private:
+ void TickKeyframeModel(base::TimeTicks monotonic_time,
+ KeyframeModel* keyframe_model);
+ void TickInternal(base::TimeTicks monotonic_time,
+ bool include_infinite_animations);
+ void StartKeyframeModels(base::TimeTicks monotonic_time,
+ bool include_infinite_animations);
+ KeyframeModel* GetKeyframeModelForProperty(int target_property) const;
+ template <typename ValueType>
+ ValueType GetTargetValue(int target_property,
+ const ValueType& default_value) const;
+
+ KeyframeModels keyframe_models_;
+ Transition transition_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_ANIMATION_KEYFRAME_KEYFRAME_EFFECT_H_
diff --git a/chromium/ui/gfx/animation/keyframe/keyframe_model.cc b/chromium/ui/gfx/animation/keyframe/keyframe_model.cc
new file mode 100644
index 00000000000..1b20c082fd8
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/keyframe_model.cc
@@ -0,0 +1,257 @@
+// Copyright 2021 The Chromium 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/animation/keyframe/keyframe_model.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/notreached.h"
+#include "base/stl_util.h"
+
+namespace gfx {
+namespace {
+
+// This should match the RunState enum.
+static const char* const s_runStateNames[] = {"WAITING_FOR_TARGET_AVAILABILITY",
+ "WAITING_FOR_DELETION",
+ "STARTING",
+ "RUNNING",
+ "PAUSED",
+ "FINISHED",
+ "ABORTED",
+ "ABORTED_BUT_NEEDS_COMPLETION"};
+
+static_assert(static_cast<int>(KeyframeModel::LAST_RUN_STATE) + 1 ==
+ base::size(s_runStateNames),
+ "RunStateEnumSize should equal the number of elements in "
+ "s_runStateNames");
+
+} // namespace
+
+std::string KeyframeModel::ToString(RunState state) {
+ return s_runStateNames[state];
+}
+
+std::unique_ptr<KeyframeModel> KeyframeModel::Create(
+ std::unique_ptr<AnimationCurve> curve,
+ int keyframe_model_id,
+ int target_property_id) {
+ return base::WrapUnique(new KeyframeModel(std::move(curve), keyframe_model_id,
+ target_property_id));
+}
+
+KeyframeModel::KeyframeModel(std::unique_ptr<AnimationCurve> curve,
+ int keyframe_model_id,
+ int target_property_id)
+ : curve_(std::move(curve)),
+ id_(keyframe_model_id),
+ target_property_(target_property_id),
+ run_state_(WAITING_FOR_TARGET_AVAILABILITY),
+ iterations_(1),
+ iteration_start_(0),
+ direction_(Direction::NORMAL),
+ playback_rate_(1),
+ fill_mode_(FillMode::BOTH) {}
+
+KeyframeModel::~KeyframeModel() {
+ if (run_state() == RUNNING || run_state() == PAUSED)
+ SetRunState(ABORTED, base::TimeTicks());
+}
+
+int KeyframeModel::TargetProperty() const {
+ return target_property_;
+}
+
+void KeyframeModel::SetRunState(RunState run_state,
+ base::TimeTicks monotonic_time) {
+ if (run_state == RUNNING && run_state_ == PAUSED)
+ total_paused_duration_ += (monotonic_time - pause_time_);
+ else if (run_state == PAUSED)
+ pause_time_ = monotonic_time;
+ run_state_ = run_state;
+}
+
+void KeyframeModel::Pause(base::TimeDelta pause_offset) {
+ // Convert pause offset which is in local time to monotonic time.
+ // TODO(crbug.com/912407): This should be scaled by playbackrate.
+ base::TimeTicks monotonic_time =
+ pause_offset + start_time_ + total_paused_duration_;
+ SetRunState(PAUSED, monotonic_time);
+}
+
+KeyframeModel::Phase KeyframeModel::CalculatePhaseForTesting(
+ base::TimeDelta local_time) const {
+ return CalculatePhase(local_time);
+}
+
+KeyframeModel::Phase KeyframeModel::CalculatePhase(
+ base::TimeDelta local_time) const {
+ base::TimeDelta opposite_time_offset = time_offset_ == base::TimeDelta::Min()
+ ? base::TimeDelta::Max()
+ : -time_offset_;
+ base::TimeDelta before_active_boundary_time =
+ std::max(opposite_time_offset, base::TimeDelta());
+ if (local_time < before_active_boundary_time ||
+ (local_time == before_active_boundary_time && playback_rate_ < 0)) {
+ return KeyframeModel::Phase::BEFORE;
+ }
+ // TODO(crbug.com/909794): By spec end time = max(start delay + duration +
+ // end delay, 0). The logic should be updated once "end delay" is supported.
+ base::TimeDelta active_after_boundary_time = base::TimeDelta::Max();
+ if (std::isfinite(iterations_)) {
+ // Scaling the duration is against spec but needed to comply with the cc
+ // implementation. By spec (in blink) the playback rate is an Animation
+ // level concept but in cc it's per KeyframeModel. We grab the active time
+ // calculated here and later scale it with the playback rate in order to get
+ // a proper progress. Therefore we need to un-scale it here. This can be
+ // fixed once we scale the local time by playback rate. See
+ // https://crbug.com/912407.
+ base::TimeDelta active_duration =
+ curve_->Duration() * iterations_ / std::abs(playback_rate_);
+ active_after_boundary_time =
+ std::max(opposite_time_offset + active_duration, base::TimeDelta());
+ }
+ if (local_time > active_after_boundary_time ||
+ (local_time == active_after_boundary_time && playback_rate_ > 0)) {
+ return KeyframeModel::Phase::AFTER;
+ }
+ return KeyframeModel::Phase::ACTIVE;
+}
+
+base::Optional<base::TimeDelta> KeyframeModel::CalculateActiveTime(
+ base::TimeTicks monotonic_time) const {
+ base::TimeDelta local_time = ConvertMonotonicTimeToLocalTime(monotonic_time);
+ KeyframeModel::Phase phase = CalculatePhase(local_time);
+ DCHECK(playback_rate_);
+ switch (phase) {
+ case KeyframeModel::Phase::BEFORE:
+ if (fill_mode_ == FillMode::BACKWARDS || fill_mode_ == FillMode::BOTH)
+ return std::max(local_time + time_offset_, base::TimeDelta());
+ return base::nullopt;
+ case KeyframeModel::Phase::ACTIVE:
+ return local_time + time_offset_;
+ case KeyframeModel::Phase::AFTER:
+ if (fill_mode_ == FillMode::FORWARDS || fill_mode_ == FillMode::BOTH) {
+ DCHECK_NE(iterations_, std::numeric_limits<double>::infinity());
+ base::TimeDelta active_duration =
+ curve_->Duration() * iterations_ / std::abs(playback_rate_);
+ return std::max(std::min(local_time + time_offset_, active_duration),
+ base::TimeDelta());
+ }
+ return base::nullopt;
+ default:
+ NOTREACHED();
+ return base::nullopt;
+ }
+}
+
+bool KeyframeModel::IsFinishedAt(base::TimeTicks monotonic_time) const {
+ if (is_finished())
+ return true;
+
+ if (StartShouldBeDeferred())
+ return false;
+
+ if (playback_rate_ == 0)
+ return false;
+
+ return run_state_ == RUNNING && std::isfinite(iterations_) &&
+ (curve_->Duration() * (iterations_ / std::abs(playback_rate_))) <=
+ (ConvertMonotonicTimeToLocalTime(monotonic_time) + time_offset_);
+}
+
+bool KeyframeModel::HasActiveTime(base::TimeTicks monotonic_time) const {
+ return CalculateActiveTime(monotonic_time).has_value();
+}
+
+bool KeyframeModel::StartShouldBeDeferred() const {
+ return false;
+}
+
+base::TimeDelta KeyframeModel::TrimTimeToCurrentIteration(
+ base::TimeTicks monotonic_time) const {
+ DCHECK(playback_rate_);
+ DCHECK_GE(iteration_start_, 0);
+
+ DCHECK(HasActiveTime(monotonic_time));
+ base::TimeDelta active_time = CalculateActiveTime(monotonic_time).value();
+ base::TimeDelta start_offset = curve_->Duration() * iteration_start_;
+
+ // Return start offset if we are before the start of the keyframe model
+ if (active_time < base::TimeDelta())
+ return start_offset;
+ // Always return zero if we have no iterations.
+ if (!iterations_)
+ return base::TimeDelta();
+
+ // Don't attempt to trim if we have no duration.
+ if (curve_->Duration() <= base::TimeDelta())
+ return base::TimeDelta();
+
+ base::TimeDelta repeated_duration = std::isfinite(iterations_)
+ ? (curve_->Duration() * iterations_)
+ : base::TimeDelta::Max();
+
+ // Calculate the scaled active time
+ base::TimeDelta scaled_active_time;
+ if (playback_rate_ < 0) {
+ DCHECK(std::isfinite(iterations_));
+ base::TimeDelta active_duration =
+ repeated_duration / std::abs(playback_rate_);
+ scaled_active_time =
+ ((active_time - active_duration) * playback_rate_) + start_offset;
+ } else {
+ scaled_active_time = (active_time * playback_rate_) + start_offset;
+ }
+
+ // Calculate the iteration time
+ base::TimeDelta iteration_time;
+ bool has_defined_time_delta =
+ (start_offset != scaled_active_time) ||
+ !(start_offset.is_max() || start_offset.is_min());
+ if (has_defined_time_delta &&
+ scaled_active_time - start_offset == repeated_duration &&
+ fmod(iterations_ + iteration_start_, 1) == 0)
+ iteration_time = curve_->Duration();
+ else
+ iteration_time = scaled_active_time % curve_->Duration();
+
+ // Calculate the current iteration
+ int iteration;
+ if (scaled_active_time <= base::TimeDelta())
+ iteration = 0;
+ else if (iteration_time == curve_->Duration())
+ iteration = ceil(iteration_start_ + iterations_ - 1);
+ else
+ iteration = base::ClampFloor(scaled_active_time / curve_->Duration());
+
+ // Check if we are running the keyframe model in reverse direction for the
+ // current iteration
+ bool reverse =
+ (direction_ == Direction::REVERSE) ||
+ (direction_ == Direction::ALTERNATE_NORMAL && iteration % 2 == 1) ||
+ (direction_ == Direction::ALTERNATE_REVERSE && iteration % 2 == 0);
+
+ // If we are running the keyframe model in reverse direction, reverse the
+ // result
+ if (reverse)
+ iteration_time = curve_->Duration() - iteration_time;
+
+ return iteration_time;
+}
+
+// TODO(crbug.com/912407): Local time should be scaled by playback rate by spec.
+base::TimeDelta KeyframeModel::ConvertMonotonicTimeToLocalTime(
+ base::TimeTicks monotonic_time) const {
+ // When waiting on receiving a start time, then our global clock is 'stuck' at
+ // the initial state.
+ if ((run_state_ == STARTING && !has_set_start_time()) ||
+ StartShouldBeDeferred())
+ return base::TimeDelta();
+
+ // If we're paused, time is 'stuck' at the pause time.
+ base::TimeTicks time = (run_state_ == PAUSED) ? pause_time_ : monotonic_time;
+ return time - start_time_ - total_paused_duration_;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/animation/keyframe/keyframe_model.h b/chromium/ui/gfx/animation/keyframe/keyframe_model.h
new file mode 100644
index 00000000000..92f9c07547a
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/keyframe_model.h
@@ -0,0 +1,206 @@
+// Copyright 2021 The Chromium 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_ANIMATION_KEYFRAME_KEYFRAME_MODEL_H_
+#define UI_GFX_ANIMATION_KEYFRAME_KEYFRAME_MODEL_H_
+
+#include <string>
+
+#include "ui/gfx/animation/keyframe/animation_curve.h"
+#include "ui/gfx/animation/keyframe/keyframe_animation_export.h"
+
+namespace gfx {
+
+class GFX_KEYFRAME_ANIMATION_EXPORT KeyframeModel {
+ public:
+ // KeyframeModels begin in the 'WAITING_FOR_TARGET_AVAILABILITY' state. A
+ // KeyframeModel waiting for target availability will run as soon as its
+ // target property is free (and all the KeyframeModels animating with it are
+ // also able to run). When this time arrives, the controller will move the
+ // keyframe model into the STARTING state, and then into the RUNNING state.
+ // RUNNING KeyframeModels may toggle between RUNNING and PAUSED, and may be
+ // stopped by moving into either the ABORTED or FINISHED states. A FINISHED
+ // keyframe model was allowed to run to completion, but an ABORTED keyframe
+ // model was not. An animation in the state ABORTED_BUT_NEEDS_COMPLETION is a
+ // keyframe model that was aborted for some reason, but needs to be finished.
+ // Currently this is for impl-only scroll offset KeyframeModels that need to
+ // be completed on the main thread.
+ enum RunState {
+ WAITING_FOR_TARGET_AVAILABILITY = 0,
+ WAITING_FOR_DELETION,
+ STARTING,
+ RUNNING,
+ PAUSED,
+ FINISHED,
+ ABORTED,
+ ABORTED_BUT_NEEDS_COMPLETION,
+ // This sentinel must be last.
+ LAST_RUN_STATE = ABORTED_BUT_NEEDS_COMPLETION
+ };
+ static std::string ToString(RunState);
+
+ enum class Direction { NORMAL, REVERSE, ALTERNATE_NORMAL, ALTERNATE_REVERSE };
+
+ enum class FillMode { NONE, FORWARDS, BACKWARDS, BOTH, AUTO };
+
+ enum class Phase { BEFORE, ACTIVE, AFTER };
+
+ static std::unique_ptr<KeyframeModel> Create(
+ std::unique_ptr<AnimationCurve> curve,
+ int keyframe_model_id,
+ int target_property_id);
+
+ KeyframeModel(const KeyframeModel&) = delete;
+ virtual ~KeyframeModel();
+
+ KeyframeModel& operator=(const KeyframeModel&) = delete;
+
+ int id() const { return id_; }
+
+ virtual int TargetProperty() const;
+
+ RunState run_state() const { return run_state_; }
+ virtual void SetRunState(RunState run_state, base::TimeTicks monotonic_time);
+
+ // Pause the keyframe effect at local time |pause_offset|.
+ void Pause(base::TimeDelta pause_offset);
+
+ base::TimeTicks start_time() const { return start_time_; }
+
+ void set_start_time(base::TimeTicks monotonic_time) {
+ start_time_ = monotonic_time;
+ }
+ bool has_set_start_time() const { return !start_time_.is_null(); }
+
+ base::TimeDelta time_offset() const { return time_offset_; }
+ void set_time_offset(base::TimeDelta monotonic_time) {
+ time_offset_ = monotonic_time;
+ }
+
+ Direction direction() const { return direction_; }
+ void set_direction(Direction direction) { direction_ = direction; }
+
+ FillMode fill_mode() const { return fill_mode_; }
+ void set_fill_mode(FillMode fill_mode) { fill_mode_ = fill_mode; }
+
+ double playback_rate() const { return playback_rate_; }
+ void set_playback_rate(double playback_rate) {
+ playback_rate_ = playback_rate;
+ }
+
+ base::TimeTicks pause_time() const { return pause_time_; }
+ void set_pause_time(base::TimeTicks pause_time) { pause_time_ = pause_time; }
+
+ base::TimeDelta total_paused_duration() const {
+ return total_paused_duration_;
+ }
+ void set_total_paused_duration(base::TimeDelta total_paused_duration) {
+ total_paused_duration_ = total_paused_duration;
+ }
+
+ // This is the number of times that the keyframe model will play. If this
+ // value is zero the keyframe model will not play. If it is negative, then
+ // the keyframe model will loop indefinitely.
+ double iterations() const { return iterations_; }
+ void set_iterations(double n) { iterations_ = n; }
+
+ double iteration_start() const { return iteration_start_; }
+ void set_iteration_start(double iteration_start) {
+ iteration_start_ = iteration_start;
+ }
+
+ AnimationCurve* curve() { return curve_.get(); }
+ const AnimationCurve* curve() const { return curve_.get(); }
+
+ bool IsFinishedAt(base::TimeTicks monotonic_time) const;
+ bool is_finished() const {
+ return run_state_ == FINISHED || run_state_ == ABORTED ||
+ run_state_ == WAITING_FOR_DELETION;
+ }
+
+ bool HasActiveTime(base::TimeTicks monotonic_time) const;
+
+ // Some clients may run threaded animations and may need to defer starting
+ // until the animation on the other thread has been started.
+ virtual bool StartShouldBeDeferred() const;
+
+ // Takes the given absolute time, and using the start time and the number
+ // of iterations, returns the relative time in the current iteration.
+ base::TimeDelta TrimTimeToCurrentIteration(
+ base::TimeTicks monotonic_time) const;
+
+ KeyframeModel::Phase CalculatePhaseForTesting(
+ base::TimeDelta local_time) const;
+
+ protected:
+ KeyframeModel(std::unique_ptr<AnimationCurve> curve,
+ int keyframe_model_id,
+ int target_property_id);
+
+ void ForceRunState(RunState run_state) { run_state_ = run_state; }
+ base::Optional<base::TimeDelta> CalculateActiveTime(
+ base::TimeTicks monotonic_time) const;
+
+ private:
+ KeyframeModel::Phase CalculatePhase(base::TimeDelta local_time) const;
+
+ // Return local time for this keyframe model given the absolute monotonic
+ // time.
+ //
+ // Local time represents the time value that is used to tick this keyframe
+ // model and is relative to its start time. It is closely related to the local
+ // time concept in web animations [1]. It is:
+ // - for playing animation : wall time - start time - paused duration
+ // - for paused animation : paused time
+ // - otherwise : zero
+ //
+ // Here is small diagram that shows how active, local, and monotonic times
+ // relate to each other and to the run state.
+ //
+ // run state Starting (R)unning Paused (R) Paused (R) Finished
+ // ^ ^
+ // | |
+ // monotonic time ------------------------------------------------->
+ // | |
+ // local time +-----------------+ +---+ +--------->
+ // | |
+ // active time + +------+ +---+ +------+
+ // (-offset)
+ //
+ // [1] https://drafts.csswg.org/web-animations/#local-time-section
+ base::TimeDelta ConvertMonotonicTimeToLocalTime(
+ base::TimeTicks monotonic_time) const;
+
+ std::unique_ptr<AnimationCurve> curve_;
+
+ // IDs must be unique.
+ int id_;
+
+ int target_property_ = 0;
+ RunState run_state_;
+ double iterations_;
+ double iteration_start_;
+ Direction direction_;
+ double playback_rate_;
+ FillMode fill_mode_;
+
+ base::TimeTicks start_time_;
+
+ // The time offset effectively pushes the start of the keyframe model back in
+ // time. This is used for resuming paused KeyframeModels -- an animation is
+ // added with a non-zero time offset, causing the keyframe model to skip ahead
+ // to the desired point in time.
+ base::TimeDelta time_offset_;
+
+ // These are used when converting monotonic to local time to account for time
+ // spent while paused. This is not included in AnimationState since it
+ // there is absolutely no need for clients of this controller to know
+ // about these values.
+ base::TimeTicks pause_time_;
+ base::TimeDelta total_paused_duration_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_ANIMATION_KEYFRAME_KEYFRAME_MODEL_H_
diff --git a/chromium/ui/gfx/animation/keyframe/keyframed_animation_curve.cc b/chromium/ui/gfx/animation/keyframe/keyframed_animation_curve.cc
new file mode 100644
index 00000000000..6ff33616160
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/keyframed_animation_curve.cc
@@ -0,0 +1,515 @@
+// Copyright 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/animation/keyframe/keyframed_animation_curve.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/geometry/box_f.h"
+
+namespace gfx {
+
+namespace {
+
+template <class KeyframeType>
+void InsertKeyframe(std::unique_ptr<KeyframeType> keyframe,
+ std::vector<std::unique_ptr<KeyframeType>>* keyframes) {
+ // Usually, the keyframes will be added in order, so this loop would be
+ // unnecessary and we should skip it if possible.
+ if (!keyframes->empty() && keyframe->Time() < keyframes->back()->Time()) {
+ for (size_t i = 0; i < keyframes->size(); ++i) {
+ if (keyframe->Time() < keyframes->at(i)->Time()) {
+ keyframes->insert(keyframes->begin() + i, std::move(keyframe));
+ return;
+ }
+ }
+ }
+
+ keyframes->push_back(std::move(keyframe));
+}
+
+struct TimeValues {
+ base::TimeDelta start_time;
+ base::TimeDelta duration;
+ double progress;
+};
+
+template <typename KeyframeType>
+TimeValues GetTimeValues(const KeyframeType& start_frame,
+ const KeyframeType& end_frame,
+ double scaled_duration,
+ base::TimeDelta time) {
+ TimeValues values;
+ values.start_time = start_frame.Time() * scaled_duration;
+ values.duration = (end_frame.Time() * scaled_duration) - values.start_time;
+ const base::TimeDelta elapsed = time - values.start_time;
+ values.progress = (elapsed.is_inf() || values.duration.is_zero())
+ ? 1.0
+ : (elapsed / values.duration);
+ return values;
+}
+
+template <typename KeyframeType>
+base::TimeDelta TransformedAnimationTime(
+ const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
+ const std::unique_ptr<TimingFunction>& timing_function,
+ double scaled_duration,
+ base::TimeDelta time) {
+ if (timing_function) {
+ const auto values = GetTimeValues(*keyframes.front(), *keyframes.back(),
+ scaled_duration, time);
+ time = (values.duration * timing_function->GetValue(values.progress)) +
+ values.start_time;
+ }
+
+ return time;
+}
+
+template <typename KeyframeType>
+size_t GetActiveKeyframe(
+ const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
+ double scaled_duration,
+ base::TimeDelta time) {
+ DCHECK_GE(keyframes.size(), 2ul);
+ size_t i = 0;
+ while ((i < keyframes.size() - 2) && // Last keyframe is never active.
+ (time >= (keyframes[i + 1]->Time() * scaled_duration)))
+ ++i;
+
+ return i;
+}
+
+template <typename KeyframeType>
+double TransformedKeyframeProgress(
+ const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
+ double scaled_duration,
+ base::TimeDelta time,
+ size_t i) {
+ const double progress =
+ GetTimeValues(*keyframes[i], *keyframes[i + 1], scaled_duration, time)
+ .progress;
+ return keyframes[i]->timing_function()
+ ? keyframes[i]->timing_function()->GetValue(progress)
+ : progress;
+}
+
+int GetTimingFunctionSteps(const TimingFunction* timing_function) {
+ DCHECK(timing_function &&
+ timing_function->GetType() == TimingFunction::Type::STEPS);
+ const StepsTimingFunction* steps_timing_function =
+ reinterpret_cast<const StepsTimingFunction*>(timing_function);
+ DCHECK(steps_timing_function);
+ return steps_timing_function->steps();
+}
+
+template <class KeyframeType>
+base::TimeDelta ComputeTickInterval(
+ const std::unique_ptr<TimingFunction>& timing_function,
+ double scaled_duration,
+ const std::vector<std::unique_ptr<KeyframeType>>& keyframes) {
+ // TODO(crbug.com/1140603): include animation progress in order to pinpoint
+ // which keyframe's timing function is in effect at any point in time.
+ DCHECK_LT(0u, keyframes.size());
+ TimingFunction::Type timing_function_type =
+ timing_function ? timing_function->GetType()
+ : TimingFunction::Type::LINEAR;
+ // Even if the keyframe's have step timing functions, a non-linear
+ // animation-wide timing function results in unevenly timed steps.
+ switch (timing_function_type) {
+ case TimingFunction::Type::LINEAR: {
+ base::TimeDelta min_interval = base::TimeDelta::Max();
+ // If any keyframe uses non-step "easing", return 0, except for the last
+ // keyframe, whose "easing" is never used.
+ for (size_t ii = 0; ii < keyframes.size() - 1; ++ii) {
+ KeyframeType* keyframe = keyframes[ii].get();
+ if (!keyframe->timing_function() ||
+ keyframe->timing_function()->GetType() !=
+ TimingFunction::Type::STEPS) {
+ return base::TimeDelta();
+ }
+ KeyframeType* next_keyframe = keyframes[ii + 1].get();
+ int steps = GetTimingFunctionSteps(keyframe->timing_function());
+ DCHECK_LT(0, steps);
+ base::TimeDelta interval = (next_keyframe->Time() - keyframe->Time()) *
+ scaled_duration / steps;
+ if (interval < min_interval)
+ min_interval = interval;
+ }
+ return min_interval;
+ }
+ case TimingFunction::Type::STEPS: {
+ return (keyframes.back()->Time() - keyframes.front()->Time()) *
+ scaled_duration / GetTimingFunctionSteps(timing_function.get());
+ }
+ case TimingFunction::Type::CUBIC_BEZIER:
+ break;
+ }
+ return base::TimeDelta();
+}
+
+} // namespace
+
+Keyframe::Keyframe(base::TimeDelta time,
+ std::unique_ptr<TimingFunction> timing_function)
+ : time_(time), timing_function_(std::move(timing_function)) {}
+
+Keyframe::~Keyframe() = default;
+
+base::TimeDelta Keyframe::Time() const {
+ return time_;
+}
+
+std::unique_ptr<ColorKeyframe> ColorKeyframe::Create(
+ base::TimeDelta time,
+ SkColor value,
+ std::unique_ptr<TimingFunction> timing_function) {
+ return base::WrapUnique(
+ new ColorKeyframe(time, value, std::move(timing_function)));
+}
+
+ColorKeyframe::ColorKeyframe(base::TimeDelta time,
+ SkColor value,
+ std::unique_ptr<TimingFunction> timing_function)
+ : Keyframe(time, std::move(timing_function)), value_(value) {}
+
+ColorKeyframe::~ColorKeyframe() = default;
+
+SkColor ColorKeyframe::Value() const {
+ return value_;
+}
+
+std::unique_ptr<ColorKeyframe> ColorKeyframe::Clone() const {
+ std::unique_ptr<TimingFunction> func;
+ if (timing_function())
+ func = timing_function()->Clone();
+ return ColorKeyframe::Create(Time(), Value(), std::move(func));
+}
+
+std::unique_ptr<FloatKeyframe> FloatKeyframe::Create(
+ base::TimeDelta time,
+ float value,
+ std::unique_ptr<TimingFunction> timing_function) {
+ return base::WrapUnique(
+ new FloatKeyframe(time, value, std::move(timing_function)));
+}
+
+FloatKeyframe::FloatKeyframe(base::TimeDelta time,
+ float value,
+ std::unique_ptr<TimingFunction> timing_function)
+ : Keyframe(time, std::move(timing_function)), value_(value) {}
+
+FloatKeyframe::~FloatKeyframe() = default;
+
+float FloatKeyframe::Value() const {
+ return value_;
+}
+
+std::unique_ptr<FloatKeyframe> FloatKeyframe::Clone() const {
+ std::unique_ptr<TimingFunction> func;
+ if (timing_function())
+ func = timing_function()->Clone();
+ return FloatKeyframe::Create(Time(), Value(), std::move(func));
+}
+
+std::unique_ptr<TransformKeyframe> TransformKeyframe::Create(
+ base::TimeDelta time,
+ const gfx::TransformOperations& value,
+ std::unique_ptr<TimingFunction> timing_function) {
+ return base::WrapUnique(
+ new TransformKeyframe(time, value, std::move(timing_function)));
+}
+
+TransformKeyframe::TransformKeyframe(
+ base::TimeDelta time,
+ const gfx::TransformOperations& value,
+ std::unique_ptr<TimingFunction> timing_function)
+ : Keyframe(time, std::move(timing_function)), value_(value) {}
+
+TransformKeyframe::~TransformKeyframe() = default;
+
+const gfx::TransformOperations& TransformKeyframe::Value() const {
+ return value_;
+}
+
+std::unique_ptr<TransformKeyframe> TransformKeyframe::Clone() const {
+ std::unique_ptr<TimingFunction> func;
+ if (timing_function())
+ func = timing_function()->Clone();
+ return TransformKeyframe::Create(Time(), Value(), std::move(func));
+}
+
+std::unique_ptr<SizeKeyframe> SizeKeyframe::Create(
+ base::TimeDelta time,
+ const gfx::SizeF& value,
+ std::unique_ptr<TimingFunction> timing_function) {
+ return base::WrapUnique(
+ new SizeKeyframe(time, value, std::move(timing_function)));
+}
+
+SizeKeyframe::SizeKeyframe(base::TimeDelta time,
+ const gfx::SizeF& value,
+ std::unique_ptr<TimingFunction> timing_function)
+ : Keyframe(time, std::move(timing_function)), value_(value) {}
+
+SizeKeyframe::~SizeKeyframe() = default;
+
+const gfx::SizeF& SizeKeyframe::Value() const {
+ return value_;
+}
+
+std::unique_ptr<SizeKeyframe> SizeKeyframe::Clone() const {
+ std::unique_ptr<TimingFunction> func;
+ if (timing_function())
+ func = timing_function()->Clone();
+ return SizeKeyframe::Create(Time(), Value(), std::move(func));
+}
+
+std::unique_ptr<KeyframedColorAnimationCurve>
+KeyframedColorAnimationCurve::Create() {
+ return base::WrapUnique(new KeyframedColorAnimationCurve);
+}
+
+KeyframedColorAnimationCurve::KeyframedColorAnimationCurve()
+ : scaled_duration_(1.0) {}
+
+KeyframedColorAnimationCurve::~KeyframedColorAnimationCurve() = default;
+
+void KeyframedColorAnimationCurve::AddKeyframe(
+ std::unique_ptr<ColorKeyframe> keyframe) {
+ InsertKeyframe(std::move(keyframe), &keyframes_);
+}
+
+base::TimeDelta KeyframedColorAnimationCurve::Duration() const {
+ return (keyframes_.back()->Time() - keyframes_.front()->Time()) *
+ scaled_duration();
+}
+
+base::TimeDelta KeyframedColorAnimationCurve::TickInterval() const {
+ return ComputeTickInterval(timing_function_, scaled_duration(), keyframes_);
+}
+
+std::unique_ptr<AnimationCurve> KeyframedColorAnimationCurve::Clone() const {
+ std::unique_ptr<KeyframedColorAnimationCurve> to_return =
+ KeyframedColorAnimationCurve::Create();
+ for (const auto& keyframe : keyframes_)
+ to_return->AddKeyframe(keyframe->Clone());
+
+ if (timing_function_)
+ to_return->SetTimingFunction(timing_function_->Clone());
+
+ to_return->set_scaled_duration(scaled_duration());
+
+ return std::move(to_return);
+}
+
+SkColor KeyframedColorAnimationCurve::GetValue(base::TimeDelta t) const {
+ if (t <= (keyframes_.front()->Time() * scaled_duration()))
+ return keyframes_.front()->Value();
+
+ if (t >= (keyframes_.back()->Time() * scaled_duration()))
+ return keyframes_.back()->Value();
+
+ t = TransformedAnimationTime(keyframes_, timing_function_, scaled_duration(),
+ t);
+ size_t i = GetActiveKeyframe(keyframes_, scaled_duration(), t);
+ double progress =
+ TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
+
+ return gfx::Tween::ColorValueBetween(progress, keyframes_[i]->Value(),
+ keyframes_[i + 1]->Value());
+}
+
+std::unique_ptr<KeyframedFloatAnimationCurve>
+KeyframedFloatAnimationCurve::Create() {
+ return base::WrapUnique(new KeyframedFloatAnimationCurve);
+}
+
+KeyframedFloatAnimationCurve::KeyframedFloatAnimationCurve()
+ : scaled_duration_(1.0) {}
+
+KeyframedFloatAnimationCurve::~KeyframedFloatAnimationCurve() = default;
+
+void KeyframedFloatAnimationCurve::AddKeyframe(
+ std::unique_ptr<FloatKeyframe> keyframe) {
+ InsertKeyframe(std::move(keyframe), &keyframes_);
+}
+
+base::TimeDelta KeyframedFloatAnimationCurve::Duration() const {
+ return (keyframes_.back()->Time() - keyframes_.front()->Time()) *
+ scaled_duration();
+}
+
+base::TimeDelta KeyframedFloatAnimationCurve::TickInterval() const {
+ return ComputeTickInterval(timing_function_, scaled_duration(), keyframes_);
+}
+
+std::unique_ptr<AnimationCurve> KeyframedFloatAnimationCurve::Clone() const {
+ std::unique_ptr<KeyframedFloatAnimationCurve> to_return =
+ KeyframedFloatAnimationCurve::Create();
+ for (const auto& keyframe : keyframes_)
+ to_return->AddKeyframe(keyframe->Clone());
+
+ if (timing_function_)
+ to_return->SetTimingFunction(timing_function_->Clone());
+
+ to_return->set_scaled_duration(scaled_duration());
+
+ return std::move(to_return);
+}
+
+float KeyframedFloatAnimationCurve::GetValue(base::TimeDelta t) const {
+ if (t <= (keyframes_.front()->Time() * scaled_duration()))
+ return keyframes_.front()->Value();
+
+ if (t >= (keyframes_.back()->Time() * scaled_duration()))
+ return keyframes_.back()->Value();
+
+ t = TransformedAnimationTime(keyframes_, timing_function_, scaled_duration(),
+ t);
+ size_t i = GetActiveKeyframe(keyframes_, scaled_duration(), t);
+ double progress =
+ TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
+
+ return keyframes_[i]->Value() +
+ (keyframes_[i + 1]->Value() - keyframes_[i]->Value()) * progress;
+}
+
+std::unique_ptr<KeyframedTransformAnimationCurve>
+KeyframedTransformAnimationCurve::Create() {
+ return base::WrapUnique(new KeyframedTransformAnimationCurve);
+}
+
+KeyframedTransformAnimationCurve::KeyframedTransformAnimationCurve()
+ : scaled_duration_(1.0) {}
+
+KeyframedTransformAnimationCurve::~KeyframedTransformAnimationCurve() = default;
+
+void KeyframedTransformAnimationCurve::AddKeyframe(
+ std::unique_ptr<TransformKeyframe> keyframe) {
+ InsertKeyframe(std::move(keyframe), &keyframes_);
+}
+
+base::TimeDelta KeyframedTransformAnimationCurve::Duration() const {
+ return (keyframes_.back()->Time() - keyframes_.front()->Time()) *
+ scaled_duration();
+}
+
+base::TimeDelta KeyframedTransformAnimationCurve::TickInterval() const {
+ return ComputeTickInterval(timing_function_, scaled_duration(), keyframes_);
+}
+
+std::unique_ptr<AnimationCurve> KeyframedTransformAnimationCurve::Clone()
+ const {
+ std::unique_ptr<KeyframedTransformAnimationCurve> to_return =
+ KeyframedTransformAnimationCurve::Create();
+ for (const auto& keyframe : keyframes_)
+ to_return->AddKeyframe(keyframe->Clone());
+
+ if (timing_function_)
+ to_return->SetTimingFunction(timing_function_->Clone());
+
+ to_return->set_scaled_duration(scaled_duration());
+
+ return std::move(to_return);
+}
+
+gfx::TransformOperations KeyframedTransformAnimationCurve::GetValue(
+ base::TimeDelta t) const {
+ if (t <= (keyframes_.front()->Time() * scaled_duration()))
+ return keyframes_.front()->Value();
+
+ if (t >= (keyframes_.back()->Time() * scaled_duration()))
+ return keyframes_.back()->Value();
+
+ t = TransformedAnimationTime(keyframes_, timing_function_, scaled_duration(),
+ t);
+ size_t i = GetActiveKeyframe(keyframes_, scaled_duration(), t);
+ double progress =
+ TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
+
+ return keyframes_[i + 1]->Value().Blend(keyframes_[i]->Value(), progress);
+}
+
+bool KeyframedTransformAnimationCurve::PreservesAxisAlignment() const {
+ for (const auto& keyframe : keyframes_) {
+ if (!keyframe->Value().PreservesAxisAlignment())
+ return false;
+ }
+ return true;
+}
+
+bool KeyframedTransformAnimationCurve::MaximumScale(float* max_scale) const {
+ DCHECK_GE(keyframes_.size(), 2ul);
+ *max_scale = 0.f;
+ for (auto& keyframe : keyframes_) {
+ float keyframe_scale = 0.f;
+ if (!keyframe->Value().ScaleComponent(&keyframe_scale))
+ continue;
+ *max_scale = std::max(*max_scale, keyframe_scale);
+ }
+ return *max_scale > 0.f;
+}
+
+std::unique_ptr<KeyframedSizeAnimationCurve>
+KeyframedSizeAnimationCurve::Create() {
+ return base::WrapUnique(new KeyframedSizeAnimationCurve);
+}
+
+KeyframedSizeAnimationCurve::KeyframedSizeAnimationCurve()
+ : scaled_duration_(1.0) {}
+
+KeyframedSizeAnimationCurve::~KeyframedSizeAnimationCurve() = default;
+
+void KeyframedSizeAnimationCurve::AddKeyframe(
+ std::unique_ptr<SizeKeyframe> keyframe) {
+ InsertKeyframe(std::move(keyframe), &keyframes_);
+}
+
+base::TimeDelta KeyframedSizeAnimationCurve::Duration() const {
+ return (keyframes_.back()->Time() - keyframes_.front()->Time()) *
+ scaled_duration();
+}
+
+base::TimeDelta KeyframedSizeAnimationCurve::TickInterval() const {
+ return ComputeTickInterval(timing_function_, scaled_duration(), keyframes_);
+}
+
+std::unique_ptr<AnimationCurve> KeyframedSizeAnimationCurve::Clone() const {
+ std::unique_ptr<KeyframedSizeAnimationCurve> to_return =
+ KeyframedSizeAnimationCurve::Create();
+ for (const auto& keyframe : keyframes_)
+ to_return->AddKeyframe(keyframe->Clone());
+
+ if (timing_function_)
+ to_return->SetTimingFunction(timing_function_->Clone());
+
+ to_return->set_scaled_duration(scaled_duration());
+
+ return std::move(to_return);
+}
+
+gfx::SizeF KeyframedSizeAnimationCurve::GetValue(base::TimeDelta t) const {
+ if (t <= (keyframes_.front()->Time() * scaled_duration()))
+ return keyframes_.front()->Value();
+
+ if (t >= (keyframes_.back()->Time() * scaled_duration()))
+ return keyframes_.back()->Value();
+
+ t = TransformedAnimationTime(keyframes_, timing_function_, scaled_duration(),
+ t);
+ size_t i = GetActiveKeyframe(keyframes_, scaled_duration(), t);
+ double progress =
+ TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
+
+ return gfx::Tween::SizeFValueBetween(progress, keyframes_[i]->Value(),
+ keyframes_[i + 1]->Value());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/animation/keyframe/keyframed_animation_curve.h b/chromium/ui/gfx/animation/keyframe/keyframed_animation_curve.h
new file mode 100644
index 00000000000..50bbb3b880f
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/keyframed_animation_curve.h
@@ -0,0 +1,292 @@
+// Copyright 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_ANIMATION_KEYFRAME_KEYFRAMED_ANIMATION_CURVE_H_
+#define UI_GFX_ANIMATION_KEYFRAME_KEYFRAMED_ANIMATION_CURVE_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/time/time.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
+#include "ui/gfx/animation/keyframe/keyframe_animation_export.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/transform_operations.h"
+
+namespace gfx {
+
+class GFX_KEYFRAME_ANIMATION_EXPORT Keyframe {
+ public:
+ Keyframe(const Keyframe&) = delete;
+ Keyframe& operator=(const Keyframe&) = delete;
+
+ base::TimeDelta Time() const;
+ const TimingFunction* timing_function() const {
+ return timing_function_.get();
+ }
+
+ protected:
+ Keyframe(base::TimeDelta time,
+ std::unique_ptr<TimingFunction> timing_function);
+ virtual ~Keyframe();
+
+ private:
+ base::TimeDelta time_;
+ std::unique_ptr<TimingFunction> timing_function_;
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT ColorKeyframe : public Keyframe {
+ public:
+ static std::unique_ptr<ColorKeyframe> Create(
+ base::TimeDelta time,
+ SkColor value,
+ std::unique_ptr<TimingFunction> timing_function);
+ ~ColorKeyframe() override;
+
+ SkColor Value() const;
+
+ std::unique_ptr<ColorKeyframe> Clone() const;
+
+ private:
+ ColorKeyframe(base::TimeDelta time,
+ SkColor value,
+ std::unique_ptr<TimingFunction> timing_function);
+
+ SkColor value_;
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT FloatKeyframe : public Keyframe {
+ public:
+ static std::unique_ptr<FloatKeyframe> Create(
+ base::TimeDelta time,
+ float value,
+ std::unique_ptr<TimingFunction> timing_function);
+ ~FloatKeyframe() override;
+
+ float Value() const;
+
+ std::unique_ptr<FloatKeyframe> Clone() const;
+
+ private:
+ FloatKeyframe(base::TimeDelta time,
+ float value,
+ std::unique_ptr<TimingFunction> timing_function);
+
+ float value_;
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT TransformKeyframe : public Keyframe {
+ public:
+ static std::unique_ptr<TransformKeyframe> Create(
+ base::TimeDelta time,
+ const gfx::TransformOperations& value,
+ std::unique_ptr<TimingFunction> timing_function);
+ ~TransformKeyframe() override;
+
+ const gfx::TransformOperations& Value() const;
+
+ std::unique_ptr<TransformKeyframe> Clone() const;
+
+ private:
+ TransformKeyframe(base::TimeDelta time,
+ const gfx::TransformOperations& value,
+ std::unique_ptr<TimingFunction> timing_function);
+
+ gfx::TransformOperations value_;
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT SizeKeyframe : public Keyframe {
+ public:
+ static std::unique_ptr<SizeKeyframe> Create(
+ base::TimeDelta time,
+ const gfx::SizeF& bounds,
+ std::unique_ptr<TimingFunction> timing_function);
+ ~SizeKeyframe() override;
+
+ const gfx::SizeF& Value() const;
+
+ std::unique_ptr<SizeKeyframe> Clone() const;
+
+ private:
+ SizeKeyframe(base::TimeDelta time,
+ const gfx::SizeF& value,
+ std::unique_ptr<TimingFunction> timing_function);
+
+ gfx::SizeF value_;
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT KeyframedColorAnimationCurve
+ : public ColorAnimationCurve {
+ public:
+ // It is required that the keyframes be sorted by time.
+ static std::unique_ptr<KeyframedColorAnimationCurve> Create();
+
+ KeyframedColorAnimationCurve(const KeyframedColorAnimationCurve&) = delete;
+ ~KeyframedColorAnimationCurve() override;
+
+ KeyframedColorAnimationCurve& operator=(const KeyframedColorAnimationCurve&) =
+ delete;
+
+ void AddKeyframe(std::unique_ptr<ColorKeyframe> keyframe);
+ void SetTimingFunction(std::unique_ptr<TimingFunction> timing_function) {
+ timing_function_ = std::move(timing_function);
+ }
+ double scaled_duration() const { return scaled_duration_; }
+ void set_scaled_duration(double scaled_duration) {
+ scaled_duration_ = scaled_duration;
+ }
+
+ // AnimationCurve implementation
+ base::TimeDelta Duration() const override;
+ std::unique_ptr<AnimationCurve> Clone() const override;
+ base::TimeDelta TickInterval() const override;
+
+ // BackgrounColorAnimationCurve implementation
+ SkColor GetValue(base::TimeDelta t) const override;
+
+ using Keyframes = std::vector<std::unique_ptr<ColorKeyframe>>;
+ const Keyframes& keyframes_for_testing() const { return keyframes_; }
+
+ private:
+ KeyframedColorAnimationCurve();
+
+ // Always sorted in order of increasing time. No two keyframes have the
+ // same time.
+ Keyframes keyframes_;
+ std::unique_ptr<TimingFunction> timing_function_;
+ double scaled_duration_;
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT KeyframedFloatAnimationCurve
+ : public FloatAnimationCurve {
+ public:
+ // It is required that the keyframes be sorted by time.
+ static std::unique_ptr<KeyframedFloatAnimationCurve> Create();
+
+ KeyframedFloatAnimationCurve(const KeyframedFloatAnimationCurve&) = delete;
+ ~KeyframedFloatAnimationCurve() override;
+
+ KeyframedFloatAnimationCurve& operator=(const KeyframedFloatAnimationCurve&) =
+ delete;
+
+ void AddKeyframe(std::unique_ptr<FloatKeyframe> keyframe);
+
+ void SetTimingFunction(std::unique_ptr<TimingFunction> timing_function) {
+ timing_function_ = std::move(timing_function);
+ }
+ TimingFunction* timing_function_for_testing() const {
+ return timing_function_.get();
+ }
+ double scaled_duration() const { return scaled_duration_; }
+ void set_scaled_duration(double scaled_duration) {
+ scaled_duration_ = scaled_duration;
+ }
+
+ // AnimationCurve implementation
+ base::TimeDelta Duration() const override;
+ std::unique_ptr<AnimationCurve> Clone() const override;
+ base::TimeDelta TickInterval() const override;
+
+ // FloatAnimationCurve implementation
+ float GetValue(base::TimeDelta t) const override;
+
+ using Keyframes = std::vector<std::unique_ptr<FloatKeyframe>>;
+ const Keyframes& keyframes_for_testing() const { return keyframes_; }
+
+ private:
+ KeyframedFloatAnimationCurve();
+
+ // Always sorted in order of increasing time. No two keyframes have the
+ // same time.
+ Keyframes keyframes_;
+ std::unique_ptr<TimingFunction> timing_function_;
+ double scaled_duration_;
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT KeyframedTransformAnimationCurve
+ : public TransformAnimationCurve {
+ public:
+ // It is required that the keyframes be sorted by time.
+ static std::unique_ptr<KeyframedTransformAnimationCurve> Create();
+
+ KeyframedTransformAnimationCurve(const KeyframedTransformAnimationCurve&) =
+ delete;
+ ~KeyframedTransformAnimationCurve() override;
+
+ KeyframedTransformAnimationCurve& operator=(
+ const KeyframedTransformAnimationCurve&) = delete;
+
+ void AddKeyframe(std::unique_ptr<TransformKeyframe> keyframe);
+ void SetTimingFunction(std::unique_ptr<TimingFunction> timing_function) {
+ timing_function_ = std::move(timing_function);
+ }
+ double scaled_duration() const { return scaled_duration_; }
+ void set_scaled_duration(double scaled_duration) {
+ scaled_duration_ = scaled_duration;
+ }
+
+ // AnimationCurve implementation
+ base::TimeDelta Duration() const override;
+ std::unique_ptr<AnimationCurve> Clone() const override;
+ base::TimeDelta TickInterval() const override;
+
+ // TransformAnimationCurve implementation
+ gfx::TransformOperations GetValue(base::TimeDelta t) const override;
+ bool PreservesAxisAlignment() const override;
+ bool MaximumScale(float* max_scale) const override;
+
+ private:
+ KeyframedTransformAnimationCurve();
+
+ // Always sorted in order of increasing time. No two keyframes have the
+ // same time.
+ std::vector<std::unique_ptr<TransformKeyframe>> keyframes_;
+ std::unique_ptr<TimingFunction> timing_function_;
+ double scaled_duration_;
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT KeyframedSizeAnimationCurve
+ : public SizeAnimationCurve {
+ public:
+ // It is required that the keyframes be sorted by time.
+ static std::unique_ptr<KeyframedSizeAnimationCurve> Create();
+
+ KeyframedSizeAnimationCurve(const KeyframedSizeAnimationCurve&) = delete;
+ ~KeyframedSizeAnimationCurve() override;
+
+ KeyframedSizeAnimationCurve& operator=(const KeyframedSizeAnimationCurve&) =
+ delete;
+
+ void AddKeyframe(std::unique_ptr<SizeKeyframe> keyframe);
+ void SetTimingFunction(std::unique_ptr<TimingFunction> timing_function) {
+ timing_function_ = std::move(timing_function);
+ }
+ double scaled_duration() const { return scaled_duration_; }
+ void set_scaled_duration(double scaled_duration) {
+ scaled_duration_ = scaled_duration;
+ }
+
+ // AnimationCurve implementation
+ base::TimeDelta Duration() const override;
+ std::unique_ptr<AnimationCurve> Clone() const override;
+ base::TimeDelta TickInterval() const override;
+
+ // SizeAnimationCurve implementation
+ gfx::SizeF GetValue(base::TimeDelta t) const override;
+
+ private:
+ KeyframedSizeAnimationCurve();
+
+ // Always sorted in order of increasing time. No two keyframes have the
+ // same time.
+ std::vector<std::unique_ptr<SizeKeyframe>> keyframes_;
+ std::unique_ptr<TimingFunction> timing_function_;
+ double scaled_duration_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_ANIMATION_KEYFRAME_KEYFRAMED_ANIMATION_CURVE_H_
diff --git a/chromium/ui/gfx/animation/keyframe/keyframed_animation_curve_unittest.cc b/chromium/ui/gfx/animation/keyframe/keyframed_animation_curve_unittest.cc
new file mode 100644
index 00000000000..c83350bbf55
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/keyframed_animation_curve_unittest.cc
@@ -0,0 +1,993 @@
+// Copyright 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/animation/keyframe/keyframed_animation_curve.h"
+
+#include <memory>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/geometry/test/transform_test_util.h"
+#include "ui/gfx/test/gfx_util.h"
+#include "ui/gfx/transform_operations.h"
+
+namespace gfx {
+namespace {
+
+void ExpectTranslateX(SkScalar translate_x,
+ const gfx::TransformOperations& operations) {
+ EXPECT_FLOAT_EQ(translate_x, operations.Apply().matrix().get(0, 3));
+}
+
+// Tests that a color animation with one keyframe works as expected.
+TEST(KeyframedAnimationCurveTest, OneColorKeyFrame) {
+ SkColor color = SkColorSetARGB(255, 255, 255, 255);
+ std::unique_ptr<KeyframedColorAnimationCurve> curve(
+ KeyframedColorAnimationCurve::Create());
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta(), color, nullptr));
+
+ EXPECT_SKCOLOR_EQ(color,
+ curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SKCOLOR_EQ(color,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a color animation with two keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, TwoColorKeyFrame) {
+ SkColor color_a = SkColorSetARGB(255, 255, 0, 0);
+ SkColor color_b = SkColorSetARGB(255, 0, 255, 0);
+ SkColor color_midpoint = gfx::Tween::ColorValueBetween(0.5, color_a, color_b);
+ std::unique_ptr<KeyframedColorAnimationCurve> curve(
+ KeyframedColorAnimationCurve::Create());
+ curve->AddKeyframe(
+ ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ color_b, nullptr));
+
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SKCOLOR_EQ(color_midpoint,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a color animation with three keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, ThreeColorKeyFrame) {
+ SkColor color_a = SkColorSetARGB(255, 255, 0, 0);
+ SkColor color_b = SkColorSetARGB(255, 0, 255, 0);
+ SkColor color_c = SkColorSetARGB(255, 0, 0, 255);
+ SkColor color_midpoint1 =
+ gfx::Tween::ColorValueBetween(0.5, color_a, color_b);
+ SkColor color_midpoint2 =
+ gfx::Tween::ColorValueBetween(0.5, color_b, color_c);
+ std::unique_ptr<KeyframedColorAnimationCurve> curve(
+ KeyframedColorAnimationCurve::Create());
+ curve->AddKeyframe(
+ ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ color_b, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
+ color_c, nullptr));
+
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SKCOLOR_EQ(color_midpoint1,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_SKCOLOR_EQ(color_midpoint2,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_SKCOLOR_EQ(color_c,
+ curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_SKCOLOR_EQ(color_c,
+ curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
+}
+
+// Tests that a color animation with multiple keys at a given time works sanely.
+TEST(KeyframedAnimationCurveTest, RepeatedColorKeyFrame) {
+ SkColor color_a = SkColorSetARGB(255, 64, 0, 0);
+ SkColor color_b = SkColorSetARGB(255, 192, 0, 0);
+
+ std::unique_ptr<KeyframedColorAnimationCurve> curve(
+ KeyframedColorAnimationCurve::Create());
+ curve->AddKeyframe(
+ ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ color_a, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ color_b, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
+ color_b, nullptr));
+
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+
+ SkColor value = curve->GetValue(base::TimeDelta::FromSecondsD(1.0f));
+ EXPECT_EQ(255u, SkColorGetA(value));
+ int red_value = SkColorGetR(value);
+ EXPECT_LE(64, red_value);
+ EXPECT_GE(192, red_value);
+
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
+}
+
+// Tests that a float animation with one keyframe works as expected.
+TEST(KeyframedAnimationCurveTest, OneFloatKeyframe) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a float animation with two keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, TwoFloatKeyframe) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a float animation with three keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, ThreeFloatKeyframe) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 8.f, nullptr));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
+}
+
+// Tests that a float animation with multiple keys at a given time works sanely.
+TEST(KeyframedAnimationCurveTest, RepeatedFloatKeyTimes) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 4.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 6.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 6.f, nullptr));
+
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+
+ // There is a discontinuity at 1. Any value between 4 and 6 is valid.
+ float value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f));
+ EXPECT_TRUE(value >= 4 && value <= 6);
+
+ EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
+}
+
+// Tests that a transform animation with one keyframe works as expected.
+TEST(KeyframedAnimationCurveTest, OneTransformKeyframe) {
+ std::unique_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+ gfx::TransformOperations operations;
+ operations.AppendTranslate(2.f, 0.f, 0.f);
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations, nullptr));
+
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a transform animation with two keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, TwoTransformKeyframe) {
+ std::unique_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+ gfx::TransformOperations operations1;
+ operations1.AppendTranslate(2.f, 0.f, 0.f);
+ gfx::TransformOperations operations2;
+ operations2.AppendTranslate(4.f, 0.f, 0.f);
+
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectTranslateX(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a transform animation with three keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, ThreeTransformKeyframe) {
+ std::unique_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+ gfx::TransformOperations operations1;
+ operations1.AppendTranslate(2.f, 0.f, 0.f);
+ gfx::TransformOperations operations2;
+ operations2.AppendTranslate(4.f, 0.f, 0.f);
+ gfx::TransformOperations operations3;
+ operations3.AppendTranslate(8.f, 0.f, 0.f);
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(2.0), operations3, nullptr));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectTranslateX(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ ExpectTranslateX(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ ExpectTranslateX(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
+}
+
+// Tests that a transform animation with multiple keys at a given time works
+// sanely.
+TEST(KeyframedAnimationCurveTest, RepeatedTransformKeyTimes) {
+ std::unique_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+ // A step function.
+ gfx::TransformOperations operations1;
+ operations1.AppendTranslate(4.f, 0.f, 0.f);
+ gfx::TransformOperations operations2;
+ operations2.AppendTranslate(4.f, 0.f, 0.f);
+ gfx::TransformOperations operations3;
+ operations3.AppendTranslate(6.f, 0.f, 0.f);
+ gfx::TransformOperations operations4;
+ operations4.AppendTranslate(6.f, 0.f, 0.f);
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations3, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(2.0), operations4, nullptr));
+
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+
+ // There is a discontinuity at 1. Any value between 4 and 6 is valid.
+ gfx::Transform value =
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.f)).Apply();
+ EXPECT_GE(value.matrix().get(0, 3), 4.f);
+ EXPECT_LE(value.matrix().get(0, 3), 6.f);
+
+ ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
+}
+
+// Tests that a discrete transform animation (e.g. where one or more keyframes
+// is a non-invertible matrix) works as expected.
+TEST(KeyframedAnimationCurveTest, DiscreteLinearTransformAnimation) {
+ gfx::Transform non_invertible_matrix(0, 0, 0, 0, 0, 0);
+ gfx::Transform identity_matrix;
+
+ std::unique_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+ gfx::TransformOperations operations1;
+ operations1.AppendMatrix(non_invertible_matrix);
+ gfx::TransformOperations operations2;
+ operations2.AppendMatrix(identity_matrix);
+ gfx::TransformOperations operations3;
+ operations3.AppendMatrix(non_invertible_matrix);
+
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(2.0), operations3, nullptr));
+
+ gfx::TransformOperations result;
+
+ // Between 0 and 0.5 seconds, the first keyframe should be returned.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.01f));
+ ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.49f));
+ ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+
+ // Between 0.5 and 1.5 seconds, the middle keyframe should be returned.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.5f));
+ ExpectTransformationMatrixEq(identity_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(1.49f));
+ ExpectTransformationMatrixEq(identity_matrix, result.Apply());
+
+ // Between 1.5 and 2.0 seconds, the last keyframe should be returned.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(1.5f));
+ ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(2.0f));
+ ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+}
+
+TEST(KeyframedAnimationCurveTest, DiscreteCubicBezierTransformAnimation) {
+ gfx::Transform non_invertible_matrix(0, 0, 0, 0, 0, 0);
+ gfx::Transform identity_matrix;
+
+ std::unique_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+ gfx::TransformOperations operations1;
+ operations1.AppendMatrix(non_invertible_matrix);
+ gfx::TransformOperations operations2;
+ operations2.AppendMatrix(identity_matrix);
+ gfx::TransformOperations operations3;
+ operations3.AppendMatrix(non_invertible_matrix);
+
+ // The cubic-bezier here is a nice fairly strong ease-in curve, where 50%
+ // progression is at approximately 85% of the time.
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta(), operations1,
+ CubicBezierTimingFunction::Create(0.75f, 0.25f, 0.9f, 0.4f)));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2,
+ CubicBezierTimingFunction::Create(0.75f, 0.25f, 0.9f, 0.4f)));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(2.0), operations3,
+ CubicBezierTimingFunction::Create(0.75f, 0.25f, 0.9f, 0.4f)));
+
+ gfx::TransformOperations result;
+
+ // Due to the cubic-bezier, the first keyframe is returned almost all the way
+ // to 1 second.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.01f));
+ ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.8f));
+ ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+
+ // Between ~0.85 and ~1.85 seconds, the middle keyframe should be returned.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(0.85f));
+ ExpectTransformationMatrixEq(identity_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(1.8f));
+ ExpectTransformationMatrixEq(identity_matrix, result.Apply());
+
+ // Finally the last keyframe only takes effect after ~1.85 seconds.
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(1.85f));
+ ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+
+ result = curve->GetValue(base::TimeDelta::FromSecondsD(2.0f));
+ ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+}
+
+// Tests that the keyframes may be added out of order.
+TEST(KeyframedAnimationCurveTest, UnsortedKeyframes) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 8.f, nullptr));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 4.f, nullptr));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
+}
+
+// Tests that a linear timing function works as expected.
+TEST(KeyframedAnimationCurveTest, LinearTimingFunction) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f,
+ LinearTimingFunction::Create()));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
+
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(0.75f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+}
+
+// Tests that a cubic bezier timing function works as expected.
+TEST(KeyframedAnimationCurveTest, CubicBezierTimingFunction) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ CubicBezierTimingFunction::Create(0.25f, 0.f, 0.75f, 1.f)));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
+
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_LT(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
+ EXPECT_GT(0.25f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
+ EXPECT_NEAR(curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)), 0.5f,
+ 0.00015f);
+ EXPECT_LT(0.75f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+ EXPECT_GT(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+}
+
+// Tests a step timing function if the change of values occur at the start.
+TEST(KeyframedAnimationCurveTest, StepsTimingFunctionStepAtStart) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ const int num_steps = 36;
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ StepsTimingFunction::Create(num_steps,
+ StepsTimingFunction::StepPosition::START)));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ num_steps, nullptr));
+
+ const float time_threshold = 0.0001f;
+
+ for (float i = 0.f; i < num_steps; i += 1.f) {
+ const base::TimeDelta time1 =
+ base::TimeDelta::FromSecondsD(i / num_steps - time_threshold);
+ const base::TimeDelta time2 =
+ base::TimeDelta::FromSecondsD(i / num_steps + time_threshold);
+ EXPECT_FLOAT_EQ(std::ceil(i), curve->GetValue(time1));
+ EXPECT_FLOAT_EQ(std::ceil(i) + 1.f, curve->GetValue(time2));
+ }
+ EXPECT_FLOAT_EQ(num_steps,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.0)));
+
+ for (float i = 0.5f; i <= num_steps; i += 1.0f) {
+ const base::TimeDelta time = base::TimeDelta::FromSecondsD(i / num_steps);
+ EXPECT_FLOAT_EQ(std::ceil(i), curve->GetValue(time));
+ }
+}
+
+// Tests a step timing function if the change of values occur at the end.
+TEST(KeyframedAnimationCurveTest, StepsTimingFunctionStepAtEnd) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ const int num_steps = 36;
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ StepsTimingFunction::Create(num_steps,
+ StepsTimingFunction::StepPosition::END)));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ num_steps, nullptr));
+
+ const float time_threshold = 0.0001f;
+
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta()));
+ for (float i = 1.f; i <= num_steps; i += 1.f) {
+ const base::TimeDelta time1 =
+ base::TimeDelta::FromSecondsD(i / num_steps - time_threshold);
+ const base::TimeDelta time2 =
+ base::TimeDelta::FromSecondsD(i / num_steps + time_threshold);
+ EXPECT_FLOAT_EQ(std::floor(i) - 1.f, curve->GetValue(time1));
+ EXPECT_FLOAT_EQ(std::floor(i), curve->GetValue(time2));
+ }
+ EXPECT_FLOAT_EQ(num_steps,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.0)));
+
+ for (float i = 0.5f; i <= num_steps; i += 1.0f) {
+ const base::TimeDelta time = base::TimeDelta::FromSecondsD(i / num_steps);
+ EXPECT_FLOAT_EQ(std::floor(i), curve->GetValue(time));
+ }
+}
+
+// Tests that maximum animation scale is computed as expected.
+TEST(KeyframedAnimationCurveTest, MaximumScale) {
+ std::unique_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+
+ gfx::TransformOperations operations1;
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ operations1.AppendScale(2.f, -3.f, 1.f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.f), operations1,
+ CubicBezierTimingFunction::CreatePreset(
+ CubicBezierTimingFunction::EaseType::EASE)));
+
+ constexpr float kArbitraryScale = 12345.f;
+ float maximum_scale = kArbitraryScale;
+ EXPECT_TRUE(curve->MaximumScale(&maximum_scale));
+ EXPECT_EQ(3.f, maximum_scale);
+
+ gfx::TransformOperations operations2;
+ operations2.AppendScale(6.f, 3.f, 2.f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(2.f), operations2,
+ CubicBezierTimingFunction::CreatePreset(
+ CubicBezierTimingFunction::EaseType::EASE)));
+
+ maximum_scale = kArbitraryScale;
+ EXPECT_TRUE(curve->MaximumScale(&maximum_scale));
+ EXPECT_EQ(6.f, maximum_scale);
+
+ gfx::TransformOperations operations3;
+ operations3.AppendRotate(1.f, 0.f, 0.f, 90.f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(3.f), operations3,
+ CubicBezierTimingFunction::CreatePreset(
+ CubicBezierTimingFunction::EaseType::EASE)));
+
+ maximum_scale = kArbitraryScale;
+ EXPECT_TRUE(curve->MaximumScale(&maximum_scale));
+ EXPECT_EQ(6.f, maximum_scale);
+
+ // All scales are used in computing the max.
+ std::unique_ptr<KeyframedTransformAnimationCurve> curve2(
+ KeyframedTransformAnimationCurve::Create());
+
+ gfx::TransformOperations operations5;
+ operations5.AppendScale(0.4f, 0.2f, 0.6f);
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta(), operations5,
+ CubicBezierTimingFunction::CreatePreset(
+ CubicBezierTimingFunction::EaseType::EASE)));
+ gfx::TransformOperations operations6;
+ operations6.AppendScale(0.5f, 0.3f, -0.8f);
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.f), operations6,
+ CubicBezierTimingFunction::CreatePreset(
+ CubicBezierTimingFunction::EaseType::EASE)));
+
+ maximum_scale = kArbitraryScale;
+ EXPECT_TRUE(curve2->MaximumScale(&maximum_scale));
+ EXPECT_EQ(0.8f, maximum_scale);
+}
+
+TEST(KeyframeAnimationCurveTest, NonCalculatableMaximumScale) {
+ auto curve = KeyframedTransformAnimationCurve::Create();
+ gfx::TransformOperations operations4;
+ operations4.AppendPerspective(3.f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.f), operations4,
+ CubicBezierTimingFunction::CreatePreset(
+ CubicBezierTimingFunction::EaseType::EASE)));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.f), operations4,
+ CubicBezierTimingFunction::CreatePreset(
+ CubicBezierTimingFunction::EaseType::EASE)));
+
+ constexpr float kArbitraryScale = 12345.f;
+ float maximum_scale = kArbitraryScale;
+ EXPECT_FALSE(curve->MaximumScale(&maximum_scale));
+
+ // If the scale of any keyframe can be calculated, the keyframes with
+ // non-calculatable scale will be ignored.
+ gfx::TransformOperations operations;
+ operations.AppendScale(0.4f, 0.2f, 0.6f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta(), operations,
+ CubicBezierTimingFunction::CreatePreset(
+ CubicBezierTimingFunction::EaseType::EASE)));
+
+ maximum_scale = kArbitraryScale;
+ EXPECT_TRUE(curve->MaximumScale(&maximum_scale));
+ EXPECT_EQ(0.6f, maximum_scale);
+}
+
+// Tests that an animation with a curve timing function works as expected.
+TEST(KeyframedAnimationCurveTest, CurveTiming) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.75f, 0.f, 0.25f, 1.f));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_NEAR(0.05f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)),
+ 0.005f);
+ EXPECT_FLOAT_EQ(0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_NEAR(0.95f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)),
+ 0.005f);
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that an animation with a curve and keyframe timing function works as
+// expected.
+TEST(KeyframedAnimationCurveTest, CurveAndKeyframeTiming) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ CubicBezierTimingFunction::Create(0.35f, 0.f, 0.65f, 1.f)));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
+ // Curve timing function producing outputs outside of range [0,1].
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(
+ 0.25f))); // Clamped. c(.25) < 0
+ EXPECT_NEAR(0.17f, curve->GetValue(base::TimeDelta::FromSecondsD(0.42f)),
+ 0.005f); // c(.42)=.27, k(.27)=.17
+ EXPECT_FLOAT_EQ(0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_NEAR(0.83f, curve->GetValue(base::TimeDelta::FromSecondsD(0.58f)),
+ 0.005f); // c(.58)=.73, k(.73)=.83
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(
+ 0.75f))); // Clamped. c(.75) > 1
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a linear timing function works as expected for inputs outside of
+// range [0,1]
+TEST(KeyframedAnimationCurveTest, LinearTimingInputsOutsideZeroOneRange) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr));
+ // Curve timing function producing timing outputs outside of range [0,1].
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
+
+ EXPECT_NEAR(-0.076f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)),
+ 0.001f);
+ EXPECT_NEAR(2.076f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)),
+ 0.001f);
+}
+
+// If a curve cubic-bezier timing function produces timing outputs outside
+// the range [0, 1] then a keyframe cubic-bezier timing function
+// should consume that input properly (using end-point gradients).
+TEST(KeyframedAnimationCurveTest, CurveTimingInputsOutsideZeroOneRange) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ // Keyframe timing function with 0.5 gradients at each end.
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ CubicBezierTimingFunction::Create(0.5f, 0.25f, 0.5f, 0.75f)));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
+ // Curve timing function producing timing outputs outside of range [0,1].
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
+
+ EXPECT_NEAR(-0.02f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)),
+ 0.002f); // c(.25)=-.04, -.04*0.5=-0.02
+ EXPECT_NEAR(0.33f, curve->GetValue(base::TimeDelta::FromSecondsD(0.46f)),
+ 0.002f); // c(.46)=.38, k(.38)=.33
+
+ EXPECT_NEAR(0.67f, curve->GetValue(base::TimeDelta::FromSecondsD(0.54f)),
+ 0.002f); // c(.54)=.62, k(.62)=.67
+ EXPECT_NEAR(1.02f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)),
+ 0.002f); // c(.75)=1.04 1+.04*0.5=1.02
+}
+
+// Tests that a step timing function works as expected for inputs outside of
+// range [0,1]
+TEST(KeyframedAnimationCurveTest, StepsTimingStartInputsOutsideZeroOneRange) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta(), 0.f,
+ StepsTimingFunction::Create(
+ 4, StepsTimingFunction::StepPosition::START)));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr));
+ // Curve timing function producing timing outputs outside of range [0,1].
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
+
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
+ EXPECT_FLOAT_EQ(2.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+}
+
+TEST(KeyframedAnimationCurveTest, StepsTimingEndInputsOutsideZeroOneRange) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ StepsTimingFunction::Create(4, StepsTimingFunction::StepPosition::END)));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr));
+ // Curve timing function producing timing outputs outside of range [0,1].
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
+
+ EXPECT_FLOAT_EQ(-0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+}
+
+// Tests that an animation with a curve timing function and multiple keyframes
+// works as expected.
+TEST(KeyframedAnimationCurveTest, CurveTimingMultipleKeyframes) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 3.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.f), 6.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.f), 9.f, nullptr));
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, 0.f, 0.5f, 1.f));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_NEAR(0.42f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)),
+ 0.005f);
+ EXPECT_NEAR(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.455f)),
+ 0.005f);
+ EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_NEAR(8.72f, curve->GetValue(base::TimeDelta::FromSecondsD(3.5f)),
+ 0.01f);
+ EXPECT_FLOAT_EQ(9.f, curve->GetValue(base::TimeDelta::FromSecondsD(4.f)));
+ EXPECT_FLOAT_EQ(9.f, curve->GetValue(base::TimeDelta::FromSecondsD(5.f)));
+}
+
+// Tests that an animation with a curve timing function that overshoots works as
+// expected.
+TEST(KeyframedAnimationCurveTest, CurveTimingOvershootMultipeKeyframes) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 3.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.0), 6.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.0), 9.f, nullptr));
+ // Curve timing function producing outputs outside of range [0,1].
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
+ EXPECT_LE(curve->GetValue(base::TimeDelta::FromSecondsD(1.f)),
+ 0.f); // c(.25) < 0
+ EXPECT_GE(curve->GetValue(base::TimeDelta::FromSecondsD(3.f)),
+ 9.f); // c(.75) > 1
+}
+
+// Tests that a float animation with multiple keys works with scaled duration.
+TEST(KeyframedAnimationCurveTest, ScaledDuration) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 3.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.f), 6.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.f), 9.f, nullptr));
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, 0.f, 0.5f, 1.f));
+
+ const double scale = 1000.0;
+ curve->set_scaled_duration(scale);
+
+ EXPECT_DOUBLE_EQ(scale * 4, curve->Duration().InSecondsF());
+
+ EXPECT_FLOAT_EQ(0.f,
+ curve->GetValue(base::TimeDelta::FromSecondsD(scale * -1.f)));
+ EXPECT_FLOAT_EQ(0.f,
+ curve->GetValue(base::TimeDelta::FromSecondsD(scale * 0.f)));
+ EXPECT_NEAR(0.42f,
+ curve->GetValue(base::TimeDelta::FromSecondsD(scale * 1.f)),
+ 0.005f);
+ EXPECT_NEAR(1.f,
+ curve->GetValue(base::TimeDelta::FromSecondsD(scale * 1.455f)),
+ 0.005f);
+ EXPECT_FLOAT_EQ(3.f,
+ curve->GetValue(base::TimeDelta::FromSecondsD(scale * 2.f)));
+ EXPECT_NEAR(8.72f,
+ curve->GetValue(base::TimeDelta::FromSecondsD(scale * 3.5f)),
+ 0.01f);
+ EXPECT_FLOAT_EQ(9.f,
+ curve->GetValue(base::TimeDelta::FromSecondsD(scale * 4.f)));
+ EXPECT_FLOAT_EQ(9.f,
+ curve->GetValue(base::TimeDelta::FromSecondsD(scale * 5.f)));
+}
+
+// Tests that a size animation with one keyframe works as expected.
+TEST(KeyframedAnimationCurveTest, OneSizeKeyFrame) {
+ gfx::SizeF size = gfx::SizeF(100, 100);
+ std::unique_ptr<KeyframedSizeAnimationCurve> curve(
+ KeyframedSizeAnimationCurve::Create());
+ curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta(), size, nullptr));
+
+ EXPECT_SIZEF_EQ(size, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SIZEF_EQ(size, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SIZEF_EQ(size, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_SIZEF_EQ(size, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_SIZEF_EQ(size, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a size animation with two keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, TwoSizeKeyFrame) {
+ gfx::SizeF size_a = gfx::SizeF(100, 100);
+ gfx::SizeF size_b = gfx::SizeF(100, 0);
+ gfx::SizeF size_midpoint = gfx::Tween::SizeFValueBetween(0.5, size_a, size_b);
+ std::unique_ptr<KeyframedSizeAnimationCurve> curve(
+ KeyframedSizeAnimationCurve::Create());
+ curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta(), size_a, nullptr));
+ curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ size_b, nullptr));
+
+ EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SIZEF_EQ(size_midpoint,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a size animation with three keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, ThreeSizeKeyFrame) {
+ gfx::SizeF size_a = gfx::SizeF(100, 100);
+ gfx::SizeF size_b = gfx::SizeF(100, 0);
+ gfx::SizeF size_c = gfx::SizeF(200, 0);
+ gfx::SizeF size_midpoint1 =
+ gfx::Tween::SizeFValueBetween(0.5, size_a, size_b);
+ gfx::SizeF size_midpoint2 =
+ gfx::Tween::SizeFValueBetween(0.5, size_b, size_c);
+ std::unique_ptr<KeyframedSizeAnimationCurve> curve(
+ KeyframedSizeAnimationCurve::Create());
+ curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta(), size_a, nullptr));
+ curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ size_b, nullptr));
+ curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
+ size_c, nullptr));
+
+ EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SIZEF_EQ(size_midpoint1,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_SIZEF_EQ(size_midpoint2,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_SIZEF_EQ(size_c, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_SIZEF_EQ(size_c, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
+}
+
+// Tests that a size animation with multiple keys at a given time works sanely.
+TEST(KeyframedAnimationCurveTest, RepeatedSizeKeyFrame) {
+ gfx::SizeF size_a = gfx::SizeF(100, 64);
+ gfx::SizeF size_b = gfx::SizeF(100, 192);
+
+ std::unique_ptr<KeyframedSizeAnimationCurve> curve(
+ KeyframedSizeAnimationCurve::Create());
+ curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta(), size_a, nullptr));
+ curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ size_a, nullptr));
+ curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ size_b, nullptr));
+ curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
+ size_b, nullptr));
+
+ EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+
+ gfx::SizeF value = curve->GetValue(base::TimeDelta::FromSecondsD(1.0f));
+ EXPECT_FLOAT_EQ(100.0f, value.width());
+ EXPECT_LE(64.0f, value.height());
+ EXPECT_GE(192.0f, value.height());
+
+ EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
+}
+
+// Tests that the computing of tick interval for STEPS TimingFunction works
+// correctly.
+TEST(KeyFrameAnimationCurveTest, TickIntervalForStepsTimingFunction) {
+ double kDuration = 1.0;
+ int kNumSteps = 10;
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.0, nullptr));
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta::FromSecondsD(kDuration), 4.0, nullptr));
+ curve->SetTimingFunction(StepsTimingFunction::Create(
+ kNumSteps, StepsTimingFunction::StepPosition::START));
+ EXPECT_FLOAT_EQ(kDuration / kNumSteps, curve->TickInterval().InSecondsF());
+}
+
+// Tests that the computing of tick interval for CUBIC_BEZIER TimingFunction
+// works correctly.
+TEST(KeyFrameAnimationCurveTest, TickIntervalForCubicBezierTimingFunction) {
+ SkColor color_a = SkColorSetARGB(255, 255, 0, 0);
+ SkColor color_b = SkColorSetARGB(255, 0, 255, 0);
+ double kDuration = 1.0;
+ std::unique_ptr<KeyframedColorAnimationCurve> curve(
+ KeyframedColorAnimationCurve::Create());
+ curve->AddKeyframe(
+ ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(
+ base::TimeDelta::FromSecondsD(kDuration), color_b, nullptr));
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.75f, 0.25f, 0.9f, 0.4f));
+ EXPECT_FLOAT_EQ(0, curve->TickInterval().InSecondsF());
+}
+
+// Tests that the computing of tick interval for LINEAR TimingFunction works
+// correctly.
+TEST(KeyFrameAnimationCurveTest, TickIntervalForLinearTimingFunction) {
+ gfx::SizeF size_a = gfx::SizeF(100, 64);
+ gfx::SizeF size_b = gfx::SizeF(100, 192);
+ gfx::SizeF size_c = gfx::SizeF(100, 218);
+ gfx::SizeF size_d = gfx::SizeF(100, 321);
+ double kDurationAB = 1.0;
+ double kDurationBC = 2.0;
+ double kDurationCD = 1.0;
+ int kNumStepsAB = 10;
+ int kNumStepsBC = 100;
+ std::unique_ptr<KeyframedSizeAnimationCurve> curve(
+ KeyframedSizeAnimationCurve::Create());
+ curve->AddKeyframe(SizeKeyframe::Create(
+ base::TimeDelta(), size_a,
+ StepsTimingFunction::Create(kNumStepsAB,
+ StepsTimingFunction::StepPosition::START)));
+ curve->AddKeyframe(SizeKeyframe::Create(
+ base::TimeDelta::FromSecondsD(kDurationAB), size_b,
+ StepsTimingFunction::Create(kNumStepsBC,
+ StepsTimingFunction::StepPosition::START)));
+ curve->AddKeyframe(SizeKeyframe::Create(
+ base::TimeDelta::FromSecondsD(kDurationAB + kDurationBC), size_c,
+ nullptr));
+
+ // Without explicitly setting a timing function, the default is linear.
+ EXPECT_FLOAT_EQ(kDurationBC / kNumStepsBC,
+ curve->TickInterval().InSecondsF());
+ curve->SetTimingFunction(LinearTimingFunction::Create());
+ EXPECT_FLOAT_EQ(kDurationBC / kNumStepsBC,
+ curve->TickInterval().InSecondsF());
+
+ // Add a 4th keyframe.
+ // Now the 3rd keyframe's "easing" into the 4th isn't STEPS.
+ curve->AddKeyframe(SizeKeyframe::Create(
+ base::TimeDelta::FromSecondsD(kDurationAB + kDurationBC + kDurationCD),
+ size_d, nullptr));
+ EXPECT_FLOAT_EQ(0, curve->TickInterval().InSecondsF());
+}
+
+} // namespace
+} // namespace gfx
diff --git a/chromium/ui/gfx/animation/keyframe/target_property.h b/chromium/ui/gfx/animation/keyframe/target_property.h
new file mode 100644
index 00000000000..1c76ab41ed3
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/target_property.h
@@ -0,0 +1,19 @@
+// Copyright 2021 The Chromium 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_ANIMATION_KEYFRAME_TARGET_PROPERTY_H_
+#define UI_GFX_ANIMATION_KEYFRAME_TARGET_PROPERTY_H_
+
+#include <bitset>
+
+namespace gfx {
+
+static constexpr size_t kMaxTargetPropertyIndex = 32u;
+
+// A set of target properties.
+using TargetProperties = std::bitset<kMaxTargetPropertyIndex>;
+
+} // namespace gfx
+
+#endif // UI_GFX_ANIMATION_KEYFRAME_TARGET_PROPERTY_H_
diff --git a/chromium/ui/gfx/animation/keyframe/timing_function.cc b/chromium/ui/gfx/animation/keyframe/timing_function.cc
new file mode 100644
index 00000000000..9650a501bd6
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/timing_function.cc
@@ -0,0 +1,182 @@
+// Copyright 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/animation/keyframe/timing_function.h"
+
+#include <cmath>
+#include <memory>
+
+#include "base/check_op.h"
+#include "base/memory/ptr_util.h"
+#include "base/notreached.h"
+
+namespace gfx {
+
+TimingFunction::TimingFunction() = default;
+
+TimingFunction::~TimingFunction() = default;
+
+std::unique_ptr<CubicBezierTimingFunction>
+CubicBezierTimingFunction::CreatePreset(EaseType ease_type) {
+ // These numbers come from
+ // http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag.
+ switch (ease_type) {
+ case EaseType::EASE:
+ return base::WrapUnique(
+ new CubicBezierTimingFunction(ease_type, 0.25, 0.1, 0.25, 1.0));
+ case EaseType::EASE_IN:
+ return base::WrapUnique(
+ new CubicBezierTimingFunction(ease_type, 0.42, 0.0, 1.0, 1.0));
+ case EaseType::EASE_OUT:
+ return base::WrapUnique(
+ new CubicBezierTimingFunction(ease_type, 0.0, 0.0, 0.58, 1.0));
+ case EaseType::EASE_IN_OUT:
+ return base::WrapUnique(
+ new CubicBezierTimingFunction(ease_type, 0.42, 0.0, 0.58, 1));
+ default:
+ NOTREACHED();
+ return nullptr;
+ }
+}
+std::unique_ptr<CubicBezierTimingFunction>
+CubicBezierTimingFunction::Create(double x1, double y1, double x2, double y2) {
+ return base::WrapUnique(
+ new CubicBezierTimingFunction(EaseType::CUSTOM, x1, y1, x2, y2));
+}
+
+CubicBezierTimingFunction::CubicBezierTimingFunction(EaseType ease_type,
+ double x1,
+ double y1,
+ double x2,
+ double y2)
+ : bezier_(x1, y1, x2, y2), ease_type_(ease_type) {}
+
+CubicBezierTimingFunction::~CubicBezierTimingFunction() = default;
+
+TimingFunction::Type CubicBezierTimingFunction::GetType() const {
+ return Type::CUBIC_BEZIER;
+}
+
+double CubicBezierTimingFunction::GetValue(double x) const {
+ return bezier_.Solve(x);
+}
+
+double CubicBezierTimingFunction::Velocity(double x) const {
+ return bezier_.Slope(x);
+}
+
+std::unique_ptr<TimingFunction> CubicBezierTimingFunction::Clone() const {
+ return base::WrapUnique(new CubicBezierTimingFunction(*this));
+}
+
+std::unique_ptr<StepsTimingFunction> StepsTimingFunction::Create(
+ int steps,
+ StepPosition step_position) {
+ return base::WrapUnique(new StepsTimingFunction(steps, step_position));
+}
+
+StepsTimingFunction::StepsTimingFunction(int steps, StepPosition step_position)
+ : steps_(steps), step_position_(step_position) {}
+
+StepsTimingFunction::~StepsTimingFunction() = default;
+
+TimingFunction::Type StepsTimingFunction::GetType() const {
+ return Type::STEPS;
+}
+
+double StepsTimingFunction::GetValue(double t) const {
+ return GetPreciseValue(t, TimingFunction::LimitDirection::RIGHT);
+}
+
+std::unique_ptr<TimingFunction> StepsTimingFunction::Clone() const {
+ return base::WrapUnique(new StepsTimingFunction(*this));
+}
+
+double StepsTimingFunction::Velocity(double x) const {
+ return 0;
+}
+
+double StepsTimingFunction::GetPreciseValue(double t,
+ LimitDirection direction) const {
+ const double steps = static_cast<double>(steps_);
+ double current_step = std::floor((steps * t) + GetStepsStartOffset());
+ // Adjust step if using a left limit at a discontinuous step boundary.
+ if (direction == LimitDirection::LEFT &&
+ steps * t - std::floor(steps * t) == 0) {
+ current_step -= 1;
+ }
+ // Jumps may differ from steps based on the number of end-point
+ // discontinuities, which may be 0, 1 or 2.
+ int jumps = NumberOfJumps();
+ if (t >= 0 && current_step < 0)
+ current_step = 0;
+ if (t <= 1 && current_step > jumps)
+ current_step = jumps;
+ return current_step / jumps;
+}
+
+int StepsTimingFunction::NumberOfJumps() const {
+ switch (step_position_) {
+ case StepPosition::END:
+ case StepPosition::START:
+ case StepPosition::JUMP_END:
+ case StepPosition::JUMP_START:
+ return steps_;
+
+ case StepPosition::JUMP_BOTH:
+ return steps_ + 1;
+
+ case StepPosition::JUMP_NONE:
+ DCHECK_GT(steps_, 1);
+ return steps_ - 1;
+
+ default:
+ NOTREACHED();
+ return steps_;
+ }
+}
+
+float StepsTimingFunction::GetStepsStartOffset() const {
+ switch (step_position_) {
+ case StepPosition::JUMP_BOTH:
+ case StepPosition::JUMP_START:
+ case StepPosition::START:
+ return 1;
+
+ case StepPosition::JUMP_END:
+ case StepPosition::JUMP_NONE:
+ case StepPosition::END:
+ return 0;
+
+ default:
+ NOTREACHED();
+ return 1;
+ }
+}
+
+std::unique_ptr<LinearTimingFunction> LinearTimingFunction::Create() {
+ return base::WrapUnique(new LinearTimingFunction());
+}
+
+LinearTimingFunction::LinearTimingFunction() = default;
+
+LinearTimingFunction::~LinearTimingFunction() = default;
+
+TimingFunction::Type LinearTimingFunction::GetType() const {
+ return Type::LINEAR;
+}
+
+std::unique_ptr<TimingFunction> LinearTimingFunction::Clone() const {
+ return base::WrapUnique(new LinearTimingFunction(*this));
+}
+
+double LinearTimingFunction::Velocity(double x) const {
+ return 0;
+}
+
+double LinearTimingFunction::GetValue(double t) const {
+ return t;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/animation/keyframe/timing_function.h b/chromium/ui/gfx/animation/keyframe/timing_function.h
new file mode 100644
index 00000000000..7ce71331dfe
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/timing_function.h
@@ -0,0 +1,143 @@
+// Copyright 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_ANIMATION_KEYFRAME_TIMING_FUNCTION_H_
+#define UI_GFX_ANIMATION_KEYFRAME_TIMING_FUNCTION_H_
+
+#include <memory>
+
+#include "ui/gfx/animation/keyframe/keyframe_animation_export.h"
+#include "ui/gfx/geometry/cubic_bezier.h"
+
+namespace gfx {
+
+// See http://www.w3.org/TR/css3-transitions/.
+class GFX_KEYFRAME_ANIMATION_EXPORT TimingFunction {
+ public:
+ virtual ~TimingFunction();
+
+ TimingFunction& operator=(const TimingFunction&) = delete;
+
+ // Note that LINEAR is a nullptr TimingFunction (for now).
+ enum class Type { LINEAR, CUBIC_BEZIER, STEPS };
+
+ // Which limit to apply at a discontinuous boundary.
+ enum class LimitDirection { LEFT, RIGHT };
+
+ virtual Type GetType() const = 0;
+ virtual double GetValue(double t) const = 0;
+ virtual double Velocity(double time) const = 0;
+ virtual std::unique_ptr<TimingFunction> Clone() const = 0;
+
+ protected:
+ TimingFunction();
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT CubicBezierTimingFunction
+ : public TimingFunction {
+ public:
+ enum class EaseType { EASE, EASE_IN, EASE_OUT, EASE_IN_OUT, CUSTOM };
+
+ static std::unique_ptr<CubicBezierTimingFunction> CreatePreset(
+ EaseType ease_type);
+ static std::unique_ptr<CubicBezierTimingFunction> Create(double x1,
+ double y1,
+ double x2,
+ double y2);
+ ~CubicBezierTimingFunction() override;
+
+ CubicBezierTimingFunction& operator=(const CubicBezierTimingFunction&) =
+ delete;
+
+ // TimingFunction implementation.
+ Type GetType() const override;
+ double GetValue(double time) const override;
+ double Velocity(double time) const override;
+ std::unique_ptr<TimingFunction> Clone() const override;
+
+ EaseType ease_type() const { return ease_type_; }
+ const gfx::CubicBezier& bezier() const { return bezier_; }
+
+ private:
+ CubicBezierTimingFunction(EaseType ease_type,
+ double x1,
+ double y1,
+ double x2,
+ double y2);
+
+ gfx::CubicBezier bezier_;
+ EaseType ease_type_;
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT StepsTimingFunction
+ : public TimingFunction {
+ public:
+ // step-timing-function values
+ // https://drafts.csswg.org/css-easing-1/#typedef-step-timing-function
+ enum class StepPosition {
+ START, // Discontinuity at progress = 0.
+ // Alias for jump-start. Maintaining a separate enumerated value
+ // for serialization.
+ END, // Discontinuity at progress = 1.
+ // Alias for jump-end. Maintaining a separate enumerated value
+ // for serialization.
+ JUMP_BOTH, // Discontinuities at progress = 0 and 1.
+ JUMP_END, // Discontinuity at progress = 1.
+ JUMP_NONE, // Continuous at progress = 0 and 1.
+ JUMP_START // Discontinuity at progress = 0.
+ };
+
+ static std::unique_ptr<StepsTimingFunction> Create(
+ int steps,
+ StepPosition step_position);
+ ~StepsTimingFunction() override;
+
+ StepsTimingFunction& operator=(const StepsTimingFunction&) = delete;
+
+ // TimingFunction implementation.
+ Type GetType() const override;
+ double GetValue(double t) const override;
+ std::unique_ptr<TimingFunction> Clone() const override;
+ double Velocity(double time) const override;
+
+ int steps() const { return steps_; }
+ StepPosition step_position() const { return step_position_; }
+ double GetPreciseValue(double t, LimitDirection limit_direction) const;
+
+ private:
+ StepsTimingFunction(int steps, StepPosition step_position);
+
+ // The number of jumps is the number of discontinuities in the timing
+ // function. There is a subtle distinction between the number of steps and
+ // jumps. The number of steps is the number of intervals in the timing
+ // function. The number of jumps differs from the number of steps when either
+ // both or neither end point has a discontinuity.
+ // https://drafts.csswg.org/css-easing-1/#step-easing-functions
+ int NumberOfJumps() const;
+
+ float GetStepsStartOffset() const;
+
+ int steps_;
+ StepPosition step_position_;
+};
+
+class GFX_KEYFRAME_ANIMATION_EXPORT LinearTimingFunction
+ : public TimingFunction {
+ public:
+ static std::unique_ptr<LinearTimingFunction> Create();
+ ~LinearTimingFunction() override;
+
+ // TimingFunction implementation.
+ Type GetType() const override;
+ double GetValue(double t) const override;
+ std::unique_ptr<TimingFunction> Clone() const override;
+ double Velocity(double time) const override;
+
+ private:
+ LinearTimingFunction();
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_ANIMATION_KEYFRAME_TIMING_FUNCTION_H_
diff --git a/chromium/ui/gfx/animation/keyframe/transition.cc b/chromium/ui/gfx/animation/keyframe/transition.cc
new file mode 100644
index 00000000000..05ce53da634
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/transition.cc
@@ -0,0 +1,19 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/animation/keyframe/transition.h"
+
+namespace gfx {
+
+namespace {
+static constexpr int kDefaultTransitionDurationMs = 225;
+} // namespace
+
+Transition::Transition()
+ : duration(
+ base::TimeDelta::FromMilliseconds(kDefaultTransitionDurationMs)) {}
+
+Transition::~Transition() {}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/animation/keyframe/transition.h b/chromium/ui/gfx/animation/keyframe/transition.h
new file mode 100644
index 00000000000..a43b606eafb
--- /dev/null
+++ b/chromium/ui/gfx/animation/keyframe/transition.h
@@ -0,0 +1,25 @@
+// 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_GFX_ANIMATION_KEYFRAME_TRANSITION_H_
+#define UI_GFX_ANIMATION_KEYFRAME_TRANSITION_H_
+
+#include <set>
+
+#include "base/time/time.h"
+#include "ui/gfx/animation/keyframe/keyframe_animation_export.h"
+
+namespace gfx {
+
+struct GFX_KEYFRAME_ANIMATION_EXPORT Transition {
+ Transition();
+ ~Transition();
+
+ base::TimeDelta duration;
+ std::set<int> target_properties;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_ANIMATION_KEYFRAME_TRANSITION_H_
diff --git a/chromium/ui/gfx/animation/tween.cc b/chromium/ui/gfx/animation/tween.cc
index b5a65906318..6b9e9dec555 100644
--- a/chromium/ui/gfx/animation/tween.cc
+++ b/chromium/ui/gfx/animation/tween.cc
@@ -45,6 +45,9 @@ double Tween::CalculateValue(Tween::Type type, double state) {
case EASE_OUT_3:
return gfx::CubicBezier(0.6, 0, 0, 1).Solve(state);
+ case EASE_OUT_4:
+ return gfx::CubicBezier(1, 0, 0.8, 1).Solve(state);
+
case LINEAR:
return state;
@@ -63,6 +66,9 @@ double Tween::CalculateValue(Tween::Type type, double state) {
case FAST_OUT_SLOW_IN_2:
return gfx::CubicBezier(0.2, 0, 0.2, 1).Solve(state);
+ case FAST_OUT_SLOW_IN_3:
+ return gfx::CubicBezier(0.2, 0, 0, 1).Solve(state);
+
case LINEAR_OUT_SLOW_IN:
return gfx::CubicBezier(0, 0, .2, 1).Solve(state);
@@ -74,6 +80,12 @@ double Tween::CalculateValue(Tween::Type type, double state) {
case ZERO:
return 0;
+
+ case ACCEL_LIN_DECEL_60:
+ return gfx::CubicBezier(0, 0, 0.4, 1).Solve(state);
+
+ case ACCEL_20_DECEL_60:
+ return gfx::CubicBezier(0.2, 0, 0.4, 1).Solve(state);
}
NOTREACHED();
@@ -209,6 +221,14 @@ gfx::Transform Tween::TransformValueBetween(double value,
return to_return;
}
+// static
+gfx::TransformOperations Tween::TransformOperationsValueBetween(
+ double value,
+ const gfx::TransformOperations& start,
+ const gfx::TransformOperations& target) {
+ return target.Blend(start, value);
+}
+
gfx::Size Tween::SizeValueBetween(double value,
const gfx::Size& start,
const gfx::Size& target) {
diff --git a/chromium/ui/gfx/animation/tween.h b/chromium/ui/gfx/animation/tween.h
index 9d5c82137fe..e2502a3c202 100644
--- a/chromium/ui/gfx/animation/tween.h
+++ b/chromium/ui/gfx/animation/tween.h
@@ -12,6 +12,7 @@
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/transform.h"
+#include "ui/gfx/transform_operations.h"
namespace base {
class TimeTicks;
@@ -26,6 +27,9 @@ class ANIMATION_EXPORT Tween {
EASE_OUT, // Fast in, slow out (default).
EASE_OUT_2, // Variant of EASE_OUT that ends slower than EASE_OUT.
EASE_OUT_3, // Variant of EASE_OUT that ends slower than EASE_OUT_2.
+ EASE_OUT_4, // Variant of EASE_OUT that start slower than EASE_OUT_3,
+ // and ends faster. Best used to lead into a bounce
+ // animation.
EASE_IN, // Slow in, fast out.
EASE_IN_2, // Variant of EASE_IN that starts out slower than
// EASE_IN.
@@ -36,6 +40,9 @@ class ANIMATION_EXPORT Tween {
FAST_OUT_SLOW_IN, // Variant of EASE_IN_OUT which should be used in most
// cases.
FAST_OUT_SLOW_IN_2, // Variant of FAST_OUT_SLOW_IN that starts out quicker.
+ FAST_OUT_SLOW_IN_3, // Variant of FAST_OUT_SLOW_IN that starts out quicker
+ // than FAST_OUT_SLOW_IN_2. Best used for rebound in
+ // bounce animation.
LINEAR_OUT_SLOW_IN, // Variant of EASE_OUT which should be used for
// fading in from 0% or motion when entering a scene.
SLOW_OUT_LINEAR_IN, // Reverse of LINEAR_OUT_SLOW_IN which should be used
@@ -43,6 +50,21 @@ class ANIMATION_EXPORT Tween {
FAST_OUT_LINEAR_IN, // Variant of EASE_IN which should should be used for
// fading out to 0% or motion when exiting a scene.
ZERO, // Returns a value of 0 always.
+
+ // TODO(zxdan): New animation curve name convention will be used to resolve
+ // the confusion caused by "IN" and "OUT".
+
+ // The new name convention is below:
+ // ACCEL_<1>_DECEL_<2> where <1> and <2> are used to express the
+ // acceleration and deceleration speeds. The corresponding cubic bezier
+ // curve parameters would be ( 0.01 * <1>, 0, 1 - 0.01 * <2>, 1 ). Note that
+ // LIN means the speed is 0. For example,
+ // ACCEL_20_DECEL_20 = (0.2, 0, 0.8, 1): https://cubic-bezier.com/#.2,0,.8,1
+ // ACCEL_100_DECEL_100 = (1, 0, 0, 1): https://cubic-bezier.com/#1,0,0,1
+ // ACCEL_LIN_DECEL_LIN = (0, 0, 1, 1): https://cubic-bezier.com/#0,0,1,1
+ // ACCEL_40_DECEL_80 = (0.4, 0, 0.2, 1): https://cubic-bezier.com/#.4,0,.2,1
+ ACCEL_LIN_DECEL_60, // Pulling a small to medium element into a place.
+ ACCEL_20_DECEL_60, // Moving a small, low emphasis or responsive elements.
};
// Returns the value based on the tween type. |state| is from 0-1.
@@ -84,6 +106,11 @@ class ANIMATION_EXPORT Tween {
const gfx::Transform& start,
const gfx::Transform& target);
+ static gfx::TransformOperations TransformOperationsValueBetween(
+ double value,
+ const gfx::TransformOperations& start,
+ const gfx::TransformOperations& target);
+
static gfx::Size SizeValueBetween(double value,
const gfx::Size& start,
const gfx::Size& target);
diff --git a/chromium/ui/gfx/bidi_line_iterator.cc b/chromium/ui/gfx/bidi_line_iterator.cc
index 976d33ff16d..0ffb94b5c6f 100644
--- a/chromium/ui/gfx/bidi_line_iterator.cc
+++ b/chromium/ui/gfx/bidi_line_iterator.cc
@@ -5,6 +5,7 @@
#include "ui/gfx/bidi_line_iterator.h"
#include "base/check.h"
+#include "base/i18n/uchar.h"
#include "base/notreached.h"
namespace ui {
@@ -45,7 +46,8 @@ bool BiDiLineIterator::Open(const base::string16& text,
if (U_FAILURE(error))
return false;
- ubidi_setPara(bidi_, text.data(), static_cast<int>(text.length()),
+ ubidi_setPara(bidi_, base::i18n::ToUCharPtr(text.data()),
+ static_cast<int>(text.length()),
GetParagraphLevelForDirection(direction), nullptr, &error);
return (U_SUCCESS(error));
}
diff --git a/chromium/ui/gfx/buffer_types.h b/chromium/ui/gfx/buffer_types.h
index 32ffc612abb..fbb58c7a668 100644
--- a/chromium/ui/gfx/buffer_types.h
+++ b/chromium/ui/gfx/buffer_types.h
@@ -52,9 +52,9 @@ enum class BufferUsage {
PROTECTED_SCANOUT_VDA_WRITE,
GPU_READ_CPU_READ_WRITE,
SCANOUT_VEA_CPU_READ,
- SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE,
+ VEA_READ_CAMERA_AND_CPU_READ_WRITE,
- LAST = SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE
+ LAST = VEA_READ_CAMERA_AND_CPU_READ_WRITE
};
struct BufferUsageAndFormat {
diff --git a/chromium/ui/gfx/buffer_usage_util.cc b/chromium/ui/gfx/buffer_usage_util.cc
index 20e17d98639..081cda9b158 100644
--- a/chromium/ui/gfx/buffer_usage_util.cc
+++ b/chromium/ui/gfx/buffer_usage_util.cc
@@ -26,8 +26,8 @@ const char* BufferUsageToString(BufferUsage usage) {
return "GPU_READ_CPU_READ_WRITE";
case BufferUsage::SCANOUT_VEA_CPU_READ:
return "SCANOUT_VEA_CPU_READ";
- case BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE:
- return "SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE";
+ case BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE:
+ return "VEA_READ_CAMERA_AND_CPU_READ_WRITE";
}
return "Invalid Usage";
}
diff --git a/chromium/ui/gfx/canvas_skia.cc b/chromium/ui/gfx/canvas_skia.cc
index ddc60e28c8d..4ef6a0660d0 100644
--- a/chromium/ui/gfx/canvas_skia.cc
+++ b/chromium/ui/gfx/canvas_skia.cc
@@ -25,13 +25,16 @@ namespace {
// Returns a range in |text| to underline or Range::InvalidRange() if
// underlining is not needed.
Range StripAcceleratorChars(int flags, base::string16* text) {
- if (flags & (Canvas::SHOW_PREFIX | Canvas::HIDE_PREFIX)) {
+ if (flags & Canvas::SHOW_PREFIX) {
int char_pos = -1;
int char_span = 0;
- *text = RemoveAcceleratorChar(*text, '&', &char_pos, &char_span);
- if ((flags & Canvas::SHOW_PREFIX) && char_pos != -1)
+ *text = LocateAndRemoveAcceleratorChar(*text, &char_pos, &char_span);
+ if (char_pos != -1)
return Range(char_pos, char_pos + char_span);
+ } else if (flags & Canvas::HIDE_PREFIX) {
+ *text = RemoveAccelerator(*text);
}
+
return Range::InvalidRange();
}
diff --git a/chromium/ui/gfx/color_space.cc b/chromium/ui/gfx/color_space.cc
index 24b0b0313a2..7df2b335b75 100644
--- a/chromium/ui/gfx/color_space.cc
+++ b/chromium/ui/gfx/color_space.cc
@@ -1087,7 +1087,18 @@ bool ColorSpace::GetPiecewiseHDRParams(float* sdr_joint,
return true;
}
-void ColorSpace::GetTransferMatrix(SkMatrix44* matrix) const {
+void ColorSpace::GetTransferMatrix(int bit_depth, SkMatrix44* matrix) const {
+ DCHECK_GE(bit_depth, 8);
+ // If chroma samples are real numbers in the range of −0.5 to 0.5, an offset
+ // of 0.5 is added to get real numbers in the range of 0 to 1. When
+ // represented as an unsigned |bit_depth|-bit integer, this 0.5 offset is
+ // approximated by 1 << (bit_depth - 1). chroma_0_5 is this approximate value
+ // converted to a real number in the range of 0 to 1.
+ //
+ // TODO(wtc): For now chroma_0_5 is only used for YCgCo. It should also be
+ // used for YUV.
+ const float chroma_0_5 =
+ static_cast<float>(1 << (bit_depth - 1)) / ((1 << bit_depth) - 1);
float Kr = 0;
float Kb = 0;
switch (matrix_) {
@@ -1118,12 +1129,10 @@ void ColorSpace::GetTransferMatrix(SkMatrix44* matrix) const {
break;
case ColorSpace::MatrixID::YCOCG: {
- float data[16] = {
- 0.25f, 0.5f, 0.25f, 0.0f, // Y
- -0.25f, 0.5f, -0.25f, 0.5f, // Cg
- 0.5f, 0.0f, -0.5f, 0.5f, // Co
- 0.0f, 0.0f, 0.0f, 1.0f
- };
+ float data[16] = {0.25f, 0.5f, 0.25f, 0.0f, // Y
+ -0.25f, 0.5f, -0.25f, chroma_0_5, // Cg
+ 0.5f, 0.0f, -0.5f, chroma_0_5, // Co
+ 0.0f, 0.0f, 0.0f, 1.0f};
matrix->setRowMajorf(data);
return;
}
diff --git a/chromium/ui/gfx/color_space.h b/chromium/ui/gfx/color_space.h
index ebaa674060b..464b747579d 100644
--- a/chromium/ui/gfx/color_space.h
+++ b/chromium/ui/gfx/color_space.h
@@ -327,8 +327,9 @@ class COLOR_SPACE_EXPORT ColorSpace {
// CreatePiecewiseHDR for parameter meanings.
bool GetPiecewiseHDRParams(float* sdr_point, float* hdr_level) const;
- // For most formats, this is the RGB to YUV matrix.
- void GetTransferMatrix(SkMatrix44* matrix) const;
+ // Returns the transfer matrix for |bit_depth|. For most formats, this is the
+ // RGB to YUV matrix.
+ void GetTransferMatrix(int bit_depth, SkMatrix44* matrix) const;
// Returns the range adjust matrix that converts from |range_| to full range
// for |bit_depth|.
diff --git a/chromium/ui/gfx/color_space_unittest.cc b/chromium/ui/gfx/color_space_unittest.cc
index c09ad1fedda..58513971802 100644
--- a/chromium/ui/gfx/color_space_unittest.cc
+++ b/chromium/ui/gfx/color_space_unittest.cc
@@ -66,7 +66,7 @@ TEST(ColorSpace, RGBToYUV) {
for (size_t i = 0; i < kNumColorSpaces; ++i) {
SkMatrix44 transfer;
- color_spaces[i].GetTransferMatrix(&transfer);
+ color_spaces[i].GetTransferMatrix(/*bit_depth=*/8, &transfer);
SkMatrix44 range_adjust;
color_spaces[i].GetRangeAdjustMatrix(&range_adjust);
diff --git a/chromium/ui/gfx/color_transform.cc b/chromium/ui/gfx/color_transform.cc
index cac5747727e..ab66361f034 100644
--- a/chromium/ui/gfx/color_transform.cc
+++ b/chromium/ui/gfx/color_transform.cc
@@ -143,9 +143,9 @@ float ToLinear(ColorSpace::TransferID id, float v) {
return 0;
}
-Transform GetTransferMatrix(const gfx::ColorSpace& color_space) {
+Transform GetTransferMatrix(const gfx::ColorSpace& color_space, int bit_depth) {
SkMatrix44 transfer_matrix;
- color_space.GetTransferMatrix(&transfer_matrix);
+ color_space.GetTransferMatrix(bit_depth, &transfer_matrix);
return Transform(transfer_matrix);
}
@@ -938,17 +938,28 @@ void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform(
int src_bit_depth,
const ColorSpace& dst,
int dst_bit_depth) {
- steps_.push_back(std::make_unique<ColorTransformMatrix>(
- GetRangeAdjustMatrix(src, src_bit_depth)));
+ // ITU-T H.273: If MatrixCoefficients is equal to 0 (Identity) or 8 (YCgCo),
+ // range adjustment is performed on R,G,B samples rather than Y,U,V samples.
+ const bool src_matrix_is_identity_or_ycgco =
+ src.GetMatrixID() == ColorSpace::MatrixID::GBR ||
+ src.GetMatrixID() == ColorSpace::MatrixID::YCOCG;
+ auto src_range_adjust_matrix = std::make_unique<ColorTransformMatrix>(
+ GetRangeAdjustMatrix(src, src_bit_depth));
+
+ if (!src_matrix_is_identity_or_ycgco)
+ steps_.push_back(std::move(src_range_adjust_matrix));
if (src.GetMatrixID() == ColorSpace::MatrixID::BT2020_CL) {
// BT2020 CL is a special case.
steps_.push_back(std::make_unique<ColorTransformFromBT2020CL>());
} else {
- steps_.push_back(
- std::make_unique<ColorTransformMatrix>(Invert(GetTransferMatrix(src))));
+ steps_.push_back(std::make_unique<ColorTransformMatrix>(
+ Invert(GetTransferMatrix(src, src_bit_depth))));
}
+ if (src_matrix_is_identity_or_ycgco)
+ steps_.push_back(std::move(src_range_adjust_matrix));
+
// If the target color space is not defined, just apply the adjust and
// tranfer matrices. This path is used by YUV to RGB color conversion
// when full color conversion is not enabled.
@@ -981,8 +992,8 @@ void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform(
if (src.GetMatrixID() == ColorSpace::MatrixID::BT2020_CL) {
// BT2020 CL is a special case.
- steps_.push_back(
- std::make_unique<ColorTransformMatrix>(Invert(GetTransferMatrix(src))));
+ steps_.push_back(std::make_unique<ColorTransformMatrix>(
+ Invert(GetTransferMatrix(src, src_bit_depth))));
}
steps_.push_back(
std::make_unique<ColorTransformMatrix>(GetPrimaryTransform(src)));
@@ -991,8 +1002,8 @@ void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform(
std::make_unique<ColorTransformMatrix>(Invert(GetPrimaryTransform(dst))));
if (dst.GetMatrixID() == ColorSpace::MatrixID::BT2020_CL) {
// BT2020 CL is a special case.
- steps_.push_back(
- std::make_unique<ColorTransformMatrix>(GetTransferMatrix(dst)));
+ steps_.push_back(std::make_unique<ColorTransformMatrix>(
+ GetTransferMatrix(dst, dst_bit_depth)));
}
skcms_TransferFunction dst_from_linear_fn;
@@ -1020,15 +1031,26 @@ void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform(
std::make_unique<ColorTransformFromLinear>(dst.GetTransferID()));
}
+ // ITU-T H.273: If MatrixCoefficients is equal to 0 (Identity) or 8 (YCgCo),
+ // range adjustment is performed on R,G,B samples rather than Y,U,V samples.
+ const bool dst_matrix_is_identity_or_ycgco =
+ dst.GetMatrixID() == ColorSpace::MatrixID::GBR ||
+ dst.GetMatrixID() == ColorSpace::MatrixID::YCOCG;
+ auto dst_range_adjust_matrix = std::make_unique<ColorTransformMatrix>(
+ Invert(GetRangeAdjustMatrix(dst, dst_bit_depth)));
+
+ if (dst_matrix_is_identity_or_ycgco)
+ steps_.push_back(std::move(dst_range_adjust_matrix));
+
if (dst.GetMatrixID() == ColorSpace::MatrixID::BT2020_CL) {
NOTREACHED();
} else {
- steps_.push_back(
- std::make_unique<ColorTransformMatrix>(GetTransferMatrix(dst)));
+ steps_.push_back(std::make_unique<ColorTransformMatrix>(
+ GetTransferMatrix(dst, dst_bit_depth)));
}
- steps_.push_back(std::make_unique<ColorTransformMatrix>(
- Invert(GetRangeAdjustMatrix(dst, dst_bit_depth))));
+ if (!dst_matrix_is_identity_or_ycgco)
+ steps_.push_back(std::move(dst_range_adjust_matrix));
}
ColorTransformInternal::ColorTransformInternal(const ColorSpace& src,
diff --git a/chromium/ui/gfx/color_transform_unittest.cc b/chromium/ui/gfx/color_transform_unittest.cc
index ff7835458ae..1b91fc4e566 100644
--- a/chromium/ui/gfx/color_transform_unittest.cc
+++ b/chromium/ui/gfx/color_transform_unittest.cc
@@ -128,6 +128,48 @@ TEST(SimpleColorSpace, BT2020CLtoBT2020RGB) {
EXPECT_GT(tmp.z(), tmp.y());
}
+TEST(SimpleColorSpace, YCOCGLimitedToSRGB) {
+ ColorSpace ycocg(ColorSpace::PrimaryID::BT709,
+ ColorSpace::TransferID::IEC61966_2_1,
+ ColorSpace::MatrixID::YCOCG, ColorSpace::RangeID::LIMITED);
+ ColorSpace sRGB = ColorSpace::CreateSRGB();
+ std::unique_ptr<ColorTransform> t(ColorTransform::NewColorTransform(
+ ycocg, sRGB, ColorTransform::Intent::INTENT_ABSOLUTE));
+
+ ColorTransform::TriStim tmp(16.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f);
+ t->Transform(&tmp, 1);
+ EXPECT_NEAR(tmp.x(), 0.0f, kMathEpsilon);
+ EXPECT_NEAR(tmp.y(), 0.0f, kMathEpsilon);
+ EXPECT_NEAR(tmp.z(), 0.0f, kMathEpsilon);
+
+ tmp = ColorTransform::TriStim(235.0f / 255.0f, 128.0f / 255.0f,
+ 128.0f / 255.0f);
+ t->Transform(&tmp, 1);
+ EXPECT_NEAR(tmp.x(), 1.0f, kMathEpsilon);
+ EXPECT_NEAR(tmp.y(), 1.0f, kMathEpsilon);
+ EXPECT_NEAR(tmp.z(), 1.0f, kMathEpsilon);
+
+ // Test a blue color
+ // Use the equations for MatrixCoefficients 8 and VideoFullRangeFlag 0 in
+ // ITU-T H.273:
+ // Equations 11-13: E'_R = 0.0, E'_G = 0.0, E'_B = 1.0
+ // Equations 20-22: R = 16, G = 16, B = 219 + 16 = 235
+ // Equations 44-46:
+ // Y = Round(0.5 * 16 + 0.25 * (16 + 235)) = Round(70.75) = 71
+ // Cb = Round(0.5 * 16 - 0.25 * (16 + 235)) + 128 = Round(-54.75) + 128 = 73
+ // Cr = Round(0.5 * (16 - 235)) + 128 = Round(-109.5) + 128 = 18
+ // In this test we omit the Round() calls to avoid rounding errors.
+ // Y = 0.5 * 16 + 0.25 * (16 + 235) = 70.75
+ // Cb = 0.5 * 16 - 0.25 * (16 + 235) + 128 = -54.75 + 128 = 73.25
+ // Cr = 0.5 * (16 - 235) + 128 = -109.5 + 128 = 18.5
+ tmp =
+ ColorTransform::TriStim(70.75f / 255.0f, 73.25f / 255.0f, 18.5f / 255.0f);
+ t->Transform(&tmp, 1);
+ EXPECT_NEAR(tmp.x(), 0.0f, kMathEpsilon);
+ EXPECT_NEAR(tmp.y(), 0.0f, kMathEpsilon);
+ EXPECT_NEAR(tmp.z(), 1.0f, kMathEpsilon);
+}
+
TEST(SimpleColorSpace, TransferFnCancel) {
ColorSpace::PrimaryID primary = ColorSpace::PrimaryID::BT709;
ColorSpace::MatrixID matrix = ColorSpace::MatrixID::RGB;
@@ -524,10 +566,10 @@ TEST(SimpleColorSpace, CanParseSkShaderSource) {
"half4 main() {\n"
" half4 color = sample(child);\n" +
transform->GetSkShaderSource() + " return color; }";
- auto result =
- SkRuntimeEffect::Make(SkString(source.c_str(), source.length()));
- EXPECT_NE(std::get<0>(result), nullptr);
- EXPECT_TRUE(std::get<1>(result).isEmpty()) << std::get<1>(result).c_str();
+ SkRuntimeEffect::Result result = SkRuntimeEffect::Make(
+ SkString(source.c_str(), source.length()), /*options=*/{});
+ EXPECT_NE(result.effect, nullptr);
+ EXPECT_STREQ(result.errorText.c_str(), "");
}
}
}
diff --git a/chromium/ui/gfx/color_utils.h b/chromium/ui/gfx/color_utils.h
index 5838b5279eb..94ab366f157 100644
--- a/chromium/ui/gfx/color_utils.h
+++ b/chromium/ui/gfx/color_utils.h
@@ -34,6 +34,11 @@ struct BlendResult {
// This value is taken from w3c accessibility guidelines.
constexpr float kMinimumReadableContrastRatio = 4.5f;
+// The minimum contrast between button glyphs, focus indicators, large text, or
+// other "have to see it but perhaps don't have to read fine detail" cases and
+// background.
+constexpr float kMinimumVisibleContrastRatio = 3.0f;
+
// Determines the contrast ratio of two colors or two relative luminance values
// (as computed by RelativeLuminance()), calculated according to
// http://www.w3.org/TR/WCAG20/#contrast-ratiodef .
diff --git a/chromium/ui/gfx/display_color_spaces.cc b/chromium/ui/gfx/display_color_spaces.cc
index 08c30ede734..6016876e126 100644
--- a/chromium/ui/gfx/display_color_spaces.cc
+++ b/chromium/ui/gfx/display_color_spaces.cc
@@ -5,6 +5,7 @@
#include "ui/gfx/display_color_spaces.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
namespace gfx {
@@ -19,7 +20,7 @@ const ContentColorUsage kAllColorUsages[] = {
gfx::BufferFormat DefaultBufferFormat() {
// ChromeOS expects the default buffer format be BGRA_8888 in several places.
// https://crbug.com/1057501, https://crbug.com/1073237
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return gfx::BufferFormat::BGRA_8888;
#else
return gfx::BufferFormat::RGBA_8888;
diff --git a/chromium/ui/gfx/font_fallback_skia_unittest.cc b/chromium/ui/gfx/font_fallback_skia_unittest.cc
index 8d38bcc060a..e700c714736 100644
--- a/chromium/ui/gfx/font_fallback_skia_unittest.cc
+++ b/chromium/ui/gfx/font_fallback_skia_unittest.cc
@@ -4,6 +4,7 @@
#include "ui/gfx/font_fallback.h"
+#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/ui/gfx/font_fallback_unittest.cc b/chromium/ui/gfx/font_fallback_unittest.cc
index 2d60121c657..3af544bf66b 100644
--- a/chromium/ui/gfx/font_fallback_unittest.cc
+++ b/chromium/ui/gfx/font_fallback_unittest.cc
@@ -6,6 +6,7 @@
#include <tuple>
+#include "base/i18n/uchar.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -235,10 +236,10 @@ std::vector<FallbackFontTestCase> GetSampleFontTestCases() {
const UScriptCode script = static_cast<UScriptCode>(i);
// Make a sample text to test the script.
- UChar text[8];
+ base::char16 text[8];
UErrorCode errorCode = U_ZERO_ERROR;
- int text_length =
- uscript_getSampleString(script, text, base::size(text), &errorCode);
+ int text_length = uscript_getSampleString(
+ script, base::i18n::ToUCharPtr(text), base::size(text), &errorCode);
if (text_length <= 0 || errorCode != U_ZERO_ERROR)
continue;
diff --git a/chromium/ui/gfx/font_fallback_win.cc b/chromium/ui/gfx/font_fallback_win.cc
index d94a4fce1d7..0f7253bf35e 100644
--- a/chromium/ui/gfx/font_fallback_win.cc
+++ b/chromium/ui/gfx/font_fallback_win.cc
@@ -9,7 +9,6 @@
#include "base/macros.h"
#include "base/memory/singleton.h"
-#include "base/metrics/histogram_macros.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -142,19 +141,14 @@ CachedFontLinkSettings* CachedFontLinkSettings::GetInstance() {
const std::vector<Font>* CachedFontLinkSettings::GetLinkedFonts(
const Font& font) {
- SCOPED_UMA_HISTOGRAM_LONG_TIMER("FontFallback.GetLinkedFonts.Timing");
const std::string& font_name = font.GetFontName();
std::map<std::string, std::vector<Font> >::const_iterator it =
cached_linked_fonts_.find(font_name);
if (it != cached_linked_fonts_.end())
return &it->second;
- SCOPED_UMA_HISTOGRAM_LONG_TIMER(
- "FontFallback.GetLinkedFonts.CacheMissTiming");
std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name];
QueryLinkedFontsFromRegistry(font, &cached_system_fonts_, linked_fonts);
- UMA_HISTOGRAM_COUNTS_100("FontFallback.GetLinkedFonts.FontCount",
- linked_fonts->size());
return linked_fonts;
}
diff --git a/chromium/ui/gfx/font_fallback_win_unittest.cc b/chromium/ui/gfx/font_fallback_win_unittest.cc
index fa615eacf04..a1b05ae1abd 100644
--- a/chromium/ui/gfx/font_fallback_win_unittest.cc
+++ b/chromium/ui/gfx/font_fallback_win_unittest.cc
@@ -88,18 +88,18 @@ TEST_F(FontFallbackWinTest, NulTerminatedStringPiece) {
Font base_font;
Font fallback_font;
// Multiple ending NUL characters.
- const wchar_t kTest1[] = {0x0540, 0x0541, 0, 0, 0};
+ const base::char16 kTest1[] = {0x0540, 0x0541, 0, 0, 0};
EXPECT_FALSE(GetFallbackFont(base_font, kDefaultApplicationLocale,
base::StringPiece16(kTest1, base::size(kTest1)),
&fallback_font));
// No ending NUL character.
- const wchar_t kTest2[] = {0x0540, 0x0541};
+ const base::char16 kTest2[] = {0x0540, 0x0541};
EXPECT_TRUE(GetFallbackFont(base_font, kDefaultApplicationLocale,
base::StringPiece16(kTest2, base::size(kTest2)),
&fallback_font));
// NUL only characters.
- const wchar_t kTest3[] = {0, 0, 0};
+ const base::char16 kTest3[] = {0, 0, 0};
EXPECT_FALSE(GetFallbackFont(base_font, kDefaultApplicationLocale,
base::StringPiece16(kTest3, base::size(kTest3)),
&fallback_font));
@@ -115,7 +115,7 @@ TEST_F(FontFallbackWinTest, CJKLocaleFallback) {
// common feature of written Chinese (hanzi), Japanese (kanji), and Korean
// (hanja). The same text will be rendered using a different font based on
// locale.
- const wchar_t kCJKTest[] = L"\u8AA4\u904E\u9AA8";
+ const base::char16 kCJKTest[] = STRING16_LITERAL("\u8AA4\u904E\u9AA8");
Font base_font;
Font fallback_font;
diff --git a/chromium/ui/gfx/font_render_params_linux.cc b/chromium/ui/gfx/font_render_params_linux.cc
index 838626ea9c9..3ab8b2ed3ee 100644
--- a/chromium/ui/gfx/font_render_params_linux.cc
+++ b/chromium/ui/gfx/font_render_params_linux.cc
@@ -21,6 +21,7 @@
#include "base/synchronization/lock.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/font.h"
#include "ui/gfx/linux/fontconfig_util.h"
#include "ui/gfx/skia_font_delegate.h"
@@ -227,7 +228,7 @@ FontRenderParams GetFontRenderParams(const FontRenderParamsQuery& query,
params.subpixel_positioning = false;
} else if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableFontSubpixelPositioning)) {
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
params.subpixel_positioning = actual_query.device_scale_factor > 1.0f;
#else
// We want to enable subpixel positioning for fractional dsf.
@@ -235,7 +236,7 @@ FontRenderParams GetFontRenderParams(const FontRenderParamsQuery& query,
std::abs(std::round(actual_query.device_scale_factor) -
actual_query.device_scale_factor) >
std::numeric_limits<float>::epsilon();
-#endif // !defined(OS_CHROMEOS)
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
// To enable subpixel positioning, we need to disable hinting.
if (params.subpixel_positioning)
diff --git a/chromium/ui/gfx/font_render_params_linux_unittest.cc b/chromium/ui/gfx/font_render_params_linux_unittest.cc
index b3236a323cc..770708d23d0 100644
--- a/chromium/ui/gfx/font_render_params_linux_unittest.cc
+++ b/chromium/ui/gfx/font_render_params_linux_unittest.cc
@@ -14,6 +14,7 @@
#include "base/strings/stringprintf.h"
#include "base/test/fontconfig_util_linux.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font.h"
#include "ui/gfx/linux/fontconfig_util.h"
@@ -363,12 +364,12 @@ TEST_F(FontRenderParamsTest, ForceSubpixelPositioning) {
FontRenderParams params =
GetFontRenderParams(FontRenderParamsQuery(), nullptr);
EXPECT_TRUE(params.antialiasing);
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
EXPECT_TRUE(params.subpixel_positioning);
#else
// Integral scale factor does not require subpixel positioning.
EXPECT_FALSE(params.subpixel_positioning);
-#endif // !defined(OS_CHROMEOS)
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
SetFontRenderParamsDeviceScaleFactor(1.0f);
}
}
diff --git a/chromium/ui/gfx/geometry/BUILD.gn b/chromium/ui/gfx/geometry/BUILD.gn
index f4e4a7d8859..3f83f70106d 100644
--- a/chromium/ui/gfx/geometry/BUILD.gn
+++ b/chromium/ui/gfx/geometry/BUILD.gn
@@ -41,6 +41,8 @@ component("geometry") {
"rect_conversions.h",
"rect_f.cc",
"rect_f.h",
+ "resize_utils.cc",
+ "resize_utils.h",
"rounded_corners_f.cc",
"rounded_corners_f.h",
"scroll_offset.cc",
diff --git a/chromium/ui/gfx/geometry/axis_transform2d.h b/chromium/ui/gfx/geometry/axis_transform2d.h
index 6aec0e5acbf..57b45ac9d22 100644
--- a/chromium/ui/gfx/geometry/axis_transform2d.h
+++ b/chromium/ui/gfx/geometry/axis_transform2d.h
@@ -84,21 +84,21 @@ class GEOMETRY_EXPORT AxisTransform2d {
Vector2dF translation_;
};
-static inline AxisTransform2d PreScaleAxisTransform2d(const AxisTransform2d& t,
- float scale) {
+inline AxisTransform2d PreScaleAxisTransform2d(const AxisTransform2d& t,
+ float scale) {
AxisTransform2d result(t);
result.PreScale(scale);
return result;
}
-static inline AxisTransform2d PostScaleAxisTransform2d(const AxisTransform2d& t,
- float scale) {
+inline AxisTransform2d PostScaleAxisTransform2d(const AxisTransform2d& t,
+ float scale) {
AxisTransform2d result(t);
result.PostScale(scale);
return result;
}
-static inline AxisTransform2d PreTranslateAxisTransform2d(
+inline AxisTransform2d PreTranslateAxisTransform2d(
const AxisTransform2d& t,
const Vector2dF& translation) {
AxisTransform2d result(t);
@@ -106,7 +106,7 @@ static inline AxisTransform2d PreTranslateAxisTransform2d(
return result;
}
-static inline AxisTransform2d PostTranslateAxisTransform2d(
+inline AxisTransform2d PostTranslateAxisTransform2d(
const AxisTransform2d& t,
const Vector2dF& translation) {
AxisTransform2d result(t);
@@ -114,15 +114,14 @@ static inline AxisTransform2d PostTranslateAxisTransform2d(
return result;
}
-static inline AxisTransform2d ConcatAxisTransform2d(
- const AxisTransform2d& post,
- const AxisTransform2d& pre) {
+inline AxisTransform2d ConcatAxisTransform2d(const AxisTransform2d& post,
+ const AxisTransform2d& pre) {
AxisTransform2d result(post);
result.PreConcat(pre);
return result;
}
-static inline AxisTransform2d InvertAxisTransform2d(const AxisTransform2d& t) {
+inline AxisTransform2d InvertAxisTransform2d(const AxisTransform2d& t) {
AxisTransform2d result = t;
result.Invert();
return result;
diff --git a/chromium/ui/gfx/geometry/mojom/geometry.mojom b/chromium/ui/gfx/geometry/mojom/geometry.mojom
index 82218aef7f6..7ed95f64baa 100644
--- a/chromium/ui/gfx/geometry/mojom/geometry.mojom
+++ b/chromium/ui/gfx/geometry/mojom/geometry.mojom
@@ -22,6 +22,7 @@ struct Point3F {
float z;
};
+[Stable]
struct Size {
int32 width;
int32 height;
diff --git a/chromium/ui/gfx/geometry/resize_utils.cc b/chromium/ui/gfx/geometry/resize_utils.cc
new file mode 100644
index 00000000000..33de68bf659
--- /dev/null
+++ b/chromium/ui/gfx/geometry/resize_utils.cc
@@ -0,0 +1,112 @@
+// Copyright 2020 The Chromium 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/geometry/resize_utils.h"
+
+#include "base/check_op.h"
+#include "base/numerics/ranges.h"
+#include "base/numerics/safe_conversions.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace gfx {
+namespace {
+
+// This function decides whether SizeRectToAspectRatio() will adjust the height
+// to match the specified width (resizing horizontally) or vice versa (resizing
+// vertically).
+bool IsResizingHorizontally(ResizeEdge resize_edge) {
+ switch (resize_edge) {
+ case ResizeEdge::kLeft:
+ case ResizeEdge::kRight:
+ case ResizeEdge::kTopLeft:
+ case ResizeEdge::kBottomLeft:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace
+
+void SizeRectToAspectRatio(ResizeEdge resize_edge,
+ float aspect_ratio,
+ const Size& min_window_size,
+ const Size& max_window_size,
+ Rect* rect) {
+ DCHECK_GT(aspect_ratio, 0.0f);
+ DCHECK_GE(max_window_size.width(), min_window_size.width());
+ DCHECK_GE(max_window_size.height(), min_window_size.height());
+ DCHECK(rect->Contains(Rect(rect->origin(), min_window_size)))
+ << rect->ToString() << " is smaller than the minimum size "
+ << min_window_size.ToString();
+ DCHECK(Rect(rect->origin(), max_window_size).Contains(*rect))
+ << rect->ToString() << " is larger than the maximum size "
+ << max_window_size.ToString();
+
+ Size new_size = rect->size();
+ if (IsResizingHorizontally(resize_edge)) {
+ new_size.set_height(base::ClampRound(new_size.width() / aspect_ratio));
+ if (min_window_size.height() > new_size.height() ||
+ new_size.height() > max_window_size.height()) {
+ new_size.set_height(base::ClampToRange(new_size.height(),
+ min_window_size.height(),
+ max_window_size.height()));
+ new_size.set_width(base::ClampRound(new_size.height() * aspect_ratio));
+ }
+ } else {
+ new_size.set_width(base::ClampRound(new_size.height() * aspect_ratio));
+ if (min_window_size.width() > new_size.width() ||
+ new_size.width() > max_window_size.width()) {
+ new_size.set_width(base::ClampToRange(
+ new_size.width(), min_window_size.width(), max_window_size.width()));
+ new_size.set_height(base::ClampRound(new_size.width() / aspect_ratio));
+ }
+ }
+
+ // The dimensions might still be outside of the allowed ranges at this point.
+ // This happens when the aspect ratio makes it impossible to fit |rect|
+ // within the size limits without letter-/pillarboxing.
+ new_size.SetToMin(max_window_size);
+ new_size.SetToMax(min_window_size);
+
+ // |rect| bounds before sizing to aspect ratio.
+ int left = rect->x();
+ int top = rect->y();
+ int right = rect->right();
+ int bottom = rect->bottom();
+
+ switch (resize_edge) {
+ case ResizeEdge::kRight:
+ case ResizeEdge::kBottom:
+ right = new_size.width() + left;
+ bottom = top + new_size.height();
+ break;
+ case ResizeEdge::kTop:
+ right = new_size.width() + left;
+ top = bottom - new_size.height();
+ break;
+ case ResizeEdge::kLeft:
+ case ResizeEdge::kTopLeft:
+ left = right - new_size.width();
+ top = bottom - new_size.height();
+ break;
+ case ResizeEdge::kTopRight:
+ right = left + new_size.width();
+ top = bottom - new_size.height();
+ break;
+ case ResizeEdge::kBottomLeft:
+ left = right - new_size.width();
+ bottom = top + new_size.height();
+ break;
+ case ResizeEdge::kBottomRight:
+ right = left + new_size.width();
+ bottom = top + new_size.height();
+ break;
+ }
+
+ rect->SetByBounds(left, top, right, bottom);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/resize_utils.h b/chromium/ui/gfx/geometry/resize_utils.h
new file mode 100644
index 00000000000..318a31bdb01
--- /dev/null
+++ b/chromium/ui/gfx/geometry/resize_utils.h
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium 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_GEOMETRY_RESIZE_UTILS_H_
+#define UI_GFX_GEOMETRY_RESIZE_UTILS_H_
+
+#include "ui/gfx/geometry/geometry_export.h"
+
+namespace gfx {
+
+class Rect;
+class Size;
+
+enum class ResizeEdge {
+ kBottom,
+ kBottomLeft,
+ kBottomRight,
+ kLeft,
+ kRight,
+ kTop,
+ kTopLeft,
+ kTopRight
+};
+
+// Updates |rect| to adhere to the |aspect_ratio| of the window, if it has
+// been set. |resize_edge| refers to the edge of the window being sized.
+// |min_window_size| and |max_window_size| are expected to adhere to the
+// given aspect ratio.
+// |aspect_ratio| must be valid and is found using width / height.
+// TODO(apacible): |max_window_size| is expected to be non-empty. Handle
+// unconstrained max sizes and sizing when windows are maximized.
+void GEOMETRY_EXPORT SizeRectToAspectRatio(ResizeEdge resize_edge,
+ float aspect_ratio,
+ const Size& min_window_size,
+ const Size& max_window_size,
+ Rect* rect);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_RESIZE_UTILS_H_
diff --git a/chromium/ui/gfx/geometry/resize_utils_unittest.cc b/chromium/ui/gfx/geometry/resize_utils_unittest.cc
new file mode 100644
index 00000000000..bf1e90bcc2c
--- /dev/null
+++ b/chromium/ui/gfx/geometry/resize_utils_unittest.cc
@@ -0,0 +1,181 @@
+// Copyright 2020 The Chromium 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/geometry/resize_utils.h"
+
+#include <string>
+
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace gfx {
+namespace {
+
+// Aspect ratio is defined by width / height.
+constexpr float kAspectRatioSquare = 1.0f;
+constexpr float kAspectRatioHorizontal = 2.0f;
+constexpr float kAspectRatioVertical = 0.5f;
+
+constexpr Size kMinSizeHorizontal(20, 10);
+constexpr Size kMaxSizeHorizontal(50, 25);
+
+constexpr Size kMinSizeVertical(10, 20);
+constexpr Size kMaxSizeVertical(25, 50);
+
+std::string HitTestToString(ResizeEdge resize_edge) {
+ switch (resize_edge) {
+ case ResizeEdge::kTop:
+ return "top";
+ case ResizeEdge::kTopRight:
+ return "top-righ";
+ case ResizeEdge::kRight:
+ return "right";
+ case ResizeEdge::kBottomRight:
+ return "bottom-right";
+ case ResizeEdge::kBottom:
+ return "bottom";
+ case ResizeEdge::kBottomLeft:
+ return "bottom-left";
+ case ResizeEdge::kLeft:
+ return "left";
+ case ResizeEdge::kTopLeft:
+ return "top-left";
+ }
+}
+
+} // namespace
+
+struct SizingParams {
+ ResizeEdge resize_edge{};
+ float aspect_ratio = 0.0f;
+ Size min_size;
+ Size max_size;
+ Rect input_rect;
+ Rect expected_output_rect;
+
+ std::string ToString() const {
+ return base::StrCat({HitTestToString(resize_edge),
+ " ratio=", base::NumberToString(aspect_ratio), " [",
+ min_size.ToString(), "..", max_size.ToString(), "] ",
+ input_rect.ToString(), " -> ",
+ expected_output_rect.ToString()});
+ }
+};
+
+using ResizeUtilsTest = testing::TestWithParam<SizingParams>;
+
+TEST_P(ResizeUtilsTest, SizeRectToAspectRatio) {
+ Rect rect = GetParam().input_rect;
+ SizeRectToAspectRatio(GetParam().resize_edge, GetParam().aspect_ratio,
+ GetParam().min_size, GetParam().max_size, &rect);
+ EXPECT_EQ(rect, GetParam().expected_output_rect) << GetParam().ToString();
+}
+
+const SizingParams kSizeRectToSquareAspectRatioTestCases[] = {
+ // Dragging the top resizer up.
+ {ResizeEdge::kTop, kAspectRatioSquare, kMinSizeHorizontal,
+ kMaxSizeHorizontal, Rect(100, 98, 22, 24), Rect(100, 98, 24, 24)},
+
+ // Dragging the bottom resizer down.
+ {ResizeEdge::kBottom, kAspectRatioSquare, kMinSizeHorizontal,
+ kMaxSizeHorizontal, Rect(100, 100, 22, 24), Rect(100, 100, 24, 24)},
+
+ // Dragging the left resizer right.
+ {ResizeEdge::kLeft, kAspectRatioSquare, kMinSizeHorizontal,
+ kMaxSizeHorizontal, Rect(102, 100, 22, 24), Rect(102, 102, 22, 22)},
+
+ // Dragging the right resizer left.
+ {ResizeEdge::kRight, kAspectRatioSquare, kMinSizeHorizontal,
+ kMaxSizeHorizontal, Rect(100, 100, 22, 24), Rect(100, 100, 22, 22)},
+
+ // Dragging the top-left resizer right.
+ {ResizeEdge::kTopLeft, kAspectRatioSquare, kMinSizeHorizontal,
+ kMaxSizeHorizontal, Rect(102, 100, 22, 24), Rect(102, 102, 22, 22)},
+
+ // Dragging the top-right resizer down.
+ {ResizeEdge::kTopRight, kAspectRatioSquare, kMinSizeHorizontal,
+ kMaxSizeHorizontal, Rect(100, 102, 24, 22), Rect(100, 102, 22, 22)},
+
+ // Dragging the bottom-left resizer right.
+ {ResizeEdge::kBottomLeft, kAspectRatioSquare, kMinSizeHorizontal,
+ kMaxSizeHorizontal, Rect(100, 102, 22, 24), Rect(100, 102, 22, 22)},
+
+ // Dragging the bottom-right resizer up.
+ {ResizeEdge::kBottomRight, kAspectRatioSquare, kMinSizeHorizontal,
+ kMaxSizeHorizontal, Rect(100, 100, 24, 22), Rect(100, 100, 22, 22)},
+
+ // Dragging the bottom-right resizer left.
+ // Rect already as small as `kMinSizeHorizontal` allows.
+ {ResizeEdge::kBottomRight, kAspectRatioSquare, kMinSizeHorizontal,
+ kMaxSizeHorizontal,
+ Rect(100, 100, kMinSizeHorizontal.width(), kMinSizeHorizontal.width()),
+ Rect(100, 100, kMinSizeHorizontal.width(), kMinSizeHorizontal.width())},
+
+ // Dragging the top-left resizer left.
+ // Rect already as large as `kMaxSizeHorizontal` allows.
+ {ResizeEdge::kTopLeft, kAspectRatioSquare, kMinSizeHorizontal,
+ kMaxSizeHorizontal,
+ Rect(100, 100, kMaxSizeHorizontal.height(), kMaxSizeHorizontal.height()),
+ Rect(100, 100, kMaxSizeHorizontal.height(), kMaxSizeHorizontal.height())},
+};
+
+const SizingParams kSizeRectToHorizontalAspectRatioTestCases[] = {
+ // Dragging the top resizer down.
+ {ResizeEdge::kTop, kAspectRatioHorizontal, kMinSizeHorizontal,
+ kMaxSizeHorizontal, Rect(100, 102, 48, 22), Rect(100, 102, 44, 22)},
+
+ // Dragging the left resizer left.
+ {ResizeEdge::kLeft, kAspectRatioHorizontal, kMinSizeHorizontal,
+ kMaxSizeHorizontal, Rect(96, 100, 48, 22), Rect(96, 98, 48, 24)},
+
+ // Rect already as small as `kMinSizeHorizontal` allows.
+ {ResizeEdge::kTop, kAspectRatioHorizontal, kMinSizeHorizontal,
+ kMaxSizeHorizontal,
+ Rect(100, 100, kMinSizeHorizontal.width(), kMinSizeHorizontal.height()),
+ Rect(100, 100, kMinSizeHorizontal.width(), kMinSizeHorizontal.height())},
+
+ // Rect already as large as `kMaxSizeHorizontal` allows.
+ {ResizeEdge::kTop, kAspectRatioHorizontal, kMinSizeHorizontal,
+ kMaxSizeHorizontal,
+ Rect(100, 100, kMaxSizeHorizontal.width(), kMaxSizeHorizontal.height()),
+ Rect(100, 100, kMaxSizeHorizontal.width(), kMaxSizeHorizontal.height())},
+};
+
+const SizingParams kSizeRectToVerticalAspectRatioTestCases[] = {
+ // Dragging the bottom resizer up.
+ {ResizeEdge::kBottom, kAspectRatioVertical, kMinSizeVertical,
+ kMaxSizeVertical, Rect(100, 100, 24, 44), Rect(100, 100, 22, 44)},
+
+ // Dragging the right resizer right.
+ {ResizeEdge::kRight, kAspectRatioVertical, kMinSizeVertical,
+ kMaxSizeVertical, Rect(100, 100, 24, 44), Rect(100, 100, 24, 48)},
+
+ // Rect already as small as `kMinSizeVertical` allows.
+ {ResizeEdge::kTop, kAspectRatioVertical, kMinSizeVertical, kMaxSizeVertical,
+ Rect(100, 100, kMinSizeVertical.width(), kMinSizeVertical.height()),
+ Rect(100, 100, kMinSizeVertical.width(), kMinSizeVertical.height())},
+
+ // Rect already as large as `kMaxSizeVertical` allows.
+ {ResizeEdge::kTop, kAspectRatioVertical, kMinSizeVertical, kMaxSizeVertical,
+ Rect(100, 100, kMaxSizeVertical.width(), kMaxSizeVertical.height()),
+ Rect(100, 100, kMaxSizeVertical.width(), kMaxSizeVertical.height())},
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ Square,
+ ResizeUtilsTest,
+ testing::ValuesIn(kSizeRectToSquareAspectRatioTestCases));
+INSTANTIATE_TEST_SUITE_P(
+ Horizontal,
+ ResizeUtilsTest,
+ testing::ValuesIn(kSizeRectToHorizontalAspectRatioTestCases));
+INSTANTIATE_TEST_SUITE_P(
+ Vertical,
+ ResizeUtilsTest,
+ testing::ValuesIn(kSizeRectToVerticalAspectRatioTestCases));
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/gpu_extra_info.h b/chromium/ui/gfx/gpu_extra_info.h
index 90fe896677d..98234d2f2e0 100644
--- a/chromium/ui/gfx/gpu_extra_info.h
+++ b/chromium/ui/gfx/gpu_extra_info.h
@@ -11,8 +11,15 @@
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/gfx_export.h"
-#if defined(USE_OZONE) || defined(USE_X11)
-typedef unsigned long VisualID;
+#if defined(USE_OZONE)
+#include "ui/ozone/buildflags.h"
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+#define USE_OZONE_PLATFORM_X11
+#endif
+#endif
+
+#if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11)
+#include "ui/gfx/x/xproto.h"
#endif
namespace gfx {
@@ -58,9 +65,9 @@ struct GFX_EXPORT GpuExtraInfo {
// applicable.
ANGLEFeatures angle_features;
-#if defined(USE_OZONE) || defined(USE_X11)
- VisualID system_visual = 0;
- VisualID rgba_visual = 0;
+#if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11)
+ x11::VisualId system_visual{};
+ x11::VisualId rgba_visual{};
std::vector<gfx::BufferUsageAndFormat> gpu_memory_buffer_support_x11;
#endif
diff --git a/chromium/ui/gfx/gpu_memory_buffer.cc b/chromium/ui/gfx/gpu_memory_buffer.cc
index 5d37183d17e..44b2667960d 100644
--- a/chromium/ui/gfx/gpu_memory_buffer.cc
+++ b/chromium/ui/gfx/gpu_memory_buffer.cc
@@ -4,10 +4,29 @@
#include "ui/gfx/gpu_memory_buffer.h"
+#include "base/logging.h"
#include "ui/gfx/generic_shared_memory_id.h"
+#if defined(OS_WIN)
+#include <windows.h>
+#include "base/win/scoped_handle.h"
+#endif
+
namespace gfx {
+#if defined(OS_WIN)
+namespace {
+base::win::ScopedHandle CloneDXGIHandle(HANDLE handle) {
+ HANDLE target_handle = nullptr;
+ if (!::DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
+ &target_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+ DVLOG(1) << "Error duplicating GMB DXGI handle. error=" << GetLastError();
+ }
+ return base::win::ScopedHandle(target_handle);
+}
+} // namespace
+#endif
+
GpuMemoryBufferHandle::GpuMemoryBufferHandle() = default;
#if defined(OS_ANDROID)
@@ -39,13 +58,15 @@ GpuMemoryBufferHandle GpuMemoryBufferHandle::Clone() const {
#elif defined(OS_MAC)
handle.io_surface = io_surface;
#elif defined(OS_WIN)
- NOTIMPLEMENTED();
+ handle.dxgi_handle = CloneDXGIHandle(dxgi_handle.Get());
#elif defined(OS_ANDROID)
NOTIMPLEMENTED();
#endif
return handle;
}
-void GpuMemoryBuffer::SetColorSpace(const gfx::ColorSpace& color_space) {}
+void GpuMemoryBuffer::SetColorSpace(const ColorSpace& color_space) {}
+
+void GpuMemoryBuffer::SetHDRMetadata(const HDRMetadata& hdr_metadata) {}
} // namespace gfx
diff --git a/chromium/ui/gfx/gpu_memory_buffer.h b/chromium/ui/gfx/gpu_memory_buffer.h
index 7a33fcbfaa6..c3a1f813ca3 100644
--- a/chromium/ui/gfx/gpu_memory_buffer.h
+++ b/chromium/ui/gfx/gpu_memory_buffer.h
@@ -14,6 +14,7 @@
#include "ui/gfx/generic_shared_memory_id.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/hdr_metadata.h"
#if defined(USE_OZONE) || defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "ui/gfx/native_pixmap_handle.h"
@@ -72,7 +73,7 @@ struct GFX_EXPORT GpuMemoryBufferHandle {
#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
NativePixmapHandle native_pixmap_handle;
#elif defined(OS_MAC)
- gfx::ScopedIOSurface io_surface;
+ ScopedIOSurface io_surface;
#elif defined(OS_WIN)
base::win::ScopedHandle dxgi_handle;
#elif defined(OS_ANDROID)
@@ -113,7 +114,11 @@ class GFX_EXPORT GpuMemoryBuffer {
// Set the color space in which this buffer should be interpreted when used
// as an overlay. Note that this will not impact texturing from the buffer.
- virtual void SetColorSpace(const gfx::ColorSpace& color_space);
+ virtual void SetColorSpace(const ColorSpace& color_space);
+
+ // Set the HDR metadata for use when this buffer is used as an overlay. Note
+ // that this will not impact texturing from the buffer.
+ virtual void SetHDRMetadata(const HDRMetadata& hdr_metadata);
// Returns a unique identifier associated with buffer.
virtual GpuMemoryBufferId GetId() const = 0;
diff --git a/chromium/ui/gfx/icon_util.cc b/chromium/ui/gfx/icon_util.cc
index 504d2093f1f..b9702dde23c 100644
--- a/chromium/ui/gfx/icon_util.cc
+++ b/chromium/ui/gfx/icon_util.cc
@@ -98,7 +98,7 @@ bool BuildResizedImageFamily(const gfx::ImageFamily& image_family,
// |bitmaps| must be an empty vector, and not NULL.
// Returns true on success, false on failure. This fails if any image in
// |image_family| is not a 32-bit ARGB image, or is otherwise invalid.
-bool ConvertImageFamilyToBitmaps(
+void ConvertImageFamilyToBitmaps(
const gfx::ImageFamily& image_family,
std::vector<SkBitmap>* bitmaps,
scoped_refptr<base::RefCountedMemory>* png_bytes) {
@@ -117,8 +117,7 @@ bool ConvertImageFamilyToBitmaps(
SkBitmap bitmap = image.AsBitmap();
CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
- if (bitmap.isNull())
- return false;
+ CHECK(!bitmap.isNull());
// Special case: Icons exactly 256x256 are stored in PNG format.
if (image.Width() == IconUtil::kLargeIconSize &&
@@ -128,8 +127,6 @@ bool ConvertImageFamilyToBitmaps(
bitmaps->push_back(bitmap);
}
}
-
- return true;
}
} // namespace
@@ -461,8 +458,7 @@ bool IconUtil::CreateIconFileFromImageFamily(
std::vector<SkBitmap> bitmaps;
scoped_refptr<base::RefCountedMemory> png_bytes;
- if (!ConvertImageFamilyToBitmaps(resized_image_family, &bitmaps, &png_bytes))
- return false;
+ ConvertImageFamilyToBitmaps(resized_image_family, &bitmaps, &png_bytes);
// Guaranteed true because BuildResizedImageFamily will provide at least one
// image < 256x256.
diff --git a/chromium/ui/gfx/icon_util_unittest.cc b/chromium/ui/gfx/icon_util_unittest.cc
index 0130a4560ab..21c228ed9fa 100644
--- a/chromium/ui/gfx/icon_util_unittest.cc
+++ b/chromium/ui/gfx/icon_util_unittest.cc
@@ -207,14 +207,8 @@ TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
base::FilePath invalid_icon_filename =
temp_directory_.GetPath().AppendASCII("<>?.ico");
- // Null bitmap.
- SkBitmap bitmap;
- image_family.Add(gfx::Image::CreateFrom1xBitmap(bitmap));
- EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
- valid_icon_filename));
- EXPECT_FALSE(base::PathExists(valid_icon_filename));
-
// Invalid file name.
+ SkBitmap bitmap;
image_family.clear();
bitmap.allocN32Pixels(1, 1);
image_family.Add(gfx::Image::CreateFrom1xBitmap(bitmap));
diff --git a/chromium/ui/gfx/image/image_skia.cc b/chromium/ui/gfx/image/image_skia.cc
index 06ad22fc1d7..31dfdf5d2f1 100644
--- a/chromium/ui/gfx/image/image_skia.cc
+++ b/chromium/ui/gfx/image/image_skia.cc
@@ -75,10 +75,13 @@ ImageSkiaRep ScaleImageSkiaRep(const ImageSkiaRep& rep, float target_scale) {
// A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a
// refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's
-// information. Using a |base::SequenceChecker| on a
-// |base::RefCountedThreadSafe| subclass may sound strange but is necessary to
-// turn the 'thread-non-safe modifiable ImageSkiaStorage' into the 'thread-safe
-// read-only ImageSkiaStorage'.
+// information.
+// The ImageSkia, and this class, are designed to be thread-safe in their const
+// methods, but also are bound to a single sequence for mutating methods.
+// NOTE: The FindRepresentation() method const and thread-safe *iff* it is
+// called with `fetch_new_image` set to true. Otherwise it may mutate the
+// class, which is not thread-safe. Internally, mutation is bound to a single
+// sequence with a `base::SequenceChecker`.
class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage> {
public:
ImageSkiaStorage(std::unique_ptr<ImageSkiaSource> source,
@@ -122,7 +125,7 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage> {
// one and rescale the image.
// Right now only Windows uses 2 and other platforms use 1 by default.
// TODO(mukai, oshima): abandon 1 code path and use 2 for every platforms.
- std::vector<ImageSkiaRep>::iterator FindRepresentation(
+ std::vector<ImageSkiaRep>::const_iterator FindRepresentation(
float scale,
bool fetch_new_image) const;
@@ -131,9 +134,12 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage> {
virtual ~ImageSkiaStorage();
- // Vector of bitmaps and their associated scale.
+ // Each entry in here has a different scale and is returned when looking for
+ // an ImageSkiaRep of that scale.
std::vector<gfx::ImageSkiaRep> image_reps_;
+ // If no ImageSkiaRep exists in `image_reps_` for a given scale, the `source_`
+ // is queried to produce an ImageSkiaRep at that scale.
std::unique_ptr<ImageSkiaSource> source_;
// Size of the image in DIP.
@@ -141,7 +147,9 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage> {
bool read_only_;
- base::SequenceChecker sequence_checker_;
+ // This isn't using SEQUENCE_CHECKER() macros because we use the sequence
+ // checker outside of DCHECKs to make branching decisions.
+ base::SequenceChecker sequence_checker_; // nocheck
DISALLOW_COPY_AND_ASSIGN(ImageSkiaStorage);
};
@@ -203,16 +211,13 @@ bool ImageSkiaStorage::HasRepresentationAtAllScales() const {
return source_ && source_->HasRepresentationAtAllScales();
}
-std::vector<ImageSkiaRep>::iterator ImageSkiaStorage::FindRepresentation(
+std::vector<ImageSkiaRep>::const_iterator ImageSkiaStorage::FindRepresentation(
float scale,
bool fetch_new_image) const {
- ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this);
-
- auto closest_iter = non_const->image_reps().end();
- auto exact_iter = non_const->image_reps().end();
+ auto closest_iter = image_reps_.end();
+ auto exact_iter = image_reps_.end();
float smallest_diff = std::numeric_limits<float>::max();
- for (auto it = non_const->image_reps().begin(); it < image_reps_.end();
- ++it) {
+ for (auto it = image_reps_.begin(); it < image_reps_.end(); ++it) {
if (it->scale() == scale) {
// found exact match
fetch_new_image = false;
@@ -228,10 +233,15 @@ std::vector<ImageSkiaRep>::iterator ImageSkiaStorage::FindRepresentation(
}
}
- if (fetch_new_image && source_.get()) {
+ if (fetch_new_image && source_) {
DCHECK(sequence_checker_.CalledOnValidSequence())
<< "An ImageSkia with the source must be accessed by the same "
"sequence.";
+ // This method is const and thread-safe, unless `fetch_new_image` is true,
+ // in which case the method is no longer considered const and we ensure
+ // that it is used in this way on a single sequence at a time with the above
+ // `sequence_checker_`.
+ auto* mutable_this = const_cast<ImageSkiaStorage*>(this);
ImageSkiaRep image;
float resource_scale = scale;
@@ -256,17 +266,12 @@ std::vector<ImageSkiaRep>::iterator ImageSkiaStorage::FindRepresentation(
[&image](const ImageSkiaRep& rep) {
return rep.scale() == image.scale();
}) == image_reps_.end()) {
- non_const->image_reps().push_back(image);
- }
-
- // If the result image's scale isn't same as the expected scale, create a
- // null ImageSkiaRep with the |scale| so that the next lookup will fall back
- // to the closest scale.
- if (image.is_null() || image.scale() != scale) {
- non_const->image_reps().push_back(ImageSkiaRep(SkBitmap(), scale));
+ mutable_this->image_reps_.push_back(image);
}
- // image_reps_ must have the exact much now, so find again.
+ // image_reps_ should have the exact much now, or we will fallback
+ // to the new closest value. We pass false to prevent the generation step
+ // from running again and repeating the recursion.
return FindRepresentation(scale, false);
}
return exact_iter != image_reps_.end() ? exact_iter : closest_iter;
@@ -299,6 +304,7 @@ ImageSkia::ImageSkia(std::unique_ptr<ImageSkiaSource> source, float scale)
}
ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) {
+ DCHECK(!image_rep.is_null());
Init(image_rep);
// No other thread has reference to this, so it's safe to detach the sequence.
DetachStorageFromSequence();
@@ -335,7 +341,18 @@ float ImageSkia::GetMaxSupportedScale() {
}
// static
+ImageSkia ImageSkia::CreateFromBitmap(const SkBitmap& bitmap, float scale) {
+ // An uninitialized/empty/null bitmap makes a null ImageSkia.
+ if (bitmap.drawsNothing())
+ return ImageSkia();
+ return ImageSkia(ImageSkiaRep(bitmap, scale));
+}
+
+// static
ImageSkia ImageSkia::CreateFrom1xBitmap(const SkBitmap& bitmap) {
+ // An uninitialized/empty/null bitmap makes a null ImageSkia.
+ if (bitmap.drawsNothing())
+ return ImageSkia();
return ImageSkia(ImageSkiaRep(bitmap, 0.0f));
}
@@ -367,7 +384,6 @@ const void* ImageSkia::GetBackingObject() const {
void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) {
DCHECK(!image_rep.is_null());
-
// TODO(oshima): This method should be called |SetRepresentation|
// and replace the existing rep if there is already one with the
// same scale so that we can guarantee that a ImageSkia instance contains only
@@ -496,10 +512,7 @@ void ImageSkia::RemoveUnsupportedRepresentationsForScale(float scale) {
}
void ImageSkia::Init(const ImageSkiaRep& image_rep) {
- if (image_rep.GetBitmap().drawsNothing()) {
- storage_.reset();
- return;
- }
+ DCHECK(!image_rep.is_null());
storage_ = new internal::ImageSkiaStorage(
NULL, gfx::Size(image_rep.GetWidth(), image_rep.GetHeight()));
storage_->image_reps().push_back(image_rep);
diff --git a/chromium/ui/gfx/image/image_skia.h b/chromium/ui/gfx/image/image_skia.h
index 94e36e8ba56..156c8283cba 100644
--- a/chromium/ui/gfx/image/image_skia.h
+++ b/chromium/ui/gfx/image/image_skia.h
@@ -73,9 +73,21 @@ class GFX_EXPORT ImageSkia {
// Returns the maximum scale supported by this platform.
static float GetMaxSupportedScale();
- // Creates an image from the passed in bitmap.
- // DIP width and height are based on scale factor of 1x.
- // Adds ref to passed in bitmap.
+ // Creates an image from the passed in bitmap, which is designed for display
+ // at the device scale factor given in `scale`. The DIP width and height will
+ // be based on that scale factor. A scale factor of 0 is equivalent to
+ // calling CreateFrom1xBitmap(), which indicates the bitmap is not scaled.
+ // The `bitmap`, if present, will be made immutable. If the `bitmap` is
+ // uninitialized, empty, or null then the returned ImageSkia will be
+ // default-constructed and empty.
+ // WARNING: If the device scale factory differs from the scale given here,
+ // the resulting image will be pixelated when displayed.
+ static ImageSkia CreateFromBitmap(const SkBitmap& bitmap, float scale);
+
+ // Creates an image from the passed in bitmap. The DIP width and height will
+ // be based on scale factor of 1x. The `bitmap`, if present, will be made
+ // immutable. If the bitmap is uninitialized, empty, or null then the
+ // returned ImageSkia will be default-constructed and empty.
// WARNING: The resulting image will be pixelated when painted on a high
// density display.
static ImageSkia CreateFrom1xBitmap(const SkBitmap& bitmap);
diff --git a/chromium/ui/gfx/image/image_skia_operations.cc b/chromium/ui/gfx/image/image_skia_operations.cc
index 60a3eba52f2..f62434cb1a4 100644
--- a/chromium/ui/gfx/image/image_skia_operations.cc
+++ b/chromium/ui/gfx/image/image_skia_operations.cc
@@ -69,7 +69,12 @@ class BinaryImageSource : public gfx::ImageSkiaSource {
// gfx::ImageSkiaSource overrides:
ImageSkiaRep GetImageForScale(float scale) override {
ImageSkiaRep first_rep = first_.GetRepresentation(scale);
+ if (first_rep.is_null())
+ return first_rep;
ImageSkiaRep second_rep = second_.GetRepresentation(scale);
+ if (second_rep.is_null())
+ return second_rep;
+
if (first_rep.pixel_size() != second_rep.pixel_size()) {
DCHECK_NE(first_rep.scale(), second_rep.scale());
if (first_rep.scale() == second_rep.scale()) {
@@ -167,6 +172,9 @@ class TransparentImageSource : public gfx::ImageSkiaSource {
// gfx::ImageSkiaSource overrides:
ImageSkiaRep GetImageForScale(float scale) override {
ImageSkiaRep image_rep = image_.GetRepresentation(scale);
+ if (image_rep.is_null())
+ return image_rep;
+
SkBitmap alpha;
alpha.allocN32Pixels(image_rep.pixel_width(),
image_rep.pixel_height());
@@ -220,6 +228,9 @@ class TiledImageSource : public gfx::ImageSkiaSource {
// gfx::ImageSkiaSource overrides:
ImageSkiaRep GetImageForScale(float scale) override {
ImageSkiaRep source_rep = source_.GetRepresentation(scale);
+ if (source_rep.is_null())
+ return source_rep;
+
gfx::Rect bounds = DIPToPixelBounds(gfx::Rect(src_x_, src_y_, dst_w_,
dst_h_), source_rep.scale());
return ImageSkiaRep(SkBitmapOperations::CreateTiledBitmap(
@@ -251,6 +262,9 @@ class HSLImageSource : public gfx::ImageSkiaSource {
// gfx::ImageSkiaSource overrides:
ImageSkiaRep GetImageForScale(float scale) override {
ImageSkiaRep image_rep = image_.GetRepresentation(scale);
+ if (image_rep.is_null())
+ return image_rep;
+
return gfx::ImageSkiaRep(SkBitmapOperations::CreateHSLShiftedBitmap(
image_rep.GetBitmap(), hsl_shift_),
image_rep.scale());
@@ -280,7 +294,12 @@ class ButtonImageSource: public gfx::ImageSkiaSource {
// gfx::ImageSkiaSource overrides:
ImageSkiaRep GetImageForScale(float scale) override {
ImageSkiaRep image_rep = image_.GetRepresentation(scale);
+ if (image_rep.is_null())
+ return image_rep;
ImageSkiaRep mask_rep = mask_.GetRepresentation(scale);
+ if (mask_rep.is_null())
+ return image_rep;
+
if (image_rep.scale() != mask_rep.scale()) {
image_rep = image_.GetRepresentation(1.0f);
mask_rep = mask_.GetRepresentation(1.0f);
@@ -314,6 +333,9 @@ class ExtractSubsetImageSource: public gfx::ImageSkiaSource {
// gfx::ImageSkiaSource overrides:
ImageSkiaRep GetImageForScale(float scale) override {
ImageSkiaRep image_rep = image_.GetRepresentation(scale);
+ if (image_rep.is_null())
+ return image_rep;
+
SkIRect subset_bounds_in_pixel = RectToSkIRect(
DIPToPixelBounds(subset_bounds_, image_rep.scale()));
SkBitmap dst;
@@ -346,6 +368,8 @@ class ResizeSource : public ImageSkiaSource {
// gfx::ImageSkiaSource overrides:
ImageSkiaRep GetImageForScale(float scale) override {
const ImageSkiaRep& image_rep = source_.GetRepresentation(scale);
+ if (image_rep.is_null())
+ return image_rep;
if (image_rep.GetWidth() == target_dip_size_.width() &&
image_rep.GetHeight() == target_dip_size_.height())
return image_rep;
@@ -354,6 +378,8 @@ class ResizeSource : public ImageSkiaSource {
const SkBitmap resized = skia::ImageOperations::Resize(
image_rep.GetBitmap(), resize_method_, target_pixel_size.width(),
target_pixel_size.height());
+ if (resized.colorType() == kUnknown_SkColorType)
+ return ImageSkiaRep();
return ImageSkiaRep(resized, scale);
}
@@ -376,6 +402,8 @@ class DropShadowSource : public ImageSkiaSource {
// gfx::ImageSkiaSource overrides:
ImageSkiaRep GetImageForScale(float scale) override {
const ImageSkiaRep& image_rep = source_.GetRepresentation(scale);
+ if (image_rep.is_null())
+ return image_rep;
ShadowValues shadows_in_pixel;
for (size_t i = 0; i < shadows_in_dip_.size(); ++i)
@@ -442,6 +470,9 @@ class RotatedSource : public ImageSkiaSource {
// gfx::ImageSkiaSource overrides:
ImageSkiaRep GetImageForScale(float scale) override {
const ImageSkiaRep& image_rep = source_.GetRepresentation(scale);
+ if (image_rep.is_null())
+ return image_rep;
+
const SkBitmap rotated_bitmap =
SkBitmapOperations::Rotate(image_rep.GetBitmap(), rotation_);
return ImageSkiaRep(rotated_bitmap, image_rep.scale());
@@ -487,6 +518,9 @@ class ColorMaskSource : public gfx::ImageSkiaSource {
// gfx::ImageSkiaSource overrides:
ImageSkiaRep GetImageForScale(float scale) override {
ImageSkiaRep image_rep = image_.GetRepresentation(scale);
+ if (image_rep.is_null())
+ return image_rep;
+
return ImageSkiaRep(
SkBitmapOperations::CreateColorMask(image_rep.GetBitmap(), color_),
image_rep.scale());
diff --git a/chromium/ui/gfx/image/image_skia_operations_unittest.cc b/chromium/ui/gfx/image/image_skia_operations_unittest.cc
new file mode 100644
index 00000000000..473e2d51168
--- /dev/null
+++ b/chromium/ui/gfx/image/image_skia_operations_unittest.cc
@@ -0,0 +1,23 @@
+// Copyright 2021 The Chromium 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/image/image_skia_operations.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace gfx {
+namespace {
+
+TEST(ImageSkiaOperationsTest, ResizeFailure) {
+ ImageSkia image(ImageSkiaRep(gfx::Size(10, 10), 1.f));
+
+ // Try to resize to empty. This isn't a valid resize and fails gracefully.
+ ImageSkia resized = ImageSkiaOperations::CreateResizedImage(
+ image, skia::ImageOperations::RESIZE_BEST, gfx::Size());
+ EXPECT_TRUE(resized.GetRepresentation(1.0f).is_null());
+}
+
+} // namespace
+} // namespace gfx
diff --git a/chromium/ui/gfx/image/image_skia_rep_default.cc b/chromium/ui/gfx/image/image_skia_rep_default.cc
index a8cbaf36e78..66c76570087 100644
--- a/chromium/ui/gfx/image/image_skia_rep_default.cc
+++ b/chromium/ui/gfx/image/image_skia_rep_default.cc
@@ -4,7 +4,7 @@
#include "ui/gfx/image/image_skia_rep_default.h"
-#include "base/check.h"
+#include "base/check_op.h"
#include "base/notreached.h"
#include "cc/paint/display_item_list.h"
#include "cc/paint/record_paint_canvas.h"
@@ -33,10 +33,8 @@ ImageSkiaRep::ImageSkiaRep(const SkBitmap& src, float scale)
pixel_size_(gfx::Size(src.width(), src.height())),
bitmap_(src),
scale_(scale) {
- // If the bitmap has been initialized then it must be in N32 format.
- if (!(bitmap_.isNull() && bitmap_.colorType() == kUnknown_SkColorType &&
- bitmap_.alphaType() == kUnknown_SkAlphaType))
- CHECK_EQ(bitmap_.colorType(), kN32_SkColorType);
+ CHECK_EQ(bitmap_.colorType(), kN32_SkColorType);
+ DCHECK(!bitmap_.drawsNothing());
bitmap_.setImmutable();
paint_image_ = cc::PaintImage::CreateFromBitmap(src);
}
@@ -47,7 +45,9 @@ ImageSkiaRep::ImageSkiaRep(sk_sp<cc::PaintRecord> paint_record,
: paint_record_(std::move(paint_record)),
type_(ImageRepType::kImageTypeDrawable),
pixel_size_(pixel_size),
- scale_(scale) {}
+ scale_(scale) {
+ DCHECK(!pixel_size.IsEmpty());
+}
ImageSkiaRep::ImageSkiaRep(const ImageSkiaRep& other)
: paint_image_(other.paint_image_),
@@ -84,7 +84,7 @@ sk_sp<cc::PaintRecord> ImageSkiaRep::GetPaintRecord() const {
display_item_list.get(), SkRect::MakeIWH(pixel_width(), pixel_height()));
display_item_list->StartPaint();
- record_canvas.drawImage(paint_image(), 0, 0, nullptr);
+ record_canvas.drawImage(paint_image(), 0, 0);
display_item_list->EndPaintOfPairedEnd();
display_item_list->Finalize();
diff --git a/chromium/ui/gfx/image/image_skia_rep_default.h b/chromium/ui/gfx/image/image_skia_rep_default.h
index 28064f48fbc..651ff76da31 100644
--- a/chromium/ui/gfx/image/image_skia_rep_default.h
+++ b/chromium/ui/gfx/image/image_skia_rep_default.h
@@ -28,17 +28,21 @@ class GFX_EXPORT ImageSkiaRep {
// Creates a bitmap with kARGB_8888_Config config with given |size| in DIP.
// This allocates pixels in the bitmap. It is guaranteed that the data in the
// bitmap are initialized but the actual values are undefined.
- // Specifying 0 scale means the image is for unscaled image. (unscaled()
- // returns truen, and scale() returns 1.0f;)
+ // Specifying 0 scale means the image is for unscaled image (unscaled()
+ // returns true, and scale() returns 1.0f).
ImageSkiaRep(const gfx::Size& size, float scale);
- // Creates a bitmap with given scale.
- // Adds ref to |src|.
+ // Creates an ImageSkiaRep that holds the `src` bitmap, which is created for
+ // display at the given device scale factor. Takes ownership of a reference to
+ // the SkBitmap's backing store. The `src` bitmap may not be uninitialized,
+ // null or empty; in that case the default constructor should be used
+ // instead.
ImageSkiaRep(const SkBitmap& src, float scale);
// Creates an image rep backed by a paint record of given size and scale. This
- // is used when the image representation is sourced from a drawable sunch as
- // CanvasImageSource.
+ // is used when the image representation is sourced from a drawable such as
+ // CanvasImageSource. The `size` must not be empty; in that case the default
+ // constructor should be used instead.
ImageSkiaRep(sk_sp<cc::PaintRecord> paint_record,
const gfx::Size& size,
float scale);
diff --git a/chromium/ui/gfx/image/image_skia_rep_ios.cc b/chromium/ui/gfx/image/image_skia_rep_ios.cc
index c28b5edfabb..5fb5925c47a 100644
--- a/chromium/ui/gfx/image/image_skia_rep_ios.cc
+++ b/chromium/ui/gfx/image/image_skia_rep_ios.cc
@@ -4,6 +4,7 @@
#include "ui/gfx/image/image_skia_rep_ios.h"
+#include "base/check_op.h"
#include "ui/gfx/color_palette.h"
namespace gfx {
@@ -22,6 +23,8 @@ ImageSkiaRep::ImageSkiaRep(const SkBitmap& src, float scale)
: pixel_size_(gfx::Size(src.width(), src.height())),
bitmap_(src),
scale_(scale) {
+ CHECK_EQ(src.colorType(), kN32_SkColorType);
+ DCHECK(!bitmap_.drawsNothing());
bitmap_.setImmutable();
}
diff --git a/chromium/ui/gfx/image/mojom/BUILD.gn b/chromium/ui/gfx/image/mojom/BUILD.gn
index d4536428e5a..dd07e3cbce5 100644
--- a/chromium/ui/gfx/image/mojom/BUILD.gn
+++ b/chromium/ui/gfx/image/mojom/BUILD.gn
@@ -20,7 +20,6 @@ mojom("mojom") {
{
mojom = "gfx.mojom.ImageSkiaRep"
cpp = "::gfx::ImageSkiaRep"
- nullable_is_same_type = true
},
]
traits_headers = [ "image_skia_mojom_traits.h" ]
@@ -61,6 +60,7 @@ source_set("unit_test") {
"//base",
"//base/test:test_support",
"//mojo/public/cpp/bindings",
+ "//mojo/public/cpp/test_support:test_utils",
"//testing/gtest",
"//ui/gfx:test_support",
]
diff --git a/chromium/ui/gfx/image/mojom/image.mojom b/chromium/ui/gfx/image/mojom/image.mojom
index c117cf314c5..e8752007186 100644
--- a/chromium/ui/gfx/image/mojom/image.mojom
+++ b/chromium/ui/gfx/image/mojom/image.mojom
@@ -8,8 +8,11 @@ import "skia/public/mojom/bitmap.mojom";
[Stable]
struct ImageSkiaRep {
- // Transport of the bitmap in this representation.
- skia.mojom.Bitmap bitmap;
+ // Transport of the bitmap in this representation. The type here is
+ // BitmapWithArbitraryBpp because this structure is marked Stable, however
+ // only N32-format bitmaps are allowed, similar to the skia.mojom.BitmapN32
+ // type.
+ skia.mojom.BitmapWithArbitraryBpp bitmap;
// Corresponding scale of the bitmap or 0 if unscaled.
float scale;
diff --git a/chromium/ui/gfx/image/mojom/image_skia_mojom_traits.cc b/chromium/ui/gfx/image/mojom/image_skia_mojom_traits.cc
index c45c063870b..cda3a626698 100644
--- a/chromium/ui/gfx/image/mojom/image_skia_mojom_traits.cc
+++ b/chromium/ui/gfx/image/mojom/image_skia_mojom_traits.cc
@@ -11,11 +11,20 @@
namespace mojo {
// static
+SkBitmap
+StructTraits<gfx::mojom::ImageSkiaRepDataView, gfx::ImageSkiaRep>::bitmap(
+ const gfx::ImageSkiaRep& input) {
+ SkBitmap bitmap = input.GetBitmap();
+ DCHECK(!bitmap.drawsNothing());
+ CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
+ return bitmap;
+}
+
+// static
float StructTraits<gfx::mojom::ImageSkiaRepDataView, gfx::ImageSkiaRep>::scale(
const gfx::ImageSkiaRep& input) {
const float scale = input.unscaled() ? 0.0f : input.scale();
DCHECK_GE(scale, 0.0f);
-
return scale;
}
@@ -30,6 +39,14 @@ bool StructTraits<gfx::mojom::ImageSkiaRepDataView, gfx::ImageSkiaRep>::Read(
SkBitmap bitmap;
if (!data.ReadBitmap(&bitmap))
return false;
+ // Null/uninitialized bitmaps are not allowed, and an ImageSkiaRep is never
+ // empty-sized either.
+ if (bitmap.drawsNothing())
+ return false;
+ // Similar to BitmapN32, ImageSkiaReps are expected to have an N32 bitmap
+ // type.
+ if (bitmap.colorType() != kN32_SkColorType)
+ return false;
*out = gfx::ImageSkiaRep(bitmap, data.scale());
return true;
diff --git a/chromium/ui/gfx/image/mojom/image_skia_mojom_traits.h b/chromium/ui/gfx/image/mojom/image_skia_mojom_traits.h
index d648a393469..eb351658332 100644
--- a/chromium/ui/gfx/image/mojom/image_skia_mojom_traits.h
+++ b/chromium/ui/gfx/image/mojom/image_skia_mojom_traits.h
@@ -9,6 +9,7 @@
#include <vector>
+#include "base/check_op.h"
#include "skia/public/mojom/bitmap_skbitmap_mojom_traits.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image_skia.h"
@@ -19,14 +20,9 @@ namespace mojo {
template <>
struct StructTraits<gfx::mojom::ImageSkiaRepDataView, gfx::ImageSkiaRep> {
- static SkBitmap bitmap(const gfx::ImageSkiaRep& input) {
- return input.GetBitmap();
- }
+ static SkBitmap bitmap(const gfx::ImageSkiaRep& input);
static float scale(const gfx::ImageSkiaRep& input);
- static bool IsNull(const gfx::ImageSkiaRep& input) { return input.is_null(); }
- static void SetToNull(gfx::ImageSkiaRep* out) { *out = gfx::ImageSkiaRep(); }
-
static bool Read(gfx::mojom::ImageSkiaRepDataView data,
gfx::ImageSkiaRep* out);
};
diff --git a/chromium/ui/gfx/image/mojom/image_traits_unittest.cc b/chromium/ui/gfx/image/mojom/image_traits_unittest.cc
index ce090b7bf56..2e4e5e71c6c 100644
--- a/chromium/ui/gfx/image/mojom/image_traits_unittest.cc
+++ b/chromium/ui/gfx/image/mojom/image_traits_unittest.cc
@@ -9,14 +9,15 @@
#include "base/test/task_environment.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/image/image_unittest_util.h"
+#include "ui/gfx/image/mojom/image.mojom.h"
#include "ui/gfx/image/mojom/image_skia_mojom_traits.h"
-#include "ui/gfx/image/mojom/image_traits_test_service.mojom.h"
namespace gfx {
@@ -25,8 +26,7 @@ namespace {
// A test ImageSkiaSource that creates an ImageSkiaRep for any scale.
class TestImageSkiaSource : public ImageSkiaSource {
public:
- explicit TestImageSkiaSource(const gfx::Size& dip_size)
- : dip_size_(dip_size) {}
+ explicit TestImageSkiaSource(const Size& dip_size) : dip_size_(dip_size) {}
~TestImageSkiaSource() override = default;
// ImageSkiaSource:
@@ -35,156 +35,132 @@ class TestImageSkiaSource : public ImageSkiaSource {
}
private:
- const gfx::Size dip_size_;
+ const Size dip_size_;
DISALLOW_COPY_AND_ASSIGN(TestImageSkiaSource);
};
-// Revisit this after Deserialize(Serialize()) API works with handles.
-class ImageTraitsTest : public testing::Test,
- public mojom::ImageTraitsTestService {
- public:
- ImageTraitsTest() = default;
-
- // testing::Test:
- void SetUp() override {
- receivers_.Add(this, service_.BindNewPipeAndPassReceiver());
- }
-
- mojo::Remote<mojom::ImageTraitsTestService>& service() { return service_; }
-
- private:
- // mojom::ImageTraitsTestService:
- void EchoImageSkiaRep(const ImageSkiaRep& in,
- EchoImageSkiaRepCallback callback) override {
- std::move(callback).Run(in);
- }
- void EchoImageSkia(const ImageSkia& in,
- EchoImageSkiaCallback callback) override {
- std::move(callback).Run(in);
- }
-
- base::test::TaskEnvironment task_environment_;
- mojo::ReceiverSet<ImageTraitsTestService> receivers_;
- mojo::Remote<mojom::ImageTraitsTestService> service_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageTraitsTest);
-};
+// A helper to construct a skia.mojom.BitmapN32 without using StructTraits
+// to bypass checks on the sending/serialization side.
+mojo::StructPtr<mojom::ImageSkiaRep> ConstructImageSkiaRep(
+ const SkBitmap& bitmap,
+ float scale) {
+ auto mojom_rep = mojom::ImageSkiaRep::New();
+ mojom_rep->bitmap = bitmap;
+ mojom_rep->scale = scale;
+ return mojom_rep;
+}
} // namespace
-TEST_F(ImageTraitsTest, NullImageSkiaRep) {
- ImageSkiaRep null_rep;
- ASSERT_TRUE(null_rep.is_null());
+TEST(ImageTraitsTest, VerifyMojomConstruction) {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(1, 1);
+ mojo::StructPtr<mojom::ImageSkiaRep> input = ConstructImageSkiaRep(bitmap, 1);
+ ImageSkiaRep output;
+ EXPECT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::ImageSkiaRep>(input, output));
+}
+
+TEST(ImageTraitsTest, BadColorTypeImageSkiaRep_Deserialize) {
+ SkBitmap a8_bitmap;
+ a8_bitmap.allocPixels(SkImageInfo::MakeA8(1, 1));
- ImageSkiaRep output(gfx::Size(1, 1), 1.0f);
- ASSERT_FALSE(output.is_null());
- service()->EchoImageSkiaRep(null_rep, &output);
- EXPECT_TRUE(output.is_null());
+ mojo::StructPtr<mojom::ImageSkiaRep> input =
+ ConstructImageSkiaRep(a8_bitmap, 1);
+ ImageSkiaRep output;
+ EXPECT_FALSE(
+ mojo::test::SerializeAndDeserialize<mojom::ImageSkiaRep>(input, output));
}
-TEST_F(ImageTraitsTest, EmptyImageSkiaRep) {
+TEST(ImageTraitsTest, EmptyImageSkiaRep_Deserialize) {
SkBitmap empty_bitmap;
empty_bitmap.allocN32Pixels(0, 0);
// Empty SkBitmap is not null.
EXPECT_FALSE(empty_bitmap.isNull());
EXPECT_TRUE(empty_bitmap.drawsNothing());
- ImageSkiaRep empty_rep(empty_bitmap, 1.0f);
- // ImageSkiaRep with empty bitmap is not null.
- ASSERT_FALSE(empty_rep.is_null());
-
- ImageSkiaRep output(gfx::Size(1, 1), 1.0f);
- ASSERT_FALSE(output.is_null());
- service()->EchoImageSkiaRep(empty_rep, &output);
- EXPECT_TRUE(empty_rep.GetBitmap().drawsNothing());
- EXPECT_TRUE(test::AreBitmapsEqual(empty_rep.GetBitmap(), output.GetBitmap()));
+ mojo::StructPtr<mojom::ImageSkiaRep> input =
+ ConstructImageSkiaRep(empty_bitmap, 1);
+ ImageSkiaRep output;
+ EXPECT_FALSE(
+ mojo::test::SerializeAndDeserialize<mojom::ImageSkiaRep>(input, output));
}
-TEST_F(ImageTraitsTest, ImageSkiaRep) {
- ImageSkiaRep image_rep(gfx::Size(2, 4), 2.0f);
+TEST(ImageTraitsTest, ValidImageSkiaRep) {
+ ImageSkiaRep image_rep(Size(2, 4), 2.0f);
ImageSkiaRep output;
- service()->EchoImageSkiaRep(image_rep, &output);
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::ImageSkiaRep>(
+ image_rep, output));
EXPECT_FALSE(output.is_null());
EXPECT_EQ(image_rep.scale(), output.scale());
EXPECT_TRUE(test::AreBitmapsEqual(image_rep.GetBitmap(), output.GetBitmap()));
}
-TEST_F(ImageTraitsTest, UnscaledImageSkiaRep) {
- ImageSkiaRep image_rep(gfx::Size(2, 4), 0.0f);
+TEST(ImageTraitsTest, UnscaledImageSkiaRep) {
+ ImageSkiaRep image_rep(Size(2, 4), 0.0f);
ASSERT_TRUE(image_rep.unscaled());
- ImageSkiaRep output(gfx::Size(1, 1), 1.0f);
- EXPECT_FALSE(output.unscaled());
- service()->EchoImageSkiaRep(image_rep, &output);
+ ImageSkiaRep output;
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::ImageSkiaRep>(
+ image_rep, output));
EXPECT_TRUE(output.unscaled());
EXPECT_TRUE(test::AreBitmapsEqual(image_rep.GetBitmap(), output.GetBitmap()));
}
-TEST_F(ImageTraitsTest, NullImageSkia) {
+TEST(ImageTraitsTest, NullImageSkia) {
ImageSkia null_image;
ASSERT_TRUE(null_image.isNull());
- ImageSkia output(ImageSkiaRep(gfx::Size(1, 1), 1.0f));
+ ImageSkia output(ImageSkiaRep(Size(1, 1), 1.0f));
ASSERT_FALSE(output.isNull());
- service()->EchoImageSkia(null_image, &output);
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::ImageSkia>(null_image,
+ output));
EXPECT_TRUE(output.isNull());
}
-TEST_F(ImageTraitsTest, ImageSkiaRepsAreCreatedAsNeeded) {
- const gfx::Size kSize(1, 2);
+TEST(ImageTraitsTest, ImageSkiaRepsAreCreatedAsNeeded) {
+ const Size kSize(1, 2);
ImageSkia image(std::make_unique<TestImageSkiaSource>(kSize), kSize);
EXPECT_FALSE(image.isNull());
EXPECT_TRUE(image.image_reps().empty());
ImageSkia output;
EXPECT_TRUE(output.isNull());
- service()->EchoImageSkia(image, &output);
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::ImageSkia>(image, output));
EXPECT_FALSE(image.image_reps().empty());
EXPECT_FALSE(output.isNull());
}
-TEST_F(ImageTraitsTest, ImageSkia) {
- const gfx::Size kSize(1, 2);
+TEST(ImageTraitsTest, ImageSkia) {
+ const Size kSize(1, 2);
ImageSkia image(std::make_unique<TestImageSkiaSource>(kSize), kSize);
image.GetRepresentation(1.0f);
image.GetRepresentation(2.0f);
ImageSkia output;
- service()->EchoImageSkia(image, &output);
-
- EXPECT_TRUE(test::AreImagesEqual(Image(output), Image(image)));
-}
-
-TEST_F(ImageTraitsTest, EmptyRepPreserved) {
- const gfx::Size kSize(1, 2);
- ImageSkia image(std::make_unique<TestImageSkiaSource>(kSize), kSize);
- image.GetRepresentation(1.0f);
-
- SkBitmap empty_bitmap;
- empty_bitmap.allocN32Pixels(0, 0);
- image.AddRepresentation(ImageSkiaRep(empty_bitmap, 2.0f));
-
- ImageSkia output;
- service()->EchoImageSkia(image, &output);
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::ImageSkia>(image, output));
EXPECT_TRUE(test::AreImagesEqual(Image(output), Image(image)));
}
-TEST_F(ImageTraitsTest, ImageSkiaWithOperations) {
- const gfx::Size kSize(32, 32);
+TEST(ImageTraitsTest, ImageSkiaWithOperations) {
+ const Size kSize(32, 32);
ImageSkia image(std::make_unique<TestImageSkiaSource>(kSize), kSize);
- const gfx::Size kNewSize(16, 16);
+ const Size kNewSize(16, 16);
ImageSkia resized = ImageSkiaOperations::CreateResizedImage(
image, skia::ImageOperations::RESIZE_BEST, kNewSize);
resized.GetRepresentation(1.0f);
resized.GetRepresentation(2.0f);
ImageSkia output;
- service()->EchoImageSkia(resized, &output);
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::ImageSkia>(resized, output));
EXPECT_TRUE(test::AreImagesEqual(Image(output), Image(resized)));
}
diff --git a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
index 8c94f8be779..86c3dceea29 100644
--- a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
+++ b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
@@ -24,6 +24,7 @@
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/switches.h"
@@ -93,18 +94,8 @@ ClientNativePixmapDmaBuf::PlaneInfo::~PlaneInfo() {
bool ClientNativePixmapDmaBuf::IsConfigurationSupported(
gfx::BufferFormat format,
gfx::BufferUsage usage) {
-#if BUILDFLAG(IS_CHROMECAST)
- switch (usage) {
- case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
- // TODO(spang): Fix b/121148905 and turn these back on.
- return false;
- default:
- break;
- }
-#endif
-
bool disable_yuv_biplanar = true;
-#if defined(OS_CHROMEOS) || BUILDFLAG(IS_CHROMECAST)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMECAST)
// IsConfigurationSupported(SCANOUT_CPU_READ_WRITE) is used by the renderer
// to tell whether the platform supports sampling a given format. Zero-copy
// video capture and encoding requires gfx::BufferFormat::YUV_420_BIPLANAR to
@@ -193,7 +184,7 @@ bool ClientNativePixmapDmaBuf::IsConfigurationSupported(
// R_8 is used as the underlying pixel format for BLOB buffers.
return format == gfx::BufferFormat::R_8;
case gfx::BufferUsage::SCANOUT_VEA_CPU_READ:
- case gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE:
+ case gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE:
return format == gfx::BufferFormat::YVU_420 ||
format == gfx::BufferFormat::YUV_420_BIPLANAR;
}
diff --git a/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc b/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
index 1607888d56a..301b75bbb2e 100644
--- a/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
+++ b/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
@@ -60,7 +60,7 @@ class ClientNativePixmapFactoryDmabuf : public ClientNativePixmapFactory {
case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE:
case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE:
case gfx::BufferUsage::SCANOUT_VEA_CPU_READ:
- case gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE:
+ case gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE:
return ClientNativePixmapDmaBuf::ImportFromDmabuf(std::move(handle),
size, format);
case gfx::BufferUsage::GPU_READ:
diff --git a/chromium/ui/gfx/linux/gbm_defines.h b/chromium/ui/gfx/linux/gbm_defines.h
index 8f893785c20..c139b377f9e 100644
--- a/chromium/ui/gfx/linux/gbm_defines.h
+++ b/chromium/ui/gfx/linux/gbm_defines.h
@@ -20,6 +20,7 @@
#define GBM_BO_USE_HW_VIDEO_DECODER 0
#define GBM_BO_USE_HW_VIDEO_ENCODER 0
#define GBM_BO_USE_PROTECTED 0
+#define GBM_BO_USE_SW_READ_OFTEN 0
#endif
#endif // UI_GFX_LINUX_GBM_DEFINES_H_
diff --git a/chromium/ui/gfx/linux/gbm_util.cc b/chromium/ui/gfx/linux/gbm_util.cc
index b945ef444ea..e0ad3ddc030 100644
--- a/chromium/ui/gfx/linux/gbm_util.cc
+++ b/chromium/ui/gfx/linux/gbm_util.cc
@@ -33,9 +33,10 @@ uint32_t BufferUsageToGbmFlags(gfx::BufferUsage usage) {
case gfx::BufferUsage::SCANOUT_VEA_CPU_READ:
return GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT | GBM_BO_USE_TEXTURING |
GBM_BO_USE_HW_VIDEO_ENCODER;
- case gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE:
- return GBM_BO_USE_LINEAR | GBM_BO_USE_CAMERA_WRITE | GBM_BO_USE_SCANOUT |
- GBM_BO_USE_TEXTURING | GBM_BO_USE_HW_VIDEO_ENCODER;
+ case gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE:
+ return GBM_BO_USE_LINEAR | GBM_BO_USE_CAMERA_WRITE |
+ GBM_BO_USE_TEXTURING | GBM_BO_USE_HW_VIDEO_ENCODER |
+ GBM_BO_USE_SW_READ_OFTEN;
default:
NOTREACHED();
return 0;
diff --git a/chromium/ui/gfx/linux/gpu_memory_buffer_support_x11.cc b/chromium/ui/gfx/linux/gpu_memory_buffer_support_x11.cc
index 28e5d27ee24..5b89bfdaad6 100644
--- a/chromium/ui/gfx/linux/gpu_memory_buffer_support_x11.cc
+++ b/chromium/ui/gfx/linux/gpu_memory_buffer_support_x11.cc
@@ -9,9 +9,9 @@
#include <memory>
+#include "base/containers/contains.h"
#include "base/debug/crash_logging.h"
#include "base/posix/eintr_wrapper.h"
-#include "base/stl_util.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/buffer_usage_util.h"
@@ -22,6 +22,7 @@
#include "ui/gfx/linux/gbm_wrapper.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/dri3.h"
+#include "ui/gfx/x/future.h"
namespace ui {
@@ -48,13 +49,13 @@ std::unique_ptr<ui::GbmDevice> CreateX11GbmDevice() {
if (!reply)
return nullptr;
- int fd = reply->device_fd.release();
- if (fd < 0)
+ base::ScopedFD fd(HANDLE_EINTR(dup(reply->device_fd.get())));
+ if (!fd.is_valid())
return nullptr;
- if (HANDLE_EINTR(fcntl(fd, F_SETFD, FD_CLOEXEC)) == -1)
+ if (HANDLE_EINTR(fcntl(fd.get(), F_SETFD, FD_CLOEXEC)) == -1)
return nullptr;
- return ui::CreateGbmDevice(fd);
+ return ui::CreateGbmDevice(fd.release());
}
std::vector<gfx::BufferUsageAndFormat> CreateSupportedConfigList(
diff --git a/chromium/ui/gfx/mac/io_surface.cc b/chromium/ui/gfx/mac/io_surface.cc
index 5728c068262..e5fd0a36f83 100644
--- a/chromium/ui/gfx/mac/io_surface.cc
+++ b/chromium/ui/gfx/mac/io_surface.cc
@@ -163,12 +163,20 @@ bool IOSurfaceSetColorSpace(IOSurfaceRef io_surface,
ColorSpace::TransferID::SMPTEST2084,
ColorSpace::MatrixID::BT2020_NCL,
ColorSpace::RangeID::LIMITED)) {
- return true;
+ if (__builtin_available(macos 11.0, *)) {
+ color_space_name = kCGColorSpaceITUR_2100_PQ;
+ } else {
+ return true;
+ }
} else if (color_space == ColorSpace(ColorSpace::PrimaryID::BT2020,
ColorSpace::TransferID::ARIB_STD_B67,
ColorSpace::MatrixID::BT2020_NCL,
ColorSpace::RangeID::LIMITED)) {
- return true;
+ if (__builtin_available(macos 11.0, *)) {
+ color_space_name = kCGColorSpaceITUR_2100_HLG;
+ } else {
+ return true;
+ }
}
}
if (color_space_name) {
@@ -280,11 +288,6 @@ IOSurfaceRef CreateIOSurface(const gfx::Size& size,
return nullptr;
}
- // IOSurface clearing causes significant performance regression on about half
- // of all devices running Yosemite. https://crbug.com/606850#c22.
- if (base::mac::IsOS10_10())
- should_clear = false;
-
if (should_clear) {
// Zero-initialize the IOSurface. Calling IOSurfaceLock/IOSurfaceUnlock
// appears to be sufficient. https://crbug.com/584760#c17
diff --git a/chromium/ui/gfx/mac/io_surface_hdr_metadata.cc b/chromium/ui/gfx/mac/io_surface_hdr_metadata.cc
new file mode 100644
index 00000000000..f4250246550
--- /dev/null
+++ b/chromium/ui/gfx/mac/io_surface_hdr_metadata.cc
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium 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/mac/io_surface_hdr_metadata.h"
+
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "ui/gfx/mojom/hdr_metadata.mojom.h"
+
+namespace gfx {
+
+namespace {
+
+// The key under which HDR metadata is attached to an IOSurface.
+const CFStringRef kCrIOSurfaceHDRMetadataKey =
+ CFSTR("CrIOSurfaceHDRMetadataKey");
+
+} // namespace
+
+void IOSurfaceSetHDRMetadata(IOSurfaceRef io_surface,
+ gfx::HDRMetadata hdr_metadata) {
+ std::vector<uint8_t> std_data =
+ gfx::mojom::HDRMetadata::Serialize(&hdr_metadata);
+ base::ScopedCFTypeRef<CFDataRef> cf_data(
+ CFDataCreate(nullptr, std_data.data(), std_data.size()));
+ IOSurfaceSetValue(io_surface, kCrIOSurfaceHDRMetadataKey, cf_data);
+}
+
+bool IOSurfaceGetHDRMetadata(IOSurfaceRef io_surface,
+ gfx::HDRMetadata& hdr_metadata) {
+ base::ScopedCFTypeRef<CFTypeRef> cf_untyped(
+ IOSurfaceCopyValue(io_surface, kCrIOSurfaceHDRMetadataKey));
+ CFDataRef cf_data = base::mac::CFCast<CFDataRef>(cf_untyped);
+ if (!cf_data)
+ return false;
+ const UInt8* raw_data = CFDataGetBytePtr(cf_data);
+ std::vector<uint8_t> std_data(raw_data, raw_data + CFDataGetLength(cf_data));
+ return gfx::mojom::HDRMetadata::Deserialize(std_data, &hdr_metadata);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/mac/io_surface_hdr_metadata.h b/chromium/ui/gfx/mac/io_surface_hdr_metadata.h
new file mode 100644
index 00000000000..1bee4842c19
--- /dev/null
+++ b/chromium/ui/gfx/mac/io_surface_hdr_metadata.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Chromium 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_MAC_IO_SURFACE_HDR_METADATA_H_
+#define UI_GFX_MAC_IO_SURFACE_HDR_METADATA_H_
+
+#include <IOSurface/IOSurface.h>
+
+#include "base/component_export.h"
+
+namespace gfx {
+
+struct HDRMetadata;
+
+// Attach |hdr_metadata| to |io_surface|. After this is called, any other
+// process that has opened |io_surface| will be able to read |hdr_metadata|
+// using the function IOSurfaceGetHDRMetadata.
+void COMPONENT_EXPORT(GFX_IO_SURFACE_HDR_METADATA)
+ IOSurfaceSetHDRMetadata(IOSurfaceRef io_surface,
+ gfx::HDRMetadata hdr_metadata);
+
+// Retrieve in |hdr_metadata| the value that was attached to |io_surface|. This
+// will return false on failure.
+bool COMPONENT_EXPORT(GFX_IO_SURFACE_HDR_METADATA)
+ IOSurfaceGetHDRMetadata(IOSurfaceRef io_surface,
+ gfx::HDRMetadata& hdr_metadata);
+
+} // namespace gfx
+
+#endif // UI_GFX_MAC_IO_SURFACE_HDR_METADATA_H_
diff --git a/chromium/ui/gfx/mac/io_surface_unittest.cc b/chromium/ui/gfx/mac/io_surface_unittest.cc
new file mode 100644
index 00000000000..fff1dcbfab4
--- /dev/null
+++ b/chromium/ui/gfx/mac/io_surface_unittest.cc
@@ -0,0 +1,38 @@
+// Copyright 2020 The Chromium 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/mac/io_surface.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/hdr_metadata.h"
+#include "ui/gfx/mac/io_surface_hdr_metadata.h"
+
+namespace gfx {
+
+namespace {
+
+// Check that empty NSBezierPath is returned for empty SkPath.
+TEST(IOSurface, HDRMetadata) {
+ gfx::HDRMetadata in;
+ in.mastering_metadata.primary_r = PointF(1.0, 2.0);
+ in.mastering_metadata.primary_g = PointF(4.0, 5.0);
+ in.mastering_metadata.primary_b = PointF(7.0, 8.0);
+ in.mastering_metadata.white_point = PointF(10.0, 11.0);
+ in.mastering_metadata.luminance_max = 13;
+ in.mastering_metadata.luminance_min = 14;
+ in.max_content_light_level = 15;
+ in.max_frame_average_light_level = 16;
+
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
+ CreateIOSurface(gfx::Size(100, 100), gfx::BufferFormat::BGRA_8888));
+
+ gfx::HDRMetadata out;
+ EXPECT_FALSE(IOSurfaceGetHDRMetadata(io_surface, out));
+ IOSurfaceSetHDRMetadata(io_surface, in);
+ EXPECT_TRUE(IOSurfaceGetHDRMetadata(io_surface, out));
+ EXPECT_EQ(in, out);
+}
+
+} // namespace
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm b/chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm
index 981a6eff43d..b31792b689b 100644
--- a/chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm
+++ b/chromium/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm
@@ -6,27 +6,14 @@
#import <Cocoa/Cocoa.h>
-#include "base/mac/mac_util.h"
-
namespace gfx {
ScopedCocoaDisableScreenUpdates::ScopedCocoaDisableScreenUpdates() {
- if (base::mac::IsAtLeastOS10_11()) {
- // Beginning with OS X 10.11, [NSAnimationContext beginGrouping] is the
- // preferred way of disabling screen updates. Use of
- // NSDisableScreenUpdates() is discouraged.
- [NSAnimationContext beginGrouping];
- } else {
- NSDisableScreenUpdates();
- }
+ [NSAnimationContext beginGrouping];
}
ScopedCocoaDisableScreenUpdates::~ScopedCocoaDisableScreenUpdates() {
- if (base::mac::IsAtLeastOS10_11()) {
- [NSAnimationContext endGrouping];
- } else {
- NSEnableScreenUpdates();
- }
+ [NSAnimationContext endGrouping];
}
} // namespace gfx
diff --git a/chromium/ui/gfx/mojom/BUILD.gn b/chromium/ui/gfx/mojom/BUILD.gn
index 91d290a8af8..d52a4e96306 100644
--- a/chromium/ui/gfx/mojom/BUILD.gn
+++ b/chromium/ui/gfx/mojom/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/ozone.gni")
import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojom") {
@@ -33,7 +34,7 @@ mojom("mojom") {
]
enabled_features = []
- if (use_x11 || use_ozone) {
+ if (use_x11 || ozone_platform_x11) {
enabled_features += [ "enable_x11_params" ]
}
@@ -80,7 +81,17 @@ mojom("mojom") {
},
]
traits_headers = [ "color_space_mojom_traits.h" ]
- traits_public_deps = [ ":color_space_mojom_support" ]
+ traits_public_deps = [ ":shared_mojom_traits" ]
+ },
+ {
+ types = [
+ {
+ mojom = "gfx.mojom.DisplayColorSpaces"
+ cpp = "::gfx::DisplayColorSpaces"
+ },
+ ]
+ traits_headers = [ "display_color_spaces_mojom_traits.h" ]
+ traits_public_deps = [ ":shared_mojom_traits" ]
},
{
types = [
@@ -176,17 +187,6 @@ mojom("mojom") {
{
types = [
{
- mojom = "gfx.mojom.DisplayColorSpaces"
- cpp = "::gfx::DisplayColorSpaces"
- },
- ]
- traits_sources = [ "display_color_spaces_mojom_traits.cc" ]
- traits_headers = [ "display_color_spaces_mojom_traits.h" ]
- traits_public_deps = [ "//ui/gfx" ]
- },
- {
- types = [
- {
mojom = "gfx.mojom.MasteringMetadata"
cpp = "::gfx::MasteringMetadata"
},
@@ -294,18 +294,6 @@ mojom("test_interfaces") {
public_deps = [ ":mojom" ]
}
-component("color_space_mojom_support") {
- sources = [
- "color_space_mojom_traits.cc",
- "color_space_mojom_traits.h",
- ]
- public_deps = [
- ":mojom_shared_cpp_sources",
- "//ui/gfx",
- ]
- defines = [ "IS_UI_GFX_MOJOM_TRAITS_IMPL" ]
-}
-
component("native_handle_types_mojom_traits") {
output_name = "gfx_native_types_shared_mojom_traits"
defines = [ "IS_GFX_NATIVE_HANDLE_TYPES_SHARED_MOJOM_TRAITS_IMPL" ]
@@ -328,6 +316,10 @@ component("shared_mojom_traits") {
sources = [
"buffer_types_mojom_traits.cc",
"buffer_types_mojom_traits.h",
+ "color_space_mojom_traits.cc",
+ "color_space_mojom_traits.h",
+ "display_color_spaces_mojom_traits.cc",
+ "display_color_spaces_mojom_traits.h",
"gpu_extra_info_mojom_traits.cc",
"gpu_extra_info_mojom_traits.h",
"gpu_fence_handle_mojom_traits.cc",
@@ -338,6 +330,9 @@ component("shared_mojom_traits") {
":native_handle_types",
"//ui/gfx",
]
+ if (use_ozone) {
+ public_deps += [ "//ui/ozone:buildflags" ]
+ }
frameworks = [
"CoreFoundation.framework",
"IOSurface.framework",
diff --git a/chromium/ui/gfx/mojom/buffer_types.mojom b/chromium/ui/gfx/mojom/buffer_types.mojom
index 5d38cdba515..09647403fe2 100644
--- a/chromium/ui/gfx/mojom/buffer_types.mojom
+++ b/chromium/ui/gfx/mojom/buffer_types.mojom
@@ -36,7 +36,7 @@ enum BufferUsage {
PROTECTED_SCANOUT_VDA_WRITE,
GPU_READ_CPU_READ_WRITE,
SCANOUT_VEA_CPU_READ,
- SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE,
+ VEA_READ_CAMERA_AND_CPU_READ_WRITE,
};
struct BufferUsageAndFormat {
diff --git a/chromium/ui/gfx/mojom/buffer_types_mojom_traits.h b/chromium/ui/gfx/mojom/buffer_types_mojom_traits.h
index da8ac0b4ce9..4aa2ecf2ace 100644
--- a/chromium/ui/gfx/mojom/buffer_types_mojom_traits.h
+++ b/chromium/ui/gfx/mojom/buffer_types_mojom_traits.h
@@ -135,9 +135,8 @@ struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS)
return gfx::mojom::BufferUsage::GPU_READ_CPU_READ_WRITE;
case gfx::BufferUsage::SCANOUT_VEA_CPU_READ:
return gfx::mojom::BufferUsage::SCANOUT_VEA_CPU_READ;
- case gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE:
- return gfx::mojom::BufferUsage::
- SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE;
+ case gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE:
+ return gfx::mojom::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE;
}
NOTREACHED();
return gfx::mojom::BufferUsage::kMinValue;
@@ -172,8 +171,8 @@ struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS)
case gfx::mojom::BufferUsage::SCANOUT_VEA_CPU_READ:
*out = gfx::BufferUsage::SCANOUT_VEA_CPU_READ;
return true;
- case gfx::mojom::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE:
- *out = gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE;
+ case gfx::mojom::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE:
+ *out = gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE;
return true;
}
NOTREACHED();
diff --git a/chromium/ui/gfx/mojom/color_space_mojom_traits.h b/chromium/ui/gfx/mojom/color_space_mojom_traits.h
index 5c0ddd7425a..28943a0cf9e 100644
--- a/chromium/ui/gfx/mojom/color_space_mojom_traits.h
+++ b/chromium/ui/gfx/mojom/color_space_mojom_traits.h
@@ -374,7 +374,7 @@ struct EnumTraits<gfx::mojom::ColorSpaceRangeID, gfx::ColorSpace::RangeID> {
};
template <>
-struct COMPONENT_EXPORT(UI_GFX_MOJOM_TRAITS)
+struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS)
StructTraits<gfx::mojom::ColorSpaceDataView, gfx::ColorSpace> {
static gfx::ColorSpace::PrimaryID primaries(const gfx::ColorSpace& input) {
return input.primaries_;
diff --git a/chromium/ui/gfx/mojom/display_color_spaces_mojom_traits.h b/chromium/ui/gfx/mojom/display_color_spaces_mojom_traits.h
index 1923d7e85a3..9ff5f93c71f 100644
--- a/chromium/ui/gfx/mojom/display_color_spaces_mojom_traits.h
+++ b/chromium/ui/gfx/mojom/display_color_spaces_mojom_traits.h
@@ -9,20 +9,22 @@
#include "ui/gfx/display_color_spaces.h"
#include "ui/gfx/mojom/buffer_types_mojom_traits.h"
#include "ui/gfx/mojom/color_space_mojom_traits.h"
-#include "ui/gfx/mojom/display_color_spaces.mojom.h"
+#include "ui/gfx/mojom/display_color_spaces.mojom-shared.h"
namespace mojo {
template <>
-struct EnumTraits<gfx::mojom::ContentColorUsage, gfx::ContentColorUsage> {
+struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS)
+ EnumTraits<gfx::mojom::ContentColorUsage, gfx::ContentColorUsage> {
static gfx::mojom::ContentColorUsage ToMojom(gfx::ContentColorUsage input);
static bool FromMojom(gfx::mojom::ContentColorUsage input,
gfx::ContentColorUsage* output);
};
template <>
-struct StructTraits<gfx::mojom::DisplayColorSpacesDataView,
- gfx::DisplayColorSpaces> {
+struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS)
+ StructTraits<gfx::mojom::DisplayColorSpacesDataView,
+ gfx::DisplayColorSpaces> {
static base::span<const gfx::ColorSpace> color_spaces(
const gfx::DisplayColorSpaces& input);
static base::span<const gfx::BufferFormat> buffer_formats(
diff --git a/chromium/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc b/chromium/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc
index daa461e542e..6b7ff134e8a 100644
--- a/chromium/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc
+++ b/chromium/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc
@@ -24,9 +24,15 @@ bool StructTraits<gfx::mojom::GpuExtraInfoDataView, gfx::GpuExtraInfo>::Read(
gfx::GpuExtraInfo* out) {
if (!data.ReadAngleFeatures(&out->angle_features))
return false;
-#if defined(USE_OZONE) || defined(USE_X11)
- out->system_visual = data.system_visual();
- out->rgba_visual = data.rgba_visual();
+#if defined(USE_OZONE_PLATFORM_X11) || defined(USE_X11)
+ // These visuals below are obtained via methods of gl::GLVisualPickerGLX class
+ // and consumed by ui::XVisualManager::UpdateVisualsOnGpuInfoChanged(); should
+ // bad visuals come there, the GPU process will be shut down.
+ //
+ // See content::GpuDataManagerVisualProxyOzoneLinux and the ShutdownGpuOnIO()
+ // function there.
+ out->system_visual = static_cast<x11::VisualId>(data.system_visual());
+ out->rgba_visual = static_cast<x11::VisualId>(data.rgba_visual());
if (!data.ReadGpuMemoryBufferSupportX11(&out->gpu_memory_buffer_support_x11))
return false;
#endif
diff --git a/chromium/ui/gfx/mojom/gpu_extra_info_mojom_traits.h b/chromium/ui/gfx/mojom/gpu_extra_info_mojom_traits.h
index 0f3a94c1262..40a1114cb15 100644
--- a/chromium/ui/gfx/mojom/gpu_extra_info_mojom_traits.h
+++ b/chromium/ui/gfx/mojom/gpu_extra_info_mojom_traits.h
@@ -10,6 +10,13 @@
#include "ui/gfx/mojom/buffer_types_mojom_traits.h"
#include "ui/gfx/mojom/gpu_extra_info.mojom-shared.h"
+#if defined(USE_OZONE)
+#include "ui/ozone/buildflags.h"
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+#define USE_OZONE_PLATFORM_X11
+#endif
+#endif
+
namespace mojo {
template <>
@@ -54,13 +61,13 @@ struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS)
return input.angle_features;
}
-#if defined(USE_OZONE) || defined(USE_X11)
+#if defined(USE_OZONE_PLATFORM_X11) || defined(USE_X11)
static uint64_t system_visual(const gfx::GpuExtraInfo& input) {
- return input.system_visual;
+ return static_cast<uint64_t>(input.system_visual);
}
static uint64_t rgba_visual(const gfx::GpuExtraInfo& input) {
- return input.rgba_visual;
+ return static_cast<uint64_t>(input.rgba_visual);
}
static const std::vector<gfx::BufferUsageAndFormat>&
diff --git a/chromium/ui/gfx/mojom/mojom_traits_unittest.cc b/chromium/ui/gfx/mojom/mojom_traits_unittest.cc
index 73c764ffb75..78479528433 100644
--- a/chromium/ui/gfx/mojom/mojom_traits_unittest.cc
+++ b/chromium/ui/gfx/mojom/mojom_traits_unittest.cc
@@ -138,8 +138,8 @@ TEST_F(StructTraitsTest, Transform) {
TEST_F(StructTraitsTest, AcceleratedWidget) {
gfx::AcceleratedWidget input(CastToAcceleratedWidget(1001));
gfx::AcceleratedWidget output;
- mojo::test::SerializeAndDeserialize<gfx::mojom::AcceleratedWidget>(&input,
- &output);
+ mojo::test::SerializeAndDeserialize<gfx::mojom::AcceleratedWidget>(input,
+ output);
EXPECT_EQ(input, output);
}
@@ -252,8 +252,8 @@ TEST_F(StructTraitsTest, PresentationFeedback) {
input.latch_timestamp =
base::TimeTicks() + base::TimeDelta::FromMilliseconds(22);
PresentationFeedback output;
- mojo::test::SerializeAndDeserialize<gfx::mojom::PresentationFeedback>(
- &input, &output);
+ mojo::test::SerializeAndDeserialize<gfx::mojom::PresentationFeedback>(input,
+ output);
EXPECT_EQ(timestamp, output.timestamp);
EXPECT_EQ(interval, output.interval);
EXPECT_EQ(flags, output.flags);
diff --git a/chromium/ui/gfx/native_widget_types.h b/chromium/ui/gfx/native_widget_types.h
index f823bb318de..334d61f1f33 100644
--- a/chromium/ui/gfx/native_widget_types.h
+++ b/chromium/ui/gfx/native_widget_types.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/gfx_export.h"
#if defined(OS_ANDROID)
@@ -103,7 +104,9 @@ class ViewAndroid;
#endif
class SkBitmap;
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
extern "C" {
struct _AtkObject;
typedef struct _AtkObject AtkObject;
@@ -204,7 +207,9 @@ typedef id NativeViewAccessible;
#elif defined(OS_MAC)
typedef NSFont* NativeFont;
typedef id NativeViewAccessible;
-#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Linux doesn't have a native font type.
typedef AtkObject* NativeViewAccessible;
#else
diff --git a/chromium/ui/gfx/nine_image_painter_unittest.cc b/chromium/ui/gfx/nine_image_painter_unittest.cc
index 1cf8506291a..9897d001199 100644
--- a/chromium/ui/gfx/nine_image_painter_unittest.cc
+++ b/chromium/ui/gfx/nine_image_painter_unittest.cc
@@ -72,7 +72,7 @@ TEST(NineImagePainterTest, PaintHighDPI) {
float image_scale = 2.f;
- gfx::ImageSkia image(gfx::ImageSkiaRep(src, image_scale));
+ gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale);
gfx::Insets insets(10, 10, 10, 10);
gfx::NineImagePainter painter(image, insets);
@@ -104,7 +104,7 @@ TEST(NineImagePainterTest, PaintStaysInBounds) {
src.eraseColor(SK_ColorGREEN);
src.erase(SK_ColorRED, SkIRect::MakeXYWH(2, 2, 2, 2));
- gfx::ImageSkia image(gfx::ImageSkiaRep(src, 0.0f));
+ gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(src);
gfx::Insets insets(2, 2, 2, 2);
gfx::NineImagePainter painter(image, insets);
@@ -136,7 +136,7 @@ TEST(NineImagePainterTest, PaintWithBoundOffset) {
src.eraseColor(SK_ColorRED);
src.eraseArea(SkIRect::MakeXYWH(1, 1, 8, 8), SK_ColorGREEN);
- gfx::ImageSkia image(gfx::ImageSkiaRep(src, 0.0f));
+ gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(src);
gfx::Insets insets(1, 1, 1, 1);
gfx::NineImagePainter painter(image, insets);
@@ -168,7 +168,7 @@ TEST(NineImagePainterTest, PaintWithScale) {
float image_scale = 2.f;
- gfx::ImageSkia image(gfx::ImageSkiaRep(src, image_scale));
+ gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale);
gfx::Insets insets(10, 10, 10, 10);
gfx::NineImagePainter painter(image, insets);
@@ -199,7 +199,7 @@ TEST(NineImagePainterTest, PaintWithNegativeScale) {
float image_scale = 2.f;
- gfx::ImageSkia image(gfx::ImageSkiaRep(src, image_scale));
+ gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale);
gfx::Insets insets(10, 10, 10, 10);
gfx::NineImagePainter painter(image, insets);
diff --git a/chromium/ui/gfx/platform_font_mac.mm b/chromium/ui/gfx/platform_font_mac.mm
index fc6047806e3..bc8aeaade05 100644
--- a/chromium/ui/gfx/platform_font_mac.mm
+++ b/chromium/ui/gfx/platform_font_mac.mm
@@ -126,63 +126,26 @@ Weight GetFontWeightFromNSFont(NSFont* font) {
// Converts a Font::Weight value to the corresponding NSFontWeight value.
NSFontWeight ToNSFontWeight(Weight weight) {
- if (@available(macOS 10.11, *)) {
- switch (weight) {
- case Weight::THIN:
- return NSFontWeightUltraLight;
- case Weight::EXTRA_LIGHT:
- return NSFontWeightThin;
- case Weight::LIGHT:
- return NSFontWeightLight;
- case Weight::INVALID:
- case Weight::NORMAL:
- return NSFontWeightRegular;
- case Weight::MEDIUM:
- return NSFontWeightMedium;
- case Weight::SEMIBOLD:
- return NSFontWeightSemibold;
- case Weight::BOLD:
- return NSFontWeightBold;
- case Weight::EXTRA_BOLD:
- return NSFontWeightHeavy;
- case Weight::BLACK:
- return NSFontWeightBlack;
- }
- } else {
- // See third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm.
- uint64_t int_value = 0;
- switch (weight) {
- case Weight::THIN:
- int_value = 0xbfe99999a0000000; // NSFontWeightUltraLight;
- break;
- case Weight::EXTRA_LIGHT:
- int_value = 0xbfe3333340000000; // NSFontWeightThin;
- break;
- case Weight::LIGHT:
- int_value = 0xbfd99999a0000000; // NSFontWeightLight;
- break;
- case Weight::INVALID:
- case Weight::NORMAL:
- int_value = 0x0000000000000000; // NSFontWeightRegular;
- break;
- case Weight::MEDIUM:
- int_value = 0x3fcd70a3e0000000; // NSFontWeightMedium;
- break;
- case Weight::SEMIBOLD:
- int_value = 0x3fd3333340000000; // NSFontWeightSemibold;
- break;
- case Weight::BOLD:
- int_value = 0x3fd99999a0000000; // NSFontWeightBold;
- break;
- case Weight::EXTRA_BOLD:
- int_value = 0x3fe1eb8520000000; // NSFontWeightHeavy;
- break;
- case Weight::BLACK:
- int_value = 0x3fe3d70a40000000; // NSFontWeightBlack;
- break;
- }
-
- return bit_cast<CGFloat>(int_value);
+ switch (weight) {
+ case Weight::THIN:
+ return NSFontWeightUltraLight;
+ case Weight::EXTRA_LIGHT:
+ return NSFontWeightThin;
+ case Weight::LIGHT:
+ return NSFontWeightLight;
+ case Weight::INVALID:
+ case Weight::NORMAL:
+ return NSFontWeightRegular;
+ case Weight::MEDIUM:
+ return NSFontWeightMedium;
+ case Weight::SEMIBOLD:
+ return NSFontWeightSemibold;
+ case Weight::BOLD:
+ return NSFontWeightBold;
+ case Weight::EXTRA_BOLD:
+ return NSFontWeightHeavy;
+ case Weight::BLACK:
+ return NSFontWeightBlack;
}
}
@@ -356,13 +319,8 @@ Font PlatformFontMac::DeriveFont(int size_delta,
// versions of the macOS.
if (system_font_type_ == SystemFontType::kGeneral) {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability"
- // +[NSFont systemFontOfSize:weight:] is declared as available on 10.11+,
- // but actually it is there and works on 10.10.
NSFont* derived = [NSFont systemFontOfSize:font_spec_.size + size_delta
weight:ToNSFontWeight(weight)];
-#pragma clang diagnostic pop
NSFontTraitMask italic_trait_mask =
(style & Font::ITALIC) ? NSItalicFontMask : NSUnitalicFontMask;
derived = [[NSFontManager sharedFontManager] convertFont:derived
@@ -559,16 +517,9 @@ NSFont* PlatformFontMac::NSFontWithSpec(FontSpec font_spec) const {
// If that doesn't find a font, whip up a system font to stand in for the
// specified font.
- if (@available(macOS 10.11, *)) {
- font = [NSFont systemFontOfSize:font_spec.size
- weight:ToNSFontWeight(font_spec.weight)];
- return [font_manager convertFont:font toHaveTrait:traits];
- } else {
- font = [NSFont systemFontOfSize:font_spec.size];
- if (font_spec.weight >= Weight::BOLD)
- traits |= NSBoldFontMask;
- return [font_manager convertFont:font toHaveTrait:traits];
- }
+ font = [NSFont systemFontOfSize:font_spec.size
+ weight:ToNSFontWeight(font_spec.weight)];
+ return [font_manager convertFont:font toHaveTrait:traits];
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/ui/gfx/platform_font_mac_unittest.mm b/chromium/ui/gfx/platform_font_mac_unittest.mm
index 0f812e9e70b..ca6e5237f61 100644
--- a/chromium/ui/gfx/platform_font_mac_unittest.mm
+++ b/chromium/ui/gfx/platform_font_mac_unittest.mm
@@ -8,7 +8,6 @@
#include <stddef.h>
#import "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -174,16 +173,8 @@ TEST(PlatformFontMacTest, DerivedFineGrainedFonts) {
EXPECT_EQ(static_cast<int>(Weight::LIGHT), DerivedIntWeight(Weight::LIGHT));
EXPECT_EQ(static_cast<int>(Weight::NORMAL), DerivedIntWeight(Weight::NORMAL));
EXPECT_EQ(static_cast<int>(Weight::MEDIUM), DerivedIntWeight(Weight::MEDIUM));
- if (base::mac::IsAtMostOS10_10()) {
- // If a SEMIBOLD system font is requested, 10.10 will return the bold system
- // font, but somehow bearing a weight number of 0.24, which is really a
- // medium weight (0.23).
- EXPECT_EQ(static_cast<int>(Weight::MEDIUM),
- DerivedIntWeight(Weight::SEMIBOLD));
- } else {
- EXPECT_EQ(static_cast<int>(Weight::SEMIBOLD),
- DerivedIntWeight(Weight::SEMIBOLD));
- }
+ EXPECT_EQ(static_cast<int>(Weight::SEMIBOLD),
+ DerivedIntWeight(Weight::SEMIBOLD));
EXPECT_EQ(static_cast<int>(Weight::BOLD), DerivedIntWeight(Weight::BOLD));
EXPECT_EQ(static_cast<int>(Weight::EXTRA_BOLD),
DerivedIntWeight(Weight::EXTRA_BOLD));
diff --git a/chromium/ui/gfx/platform_font_skia.cc b/chromium/ui/gfx/platform_font_skia.cc
index 0e4901926e6..00361316bbe 100644
--- a/chromium/ui/gfx/platform_font_skia.cc
+++ b/chromium/ui/gfx/platform_font_skia.cc
@@ -14,6 +14,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/skia/include/core/SkFont.h"
#include "third_party/skia/include/core/SkFontMetrics.h"
#include "third_party/skia/include/core/SkFontStyle.h"
@@ -171,7 +172,7 @@ bool PlatformFontSkia::InitDefaultFont() {
delegate->GetDefaultFontDescription(&family, &size_pixels, &style, &weight,
&params);
} else if (default_font_description_) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
// On ChromeOS, a FontList font description string is stored as a
// translatable resource and passed in via SetDefaultFontDescription().
FontRenderParamsQuery query;
diff --git a/chromium/ui/gfx/render_text.cc b/chromium/ui/gfx/render_text.cc
index bae9421235d..8b6064d1599 100644
--- a/chromium/ui/gfx/render_text.cc
+++ b/chromium/ui/gfx/render_text.cc
@@ -583,6 +583,9 @@ size_t RenderText::GetTextIndexOfLine(size_t line) {
}
void RenderText::SetWordWrapBehavior(WordWrapBehavior behavior) {
+ // TODO(1150235): ELIDE_LONG_WORDS is not supported.
+ DCHECK_NE(behavior, ELIDE_LONG_WORDS);
+
if (word_wrap_behavior_ != behavior) {
word_wrap_behavior_ = behavior;
if (multiline_) {
@@ -601,7 +604,6 @@ void RenderText::SetMinLineHeight(int line_height) {
}
void RenderText::SetElideBehavior(ElideBehavior elide_behavior) {
- // TODO(skanuj) : Add a test for triggering layout change.
if (elide_behavior_ != elide_behavior) {
elide_behavior_ = elide_behavior;
OnDisplayTextAttributeChanged();
@@ -1188,6 +1190,10 @@ const Vector2d& RenderText::GetUpdatedDisplayOffset() {
}
void RenderText::SetDisplayOffset(int horizontal_offset) {
+ SetDisplayOffset({horizontal_offset, display_offset_.y()});
+}
+
+void RenderText::SetDisplayOffset(Vector2d offset) {
const int extra_content = GetContentWidth() - display_rect_.width();
const int cursor_width = cursor_enabled_ ? 1 : 0;
@@ -1213,24 +1219,30 @@ void RenderText::SetDisplayOffset(int horizontal_offset) {
break;
}
}
- if (horizontal_offset < min_offset)
- horizontal_offset = min_offset;
- else if (horizontal_offset > max_offset)
- horizontal_offset = max_offset;
+
+ const int horizontal_offset =
+ base::ClampToRange(offset.x(), min_offset, max_offset);
+
+ // y-offset is set only when the vertical alignment is ALIGN_TOP.
+ // TODO(jongkown.lee): Support other vertical alignments.
+ DCHECK(vertical_alignment_ == ALIGN_TOP || offset.y() == 0);
+ const int vertical_offset = base::ClampToRange(
+ offset.y(),
+ std::min(display_rect_.height() - GetStringSize().height(), 0), 0);
cached_bounds_and_offset_valid_ = true;
- display_offset_.set_x(horizontal_offset);
+ display_offset_ = {horizontal_offset, vertical_offset};
cursor_bounds_ = GetCursorBounds(selection_model_, true);
}
Vector2d RenderText::GetLineOffset(size_t line_number) {
const internal::ShapedText* shaped_text = GetShapedText();
Vector2d offset = display_rect().OffsetFromOrigin();
- // TODO(ckocagil): Apply the display offset for multiline scrolling.
if (!multiline()) {
offset.Add(GetUpdatedDisplayOffset());
} else {
DCHECK_LT(line_number, shaped_text->lines().size());
+ offset.Add(GetUpdatedDisplayOffset());
offset.Add(
Vector2d(0, shaped_text->lines()[line_number].preceding_heights));
}
@@ -2081,6 +2093,8 @@ base::string16 RenderText::Elide(const base::string16& text,
if (trailing_text_direction != text_direction &&
new_text.length() + 2 > text.length() && guess >= 1) {
new_text = slicer.CutString(guess - 1, false);
+ trailing_text_direction =
+ base::i18n::GetLastStrongCharacterDirection(new_text);
}
// Append the ellipsis and the optional directional marker characters.
@@ -2220,9 +2234,8 @@ void RenderText::UpdateCachedBoundsAndOffset() {
if (cached_bounds_and_offset_valid_)
return;
- // TODO(ckocagil): Add support for scrolling multiline text.
-
int delta_x = 0;
+ int delta_y = 0;
if (cursor_enabled()) {
// When cursor is enabled, ensure it is visible. For this, set the valid
@@ -2237,9 +2250,16 @@ void RenderText::UpdateCachedBoundsAndOffset() {
delta_x = display_rect_.right() - cursor_bounds_.right();
else if (cursor_bounds_.x() < display_rect_.x())
delta_x = display_rect_.x() - cursor_bounds_.x();
+
+ if (vertical_alignment_ == ALIGN_TOP) {
+ if (cursor_bounds_.bottom() > display_rect_.bottom())
+ delta_y = display_rect_.bottom() - cursor_bounds_.bottom();
+ else if (cursor_bounds_.y() < display_rect_.y())
+ delta_y = display_rect_.y() - cursor_bounds_.y();
+ }
}
- SetDisplayOffset(display_offset_.x() + delta_x);
+ SetDisplayOffset(display_offset_ + Vector2d(delta_x, delta_y));
}
internal::GraphemeIterator RenderText::GetGraphemeIteratorAtIndex(
diff --git a/chromium/ui/gfx/render_text.h b/chromium/ui/gfx/render_text.h
index 29c589ee9fe..bb7ce1ca82b 100644
--- a/chromium/ui/gfx/render_text.h
+++ b/chromium/ui/gfx/render_text.h
@@ -582,6 +582,7 @@ class GFX_EXPORT RenderText {
const Vector2d& GetUpdatedDisplayOffset();
void SetDisplayOffset(int horizontal_offset);
+ void SetDisplayOffset(Vector2d offset);
// Returns the line offset from the origin after applying the text alignment
// and the display offset.
diff --git a/chromium/ui/gfx/render_text_api_fuzzer.cc b/chromium/ui/gfx/render_text_api_fuzzer.cc
index 821cd5c2a12..8d39dfc2ee0 100644
--- a/chromium/ui/gfx/render_text_api_fuzzer.cc
+++ b/chromium/ui/gfx/render_text_api_fuzzer.cc
@@ -14,10 +14,13 @@
#include "base/test/task_environment.h"
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/render_text.h"
-#if defined(OS_ANDROID) || defined(OS_LINUX)
+// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
+// complete.
+#if defined(OS_ANDROID) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
#include "base/test/test_discardable_memory_allocator.h"
#endif
@@ -37,7 +40,9 @@ struct Environment {
TestTimeouts::Initialize(),
base::test::TaskEnvironment::MainThreadType::UI)) {
logging::SetMinLogLevel(logging::LOG_FATAL);
-#if defined(OS_ANDROID) || defined(OS_LINUX)
+// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
+// complete.
+#if defined(OS_ANDROID) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
// Some platforms require discardable memory to use bitmap fonts.
base::DiscardableMemoryAllocator::SetInstance(
&discardable_memory_allocator);
@@ -46,7 +51,9 @@ struct Environment {
gfx::FontList::SetDefaultFontDescription(kFontDescription);
}
-#if defined(OS_ANDROID) || defined(OS_LINUX)
+// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
+// complete.
+#if defined(OS_ANDROID) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
base::TestDiscardableMemoryAllocator discardable_memory_allocator;
#endif
@@ -141,14 +148,13 @@ gfx::TextStyle ConsumeStyle(FuzzedDataProvider* fdp) {
}
gfx::WordWrapBehavior ConsumeWordWrap(FuzzedDataProvider* fdp) {
- switch (fdp->ConsumeIntegralInRange(0, 4)) {
+ // TODO(1150235): ELIDE_LONG_WORDS is not supported.
+ switch (fdp->ConsumeIntegralInRange(0, 3)) {
case 0:
return gfx::IGNORE_LONG_WORDS;
case 1:
return gfx::TRUNCATE_LONG_WORDS;
case 2:
- return gfx::ELIDE_LONG_WORDS;
- case 3:
return gfx::WRAP_LONG_WORDS;
default:
return gfx::IGNORE_LONG_WORDS;
diff --git a/chromium/ui/gfx/render_text_harfbuzz.cc b/chromium/ui/gfx/render_text_harfbuzz.cc
index 2f92818f7cb..29d3b45791f 100644
--- a/chromium/ui/gfx/render_text_harfbuzz.cc
+++ b/chromium/ui/gfx/render_text_harfbuzz.cc
@@ -8,6 +8,7 @@
#include <set>
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/containers/mru_cache.h"
#include "base/containers/span.h"
#include "base/feature_list.h"
@@ -21,7 +22,6 @@
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/numerics/safe_conversions.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/ui/gfx/render_text_test_api.h b/chromium/ui/gfx/render_text_test_api.h
index 07c48f4a035..1de8993c8fb 100644
--- a/chromium/ui/gfx/render_text_test_api.h
+++ b/chromium/ui/gfx/render_text_test_api.h
@@ -66,6 +66,10 @@ class RenderTextTestApi {
return render_text_->GetShapedText()->lines();
}
+ const Vector2d& display_offset() const {
+ return render_text_->display_offset_;
+ }
+
SelectionModel EdgeSelectionModel(VisualCursorDirection direction) {
return render_text_->EdgeSelectionModel(direction);
}
diff --git a/chromium/ui/gfx/render_text_unittest.cc b/chromium/ui/gfx/render_text_unittest.cc
index d5e8883811c..1b25f807e95 100644
--- a/chromium/ui/gfx/render_text_unittest.cc
+++ b/chromium/ui/gfx/render_text_unittest.cc
@@ -15,6 +15,7 @@
#include "base/format_macros.h"
#include "base/i18n/break_iterator.h"
#include "base/i18n/char_iterator.h"
+#include "base/logging.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
@@ -1895,11 +1896,20 @@ struct ElideTextTestOptions {
const ElideBehavior elide_behavior;
};
+const bool kForceNoWhitespaceElision = false;
+const bool kForceWhitespaceElision = true;
+
struct ElideTextCase {
const char* test_name;
const wchar_t* text;
const wchar_t* display_text;
- int available_width_as_glyph_count = -1;
+ // The available width, specified as a number of fixed-width glyphs. If no
+ // value is specified, the width of the resulting |display_text| is used. This
+ // helps test available widths larger than the resulting test; e.g. "a b"
+ // should yield "a\u2026" even if 3 glyph widths are available, when
+ // whitespace elision is enabled.
+ const base::Optional<size_t> available_width_as_glyph_count = base::nullopt;
+ const base::Optional<bool> whitespace_elision = base::nullopt;
};
using ElideTextCaseParam = std::tuple<ElideTextTestOptions, ElideTextCase>;
@@ -1932,14 +1942,19 @@ TEST_P(RenderTextTestWithElideTextCase, ElideText) {
// Set the text and the eliding behavior.
render_text->SetText(text);
render_text->SetElideBehavior(options.elide_behavior);
- render_text->SetWhitespaceElision(false);
+
+ // If specified, set the whitespace elision. Otherwise, keep the eliding
+ // behavior default value.
+ if (param.whitespace_elision.has_value())
+ render_text->SetWhitespaceElision(param.whitespace_elision.value());
// Set the display width to trigger the eliding.
- if (param.available_width_as_glyph_count >= 0) {
- render_text->SetDisplayRect(Rect(
- 0, 0,
- param.available_width_as_glyph_count * kGlyphWidth + kGlyphWidth / 2,
- 100));
+ if (param.available_width_as_glyph_count.has_value()) {
+ render_text->SetDisplayRect(
+ Rect(0, 0,
+ param.available_width_as_glyph_count.value() * kGlyphWidth +
+ kGlyphWidth / 2,
+ 100));
} else {
render_text->SetDisplayRect(
Rect(0, 0, expected_width + kGlyphWidth / 2, 100));
@@ -1987,6 +2002,34 @@ const ElideTextCase kElideHeadTextCases[] = {
// 𝄞 (U+1D11E, MUSICAL SYMBOL G CLEF) should be fully elided.
{"emoji1", L"012\U0001D11Ex", L"\u2026\U0001D11Ex"},
{"emoji2", L"012\U0001D11Ex", L"\u2026x"},
+
+ // Whitespace elision tests.
+ {"empty_no_elision", L"", L"", 0, kForceNoWhitespaceElision},
+ {"empty_elision", L"", L"", 0, kForceWhitespaceElision},
+ {"xyz_no_elision", L" x xyz", L"\u2026 xyz", 5,
+ kForceNoWhitespaceElision},
+ {"xyz_elision", L" x xyz", L"\u2026xyz", 5, kForceWhitespaceElision},
+ {"ltr_rtl_elision3", L"x \u05d1 y \u05d2", L"\u2026\u05d2", 3,
+ kForceWhitespaceElision},
+ {"ltr_rtl_elision6", L"x \u05d1 y \u05d2", L"\u2026\u05d2", 6,
+ kForceWhitespaceElision},
+ {"ltr_rtl_elision7", L"x \u05d1 y \u05d2", L"\u2026y \u05d2", 7,
+ kForceWhitespaceElision},
+ {"ltr_rtl_elision10", L"x \u05d1 y \u05d2",
+ L"\u2026\u05d1 y \u05d2", 10, kForceWhitespaceElision},
+ {"ltr_rtl_elision11", L"x \u05d1 y \u05d2",
+ L"\u2026\u05d1 y \u05d2", 11, kForceWhitespaceElision},
+ // Emoji U+1F601 and emoji U+1F321 U+FE0E are graphemes that result in
+ // one glyph each. Eliding a glyph must remove the whole grapheme. It is
+ // invalid to break a grapheme in pieces.
+ {"graphemes_elision3", L" \U0001F601 \U0001F321\uFE0E ", L"\u2026", 3,
+ kForceWhitespaceElision},
+ {"graphemes_elision4", L" \U0001F601 \U0001F321\uFE0E ",
+ L"\u2026\U0001F321\uFE0E ", 4, kForceWhitespaceElision},
+ {"graphemes_elision6", L" \U0001F601 \U0001F321\uFE0E ",
+ L"\u2026\U0001F321\uFE0E ", 6, kForceWhitespaceElision},
+ {"graphemes_elision7", L" \U0001F601 \U0001F321\uFE0E ",
+ L"\u2026\U0001F601 \U0001F321\uFE0E ", 7, kForceWhitespaceElision},
};
INSTANTIATE_TEST_SUITE_P(
@@ -2001,7 +2044,7 @@ const ElideTextCase kElideTailTextCases[] = {
{"letter_m_tail0", L"M", L""},
{"letter_m_tail1", L"M", L"M"},
{"letter_weak_3", L" . ", L" . "},
- {"letter_weak_2", L" . ", L" \u2026"},
+ {"letter_weak_2", L" . ", L"\u2026"},
{"no_eliding", L"012ab", L"012ab"},
{"ltr_3", L"abc", L"abc"},
{"ltr_2", L"abc", L"a\u2026"},
@@ -2011,15 +2054,15 @@ const ElideTextCase kElideTailTextCases[] = {
{"rtl_2", L"\u05d0\u05d1\u05d2", L"\u05d0\u2026"},
{"rtl_1", L"\u05d0\u05d1\u05d2", L"\u2026"},
{"rtl_0", L"\u05d0\u05d1\u05d2", L""},
- {"ltr_rtl_5", L"abc\u05d0\u05d1\u05d2", L"abc\u05d0\u2026\x200F"},
+ {"ltr_rtl_5", L"abc\u05d0\u05d1\u05d2", L"abc\u05d0\u2026\u200F"},
{"ltr_rtl_4", L"abc\u05d0\u05d1\u05d2", L"abc\u2026"},
{"ltr_rtl_3", L"abc\u05d0\u05d1\u05d2", L"ab\u2026"},
- {"rtl_ltr_5", L"\u05d0\u05d1\u05d2abc", L"\u05d0\u05d1\u05d2a\u2026\x200E"},
+ {"rtl_ltr_5", L"\u05d0\u05d1\u05d2abc", L"\u05d0\u05d1\u05d2a\u2026\u200E"},
{"rtl_ltr_4", L"\u05d0\u05d1\u05d2abc", L"\u05d0\u05d1\u05d2\u2026"},
{"rtl_ltr_3", L"\u05d0\u05d1\u05d2abc", L"\u05d0\u05d1\u2026"},
{"bidi_1", L"012a\u05d1b\u05d1c", L"012a\u2026"},
- {"bidi_2", L"012a\u05d1b\u05d1c", L"012a\u05d1\u2026\x200F"},
- {"bidi_3", L"012a\u05d1b\u05d1c", L"012a\u05d1b\u2026\x200F"},
+ {"bidi_2", L"012a\u05d1b\u05d1c", L"012a\u05d1\u2026\u200F"},
+ {"bidi_3", L"012a\u05d1b\u05d1c", L"012a\u05d1b\u2026"},
// No RLM marker added as digits (012) have weak directionality.
{"no_rlm", L"01\u05d0\u05d1\u05d2", L"01\u05d0\u2026"},
// RLM marker added as "ab" have strong LTR directionality.
@@ -2042,6 +2085,30 @@ const ElideTextCase kElideTailTextCases[] = {
{"grapheme4", L"012\u05e9\u05bc\u05c1\u05b8abc", L"012\u2026\u200E"},
// 𝄞 (U+1D11E, MUSICAL SYMBOL G CLEF) should be fully elided.
{"emoji", L"012\U0001D11Ex", L"012\u2026"},
+
+ // Whitespace elision tests.
+ {"empty_no_elision", L"", L"", 0, kForceNoWhitespaceElision},
+ {"empty_elision", L"", L"", 0, kForceWhitespaceElision},
+ {"letter_weak_2_no_elision", L" . ", L" \u2026", 2,
+ kForceNoWhitespaceElision},
+ {"xyz_no_elision", L" x xyz", L" x \u2026", 5,
+ kForceNoWhitespaceElision},
+ {"xyz_elision", L" x xyz", L" x\u2026", 5, kForceWhitespaceElision},
+ {"ltr_rtl_elision4", L"x \u05d1 y \u05d2", L"x\u2026", 4,
+ kForceWhitespaceElision},
+ {"ltr_rtl_elision5", L"x \u05d1 y \u05d2", L"x \u05d1\u2026\u200F", 5,
+ kForceWhitespaceElision},
+ {"ltr_rtl_elision9", L"x \u05d1 y \u05d2", L"x \u05d1 y\u2026", 9,
+ kForceWhitespaceElision},
+ // Emoji U+1F601 and emoji U+1F321 U+FE0E are graphemes that result in
+ // one glyph each. Eliding a glyph must remove the whole grapheme. It is
+ // invalid to break a grapheme in pieces.
+ {"graphemes_elision3", L" \U0001F601 \U0001F321\uFE0E ", L"\u2026", 3,
+ kForceWhitespaceElision},
+ {"graphemes_elision6", L" \U0001F601 \U0001F321\uFE0E ",
+ L" \U0001F601\u2026", 6, kForceWhitespaceElision},
+ {"graphemes_elision7", L" \U0001F601 \U0001F321\uFE0E ",
+ L" \U0001F601 \U0001F321\uFE0E\u2026", 7, kForceWhitespaceElision},
};
INSTANTIATE_TEST_SUITE_P(
@@ -2089,6 +2156,33 @@ const ElideTextCase kElideTruncateTextCases[] = {
// 𝄞 (U+1D11E, MUSICAL SYMBOL G CLEF) should be fully elided.
{"emoji1", L"012\U0001D11Ex", L"012\U0001D11E"},
{"emoji2", L"012\U0001D11Ex", L"012"},
+
+ // Whitespace elision tests.
+ {"empty_no_elision", L"", L"", 0, kForceNoWhitespaceElision},
+ {"empty_elision", L"", L"", 0, kForceWhitespaceElision},
+ {"xyz_no_elision", L" x xyz", L" x ", 5, kForceNoWhitespaceElision},
+ {"xyz_elision", L" x xyz", L" x", 5, kForceWhitespaceElision},
+ {"ltr_rtl_elision3", L"x \u05d1 y \u05d2", L"x", 3,
+ kForceWhitespaceElision},
+ {"ltr_rtl_elision4", L"x \u05d1 y \u05d2", L"x \u05d1", 4,
+ kForceWhitespaceElision},
+ {"ltr_rtl_elision5", L"x \u05d1 y \u05d2", L"x \u05d1", 5,
+ kForceWhitespaceElision},
+ {"ltr_rtl_elision9", L"x \u05d1 y \u05d2", L"x \u05d1 y", 9,
+ kForceWhitespaceElision},
+ // Emoji U+1F601 and emoji U+1F321 U+FE0E are graphemes that result in
+ // one glyph each. Eliding a glyph must remove the whole grapheme. It is
+ // invalid to break a grapheme in pieces.
+ {"graphemes_elision2", L" \U0001F601 \U0001F321\uFE0E ", L"", 2,
+ kForceWhitespaceElision},
+ {"graphemes_elision3", L" \U0001F601 \U0001F321\uFE0E ", L" \U0001F601",
+ 3, kForceWhitespaceElision},
+ {"graphemes_elision5", L" \U0001F601 \U0001F321\uFE0E ", L" \U0001F601",
+ 5, kForceWhitespaceElision},
+ {"graphemes_elision6", L" \U0001F601 \U0001F321\uFE0E ",
+ L" \U0001F601 \U0001F321\uFE0E", 6, kForceWhitespaceElision},
+ {"graphemes_elision7", L" \U0001F601 \U0001F321\uFE0E ",
+ L" \U0001F601 \U0001F321\uFE0E", 7, kForceWhitespaceElision},
};
INSTANTIATE_TEST_SUITE_P(
@@ -2135,7 +2229,7 @@ const ElideTextCase kElideEmailTextCases[] = {
{"email_nobody7", L"nobody@gmail.com", L"no\u2026@g\u2026m", 7},
{"email_nobody8", L"nobody@gmail.com", L"nob\u2026@g\u2026m", 8},
{"email_nobody9", L"nobody@gmail.com", L"nob\u2026@gm\u2026m", 9},
- {"email_nobody10", L"nobody@gmail.com", L"nobo\x2026@gm\u2026m", 10},
+ {"email_nobody10", L"nobody@gmail.com", L"nobo\u2026@gm\u2026m", 10},
{"email_root", L"root@localhost", L"r\u2026@l\u2026", 5},
{"email_myself", L"myself@127.0.0.1", L"my\u2026@1\u2026", 6},
};
@@ -2182,6 +2276,41 @@ TEST_F(RenderTextTest, ElidedText_NoTrimWhitespace) {
EXPECT_EQ(expected, result);
}
+TEST_F(RenderTextTest, SetElideBehavior) {
+ // This test requires glyphs to be the same width.
+ constexpr int kGlyphWidth = 10;
+ SetGlyphWidth(kGlyphWidth);
+
+ RenderText* render_text = GetRenderText();
+ render_text->SetText(ASCIIToUTF16("abcdef"));
+ render_text->SetCursorEnabled(false);
+ render_text->SetDisplayRect(Rect(0, 0, 3 * kGlyphWidth, 100));
+ render_text->SetElideBehavior(ELIDE_TAIL);
+ EXPECT_EQ(WideToUTF16(L"ab\u2026"), render_text->GetDisplayText());
+
+ // Setting a different eliding behavior must trigger a relayout.
+ render_text->SetElideBehavior(ELIDE_HEAD);
+ EXPECT_EQ(WideToUTF16(L"\u2026ef"), render_text->GetDisplayText());
+}
+
+TEST_F(RenderTextTest, SetWhitespaceElision) {
+ // This test requires glyphs to be the same width.
+ constexpr int kGlyphWidth = 10;
+ SetGlyphWidth(kGlyphWidth);
+
+ RenderText* render_text = GetRenderText();
+ render_text->SetText(ASCIIToUTF16("a b c d"));
+ render_text->SetCursorEnabled(false);
+ render_text->SetDisplayRect(Rect(0, 0, 3 * kGlyphWidth, 100));
+ render_text->SetElideBehavior(ELIDE_TAIL);
+ render_text->SetWhitespaceElision(false);
+ EXPECT_EQ(WideToUTF16(L"a \u2026"), render_text->GetDisplayText());
+
+ // Setting a different whitespace elision must trigger a relayout.
+ render_text->SetWhitespaceElision(true);
+ EXPECT_EQ(WideToUTF16(L"a\u2026"), render_text->GetDisplayText());
+}
+
TEST_F(RenderTextTest, ElidedObscuredText) {
auto expected_render_text = std::make_unique<RenderTextHarfBuzz>();
expected_render_text->SetDisplayRect(Rect(0, 0, 9999, 100));
@@ -3203,6 +3332,56 @@ TEST_F(RenderTextTest, DirectionalityInvalidation) {
EXPECT_EQ(original_text_direction, render_text->GetDisplayTextDirection());
}
+TEST_F(RenderTextTest, MoveCursor_UpDown_Scroll) {
+ RenderText* render_text = GetRenderText();
+ render_text->SetDisplayRect(Rect(100, 30));
+ render_text->SetMultiline(true);
+ render_text->SetVerticalAlignment(ALIGN_TOP);
+
+ const size_t kLineSize = 50;
+ std::string text;
+ for (size_t i = 0; i < kLineSize - 1; ++i)
+ text += "a\n";
+
+ render_text->SetText(ASCIIToUTF16(text));
+ EXPECT_EQ(kLineSize, render_text->GetNumLines());
+
+ // Move cursor down with scroll.
+ render_text->SelectRange(Range(0));
+ // |line_height| is the distance from the top.
+ float line_height =
+ render_text->GetLineSizeF(render_text->selection_model()).height();
+ for (size_t i = 1; i < kLineSize; ++i) {
+ SCOPED_TRACE(base::StringPrintf("Testing line [%" PRIuS "]", i));
+ render_text->MoveCursor(CHARACTER_BREAK, CURSOR_DOWN, SELECTION_NONE);
+ ASSERT_EQ(Range(i * 2), render_text->selection());
+ ASSERT_TRUE(render_text->display_rect().Contains(
+ render_text->GetUpdatedCursorBounds()));
+ line_height +=
+ render_text->GetLineSizeF(render_text->selection_model()).height();
+ ASSERT_FLOAT_EQ(test_api()->display_offset().y(),
+ std::min(0.0f, 30.0f - line_height));
+ }
+
+ // Move cursor up with scroll.
+ // |line_height| is the distance from the bottom.
+ line_height =
+ render_text->GetLineSizeF(render_text->selection_model()).height();
+ int offset_y = test_api()->display_offset().y();
+ for (size_t i = kLineSize - 2; i != size_t{-1}; --i) {
+ SCOPED_TRACE(base::StringPrintf("Testing line [%" PRIuS "]", i));
+ render_text->MoveCursor(CHARACTER_BREAK, CURSOR_UP, SELECTION_NONE);
+ ASSERT_EQ(Range(i * 2), render_text->selection());
+ ASSERT_TRUE(render_text->display_rect().Contains(
+ render_text->GetUpdatedCursorBounds()));
+ line_height +=
+ render_text->GetLineSizeF(render_text->selection_model()).height();
+ ASSERT_FLOAT_EQ(test_api()->display_offset().y(),
+ offset_y + std::max(0.0f, line_height - 30.0f));
+ }
+ EXPECT_EQ(0, test_api()->display_offset().y());
+}
+
TEST_F(RenderTextTest, GetDisplayTextDirection) {
struct {
const char* text;
@@ -5915,13 +6094,6 @@ TEST_F(RenderTextTest, Multiline_SurrogatePairsOrCombiningChars) {
TEST_F(RenderTextTest, Multiline_ZeroWidthChars) {
RenderTextHarfBuzz* render_text = GetRenderText();
-#if defined(OS_APPLE)
- // Don't use Helvetica Neue on 10.10 - it has a buggy zero-width space that
- // actually gets some width. See http://crbug.com/799333.
- if (base::mac::IsOS10_10())
- render_text->SetFontList(FontList("Arial, 12px"));
-#endif
-
render_text->SetMultiline(true);
render_text->SetWordWrapBehavior(WRAP_LONG_WORDS);
diff --git a/chromium/ui/gfx/rendering_pipeline.cc b/chromium/ui/gfx/rendering_pipeline.cc
new file mode 100644
index 00000000000..6790edbf233
--- /dev/null
+++ b/chromium/ui/gfx/rendering_pipeline.cc
@@ -0,0 +1,298 @@
+// Copyright 2020 The Chromium 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/rendering_pipeline.h"
+
+#include "base/task/current_thread.h"
+#include "base/task/sequence_manager/task_time_observer.h"
+#include "base/thread_annotations.h"
+#include "base/threading/thread_checker.h"
+#include "ui/gfx/rendering_stage_scheduler.h"
+
+namespace gfx {
+namespace {
+
+class ThreadSafeTimeObserver : public base::sequence_manager::TaskTimeObserver {
+ public:
+ explicit ThreadSafeTimeObserver(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : task_runner_(std::move(task_runner)) {}
+ ~ThreadSafeTimeObserver() override {
+ // If the observer is being used on the target thread, unregister now. If it
+ // was being used on a different thread, then the target thread should have
+ // been torn down already.
+ SetEnabled(false);
+ }
+
+ ThreadSafeTimeObserver(const ThreadSafeTimeObserver&) = delete;
+ ThreadSafeTimeObserver& operator=(const ThreadSafeTimeObserver&) = delete;
+
+ void SetEnabled(bool enabled) {
+ {
+ base::AutoLock hold(time_lock_);
+ if (enabled_ == enabled)
+ return;
+ enabled_ = enabled;
+ }
+
+ if (!task_runner_)
+ return;
+
+ if (task_runner_->BelongsToCurrentThread()) {
+ UpdateOnTargetThread(enabled);
+ return;
+ }
+
+ task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&ThreadSafeTimeObserver::UpdateOnTargetThread,
+ base::Unretained(this), enabled));
+ }
+
+ base::TimeDelta GetAndResetTimeSinceLastFrame() {
+ base::AutoLock hold(time_lock_);
+
+ if (!start_time_active_task_.is_null()) {
+ auto now = base::TimeTicks::Now();
+ time_since_last_frame_ += now - start_time_active_task_;
+ start_time_active_task_ = now;
+ }
+
+ auto result = time_since_last_frame_;
+ time_since_last_frame_ = base::TimeDelta();
+ return result;
+ }
+
+ // TaskTimeObserver impl.
+ void WillProcessTask(base::TimeTicks start_time) override {
+ base::AutoLock hold(time_lock_);
+ if (!enabled_)
+ return;
+
+ DCHECK(start_time_active_task_.is_null());
+ start_time_active_task_ = start_time;
+ }
+
+ void DidProcessTask(base::TimeTicks start_time,
+ base::TimeTicks end_time) override {
+ base::AutoLock hold(time_lock_);
+ if (!enabled_) {
+ start_time_active_task_ = base::TimeTicks();
+ return;
+ }
+
+ // This should be null for the task which adds this object to the observer
+ // list.
+ if (start_time_active_task_.is_null())
+ return;
+
+ if (start_time_active_task_ <= end_time) {
+ time_since_last_frame_ += (end_time - start_time_active_task_);
+ } else {
+ // This could happen if |GetAndResetTimeSinceLastFrame| is called on a
+ // different thread and the observed thread had to wait to acquire the
+ // lock to call DidProcessTask. Assume the time for this task is already
+ // recorded in |GetAndResetTimeSinceLastFrame|.
+ DCHECK_NE(start_time_active_task_, start_time);
+ }
+
+ start_time_active_task_ = base::TimeTicks();
+ }
+
+ private:
+ void UpdateOnTargetThread(bool enabled) {
+ if (enabled) {
+ base::CurrentThread::Get().AddTaskTimeObserver(this);
+
+ base::AutoLock hold(time_lock_);
+ start_time_active_task_ = base::TimeTicks();
+ time_since_last_frame_ = base::TimeDelta();
+ } else {
+ base::CurrentThread::Get().RemoveTaskTimeObserver(this);
+ }
+ }
+
+ // Accessed only on the calling thread. The caller ensures no concurrent
+ // access.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ // Accessed on calling and target thread.
+ base::Lock time_lock_;
+ bool enabled_ GUARDED_BY(time_lock_) = false;
+ base::TimeTicks start_time_active_task_ GUARDED_BY(time_lock_);
+ base::TimeDelta time_since_last_frame_ GUARDED_BY(time_lock_);
+};
+
+} // namespace
+
+class RenderingPipelineImpl final : public RenderingPipeline {
+ public:
+ explicit RenderingPipelineImpl(const char* pipeline_type)
+ : pipeline_type_(pipeline_type) {
+ RenderingStageScheduler::EnsureInitialized();
+ DETACH_FROM_THREAD(bound_thread_);
+ }
+ ~RenderingPipelineImpl() override { TearDown(); }
+
+ RenderingPipelineImpl(const RenderingPipelineImpl&) = delete;
+ RenderingPipelineImpl& operator=(const RenderingPipelineImpl&) = delete;
+
+ void SetTargetDuration(base::TimeDelta target_duration) override {
+ DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
+ DCHECK(!target_duration.is_zero());
+
+ if (target_duration_ == target_duration)
+ return;
+
+ target_duration_ = target_duration;
+ if (should_use_scheduler())
+ SetUp();
+ }
+
+ void AddSequenceManagerThread(
+ base::PlatformThreadId thread_id,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
+ base::AutoLock lock(lock_);
+ DCHECK(time_observers_.find(thread_id) == time_observers_.end());
+ time_observers_[thread_id] =
+ std::make_unique<ThreadSafeTimeObserver>(task_runner);
+ if (scheduler_)
+ CreateSchedulerAndEnableWithLockAcquired();
+ }
+
+ base::sequence_manager::TaskTimeObserver* AddSimpleThread(
+ base::PlatformThreadId thread_id) override {
+ base::AutoLock lock(lock_);
+ DCHECK(time_observers_.find(thread_id) == time_observers_.end());
+ time_observers_[thread_id] =
+ std::make_unique<ThreadSafeTimeObserver>(nullptr);
+
+ if (scheduler_)
+ CreateSchedulerAndEnableWithLockAcquired();
+ return time_observers_[thread_id].get();
+ }
+
+ void NotifyFrameFinished() override {
+ DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
+
+ base::AutoLock lock(lock_);
+ if (!scheduler_)
+ return;
+
+ // TODO(crbug.com/1157620): This can be optimized to exclude tasks which can
+ // be paused during rendering. The best use-case is idle tasks on the
+ // renderer main thread. If all non-optional work is close to the frame
+ // budget then the scheduler dynamically adjusts to pause work like idle
+ // tasks.
+ base::TimeDelta total_time;
+ for (auto& it : time_observers_) {
+ total_time += it.second->GetAndResetTimeSinceLastFrame();
+ }
+ scheduler_->ReportCpuCompletionTime(total_time + gpu_latency_);
+ }
+
+ void SetGpuLatency(base::TimeDelta gpu_latency) override {
+ DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
+ gpu_latency_ = gpu_latency;
+ }
+
+ void UpdateActiveCount(bool active) override {
+ DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
+
+ if (active) {
+ active_count_++;
+ } else {
+ DCHECK_GT(active_count_, 0);
+ active_count_--;
+ }
+
+ if (should_use_scheduler()) {
+ SetUp();
+ } else {
+ TearDown();
+ }
+ }
+
+ private:
+ bool should_use_scheduler() const {
+ // TODO(crbug.com/1157620) : Figure out what we should be doing if multiple
+ // independent pipelines of a type are running simultaneously. The common
+ // use-case for this in practice would be multi-window. The tabs could be
+ // hosted in the same renderer process and each window is composited
+ // independently by the GPU process.
+ return active_count_ == 1 && !target_duration_.is_zero();
+ }
+
+ void SetUp() {
+ base::AutoLock lock(lock_);
+ CreateSchedulerAndEnableWithLockAcquired();
+ }
+
+ void CreateSchedulerAndEnableWithLockAcquired() {
+ lock_.AssertAcquired();
+ scheduler_.reset();
+
+ std::vector<base::PlatformThreadId> platform_threads;
+ for (auto& it : time_observers_) {
+ platform_threads.push_back(it.first);
+ it.second->SetEnabled(true);
+ }
+
+ scheduler_ = RenderingStageScheduler::CreateAdpf(
+ pipeline_type_, std::move(platform_threads), target_duration_);
+ }
+
+ void TearDown() {
+ base::AutoLock lock(lock_);
+ for (auto& it : time_observers_)
+ it.second->SetEnabled(false);
+ scheduler_.reset();
+ }
+
+ THREAD_CHECKER(bound_thread_);
+
+ base::Lock lock_;
+ base::flat_map<base::PlatformThreadId,
+ std::unique_ptr<ThreadSafeTimeObserver>>
+ time_observers_ GUARDED_BY(lock_);
+ std::unique_ptr<RenderingStageScheduler> scheduler_ GUARDED_BY(lock_);
+
+ // Pipeline name, for tracing and metrics.
+ const char* pipeline_type_;
+
+ // The number of currently active pipelines of this type.
+ int active_count_ = 0;
+
+ // The target time for this rendering stage for a frame.
+ base::TimeDelta target_duration_;
+
+ base::TimeDelta gpu_latency_;
+};
+
+RenderingPipeline::ScopedPipelineActive::ScopedPipelineActive(
+ RenderingPipeline* pipeline)
+ : pipeline_(pipeline) {
+ pipeline_->UpdateActiveCount(true);
+}
+
+RenderingPipeline::ScopedPipelineActive::~ScopedPipelineActive() {
+ pipeline_->UpdateActiveCount(false);
+}
+
+std::unique_ptr<RenderingPipeline> RenderingPipeline::CreateRendererMain() {
+ static constexpr char kRendererMain[] = "RendererMain";
+ return std::make_unique<RenderingPipelineImpl>(kRendererMain);
+}
+
+std::unique_ptr<RenderingPipeline>
+RenderingPipeline::CreateRendererCompositor() {
+ static constexpr char kRendererCompositor[] = "RendererCompositor";
+ return std::make_unique<RenderingPipelineImpl>(kRendererCompositor);
+}
+
+std::unique_ptr<RenderingPipeline> RenderingPipeline::CreateGpu() {
+ static constexpr char kGpu[] = "Gpu";
+ return std::make_unique<RenderingPipelineImpl>(kGpu);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/rendering_pipeline.h b/chromium/ui/gfx/rendering_pipeline.h
new file mode 100644
index 00000000000..f832244c6c8
--- /dev/null
+++ b/chromium/ui/gfx/rendering_pipeline.h
@@ -0,0 +1,83 @@
+// Copyright 2020 The Chromium 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_RENDERING_PIPELINE_H_
+#define UI_GFX_RENDERING_PIPELINE_H_
+
+#include "base/containers/flat_map.h"
+#include "base/memory/singleton.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/platform_thread.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace base {
+namespace sequence_manager {
+class TaskTimeObserver;
+}
+} // namespace base
+
+namespace gfx {
+
+// Tracks the desired and actual execution time of rendering threads to
+// optimally schedule them on the CPU. Instances of this class should be shared
+// between all compositors of the same rendering stage.
+//
+// This class can be created on any thread but becomes bound to the thread it's
+// subsequently used on. The class may be destroyed on any thread but the caller
+// is responsible for ensuring all other threads in the rendering stage, other
+// than the thread the object is destroyed on, are torn down before destroying
+// an instance of this class.
+class GFX_EXPORT RenderingPipeline {
+ public:
+ // Notifies when this pipeline is active. Multiple pipelines of the same type
+ // can be concurrently active at a time. The pipeline is assumed active for
+ // the lifetime of this object.
+ class GFX_EXPORT ScopedPipelineActive {
+ public:
+ explicit ScopedPipelineActive(RenderingPipeline* pipeline);
+ ~ScopedPipelineActive();
+
+ private:
+ RenderingPipeline* const pipeline_;
+ };
+
+ static std::unique_ptr<RenderingPipeline> CreateRendererMain();
+ static std::unique_ptr<RenderingPipeline> CreateRendererCompositor();
+ static std::unique_ptr<RenderingPipeline> CreateGpu();
+
+ virtual ~RenderingPipeline() = default;
+
+ // Add to this pipeline a thread backed by base sequence manager, where
+ // |base::CurrentThread| works. Most threads in chromium should fall into
+ // this category.
+ // This method is thread safe and can be called on any thread.
+ virtual void AddSequenceManagerThread(
+ base::PlatformThreadId thread_id,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) = 0;
+
+ // Add a simple thread to this pipeline. The caller is responsible for
+ // updating the returned observer for tasks executed on the thread.
+ // The returned observer is owned by this pipeline object.
+ // This method is thread safe and can be called on any thread.
+ virtual base::sequence_manager::TaskTimeObserver* AddSimpleThread(
+ base::PlatformThreadId thread_id) = 0;
+
+ // Notifies when this pipeline stage has finished rendering to compute the
+ // execution time per frame for the associated threads.
+ virtual void NotifyFrameFinished() = 0;
+
+ // Sets the desired duration for this pipeline.
+ virtual void SetTargetDuration(base::TimeDelta target_duration) = 0;
+
+ // Sets the latency from composition for a display buffer finishing on the
+ // Gpu thread to when execution finished on the Gpu.
+ virtual void SetGpuLatency(base::TimeDelta delta) = 0;
+
+ protected:
+ virtual void UpdateActiveCount(bool active) = 0;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_RENDERING_PIPELINE_H_
diff --git a/chromium/ui/gfx/rendering_stage_scheduler.cc b/chromium/ui/gfx/rendering_stage_scheduler.cc
new file mode 100644
index 00000000000..58c365c9f30
--- /dev/null
+++ b/chromium/ui/gfx/rendering_stage_scheduler.cc
@@ -0,0 +1,163 @@
+// Copyright 2020 The Chromium 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/rendering_stage_scheduler.h"
+
+#include "base/logging.h"
+#include "base/native_library.h"
+#include "base/no_destructor.h"
+#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+
+#include <dlfcn.h>
+#include <sys/types.h>
+
+extern "C" {
+
+typedef struct APowerManager APowerManager;
+
+using pAPower_acquireManager = APowerManager* (*)();
+using pAPower_createThreadGroup = int64_t (*)(APowerManager* manager,
+ pid_t* threadIds,
+ size_t numThreadIds,
+ uint64_t desiredDurationMicros);
+using pAPower_destroyThreadGroup =
+ void (*)(APowerManager* manager, int64_t /* ThreadGroupId */ threadGroup);
+using pAPower_updateThreadGroupDesiredDuration =
+ void (*)(APowerManager* manager,
+ int64_t /* ThreadGroupId */ threadGroup,
+ uint64_t desiredDurationMicros);
+using pAPower_reportThreadGroupDuration =
+ void (*)(APowerManager* manager,
+ int64_t /* ThreadGroupId */ threadGroup,
+ uint64_t actualDurationMicros);
+}
+
+#endif // OS_ANDROID
+
+namespace gfx {
+namespace {
+
+#if defined(OS_ANDROID)
+
+#define LOAD_FUNCTION(lib, func) \
+ do { \
+ func##Fn = reinterpret_cast<p##func>( \
+ base::GetFunctionPointerFromNativeLibrary(lib, #func)); \
+ if (!func##Fn) { \
+ supported = false; \
+ LOG(ERROR) << "Unable to load function " << #func; \
+ } \
+ } while (0)
+
+struct AdpfMethods {
+ static const AdpfMethods& Get() {
+ static const base::NoDestructor<AdpfMethods> instance;
+ return *instance;
+ }
+
+ AdpfMethods() {
+ base::NativeLibraryLoadError error;
+ base::NativeLibrary main_dl_handle =
+ base::LoadNativeLibrary(base::FilePath("libandroid.so"), &error);
+ if (!main_dl_handle) {
+ LOG(ERROR) << "Couldnt load libandroid.so: " << error.ToString();
+ supported = false;
+ return;
+ }
+
+ LOAD_FUNCTION(main_dl_handle, APower_acquireManager);
+ LOAD_FUNCTION(main_dl_handle, APower_createThreadGroup);
+ LOAD_FUNCTION(main_dl_handle, APower_destroyThreadGroup);
+ LOAD_FUNCTION(main_dl_handle, APower_updateThreadGroupDesiredDuration);
+ LOAD_FUNCTION(main_dl_handle, APower_reportThreadGroupDuration);
+ }
+
+ ~AdpfMethods() = default;
+
+ bool supported = true;
+ pAPower_acquireManager APower_acquireManagerFn;
+ pAPower_createThreadGroup APower_createThreadGroupFn;
+ pAPower_destroyThreadGroup APower_destroyThreadGroupFn;
+ pAPower_updateThreadGroupDesiredDuration
+ APower_updateThreadGroupDesiredDurationFn;
+ pAPower_reportThreadGroupDuration APower_reportThreadGroupDurationFn;
+};
+
+APowerManager* GetPowerManager() {
+ static APowerManager* power_manager =
+ AdpfMethods::Get().supported
+ ? AdpfMethods::Get().APower_acquireManagerFn()
+ : nullptr;
+ return power_manager;
+}
+
+class RenderingStageSchedulerAdpf : public RenderingStageScheduler {
+ public:
+ RenderingStageSchedulerAdpf(const char* pipeline_type,
+ std::vector<base::PlatformThreadId> threads,
+ base::TimeDelta desired_duration)
+ : pipeline_type_(pipeline_type), desired_duration_(desired_duration) {
+ static_assert(sizeof(base::PlatformThreadId) == sizeof(pid_t),
+ "thread id types incompatible");
+
+ if (!GetPowerManager())
+ return;
+
+ id_ = AdpfMethods::Get().APower_createThreadGroupFn(
+ GetPowerManager(), threads.data(), threads.size(),
+ desired_duration.InMicroseconds());
+ }
+
+ ~RenderingStageSchedulerAdpf() override {
+ if (!GetPowerManager())
+ return;
+
+ AdpfMethods::Get().APower_destroyThreadGroupFn(GetPowerManager(), id_);
+ }
+
+ void ReportCpuCompletionTime(base::TimeDelta actual_duration) override {
+ TRACE_EVENT_INSTANT2(
+ "benchmark", "RenderingStageSchedulerAdpf::ReportCpuCompletionTime",
+ TRACE_EVENT_SCOPE_THREAD, "pipeline_type", pipeline_type_,
+ "utilization_percentage",
+ static_cast<int>(actual_duration * 100 / desired_duration_));
+
+ if (!GetPowerManager())
+ return;
+
+ AdpfMethods::Get().APower_reportThreadGroupDurationFn(
+ GetPowerManager(), id_, actual_duration.InMicroseconds());
+ }
+
+ private:
+ int64_t id_;
+ const char* pipeline_type_;
+ const base::TimeDelta desired_duration_;
+};
+
+#endif // OS_ANDROID
+
+} // namespace
+
+void RenderingStageScheduler::EnsureInitialized() {
+#if defined(OS_ANDROID)
+ AdpfMethods::Get();
+#endif
+}
+
+std::unique_ptr<RenderingStageScheduler> RenderingStageScheduler::CreateAdpf(
+ const char* pipeline_type,
+ std::vector<base::PlatformThreadId> threads,
+ base::TimeDelta desired_duration) {
+#if defined(OS_ANDROID)
+ return std::make_unique<RenderingStageSchedulerAdpf>(
+ pipeline_type, std::move(threads), desired_duration);
+#endif
+ return nullptr;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/rendering_stage_scheduler.h b/chromium/ui/gfx/rendering_stage_scheduler.h
new file mode 100644
index 00000000000..3c00f17b431
--- /dev/null
+++ b/chromium/ui/gfx/rendering_stage_scheduler.h
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium 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_RENDERING_STAGE_SCHEDULER_H_
+#define UI_GFX_RENDERING_STAGE_SCHEDULER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/threading/platform_thread.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+class GFX_EXPORT RenderingStageScheduler {
+ public:
+ // Creating instances of this class requires loading native libraries which
+ // require synchronous file access. This method ensures the synchronous work
+ // is finished.
+ static void EnsureInitialized();
+
+ static std::unique_ptr<RenderingStageScheduler> CreateAdpf(
+ const char* pipeline_type,
+ std::vector<base::PlatformThreadId> threads,
+ base::TimeDelta desired_duration);
+
+ virtual ~RenderingStageScheduler() = default;
+
+ virtual void ReportCpuCompletionTime(base::TimeDelta actual_duration) = 0;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_RENDERING_STAGE_SCHEDULER_H_
diff --git a/chromium/ui/gfx/rrect_f.cc b/chromium/ui/gfx/rrect_f.cc
index c58e0cfdad4..8a8d3c37cca 100644
--- a/chromium/ui/gfx/rrect_f.cc
+++ b/chromium/ui/gfx/rrect_f.cc
@@ -66,8 +66,9 @@ gfx::Vector2dF RRectF::GetSimpleRadii() const {
}
float RRectF::GetSimpleRadius() const {
- DCHECK(GetType() <= Type::kSingle);
+ DCHECK(GetType() <= Type::kOval);
SkPoint result = skrrect_.getSimpleRadii();
+ DCHECK_EQ(result.x(), result.y());
return result.x();
}
@@ -85,6 +86,10 @@ RRectF::Type RRectF::GetType() const {
}
return Type::kSimple;
case SkRRect::kOval_Type:
+ rad = skrrect_.getSimpleRadii();
+ if (rad.x() == rad.y()) {
+ return Type::kSingle;
+ }
return Type::kOval;
case SkRRect::kNinePatch_Type:
case SkRRect::kComplex_Type:
diff --git a/chromium/ui/gfx/rrect_f.h b/chromium/ui/gfx/rrect_f.h
index c7687c3c9be..61893646875 100644
--- a/chromium/ui/gfx/rrect_f.h
+++ b/chromium/ui/gfx/rrect_f.h
@@ -105,7 +105,7 @@ class GEOMETRY_SKIA_EXPORT RRectF {
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.
+ // radii all equal to height/2, and x_rad != y_rad.
kComplex, // Non-zero width and height, and arbitrary (non-equal) radii.
};
Type GetType() const;
diff --git a/chromium/ui/gfx/rrect_f_unittest.cc b/chromium/ui/gfx/rrect_f_unittest.cc
index 3630c0204f6..6338797f8bc 100644
--- a/chromium/ui/gfx/rrect_f_unittest.cc
+++ b/chromium/ui/gfx/rrect_f_unittest.cc
@@ -63,6 +63,8 @@ TEST(RRectFTest, RRectTypes) {
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, 60, 30, 30);
+ 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);
diff --git a/chromium/ui/gfx/skbitmap_operations.cc b/chromium/ui/gfx/skbitmap_operations.cc
index 0a3fc8bf20a..9bcbd2efbb2 100644
--- a/chromium/ui/gfx/skbitmap_operations.cc
+++ b/chromium/ui/gfx/skbitmap_operations.cc
@@ -15,14 +15,21 @@
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkColorPriv.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
-#include "third_party/skia/include/effects/SkBlurImageFilter.h"
+#include "third_party/skia/include/effects/SkImageFilters.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
+static bool IsUninitializedBitmap(const SkBitmap& bitmap) {
+ return bitmap.isNull() && bitmap.colorType() == kUnknown_SkColorType &&
+ bitmap.alphaType() == kUnknown_SkAlphaType;
+}
+
// static
SkBitmap SkBitmapOperations::CreateInvertedBitmap(const SkBitmap& image) {
- DCHECK(image.colorType() == kN32_SkColorType);
+ if (IsUninitializedBitmap(image))
+ return image;
+ CHECK_EQ(image.colorType(), kN32_SkColorType);
SkBitmap inverted;
inverted.allocN32Pixels(image.width(), image.height());
@@ -46,10 +53,10 @@ SkBitmap SkBitmapOperations::CreateBlendedBitmap(const SkBitmap& first,
const SkBitmap& second,
double alpha) {
DCHECK((alpha >= 0) && (alpha <= 1));
- DCHECK(first.width() == second.width());
- DCHECK(first.height() == second.height());
- DCHECK(first.bytesPerPixel() == second.bytesPerPixel());
- DCHECK(first.colorType() == kN32_SkColorType);
+ CHECK_EQ(first.width(), second.width());
+ CHECK_EQ(first.height(), second.height());
+ CHECK_EQ(first.colorType(), kN32_SkColorType);
+ CHECK_EQ(second.colorType(), kN32_SkColorType);
// Optimize for case where we won't need to blend anything.
static const double alpha_min = 1.0 / 255;
@@ -92,11 +99,10 @@ SkBitmap SkBitmapOperations::CreateBlendedBitmap(const SkBitmap& first,
// static
SkBitmap SkBitmapOperations::CreateMaskedBitmap(const SkBitmap& rgb,
const SkBitmap& alpha) {
- DCHECK(rgb.width() == alpha.width());
- DCHECK(rgb.height() == alpha.height());
- DCHECK(rgb.bytesPerPixel() == alpha.bytesPerPixel());
- DCHECK(rgb.colorType() == kN32_SkColorType);
- DCHECK(alpha.colorType() == kN32_SkColorType);
+ CHECK_EQ(rgb.width(), alpha.width());
+ CHECK_EQ(rgb.height(), alpha.height());
+ CHECK_EQ(rgb.colorType(), kN32_SkColorType);
+ CHECK_EQ(alpha.colorType(), kN32_SkColorType);
SkBitmap masked;
masked.allocN32Pixels(rgb.width(), rgb.height());
@@ -120,11 +126,8 @@ SkBitmap SkBitmapOperations::CreateMaskedBitmap(const SkBitmap& rgb,
SkBitmap SkBitmapOperations::CreateButtonBackground(SkColor color,
const SkBitmap& image,
const SkBitmap& mask) {
- // Despite this assert, it seems like image is actually unpremultiplied.
- // The math producing dst_row[x] below is a correct SrcOver when
- // bg_* are premultiplied and img_* are unpremultiplied.
- DCHECK(image.colorType() == kN32_SkColorType);
- DCHECK(mask.colorType() == kN32_SkColorType);
+ CHECK_EQ(image.colorType(), kN32_SkColorType);
+ CHECK_EQ(mask.colorType(), kN32_SkColorType);
SkBitmap background;
background.allocN32Pixels(mask.width(), mask.height());
@@ -476,6 +479,10 @@ const LineProcessor kLineProcessors[kNumHOps][kNumSOps][kNumLOps] = {
SkBitmap SkBitmapOperations::CreateHSLShiftedBitmap(
const SkBitmap& bitmap,
const color_utils::HSL& hsl_shift) {
+ if (IsUninitializedBitmap(bitmap))
+ return bitmap;
+ CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
+
// Default to NOPs.
HSLShift::OperationOnH H_op = HSLShift::kOpHNone;
HSLShift::OperationOnS S_op = HSLShift::kOpSNone;
@@ -520,7 +527,7 @@ SkBitmap SkBitmapOperations::CreateHSLShiftedBitmap(
SkBitmap SkBitmapOperations::CreateTiledBitmap(const SkBitmap& source,
int src_x, int src_y,
int dst_w, int dst_h) {
- DCHECK(source.colorType() == kN32_SkColorType);
+ CHECK_EQ(source.colorType(), kN32_SkColorType);
SkBitmap cropped;
cropped.allocN32Pixels(dst_w, dst_h);
@@ -563,6 +570,10 @@ SkBitmap SkBitmapOperations::DownsampleByTwoUntilSize(const SkBitmap& bitmap,
// static
SkBitmap SkBitmapOperations::DownsampleByTwo(const SkBitmap& bitmap) {
+ if (IsUninitializedBitmap(bitmap))
+ return bitmap;
+ CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
+
// Handle the nop case.
if ((bitmap.width() <= 1) || (bitmap.height() <= 1))
return bitmap;
@@ -626,12 +637,12 @@ SkBitmap SkBitmapOperations::DownsampleByTwo(const SkBitmap& bitmap) {
// static
SkBitmap SkBitmapOperations::UnPreMultiply(const SkBitmap& bitmap) {
- if (bitmap.isNull())
+ if (IsUninitializedBitmap(bitmap))
return bitmap;
+ CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
+
if (bitmap.alphaType() != kPremul_SkAlphaType)
return bitmap;
- // It's expected this code is called with a 32bpp image.
- CHECK_EQ(kN32_SkColorType, bitmap.colorType());
const SkImageInfo& opaque_info =
bitmap.info().makeAlphaType(kUnpremul_SkAlphaType);
@@ -652,7 +663,9 @@ SkBitmap SkBitmapOperations::UnPreMultiply(const SkBitmap& bitmap) {
// static
SkBitmap SkBitmapOperations::CreateTransposedBitmap(const SkBitmap& image) {
- DCHECK(image.colorType() == kN32_SkColorType);
+ if (IsUninitializedBitmap(image))
+ return image;
+ CHECK_EQ(image.colorType(), kN32_SkColorType);
SkBitmap transposed;
transposed.allocN32Pixels(image.height(), image.width());
@@ -671,7 +684,7 @@ SkBitmap SkBitmapOperations::CreateTransposedBitmap(const SkBitmap& image) {
// static
SkBitmap SkBitmapOperations::CreateColorMask(const SkBitmap& bitmap,
SkColor c) {
- DCHECK(bitmap.colorType() == kN32_SkColorType);
+ CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
SkBitmap color_mask;
color_mask.allocN32Pixels(bitmap.width(), bitmap.height());
@@ -681,7 +694,7 @@ SkBitmap SkBitmapOperations::CreateColorMask(const SkBitmap& bitmap,
SkPaint paint;
paint.setColorFilter(SkColorFilters::Blend(c, SkBlendMode::kSrcIn));
- canvas.drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0), &paint);
+ canvas.drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);
return color_mask;
}
@@ -689,7 +702,7 @@ SkBitmap SkBitmapOperations::CreateColorMask(const SkBitmap& bitmap,
SkBitmap SkBitmapOperations::CreateDropShadow(
const SkBitmap& bitmap,
const gfx::ShadowValues& shadows) {
- DCHECK(bitmap.colorType() == kN32_SkColorType);
+ CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
// Shadow margin insets are negative values because they grow outside.
// Negate them here as grow direction is not important and only pixel value
@@ -714,22 +727,24 @@ SkBitmap SkBitmapOperations::CreateDropShadow(
// The blur is halved to produce a shadow that correctly fits within the
// |shadow_margin|.
SkScalar sigma = SkDoubleToScalar(shadow.blur() / 2);
- paint.setImageFilter(SkBlurImageFilter::Make(sigma, sigma, nullptr));
+ paint.setImageFilter(SkImageFilters::Blur(sigma, sigma, nullptr));
canvas.saveLayer(0, &paint);
- canvas.drawBitmap(shadow_image,
- SkIntToScalar(shadow.x()),
- SkIntToScalar(shadow.y()));
+ canvas.drawImage(shadow_image.asImage(), SkIntToScalar(shadow.x()),
+ SkIntToScalar(shadow.y()));
canvas.restore();
}
- canvas.drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0));
+ canvas.drawImage(bitmap.asImage(), 0, 0);
return image_with_shadow;
}
// static
SkBitmap SkBitmapOperations::Rotate(const SkBitmap& source,
RotationAmount rotation) {
+ if (IsUninitializedBitmap(source))
+ return source;
+ CHECK_EQ(source.colorType(), kN32_SkColorType);
// SkCanvas::drawBitmap() fails silently with unpremultiplied SkBitmap.
DCHECK_NE(source.info().alphaType(), kUnpremul_SkAlphaType);
@@ -759,7 +774,7 @@ SkBitmap SkBitmapOperations::Rotate(const SkBitmap& source,
canvas.rotate(angle);
canvas.translate(-SkFloatToScalar(source.width() * 0.5f),
-SkFloatToScalar(source.height() * 0.5f));
- canvas.drawBitmap(source, 0, 0);
+ canvas.drawImage(source.asImage(), 0, 0);
canvas.flush();
return result;
diff --git a/chromium/ui/gfx/skia_util.cc b/chromium/ui/gfx/skia_util.cc
index 68ecba0144e..a2686b04203 100644
--- a/chromium/ui/gfx/skia_util.cc
+++ b/chromium/ui/gfx/skia_util.cc
@@ -13,7 +13,6 @@
#include "third_party/skia/include/core/SkColorPriv.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
-#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
#include "ui/gfx/geometry/quad_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
diff --git a/chromium/ui/gfx/system_fonts_win_unittest.cc b/chromium/ui/gfx/system_fonts_win_unittest.cc
index 502c2e864b4..77559e2a516 100644
--- a/chromium/ui/gfx/system_fonts_win_unittest.cc
+++ b/chromium/ui/gfx/system_fonts_win_unittest.cc
@@ -34,7 +34,7 @@ class SystemFontsWinTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(SystemFontsWinTest);
};
-LOGFONT CreateLOGFONT(const base::char16* name, LONG height) {
+LOGFONT CreateLOGFONT(const wchar_t* name, LONG height) {
LOGFONT logfont = {};
logfont.lfHeight = height;
auto result = wcscpy_s(logfont.lfFaceName, name);
@@ -42,8 +42,8 @@ LOGFONT CreateLOGFONT(const base::char16* name, LONG height) {
return logfont;
}
-const base::char16 kSegoeUI[] = L"Segoe UI";
-const base::char16 kArial[] = L"Arial";
+const wchar_t kSegoeUI[] = L"Segoe UI";
+const wchar_t kArial[] = L"Arial";
} // namespace
diff --git a/chromium/ui/gfx/text_elider_unittest.cc b/chromium/ui/gfx/text_elider_unittest.cc
index d7fa4b86b09..5839ba76d76 100644
--- a/chromium/ui/gfx/text_elider_unittest.cc
+++ b/chromium/ui/gfx/text_elider_unittest.cc
@@ -13,12 +13,14 @@
#include "base/files/file_path.h"
#include "base/i18n/rtl.h"
+#include "base/logging.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 "base/test/task_environment.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font.h"
#include "ui/gfx/font_list.h"
@@ -762,31 +764,31 @@ TEST(TextEliderTest, ElideRectangleText) {
bool truncated_y;
const char* output;
} cases[] = {
- { "", 0, 0, false, NULL },
- { "", 1, 1, false, NULL },
- { "Test", test_width, 0, true, NULL },
- { "Test", test_width, 1, false, "Test" },
- { "Test", test_width, line_height, false, "Test" },
- { "Test Test", test_width, line_height, true, "Test" },
- { "Test Test", test_width, line_height + 1, false, "Test|Test" },
- { "Test Test", test_width, line_height * 2, false, "Test|Test" },
- { "Test Test", test_width, line_height * 3, false, "Test|Test" },
- { "Test Test", test_width * 2, line_height * 2, false, "Test|Test" },
- { "Test Test", test_width * 3, line_height, false, "Test Test" },
- { "Test\nTest", test_width * 3, line_height * 2, false, "Test|Test" },
- { "Te\nst Te", test_width, line_height * 3, false, "Te|st|Te" },
- { "\nTest", test_width, line_height * 2, false, "|Test" },
- { "\nTest", test_width, line_height, true, "" },
- { "\n\nTest", test_width, line_height * 3, false, "||Test" },
- { "\n\nTest", test_width, line_height * 2, true, "|" },
- { "Test\n", 2 * test_width, line_height * 5, false, "Test|" },
- { "Test\n\n", 2 * test_width, line_height * 5, false, "Test||" },
- { "Test\n\n\n", 2 * test_width, line_height * 5, false, "Test|||" },
- { "Test\nTest\n\n", 2 * test_width, line_height * 5, false, "Test|Test||" },
- { "Test\n\nTest\n", 2 * test_width, line_height * 5, false, "Test||Test|" },
- { "Test\n\n\nTest", 2 * test_width, line_height * 5, false, "Test|||Test" },
- { "Te ", test_width, line_height, false, "Te" },
- { "Te Te Test", test_width, 3 * line_height, false, "Te|Te|Test" },
+ {"", 0, 0, false, nullptr},
+ {"", 1, 1, false, nullptr},
+ {"Test", test_width, 0, true, nullptr},
+ {"Test", test_width, 1, false, "Test"},
+ {"Test", test_width, line_height, false, "Test"},
+ {"Test Test", test_width, line_height, true, "Test"},
+ {"Test Test", test_width, line_height + 1, false, "Test|Test"},
+ {"Test Test", test_width, line_height * 2, false, "Test|Test"},
+ {"Test Test", test_width, line_height * 3, false, "Test|Test"},
+ {"Test Test", test_width * 2, line_height * 2, false, "Test|Test"},
+ {"Test Test", test_width * 3, line_height, false, "Test Test"},
+ {"Test\nTest", test_width * 3, line_height * 2, false, "Test|Test"},
+ {"Te\nst Te", test_width, line_height * 3, false, "Te|st|Te"},
+ {"\nTest", test_width, line_height * 2, false, "|Test"},
+ {"\nTest", test_width, line_height, true, ""},
+ {"\n\nTest", test_width, line_height * 3, false, "||Test"},
+ {"\n\nTest", test_width, line_height * 2, true, "|"},
+ {"Test\n", 2 * test_width, line_height * 5, false, "Test|"},
+ {"Test\n\n", 2 * test_width, line_height * 5, false, "Test||"},
+ {"Test\n\n\n", 2 * test_width, line_height * 5, false, "Test|||"},
+ {"Test\nTest\n\n", 2 * test_width, line_height * 5, false, "Test|Test||"},
+ {"Test\n\nTest\n", 2 * test_width, line_height * 5, false, "Test||Test|"},
+ {"Test\n\n\nTest", 2 * test_width, line_height * 5, false, "Test|||Test"},
+ {"Te ", test_width, line_height, false, "Te"},
+ {"Te Te Test", test_width, 3 * line_height, false, "Te|Te|Test"},
};
for (size_t i = 0; i < base::size(cases); ++i) {
@@ -989,7 +991,7 @@ TEST(TextEliderTest, ElideRectangleTextCheckLineWidth) {
EXPECT_LE(GetStringWidthF(lines[1], font_list), kAvailableWidth);
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// This test was created specifically to test a message from crbug.com/415213.
// It tests that width of concatenation of words equals sum of widths of the
// words.
@@ -1004,7 +1006,7 @@ TEST(TextEliderTest, ElideRectangleTextCheckConcatWidthEqualsSumOfWidths) {
#undef WIDTH
SetFontRenderParamsDeviceScaleFactor(1.0f);
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
TEST(TextEliderTest, ElideRectangleString) {
struct TestData {
diff --git a/chromium/ui/gfx/text_utils.cc b/chromium/ui/gfx/text_utils.cc
index ab52cf4fdf3..58a002da7c3 100644
--- a/chromium/ui/gfx/text_utils.cc
+++ b/chromium/ui/gfx/text_utils.cc
@@ -22,6 +22,10 @@ using base::i18n::UTF16CharIterator;
namespace {
+constexpr base::char16 kAcceleratorChar = '&';
+constexpr base::char16 kOpenParenthesisChar = '(';
+constexpr base::char16 kCloseParenthesisChar = ')';
+
// Returns true if the specified character must be elided from a string.
// Examples are combining marks and whitespace.
bool IsCombiningMark(UChar32 c) {
@@ -39,10 +43,8 @@ bool IsSpace(UChar32 c) {
char_type == U_PARAGRAPH_SEPARATOR || char_type == U_CONTROL_CHAR;
}
-} // namespace
-
-base::string16 RemoveAcceleratorChar(const base::string16& s,
- base::char16 accelerator_char,
+base::string16 RemoveAcceleratorChar(bool full_removal,
+ const base::string16& s,
int* accelerated_char_pos,
int* accelerated_char_span) {
bool escaped = false;
@@ -51,15 +53,47 @@ base::string16 RemoveAcceleratorChar(const base::string16& s,
UTF16CharIterator chars(s);
base::string16 accelerator_removed;
+ // The states of a state machine looking for a CJK-style accelerator (i.e.
+ // "(&x)"). |cjk_state| proceeds up from |kFoundNothing| through these states,
+ // resetting either when it sees a complete accelerator, or gives up because
+ // the current character doesn't match.
+ enum {
+ kFoundNothing,
+ kFoundOpenParen,
+ kFoundAcceleratorChar,
+ kFoundAccelerator
+ } cjk_state = kFoundNothing;
+ size_t pre_cjk_size = 0;
+
accelerator_removed.reserve(s.size());
while (!chars.end()) {
int32_t c = chars.get();
int array_pos = chars.array_pos();
chars.Advance();
- if (c != accelerator_char || escaped) {
+ if (full_removal) {
+ if (cjk_state == kFoundNothing && c == kOpenParenthesisChar) {
+ pre_cjk_size = array_pos;
+ cjk_state = kFoundOpenParen;
+ } else if (cjk_state == kFoundOpenParen && c == kAcceleratorChar) {
+ cjk_state = kFoundAcceleratorChar;
+ } else if (cjk_state == kFoundAcceleratorChar) {
+ // Accept any character as the accelerator.
+ cjk_state = kFoundAccelerator;
+ } else if (cjk_state == kFoundAccelerator && c == kCloseParenthesisChar) {
+ cjk_state = kFoundNothing;
+ accelerator_removed.resize(pre_cjk_size);
+ pre_cjk_size = 0;
+ escaped = false;
+ continue;
+ } else {
+ cjk_state = kFoundNothing;
+ }
+ }
+
+ if (c != kAcceleratorChar || escaped) {
int span = chars.array_pos() - array_pos;
- if (escaped && c != accelerator_char) {
+ if (escaped && c != kAcceleratorChar) {
last_char_pos = accelerator_removed.size();
last_char_span = span;
}
@@ -71,14 +105,27 @@ base::string16 RemoveAcceleratorChar(const base::string16& s,
}
}
- if (accelerated_char_pos)
+ if (accelerated_char_pos && !full_removal)
*accelerated_char_pos = last_char_pos;
- if (accelerated_char_span)
+ if (accelerated_char_span && !full_removal)
*accelerated_char_span = last_char_span;
return accelerator_removed;
}
+} // namespace
+
+base::string16 LocateAndRemoveAcceleratorChar(const base::string16& s,
+ int* accelerated_char_pos,
+ int* accelerated_char_span) {
+ return RemoveAcceleratorChar(false, s, accelerated_char_pos,
+ accelerated_char_span);
+}
+
+base::string16 RemoveAccelerator(const base::string16& s) {
+ return RemoveAcceleratorChar(true, s, nullptr, nullptr);
+}
+
size_t FindValidBoundaryBefore(const base::string16& text,
size_t index,
bool trim_whitespace) {
diff --git a/chromium/ui/gfx/text_utils.h b/chromium/ui/gfx/text_utils.h
index ea342ee5a8c..d1ca32810de 100644
--- a/chromium/ui/gfx/text_utils.h
+++ b/chromium/ui/gfx/text_utils.h
@@ -17,15 +17,27 @@ class FontList;
class Insets;
class Size;
-// Strip the accelerator char (typically '&') from a menu string. A double
-// accelerator char ('&&') will be converted to a single char. The out params
+// Strips the accelerator char ('&') from a menu string. Useful for platforms
+// which use underlining to indicate accelerators.
+//
+// Single accelerator chars ('&') will be stripped from the string. Double
+// accelerator chars ('&&') will be converted to a single '&'. The out params
// |accelerated_char_pos| and |accelerated_char_span| will be set to the index
// and span of the last accelerated character, respectively, or -1 and 0 if
// there was none.
-GFX_EXPORT base::string16 RemoveAcceleratorChar(const base::string16& s,
- base::char16 accelerator_char,
- int* accelerated_char_pos,
- int* accelerated_char_span);
+GFX_EXPORT base::string16 LocateAndRemoveAcceleratorChar(
+ const base::string16& s,
+ int* accelerated_char_pos,
+ int* accelerated_char_span);
+
+// Strips all accelerator notation from a menu string. Useful for platforms
+// which use underlining to indicate accelerators, as well as situations where
+// accelerators are not indicated.
+//
+// Single accelerator chars ('&') will be stripped from the string. Double
+// accelerator chars ('&&') will be converted to a single '&'. CJK language
+// accelerators, specified as "(&x)", will be entirely removed too.
+GFX_EXPORT base::string16 RemoveAccelerator(const base::string16& s);
// Returns the number of horizontal pixels needed to display the specified
// |text| with |font_list|. |typesetter| indicates where the text will be
diff --git a/chromium/ui/gfx/text_utils_unittest.cc b/chromium/ui/gfx/text_utils_unittest.cc
index ed1eb98a45c..12df151394e 100644
--- a/chromium/ui/gfx/text_utils_unittest.cc
+++ b/chromium/ui/gfx/text_utils_unittest.cc
@@ -21,16 +21,6 @@
namespace gfx {
namespace {
-const base::char16 kAcceleratorChar = '&';
-
-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;
EXPECT_EQ(GetStringWidth(base::string16(), font_list), 0);
@@ -117,6 +107,15 @@ TEST(TextUtilsTest, GetFontCapHeightCenterOffset_SameSize) {
EXPECT_EQ(0, GetFontCapHeightCenterOffset(original_font, original_font));
}
+struct RemoveAcceleratorCharData {
+ const char* input;
+ int accelerated_char_pos;
+ int accelerated_char_span;
+ const char* output_locate_and_strip;
+ const char* output_full_strip;
+ const char* name;
+};
+
class RemoveAcceleratorCharTest
: public testing::TestWithParam<RemoveAcceleratorCharData> {
public:
@@ -124,37 +123,62 @@ class RemoveAcceleratorCharTest
};
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",
+ {"", -1, 0, "", "", "EmptyString"},
+ {"&", -1, 0, "", "", "AcceleratorCharOnly"},
+ {"no accelerator", -1, 0, "no accelerator", "no accelerator",
+ "NoAccelerator"},
+ {"&one accelerator", 0, 1, "one accelerator", "one accelerator",
+ "OneAccelerator_Start"},
+ {"one &accelerator", 4, 1, "one accelerator", "one accelerator",
+ "OneAccelerator_Middle"},
+ {"one accelerator&", -1, 0, "one accelerator", "one accelerator",
+ "OneAccelerator_End"},
+ {"&two &accelerators", 4, 1, "two accelerators", "two accelerators",
"TwoAccelerators_OneAtStart"},
- {"two &accelerators&", 4, 1, "two accelerators",
+ {"two &accelerators&", 4, 1, "two accelerators", "two accelerators",
"TwoAccelerators_OneAtEnd"},
- {"two& &accelerators", 4, 1, "two accelerators",
+ {"two& &accelerators", 4, 1, "two accelerators", "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"},
+ {"&&escaping", -1, 0, "&escaping", "&escaping", "Escape_Start"},
+ {"escap&&ing", -1, 0, "escap&ing", "escap&ing", "Escape_Middle"},
+ {"escaping&&", -1, 0, "escaping&", "escaping&", "Escape_End"},
+ {"accelerator(&A)", 12, 1, "accelerator(A)", "accelerator", "CJK_Style"},
+ {"accelerator(&A)...", 12, 1, "accelerator(A)...", "accelerator...",
+ "CJK_StyleEllipsis"},
+ {"accelerator(paren", -1, 0, "accelerator(paren", "accelerator(paren",
+ "CJK_OpenParen"},
+ {"accelerator(&paren", 12, 1, "accelerator(paren", "accelerator(paren",
+ "CJK_NoClosingParen"},
+ {"accelerator(&paren)", 12, 1, "accelerator(paren)", "accelerator(paren)",
+ "CJK_LateClosingParen"},
+ {"accelerator&paren)", 11, 1, "acceleratorparen)", "acceleratorparen)",
+ "CJK_NoOpeningParen"},
+ {"accelerator(P)", -1, 0, "accelerator(P)", "accelerator(P)",
+ "CJK_JustParens"},
+ {"accelerator(&)", 12, 1, "accelerator()", "accelerator()",
+ "CJK_MissingAccelerator"},
+ {"&mix&&ed", 0, 1, "mix&ed", "mix&ed", "Mixed_EscapeAfterAccelerator"},
+ {"&&m&ix&&e&d&", 6, 1, "&mix&ed", "&mix&ed",
+ "Mixed_MiddleAcceleratorSkipped"},
+ {"&&m&&ix&ed&&", 5, 1, "&m&ixed&", "&m&ixed&", "Mixed_OneAccelerator"},
+ {"&m&&ix&ed&&", 4, 1, "m&ixed&", "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",
+ {"&\U0001D49C", 0, 2, "\U0001D49C", "\U0001D49C",
+ "MultibyteAccelerator_Start"},
+ {"Test&\U0001D49Cing", 4, 2, "Test\U0001D49Cing", "Test\U0001D49Cing",
"MultibyteAccelerator_Middle"},
- {"Test\U0001D49C&ing", 6, 1, "Test\U0001D49Cing",
+ {"Test\U0001D49C&ing", 6, 1, "Test\U0001D49Cing", "Test\U0001D49Cing",
"OneAccelerator_AfterMultibyte"},
- {"Test&\U0001D49C&ing", 6, 1, "Test\U0001D49Cing",
+ {"Test&\U0001D49C&ing", 6, 1, "Test\U0001D49Cing", "Test\U0001D49Cing",
"MultibyteAccelerator_Skipped"},
- {"Test&\U0001D49C&&ing", 4, 2, "Test\U0001D49C&ing",
+ {"Test&\U0001D49C&&ing", 4, 2, "Test\U0001D49C&ing", "Test\U0001D49C&ing",
"MultibyteAccelerator_EscapeAfter"},
{"Test&\U0001D49C&\U0001D49Cing", 6, 2, "Test\U0001D49C\U0001D49Cing",
+ "Test\U0001D49C\U0001D49Cing",
"MultibyteAccelerator_AfterMultibyteAccelerator"},
+ {"accelerator(&\U0001D49C)", 12, 2, "accelerator(\U0001D49C)",
+ "accelerator", "MultibyteAccelerator_CJK"},
};
INSTANTIATE_TEST_SUITE_P(
@@ -169,10 +193,14 @@ 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));
+ base::string16 result_locate_and_strip = LocateAndRemoveAcceleratorChar(
+ base::UTF8ToUTF16(data.input), &accelerated_char_pos,
+ &accelerated_char_span);
+ base::string16 result_full_strip =
+ RemoveAccelerator(base::UTF8ToUTF16(data.input));
+ EXPECT_EQ(result_locate_and_strip,
+ base::UTF8ToUTF16(data.output_locate_and_strip));
+ EXPECT_EQ(result_full_strip, base::UTF8ToUTF16(data.output_full_strip));
EXPECT_EQ(accelerated_char_pos, data.accelerated_char_pos);
EXPECT_EQ(accelerated_char_span, data.accelerated_char_span);
}
diff --git a/chromium/ui/gfx/transform.cc b/chromium/ui/gfx/transform.cc
index 0184c6a3e57..fe99ddaf1e5 100644
--- a/chromium/ui/gfx/transform.cc
+++ b/chromium/ui/gfx/transform.cc
@@ -637,4 +637,13 @@ std::string Transform::ToString() const {
matrix_.get(3, 3));
}
+SkM44 Transform::GetMatrixAsSkM44() const {
+ return SkM44(matrix_.get(0, 0), matrix_.get(0, 1), matrix_.get(0, 2),
+ matrix_.get(0, 3), matrix_.get(1, 0), matrix_.get(1, 1),
+ matrix_.get(1, 2), matrix_.get(1, 3), matrix_.get(2, 0),
+ matrix_.get(2, 1), matrix_.get(2, 2), matrix_.get(2, 3),
+ matrix_.get(3, 0), matrix_.get(3, 1), matrix_.get(3, 2),
+ matrix_.get(3, 3));
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/transform.h b/chromium/ui/gfx/transform.h
index c056ab0f854..a77d06c866c 100644
--- a/chromium/ui/gfx/transform.h
+++ b/chromium/ui/gfx/transform.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/compiler_specific.h"
+#include "third_party/skia/include/core/SkM44.h"
#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/geometry_skia_export.h"
@@ -286,6 +287,12 @@ class GEOMETRY_SKIA_EXPORT Transform {
// Returns the underlying matrix.
const SkMatrix44& matrix() const { return matrix_; }
SkMatrix44& matrix() { return matrix_; }
+
+ // TODO(crbug.com/1167153) SkMatrix44 is deprecated, this is to help in moving
+ // the code base towards SkM44, although eventually this class should just
+ // hold an SkM44
+ SkM44 GetMatrixAsSkM44() const;
+
bool ApproximatelyEqual(const gfx::Transform& transform) const;
std::string ToString() const;
diff --git a/chromium/ui/gfx/transform_operation.cc b/chromium/ui/gfx/transform_operation.cc
new file mode 100644
index 00000000000..8d12cd28ad5
--- /dev/null
+++ b/chromium/ui/gfx/transform_operation.cc
@@ -0,0 +1,514 @@
+// 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 <limits>
+#include <utility>
+
+#include "ui/gfx/transform_operation.h"
+
+#include "base/check_op.h"
+#include "base/notreached.h"
+#include "base/numerics/math_constants.h"
+#include "base/numerics/ranges.h"
+#include "ui/gfx/geometry/angle_conversions.h"
+#include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+#include "ui/gfx/transform_operations.h"
+#include "ui/gfx/transform_util.h"
+
+namespace {
+const SkScalar kAngleEpsilon = 1e-4f;
+}
+
+namespace gfx {
+
+bool TransformOperation::IsIdentity() const {
+ return matrix.IsIdentity();
+}
+
+static bool IsOperationIdentity(const TransformOperation* operation) {
+ return !operation || operation->IsIdentity();
+}
+
+static bool ShareSameAxis(const TransformOperation* from,
+ const TransformOperation* to,
+ SkScalar* axis_x,
+ SkScalar* axis_y,
+ SkScalar* axis_z,
+ SkScalar* angle_from) {
+ if (IsOperationIdentity(from) && IsOperationIdentity(to))
+ return false;
+
+ if (IsOperationIdentity(from) && !IsOperationIdentity(to)) {
+ *axis_x = to->rotate.axis.x;
+ *axis_y = to->rotate.axis.y;
+ *axis_z = to->rotate.axis.z;
+ *angle_from = 0;
+ return true;
+ }
+
+ if (!IsOperationIdentity(from) && IsOperationIdentity(to)) {
+ *axis_x = from->rotate.axis.x;
+ *axis_y = from->rotate.axis.y;
+ *axis_z = from->rotate.axis.z;
+ *angle_from = from->rotate.angle;
+ return true;
+ }
+
+ SkScalar length_2 = from->rotate.axis.x * from->rotate.axis.x +
+ from->rotate.axis.y * from->rotate.axis.y +
+ from->rotate.axis.z * from->rotate.axis.z;
+ SkScalar other_length_2 = to->rotate.axis.x * to->rotate.axis.x +
+ to->rotate.axis.y * to->rotate.axis.y +
+ to->rotate.axis.z * to->rotate.axis.z;
+
+ if (length_2 <= kAngleEpsilon || other_length_2 <= kAngleEpsilon)
+ return false;
+
+ SkScalar dot = to->rotate.axis.x * from->rotate.axis.x +
+ to->rotate.axis.y * from->rotate.axis.y +
+ to->rotate.axis.z * from->rotate.axis.z;
+ SkScalar error =
+ SkScalarAbs(SK_Scalar1 - (dot * dot) / (length_2 * other_length_2));
+ bool result = error < kAngleEpsilon;
+ if (result) {
+ *axis_x = to->rotate.axis.x;
+ *axis_y = to->rotate.axis.y;
+ *axis_z = to->rotate.axis.z;
+ // If the axes are pointing in opposite directions, we need to reverse
+ // the angle.
+ *angle_from = dot > 0 ? from->rotate.angle : -from->rotate.angle;
+ }
+ return result;
+}
+
+static SkScalar BlendSkScalars(SkScalar from, SkScalar to, SkScalar progress) {
+ return from * (1 - progress) + to * progress;
+}
+
+void TransformOperation::Bake() {
+ matrix.MakeIdentity();
+ switch (type) {
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
+ matrix.Translate3d(translate.x, translate.y, translate.z);
+ break;
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ matrix.RotateAbout(
+ gfx::Vector3dF(rotate.axis.x, rotate.axis.y, rotate.axis.z),
+ rotate.angle);
+ break;
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
+ matrix.Scale3d(scale.x, scale.y, scale.z);
+ break;
+ case TransformOperation::TRANSFORM_OPERATION_SKEWX:
+ case TransformOperation::TRANSFORM_OPERATION_SKEWY:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ matrix.Skew(skew.x, skew.y);
+ break;
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
+ matrix.ApplyPerspectiveDepth(perspective_depth);
+ break;
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ break;
+ }
+}
+
+bool TransformOperation::ApproximatelyEqual(const TransformOperation& other,
+ SkScalar tolerance) const {
+ DCHECK_LE(0, tolerance);
+ if (type != other.type)
+ return false;
+ switch (type) {
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
+ return base::IsApproximatelyEqual(translate.x, other.translate.x,
+ tolerance) &&
+ base::IsApproximatelyEqual(translate.y, other.translate.y,
+ tolerance) &&
+ base::IsApproximatelyEqual(translate.z, other.translate.z,
+ tolerance);
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ return base::IsApproximatelyEqual(rotate.axis.x, other.rotate.axis.x,
+ tolerance) &&
+ base::IsApproximatelyEqual(rotate.axis.y, other.rotate.axis.y,
+ tolerance) &&
+ base::IsApproximatelyEqual(rotate.axis.z, other.rotate.axis.z,
+ tolerance) &&
+ base::IsApproximatelyEqual(rotate.angle, other.rotate.angle,
+ tolerance);
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
+ return base::IsApproximatelyEqual(scale.x, other.scale.x, tolerance) &&
+ base::IsApproximatelyEqual(scale.y, other.scale.y, tolerance) &&
+ base::IsApproximatelyEqual(scale.z, other.scale.z, tolerance);
+ case TransformOperation::TRANSFORM_OPERATION_SKEWX:
+ case TransformOperation::TRANSFORM_OPERATION_SKEWY:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ return base::IsApproximatelyEqual(skew.x, other.skew.x, tolerance) &&
+ base::IsApproximatelyEqual(skew.y, other.skew.y, tolerance);
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
+ return base::IsApproximatelyEqual(perspective_depth,
+ other.perspective_depth, tolerance);
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
+ // TODO(vollick): we could expose a tolerance on gfx::Transform, but it's
+ // complex since we need a different tolerance per component. Driving this
+ // with a single tolerance will take some care. For now, we will check
+ // exact equality where the tolerance is 0.0f, otherwise we will use the
+ // unparameterized version of gfx::Transform::ApproximatelyEqual.
+ if (tolerance == 0.0f)
+ return matrix == other.matrix;
+ else
+ return matrix.ApproximatelyEqual(other.matrix);
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ return other.matrix.IsIdentity();
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool TransformOperation::BlendTransformOperations(
+ const TransformOperation* from,
+ const TransformOperation* to,
+ SkScalar progress,
+ TransformOperation* result) {
+ if (IsOperationIdentity(from) && IsOperationIdentity(to))
+ return true;
+
+ TransformOperation::Type interpolation_type =
+ TransformOperation::TRANSFORM_OPERATION_IDENTITY;
+ if (IsOperationIdentity(to))
+ interpolation_type = from->type;
+ else
+ interpolation_type = to->type;
+ result->type = interpolation_type;
+
+ switch (interpolation_type) {
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: {
+ SkScalar from_x = IsOperationIdentity(from) ? 0 : from->translate.x;
+ SkScalar from_y = IsOperationIdentity(from) ? 0 : from->translate.y;
+ SkScalar from_z = IsOperationIdentity(from) ? 0 : from->translate.z;
+ SkScalar to_x = IsOperationIdentity(to) ? 0 : to->translate.x;
+ SkScalar to_y = IsOperationIdentity(to) ? 0 : to->translate.y;
+ SkScalar to_z = IsOperationIdentity(to) ? 0 : to->translate.z;
+ result->translate.x = BlendSkScalars(from_x, to_x, progress),
+ result->translate.y = BlendSkScalars(from_y, to_y, progress),
+ result->translate.z = BlendSkScalars(from_z, to_z, progress),
+ result->Bake();
+ break;
+ }
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE: {
+ SkScalar axis_x = 0;
+ SkScalar axis_y = 0;
+ SkScalar axis_z = 1;
+ SkScalar from_angle = 0;
+ SkScalar to_angle = IsOperationIdentity(to) ? 0 : to->rotate.angle;
+ if (ShareSameAxis(from, to, &axis_x, &axis_y, &axis_z, &from_angle)) {
+ result->rotate.axis.x = axis_x;
+ result->rotate.axis.y = axis_y;
+ result->rotate.axis.z = axis_z;
+ result->rotate.angle = BlendSkScalars(from_angle, to_angle, progress);
+ result->Bake();
+ } else {
+ if (!IsOperationIdentity(to))
+ result->matrix = to->matrix;
+ gfx::Transform from_matrix;
+ if (!IsOperationIdentity(from))
+ from_matrix = from->matrix;
+ if (!result->matrix.Blend(from_matrix, progress))
+ return false;
+ }
+ break;
+ }
+ case TransformOperation::TRANSFORM_OPERATION_SCALE: {
+ SkScalar from_x = IsOperationIdentity(from) ? 1 : from->scale.x;
+ SkScalar from_y = IsOperationIdentity(from) ? 1 : from->scale.y;
+ SkScalar from_z = IsOperationIdentity(from) ? 1 : from->scale.z;
+ SkScalar to_x = IsOperationIdentity(to) ? 1 : to->scale.x;
+ SkScalar to_y = IsOperationIdentity(to) ? 1 : to->scale.y;
+ SkScalar to_z = IsOperationIdentity(to) ? 1 : to->scale.z;
+ result->scale.x = BlendSkScalars(from_x, to_x, progress);
+ result->scale.y = BlendSkScalars(from_y, to_y, progress);
+ result->scale.z = BlendSkScalars(from_z, to_z, progress);
+ result->Bake();
+ break;
+ }
+ case TransformOperation::TRANSFORM_OPERATION_SKEWX:
+ case TransformOperation::TRANSFORM_OPERATION_SKEWY:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW: {
+ SkScalar from_x = IsOperationIdentity(from) ? 0 : from->skew.x;
+ SkScalar from_y = IsOperationIdentity(from) ? 0 : from->skew.y;
+ SkScalar to_x = IsOperationIdentity(to) ? 0 : to->skew.x;
+ SkScalar to_y = IsOperationIdentity(to) ? 0 : to->skew.y;
+ result->skew.x = BlendSkScalars(from_x, to_x, progress);
+ result->skew.y = BlendSkScalars(from_y, to_y, progress);
+ result->Bake();
+ break;
+ }
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: {
+ SkScalar from_perspective_depth =
+ IsOperationIdentity(from) ? std::numeric_limits<SkScalar>::max()
+ : from->perspective_depth;
+ SkScalar to_perspective_depth = IsOperationIdentity(to)
+ ? std::numeric_limits<SkScalar>::max()
+ : to->perspective_depth;
+ if (from_perspective_depth == 0.f || to_perspective_depth == 0.f)
+ return false;
+
+ SkScalar blended_perspective_depth = BlendSkScalars(
+ 1.f / from_perspective_depth, 1.f / to_perspective_depth, progress);
+
+ if (blended_perspective_depth == 0.f)
+ return false;
+
+ result->perspective_depth = 1.f / blended_perspective_depth;
+ result->Bake();
+ break;
+ }
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX: {
+ if (!IsOperationIdentity(to))
+ result->matrix = to->matrix;
+ gfx::Transform from_matrix;
+ if (!IsOperationIdentity(from))
+ from_matrix = from->matrix;
+ if (!result->matrix.Blend(from_matrix, progress))
+ return false;
+ break;
+ }
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ // Do nothing.
+ break;
+ }
+
+ return true;
+}
+
+// If p = (px, py) is a point in the plane being rotated about (0, 0, nz), this
+// function computes the angles we would have to rotate from p to get to
+// (length(p), 0), (-length(p), 0), (0, length(p)), (0, -length(p)). If nz is
+// negative, these angles will need to be reversed.
+static void FindCandidatesInPlane(float px,
+ float py,
+ float nz,
+ double* candidates,
+ int* num_candidates) {
+ double phi = atan2(px, py);
+ *num_candidates = 4;
+ candidates[0] = phi;
+ for (int i = 1; i < *num_candidates; ++i)
+ candidates[i] = candidates[i - 1] + base::kPiDouble / 2;
+ if (nz < 0.f) {
+ for (int i = 0; i < *num_candidates; ++i)
+ candidates[i] *= -1.f;
+ }
+}
+
+static void BoundingBoxForArc(const gfx::Point3F& point,
+ const TransformOperation* from,
+ const TransformOperation* to,
+ SkScalar min_progress,
+ SkScalar max_progress,
+ gfx::BoxF* box) {
+ const TransformOperation* exemplar = from ? from : to;
+ gfx::Vector3dF axis(exemplar->rotate.axis.x, exemplar->rotate.axis.y,
+ exemplar->rotate.axis.z);
+
+ const bool x_is_zero = axis.x() == 0.f;
+ const bool y_is_zero = axis.y() == 0.f;
+ const bool z_is_zero = axis.z() == 0.f;
+
+ // We will have at most 6 angles to test (excluding from->angle and
+ // to->angle).
+ static const int kMaxNumCandidates = 6;
+ double candidates[kMaxNumCandidates];
+ int num_candidates = kMaxNumCandidates;
+
+ if (x_is_zero && y_is_zero && z_is_zero)
+ return;
+
+ SkScalar from_angle = from ? from->rotate.angle : 0.f;
+ SkScalar to_angle = to ? to->rotate.angle : 0.f;
+
+ // If the axes of rotation are pointing in opposite directions, we need to
+ // flip one of the angles. Note, if both |from| and |to| exist, then axis will
+ // correspond to |from|.
+ if (from && to) {
+ gfx::Vector3dF other_axis(to->rotate.axis.x, to->rotate.axis.y,
+ to->rotate.axis.z);
+ if (gfx::DotProduct(axis, other_axis) < 0.f)
+ to_angle *= -1.f;
+ }
+
+ float min_degrees =
+ SkScalarToFloat(BlendSkScalars(from_angle, to_angle, min_progress));
+ float max_degrees =
+ SkScalarToFloat(BlendSkScalars(from_angle, to_angle, max_progress));
+ if (max_degrees < min_degrees)
+ std::swap(min_degrees, max_degrees);
+
+ gfx::Transform from_transform;
+ from_transform.RotateAbout(axis, min_degrees);
+ gfx::Transform to_transform;
+ to_transform.RotateAbout(axis, max_degrees);
+
+ *box = gfx::BoxF();
+
+ gfx::Point3F point_rotated_from = point;
+ from_transform.TransformPoint(&point_rotated_from);
+ gfx::Point3F point_rotated_to = point;
+ to_transform.TransformPoint(&point_rotated_to);
+
+ box->set_origin(point_rotated_from);
+ box->ExpandTo(point_rotated_to);
+
+ if (x_is_zero && y_is_zero) {
+ FindCandidatesInPlane(point.x(), point.y(), axis.z(), candidates,
+ &num_candidates);
+ } else if (x_is_zero && z_is_zero) {
+ FindCandidatesInPlane(point.z(), point.x(), axis.y(), candidates,
+ &num_candidates);
+ } else if (y_is_zero && z_is_zero) {
+ FindCandidatesInPlane(point.y(), point.z(), axis.x(), candidates,
+ &num_candidates);
+ } else {
+ gfx::Vector3dF normal = axis;
+ normal.Scale(1.f / normal.Length());
+
+ // First, find center of rotation.
+ gfx::Point3F origin;
+ gfx::Vector3dF to_point = point - origin;
+ gfx::Point3F center =
+ origin + gfx::ScaleVector3d(normal, gfx::DotProduct(to_point, normal));
+
+ // Now we need to find two vectors in the plane of rotation. One pointing
+ // towards point and another, perpendicular vector in the plane.
+ gfx::Vector3dF v1 = point - center;
+ float v1_length = v1.Length();
+ if (v1_length == 0.f)
+ return;
+
+ v1.Scale(1.f / v1_length);
+ gfx::Vector3dF v2 = gfx::CrossProduct(normal, v1);
+ // v1 is the basis vector in the direction of the point.
+ // i.e. with a rotation of 0, v1 is our +x vector.
+ // v2 is a perpenticular basis vector of our plane (+y).
+
+ // Take the parametric equation of a circle.
+ // x = r*cos(t); y = r*sin(t);
+ // We can treat that as a circle on the plane v1xv2.
+ // From that we get the parametric equations for a circle on the
+ // plane in 3d space of:
+ // x(t) = r*cos(t)*v1.x + r*sin(t)*v2.x + cx
+ // y(t) = r*cos(t)*v1.y + r*sin(t)*v2.y + cy
+ // z(t) = r*cos(t)*v1.z + r*sin(t)*v2.z + cz
+ // Taking the derivative of (x, y, z) and solving for 0 gives us our
+ // maximum/minimum x, y, z values.
+ // x'(t) = r*cos(t)*v2.x - r*sin(t)*v1.x = 0
+ // tan(t) = v2.x/v1.x
+ // t = atan2(v2.x, v1.x) + n*pi;
+ candidates[0] = atan2(v2.x(), v1.x());
+ candidates[1] = candidates[0] + base::kPiDouble;
+ candidates[2] = atan2(v2.y(), v1.y());
+ candidates[3] = candidates[2] + base::kPiDouble;
+ candidates[4] = atan2(v2.z(), v1.z());
+ candidates[5] = candidates[4] + base::kPiDouble;
+ }
+
+ double min_radians = gfx::DegToRad(min_degrees);
+ double max_radians = gfx::DegToRad(max_degrees);
+
+ for (int i = 0; i < num_candidates; ++i) {
+ double radians = candidates[i];
+ while (radians < min_radians)
+ radians += 2.0 * base::kPiDouble;
+ while (radians > max_radians)
+ radians -= 2.0 * base::kPiDouble;
+ if (radians < min_radians)
+ continue;
+
+ gfx::Transform rotation;
+ rotation.RotateAbout(axis, gfx::RadToDeg(radians));
+ gfx::Point3F rotated = point;
+ rotation.TransformPoint(&rotated);
+
+ box->ExpandTo(rotated);
+ }
+}
+
+bool TransformOperation::BlendedBoundsForBox(const gfx::BoxF& box,
+ const TransformOperation* from,
+ const TransformOperation* to,
+ SkScalar min_progress,
+ SkScalar max_progress,
+ gfx::BoxF* bounds) {
+ bool is_identity_from = IsOperationIdentity(from);
+ bool is_identity_to = IsOperationIdentity(to);
+ if (is_identity_from && is_identity_to) {
+ *bounds = box;
+ return true;
+ }
+
+ TransformOperation::Type interpolation_type =
+ TransformOperation::TRANSFORM_OPERATION_IDENTITY;
+ if (is_identity_to)
+ interpolation_type = from->type;
+ else
+ interpolation_type = to->type;
+
+ switch (interpolation_type) {
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ *bounds = box;
+ return true;
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
+ case TransformOperation::TRANSFORM_OPERATION_SKEWX:
+ case TransformOperation::TRANSFORM_OPERATION_SKEWY:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
+ case TransformOperation::TRANSFORM_OPERATION_SCALE: {
+ TransformOperation from_operation;
+ TransformOperation to_operation;
+ if (!BlendTransformOperations(from, to, min_progress, &from_operation) ||
+ !BlendTransformOperations(from, to, max_progress, &to_operation))
+ return false;
+
+ *bounds = box;
+ from_operation.matrix.TransformBox(bounds);
+
+ gfx::BoxF to_box = box;
+ to_operation.matrix.TransformBox(&to_box);
+ bounds->ExpandTo(to_box);
+
+ return true;
+ }
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE: {
+ SkScalar axis_x = 0;
+ SkScalar axis_y = 0;
+ SkScalar axis_z = 1;
+ SkScalar from_angle = 0;
+ if (!ShareSameAxis(from, to, &axis_x, &axis_y, &axis_z, &from_angle))
+ return false;
+
+ bool first_point = true;
+ for (int i = 0; i < 8; ++i) {
+ gfx::Point3F corner = box.origin();
+ corner += gfx::Vector3dF(i & 1 ? box.width() : 0.f,
+ i & 2 ? box.height() : 0.f,
+ i & 4 ? box.depth() : 0.f);
+ gfx::BoxF box_for_arc;
+ BoundingBoxForArc(corner, from, to, min_progress, max_progress,
+ &box_for_arc);
+ if (first_point)
+ *bounds = box_for_arc;
+ else
+ bounds->Union(box_for_arc);
+ first_point = false;
+ }
+ return true;
+ }
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/transform_operation.h b/chromium/ui/gfx/transform_operation.h
new file mode 100644
index 00000000000..5bb0734eb76
--- /dev/null
+++ b/chromium/ui/gfx/transform_operation.h
@@ -0,0 +1,79 @@
+// 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_GFX_TRANSFORM_OPERATION_H_
+#define UI_GFX_TRANSFORM_OPERATION_H_
+
+#include "ui/gfx/geometry_skia_export.h"
+#include "ui/gfx/transform.h"
+
+namespace gfx {
+class BoxF;
+
+struct GEOMETRY_SKIA_EXPORT TransformOperation {
+ enum Type {
+ TRANSFORM_OPERATION_TRANSLATE,
+ TRANSFORM_OPERATION_ROTATE,
+ TRANSFORM_OPERATION_SCALE,
+ TRANSFORM_OPERATION_SKEWX,
+ TRANSFORM_OPERATION_SKEWY,
+ TRANSFORM_OPERATION_SKEW,
+ TRANSFORM_OPERATION_PERSPECTIVE,
+ TRANSFORM_OPERATION_MATRIX,
+ TRANSFORM_OPERATION_IDENTITY
+ };
+
+ TransformOperation() : type(TRANSFORM_OPERATION_IDENTITY) {}
+
+ Type type;
+ gfx::Transform matrix;
+
+ union {
+ SkScalar perspective_depth;
+
+ struct {
+ SkScalar x, y;
+ } skew;
+
+ struct {
+ SkScalar x, y, z;
+ } scale;
+
+ struct {
+ SkScalar x, y, z;
+ } translate;
+
+ struct {
+ struct {
+ SkScalar x, y, z;
+ } axis;
+
+ SkScalar angle;
+ } rotate;
+ };
+
+ bool IsIdentity() const;
+
+ // Sets |matrix| based on type and the union values.
+ void Bake();
+
+ bool ApproximatelyEqual(const TransformOperation& other,
+ SkScalar tolerance) const;
+
+ static bool BlendTransformOperations(const TransformOperation* from,
+ const TransformOperation* to,
+ SkScalar progress,
+ TransformOperation* result);
+
+ static bool BlendedBoundsForBox(const gfx::BoxF& box,
+ const TransformOperation* from,
+ const TransformOperation* to,
+ SkScalar min_progress,
+ SkScalar max_progress,
+ gfx::BoxF* bounds);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_TRANSFORM_OPERATION_H_
diff --git a/chromium/ui/gfx/transform_operations.cc b/chromium/ui/gfx/transform_operations.cc
new file mode 100644
index 00000000000..849979e0dec
--- /dev/null
+++ b/chromium/ui/gfx/transform_operations.cc
@@ -0,0 +1,384 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/transform_operations.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <utility>
+
+#include "ui/gfx/geometry/angle_conversions.h"
+#include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+#include "ui/gfx/transform_util.h"
+
+namespace gfx {
+
+TransformOperations::TransformOperations() {}
+
+TransformOperations::TransformOperations(const TransformOperations& other) {
+ operations_ = other.operations_;
+}
+
+TransformOperations::~TransformOperations() = default;
+
+TransformOperations& TransformOperations::operator=(
+ const TransformOperations& other) {
+ operations_ = other.operations_;
+ return *this;
+}
+
+Transform TransformOperations::Apply() const {
+ return ApplyRemaining(0);
+}
+
+Transform TransformOperations::ApplyRemaining(size_t start) const {
+ Transform to_return;
+ for (size_t i = start; i < operations_.size(); i++) {
+ to_return.PreconcatTransform(operations_[i].matrix);
+ }
+ return to_return;
+}
+
+// TODO(crbug.com/914397): Consolidate blink and cc implementations of transform
+// interpolation.
+TransformOperations TransformOperations::Blend(const TransformOperations& from,
+ SkScalar progress) const {
+ TransformOperations to_return;
+ if (!BlendInternal(from, progress, &to_return)) {
+ // If the matrices cannot be blended, fallback to discrete animation logic.
+ // See https://drafts.csswg.org/css-transforms/#matrix-interpolation
+ to_return = progress < 0.5 ? from : *this;
+ }
+ return to_return;
+}
+
+bool TransformOperations::BlendedBoundsForBox(const BoxF& box,
+ const TransformOperations& from,
+ SkScalar min_progress,
+ SkScalar max_progress,
+ BoxF* bounds) const {
+ *bounds = box;
+
+ bool from_identity = from.IsIdentity();
+ bool to_identity = IsIdentity();
+ if (from_identity && to_identity)
+ return true;
+
+ if (!MatchesTypes(from))
+ return false;
+
+ size_t num_operations = std::max(from_identity ? 0 : from.operations_.size(),
+ to_identity ? 0 : operations_.size());
+
+ // Because we are squashing all of the matrices together when applying
+ // them to the animation, we must apply them in reverse order when
+ // not squashing them.
+ for (size_t i = 0; i < num_operations; ++i) {
+ size_t operation_index = num_operations - 1 - i;
+ BoxF bounds_for_operation;
+ const TransformOperation* from_op =
+ from_identity ? nullptr : &from.operations_[operation_index];
+ const TransformOperation* to_op =
+ to_identity ? nullptr : &operations_[operation_index];
+ if (!TransformOperation::BlendedBoundsForBox(*bounds, from_op, to_op,
+ min_progress, max_progress,
+ &bounds_for_operation)) {
+ return false;
+ }
+ *bounds = bounds_for_operation;
+ }
+
+ return true;
+}
+
+bool TransformOperations::PreservesAxisAlignment() const {
+ for (auto& operation : operations_) {
+ switch (operation.type) {
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
+ continue;
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
+ if (!operation.matrix.IsIdentity() &&
+ !operation.matrix.IsScaleOrTranslation())
+ return false;
+ continue;
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ case TransformOperation::TRANSFORM_OPERATION_SKEWX:
+ case TransformOperation::TRANSFORM_OPERATION_SKEWY:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TransformOperations::IsTranslation() const {
+ for (auto& operation : operations_) {
+ switch (operation.type) {
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
+ continue;
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
+ if (!operation.matrix.IsIdentityOrTranslation())
+ return false;
+ continue;
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
+ case TransformOperation::TRANSFORM_OPERATION_SKEWX:
+ case TransformOperation::TRANSFORM_OPERATION_SKEWY:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
+ return false;
+ }
+ }
+ return true;
+}
+
+static SkScalar TanDegrees(double degrees) {
+ return SkDoubleToScalar(std::tan(DegToRad(degrees)));
+}
+
+bool TransformOperations::ScaleComponent(SkScalar* scale) const {
+ SkScalar operations_scale = 1.f;
+ for (auto& operation : operations_) {
+ switch (operation.type) {
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ continue;
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX: {
+ if (operation.matrix.HasPerspective())
+ return false;
+ Vector2dF scale_components =
+ ComputeTransform2dScaleComponents(operation.matrix, 1.f);
+ operations_scale *=
+ std::max(scale_components.x(), scale_components.y());
+ break;
+ }
+ case TransformOperation::TRANSFORM_OPERATION_SKEWX:
+ case TransformOperation::TRANSFORM_OPERATION_SKEWY:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW: {
+ SkScalar x_component = TanDegrees(operation.skew.x);
+ SkScalar y_component = TanDegrees(operation.skew.y);
+ SkScalar x_scale = std::sqrt(x_component * x_component + 1);
+ SkScalar y_scale = std::sqrt(y_component * y_component + 1);
+ operations_scale *= std::max(x_scale, y_scale);
+ break;
+ }
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
+ return false;
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
+ operations_scale *= std::max(
+ std::abs(operation.scale.x),
+ std::max(std::abs(operation.scale.y), std::abs(operation.scale.z)));
+ }
+ }
+ *scale = operations_scale;
+ return true;
+}
+
+bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
+ if (operations_.size() == 0 || other.operations_.size() == 0)
+ return true;
+
+ if (operations_.size() != other.operations_.size())
+ return false;
+
+ for (size_t i = 0; i < operations_.size(); ++i) {
+ if (operations_[i].type != other.operations_[i].type)
+ return false;
+ }
+
+ return true;
+}
+
+size_t TransformOperations::MatchingPrefixLength(
+ const TransformOperations& other) const {
+ size_t num_operations =
+ std::min(operations_.size(), other.operations_.size());
+ for (size_t i = 0; i < num_operations; ++i) {
+ if (operations_[i].type != other.operations_[i].type) {
+ // Remaining operations in each operations list require matrix/matrix3d
+ // interpolation.
+ return i;
+ }
+ }
+ // If the operations match to the length of the shorter list, then pad its
+ // length with the matching identity operations.
+ // https://drafts.csswg.org/css-transforms/#transform-function-lists
+ return std::max(operations_.size(), other.operations_.size());
+}
+
+bool TransformOperations::CanBlendWith(const TransformOperations& other) const {
+ TransformOperations dummy;
+ return BlendInternal(other, 0.5, &dummy);
+}
+
+void TransformOperations::AppendTranslate(SkScalar x, SkScalar y, SkScalar z) {
+ TransformOperation to_add;
+ to_add.matrix.Translate3d(x, y, z);
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_TRANSLATE;
+ to_add.translate.x = x;
+ to_add.translate.y = y;
+ to_add.translate.z = z;
+ operations_.push_back(to_add);
+ decomposed_transforms_.clear();
+}
+
+void TransformOperations::AppendRotate(SkScalar x,
+ SkScalar y,
+ SkScalar z,
+ SkScalar degrees) {
+ TransformOperation to_add;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_ROTATE;
+ to_add.rotate.axis.x = x;
+ to_add.rotate.axis.y = y;
+ to_add.rotate.axis.z = z;
+ to_add.rotate.angle = degrees;
+ to_add.Bake();
+ operations_.push_back(to_add);
+ decomposed_transforms_.clear();
+}
+
+void TransformOperations::AppendScale(SkScalar x, SkScalar y, SkScalar z) {
+ TransformOperation to_add;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_SCALE;
+ to_add.scale.x = x;
+ to_add.scale.y = y;
+ to_add.scale.z = z;
+ to_add.Bake();
+ operations_.push_back(to_add);
+ decomposed_transforms_.clear();
+}
+
+void TransformOperations::AppendSkewX(SkScalar x) {
+ TransformOperation to_add;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEWX;
+ to_add.skew.x = x;
+ to_add.skew.y = 0;
+ to_add.Bake();
+ operations_.push_back(to_add);
+ decomposed_transforms_.clear();
+}
+
+void TransformOperations::AppendSkewY(SkScalar y) {
+ TransformOperation to_add;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEWY;
+ to_add.skew.x = 0;
+ to_add.skew.y = y;
+ to_add.Bake();
+ operations_.push_back(to_add);
+ decomposed_transforms_.clear();
+}
+
+void TransformOperations::AppendSkew(SkScalar x, SkScalar y) {
+ TransformOperation to_add;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEW;
+ to_add.skew.x = x;
+ to_add.skew.y = y;
+ to_add.Bake();
+ operations_.push_back(to_add);
+ decomposed_transforms_.clear();
+}
+
+void TransformOperations::AppendPerspective(SkScalar depth) {
+ TransformOperation to_add;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE;
+ to_add.perspective_depth = depth;
+ to_add.Bake();
+ operations_.push_back(to_add);
+ decomposed_transforms_.clear();
+}
+
+void TransformOperations::AppendMatrix(const Transform& matrix) {
+ TransformOperation to_add;
+ to_add.matrix = matrix;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_MATRIX;
+ operations_.push_back(to_add);
+ decomposed_transforms_.clear();
+}
+
+void TransformOperations::AppendIdentity() {
+ operations_.push_back(TransformOperation());
+}
+
+void TransformOperations::Append(const TransformOperation& operation) {
+ operations_.push_back(operation);
+ decomposed_transforms_.clear();
+}
+
+bool TransformOperations::IsIdentity() const {
+ for (auto& operation : operations_) {
+ if (!operation.IsIdentity())
+ return false;
+ }
+ return true;
+}
+
+bool TransformOperations::ApproximatelyEqual(const TransformOperations& other,
+ SkScalar tolerance) const {
+ if (size() != other.size())
+ return false;
+ for (size_t i = 0; i < operations_.size(); ++i) {
+ if (!operations_[i].ApproximatelyEqual(other.operations_[i], tolerance))
+ return false;
+ }
+ return true;
+}
+
+bool TransformOperations::BlendInternal(const TransformOperations& from,
+ SkScalar progress,
+ TransformOperations* result) const {
+ bool from_identity = from.IsIdentity();
+ bool to_identity = IsIdentity();
+ if (from_identity && to_identity)
+ return true;
+
+ size_t matching_prefix_length = MatchingPrefixLength(from);
+ size_t from_size = from_identity ? 0 : from.operations_.size();
+ size_t to_size = to_identity ? 0 : operations_.size();
+ size_t num_operations = std::max(from_size, to_size);
+
+ for (size_t i = 0; i < matching_prefix_length; ++i) {
+ TransformOperation blended;
+ if (!TransformOperation::BlendTransformOperations(
+ i >= from_size ? nullptr : &from.operations_[i],
+ i >= to_size ? nullptr : &operations_[i], progress, &blended)) {
+ return false;
+ }
+ result->Append(blended);
+ }
+
+ if (matching_prefix_length < num_operations) {
+ if (!ComputeDecomposedTransform(matching_prefix_length) ||
+ !from.ComputeDecomposedTransform(matching_prefix_length)) {
+ return false;
+ }
+ DecomposedTransform matrix_transform = BlendDecomposedTransforms(
+ *decomposed_transforms_[matching_prefix_length].get(),
+ *from.decomposed_transforms_[matching_prefix_length].get(), progress);
+ result->AppendMatrix(ComposeTransform(matrix_transform));
+ }
+ return true;
+}
+
+bool TransformOperations::ComputeDecomposedTransform(
+ size_t start_offset) const {
+ auto it = decomposed_transforms_.find(start_offset);
+ if (it == decomposed_transforms_.end()) {
+ std::unique_ptr<DecomposedTransform> decomposed_transform =
+ std::make_unique<DecomposedTransform>();
+ Transform transform = ApplyRemaining(start_offset);
+ if (!DecomposeTransform(decomposed_transform.get(), transform))
+ return false;
+ decomposed_transforms_[start_offset] = std::move(decomposed_transform);
+ }
+ return true;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/transform_operations.h b/chromium/ui/gfx/transform_operations.h
new file mode 100644
index 00000000000..d85242abe1c
--- /dev/null
+++ b/chromium/ui/gfx/transform_operations.h
@@ -0,0 +1,140 @@
+// 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_GFX_TRANSFORM_OPERATIONS_H_
+#define UI_GFX_TRANSFORM_OPERATIONS_H_
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "base/check_op.h"
+#include "base/gtest_prod_util.h"
+#include "ui/gfx/geometry_skia_export.h"
+#include "ui/gfx/transform.h"
+#include "ui/gfx/transform_operation.h"
+
+namespace gfx {
+
+class BoxF;
+struct DecomposedTransform;
+
+// Transform operations are a decomposed transformation matrix. It can be
+// applied to obtain a Transform at any time, and can be blended
+// intelligently with other transform operations, so long as they represent the
+// same decomposition. For example, if we have a transform that is made up of
+// a rotation followed by skew, it can be blended intelligently with another
+// transform made up of a rotation followed by a skew. Blending is possible if
+// we have two dissimilar sets of transform operations, but the effect may not
+// be what was intended. For more information, see the comments for the blend
+// function below.
+class GEOMETRY_SKIA_EXPORT TransformOperations {
+ public:
+ TransformOperations();
+ TransformOperations(const TransformOperations& other);
+ ~TransformOperations();
+
+ TransformOperations& operator=(const TransformOperations& other);
+
+ // Returns a transformation matrix representing these transform operations.
+ Transform Apply() const;
+
+ // Returns a transformation matrix representing the set of transform
+ // operations from index |start| to the end of the list.
+ Transform ApplyRemaining(size_t start) const;
+
+ // Given another set of transform operations and a progress in the range
+ // [0, 1], returns a transformation matrix representing the intermediate
+ // value. If this->MatchesTypes(from), then each of the operations are
+ // blended separately and then combined. Otherwise, the two sets of
+ // transforms are baked to matrices (using apply), and the matrices are
+ // then decomposed and interpolated. For more information, see
+ // http://www.w3.org/TR/2011/WD-css3-2d-transforms-20111215/#matrix-decomposition.
+ //
+ // If either of the matrices are non-decomposable for the blend, Blend applies
+ // discrete interpolation between them based on the progress value.
+ TransformOperations Blend(const TransformOperations& from,
+ SkScalar progress) const;
+
+ // Sets |bounds| be the bounding box for the region within which |box| will
+ // exist when it is transformed by the result of calling Blend on |from| and
+ // with progress in the range [min_progress, max_progress]. If this region
+ // cannot be computed, returns false.
+ bool BlendedBoundsForBox(const BoxF& box,
+ const TransformOperations& from,
+ SkScalar min_progress,
+ SkScalar max_progress,
+ BoxF* bounds) const;
+
+ // Returns true if these operations are only translations.
+ bool IsTranslation() const;
+
+ // Returns false if the operations affect 2d axis alignment.
+ bool PreservesAxisAlignment() const;
+
+ // Returns true if this operation and its descendants have the same types
+ // as other and its descendants.
+ bool MatchesTypes(const TransformOperations& other) const;
+
+ // Returns the number of matching transform operations at the start of the
+ // transform lists. If one list is shorter but pairwise compatible, it will be
+ // extended with matching identity operators per spec
+ // (https://drafts.csswg.org/css-transforms/#interpolation-of-transforms).
+ size_t MatchingPrefixLength(const TransformOperations& other) const;
+
+ // Returns true if these operations can be blended. It will only return
+ // false if we must resort to matrix interpolation, and matrix interpolation
+ // fails (this can happen if either matrix cannot be decomposed).
+ bool CanBlendWith(const TransformOperations& other) const;
+
+ // If none of these operations have a perspective component, sets |scale| to
+ // be the product of the scale component of every operation. Otherwise,
+ // returns false.
+ bool ScaleComponent(SkScalar* scale) const;
+
+ void AppendTranslate(SkScalar x, SkScalar y, SkScalar z);
+ void AppendRotate(SkScalar x, SkScalar y, SkScalar z, SkScalar degrees);
+ void AppendScale(SkScalar x, SkScalar y, SkScalar z);
+ void AppendSkewX(SkScalar x);
+ void AppendSkewY(SkScalar y);
+ void AppendSkew(SkScalar x, SkScalar y);
+ void AppendPerspective(SkScalar depth);
+ void AppendMatrix(const Transform& matrix);
+ void AppendIdentity();
+ void Append(const TransformOperation& operation);
+ bool IsIdentity() const;
+
+ size_t size() const { return operations_.size(); }
+
+ const TransformOperation& at(size_t index) const {
+ DCHECK_LT(index, size());
+ return operations_[index];
+ }
+ TransformOperation& at(size_t index) {
+ DCHECK_LT(index, size());
+ return operations_[index];
+ }
+
+ bool ApproximatelyEqual(const TransformOperations& other,
+ SkScalar tolerance) const;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(TransformOperationsTest, TestDecompositionCache);
+
+ bool BlendInternal(const TransformOperations& from,
+ SkScalar progress,
+ TransformOperations* result) const;
+
+ std::vector<TransformOperation> operations_;
+
+ bool ComputeDecomposedTransform(size_t start_offset) const;
+
+ // For efficiency, we cache the decomposed transforms.
+ mutable std::unordered_map<size_t, std::unique_ptr<DecomposedTransform>>
+ decomposed_transforms_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_TRANSFORM_OPERATIONS_H_
diff --git a/chromium/ui/gfx/transform_operations_unittest.cc b/chromium/ui/gfx/transform_operations_unittest.cc
new file mode 100644
index 00000000000..5a432b63648
--- /dev/null
+++ b/chromium/ui/gfx/transform_operations_unittest.cc
@@ -0,0 +1,1812 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/transform_operations.h"
+
+#include <stddef.h>
+
+#include <limits>
+#include <utility>
+#include <vector>
+
+#include "base/stl_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/test/transform_test_util.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace gfx {
+namespace {
+
+void ExpectTransformOperationEqual(const TransformOperation& lhs,
+ const TransformOperation& rhs) {
+ EXPECT_EQ(lhs.type, rhs.type);
+ ExpectTransformationMatrixEq(lhs.matrix, rhs.matrix);
+ switch (lhs.type) {
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
+ EXPECT_FLOAT_EQ(lhs.translate.x, rhs.translate.x);
+ EXPECT_FLOAT_EQ(lhs.translate.y, rhs.translate.y);
+ EXPECT_FLOAT_EQ(lhs.translate.z, rhs.translate.z);
+ break;
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ EXPECT_FLOAT_EQ(lhs.rotate.axis.x, rhs.rotate.axis.x);
+ EXPECT_FLOAT_EQ(lhs.rotate.axis.y, rhs.rotate.axis.y);
+ EXPECT_FLOAT_EQ(lhs.rotate.axis.z, rhs.rotate.axis.z);
+ EXPECT_FLOAT_EQ(lhs.rotate.angle, rhs.rotate.angle);
+ break;
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
+ EXPECT_FLOAT_EQ(lhs.scale.x, rhs.scale.x);
+ EXPECT_FLOAT_EQ(lhs.scale.y, rhs.scale.y);
+ EXPECT_FLOAT_EQ(lhs.scale.z, rhs.scale.z);
+ break;
+ case TransformOperation::TRANSFORM_OPERATION_SKEWX:
+ case TransformOperation::TRANSFORM_OPERATION_SKEWY:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ EXPECT_FLOAT_EQ(lhs.skew.x, rhs.skew.x);
+ EXPECT_FLOAT_EQ(lhs.skew.y, rhs.skew.y);
+ break;
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
+ EXPECT_FLOAT_EQ(lhs.perspective_depth, rhs.perspective_depth);
+ break;
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ break;
+ }
+}
+
+TEST(TransformOperationTest, TransformTypesAreUnique) {
+ std::vector<std::unique_ptr<TransformOperations>> transforms;
+
+ std::unique_ptr<TransformOperations> to_add(
+ std::make_unique<TransformOperations>());
+ to_add->AppendTranslate(1, 0, 0);
+ transforms.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendRotate(0, 0, 1, 2);
+ transforms.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendScale(2, 2, 2);
+ transforms.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendSkew(1, 0);
+ transforms.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendPerspective(800);
+ transforms.push_back(std::move(to_add));
+
+ for (size_t i = 0; i < transforms.size(); ++i) {
+ for (size_t j = 0; j < transforms.size(); ++j) {
+ bool matches_type = transforms[i]->MatchesTypes(*transforms[j]);
+ EXPECT_TRUE((i == j && matches_type) || !matches_type);
+ }
+ }
+}
+
+TEST(TransformOperationTest, MatchingPrefixSameLength) {
+ TransformOperations translates;
+ translates.AppendTranslate(1, 0, 0);
+ translates.AppendTranslate(1, 0, 0);
+ translates.AppendTranslate(1, 0, 0);
+
+ TransformOperations skews;
+ skews.AppendSkew(0, 2);
+ skews.AppendSkew(0, 2);
+ skews.AppendSkew(0, 2);
+
+ TransformOperations translates2;
+ translates2.AppendTranslate(0, 2, 0);
+ translates2.AppendTranslate(0, 2, 0);
+ translates2.AppendTranslate(0, 2, 0);
+
+ TransformOperations mixed;
+ mixed.AppendTranslate(0, 2, 0);
+ mixed.AppendScale(2, 1, 1);
+ mixed.AppendSkew(0, 2);
+
+ TransformOperations translates3 = translates2;
+
+ EXPECT_EQ(0UL, translates.MatchingPrefixLength(skews));
+ EXPECT_EQ(3UL, translates.MatchingPrefixLength(translates2));
+ EXPECT_EQ(3UL, translates.MatchingPrefixLength(translates3));
+ EXPECT_EQ(1UL, translates.MatchingPrefixLength(mixed));
+}
+
+TEST(TransformOperationTest, MatchingPrefixDifferentLength) {
+ TransformOperations translates;
+ translates.AppendTranslate(1, 0, 0);
+ translates.AppendTranslate(1, 0, 0);
+ translates.AppendTranslate(1, 0, 0);
+
+ TransformOperations skews;
+ skews.AppendSkew(2, 0);
+ skews.AppendSkew(2, 0);
+
+ TransformOperations translates2;
+ translates2.AppendTranslate(0, 2, 0);
+ translates2.AppendTranslate(0, 2, 0);
+
+ TransformOperations none;
+
+ EXPECT_EQ(0UL, translates.MatchingPrefixLength(skews));
+ // Pad the length of the shorter list provided all previous operation-
+ // pairs match per spec
+ // (https://drafts.csswg.org/css-transforms/#interpolation-of-transforms).
+ EXPECT_EQ(3UL, translates.MatchingPrefixLength(translates2));
+ EXPECT_EQ(3UL, translates.MatchingPrefixLength(none));
+}
+
+std::vector<std::unique_ptr<TransformOperations>> GetIdentityOperations() {
+ std::vector<std::unique_ptr<TransformOperations>> operations;
+ std::unique_ptr<TransformOperations> to_add(
+ std::make_unique<TransformOperations>());
+ operations.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendTranslate(0, 0, 0);
+ operations.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendTranslate(0, 0, 0);
+ to_add->AppendTranslate(0, 0, 0);
+ operations.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendScale(1, 1, 1);
+ operations.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendScale(1, 1, 1);
+ to_add->AppendScale(1, 1, 1);
+ operations.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendSkew(0, 0);
+ operations.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendSkew(0, 0);
+ to_add->AppendSkew(0, 0);
+ operations.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendRotate(0, 0, 1, 0);
+ operations.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendRotate(0, 0, 1, 0);
+ to_add->AppendRotate(0, 0, 1, 0);
+ operations.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendMatrix(gfx::Transform());
+ operations.push_back(std::move(to_add));
+
+ to_add = std::make_unique<TransformOperations>();
+ to_add->AppendMatrix(gfx::Transform());
+ to_add->AppendMatrix(gfx::Transform());
+ operations.push_back(std::move(to_add));
+
+ return operations;
+}
+
+TEST(TransformOperationTest, MatchingPrefixLengthOrder) {
+ TransformOperations mix_order_identity;
+ mix_order_identity.AppendTranslate(0, 0, 0);
+ mix_order_identity.AppendScale(1, 1, 1);
+ mix_order_identity.AppendTranslate(0, 0, 0);
+
+ TransformOperations mix_order_one;
+ mix_order_one.AppendTranslate(0, 1, 0);
+ mix_order_one.AppendScale(2, 1, 3);
+ mix_order_one.AppendTranslate(1, 0, 0);
+
+ TransformOperations mix_order_two;
+ mix_order_two.AppendTranslate(0, 1, 0);
+ mix_order_two.AppendTranslate(1, 0, 0);
+ mix_order_two.AppendScale(2, 1, 3);
+
+ EXPECT_EQ(3UL, mix_order_identity.MatchingPrefixLength(mix_order_one));
+ EXPECT_EQ(1UL, mix_order_identity.MatchingPrefixLength(mix_order_two));
+ EXPECT_EQ(1UL, mix_order_one.MatchingPrefixLength(mix_order_two));
+}
+
+TEST(TransformOperationTest, NoneAlwaysMatches) {
+ std::vector<std::unique_ptr<TransformOperations>> operations =
+ GetIdentityOperations();
+
+ TransformOperations none_operation;
+ for (size_t i = 0; i < operations.size(); ++i)
+ EXPECT_EQ(operations[i]->size(),
+ operations[i]->MatchingPrefixLength(none_operation));
+}
+
+TEST(TransformOperationTest, ApplyTranslate) {
+ SkScalar x = 1;
+ SkScalar y = 2;
+ SkScalar z = 3;
+ TransformOperations operations;
+ operations.AppendTranslate(x, y, z);
+ gfx::Transform expected;
+ expected.Translate3d(x, y, z);
+ ExpectTransformationMatrixEq(expected, operations.Apply());
+}
+
+TEST(TransformOperationTest, ApplyRotate) {
+ SkScalar x = 1;
+ SkScalar y = 2;
+ SkScalar z = 3;
+ SkScalar degrees = 80;
+ TransformOperations operations;
+ operations.AppendRotate(x, y, z, degrees);
+ gfx::Transform expected;
+ expected.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
+ ExpectTransformationMatrixEq(expected, operations.Apply());
+}
+
+TEST(TransformOperationTest, ApplyScale) {
+ SkScalar x = 1;
+ SkScalar y = 2;
+ SkScalar z = 3;
+ TransformOperations operations;
+ operations.AppendScale(x, y, z);
+ gfx::Transform expected;
+ expected.Scale3d(x, y, z);
+ ExpectTransformationMatrixEq(expected, operations.Apply());
+}
+
+TEST(TransformOperationTest, ApplySkew) {
+ SkScalar x = 1;
+ SkScalar y = 2;
+ TransformOperations operations;
+ operations.AppendSkew(x, y);
+ gfx::Transform expected;
+ expected.Skew(x, y);
+ ExpectTransformationMatrixEq(expected, operations.Apply());
+}
+
+TEST(TransformOperationTest, ApplyPerspective) {
+ SkScalar depth = 800;
+ TransformOperations operations;
+ operations.AppendPerspective(depth);
+ gfx::Transform expected;
+ expected.ApplyPerspectiveDepth(depth);
+ ExpectTransformationMatrixEq(expected, operations.Apply());
+}
+
+TEST(TransformOperationTest, ApplyMatrix) {
+ SkScalar dx = 1;
+ SkScalar dy = 2;
+ SkScalar dz = 3;
+ gfx::Transform expected_matrix;
+ expected_matrix.Translate3d(dx, dy, dz);
+ TransformOperations matrix_transform;
+ matrix_transform.AppendMatrix(expected_matrix);
+ ExpectTransformationMatrixEq(expected_matrix, matrix_transform.Apply());
+}
+
+TEST(TransformOperationTest, ApplyOrder) {
+ SkScalar sx = 2;
+ SkScalar sy = 4;
+ SkScalar sz = 8;
+
+ SkScalar dx = 1;
+ SkScalar dy = 2;
+ SkScalar dz = 3;
+
+ TransformOperations operations;
+ operations.AppendScale(sx, sy, sz);
+ operations.AppendTranslate(dx, dy, dz);
+
+ gfx::Transform expected_scale_matrix;
+ expected_scale_matrix.Scale3d(sx, sy, sz);
+
+ gfx::Transform expected_translate_matrix;
+ expected_translate_matrix.Translate3d(dx, dy, dz);
+
+ gfx::Transform expected_combined_matrix = expected_scale_matrix;
+ expected_combined_matrix.PreconcatTransform(expected_translate_matrix);
+
+ ExpectTransformationMatrixEq(expected_combined_matrix, operations.Apply());
+}
+
+TEST(TransformOperationTest, BlendOrder) {
+ SkScalar sx1 = 2;
+ SkScalar sy1 = 4;
+ SkScalar sz1 = 8;
+
+ SkScalar dx1 = 1;
+ SkScalar dy1 = 2;
+ SkScalar dz1 = 3;
+
+ SkScalar sx2 = 4;
+ SkScalar sy2 = 8;
+ SkScalar sz2 = 16;
+
+ SkScalar dx2 = 10;
+ SkScalar dy2 = 20;
+ SkScalar dz2 = 30;
+
+ SkScalar sx3 = 2;
+ SkScalar sy3 = 1;
+ SkScalar sz3 = 1;
+
+ TransformOperations operations_from;
+ operations_from.AppendScale(sx1, sy1, sz1);
+ operations_from.AppendTranslate(dx1, dy1, dz1);
+
+ TransformOperations operations_to;
+ operations_to.AppendScale(sx2, sy2, sz2);
+ operations_to.AppendTranslate(dx2, dy2, dz2);
+
+ gfx::Transform scale_from;
+ scale_from.Scale3d(sx1, sy1, sz1);
+ gfx::Transform translate_from;
+ translate_from.Translate3d(dx1, dy1, dz1);
+
+ gfx::Transform scale_to;
+ scale_to.Scale3d(sx2, sy2, sz2);
+ gfx::Transform translate_to;
+ translate_to.Translate3d(dx2, dy2, dz2);
+
+ SkScalar progress = 0.25f;
+
+ TransformOperations operations_expected;
+ operations_expected.AppendScale(
+ gfx::Tween::FloatValueBetween(progress, sx1, sx2),
+ gfx::Tween::FloatValueBetween(progress, sy1, sy2),
+ gfx::Tween::FloatValueBetween(progress, sz1, sz2));
+
+ operations_expected.AppendTranslate(
+ gfx::Tween::FloatValueBetween(progress, dx1, dx2),
+ gfx::Tween::FloatValueBetween(progress, dy1, dy2),
+ gfx::Tween::FloatValueBetween(progress, dz1, dz2));
+
+ gfx::Transform blended_scale = scale_to;
+ blended_scale.Blend(scale_from, progress);
+
+ gfx::Transform blended_translate = translate_to;
+ blended_translate.Blend(translate_from, progress);
+
+ gfx::Transform expected = blended_scale;
+ expected.PreconcatTransform(blended_translate);
+
+ TransformOperations blended = operations_to.Blend(operations_from, progress);
+
+ ExpectTransformationMatrixEq(expected, blended.Apply());
+ ExpectTransformationMatrixEq(operations_expected.Apply(), blended.Apply());
+ EXPECT_EQ(operations_expected.size(), blended.size());
+ for (size_t i = 0; i < operations_expected.size(); ++i) {
+ TransformOperation expected_op = operations_expected.at(i);
+ TransformOperation blended_op = blended.at(i);
+ SCOPED_TRACE(i);
+ ExpectTransformOperationEqual(expected_op, blended_op);
+ }
+
+ TransformOperations base_operations_expected = operations_expected;
+
+ // Create a mismatch in number of operations. Pairwise interpolation is still
+ // used when the operations match up to the length of the shorter list.
+ operations_to.AppendScale(sx3, sy3, sz3);
+
+ gfx::Transform appended_scale;
+ appended_scale.Scale3d(sx3, sy3, sz3);
+
+ gfx::Transform blended_append_scale = appended_scale;
+ blended_append_scale.Blend(gfx::Transform(), progress);
+ expected.PreconcatTransform(blended_append_scale);
+
+ operations_expected.AppendScale(
+ gfx::Tween::FloatValueBetween(progress, 1, sx3),
+ gfx::Tween::FloatValueBetween(progress, 1, sy3),
+ gfx::Tween::FloatValueBetween(progress, 1, sz3));
+
+ blended = operations_to.Blend(operations_from, progress);
+
+ ExpectTransformationMatrixEq(expected, blended.Apply());
+ ExpectTransformationMatrixEq(operations_expected.Apply(), blended.Apply());
+ EXPECT_EQ(operations_expected.size(), blended.size());
+ for (size_t i = 0; i < operations_expected.size(); ++i) {
+ TransformOperation expected_op = operations_expected.at(i);
+ TransformOperation blended_op = blended.at(i);
+ SCOPED_TRACE(i);
+ ExpectTransformOperationEqual(expected_op, blended_op);
+ }
+
+ // Create a mismatch, forcing matrix interpolation for the last operator pair.
+ operations_from.AppendRotate(0, 0, 1, 90);
+
+ blended = operations_to.Blend(operations_from, progress);
+
+ gfx::Transform transform_from;
+ transform_from.RotateAboutZAxis(90);
+ gfx::Transform transform_to;
+ transform_to.Scale3d(sx3, sy3, sz3);
+ gfx::Transform blended_matrix = transform_to;
+ blended_matrix.Blend(transform_from, progress);
+
+ expected = blended_scale;
+ expected.PreconcatTransform(blended_translate);
+ expected.PreconcatTransform(blended_matrix);
+
+ operations_expected = base_operations_expected;
+ operations_expected.AppendMatrix(blended_matrix);
+
+ ExpectTransformationMatrixEq(expected, blended.Apply());
+ ExpectTransformationMatrixEq(operations_expected.Apply(), blended.Apply());
+ EXPECT_EQ(operations_expected.size(), blended.size());
+ for (size_t i = 0; i < operations_expected.size(); ++i) {
+ TransformOperation expected_op = operations_expected.at(i);
+ TransformOperation blended_op = blended.at(i);
+ SCOPED_TRACE(i);
+ ExpectTransformOperationEqual(expected_op, blended_op);
+ }
+}
+
+static void CheckProgress(SkScalar progress,
+ const gfx::Transform& from_matrix,
+ const gfx::Transform& to_matrix,
+ const TransformOperations& from_transform,
+ const TransformOperations& to_transform) {
+ gfx::Transform expected_matrix = to_matrix;
+ expected_matrix.Blend(from_matrix, progress);
+ ExpectTransformationMatrixEq(
+ expected_matrix, to_transform.Blend(from_transform, progress).Apply());
+}
+
+TEST(TransformOperationTest, BlendProgress) {
+ SkScalar sx = 2;
+ SkScalar sy = 4;
+ SkScalar sz = 8;
+ TransformOperations operations_from;
+ operations_from.AppendScale(sx, sy, sz);
+
+ gfx::Transform matrix_from;
+ matrix_from.Scale3d(sx, sy, sz);
+
+ sx = 4;
+ sy = 8;
+ sz = 16;
+ TransformOperations operations_to;
+ operations_to.AppendScale(sx, sy, sz);
+
+ gfx::Transform matrix_to;
+ matrix_to.Scale3d(sx, sy, sz);
+
+ CheckProgress(-1, matrix_from, matrix_to, operations_from, operations_to);
+ CheckProgress(0, matrix_from, matrix_to, operations_from, operations_to);
+ CheckProgress(0.25f, matrix_from, matrix_to, operations_from, operations_to);
+ CheckProgress(0.5f, matrix_from, matrix_to, operations_from, operations_to);
+ CheckProgress(1, matrix_from, matrix_to, operations_from, operations_to);
+ CheckProgress(2, matrix_from, matrix_to, operations_from, operations_to);
+}
+
+TEST(TransformOperationTest, BlendWhenTypesDoNotMatch) {
+ SkScalar sx1 = 2;
+ SkScalar sy1 = 4;
+ SkScalar sz1 = 8;
+
+ SkScalar dx1 = 1;
+ SkScalar dy1 = 2;
+ SkScalar dz1 = 3;
+
+ SkScalar sx2 = 4;
+ SkScalar sy2 = 8;
+ SkScalar sz2 = 16;
+
+ SkScalar dx2 = 10;
+ SkScalar dy2 = 20;
+ SkScalar dz2 = 30;
+
+ TransformOperations operations_from;
+ operations_from.AppendScale(sx1, sy1, sz1);
+ operations_from.AppendTranslate(dx1, dy1, dz1);
+
+ TransformOperations operations_to;
+ operations_to.AppendTranslate(dx2, dy2, dz2);
+ operations_to.AppendScale(sx2, sy2, sz2);
+
+ gfx::Transform from;
+ from.Scale3d(sx1, sy1, sz1);
+ from.Translate3d(dx1, dy1, dz1);
+
+ gfx::Transform to;
+ to.Translate3d(dx2, dy2, dz2);
+ to.Scale3d(sx2, sy2, sz2);
+
+ SkScalar progress = 0.25f;
+
+ gfx::Transform expected = to;
+ expected.Blend(from, progress);
+
+ ExpectTransformationMatrixEq(
+ expected, operations_to.Blend(operations_from, progress).Apply());
+}
+
+TEST(TransformOperationTest, LargeRotationsWithSameAxis) {
+ TransformOperations operations_from;
+ operations_from.AppendRotate(0, 0, 1, 0);
+
+ TransformOperations operations_to;
+ operations_to.AppendRotate(0, 0, 2, 360);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+ expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 180);
+
+ ExpectTransformationMatrixEq(
+ expected, operations_to.Blend(operations_from, progress).Apply());
+}
+
+TEST(TransformOperationTest, LargeRotationsWithSameAxisInDifferentDirection) {
+ TransformOperations operations_from;
+ operations_from.AppendRotate(0, 0, 1, 180);
+
+ TransformOperations operations_to;
+ operations_to.AppendRotate(0, 0, -1, 180);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+
+ ExpectTransformationMatrixEq(
+ expected, operations_to.Blend(operations_from, progress).Apply());
+}
+
+TEST(TransformOperationTest, LargeRotationsWithDifferentAxes) {
+ TransformOperations operations_from;
+ operations_from.AppendRotate(0, 0, 1, 175);
+
+ TransformOperations operations_to;
+ operations_to.AppendRotate(0, 1, 0, 175);
+
+ SkScalar progress = 0.5f;
+ gfx::Transform matrix_from;
+ matrix_from.RotateAbout(gfx::Vector3dF(0, 0, 1), 175);
+
+ gfx::Transform matrix_to;
+ matrix_to.RotateAbout(gfx::Vector3dF(0, 1, 0), 175);
+
+ gfx::Transform expected = matrix_to;
+ expected.Blend(matrix_from, progress);
+
+ ExpectTransformationMatrixEq(
+ expected, operations_to.Blend(operations_from, progress).Apply());
+}
+
+TEST(TransformOperationTest, RotationFromZeroDegDifferentAxes) {
+ TransformOperations operations_from;
+ operations_from.AppendRotate(0, 0, 1, 0);
+
+ TransformOperations operations_to;
+ operations_to.AppendRotate(0, 1, 0, 450);
+
+ SkScalar progress = 0.5f;
+ gfx::Transform expected;
+ expected.RotateAbout(gfx::Vector3dF(0, 1, 0), 225);
+ ExpectTransformationMatrixEq(
+ expected, operations_to.Blend(operations_from, progress).Apply());
+}
+
+TEST(TransformOperationTest, RotationFromZeroDegSameAxes) {
+ TransformOperations operations_from;
+ operations_from.AppendRotate(0, 0, 1, 0);
+
+ TransformOperations operations_to;
+ operations_to.AppendRotate(0, 0, 1, 450);
+
+ SkScalar progress = 0.5f;
+ gfx::Transform expected;
+ expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 225);
+ ExpectTransformationMatrixEq(
+ expected, operations_to.Blend(operations_from, progress).Apply());
+}
+
+TEST(TransformOperationTest, RotationToZeroDegDifferentAxes) {
+ TransformOperations operations_from;
+ operations_from.AppendRotate(0, 1, 0, 450);
+
+ TransformOperations operations_to;
+ operations_to.AppendRotate(0, 0, 1, 0);
+
+ SkScalar progress = 0.5f;
+ gfx::Transform expected;
+ expected.RotateAbout(gfx::Vector3dF(0, 1, 0), 225);
+ ExpectTransformationMatrixEq(
+ expected, operations_to.Blend(operations_from, progress).Apply());
+}
+
+TEST(TransformOperationTest, RotationToZeroDegSameAxes) {
+ TransformOperations operations_from;
+ operations_from.AppendRotate(0, 0, 1, 450);
+
+ TransformOperations operations_to;
+ operations_to.AppendRotate(0, 0, 1, 0);
+
+ SkScalar progress = 0.5f;
+ gfx::Transform expected;
+ expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 225);
+ ExpectTransformationMatrixEq(
+ expected, operations_to.Blend(operations_from, progress).Apply());
+}
+
+TEST(TransformOperationTest, BlendRotationFromIdentity) {
+ std::vector<std::unique_ptr<TransformOperations>> identity_operations =
+ GetIdentityOperations();
+
+ for (size_t i = 0; i < identity_operations.size(); ++i) {
+ TransformOperations operations;
+ operations.AppendRotate(0, 0, 1, 90);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+ expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 45);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(*identity_operations[i], progress).Apply());
+
+ progress = -0.5f;
+
+ expected.MakeIdentity();
+ expected.RotateAbout(gfx::Vector3dF(0, 0, 1), -45);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(*identity_operations[i], progress).Apply());
+
+ progress = 1.5f;
+
+ expected.MakeIdentity();
+ expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 135);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(*identity_operations[i], progress).Apply());
+ }
+}
+
+TEST(TransformOperationTest, BlendTranslationFromIdentity) {
+ std::vector<std::unique_ptr<TransformOperations>> identity_operations =
+ GetIdentityOperations();
+
+ for (size_t i = 0; i < identity_operations.size(); ++i) {
+ TransformOperations operations;
+ operations.AppendTranslate(2, 2, 2);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+ expected.Translate3d(1, 1, 1);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(*identity_operations[i], progress).Apply());
+
+ progress = -0.5f;
+
+ expected.MakeIdentity();
+ expected.Translate3d(-1, -1, -1);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(*identity_operations[i], progress).Apply());
+
+ progress = 1.5f;
+
+ expected.MakeIdentity();
+ expected.Translate3d(3, 3, 3);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(*identity_operations[i], progress).Apply());
+ }
+}
+
+TEST(TransformOperationTest, BlendScaleFromIdentity) {
+ std::vector<std::unique_ptr<TransformOperations>> identity_operations =
+ GetIdentityOperations();
+
+ for (size_t i = 0; i < identity_operations.size(); ++i) {
+ TransformOperations operations;
+ operations.AppendScale(3, 3, 3);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+ expected.Scale3d(2, 2, 2);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(*identity_operations[i], progress).Apply());
+
+ progress = -0.5f;
+
+ expected.MakeIdentity();
+ expected.Scale3d(0, 0, 0);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(*identity_operations[i], progress).Apply());
+
+ progress = 1.5f;
+
+ expected.MakeIdentity();
+ expected.Scale3d(4, 4, 4);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(*identity_operations[i], progress).Apply());
+ }
+}
+
+TEST(TransformOperationTest, BlendSkewFromEmpty) {
+ TransformOperations empty_operation;
+
+ TransformOperations operations;
+ operations.AppendSkew(2, 2);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+ expected.Skew(1, 1);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(empty_operation, progress).Apply());
+
+ progress = -0.5f;
+
+ expected.MakeIdentity();
+ expected.Skew(-1, -1);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(empty_operation, progress).Apply());
+
+ progress = 1.5f;
+
+ expected.MakeIdentity();
+ expected.Skew(3, 3);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(empty_operation, progress).Apply());
+}
+
+TEST(TransformOperationTest, BlendPerspectiveFromIdentity) {
+ std::vector<std::unique_ptr<TransformOperations>> identity_operations =
+ GetIdentityOperations();
+
+ for (size_t i = 0; i < identity_operations.size(); ++i) {
+ TransformOperations operations;
+ operations.AppendPerspective(1000);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+ expected.ApplyPerspectiveDepth(2000);
+
+ ExpectTransformationMatrixEq(
+ expected, operations.Blend(*identity_operations[i], progress).Apply());
+ }
+}
+
+TEST(TransformOperationTest, BlendRotationToIdentity) {
+ std::vector<std::unique_ptr<TransformOperations>> identity_operations =
+ GetIdentityOperations();
+
+ for (size_t i = 0; i < identity_operations.size(); ++i) {
+ TransformOperations operations;
+ operations.AppendRotate(0, 0, 1, 90);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+ expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 45);
+
+ ExpectTransformationMatrixEq(
+ expected, identity_operations[i]->Blend(operations, progress).Apply());
+ }
+}
+
+TEST(TransformOperationTest, BlendTranslationToIdentity) {
+ std::vector<std::unique_ptr<TransformOperations>> identity_operations =
+ GetIdentityOperations();
+
+ for (size_t i = 0; i < identity_operations.size(); ++i) {
+ TransformOperations operations;
+ operations.AppendTranslate(2, 2, 2);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+ expected.Translate3d(1, 1, 1);
+
+ ExpectTransformationMatrixEq(
+ expected, identity_operations[i]->Blend(operations, progress).Apply());
+ }
+}
+
+TEST(TransformOperationTest, BlendScaleToIdentity) {
+ std::vector<std::unique_ptr<TransformOperations>> identity_operations =
+ GetIdentityOperations();
+
+ for (size_t i = 0; i < identity_operations.size(); ++i) {
+ TransformOperations operations;
+ operations.AppendScale(3, 3, 3);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+ expected.Scale3d(2, 2, 2);
+
+ ExpectTransformationMatrixEq(
+ expected, identity_operations[i]->Blend(operations, progress).Apply());
+ }
+}
+
+TEST(TransformOperationTest, BlendSkewToEmpty) {
+ TransformOperations empty_operation;
+
+ TransformOperations operations;
+ operations.AppendSkew(2, 2);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+ expected.Skew(1, 1);
+
+ ExpectTransformationMatrixEq(
+ expected, empty_operation.Blend(operations, progress).Apply());
+}
+
+TEST(TransformOperationTest, BlendPerspectiveToIdentity) {
+ std::vector<std::unique_ptr<TransformOperations>> identity_operations =
+ GetIdentityOperations();
+
+ for (size_t i = 0; i < identity_operations.size(); ++i) {
+ TransformOperations operations;
+ operations.AppendPerspective(1000);
+
+ SkScalar progress = 0.5f;
+
+ gfx::Transform expected;
+ expected.ApplyPerspectiveDepth(2000);
+
+ ExpectTransformationMatrixEq(
+ expected, identity_operations[i]->Blend(operations, progress).Apply());
+ }
+}
+
+TEST(TransformOperationTest, ExtrapolatePerspectiveBlending) {
+ TransformOperations operations1;
+ operations1.AppendPerspective(1000);
+
+ TransformOperations operations2;
+ operations2.AppendPerspective(500);
+
+ gfx::Transform expected;
+ expected.ApplyPerspectiveDepth(400);
+
+ ExpectTransformationMatrixEq(expected,
+ operations1.Blend(operations2, -0.5).Apply());
+
+ expected.MakeIdentity();
+ expected.ApplyPerspectiveDepth(2000);
+
+ ExpectTransformationMatrixEq(expected,
+ operations1.Blend(operations2, 1.5).Apply());
+}
+
+TEST(TransformOperationTest, ExtrapolateMatrixBlending) {
+ gfx::Transform transform1;
+ transform1.Translate3d(1, 1, 1);
+ TransformOperations operations1;
+ operations1.AppendMatrix(transform1);
+
+ gfx::Transform transform2;
+ transform2.Translate3d(3, 3, 3);
+ TransformOperations operations2;
+ operations2.AppendMatrix(transform2);
+
+ gfx::Transform expected;
+ ExpectTransformationMatrixEq(expected,
+ operations1.Blend(operations2, 1.5).Apply());
+
+ expected.Translate3d(4, 4, 4);
+ ExpectTransformationMatrixEq(expected,
+ operations1.Blend(operations2, -0.5).Apply());
+}
+
+TEST(TransformOperationTest, NonDecomposableBlend) {
+ TransformOperations non_decomposible_transform;
+ gfx::Transform non_decomposible_matrix(0, 0, 0, 0, 0, 0);
+ non_decomposible_transform.AppendMatrix(non_decomposible_matrix);
+
+ TransformOperations identity_transform;
+ gfx::Transform identity_matrix;
+ identity_transform.AppendMatrix(identity_matrix);
+
+ // Before the half-way point, we should return the 'from' matrix.
+ ExpectTransformationMatrixEq(
+ non_decomposible_matrix,
+ identity_transform.Blend(non_decomposible_transform, 0.0f).Apply());
+ ExpectTransformationMatrixEq(
+ non_decomposible_matrix,
+ identity_transform.Blend(non_decomposible_transform, 0.49f).Apply());
+
+ // After the half-way point, we should return the 'to' matrix.
+ ExpectTransformationMatrixEq(
+ identity_matrix,
+ identity_transform.Blend(non_decomposible_transform, 0.5f).Apply());
+ ExpectTransformationMatrixEq(
+ identity_matrix,
+ identity_transform.Blend(non_decomposible_transform, 1.0f).Apply());
+}
+
+TEST(TransformOperationTest, BlendedBoundsWhenTypesDoNotMatch) {
+ TransformOperations operations_from;
+ operations_from.AppendScale(2.0, 4.0, 8.0);
+ operations_from.AppendTranslate(1.0, 2.0, 3.0);
+
+ TransformOperations operations_to;
+ operations_to.AppendTranslate(10.0, 20.0, 30.0);
+ operations_to.AppendScale(4.0, 8.0, 16.0);
+
+ gfx::BoxF box(1.f, 1.f, 1.f);
+ gfx::BoxF bounds;
+
+ SkScalar min_progress = 0.f;
+ SkScalar max_progress = 1.f;
+
+ EXPECT_FALSE(operations_to.BlendedBoundsForBox(
+ box, operations_from, min_progress, max_progress, &bounds));
+}
+
+TEST(TransformOperationTest, BlendedBoundsForIdentity) {
+ TransformOperations operations_from;
+ operations_from.AppendIdentity();
+ TransformOperations operations_to;
+ operations_to.AppendIdentity();
+
+ gfx::BoxF box(1.f, 2.f, 3.f);
+ gfx::BoxF bounds;
+
+ SkScalar min_progress = 0.f;
+ SkScalar max_progress = 1.f;
+
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+ box, operations_from, min_progress, max_progress, &bounds));
+ EXPECT_EQ(box.ToString(), bounds.ToString());
+}
+
+TEST(TransformOperationTest, BlendedBoundsForTranslate) {
+ TransformOperations operations_from;
+ operations_from.AppendTranslate(3.0, -4.0, 2.0);
+ TransformOperations operations_to;
+ operations_to.AppendTranslate(7.0, 4.0, -2.0);
+
+ gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
+ gfx::BoxF bounds;
+
+ SkScalar min_progress = -0.5f;
+ SkScalar max_progress = 1.5f;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+ box, operations_from, min_progress, max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(2.f, -6.f, -1.f, 12.f, 20.f, 12.f).ToString(),
+ bounds.ToString());
+
+ min_progress = 0.f;
+ max_progress = 1.f;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+ box, operations_from, min_progress, max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(4.f, -2.f, 1.f, 8.f, 12.f, 8.f).ToString(),
+ bounds.ToString());
+
+ TransformOperations identity;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, identity, min_progress,
+ max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(1.f, 2.f, 1.f, 11.f, 8.f, 6.f).ToString(),
+ bounds.ToString());
+
+ EXPECT_TRUE(identity.BlendedBoundsForBox(box, operations_from, min_progress,
+ max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(1.f, -2.f, 3.f, 7.f, 8.f, 6.f).ToString(),
+ bounds.ToString());
+}
+
+TEST(TransformOperationTest, BlendedBoundsForScale) {
+ TransformOperations operations_from;
+ operations_from.AppendScale(3.0, 0.5, 2.0);
+ TransformOperations operations_to;
+ operations_to.AppendScale(7.0, 4.0, -2.0);
+
+ gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
+ gfx::BoxF bounds;
+
+ SkScalar min_progress = -0.5f;
+ SkScalar max_progress = 1.5f;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+ box, operations_from, min_progress, max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(1.f, -7.5f, -28.f, 44.f, 42.f, 56.f).ToString(),
+ bounds.ToString());
+
+ min_progress = 0.f;
+ max_progress = 1.f;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+ box, operations_from, min_progress, max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(3.f, 1.f, -14.f, 32.f, 23.f, 28.f).ToString(),
+ bounds.ToString());
+
+ TransformOperations identity;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, identity, min_progress,
+ max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(1.f, 2.f, -14.f, 34.f, 22.f, 21.f).ToString(),
+ bounds.ToString());
+
+ EXPECT_TRUE(identity.BlendedBoundsForBox(box, operations_from, min_progress,
+ max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(1.f, 1.f, 3.f, 14.f, 5.f, 11.f).ToString(),
+ bounds.ToString());
+}
+
+TEST(TransformOperationTest, BlendedBoundsWithZeroScale) {
+ TransformOperations zero_scale;
+ zero_scale.AppendScale(0.0, 0.0, 0.0);
+ TransformOperations non_zero_scale;
+ non_zero_scale.AppendScale(2.0, -4.0, 5.0);
+
+ gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
+ gfx::BoxF bounds;
+
+ SkScalar min_progress = 0.f;
+ SkScalar max_progress = 1.f;
+ EXPECT_TRUE(zero_scale.BlendedBoundsForBox(box, non_zero_scale, min_progress,
+ max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(0.f, -24.f, 0.f, 10.f, 24.f, 35.f).ToString(),
+ bounds.ToString());
+
+ EXPECT_TRUE(non_zero_scale.BlendedBoundsForBox(box, zero_scale, min_progress,
+ max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(0.f, -24.f, 0.f, 10.f, 24.f, 35.f).ToString(),
+ bounds.ToString());
+
+ EXPECT_TRUE(zero_scale.BlendedBoundsForBox(box, zero_scale, min_progress,
+ max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF().ToString(), bounds.ToString());
+}
+
+TEST(TransformOperationTest, BlendedBoundsForRotationTrivial) {
+ TransformOperations operations_from;
+ operations_from.AppendRotate(0.f, 0.f, 1.f, 0.f);
+ TransformOperations operations_to;
+ operations_to.AppendRotate(0.f, 0.f, 1.f, 360.f);
+
+ float sqrt_2 = sqrt(2.f);
+ gfx::BoxF box(-sqrt_2, -sqrt_2, 0.f, sqrt_2, sqrt_2, 0.f);
+ gfx::BoxF bounds;
+
+ // Since we're rotating 360 degrees, any box with dimensions between 0 and
+ // 2 * sqrt(2) should give the same result.
+ float sizes[] = {0.f, 0.1f, sqrt_2, 2.f * sqrt_2};
+ for (size_t i = 0; i < base::size(sizes); ++i) {
+ box.set_size(sizes[i], sizes[i], 0.f);
+ SkScalar min_progress = 0.f;
+ SkScalar max_progress = 1.f;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+ box, operations_from, min_progress, max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(-2.f, -2.f, 0.f, 4.f, 4.f, 0.f).ToString(),
+ bounds.ToString());
+ }
+}
+
+TEST(TransformOperationTest, BlendedBoundsForRotationAllExtrema) {
+ // If the normal is out of the plane, we can have up to 6 extrema (a min/max
+ // in each dimension) between the endpoints of the arc. This test ensures that
+ // we consider all 6.
+ TransformOperations operations_from;
+ operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f);
+ TransformOperations operations_to;
+ operations_to.AppendRotate(1.f, 1.f, 1.f, 390.f);
+
+ gfx::BoxF box(1.f, 0.f, 0.f, 0.f, 0.f, 0.f);
+ gfx::BoxF bounds;
+
+ float min = -1.f / 3.f;
+ float max = 1.f;
+ float size = max - min;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, operations_from, 0.f, 1.f,
+ &bounds));
+ EXPECT_EQ(gfx::BoxF(min, min, min, size, size, size).ToString(),
+ bounds.ToString());
+}
+
+TEST(TransformOperationTest, BlendedBoundsForRotationDifferentAxes) {
+ // We can handle rotations about a single axis. If the axes are different,
+ // we revert to matrix interpolation for which inflated bounds cannot be
+ // computed.
+ TransformOperations operations_from;
+ operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f);
+ TransformOperations operations_to_same;
+ operations_to_same.AppendRotate(1.f, 1.f, 1.f, 390.f);
+ TransformOperations operations_to_opposite;
+ operations_to_opposite.AppendRotate(-1.f, -1.f, -1.f, 390.f);
+ TransformOperations operations_to_different;
+ operations_to_different.AppendRotate(1.f, 3.f, 1.f, 390.f);
+
+ gfx::BoxF box(1.f, 0.f, 0.f, 0.f, 0.f, 0.f);
+ gfx::BoxF bounds;
+
+ EXPECT_TRUE(operations_to_same.BlendedBoundsForBox(box, operations_from, 0.f,
+ 1.f, &bounds));
+ EXPECT_TRUE(operations_to_opposite.BlendedBoundsForBox(box, operations_from,
+ 0.f, 1.f, &bounds));
+ EXPECT_FALSE(operations_to_different.BlendedBoundsForBox(box, operations_from,
+ 0.f, 1.f, &bounds));
+}
+
+TEST(TransformOperationTest, BlendedBoundsForRotationPointOnAxis) {
+ // Checks that if the point to rotate is sitting on the axis of rotation, that
+ // it does not get affected.
+ TransformOperations operations_from;
+ operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f);
+ TransformOperations operations_to;
+ operations_to.AppendRotate(1.f, 1.f, 1.f, 390.f);
+
+ gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f);
+ gfx::BoxF bounds;
+
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, operations_from, 0.f, 1.f,
+ &bounds));
+ EXPECT_EQ(box.ToString(), bounds.ToString());
+}
+
+TEST(TransformOperationTest, BlendedBoundsForRotationProblematicAxes) {
+ // Zeros in the components of the axis of rotation turned out to be tricky to
+ // deal with in practice. This function tests some potentially problematic
+ // axes to ensure sane behavior.
+
+ // Some common values used in the expected boxes.
+ float dim1 = 0.292893f;
+ float dim2 = sqrt(2.f);
+ float dim3 = 2.f * dim2;
+
+ struct {
+ float x;
+ float y;
+ float z;
+ gfx::BoxF expected;
+ } tests[] = {{0.f, 0.f, 0.f, gfx::BoxF(1.f, 1.f, 1.f, 0.f, 0.f, 0.f)},
+ {1.f, 0.f, 0.f, gfx::BoxF(1.f, -dim2, -dim2, 0.f, dim3, dim3)},
+ {0.f, 1.f, 0.f, gfx::BoxF(-dim2, 1.f, -dim2, dim3, 0.f, dim3)},
+ {0.f, 0.f, 1.f, gfx::BoxF(-dim2, -dim2, 1.f, dim3, dim3, 0.f)},
+ {1.f, 1.f, 0.f, gfx::BoxF(dim1, dim1, -1.f, dim2, dim2, 2.f)},
+ {0.f, 1.f, 1.f, gfx::BoxF(-1.f, dim1, dim1, 2.f, dim2, dim2)},
+ {1.f, 0.f, 1.f, gfx::BoxF(dim1, -1.f, dim1, dim2, 2.f, dim2)}};
+
+ for (size_t i = 0; i < base::size(tests); ++i) {
+ float x = tests[i].x;
+ float y = tests[i].y;
+ float z = tests[i].z;
+ TransformOperations operations_from;
+ operations_from.AppendRotate(x, y, z, 0.f);
+ TransformOperations operations_to;
+ operations_to.AppendRotate(x, y, z, 360.f);
+ gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f);
+ gfx::BoxF bounds;
+
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, operations_from, 0.f,
+ 1.f, &bounds));
+ EXPECT_EQ(tests[i].expected.ToString(), bounds.ToString());
+ }
+}
+
+static void ExpectBoxesApproximatelyEqual(const gfx::BoxF& lhs,
+ const gfx::BoxF& rhs,
+ float tolerance) {
+ EXPECT_NEAR(lhs.x(), rhs.x(), tolerance);
+ EXPECT_NEAR(lhs.y(), rhs.y(), tolerance);
+ EXPECT_NEAR(lhs.z(), rhs.z(), tolerance);
+ EXPECT_NEAR(lhs.width(), rhs.width(), tolerance);
+ EXPECT_NEAR(lhs.height(), rhs.height(), tolerance);
+ EXPECT_NEAR(lhs.depth(), rhs.depth(), tolerance);
+}
+
+static void EmpiricallyTestBounds(const TransformOperations& from,
+ const TransformOperations& to,
+ SkScalar min_progress,
+ SkScalar max_progress,
+ bool test_containment_only) {
+ gfx::BoxF box(200.f, 500.f, 100.f, 100.f, 300.f, 200.f);
+ gfx::BoxF bounds;
+ EXPECT_TRUE(
+ to.BlendedBoundsForBox(box, from, min_progress, max_progress, &bounds));
+
+ bool first_time = true;
+ gfx::BoxF empirical_bounds;
+ static const size_t kNumSteps = 10;
+ for (size_t step = 0; step < kNumSteps; ++step) {
+ float t = step / (kNumSteps - 1.f);
+ t = gfx::Tween::FloatValueBetween(t, min_progress, max_progress);
+ gfx::Transform partial_transform = to.Blend(from, t).Apply();
+ gfx::BoxF transformed = box;
+ partial_transform.TransformBox(&transformed);
+
+ if (first_time) {
+ empirical_bounds = transformed;
+ first_time = false;
+ } else {
+ empirical_bounds.Union(transformed);
+ }
+ }
+
+ if (test_containment_only) {
+ gfx::BoxF unified_bounds = bounds;
+ unified_bounds.Union(empirical_bounds);
+ // Convert to the screen space rects these boxes represent.
+ gfx::Rect bounds_rect = ToEnclosingRect(
+ gfx::RectF(bounds.x(), bounds.y(), bounds.width(), bounds.height()));
+ gfx::Rect unified_bounds_rect = ToEnclosingRect(
+ gfx::RectF(unified_bounds.x(), unified_bounds.y(),
+ unified_bounds.width(), unified_bounds.height()));
+ EXPECT_EQ(bounds_rect.ToString(), unified_bounds_rect.ToString());
+ } else {
+ // Our empirical estimate will be a little rough since we're only doing
+ // 100 samples.
+ static const float kTolerance = 1e-2f;
+ ExpectBoxesApproximatelyEqual(empirical_bounds, bounds, kTolerance);
+ }
+}
+
+static void EmpiricallyTestBoundsEquality(const TransformOperations& from,
+ const TransformOperations& to,
+ SkScalar min_progress,
+ SkScalar max_progress) {
+ EmpiricallyTestBounds(from, to, min_progress, max_progress, false);
+}
+
+static void EmpiricallyTestBoundsContainment(const TransformOperations& from,
+ const TransformOperations& to,
+ SkScalar min_progress,
+ SkScalar max_progress) {
+ EmpiricallyTestBounds(from, to, min_progress, max_progress, true);
+}
+
+TEST(TransformOperationTest, BlendedBoundsForRotationEmpiricalTests) {
+ // Sets up various axis angle combinations, computes the bounding box and
+ // empirically tests that the transformed bounds are indeed contained by the
+ // computed bounding box.
+
+ struct {
+ float x;
+ float y;
+ float z;
+ } axes[] = {{1.f, 1.f, 1.f}, {-1.f, -1.f, -1.f}, {-1.f, 2.f, 3.f},
+ {1.f, -2.f, 3.f}, {1.f, 2.f, -3.f}, {0.f, 0.f, 0.f},
+ {1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, 1.f},
+ {1.f, 1.f, 0.f}, {0.f, 1.f, 1.f}, {1.f, 0.f, 1.f},
+ {-1.f, 0.f, 0.f}, {0.f, -1.f, 0.f}, {0.f, 0.f, -1.f},
+ {-1.f, -1.f, 0.f}, {0.f, -1.f, -1.f}, {-1.f, 0.f, -1.f}};
+
+ struct {
+ float theta_from;
+ float theta_to;
+ } angles[] = {{5.f, 10.f}, {10.f, 5.f}, {0.f, 360.f}, {20.f, 180.f},
+ {-20.f, -180.f}, {180.f, -220.f}, {220.f, 320.f}};
+
+ // We can go beyond the range [0, 1] (the bezier might slide out of this range
+ // at either end), but since the first and last knots are at (0, 0) and (1, 1)
+ // we will never go within it, so these tests are sufficient.
+ struct {
+ float min_progress;
+ float max_progress;
+ } progress[] = {
+ {0.f, 1.f},
+ {-.25f, 1.25f},
+ };
+
+ for (size_t i = 0; i < base::size(axes); ++i) {
+ for (size_t j = 0; j < base::size(angles); ++j) {
+ for (size_t k = 0; k < base::size(progress); ++k) {
+ float x = axes[i].x;
+ float y = axes[i].y;
+ float z = axes[i].z;
+ TransformOperations operations_from;
+ operations_from.AppendRotate(x, y, z, angles[j].theta_from);
+ TransformOperations operations_to;
+ operations_to.AppendRotate(x, y, z, angles[j].theta_to);
+ EmpiricallyTestBoundsContainment(operations_from, operations_to,
+ progress[k].min_progress,
+ progress[k].max_progress);
+ }
+ }
+ }
+}
+
+TEST(TransformOperationTest, PerspectiveMatrixAndTransformBlendingEquivalency) {
+ TransformOperations from_operations;
+ from_operations.AppendPerspective(200);
+
+ TransformOperations to_operations;
+ to_operations.AppendPerspective(1000);
+
+ gfx::Transform from_transform;
+ from_transform.ApplyPerspectiveDepth(200);
+
+ gfx::Transform to_transform;
+ to_transform.ApplyPerspectiveDepth(1000);
+
+ static const int steps = 20;
+ for (int i = 0; i < steps; ++i) {
+ double progress = static_cast<double>(i) / (steps - 1);
+
+ gfx::Transform blended_matrix = to_transform;
+ EXPECT_TRUE(blended_matrix.Blend(from_transform, progress));
+
+ gfx::Transform blended_transform =
+ to_operations.Blend(from_operations, progress).Apply();
+
+ ExpectTransformationMatrixEq(blended_matrix, blended_transform);
+ }
+}
+
+TEST(TransformOperationTest, BlendedBoundsForPerspective) {
+ struct {
+ float from_depth;
+ float to_depth;
+ } perspective_depths[] = {
+ {600.f, 400.f},
+ {800.f, 1000.f},
+ {800.f, std::numeric_limits<float>::infinity()},
+ };
+
+ struct {
+ float min_progress;
+ float max_progress;
+ } progress[] = {
+ {0.f, 1.f},
+ {-0.1f, 1.1f},
+ };
+
+ for (size_t i = 0; i < base::size(perspective_depths); ++i) {
+ for (size_t j = 0; j < base::size(progress); ++j) {
+ TransformOperations operations_from;
+ operations_from.AppendPerspective(perspective_depths[i].from_depth);
+ TransformOperations operations_to;
+ operations_to.AppendPerspective(perspective_depths[i].to_depth);
+ EmpiricallyTestBoundsEquality(operations_from, operations_to,
+ progress[j].min_progress,
+ progress[j].max_progress);
+ }
+ }
+}
+
+TEST(TransformOperationTest, BlendedBoundsForSkew) {
+ struct {
+ float from_x;
+ float from_y;
+ float to_x;
+ float to_y;
+ } skews[] = {
+ {1.f, 0.5f, 0.5f, 1.f},
+ {2.f, 1.f, 0.5f, 0.5f},
+ };
+
+ struct {
+ float min_progress;
+ float max_progress;
+ } progress[] = {
+ {0.f, 1.f},
+ {-0.1f, 1.1f},
+ };
+
+ for (size_t i = 0; i < base::size(skews); ++i) {
+ for (size_t j = 0; j < base::size(progress); ++j) {
+ TransformOperations operations_from;
+ operations_from.AppendSkew(skews[i].from_x, skews[i].from_y);
+ TransformOperations operations_to;
+ operations_to.AppendSkew(skews[i].to_x, skews[i].to_y);
+ EmpiricallyTestBoundsEquality(operations_from, operations_to,
+ progress[j].min_progress,
+ progress[j].max_progress);
+ }
+ }
+}
+
+TEST(TransformOperationTest, NonCommutativeRotations) {
+ TransformOperations operations_from;
+ operations_from.AppendRotate(1.0, 0.0, 0.0, 0.0);
+ operations_from.AppendRotate(0.0, 1.0, 0.0, 0.0);
+ TransformOperations operations_to;
+ operations_to.AppendRotate(1.0, 0.0, 0.0, 45.0);
+ operations_to.AppendRotate(0.0, 1.0, 0.0, 135.0);
+
+ gfx::BoxF box(0, 0, 0, 1, 1, 1);
+ gfx::BoxF bounds;
+
+ SkScalar min_progress = 0.0f;
+ SkScalar max_progress = 1.0f;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+ box, operations_from, min_progress, max_progress, &bounds));
+ gfx::Transform blended_transform =
+ operations_to.Blend(operations_from, max_progress).Apply();
+ gfx::Point3F blended_point(0.9f, 0.9f, 0.0f);
+ blended_transform.TransformPoint(&blended_point);
+ gfx::BoxF expanded_bounds = bounds;
+ expanded_bounds.ExpandTo(blended_point);
+ EXPECT_EQ(bounds.ToString(), expanded_bounds.ToString());
+}
+
+TEST(TransformOperationTest, BlendedBoundsForSequence) {
+ TransformOperations operations_from;
+ operations_from.AppendTranslate(1.0, -5.0, 1.0);
+ operations_from.AppendScale(-1.0, 2.0, 3.0);
+ operations_from.AppendTranslate(2.0, 4.0, -1.0);
+ TransformOperations operations_to;
+ operations_to.AppendTranslate(13.0, -1.0, 5.0);
+ operations_to.AppendScale(-3.0, -2.0, 5.0);
+ operations_to.AppendTranslate(6.0, -2.0, 3.0);
+
+ gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
+ gfx::BoxF bounds;
+
+ SkScalar min_progress = -0.5f;
+ SkScalar max_progress = 1.5f;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+ box, operations_from, min_progress, max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(-57.f, -59.f, -1.f, 76.f, 112.f, 80.f).ToString(),
+ bounds.ToString());
+
+ min_progress = 0.f;
+ max_progress = 1.f;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+ box, operations_from, min_progress, max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(-32.f, -25.f, 7.f, 42.f, 44.f, 48.f).ToString(),
+ bounds.ToString());
+
+ TransformOperations identity;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(box, identity, min_progress,
+ max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(-33.f, -13.f, 3.f, 57.f, 19.f, 52.f).ToString(),
+ bounds.ToString());
+
+ EXPECT_TRUE(identity.BlendedBoundsForBox(box, operations_from, min_progress,
+ max_progress, &bounds));
+ EXPECT_EQ(gfx::BoxF(-7.f, -3.f, 2.f, 15.f, 23.f, 20.f).ToString(),
+ bounds.ToString());
+}
+
+TEST(TransformOperationTest, IsTranslationWithSingleOperation) {
+ TransformOperations empty_operations;
+ EXPECT_TRUE(empty_operations.IsTranslation());
+
+ TransformOperations identity;
+ identity.AppendIdentity();
+ EXPECT_TRUE(identity.IsTranslation());
+
+ TransformOperations translate;
+ translate.AppendTranslate(1.f, 2.f, 3.f);
+ EXPECT_TRUE(translate.IsTranslation());
+
+ TransformOperations rotate;
+ rotate.AppendRotate(1.f, 2.f, 3.f, 4.f);
+ EXPECT_FALSE(rotate.IsTranslation());
+
+ TransformOperations scale;
+ scale.AppendScale(1.f, 2.f, 3.f);
+ EXPECT_FALSE(scale.IsTranslation());
+
+ TransformOperations skew;
+ skew.AppendSkew(1.f, 2.f);
+ EXPECT_FALSE(skew.IsTranslation());
+
+ TransformOperations perspective;
+ perspective.AppendPerspective(1.f);
+ EXPECT_FALSE(perspective.IsTranslation());
+
+ TransformOperations identity_matrix;
+ identity_matrix.AppendMatrix(gfx::Transform());
+ EXPECT_TRUE(identity_matrix.IsTranslation());
+
+ TransformOperations translation_matrix;
+ gfx::Transform translation_transform;
+ translation_transform.Translate3d(1.f, 2.f, 3.f);
+ translation_matrix.AppendMatrix(translation_transform);
+ EXPECT_TRUE(translation_matrix.IsTranslation());
+
+ TransformOperations scaling_matrix;
+ gfx::Transform scaling_transform;
+ scaling_transform.Scale(2.f, 2.f);
+ scaling_matrix.AppendMatrix(scaling_transform);
+ EXPECT_FALSE(scaling_matrix.IsTranslation());
+}
+
+TEST(TransformOperationTest, IsTranslationWithMultipleOperations) {
+ TransformOperations operations1;
+ operations1.AppendSkew(1.f, 2.f);
+ operations1.AppendTranslate(1.f, 2.f, 3.f);
+ operations1.AppendIdentity();
+ EXPECT_FALSE(operations1.IsTranslation());
+
+ TransformOperations operations2;
+ operations2.AppendIdentity();
+ operations2.AppendTranslate(3.f, 2.f, 1.f);
+ gfx::Transform translation_transform;
+ translation_transform.Translate3d(1.f, 2.f, 3.f);
+ operations2.AppendMatrix(translation_transform);
+ EXPECT_TRUE(operations2.IsTranslation());
+}
+
+TEST(TransformOperationTest, ScaleComponent) {
+ SkScalar scale;
+
+ // Scale.
+ TransformOperations operations1;
+ operations1.AppendScale(-3.f, 2.f, 5.f);
+ EXPECT_TRUE(operations1.ScaleComponent(&scale));
+ EXPECT_EQ(5.f, scale);
+
+ // Translate.
+ TransformOperations operations2;
+ operations2.AppendTranslate(1.f, 2.f, 3.f);
+ EXPECT_TRUE(operations2.ScaleComponent(&scale));
+ EXPECT_EQ(1.f, scale);
+
+ // Rotate.
+ TransformOperations operations3;
+ operations3.AppendRotate(1.f, 2.f, 3.f, 4.f);
+ EXPECT_TRUE(operations3.ScaleComponent(&scale));
+ EXPECT_EQ(1.f, scale);
+
+ // Matrix that's only a translation.
+ TransformOperations operations4;
+ gfx::Transform translation_transform;
+ translation_transform.Translate3d(1.f, 2.f, 3.f);
+ operations4.AppendMatrix(translation_transform);
+ EXPECT_TRUE(operations4.ScaleComponent(&scale));
+ EXPECT_EQ(1.f, scale);
+
+ // Matrix that includes scale.
+ TransformOperations operations5;
+ gfx::Transform matrix;
+ matrix.RotateAboutZAxis(30.0);
+ matrix.Scale(-7.f, 6.f);
+ matrix.Translate3d(gfx::Vector3dF(3.f, 7.f, 1.f));
+ operations5.AppendMatrix(matrix);
+ EXPECT_TRUE(operations5.ScaleComponent(&scale));
+ EXPECT_EQ(7.f, scale);
+
+ // Matrix with perspective.
+ TransformOperations operations6;
+ matrix.ApplyPerspectiveDepth(2000.f);
+ operations6.AppendMatrix(matrix);
+ EXPECT_FALSE(operations6.ScaleComponent(&scale));
+
+ // Skew.
+ TransformOperations operations7;
+ operations7.AppendSkew(30.f, 60.f);
+ EXPECT_TRUE(operations7.ScaleComponent(&scale));
+ EXPECT_EQ(2.f, scale);
+
+ // Perspective.
+ TransformOperations operations8;
+ operations8.AppendPerspective(500.f);
+ EXPECT_FALSE(operations8.ScaleComponent(&scale));
+
+ // Translate + Scale.
+ TransformOperations operations9;
+ operations9.AppendTranslate(1.f, 2.f, 3.f);
+ operations9.AppendScale(2.f, 5.f, 4.f);
+ EXPECT_TRUE(operations9.ScaleComponent(&scale));
+ EXPECT_EQ(5.f, scale);
+
+ // Translate + Scale + Matrix with translate.
+ operations9.AppendMatrix(translation_transform);
+ EXPECT_TRUE(operations9.ScaleComponent(&scale));
+ EXPECT_EQ(5.f, scale);
+
+ // Scale + translate.
+ TransformOperations operations10;
+ operations10.AppendScale(2.f, 3.f, 2.f);
+ operations10.AppendTranslate(1.f, 2.f, 3.f);
+ EXPECT_TRUE(operations10.ScaleComponent(&scale));
+ EXPECT_EQ(3.f, scale);
+
+ // Two Scales.
+ TransformOperations operations11;
+ operations11.AppendScale(2.f, 3.f, 2.f);
+ operations11.AppendScale(-3.f, -2.f, -3.f);
+ EXPECT_TRUE(operations11.ScaleComponent(&scale));
+ EXPECT_EQ(9.f, scale);
+
+ // Scale + Matrix.
+ TransformOperations operations12;
+ operations12.AppendScale(2.f, 2.f, 2.f);
+ gfx::Transform scaling_transform;
+ scaling_transform.Scale(2.f, 2.f);
+ operations12.AppendMatrix(scaling_transform);
+ EXPECT_TRUE(operations12.ScaleComponent(&scale));
+ EXPECT_EQ(4.f, scale);
+
+ // Scale + Rotate.
+ TransformOperations operations13;
+ operations13.AppendScale(2.f, 2.f, 2.f);
+ operations13.AppendRotate(1.f, 2.f, 3.f, 4.f);
+ EXPECT_TRUE(operations13.ScaleComponent(&scale));
+ EXPECT_EQ(2.f, scale);
+
+ // Scale + Skew.
+ TransformOperations operations14;
+ operations14.AppendScale(2.f, 2.f, 2.f);
+ operations14.AppendSkew(60.f, 45.f);
+ EXPECT_TRUE(operations14.ScaleComponent(&scale));
+ EXPECT_EQ(4.f, scale);
+
+ // Scale + Perspective.
+ TransformOperations operations15;
+ operations15.AppendScale(2.f, 2.f, 2.f);
+ operations15.AppendPerspective(1.f);
+ EXPECT_FALSE(operations15.ScaleComponent(&scale));
+
+ // Matrix with skew.
+ TransformOperations operations16;
+ gfx::Transform skew_transform;
+ skew_transform.Skew(50.f, 60.f);
+ operations16.AppendMatrix(skew_transform);
+ EXPECT_TRUE(operations16.ScaleComponent(&scale));
+ EXPECT_EQ(2.f, scale);
+}
+
+TEST(TransformOperationsTest, ApproximateEquality) {
+ float noise = 1e-7f;
+ float tolerance = 1e-5f;
+ TransformOperations lhs;
+ TransformOperations rhs;
+
+ // Empty lists of operations are trivially equal.
+ EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
+
+ rhs.AppendIdentity();
+ rhs.AppendTranslate(0, 0, 0);
+ rhs.AppendRotate(1, 0, 0, 0);
+ rhs.AppendScale(1, 1, 1);
+ rhs.AppendSkew(0, 0);
+ rhs.AppendMatrix(gfx::Transform());
+
+ // Even though both lists operations are effectively the identity matrix, rhs
+ // has a different number of operations and is therefore different.
+ EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
+
+ rhs.AppendPerspective(800);
+
+ // Assignment should produce equal lists of operations.
+ lhs = rhs;
+ EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
+
+ // Cannot affect identity operations.
+ lhs.at(0).translate.x = 1;
+ EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
+
+ lhs.at(1).translate.x += noise;
+ EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
+ lhs.at(1).translate.x += 1;
+ EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
+
+ lhs = rhs;
+ lhs.at(2).rotate.angle += noise;
+ EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
+ lhs.at(2).rotate.angle = 1;
+ EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
+
+ lhs = rhs;
+ lhs.at(3).scale.x += noise;
+ EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
+ lhs.at(3).scale.x += 1;
+ EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
+
+ lhs = rhs;
+ lhs.at(4).skew.x += noise;
+ EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
+ lhs.at(4).skew.x = 2;
+ EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
+
+ lhs = rhs;
+ lhs.at(5).matrix.Translate3d(noise, 0, 0);
+ EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
+ lhs.at(5).matrix.Translate3d(1, 1, 1);
+ EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
+
+ lhs = rhs;
+ lhs.at(6).perspective_depth += noise;
+ EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
+ lhs.at(6).perspective_depth = 801;
+ EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
+}
+
+} // namespace
+
+// This test is intentionally outside the anonymous namespace for visibility as
+// it needs to be friend of TransformOperations.
+TEST(TransformOperationsTest, TestDecompositionCache) {
+ TransformOperations transforms;
+ EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
+ EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
+ EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
+
+ // Reset cache when appending a scale transform.
+ transforms.AppendScale(2.f, 2.f, 2.f);
+ EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
+ EXPECT_TRUE(transforms.ComputeDecomposedTransform(1));
+ EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
+ EXPECT_TRUE(transforms.ComputeDecomposedTransform(1));
+ EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
+ EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
+ EXPECT_EQ(2UL, transforms.decomposed_transforms_.size());
+
+ // Reset cache when appending a rotation transform.
+ transforms.AppendRotate(1, 0, 0, 45);
+ EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
+ EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
+ EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
+
+ // Reset cache when appending a translation transform.
+ transforms.AppendTranslate(1, 1, 1);
+ EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
+ EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
+ EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
+
+ // Reset cache when appending a skew transform.
+ transforms.AppendSkew(1, 0);
+ EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
+ EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
+ EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
+
+ // Reset cache when appending a perspective transform.
+ transforms.AppendPerspective(800);
+ EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
+ EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
+ EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
+
+ // Reset cache when appending a matrix transform.
+ transforms.AppendMatrix(gfx::Transform());
+ EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
+ EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
+ EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
+
+ // Reset cache when appending a generic transform operation.
+ transforms.Append(TransformOperation());
+ EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
+ EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
+ EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
+}
+
+TEST(TransformOperationTest, BlendSkewMismatch) {
+ TransformOperations from_ops, to_ops, expected_ops;
+ from_ops.AppendSkewX(0);
+ from_ops.AppendRotate(0, 0, 1, 0);
+ to_ops.AppendSkewY(0);
+ to_ops.AppendRotate(0, 0, 1, 360);
+
+ // Skew types do not match so use matrix interpolation
+ expected_ops.AppendMatrix(gfx::Transform());
+
+ TransformOperations blended_ops = to_ops.Blend(from_ops, 0.5);
+ ASSERT_EQ(blended_ops.size(), 1u);
+ ExpectTransformOperationEqual(blended_ops.at(0), expected_ops.at(0));
+}
+
+TEST(TransformOperationTest, BlendSkewMatch) {
+ TransformOperations from_ops, to_ops, expected_ops;
+ from_ops.AppendSkew(30, 0);
+ from_ops.AppendRotate(0, 0, 1, 0);
+ to_ops.AppendSkew(0, 30);
+ to_ops.AppendRotate(0, 0, 1, 360);
+
+ // Skew types match so interpolate as a function.
+ expected_ops.AppendSkew(15, 15);
+ expected_ops.AppendRotate(0, 0, 1, 180);
+
+ TransformOperations blended_ops = to_ops.Blend(from_ops, 0.5);
+ ASSERT_EQ(blended_ops.size(), 2u);
+ ExpectTransformOperationEqual(blended_ops.at(0), expected_ops.at(0));
+ ExpectTransformOperationEqual(blended_ops.at(1), expected_ops.at(1));
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/transform_util.cc b/chromium/ui/gfx/transform_util.cc
index 97ddcbf3213..77ffa108db0 100644
--- a/chromium/ui/gfx/transform_util.cc
+++ b/chromium/ui/gfx/transform_util.cc
@@ -633,4 +633,39 @@ Transform WindowMatrix(int x, int y, int width, int height) {
return canvas;
}
+static inline bool NearlyZero(double value) {
+ return std::abs(value) < std::numeric_limits<double>::epsilon();
+}
+
+static inline float ScaleOnAxis(double a, double b, double c) {
+ if (NearlyZero(b) && NearlyZero(c))
+ return std::abs(a);
+ if (NearlyZero(a) && NearlyZero(c))
+ return std::abs(b);
+ if (NearlyZero(a) && NearlyZero(b))
+ return std::abs(c);
+
+ // Do the sqrt as a double to not lose precision.
+ return static_cast<float>(std::sqrt(a * a + b * b + c * c));
+}
+
+Vector2dF ComputeTransform2dScaleComponents(const Transform& transform,
+ float fallback_value) {
+ if (transform.HasPerspective())
+ return Vector2dF(fallback_value, fallback_value);
+ float x_scale = ScaleOnAxis(transform.matrix().getDouble(0, 0),
+ transform.matrix().getDouble(1, 0),
+ transform.matrix().getDouble(2, 0));
+ float y_scale = ScaleOnAxis(transform.matrix().getDouble(0, 1),
+ transform.matrix().getDouble(1, 1),
+ transform.matrix().getDouble(2, 1));
+ return Vector2dF(x_scale, y_scale);
+}
+
+float ComputeApproximateMaxScale(const Transform& transform) {
+ RectF unit(0.f, 0.f, 1.f, 1.f);
+ transform.TransformRect(&unit);
+ return std::max(unit.width(), unit.height());
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/transform_util.h b/chromium/ui/gfx/transform_util.h
index 59d91b7398d..af409879ab3 100644
--- a/chromium/ui/gfx/transform_util.h
+++ b/chromium/ui/gfx/transform_util.h
@@ -84,6 +84,16 @@ GEOMETRY_SKIA_EXPORT Transform WindowMatrix(int x,
int width,
int height);
+GEOMETRY_SKIA_EXPORT Vector2dF
+ComputeTransform2dScaleComponents(const Transform& transform,
+ float fallback_value);
+
+// Returns an approximate max scale value of the transform even if it has
+// perspective. Prefer to use ComputeTransform2dScaleComponents if there is no
+// perspective, since it can produce more accurate results.
+GEOMETRY_SKIA_EXPORT
+float ComputeApproximateMaxScale(const Transform& transform);
+
} // namespace gfx
#endif // UI_GFX_TRANSFORM_UTIL_H_
diff --git a/chromium/ui/gfx/win/window_impl.cc b/chromium/ui/gfx/win/window_impl.cc
index 183e91a3520..a28dd7ea4b0 100644
--- a/chromium/ui/gfx/win/window_impl.cc
+++ b/chromium/ui/gfx/win/window_impl.cc
@@ -170,8 +170,6 @@ WindowImpl::WindowImpl(const std::string& debugging_id)
: debugging_id_(debugging_id), class_style_(CS_DBLCLKS) {}
WindowImpl::~WindowImpl() {
- if (destroyed_)
- *destroyed_ = true;
ClearUserData();
}
@@ -208,8 +206,7 @@ void WindowImpl::Init(HWND parent, const Rect& bounds) {
}
ATOM atom = GetWindowClassAtom();
- bool destroyed = false;
- destroyed_ = &destroyed;
+ auto weak_this = weak_factory_.GetWeakPtr();
HWND hwnd = CreateWindowEx(window_ex_style_,
reinterpret_cast<wchar_t*>(atom), NULL,
window_style_, x, y, width, height,
@@ -226,8 +223,10 @@ void WindowImpl::Init(HWND parent, const Rect& bounds) {
}
if (!hwnd_ && create_window_error == 0) {
- base::debug::Alias(&destroyed);
+ bool still_alive = !!weak_this;
+ base::debug::Alias(&still_alive);
base::debug::Alias(&hwnd);
+ base::debug::Alias(&atom);
bool got_create = got_create_;
base::debug::Alias(&got_create);
bool got_valid_hwnd = got_valid_hwnd_;
@@ -244,8 +243,6 @@ void WindowImpl::Init(HWND parent, const Rect& bounds) {
base::debug::Alias(&procs_match);
CHECK(false);
}
- if (!destroyed)
- destroyed_ = nullptr;
CheckWindowCreated(hwnd_, create_window_error);
diff --git a/chromium/ui/gfx/win/window_impl.h b/chromium/ui/gfx/win/window_impl.h
index d34c649708a..19ce4b139b9 100644
--- a/chromium/ui/gfx/win/window_impl.h
+++ b/chromium/ui/gfx/win/window_impl.h
@@ -9,6 +9,7 @@
#include "base/check_op.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/native_widget_types.h"
@@ -122,7 +123,8 @@ class GFX_EXPORT WindowImpl : public MessageMapInterface {
// TODO(sky): nuke this when get crash data.
bool got_create_ = false;
bool got_valid_hwnd_ = false;
- bool* destroyed_ = nullptr;
+ // For tracking whether this object has been destroyed. Must be last.
+ base::WeakPtrFactory<WindowImpl> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(WindowImpl);
};
diff --git a/chromium/ui/gfx/x/BUILD.gn b/chromium/ui/gfx/x/BUILD.gn
index 96f72a4369a..87ce467eda0 100644
--- a/chromium/ui/gfx/x/BUILD.gn
+++ b/chromium/ui/gfx/x/BUILD.gn
@@ -8,9 +8,16 @@ import("//tools/generate_library_loader/generate_library_loader.gni")
assert(use_x11 || ozone_platform_x11)
-xcbproto_path = "//third_party/xcbproto/src"
+declare_args() {
+ regenerate_x11_protos = false
+}
config("x11_private_config") {
+ visibility = [ ":*" ]
+ defines = [ "IS_X11_IMPL" ]
+}
+
+config("build_xprotos_config") {
cflags = [
# Generated proto files pull all fields from a struct into scope
# even if they aren't used. Rather than adding logic in the
@@ -18,7 +25,6 @@ config("x11_private_config") {
# those, simply ignore unused variable warnings.
"-Wno-unused-variable",
]
- defines = [ "IS_X11_IMPL" ]
}
generate_library_loader("xlib_loader") {
@@ -34,97 +40,151 @@ generate_library_loader("xlib_loader") {
"XFlush",
"XSynchronize",
"XSetErrorHandler",
+ "XFree",
+ "XPending",
]
}
-action("gen_xprotos") {
- visibility = [ ":xprotos" ]
- script = "gen_xproto.py"
- protos = [
- "bigreq",
- "composite",
- "damage",
- "dpms",
- "dri2",
- "dri3",
- "ge",
- "glx",
- "present",
- "randr",
- "record",
- "render",
- "res",
- "screensaver",
- "shape",
- "shm",
- "sync",
- "xc_misc",
- "xevie",
- "xf86dri",
- "xf86vidmode",
- "xfixes",
- "xinerama",
- "xinput",
- "xkb",
- "xprint",
- "xproto",
- "xselinux",
- "xtest",
- "xv",
- "xvmc",
- ]
- sources = []
- outputs = [
- "$target_gen_dir/read_event.cc",
- "$target_gen_dir/read_error.cc",
- "$target_gen_dir/extension_manager.h",
- "$target_gen_dir/extension_manager.cc",
+generate_library_loader("xlib_xcb_loader") {
+ name = "XlibXcbLoader"
+ output_h = "xlib_xcb_loader.h"
+ output_cc = "xlib_xcb_loader.cc"
+ header = "\"ui/gfx/x/xlib_xcb.h\""
+
+ functions = [ "XGetXCBConnection" ]
+}
+
+protos = [
+ "bigreq",
+ "composite",
+ "damage",
+ "dpms",
+ "dri2",
+ "dri3",
+ "ge",
+ "glx",
+ "present",
+ "randr",
+ "record",
+ "render",
+ "res",
+ "screensaver",
+ "shape",
+ "shm",
+ "sync",
+ "xc_misc",
+ "xevie",
+ "xf86dri",
+ "xf86vidmode",
+ "xfixes",
+ "xinerama",
+ "xinput",
+ "xkb",
+ "xprint",
+ "xproto",
+ "xselinux",
+ "xtest",
+ "xv",
+ "xvmc",
+]
+proto_generated_files = [
+ "read_event.cc",
+ "read_error.cc",
+ "extension_manager.h",
+ "extension_manager.cc",
+]
+foreach(proto, protos) {
+ proto_generated_files += [
+ "${proto}.h",
+ "${proto}.cc",
]
- foreach(proto, protos) {
- sources += [ "$xcbproto_path/src/${proto}.xml" ]
- outputs += [
- "$target_gen_dir/${proto}.h",
- "$target_gen_dir/${proto}.cc",
- ]
+}
+
+if (regenerate_x11_protos) {
+ xcbproto_path = "//third_party/xcbproto/src"
+
+ action("gen_xprotos") {
+ visibility = [ ":build_xprotos" ]
+ script = "gen_xproto.py"
+
+ sources = []
+ foreach(proto, protos) {
+ sources += [ "$xcbproto_path/src/${proto}.xml" ]
+ }
+
+ outputs = []
+ foreach(proto_generated_file, proto_generated_files) {
+ outputs += [ "$target_gen_dir/$proto_generated_file" ]
+ }
+
+ args = rebase_path([
+ xcbproto_path,
+ target_gen_dir,
+ ],
+ root_build_dir) + protos
}
+} else {
+ copy("gen_xprotos") {
+ sources = []
+ foreach(proto_generated_file, proto_generated_files) {
+ sources += [ "generated_protos/$proto_generated_file" ]
+ }
- args = rebase_path([
- xcbproto_path,
- target_gen_dir,
- ],
- root_build_dir) + protos
+ outputs = [ "$target_gen_dir/{{source_file_part}}" ]
+ }
}
-component("xprotos") {
+source_set("build_xprotos") {
+ visibility = [ ":xproto" ]
deps = [
":gen_xprotos",
+ "//base",
+ ]
+ sources = get_target_outputs(":gen_xprotos")
+ configs += [
+ ":build_xprotos_config",
+ ":x11_private_config",
+ ]
+}
+
+source_set("xproto") {
+ visibility = [ ":x" ]
+ sources = [
+ "connection.cc",
+ "connection.h",
+ "error.cc",
+ "error.h",
+ "event.cc",
+ "event.h",
+ "future.h",
+ "keyboard_state.cc",
+ "keyboard_state.h",
+ "ref_counted_fd.cc",
+ "ref_counted_fd.h",
+ "scoped_ignore_errors.cc",
+ "scoped_ignore_errors.h",
+ "x11_switches.cc",
+ "x11_switches.h",
+ "xlib_support.cc",
+ "xlib_support.h",
+ "xproto_internal.cc",
+ "xproto_internal.h",
+ "xproto_types.cc",
+ "xproto_types.h",
+ "xproto_util.cc",
+ "xproto_util.h",
+ ]
+ deps = [
":xlib_loader",
+ ":xlib_xcb_loader",
"//base",
"//base:i18n",
"//ui/events/platform",
]
- public_deps = [ "//ui/gfx/x/keysyms" ]
- sources = get_target_outputs(":gen_xprotos") + [
- "connection.h",
- "connection.cc",
- "event.h",
- "event.cc",
- "error.h",
- "error.cc",
- "keyboard_state.h",
- "keyboard_state.cc",
- "scoped_ignore_errors.h",
- "scoped_ignore_errors.cc",
- "x11_switches.cc",
- "x11_switches.h",
- "xlib_support.h",
- "xlib_support.cc",
- "xproto_internal.h",
- "xproto_internal.cc",
- "xproto_types.h",
- "xproto_types.cc",
- "xproto_util.h",
- ]
+ public_deps = [
+ ":build_xprotos",
+ "//ui/gfx/x/keysyms",
+ ]
configs += [ ":x11_private_config" ]
libs = [ "xcb" ]
}
@@ -133,25 +193,31 @@ component("x") {
output_name = "gfx_x11"
sources = [
- "../gfx_export.h",
+ "property_cache.cc",
+ "property_cache.h",
"x11_atom_cache.cc",
"x11_atom_cache.h",
"x11_path.cc",
"x11_path.h",
+ "x11_window_event_manager.cc",
+ "x11_window_event_manager.h",
]
- defines = [ "GFX_IMPLEMENTATION" ]
+ configs += [ ":x11_private_config" ]
deps = [
"//base",
"//skia",
]
- public_deps = [ ":xprotos" ]
+ public_deps = [ ":xproto" ]
}
source_set("unit_test") {
testonly = true
- sources = [ "connection_unittest.cc" ]
+ sources = [
+ "connection_unittest.cc",
+ "property_cache_unittest.cc",
+ ]
deps = [
"//base",
"//testing/gtest",
diff --git a/chromium/ui/gfx/x/connection.cc b/chromium/ui/gfx/x/connection.cc
index d6350747a89..3643dba8065 100644
--- a/chromium/ui/gfx/x/connection.cc
+++ b/chromium/ui/gfx/x/connection.cc
@@ -16,6 +16,7 @@
#include "base/no_destructor.h"
#include "base/strings/string16.h"
#include "base/threading/thread_local.h"
+#include "base/trace_event/trace_event.h"
#include "ui/gfx/x/bigreq.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/keyboard_state.h"
@@ -56,8 +57,8 @@ base::ThreadLocalOwnedPointer<Connection>& GetConnectionTLS() {
return *tls;
}
-void DefaultErrorHandler(const x11::Error* error, const char* request_name) {
- LOG(WARNING) << "X error received. Request: x11::" << request_name
+void DefaultErrorHandler(const Error* error, const char* request_name) {
+ LOG(WARNING) << "X error received. Request: " << request_name
<< "Request, Error: " << error->ToString();
}
@@ -67,14 +68,14 @@ void DefaultIOErrorHandler() {
class UnknownError : public Error {
public:
- explicit UnknownError(FutureBase::RawError error_bytes)
+ explicit UnknownError(Connection::RawError error_bytes)
: error_bytes_(error_bytes) {}
~UnknownError() override = default;
std::string ToString() const override {
std::stringstream ss;
- ss << "x11::UnknownError{";
+ ss << "UnknownError{";
// Errors are always a fixed 32 bytes.
for (size_t i = 0; i < 32; i++) {
char buf[3];
@@ -88,7 +89,7 @@ class UnknownError : public Error {
}
private:
- FutureBase::RawError error_bytes_;
+ Connection::RawError error_bytes_;
};
} // namespace
@@ -105,7 +106,7 @@ Connection* Connection::Get() {
}
// static
-void Connection::Set(std::unique_ptr<x11::Connection> connection) {
+void Connection::Set(std::unique_ptr<Connection> connection) {
DCHECK_CALLED_ON_VALID_SEQUENCE(connection->sequence_checker_);
auto& tls = GetConnectionTLS();
DCHECK(!tls.Get());
@@ -142,12 +143,12 @@ Connection::Connection(const std::string& address)
}
ExtensionManager::Init(this);
- auto enable_bigreq = bigreq().Enable({});
+ auto enable_bigreq = bigreq().Enable();
// Xlib enables XKB on display creation, so we do that here to maintain
// compatibility.
xkb()
- .UseExtension({x11::Xkb::major_version, x11::Xkb::minor_version})
- .OnResponse(base::BindOnce([](x11::Xkb::UseExtensionResponse response) {
+ .UseExtension({Xkb::major_version, Xkb::minor_version})
+ .OnResponse(base::BindOnce([](Xkb::UseExtensionResponse response) {
if (!response || !response->supported)
DVLOG(1) << "Xkb extension not available.";
}));
@@ -160,11 +161,16 @@ Connection::Connection(const std::string& address)
for (const auto& format : setup_.pixmap_formats)
formats[format.depth] = &format;
+ std::vector<std::pair<VisualId, VisualInfo>> default_screen_visuals;
for (const auto& depth : default_screen().allowed_depths) {
const Format* format = formats[depth.depth];
- for (const auto& visual : depth.visuals)
- default_screen_visuals_[visual.visual_id] = VisualInfo{format, &visual};
+ for (const auto& visual : depth.visuals) {
+ default_screen_visuals.emplace_back(visual.visual_id,
+ VisualInfo{format, &visual});
+ }
}
+ default_screen_visuals_ =
+ base::flat_map<VisualId, VisualInfo>(std::move(default_screen_visuals));
keyboard_state_ = CreateKeyboardState(this);
@@ -178,11 +184,9 @@ Connection::~Connection() {
xcb_disconnect(connection_);
}
-xcb_connection_t* Connection::XcbConnection() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (io_error_handler_ && xcb_connection_has_error(connection_))
- std::move(io_error_handler_).Run();
- return connection_;
+size_t Connection::MaxRequestSizeInBytes() const {
+ return 4 * std::max<size_t>(extended_max_request_length_,
+ setup_.maximum_request_length);
}
XlibDisplayWrapper Connection::GetXlibDisplay(XlibDisplayType type) {
@@ -192,19 +196,86 @@ XlibDisplayWrapper Connection::GetXlibDisplay(XlibDisplayType type) {
return XlibDisplayWrapper(xlib_display_->display_, type);
}
-Connection::Request::Request(unsigned int sequence,
- FutureBase::ResponseCallback callback)
- : sequence(sequence), callback(std::move(callback)) {}
+Connection::FutureImpl::FutureImpl(Connection* connection,
+ SequenceType sequence,
+ bool generates_reply,
+ const char* request_name_for_tracing)
+ : connection(connection),
+ sequence(sequence),
+ generates_reply(generates_reply),
+ request_name_for_tracing(request_name_for_tracing) {}
+
+void Connection::FutureImpl::Wait() {
+ connection->WaitForResponse(this);
+ ProcessResponse();
+}
+
+void Connection::FutureImpl::Sync(RawReply* raw_reply,
+ std::unique_ptr<Error>* error) {
+ connection->WaitForResponse(this);
+ TakeResponse(raw_reply, error);
+}
+
+void Connection::FutureImpl::OnResponse(ResponseCallback callback) {
+ UpdateRequestHandler(std::move(callback));
+}
+
+void Connection::FutureImpl::UpdateRequestHandler(ResponseCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(connection->sequence_checker_);
+ DCHECK(callback);
+
+ auto* request = connection->GetRequestForFuture(this);
+ // Make sure we haven't processed this request yet.
+ DCHECK(request->callback);
+
+ request->callback = std::move(callback);
+}
+
+void Connection::FutureImpl::ProcessResponse() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(connection->sequence_checker_);
+
+ auto* request = connection->GetRequestForFuture(this);
+ DCHECK(request->callback);
+ DCHECK(request->have_response);
+
+ std::move(request->callback)
+ .Run(std::move(request->reply), std::move(request->error));
+}
+
+void Connection::FutureImpl::TakeResponse(RawReply* raw_reply,
+ std::unique_ptr<Error>* error) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(connection->sequence_checker_);
+
+ auto* request = connection->GetRequestForFuture(this);
+ DCHECK(request->callback);
+ DCHECK(request->have_response);
-Connection::Request::Request(Request&& other)
- : sequence(other.sequence),
- callback(std::move(other.callback)),
- have_response(other.have_response),
- reply(std::move(other.reply)),
- error(std::move(other.error)) {}
+ *raw_reply = std::move(request->reply);
+ *error = std::move(request->error);
+ request->callback.Reset();
+}
+
+Connection::Request::Request(ResponseCallback callback)
+ : callback(std::move(callback)) {
+ DCHECK(this->callback);
+}
+
+Connection::Request::Request(Request&& other) = default;
Connection::Request::~Request() = default;
+void Connection::Request::SetResponse(Connection* connection,
+ void* raw_reply,
+ void* raw_error) {
+ have_response = true;
+ if (raw_reply)
+ reply = base::MakeRefCounted<MallocedRefCountedMemory>(raw_reply);
+ if (raw_error) {
+ error = connection->ParseError(
+ base::MakeRefCounted<MallocedRefCountedMemory>(raw_error));
+ }
+}
+
bool Connection::HasNextResponse() {
if (requests_.empty())
return false;
@@ -214,13 +285,11 @@ bool Connection::HasNextResponse() {
void* reply = nullptr;
xcb_generic_error_t* error = nullptr;
- request.have_response =
- xcb_poll_for_reply(XcbConnection(), request.sequence, &reply, &error);
- if (reply)
- request.reply = base::MakeRefCounted<MallocedRefCountedMemory>(reply);
- if (error)
- request.error = base::MakeRefCounted<MallocedRefCountedMemory>(error);
- return request.have_response;
+ if (!xcb_poll_for_reply(XcbConnection(), first_request_id_, &reply, &error))
+ return false;
+
+ request.SetResponse(this, reply, error);
+ return true;
}
bool Connection::HasNextEvent() {
@@ -279,7 +348,7 @@ void Connection::Sync() {
return;
{
base::AutoReset<bool> auto_reset(&syncing_, true);
- GetInputFocus({}).Sync();
+ GetInputFocus().Sync();
}
}
@@ -294,7 +363,7 @@ void Connection::ReadResponses() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
while (auto* event = xcb_poll_for_event(XcbConnection())) {
events_.emplace_back(base::MakeRefCounted<MallocedRefCountedMemory>(event),
- this, true);
+ this);
}
}
@@ -307,7 +376,7 @@ Event Connection::WaitForNextEvent() {
}
if (auto* xcb_event = xcb_wait_for_event(XcbConnection())) {
return Event(base::MakeRefCounted<MallocedRefCountedMemory>(xcb_event),
- this, true);
+ this);
}
return Event();
}
@@ -347,56 +416,48 @@ void Connection::DetachFromSequence() {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
-void Connection::Dispatch(Delegate* delegate) {
+bool Connection::Dispatch() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- auto process_next_response = [&] {
- DCHECK(!requests_.empty());
- DCHECK(requests_.front().have_response);
-
- Request request = std::move(requests_.front());
- requests_.pop();
- std::move(request.callback).Run(request.reply, request.error);
- };
-
- auto process_next_event = [&] {
- DCHECK(HasNextEvent());
-
- Event event = std::move(events_.front());
- events_.pop_front();
- PreDispatchEvent(event);
- delegate->DispatchXEvent(&event);
- };
+ if (HasNextResponse() && HasNextEvent()) {
+ auto next_response_sequence = first_request_id_;
+ auto next_event_sequence = events_.front().sequence();
+
+ // All events have the sequence number of the last processed request
+ // included in them. So if a reply and an event have the same sequence,
+ // the reply must have been received first.
+ if (CompareSequenceIds(next_event_sequence, next_response_sequence) <= 0)
+ ProcessNextResponse();
+ else
+ ProcessNextEvent();
+ } else if (HasNextResponse()) {
+ ProcessNextResponse();
+ } else if (HasNextEvent()) {
+ ProcessNextEvent();
+ } else {
+ return false;
+ }
+ return true;
+}
- // Handle all pending events.
- while (delegate->ShouldContinueStream()) {
+void Connection::DispatchAll() {
+ do {
Flush();
ReadResponses();
+ } while (Dispatch());
+}
- if (HasNextResponse() && HasNextEvent()) {
- if (!events_.front().sequence_valid()) {
- process_next_event();
- continue;
- }
+void Connection::DispatchEvent(const Event& event) {
+ PreDispatchEvent(event);
- auto next_response_sequence = requests_.front().sequence;
- auto next_event_sequence = events_.front().sequence();
-
- // All events have the sequence number of the last processed request
- // included in them. So if a reply and an event have the same sequence,
- // the reply must have been received first.
- if (CompareSequenceIds(next_event_sequence, next_response_sequence) <= 0)
- process_next_response();
- else
- process_next_event();
- } else if (HasNextResponse()) {
- process_next_response();
- } else if (HasNextEvent()) {
- process_next_event();
- } else {
- break;
- }
- }
+ // NB: The event should be reset to nullptr when this function
+ // returns, not to its initial value, otherwise nested message loops
+ // will incorrectly think that the current event being dispatched is
+ // an old event. This means base::AutoReset should not be used.
+ dispatching_event_ = &event;
+ for (auto& observer : event_observers_)
+ observer.OnEvent(event);
+ dispatching_event_ = nullptr;
}
Connection::ErrorHandler Connection::SetErrorHandler(ErrorHandler new_handler) {
@@ -411,6 +472,21 @@ void Connection::SetIOErrorHandler(IOErrorHandler new_handler) {
io_error_handler_ = std::move(new_handler);
}
+void Connection::AddEventObserver(EventObserver* observer) {
+ event_observers_.AddObserver(observer);
+}
+
+void Connection::RemoveEventObserver(EventObserver* observer) {
+ event_observers_.RemoveObserver(observer);
+}
+
+xcb_connection_t* Connection::XcbConnection() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (io_error_handler_ && xcb_connection_has_error(connection_))
+ std::move(io_error_handler_).Run();
+ return connection_;
+}
+
void Connection::InitRootDepthAndVisual() {
for (auto& depth : default_screen_->allowed_depths) {
for (auto& visual : depth.visuals) {
@@ -424,13 +500,195 @@ void Connection::InitRootDepthAndVisual() {
NOTREACHED();
}
-void Connection::AddRequest(unsigned int sequence,
- FutureBase::ResponseCallback callback) {
+void Connection::ProcessNextEvent() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(HasNextEvent());
+
+ Event event = std::move(events_.front());
+ events_.pop_front();
+
+ DispatchEvent(event);
+}
+
+void Connection::ProcessNextResponse() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(!requests_.empty());
+ DCHECK(requests_.front().have_response);
+
+ Request request = std::move(requests_.front());
+ requests_.pop_front();
+ if (last_non_void_request_id_.has_value() &&
+ last_non_void_request_id_.value() == first_request_id_) {
+ last_non_void_request_id_ = base::nullopt;
+ }
+ first_request_id_++;
+ if (request.callback) {
+ std::move(request.callback)
+ .Run(std::move(request.reply), std::move(request.error));
+ }
+}
+
+std::unique_ptr<Connection::FutureImpl> Connection::SendRequest(
+ WriteBuffer* buf,
+ const char* request_name_for_tracing,
+ bool generates_reply,
+ bool reply_has_fds) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ xcb_protocol_request_t xpr{
+ .ext = nullptr,
+ .isvoid = !generates_reply,
+ };
+
+ struct RequestHeader {
+ uint8_t major_opcode;
+ uint8_t minor_opcode;
+ uint16_t length;
+ };
+
+ struct ExtendedRequestHeader {
+ RequestHeader header;
+ uint32_t long_length;
+ };
+ static_assert(sizeof(ExtendedRequestHeader) == 8, "");
+
+ auto& first_buffer = buf->GetBuffers()[0];
+ DCHECK_GE(first_buffer->size(), sizeof(RequestHeader));
+ auto* old_header = reinterpret_cast<RequestHeader*>(
+ const_cast<uint8_t*>(first_buffer->data()));
+ ExtendedRequestHeader new_header{*old_header, 0};
+
+ // Requests are always a multiple of 4 bytes on the wire. Because of this,
+ // the length field represents the size in chunks of 4 bytes.
+ DCHECK_EQ(buf->offset() % 4, 0UL);
+ size_t size32 = buf->offset() / 4;
+
+ // XCB requires 2 iovecs for its own internal usage.
+ std::vector<struct iovec> io{{nullptr, 0}, {nullptr, 0}};
+ if (size32 < setup_.maximum_request_length) {
+ // Regular request
+ old_header->length = size32;
+ } else if (size32 < extended_max_request_length_) {
+ // BigRequests extension request
+ DCHECK_EQ(new_header.header.length, 0U);
+ new_header.long_length = size32 + 1;
+
+ io.push_back({&new_header, sizeof(ExtendedRequestHeader)});
+ first_buffer = base::MakeRefCounted<OffsetRefCountedMemory>(
+ first_buffer, sizeof(RequestHeader),
+ first_buffer->size() - sizeof(RequestHeader));
+ } else {
+ LOG(ERROR) << "Cannot send request of length " << buf->offset();
+ return nullptr;
+ }
+
+ for (auto& buffer : buf->GetBuffers())
+ io.push_back({const_cast<uint8_t*>(buffer->data()), buffer->size()});
+ xpr.count = io.size() - 2;
+
+ xcb_connection_t* conn = XcbConnection();
+ auto flags = XCB_REQUEST_CHECKED | XCB_REQUEST_RAW;
+ if (reply_has_fds)
+ flags |= XCB_REQUEST_REPLY_FDS;
+
+ for (int fd : buf->fds())
+ xcb_send_fd(conn, fd);
+ SequenceType sequence = xcb_send_request(conn, flags, &io[2], &xpr);
+
+ if (xcb_connection_has_error(conn))
+ return nullptr;
+
+ SequenceType next_request_id = first_request_id_ + requests_.size();
+ DCHECK_EQ(CompareSequenceIds(next_request_id, sequence), 0);
+
+ // If we ever reach 2^32 outstanding requests, then bail because sequence IDs
+ // would no longer be unique.
+ next_request_id++;
+ CHECK_NE(next_request_id, first_request_id_);
+
+ // Install a default response-handler that throws away the reply and prints
+ // the error if there is one. This handler may be overridden by clients.
+ auto callback = base::BindOnce(
+ [](const char* request_name, Connection::ErrorHandler error_handler,
+ RawReply raw_reply, std::unique_ptr<Error> error) {
+ if (error)
+ error_handler.Run(error.get(), request_name);
+ },
+ request_name_for_tracing, error_handler_);
+ requests_.emplace_back(std::move(callback));
+ if (generates_reply)
+ last_non_void_request_id_ = sequence;
+ if (synchronous_)
+ Sync();
+
+ return std::make_unique<FutureImpl>(this, sequence, generates_reply,
+ request_name_for_tracing);
+}
+
+void Connection::WaitForResponse(FutureImpl* future) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ auto* request = GetRequestForFuture(future);
+ DCHECK(request->callback);
+ if (request->have_response)
+ return;
+
+ xcb_generic_error_t* error = nullptr;
+ void* reply = nullptr;
+ if (future->generates_reply) {
+ if (!xcb_poll_for_reply(XcbConnection(), future->sequence, &reply,
+ &error)) {
+ TRACE_EVENT1("ui", "xcb_wait_for_reply", "request",
+ future->request_name_for_tracing);
+ reply = xcb_wait_for_reply(XcbConnection(), future->sequence, &error);
+ }
+ } else {
+ // There's a special case here. This request doesn't generate a reply, and
+ // may not generate an error, so the only way to know if it finished is to
+ // send another request that we know will generate a reply or error. Once
+ // the new request finishes, we know this request has finished, since the
+ // server is guaranteed to process requests in order. Normally, the
+ // xcb_request_check() below would do this for us automatically, but we need
+ // to keep track of the sequence count ourselves, so we explicitly make a
+ // GetInputFocus request if necessary (which is the request xcb would have
+ // made -- GetInputFocus is chosen since it has the minimum size request and
+ // reply, and can be made at any time).
+ bool needs_extra_request_for_check = false;
+ if (!last_non_void_request_id_.has_value()) {
+ needs_extra_request_for_check = true;
+ } else {
+ SequenceType last_non_void_offset =
+ last_non_void_request_id_.value() - first_request_id_;
+ SequenceType sequence_offset = future->sequence - first_request_id_;
+ needs_extra_request_for_check = sequence_offset > last_non_void_offset;
+ }
+ if (needs_extra_request_for_check) {
+ GetInputFocus().IgnoreError();
+ // The circular_deque may have swapped buffers, so we need to get a fresh
+ // pointer to the request.
+ request = GetRequestForFuture(future);
+ }
+
+ // libxcb has a bug where it doesn't flush in xcb_request_check() under some
+ // circumstances, leading to deadlock [1], so always perform a manual flush.
+ // [1] https://gitlab.freedesktop.org/xorg/lib/libxcb/-/issues/53
+ Flush();
+
+ {
+ TRACE_EVENT1("ui", "xcb_request_check", "request",
+ future->request_name_for_tracing);
+ error = xcb_request_check(XcbConnection(), {future->sequence});
+ }
+ }
+ request->SetResponse(this, reply, error);
+}
+
+Connection::Request* Connection::GetRequestForFuture(FutureImpl* future) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(requests_.empty() ||
- CompareSequenceIds(requests_.back().sequence, sequence) < 0);
- requests_.emplace(sequence, std::move(callback));
+ SequenceType offset = future->sequence - first_request_id_;
+ DCHECK_LT(offset, requests_.size());
+ return &requests_[offset];
}
void Connection::PreDispatchEvent(const Event& event) {
@@ -438,12 +696,12 @@ void Connection::PreDispatchEvent(const Event& event) {
if (mapping->request == Mapping::Modifier ||
mapping->request == Mapping::Keyboard) {
setup_.min_keycode = mapping->first_keycode;
- setup_.max_keycode = static_cast<x11::KeyCode>(
+ setup_.max_keycode = static_cast<KeyCode>(
static_cast<int>(mapping->first_keycode) + mapping->count - 1);
keyboard_state_->UpdateMapping();
}
}
- if (auto* notify = event.As<x11::Xkb::NewKeyboardNotifyEvent>()) {
+ if (auto* notify = event.As<Xkb::NewKeyboardNotifyEvent>()) {
setup_.min_keycode = notify->minKeyCode;
setup_.max_keycode = notify->maxKeyCode;
keyboard_state_->UpdateMapping();
@@ -484,8 +742,7 @@ int Connection::ScreenIndexFromRootWindow(Window root) const {
return -1;
}
-std::unique_ptr<Error> Connection::ParseError(
- FutureBase::RawError error_bytes) {
+std::unique_ptr<Error> Connection::ParseError(RawError error_bytes) {
if (!error_bytes)
return nullptr;
struct ErrorHeader {
diff --git a/chromium/ui/gfx/x/connection.h b/chromium/ui/gfx/x/connection.h
index 6b16ae22dc2..761a1ef5d5d 100644
--- a/chromium/ui/gfx/x/connection.h
+++ b/chromium/ui/gfx/x/connection.h
@@ -5,13 +5,13 @@
#ifndef UI_GFX_X_CONNECTION_H_
#define UI_GFX_X_CONNECTION_H_
-#include <queue>
-
+#include "base/callback.h"
#include "base/component_export.h"
#include "base/containers/circular_deque.h"
+#include "base/containers/flat_map.h"
+#include "base/optional.h"
#include "base/sequence_checker.h"
#include "ui/events/platform/platform_event_source.h"
-#include "ui/gfx/x/event.h"
#include "ui/gfx/x/extension_manager.h"
#include "ui/gfx/x/xlib_support.h"
#include "ui/gfx/x/xproto.h"
@@ -20,7 +20,20 @@ typedef struct xcb_connection_t xcb_connection_t;
namespace x11 {
+class Event;
class KeyboardState;
+class WriteBuffer;
+
+// This interface is used by classes wanting to receive
+// Events directly. For input events (mouse, keyboard, touch), a
+// PlatformEventObserver should be used instead.
+class EVENTS_EXPORT EventObserver {
+ public:
+ virtual void OnEvent(const Event& xevent) = 0;
+
+ protected:
+ virtual ~EventObserver() = default;
+};
// Represents a socket to the X11 server.
class COMPONENT_EXPORT(X11) Connection : public XProto,
@@ -28,15 +41,14 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
public:
using ErrorHandler = base::RepeatingCallback<void(const Error*, const char*)>;
using IOErrorHandler = base::OnceClosure;
+ using RawReply = scoped_refptr<base::RefCountedMemory>;
+ using RawError = scoped_refptr<base::RefCountedMemory>;
+ using ResponseCallback =
+ base::OnceCallback<void(RawReply reply, std::unique_ptr<Error> error)>;
- class Delegate {
- public:
- virtual bool ShouldContinueStream() const = 0;
- virtual void DispatchXEvent(x11::Event* event) = 0;
-
- protected:
- virtual ~Delegate() = default;
- };
+ // xcb returns unsigned int when making requests. This may be updated to
+ // uint16_t if/when we stop using xcb for socket IO.
+ using SequenceType = unsigned int;
struct VisualInfo {
const Format* format;
@@ -47,7 +59,22 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
static Connection* Get();
// Sets the thread local connection instance.
- static void Set(std::unique_ptr<x11::Connection> connection);
+ static void Set(std::unique_ptr<Connection> connection);
+
+ template <typename T>
+ T GenerateId() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return static_cast<T>(GenerateIdImpl());
+ }
+
+ template <typename Reply>
+ Future<Reply> SendRequest(WriteBuffer* buf,
+ const char* request_name,
+ bool reply_has_fds) {
+ bool generates_reply = !std::is_void<Reply>::value;
+ return Future<Reply>(
+ SendRequest(buf, request_name, generates_reply, reply_has_fds));
+ }
explicit Connection(const std::string& address = "");
~Connection();
@@ -55,8 +82,6 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
Connection(const Connection&) = delete;
Connection(Connection&&) = delete;
- xcb_connection_t* XcbConnection();
-
// Obtain an Xlib display that's connected to the same server as |this|. This
// is meant to be used only for compatibility with components like GLX,
// Vulkan, and VAAPI. The underlying socket is not shared, so synchronization
@@ -65,10 +90,7 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
XlibDisplayWrapper GetXlibDisplay(
XlibDisplayType type = XlibDisplayType::kNormal);
- uint32_t extended_max_request_length() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return extended_max_request_length_;
- }
+ size_t MaxRequestSizeInBytes() const;
const Setup& setup() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -78,7 +100,7 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return *default_screen_;
}
- x11::Window default_root() const {
+ Window default_root() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return default_screen().root;
}
@@ -91,6 +113,11 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
return *default_root_visual_;
}
+ const Event* dispatching_event() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return dispatching_event_;
+ }
+
// Returns the underlying socket's FD if the connection is valid, or -1
// otherwise.
int GetFd();
@@ -101,12 +128,6 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
int DefaultScreenId() const;
- template <typename T>
- T GenerateId() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return static_cast<T>(GenerateIdImpl());
- }
-
// Is the connection up and error-free?
bool Ready() const;
@@ -119,8 +140,6 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
// If |synchronous| is true, this makes all requests Sync().
void SynchronizeForTest(bool synchronous);
- bool synchronous() const { return synchronous_; }
-
// Read all responses from the socket without blocking.
void ReadResponses();
@@ -129,14 +148,27 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
// Are there any events, errors, or replies already buffered?
bool HasPendingResponses();
- // Dispatch any buffered events, errors, or replies.
- void Dispatch(Delegate* delegate);
+ // Dispatches one event, reply, or error from the server; or returns false
+ // if there's none available. This function doesn't read or write any data on
+ // the socket.
+ bool Dispatch();
+
+ // Dispatches all available events, replies, and errors. This function
+ // ensures the read and write buffers on the socket are empty upon returning.
+ void DispatchAll();
+
+ // Directly dispatch an event, bypassing the event queue.
+ void DispatchEvent(const Event& event);
// Returns the old error handler.
ErrorHandler SetErrorHandler(ErrorHandler new_handler);
void SetIOErrorHandler(IOErrorHandler new_handler);
+ void AddEventObserver(EventObserver* observer);
+
+ void RemoveEventObserver(EventObserver* observer);
+
// Returns the visual data for |id|, or nullptr if the visual with that ID
// doesn't exist or only exists on a non-default screen.
const VisualInfo* GetVisualInfoFromId(VisualId id) const;
@@ -165,36 +197,97 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
std::unique_ptr<ui::PlatformEventSource> platform_event_source;
private:
- friend class FutureBase;
+ template <typename Reply>
+ friend class Future;
+
+ class COMPONENT_EXPORT(X11) FutureImpl {
+ public:
+ FutureImpl(Connection* connection,
+ SequenceType sequence,
+ bool generates_reply,
+ const char* request_name_for_tracing);
+
+ void Wait();
+
+ void Sync(RawReply* raw_reply, std::unique_ptr<Error>* error);
+
+ void OnResponse(ResponseCallback callback);
+
+ // Update an existing Request with a new handler. |sequence| must
+ // correspond to a request in the queue that has not already been processed
+ // out-of-order.
+ void UpdateRequestHandler(ResponseCallback callback);
+
+ // Call the response handler for request |sequence| now (out-of-order). The
+ // response must already have been obtained from a call to
+ // WaitForResponse().
+ void ProcessResponse();
+
+ // Clear the response handler for request |sequence| and take the response.
+ // The response must already have been obtained using WaitForResponse().
+ void TakeResponse(RawReply* reply, std::unique_ptr<Error>* error);
+
+ Connection* connection = nullptr;
+ SequenceType sequence = 0;
+ bool generates_reply = false;
+ const char* request_name_for_tracing = nullptr;
+ };
struct Request {
- Request(unsigned int sequence, FutureBase::ResponseCallback callback);
+ explicit Request(ResponseCallback callback);
Request(Request&& other);
~Request();
- const unsigned int sequence;
- FutureBase::ResponseCallback callback;
+ // Takes ownership of |reply| and |error|.
+ void SetResponse(Connection* connection, void* raw_reply, void* raw_error);
+
+ // If |callback| is nullptr, then this request has already been processed
+ // out-of-order.
+ ResponseCallback callback;
+
+ // Indicates if |reply| and |error| are available. A separate
+ // |have_response| flag is necessary to distinguish the case where a request
+ // hasn't finished yet from the case where a request finished but didn't
+ // generate a reply or error.
bool have_response = false;
- FutureBase::RawReply reply;
- FutureBase::RawError error;
+ RawReply reply;
+ std::unique_ptr<Error> error;
};
+ xcb_connection_t* XcbConnection();
+
void InitRootDepthAndVisual();
- void AddRequest(unsigned int sequence, FutureBase::ResponseCallback callback);
+ void ProcessNextEvent();
+
+ void ProcessNextResponse();
bool HasNextResponse();
bool HasNextEvent();
+ // Creates a new Request and adds it to the end of the queue.
+ // |request_name_for_tracing| must be valid until the response is
+ // dispatched; currently the string values are only stored in .rodata, so
+ // this constraint is satisfied.
+ std::unique_ptr<FutureImpl> SendRequest(WriteBuffer* buf,
+ const char* request_name_for_tracing,
+ bool generates_reply,
+ bool reply_has_fds);
+
+ // Block until the reply or error for request |sequence| is received.
+ void WaitForResponse(FutureImpl* future);
+
+ Request* GetRequestForFuture(FutureImpl* future);
+
void PreDispatchEvent(const Event& event);
- int ScreenIndexFromRootWindow(x11::Window root) const;
+ int ScreenIndexFromRootWindow(Window root) const;
// This function is implemented in the generated read_error.cc.
void InitErrorParsers();
- std::unique_ptr<Error> ParseError(FutureBase::RawError error_bytes);
+ std::unique_ptr<Error> ParseError(RawError error_bytes);
uint32_t GenerateIdImpl();
@@ -213,16 +306,27 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
Depth* default_root_depth_ = nullptr;
VisualType* default_root_visual_ = nullptr;
- std::unordered_map<VisualId, VisualInfo> default_screen_visuals_;
+ base::flat_map<VisualId, VisualInfo> default_screen_visuals_;
std::unique_ptr<KeyboardState> keyboard_state_;
base::circular_deque<Event> events_;
- std::queue<Request> requests_;
+ base::ObserverList<EventObserver>::Unchecked event_observers_;
+
+ // The Event currently being dispatched, or nullptr if there is none.
+ const Event* dispatching_event_ = nullptr;
+
+ base::circular_deque<Request> requests_;
+ // The sequence ID of requests_.front(), or if |requests_| is empty, then the
+ // ID of the next request that will go in the queue. This starts at 1 because
+ // the 0'th request is handled internally by XCB when opening the connection.
+ SequenceType first_request_id_ = 1;
+ // If any request in |requests_| will generate a reply, this is the ID of the
+ // latest one, otherwise this is base::nullopt.
+ base::Optional<SequenceType> last_non_void_request_id_;
- using ErrorParser =
- std::unique_ptr<Error> (*)(FutureBase::RawError error_bytes);
+ using ErrorParser = std::unique_ptr<Error> (*)(RawError error_bytes);
std::array<ErrorParser, 256> error_parsers_{};
ErrorHandler error_handler_;
diff --git a/chromium/ui/gfx/x/connection_unittest.cc b/chromium/ui/gfx/x/connection_unittest.cc
index 4f140e05aea..46928a735b0 100644
--- a/chromium/ui/gfx/x/connection_unittest.cc
+++ b/chromium/ui/gfx/x/connection_unittest.cc
@@ -3,14 +3,12 @@
// found in the LICENSE file.
#include "ui/gfx/x/connection.h"
-#include "base/memory/ref_counted_memory.h"
-#include "ui/gfx/x/xproto.h"
-
-#undef Bool
-
-#include <xcb/xcb.h>
+#include "base/memory/ref_counted_memory.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/x/event.h"
+#include "ui/gfx/x/future.h"
+#include "ui/gfx/x/xproto.h"
namespace x11 {
@@ -36,14 +34,12 @@ Window CreateWindow(Connection* connection) {
// Connection setup and teardown.
TEST(X11ConnectionTest, Basic) {
Connection connection;
- ASSERT_TRUE(connection.XcbConnection());
- EXPECT_TRUE(connection.Ready());
+ ASSERT_TRUE(connection.Ready());
}
TEST(X11ConnectionTest, Request) {
Connection connection;
- ASSERT_TRUE(connection.XcbConnection());
- EXPECT_TRUE(connection.Ready());
+ ASSERT_TRUE(connection.Ready());
Window window = CreateWindow(&connection);
@@ -52,7 +48,7 @@ TEST(X11ConnectionTest, Request) {
EXPECT_EQ(attributes->map_state, MapState::Unmapped);
EXPECT_TRUE(attributes->override_redirect);
- auto geometry = connection.GetGeometry({window}).Sync();
+ auto geometry = connection.GetGeometry(window).Sync();
ASSERT_TRUE(geometry);
EXPECT_EQ(geometry->x, 0);
EXPECT_EQ(geometry->y, 0);
@@ -62,8 +58,7 @@ TEST(X11ConnectionTest, Request) {
TEST(X11ConnectionTest, Event) {
Connection connection;
- ASSERT_TRUE(connection.XcbConnection());
- EXPECT_TRUE(connection.Ready());
+ ASSERT_TRUE(connection.Ready());
Window window = CreateWindow(&connection);
@@ -75,9 +70,9 @@ TEST(X11ConnectionTest, Event) {
std::vector<uint8_t> data{0};
auto prop_future = connection.ChangeProperty({
- .window = static_cast<x11::Window>(window),
- .property = x11::Atom::WM_NAME,
- .type = x11::Atom::STRING,
+ .window = static_cast<Window>(window),
+ .property = Atom::WM_NAME,
+ .type = Atom::STRING,
.format = CHAR_BIT,
.data_len = 1,
.data = base::RefCountedBytes::TakeVector(&data),
@@ -86,25 +81,24 @@ TEST(X11ConnectionTest, Event) {
connection.ReadResponses();
ASSERT_EQ(connection.events().size(), 1u);
- auto* prop = connection.events().front().As<x11::PropertyNotifyEvent>();
+ auto* prop = connection.events().front().As<PropertyNotifyEvent>();
ASSERT_TRUE(prop);
- EXPECT_EQ(prop->atom, x11::Atom::WM_NAME);
+ EXPECT_EQ(prop->atom, Atom::WM_NAME);
EXPECT_EQ(prop->state, Property::NewValue);
}
TEST(X11ConnectionTest, Error) {
Connection connection;
- ASSERT_TRUE(connection.XcbConnection());
- EXPECT_TRUE(connection.Ready());
+ ASSERT_TRUE(connection.Ready());
Window invalid_window = connection.GenerateId<Window>();
- auto geometry = connection.GetGeometry({invalid_window}).Sync();
+ auto geometry = connection.GetGeometry(invalid_window).Sync();
ASSERT_FALSE(geometry);
auto* error = geometry.error.get();
ASSERT_TRUE(error);
// TODO(thomasanderson): Implement As<> for errors, similar to events.
- auto* drawable_error = reinterpret_cast<x11::DrawableError*>(error);
+ auto* drawable_error = reinterpret_cast<DrawableError*>(error);
EXPECT_EQ(drawable_error->bad_value, static_cast<uint32_t>(invalid_window));
}
diff --git a/chromium/ui/gfx/x/event.cc b/chromium/ui/gfx/x/event.cc
index 3d0637ca39b..68d6946df08 100644
--- a/chromium/ui/gfx/x/event.cc
+++ b/chromium/ui/gfx/x/event.cc
@@ -20,22 +20,20 @@ namespace x11 {
Event::Event() = default;
Event::Event(scoped_refptr<base::RefCountedMemory> event_bytes,
- x11::Connection* connection,
- bool sequence_valid) {
+ Connection* connection) {
auto* xcb_event = reinterpret_cast<xcb_generic_event_t*>(
const_cast<uint8_t*>(event_bytes->data()));
- sequence_valid_ = sequence_valid;
sequence_ = xcb_event->full_sequence;
// KeymapNotify events are the only events that don't have a sequence.
if ((xcb_event->response_type & ~kSendEventMask) !=
- x11::KeymapNotifyEvent::opcode) {
+ KeymapNotifyEvent::opcode) {
// On the wire, events are 32 bytes except for generic events which are
// trailed by additional data. XCB inserts an extended 4-byte sequence
// between the 32-byte event and the additional data, so we need to shift
// the additional data over by 4 bytes so the event is back in its wire
// format, which is what Xlib and XProto are expecting.
if ((xcb_event->response_type & ~kSendEventMask) ==
- x11::GeGenericEvent::opcode) {
+ GeGenericEvent::opcode) {
auto* ge = reinterpret_cast<xcb_ge_event_t*>(xcb_event);
constexpr size_t ge_length = sizeof(xcb_raw_generic_event_t);
constexpr size_t offset = sizeof(ge->full_sequence);
diff --git a/chromium/ui/gfx/x/event.h b/chromium/ui/gfx/x/event.h
index c13e94228b6..ed4f9b0c0fe 100644
--- a/chromium/ui/gfx/x/event.h
+++ b/chromium/ui/gfx/x/event.h
@@ -25,16 +25,14 @@ void ReadEvent(Event* event, Connection* connection, ReadBuffer* buffer);
class COMPONENT_EXPORT(X11) Event {
public:
template <typename T>
- explicit Event(T&& xproto_event, bool sequence_valid = true) {
+ explicit Event(T&& xproto_event) {
using DecayT = std::decay_t<T>;
- sequence_valid_ = true;
sequence_ = xproto_event.sequence;
type_id_ = DecayT::type_id;
deleter_ = [](void* event) { delete reinterpret_cast<DecayT*>(event); };
auto* event = new DecayT(std::forward<T>(xproto_event));
event_ = event;
window_ = event->GetWindow();
- sequence_valid_ = sequence_valid;
}
Event();
@@ -42,8 +40,7 @@ class COMPONENT_EXPORT(X11) Event {
// |event_bytes| is modified and will not be valid after this call.
// A copy is necessary if the original data is still needed.
Event(scoped_refptr<base::RefCountedMemory> event_bytes,
- Connection* connection,
- bool sequence_valid = true);
+ Connection* connection);
Event(const Event&) = delete;
Event& operator=(const Event&) = delete;
@@ -65,11 +62,10 @@ class COMPONENT_EXPORT(X11) Event {
return const_cast<Event*>(this)->As<T>();
}
- bool sequence_valid() const { return sequence_valid_; }
uint32_t sequence() const { return sequence_; }
- x11::Window window() const { return window_ ? *window_ : x11::Window::None; }
- void set_window(x11::Window window) {
+ Window window() const { return window_ ? *window_ : Window::None; }
+ void set_window(Window window) {
if (window_)
*window_ = window;
}
@@ -83,7 +79,6 @@ class COMPONENT_EXPORT(X11) Event {
void Dealloc();
- bool sequence_valid_ = false;
uint16_t sequence_ = 0;
// XProto event state.
@@ -93,7 +88,7 @@ class COMPONENT_EXPORT(X11) Event {
// This member points to a field in |event_|, or may be nullptr if there's no
// associated window for the event. It's owned by |event_|, not us.
- x11::Window* window_ = nullptr;
+ Window* window_ = nullptr;
};
} // namespace x11
diff --git a/chromium/ui/gfx/x/future.h b/chromium/ui/gfx/x/future.h
new file mode 100644
index 00000000000..fd2009357b6
--- /dev/null
+++ b/chromium/ui/gfx/x/future.h
@@ -0,0 +1,114 @@
+// Copyright 2020 The Chromium 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_X_FUTURE_H_
+#define UI_GFX_X_FUTURE_H_
+
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/xproto_types.h"
+
+namespace x11 {
+
+// An Future wraps an asynchronous response from the X11 server. The
+// response may be waited-for with Sync(), or asynchronously handled by
+// installing a response handler using OnResponse().
+template <typename Reply>
+class Future {
+ public:
+ using Callback = base::OnceCallback<void(Response<Reply> response)>;
+
+ Future() = default;
+
+ explicit Future(std::unique_ptr<Connection::FutureImpl> impl)
+ : impl_(std::move(impl)) {}
+
+ // Blocks until we receive the response from the server. Returns the response.
+ Response<Reply> Sync() {
+ if (!impl_)
+ return {nullptr, nullptr};
+
+ Connection::RawReply raw_reply;
+ std::unique_ptr<Error> error;
+ impl_->Sync(&raw_reply, &error);
+
+ std::unique_ptr<Reply> reply;
+ if (raw_reply) {
+ auto buf = ReadBuffer(raw_reply);
+ reply = detail::ReadReply<Reply>(&buf);
+ }
+
+ return {std::move(reply), std::move(error)};
+ }
+
+ // Block until this request is handled by the server. Unlike Sync(), this
+ // method doesn't return the response. Rather, it calls the response
+ // handler installed for this request out-of-order.
+ void Wait() {
+ if (impl_)
+ impl_->Wait();
+ }
+
+ // Installs |callback| to be run when the response is received.
+ void OnResponse(Callback callback) {
+ if (!impl_)
+ return;
+
+ // This intermediate callback handles the conversion from |raw_reply| to a
+ // real Reply object before feeding the result to |callback|. This means
+ // |callback| must be bound as the first argument of the intermediate
+ // function.
+ auto wrapper = [](Callback callback, Connection::RawReply raw_reply,
+ std::unique_ptr<Error> error) {
+ std::unique_ptr<Reply> reply;
+ if (raw_reply) {
+ ReadBuffer buf(raw_reply);
+ reply = detail::ReadReply<Reply>(&buf);
+ }
+ std::move(callback).Run({std::move(reply), std::move(error)});
+ };
+ impl_->OnResponse(base::BindOnce(wrapper, std::move(callback)));
+ }
+
+ void IgnoreError() {
+ OnResponse(base::BindOnce([](Response<Reply>) {}));
+ }
+
+ private:
+ std::unique_ptr<Connection::FutureImpl> impl_;
+};
+
+// Sync() specialization for requests that don't generate replies. The returned
+// response will only contain an error if there was one.
+template <>
+inline Response<void> Future<void>::Sync() {
+ if (!impl_)
+ return Response<void>{nullptr};
+
+ Connection::RawReply raw_reply;
+ std::unique_ptr<Error> error;
+ impl_->Sync(&raw_reply, &error);
+ DCHECK(!raw_reply);
+ return Response<void>(std::move(error));
+}
+
+// OnResponse() specialization for requests that don't generate replies. The
+// response argument to |callback| will only contain an error if there was one.
+template <>
+inline void Future<void>::OnResponse(Callback callback) {
+ if (!impl_)
+ return;
+
+ // See Future<Reply>::OnResponse() for an explanation of why
+ // this wrapper is necessary.
+ auto wrapper = [](Callback callback, Connection::RawReply reply,
+ std::unique_ptr<Error> error) {
+ DCHECK(!reply);
+ std::move(callback).Run(Response<void>{std::move(error)});
+ };
+ impl_->OnResponse(base::BindOnce(wrapper, std::move(callback)));
+}
+
+} // namespace x11
+
+#endif // UI_GFX_X_FUTURE_H_
diff --git a/chromium/ui/gfx/x/gen_xproto.py b/chromium/ui/gfx/x/gen_xproto.py
index 94df052aa4f..efb9aacbb19 100644
--- a/chromium/ui/gfx/x/gen_xproto.py
+++ b/chromium/ui/gfx/x/gen_xproto.py
@@ -8,168 +8,11 @@
# wire format. However, we don't parse the XML here; xcbproto ships
# with xcbgen, a python library that parses the files into python data
# structures for us.
-#
-# The generated header and source files will look like this:
-
-# #ifndef GEN_UI_GFX_X_XPROTO_H_
-# #define GEN_UI_GFX_X_XPROTO_H_
-#
-# #include <array>
-# #include <cstddef>
-# #include <cstdint>
-# #include <cstring>
-# #include <vector>
-#
-# #include "base/component_export.h"
-# #include "ui/gfx/x/xproto_types.h"
-#
-# namespace x11 {
-#
-# class Connection;
-#
-# class COMPONENT_EXPORT(X11) XProto {
-# public:
-# explicit XProto(Connection* connection);
-#
-# Connection* connection() const { return connection_; }
-#
-# struct RGB {
-# uint16_t red{};
-# uint16_t green{};
-# uint16_t blue{};
-# };
-#
-# struct QueryColorsRequest {
-# uint32_t cmap{};
-# std::vector<uint32_t> pixels{};
-# };
-#
-# struct QueryColorsReply {
-# uint16_t colors_len{};
-# std::vector<RGB> colors{};
-# };
-#
-# using QueryColorsResponse = Response<QueryColorsReply>;
-#
-# Future<QueryColorsReply> QueryColors(const QueryColorsRequest& request);
-#
-# private:
-# Connection* const connection_;
-# };
-#
-# } // namespace x11
-#
-# #endif // GEN_UI_GFX_X_XPROTO_H_
-
-# #include "xproto.h"
-#
-# #include <xcb/xcb.h>
-# #include <xcb/xcbext.h>
-#
-# #include "base/notreached.h"
-# #include "base/check_op.h"
-# #include "ui/gfx/x/xproto_internal.h"
-#
-# namespace x11 {
-#
-# XProto::XProto(Connection* connection) : connection_(connection) {}
-#
-# Future<XProto::QueryColorsReply>
-# XProto::QueryColors(
-# const XProto::QueryColorsRequest& request) {
-# WriteBuffer buf;
-#
-# auto& cmap = request.cmap;
-# auto& pixels = request.pixels;
-# size_t pixels_len = pixels.size();
-#
-# // major_opcode
-# uint8_t major_opcode = 91;
-# Write(&major_opcode, &buf);
-#
-# // pad0
-# Pad(&buf, 1);
-#
-# // length
-# // Caller fills in length for writes.
-# Pad(&buf, sizeof(uint16_t));
-#
-# // cmap
-# Write(&cmap, &buf);
-#
-# // pixels
-# DCHECK_EQ(static_cast<size_t>(pixels_len), pixels.size());
-# for (auto& pixels_elem : pixels) {
-# Write(&pixels_elem, &buf);
-# }
-#
-# return x11::SendRequest<XProto::QueryColorsReply>(connection_, &buf);
-# }
-#
-# template<> COMPONENT_EXPORT(X11)
-# std::unique_ptr<XProto::QueryColorsReply>
-# detail::ReadReply<XProto::QueryColorsReply>(const uint8_t* buffer) {
-# ReadBuffer buf{buffer, 0UL};
-# auto reply = std::make_unique<XProto::QueryColorsReply>();
-#
-# auto& colors_len = (*reply).colors_len;
-# auto& colors = (*reply).colors;
-#
-# // response_type
-# uint8_t response_type;
-# Read(&response_type, &buf);
-#
-# // pad0
-# Pad(&buf, 1);
-#
-# // sequence
-# uint16_t sequence;
-# Read(&sequence, &buf);
-#
-# // length
-# uint32_t length;
-# Read(&length, &buf);
-#
-# // colors_len
-# Read(&colors_len, &buf);
-#
-# // pad1
-# Pad(&buf, 22);
-#
-# // colors
-# colors.resize(colors_len);
-# for (auto& colors_elem : colors) {
-# auto& red = colors_elem.red;
-# auto& green = colors_elem.green;
-# auto& blue = colors_elem.blue;
-#
-# // red
-# Read(&red, &buf);
-#
-# // green
-# Read(&green, &buf);
-#
-# // blue
-# Read(&blue, &buf);
-#
-# // pad0
-# Pad(&buf, 2);
-#
-# }
-#
-# Align(&buf, 4);
-# DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
-#
-# return reply;
-# }
-#
-# } // namespace x11
from __future__ import print_function
import argparse
import collections
-import functools
import itertools
import os
import re
@@ -195,8 +38,6 @@ RENAME = {
'DIRECTFORMAT': 'DirectFormat',
'DOTCLOCK': 'DotClock',
'FBCONFIG': 'FbConfig',
- 'FLOAT32': 'float',
- 'FLOAT64': 'double',
'FONTPROP': 'FontProperty',
'GC': 'GraphicsContextAttribute',
'GCONTEXT': 'GraphicsContext',
@@ -242,6 +83,15 @@ WRITE_SPECIAL = set([
('xcb', 'PropertyNotify'),
])
+FILE_HEADER = \
+'''// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// %s
+''' % ' \\\n// '.join(sys.argv)
+
def adjust_type_name(name):
if name in RENAME:
@@ -359,6 +209,10 @@ class FileWriter:
indent = self.indent if line and not line.startswith('#') else 0
print((' ' * indent) + line, file=self.file)
+ def write_header(self):
+ for header_line in FILE_HEADER.split('\n'):
+ self.write(header_line)
+
class GenXproto(FileWriter):
def __init__(self, proto, proto_dir, gen_dir, xcbgen, all_types):
@@ -425,10 +279,6 @@ class GenXproto(FileWriter):
return ''
def rename_type(self, t, name):
- # Work around a bug in xcbgen: ('int') should have been ('int',)
- if name == 'int':
- name = ('int', )
-
name = list(name)
if name[0] == 'xcb':
@@ -464,7 +314,7 @@ class GenXproto(FileWriter):
def fieldtype(self, field):
if field.isfd:
- return 'base::ScopedFD'
+ return 'RefCountedFD'
return self.qualtype(field.type,
field.enum if field.enum else field.field_type)
@@ -577,11 +427,8 @@ class GenXproto(FileWriter):
self.write('%s value{};' % value_typename)
def declare_simple(self, item, name):
- # The underlying type of an enum must be integral, so avoid defining
- # FLOAT32 or FLOAT64. Usages are renamed to float and double instead.
renamed = tuple(self.rename_type(item, name))
- if (name[-1] in ('FLOAT32', 'FLOAT64')
- or renamed in self.replace_with_enum):
+ if renamed in self.replace_with_enum:
return
xidunion = self.get_xidunion_element(name)
@@ -600,7 +447,7 @@ class GenXproto(FileWriter):
def copy_fd(self, field, name):
if self.is_read:
- self.write('%s = base::ScopedFD(buf.TakeFd());' % name)
+ self.write('%s = RefCountedFD(buf.TakeFd());' % name)
else:
# We take the request struct as const&, so dup() the fd to preserve
# const-correctness because XCB close()s it after writing it.
@@ -758,11 +605,15 @@ class GenXproto(FileWriter):
safe_name(case_field.field_name),
'true' if case.type.is_bitcase else 'false', name))
+ def is_field_hidden_from_api(self, field):
+ return not field.visible or getattr(
+ field, 'for_list', False) or getattr(field, 'for_switch', False)
+
def declare_field(self, field):
t = field.type
name = safe_name(field.field_name)
- if not field.visible or field.for_list or field.for_switch:
+ if self.is_field_hidden_from_api(field):
return []
if t.is_switch:
@@ -864,7 +715,7 @@ class GenXproto(FileWriter):
self.write('%s %s{};' % field_type_name)
# This tries to match XEvent.xany.window, except the window will be
- # x11::Window::None for events that don't have a window, unlike the XEvent
+ # Window::None for events that don't have a window, unlike the XEvent
# union which will get whatever data happened to be at the offset of
# xany.window.
def get_window_field(self, event):
@@ -984,6 +835,29 @@ class GenXproto(FileWriter):
'static_assert(std::is_trivially_copyable<%s>::value, "");' % name)
self.write()
+ # Returns a list of strings suitable for use as a default-initializer for
+ # |field|. There may be 0 strings (if the field is hidden from the public
+ # API), 1 string (for normal cases), or many strings (for switch fields).
+ def get_initializer(self, field):
+ if self.is_field_hidden_from_api(field):
+ return []
+
+ if field.type.is_switch:
+ return ['base::nullopt'] * len(self.declare_switch(field))
+ if field.type.is_list or not field.type.is_container:
+ return ['{}']
+
+ # While using {} as an initializer for structs is fine when nested
+ # in other structs, it causes compiler errors when used as a default
+ # argument initializer, so explicitly initialize each field.
+ return [
+ '{%s}' % ', '.join([
+ init for subfield in field.type.fields
+ if not self.is_field_hidden_from_api(subfield)
+ for init in self.get_initializer(subfield)
+ ])
+ ]
+
def declare_request(self, request):
method_name = request.name[-1]
request_name = method_name + 'Request'
@@ -1001,10 +875,30 @@ class GenXproto(FileWriter):
self.write()
if in_class:
+ # Generate a request method that takes a Request object.
self.write('Future<%s> %s(' % (reply_name, method_name))
self.write(' const %s& request);' % request_name)
self.write()
+ # Generate a request method that takes fields as arguments and
+ # forwards them as a Request object to the above implementation.
+ field_type_names = [
+ field_type_name for field in request.fields
+ for field_type_name in self.declare_field(field)
+ ]
+ inits = [
+ init for field in request.fields
+ for init in self.get_initializer(field)
+ ]
+ assert len(field_type_names) == len(inits)
+ args = [
+ 'const %s& %s = %s' % (field_type_name + (init, ))
+ for (field_type_name, init) in zip(field_type_names, inits)
+ ]
+ self.write('Future<%s> %s(%s);' %
+ (reply_name, method_name, ', '.join(args)))
+ self.write()
+
def define_request(self, request):
method_name = '%s::%s' % (self.class_name, request.name[-1])
prefix = (method_name
@@ -1016,6 +910,7 @@ class GenXproto(FileWriter):
if not reply:
reply_name = 'void'
+ # Generate a request method that takes a Request object.
self.write('Future<%s>' % reply_name)
self.write('%s(' % method_name)
with Indent(self, ' const %s& request) {' % request_name, '}'):
@@ -1034,8 +929,24 @@ class GenXproto(FileWriter):
self.write()
reply_has_fds = reply and any(field.isfd for field in reply.fields)
self.write(
- 'return x11::SendRequest<%s>(connection_, &buf, %s, "%s");' %
- (reply_name, 'true' if reply_has_fds else 'false', prefix))
+ 'return connection_->SendRequest<%s>(&buf, "%s", %s);' %
+ (reply_name, prefix, 'true' if reply_has_fds else 'false'))
+ self.write()
+
+ # Generate a request method that takes fields as arguments and
+ # forwards them as a Request object to the above implementation.
+ self.write('Future<%s>' % reply_name)
+ self.write('%s(' % method_name)
+ args = [
+ 'const %s& %s' % field_type_name for field in request.fields
+ for field_type_name in self.declare_field(field)
+ ]
+ with Indent(self, '%s) {' % ', '.join(args), '}'):
+ self.write('return %s(%s{%s});' %
+ (method_name, request_name, ', '.join([
+ field_name for field in request.fields
+ for (_, field_name) in self.declare_field(field)
+ ])))
self.write()
if not reply:
@@ -1080,7 +991,7 @@ class GenXproto(FileWriter):
name = self.qualtype(error, name)
with Indent(self, 'std::string %s::ToString() const {' % name, '}'):
self.write('std::stringstream ss_;')
- self.write('ss_ << "x11::%s{";' % name)
+ self.write('ss_ << "%s{";' % name)
fields = [field for field in error.fields if field.visible]
for i, field in enumerate(fields):
terminator = '' if i == len(fields) - 1 else ' << ", "'
@@ -1208,35 +1119,6 @@ class GenXproto(FileWriter):
# all of these events under one structure with an additional opcode field
# to indicate the type of event.
def uniquify_events(self):
- # Manually merge some events in XInput. These groups of 8 events have
- # idential structure, and are merged as XIDeviceEvent in Xlib. To avoid
- # duplication, and to ease the transition from Xlib to XProto, we merge
- # the events here too.
- # TODO(thomasanderson): We should avoid adding workarounds for xcbproto.
- # Instead, the protocol files should be modified directly. However,
- # some of the changes we want to make change the API, so the changes
- # should be made in a fork in //third_party rather than upstreamed.
- MERGE = [
- ([
- 'KeyPress', 'KeyRelease', 'ButtonPress', 'ButtonRelease',
- 'Motion', 'TouchBegin', 'TouchUpdate', 'TouchEnd'
- ], []),
- ([
- 'RawKeyPress', 'RawKeyRelease', 'RawButtonPress',
- 'RawButtonRelease', 'RawMotion', 'RawTouchBegin',
- 'RawTouchUpdate', 'RawTouchEnd'
- ], []),
- ]
- for i, (name, t) in enumerate(self.module.all):
- if t.is_event and name[1] == 'Input':
- for names, event in MERGE:
- if name[-1] in names:
- if event:
- event[0].opcodes.update(t.opcodes)
- self.module.all[i] = name, event[0]
- else:
- event.append(t)
-
types = []
events = set()
for name, t in self.module.all:
@@ -1271,13 +1153,7 @@ class GenXproto(FileWriter):
self.uniquify_events()
- for i, (name, t) in enumerate(self.module.all):
- # Work around a name conflict: the type ScreenSaver has the same
- # name as the extension, so rename the type.
- if name == ('xcb', 'ScreenSaver'):
- name = ('xcb', 'ScreenSaverMode')
- t.name = name
- self.module.all[i] = (name, t)
+ for name, t in self.module.all:
self.resolve_type(t, name)
for enum, types in list(self.enum_types.items()):
@@ -1326,16 +1202,14 @@ class GenXproto(FileWriter):
return 4
return 3
- def cmp(type1, type2):
- return type_order_priority(type1) - type_order_priority(type2)
-
# sort() is guaranteed to be stable.
- self.module.all.sort(key=functools.cmp_to_key(cmp))
+ self.module.all.sort(key=type_order_priority)
def gen_header(self):
self.file = self.header_file
- include_guard = self.header_file.name.replace('/', '_').replace(
- '.', '_').upper() + '_'
+ self.write_header()
+ include_guard = 'UI_GFX_X_GENERATED_PROTOS_%s_' % (
+ self.header_file.name.split('/')[-1].upper().replace('.', '_'))
self.write('#ifndef ' + include_guard)
self.write('#define ' + include_guard)
self.write()
@@ -1350,8 +1224,8 @@ class GenXproto(FileWriter):
self.write('#include "base/memory/scoped_refptr.h"')
self.write('#include "base/optional.h"')
self.write('#include "base/files/scoped_file.h"')
+ self.write('#include "ui/gfx/x/ref_counted_fd.h"')
self.write('#include "ui/gfx/x/error.h"')
- self.write('#include "ui/gfx/x/xproto_types.h"')
imports = set(self.module.direct_imports)
if self.module.namespace.is_ext:
imports.add(('xproto', 'xproto'))
@@ -1362,6 +1236,12 @@ class GenXproto(FileWriter):
self.write()
self.write('class Connection;')
self.write()
+ self.write('template <typename Reply>')
+ self.write('struct Response;')
+ self.write()
+ self.write('template <typename Reply>')
+ self.write('class Future;')
+ self.write()
self.namespace = ['x11']
if not self.module.namespace.is_ext:
@@ -1401,7 +1281,7 @@ class GenXproto(FileWriter):
elif isinstance(item, self.xcbgen.xtypes.Request):
self.declare_request(item)
self.write('private:')
- self.write('x11::Connection* const connection_;')
+ self.write('Connection* const connection_;')
if self.module.namespace.is_ext:
self.write('x11::QueryExtensionReply info_{};')
@@ -1428,6 +1308,7 @@ class GenXproto(FileWriter):
def gen_source(self):
self.file = self.source_file
+ self.write_header()
self.write('#include "%s.h"' % self.module.namespace.header)
self.write()
self.write('#include <xcb/xcb.h>')
@@ -1441,7 +1322,7 @@ class GenXproto(FileWriter):
self.write()
ctor = '%s::%s' % (self.class_name, self.class_name)
if self.module.namespace.is_ext:
- self.write(ctor + '(x11::Connection* connection,')
+ self.write(ctor + '(Connection* connection,')
self.write(' const x11::QueryExtensionReply& info)')
self.write(' : connection_(connection), info_(info) {}')
else:
@@ -1475,8 +1356,9 @@ class GenExtensionManager(FileWriter):
def gen_header(self):
self.file = open(os.path.join(self.gen_dir, 'extension_manager.h'),
'w')
- self.write('#ifndef UI_GFX_X_EXTENSION_MANAGER_H_')
- self.write('#define UI_GFX_X_EXTENSION_MANAGER_H_')
+ self.write_header()
+ self.write('#ifndef UI_GFX_X_GENERATED_PROTOS_EXTENSION_MANAGER_H_')
+ self.write('#define UI_GFX_X_GENERATED_PROTOS_EXTENSION_MANAGER_H_')
self.write()
self.write('#include <memory>')
self.write()
@@ -1510,11 +1392,12 @@ class GenExtensionManager(FileWriter):
self.write()
self.write('} // namespace x11')
self.write()
- self.write('#endif // UI_GFX_X_EXTENSION_MANAGER_H_')
+ self.write('#endif // UI_GFX_X_GENERATED_PROTOS_EXTENSION_MANAGER_H_')
def gen_source(self):
self.file = open(os.path.join(self.gen_dir, 'extension_manager.cc'),
'w')
+ self.write_header()
self.write('#include "ui/gfx/x/extension_manager.h"')
self.write()
self.write('#include "ui/gfx/x/connection.h"')
@@ -1528,7 +1411,7 @@ class GenExtensionManager(FileWriter):
with Indent(self, init + '(Connection* conn) {', '}'):
for extension in self.extensions:
self.write(
- 'auto %s_future = conn->QueryExtension({"%s"});' %
+ 'auto %s_future = conn->QueryExtension("%s");' %
(extension.proto, extension.module.namespace.ext_xname))
# Flush so all requests are sent before waiting on any replies.
self.write('conn->Flush();')
@@ -1615,11 +1498,13 @@ class GenReadEvent(FileWriter):
def gen_source(self):
self.file = open(os.path.join(self.gen_dir, 'read_event.cc'), 'w')
+ self.write_header()
self.write('#include "ui/gfx/x/event.h"')
self.write()
self.write('#include <xcb/xcb.h>')
self.write()
self.write('#include "ui/gfx/x/connection.h"')
+ self.write('#include "ui/gfx/x/xproto_types.h"')
for genproto in self.genprotos:
self.write('#include "ui/gfx/x/%s.h"' % genproto.proto)
self.write()
@@ -1698,6 +1583,7 @@ class GenReadError(FileWriter):
def gen_source(self):
self.file = open(os.path.join(self.gen_dir, 'read_error.cc'), 'w')
+ self.write_header()
self.write('#include "ui/gfx/x/connection.h"')
self.write('#include "ui/gfx/x/error.h"')
self.write('#include "ui/gfx/x/xproto_internal.h"')
@@ -1710,7 +1596,7 @@ class GenReadError(FileWriter):
self.write('namespace {')
self.write()
self.write('template <typename T>')
- sig = 'std::unique_ptr<Error> MakeError(FutureBase::RawError error_)'
+ sig = 'std::unique_ptr<Error> MakeError(Connection::RawError error_)'
with Indent(self, '%s {' % sig, '}'):
self.write('ReadBuffer buf(error_);')
self.write('auto error = std::make_unique<T>();')
@@ -1748,7 +1634,7 @@ def main():
for genproto in genprotos:
genproto.resolve()
- # Give each event a unique type ID. This is used by x11::Event to
+ # Give each event a unique type ID. This is used by Event to
# implement downcasting for events.
type_id = 1
for proto in genprotos:
diff --git a/chromium/ui/gfx/x/generated_protos/README.txt b/chromium/ui/gfx/x/generated_protos/README.txt
new file mode 100644
index 00000000000..aea329bd416
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/README.txt
@@ -0,0 +1,10 @@
+The files in this directory are generated by gen_xproto.py. To regenerate these
+files, add "regenerate_x11_protos=true" to your gn args, then run the following
+(assuming your build directory is out/Release):
+
+$ rm -f ui/gfx/x/generated_protos/*.h
+$ rm -f ui/gfx/x/generated_protos/*.cc
+$ ninja -C out/Release ui/gfx/x:gen_xprotos
+$ cp out/Release/gen/ui/gfx/x/*.h ui/gfx/x/generated_protos/
+$ cp out/Release/gen/ui/gfx/x/*.cc ui/gfx/x/generated_protos/
+$ git cl format
diff --git a/chromium/ui/gfx/x/generated_protos/bigreq.cc b/chromium/ui/gfx/x/generated_protos/bigreq.cc
new file mode 100644
index 00000000000..8ad0c82247f
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/bigreq.cc
@@ -0,0 +1,118 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "bigreq.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+BigRequests::BigRequests(Connection* connection,
+ const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<BigRequests::EnableReply> BigRequests::Enable(
+ const BigRequests::EnableRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<BigRequests::EnableReply>(
+ &buf, "BigRequests::Enable", false);
+}
+
+Future<BigRequests::EnableReply> BigRequests::Enable() {
+ return BigRequests::Enable(BigRequests::EnableRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<BigRequests::EnableReply> detail::ReadReply<
+ BigRequests::EnableReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<BigRequests::EnableReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& maximum_request_length = (*reply).maximum_request_length;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // maximum_request_length
+ Read(&maximum_request_length, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/bigreq.h b/chromium/ui/gfx/x/generated_protos/bigreq.h
new file mode 100644
index 00000000000..4f32d9d68ff
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/bigreq.h
@@ -0,0 +1,103 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_BIGREQ_H_
+#define UI_GFX_X_GENERATED_PROTOS_BIGREQ_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) BigRequests {
+ public:
+ static constexpr unsigned major_version = 0;
+ static constexpr unsigned minor_version = 0;
+
+ BigRequests(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ struct EnableRequest {};
+
+ struct EnableReply {
+ uint16_t sequence{};
+ uint32_t maximum_request_length{};
+ };
+
+ using EnableResponse = Response<EnableReply>;
+
+ Future<EnableReply> Enable(const EnableRequest& request);
+
+ Future<EnableReply> Enable();
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_GENERATED_PROTOS_BIGREQ_H_
diff --git a/chromium/ui/gfx/x/generated_protos/composite.cc b/chromium/ui/gfx/x/generated_protos/composite.cc
new file mode 100644
index 00000000000..5fda7238462
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/composite.cc
@@ -0,0 +1,504 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "composite.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Composite::Composite(Connection* connection,
+ const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<Composite::QueryVersionReply> Composite::QueryVersion(
+ const Composite::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client_major_version = request.client_major_version;
+ auto& client_minor_version = request.client_minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client_major_version
+ buf.Write(&client_major_version);
+
+ // client_minor_version
+ buf.Write(&client_minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Composite::QueryVersionReply>(
+ &buf, "Composite::QueryVersion", false);
+}
+
+Future<Composite::QueryVersionReply> Composite::QueryVersion(
+ const uint32_t& client_major_version,
+ const uint32_t& client_minor_version) {
+ return Composite::QueryVersion(Composite::QueryVersionRequest{
+ client_major_version, client_minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Composite::QueryVersionReply> detail::ReadReply<
+ Composite::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Composite::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Composite::RedirectWindow(
+ const Composite::RedirectWindowRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& update = request.update;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // update
+ uint8_t tmp0;
+ tmp0 = static_cast<uint8_t>(update);
+ buf.Write(&tmp0);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Composite::RedirectWindow",
+ false);
+}
+
+Future<void> Composite::RedirectWindow(const Window& window,
+ const Redirect& update) {
+ return Composite::RedirectWindow(
+ Composite::RedirectWindowRequest{window, update});
+}
+
+Future<void> Composite::RedirectSubwindows(
+ const Composite::RedirectSubwindowsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& update = request.update;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // update
+ uint8_t tmp1;
+ tmp1 = static_cast<uint8_t>(update);
+ buf.Write(&tmp1);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Composite::RedirectSubwindows",
+ false);
+}
+
+Future<void> Composite::RedirectSubwindows(const Window& window,
+ const Redirect& update) {
+ return Composite::RedirectSubwindows(
+ Composite::RedirectSubwindowsRequest{window, update});
+}
+
+Future<void> Composite::UnredirectWindow(
+ const Composite::UnredirectWindowRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& update = request.update;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // update
+ uint8_t tmp2;
+ tmp2 = static_cast<uint8_t>(update);
+ buf.Write(&tmp2);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Composite::UnredirectWindow",
+ false);
+}
+
+Future<void> Composite::UnredirectWindow(const Window& window,
+ const Redirect& update) {
+ return Composite::UnredirectWindow(
+ Composite::UnredirectWindowRequest{window, update});
+}
+
+Future<void> Composite::UnredirectSubwindows(
+ const Composite::UnredirectSubwindowsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& update = request.update;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // update
+ uint8_t tmp3;
+ tmp3 = static_cast<uint8_t>(update);
+ buf.Write(&tmp3);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Composite::UnredirectSubwindows",
+ false);
+}
+
+Future<void> Composite::UnredirectSubwindows(const Window& window,
+ const Redirect& update) {
+ return Composite::UnredirectSubwindows(
+ Composite::UnredirectSubwindowsRequest{window, update});
+}
+
+Future<void> Composite::CreateRegionFromBorderClip(
+ const Composite::CreateRegionFromBorderClipRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& region = request.region;
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // region
+ buf.Write(&region);
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(
+ &buf, "Composite::CreateRegionFromBorderClip", false);
+}
+
+Future<void> Composite::CreateRegionFromBorderClip(const XFixes::Region& region,
+ const Window& window) {
+ return Composite::CreateRegionFromBorderClip(
+ Composite::CreateRegionFromBorderClipRequest{region, window});
+}
+
+Future<void> Composite::NameWindowPixmap(
+ const Composite::NameWindowPixmapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& pixmap = request.pixmap;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // pixmap
+ buf.Write(&pixmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Composite::NameWindowPixmap",
+ false);
+}
+
+Future<void> Composite::NameWindowPixmap(const Window& window,
+ const Pixmap& pixmap) {
+ return Composite::NameWindowPixmap(
+ Composite::NameWindowPixmapRequest{window, pixmap});
+}
+
+Future<Composite::GetOverlayWindowReply> Composite::GetOverlayWindow(
+ const Composite::GetOverlayWindowRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Composite::GetOverlayWindowReply>(
+ &buf, "Composite::GetOverlayWindow", false);
+}
+
+Future<Composite::GetOverlayWindowReply> Composite::GetOverlayWindow(
+ const Window& window) {
+ return Composite::GetOverlayWindow(
+ Composite::GetOverlayWindowRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Composite::GetOverlayWindowReply> detail::ReadReply<
+ Composite::GetOverlayWindowReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Composite::GetOverlayWindowReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& overlay_win = (*reply).overlay_win;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // overlay_win
+ Read(&overlay_win, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Composite::ReleaseOverlayWindow(
+ const Composite::ReleaseOverlayWindowRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Composite::ReleaseOverlayWindow",
+ false);
+}
+
+Future<void> Composite::ReleaseOverlayWindow(const Window& window) {
+ return Composite::ReleaseOverlayWindow(
+ Composite::ReleaseOverlayWindowRequest{window});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/composite.h b/chromium/ui/gfx/x/generated_protos/composite.h
new file mode 100644
index 00000000000..4b84691e768
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/composite.h
@@ -0,0 +1,230 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_COMPOSITE_H_
+#define UI_GFX_X_GENERATED_PROTOS_COMPOSITE_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xfixes.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Composite {
+ public:
+ static constexpr unsigned major_version = 0;
+ static constexpr unsigned minor_version = 4;
+
+ Composite(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Redirect : int {
+ Automatic = 0,
+ Manual = 1,
+ };
+
+ struct QueryVersionRequest {
+ uint32_t client_major_version{};
+ uint32_t client_minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(
+ const uint32_t& client_major_version = {},
+ const uint32_t& client_minor_version = {});
+
+ struct RedirectWindowRequest {
+ Window window{};
+ Redirect update{};
+ };
+
+ using RedirectWindowResponse = Response<void>;
+
+ Future<void> RedirectWindow(const RedirectWindowRequest& request);
+
+ Future<void> RedirectWindow(const Window& window = {},
+ const Redirect& update = {});
+
+ struct RedirectSubwindowsRequest {
+ Window window{};
+ Redirect update{};
+ };
+
+ using RedirectSubwindowsResponse = Response<void>;
+
+ Future<void> RedirectSubwindows(const RedirectSubwindowsRequest& request);
+
+ Future<void> RedirectSubwindows(const Window& window = {},
+ const Redirect& update = {});
+
+ struct UnredirectWindowRequest {
+ Window window{};
+ Redirect update{};
+ };
+
+ using UnredirectWindowResponse = Response<void>;
+
+ Future<void> UnredirectWindow(const UnredirectWindowRequest& request);
+
+ Future<void> UnredirectWindow(const Window& window = {},
+ const Redirect& update = {});
+
+ struct UnredirectSubwindowsRequest {
+ Window window{};
+ Redirect update{};
+ };
+
+ using UnredirectSubwindowsResponse = Response<void>;
+
+ Future<void> UnredirectSubwindows(const UnredirectSubwindowsRequest& request);
+
+ Future<void> UnredirectSubwindows(const Window& window = {},
+ const Redirect& update = {});
+
+ struct CreateRegionFromBorderClipRequest {
+ XFixes::Region region{};
+ Window window{};
+ };
+
+ using CreateRegionFromBorderClipResponse = Response<void>;
+
+ Future<void> CreateRegionFromBorderClip(
+ const CreateRegionFromBorderClipRequest& request);
+
+ Future<void> CreateRegionFromBorderClip(const XFixes::Region& region = {},
+ const Window& window = {});
+
+ struct NameWindowPixmapRequest {
+ Window window{};
+ Pixmap pixmap{};
+ };
+
+ using NameWindowPixmapResponse = Response<void>;
+
+ Future<void> NameWindowPixmap(const NameWindowPixmapRequest& request);
+
+ Future<void> NameWindowPixmap(const Window& window = {},
+ const Pixmap& pixmap = {});
+
+ struct GetOverlayWindowRequest {
+ Window window{};
+ };
+
+ struct GetOverlayWindowReply {
+ uint16_t sequence{};
+ Window overlay_win{};
+ };
+
+ using GetOverlayWindowResponse = Response<GetOverlayWindowReply>;
+
+ Future<GetOverlayWindowReply> GetOverlayWindow(
+ const GetOverlayWindowRequest& request);
+
+ Future<GetOverlayWindowReply> GetOverlayWindow(const Window& window = {});
+
+ struct ReleaseOverlayWindowRequest {
+ Window window{};
+ };
+
+ using ReleaseOverlayWindowResponse = Response<void>;
+
+ Future<void> ReleaseOverlayWindow(const ReleaseOverlayWindowRequest& request);
+
+ Future<void> ReleaseOverlayWindow(const Window& window = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Composite::Redirect operator|(
+ x11::Composite::Redirect l,
+ x11::Composite::Redirect r) {
+ using T = std::underlying_type_t<x11::Composite::Redirect>;
+ return static_cast<x11::Composite::Redirect>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Composite::Redirect operator&(
+ x11::Composite::Redirect l,
+ x11::Composite::Redirect r) {
+ using T = std::underlying_type_t<x11::Composite::Redirect>;
+ return static_cast<x11::Composite::Redirect>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_COMPOSITE_H_
diff --git a/chromium/ui/gfx/x/generated_protos/damage.cc b/chromium/ui/gfx/x/generated_protos/damage.cc
new file mode 100644
index 00000000000..bfd9c665ee7
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/damage.cc
@@ -0,0 +1,400 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "damage.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Damage::Damage(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+std::string Damage::BadDamageError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Damage::BadDamageError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Damage::BadDamageError>(Damage::BadDamageError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Damage::NotifyEvent>(Damage::NotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& level = (*event_).level;
+ auto& sequence = (*event_).sequence;
+ auto& drawable = (*event_).drawable;
+ auto& damage = (*event_).damage;
+ auto& timestamp = (*event_).timestamp;
+ auto& area = (*event_).area;
+ auto& geometry = (*event_).geometry;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // level
+ uint8_t tmp0;
+ Read(&tmp0, &buf);
+ level = static_cast<Damage::ReportLevel>(tmp0);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // drawable
+ Read(&drawable, &buf);
+
+ // damage
+ Read(&damage, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // area
+ {
+ auto& x = area.x;
+ auto& y = area.y;
+ auto& width = area.width;
+ auto& height = area.height;
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+ }
+
+ // geometry
+ {
+ auto& x = geometry.x;
+ auto& y = geometry.y;
+ auto& width = geometry.width;
+ auto& height = geometry.height;
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+ }
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+Future<Damage::QueryVersionReply> Damage::QueryVersion(
+ const Damage::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client_major_version = request.client_major_version;
+ auto& client_minor_version = request.client_minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client_major_version
+ buf.Write(&client_major_version);
+
+ // client_minor_version
+ buf.Write(&client_minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Damage::QueryVersionReply>(
+ &buf, "Damage::QueryVersion", false);
+}
+
+Future<Damage::QueryVersionReply> Damage::QueryVersion(
+ const uint32_t& client_major_version,
+ const uint32_t& client_minor_version) {
+ return Damage::QueryVersion(
+ Damage::QueryVersionRequest{client_major_version, client_minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Damage::QueryVersionReply> detail::ReadReply<
+ Damage::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Damage::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Damage::Create(const Damage::CreateRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& damage = request.damage;
+ auto& drawable = request.drawable;
+ auto& level = request.level;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // damage
+ buf.Write(&damage);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // level
+ uint8_t tmp1;
+ tmp1 = static_cast<uint8_t>(level);
+ buf.Write(&tmp1);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Damage::Create", false);
+}
+
+Future<void> Damage::Create(const DamageId& damage,
+ const Drawable& drawable,
+ const ReportLevel& level) {
+ return Damage::Create(Damage::CreateRequest{damage, drawable, level});
+}
+
+Future<void> Damage::Destroy(const Damage::DestroyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& damage = request.damage;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // damage
+ buf.Write(&damage);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Damage::Destroy", false);
+}
+
+Future<void> Damage::Destroy(const DamageId& damage) {
+ return Damage::Destroy(Damage::DestroyRequest{damage});
+}
+
+Future<void> Damage::Subtract(const Damage::SubtractRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& damage = request.damage;
+ auto& repair = request.repair;
+ auto& parts = request.parts;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // damage
+ buf.Write(&damage);
+
+ // repair
+ buf.Write(&repair);
+
+ // parts
+ buf.Write(&parts);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Damage::Subtract", false);
+}
+
+Future<void> Damage::Subtract(const DamageId& damage,
+ const XFixes::Region& repair,
+ const XFixes::Region& parts) {
+ return Damage::Subtract(Damage::SubtractRequest{damage, repair, parts});
+}
+
+Future<void> Damage::Add(const Damage::AddRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& region = request.region;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // region
+ buf.Write(&region);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Damage::Add", false);
+}
+
+Future<void> Damage::Add(const Drawable& drawable,
+ const XFixes::Region& region) {
+ return Damage::Add(Damage::AddRequest{drawable, region});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/damage.h b/chromium/ui/gfx/x/generated_protos/damage.h
new file mode 100644
index 00000000000..cb6cd3db0b0
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/damage.h
@@ -0,0 +1,208 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_DAMAGE_H_
+#define UI_GFX_X_GENERATED_PROTOS_DAMAGE_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xfixes.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Damage {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 1;
+
+ Damage(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class DamageId : uint32_t {};
+
+ enum class ReportLevel : int {
+ RawRectangles = 0,
+ DeltaRectangles = 1,
+ BoundingBox = 2,
+ NonEmpty = 3,
+ };
+
+ struct BadDamageError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct NotifyEvent {
+ static constexpr int type_id = 1;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ ReportLevel level{};
+ uint16_t sequence{};
+ Drawable drawable{};
+ DamageId damage{};
+ Time timestamp{};
+ Rectangle area{};
+ Rectangle geometry{};
+
+ x11::Window* GetWindow() {
+ return reinterpret_cast<x11::Window*>(&drawable);
+ }
+ };
+
+ struct QueryVersionRequest {
+ uint32_t client_major_version{};
+ uint32_t client_minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(
+ const uint32_t& client_major_version = {},
+ const uint32_t& client_minor_version = {});
+
+ struct CreateRequest {
+ DamageId damage{};
+ Drawable drawable{};
+ ReportLevel level{};
+ };
+
+ using CreateResponse = Response<void>;
+
+ Future<void> Create(const CreateRequest& request);
+
+ Future<void> Create(const DamageId& damage = {},
+ const Drawable& drawable = {},
+ const ReportLevel& level = {});
+
+ struct DestroyRequest {
+ DamageId damage{};
+ };
+
+ using DestroyResponse = Response<void>;
+
+ Future<void> Destroy(const DestroyRequest& request);
+
+ Future<void> Destroy(const DamageId& damage = {});
+
+ struct SubtractRequest {
+ DamageId damage{};
+ XFixes::Region repair{};
+ XFixes::Region parts{};
+ };
+
+ using SubtractResponse = Response<void>;
+
+ Future<void> Subtract(const SubtractRequest& request);
+
+ Future<void> Subtract(const DamageId& damage = {},
+ const XFixes::Region& repair = {},
+ const XFixes::Region& parts = {});
+
+ struct AddRequest {
+ Drawable drawable{};
+ XFixes::Region region{};
+ };
+
+ using AddResponse = Response<void>;
+
+ Future<void> Add(const AddRequest& request);
+
+ Future<void> Add(const Drawable& drawable = {},
+ const XFixes::Region& region = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Damage::ReportLevel operator|(
+ x11::Damage::ReportLevel l,
+ x11::Damage::ReportLevel r) {
+ using T = std::underlying_type_t<x11::Damage::ReportLevel>;
+ return static_cast<x11::Damage::ReportLevel>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Damage::ReportLevel operator&(
+ x11::Damage::ReportLevel l,
+ x11::Damage::ReportLevel r) {
+ using T = std::underlying_type_t<x11::Damage::ReportLevel>;
+ return static_cast<x11::Damage::ReportLevel>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_DAMAGE_H_
diff --git a/chromium/ui/gfx/x/generated_protos/dpms.cc b/chromium/ui/gfx/x/generated_protos/dpms.cc
new file mode 100644
index 00000000000..dd007a3fbec
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/dpms.cc
@@ -0,0 +1,470 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "dpms.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Dpms::Dpms(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<Dpms::GetVersionReply> Dpms::GetVersion(
+ const Dpms::GetVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client_major_version = request.client_major_version;
+ auto& client_minor_version = request.client_minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client_major_version
+ buf.Write(&client_major_version);
+
+ // client_minor_version
+ buf.Write(&client_minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dpms::GetVersionReply>(
+ &buf, "Dpms::GetVersion", false);
+}
+
+Future<Dpms::GetVersionReply> Dpms::GetVersion(
+ const uint16_t& client_major_version,
+ const uint16_t& client_minor_version) {
+ return Dpms::GetVersion(
+ Dpms::GetVersionRequest{client_major_version, client_minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dpms::GetVersionReply> detail::ReadReply<Dpms::GetVersionReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dpms::GetVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& server_major_version = (*reply).server_major_version;
+ auto& server_minor_version = (*reply).server_minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // server_major_version
+ Read(&server_major_version, &buf);
+
+ // server_minor_version
+ Read(&server_minor_version, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dpms::CapableReply> Dpms::Capable(const Dpms::CapableRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dpms::CapableReply>(&buf, "Dpms::Capable",
+ false);
+}
+
+Future<Dpms::CapableReply> Dpms::Capable() {
+ return Dpms::Capable(Dpms::CapableRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dpms::CapableReply> detail::ReadReply<Dpms::CapableReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dpms::CapableReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& capable = (*reply).capable;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // capable
+ Read(&capable, &buf);
+
+ // pad1
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dpms::GetTimeoutsReply> Dpms::GetTimeouts(
+ const Dpms::GetTimeoutsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dpms::GetTimeoutsReply>(
+ &buf, "Dpms::GetTimeouts", false);
+}
+
+Future<Dpms::GetTimeoutsReply> Dpms::GetTimeouts() {
+ return Dpms::GetTimeouts(Dpms::GetTimeoutsRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dpms::GetTimeoutsReply> detail::ReadReply<
+ Dpms::GetTimeoutsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dpms::GetTimeoutsReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& standby_timeout = (*reply).standby_timeout;
+ auto& suspend_timeout = (*reply).suspend_timeout;
+ auto& off_timeout = (*reply).off_timeout;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // standby_timeout
+ Read(&standby_timeout, &buf);
+
+ // suspend_timeout
+ Read(&suspend_timeout, &buf);
+
+ // off_timeout
+ Read(&off_timeout, &buf);
+
+ // pad1
+ Pad(&buf, 18);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Dpms::SetTimeouts(const Dpms::SetTimeoutsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& standby_timeout = request.standby_timeout;
+ auto& suspend_timeout = request.suspend_timeout;
+ auto& off_timeout = request.off_timeout;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // standby_timeout
+ buf.Write(&standby_timeout);
+
+ // suspend_timeout
+ buf.Write(&suspend_timeout);
+
+ // off_timeout
+ buf.Write(&off_timeout);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Dpms::SetTimeouts", false);
+}
+
+Future<void> Dpms::SetTimeouts(const uint16_t& standby_timeout,
+ const uint16_t& suspend_timeout,
+ const uint16_t& off_timeout) {
+ return Dpms::SetTimeouts(
+ Dpms::SetTimeoutsRequest{standby_timeout, suspend_timeout, off_timeout});
+}
+
+Future<void> Dpms::Enable(const Dpms::EnableRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Dpms::Enable", false);
+}
+
+Future<void> Dpms::Enable() {
+ return Dpms::Enable(Dpms::EnableRequest{});
+}
+
+Future<void> Dpms::Disable(const Dpms::DisableRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Dpms::Disable", false);
+}
+
+Future<void> Dpms::Disable() {
+ return Dpms::Disable(Dpms::DisableRequest{});
+}
+
+Future<void> Dpms::ForceLevel(const Dpms::ForceLevelRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& power_level = request.power_level;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // power_level
+ uint16_t tmp0;
+ tmp0 = static_cast<uint16_t>(power_level);
+ buf.Write(&tmp0);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Dpms::ForceLevel", false);
+}
+
+Future<void> Dpms::ForceLevel(const DPMSMode& power_level) {
+ return Dpms::ForceLevel(Dpms::ForceLevelRequest{power_level});
+}
+
+Future<Dpms::InfoReply> Dpms::Info(const Dpms::InfoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dpms::InfoReply>(&buf, "Dpms::Info", false);
+}
+
+Future<Dpms::InfoReply> Dpms::Info() {
+ return Dpms::Info(Dpms::InfoRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dpms::InfoReply> detail::ReadReply<Dpms::InfoReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dpms::InfoReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& power_level = (*reply).power_level;
+ auto& state = (*reply).state;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // power_level
+ uint16_t tmp1;
+ Read(&tmp1, &buf);
+ power_level = static_cast<Dpms::DPMSMode>(tmp1);
+
+ // state
+ Read(&state, &buf);
+
+ // pad1
+ Pad(&buf, 21);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/dpms.h b/chromium/ui/gfx/x/generated_protos/dpms.h
new file mode 100644
index 00000000000..59779ce56be
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/dpms.h
@@ -0,0 +1,211 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_DPMS_H_
+#define UI_GFX_X_GENERATED_PROTOS_DPMS_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Dpms {
+ public:
+ static constexpr unsigned major_version = 0;
+ static constexpr unsigned minor_version = 0;
+
+ Dpms(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class DPMSMode : int {
+ On = 0,
+ Standby = 1,
+ Suspend = 2,
+ Off = 3,
+ };
+
+ struct GetVersionRequest {
+ uint16_t client_major_version{};
+ uint16_t client_minor_version{};
+ };
+
+ struct GetVersionReply {
+ uint16_t sequence{};
+ uint16_t server_major_version{};
+ uint16_t server_minor_version{};
+ };
+
+ using GetVersionResponse = Response<GetVersionReply>;
+
+ Future<GetVersionReply> GetVersion(const GetVersionRequest& request);
+
+ Future<GetVersionReply> GetVersion(const uint16_t& client_major_version = {},
+ const uint16_t& client_minor_version = {});
+
+ struct CapableRequest {};
+
+ struct CapableReply {
+ uint16_t sequence{};
+ uint8_t capable{};
+ };
+
+ using CapableResponse = Response<CapableReply>;
+
+ Future<CapableReply> Capable(const CapableRequest& request);
+
+ Future<CapableReply> Capable();
+
+ struct GetTimeoutsRequest {};
+
+ struct GetTimeoutsReply {
+ uint16_t sequence{};
+ uint16_t standby_timeout{};
+ uint16_t suspend_timeout{};
+ uint16_t off_timeout{};
+ };
+
+ using GetTimeoutsResponse = Response<GetTimeoutsReply>;
+
+ Future<GetTimeoutsReply> GetTimeouts(const GetTimeoutsRequest& request);
+
+ Future<GetTimeoutsReply> GetTimeouts();
+
+ struct SetTimeoutsRequest {
+ uint16_t standby_timeout{};
+ uint16_t suspend_timeout{};
+ uint16_t off_timeout{};
+ };
+
+ using SetTimeoutsResponse = Response<void>;
+
+ Future<void> SetTimeouts(const SetTimeoutsRequest& request);
+
+ Future<void> SetTimeouts(const uint16_t& standby_timeout = {},
+ const uint16_t& suspend_timeout = {},
+ const uint16_t& off_timeout = {});
+
+ struct EnableRequest {};
+
+ using EnableResponse = Response<void>;
+
+ Future<void> Enable(const EnableRequest& request);
+
+ Future<void> Enable();
+
+ struct DisableRequest {};
+
+ using DisableResponse = Response<void>;
+
+ Future<void> Disable(const DisableRequest& request);
+
+ Future<void> Disable();
+
+ struct ForceLevelRequest {
+ DPMSMode power_level{};
+ };
+
+ using ForceLevelResponse = Response<void>;
+
+ Future<void> ForceLevel(const ForceLevelRequest& request);
+
+ Future<void> ForceLevel(const DPMSMode& power_level = {});
+
+ struct InfoRequest {};
+
+ struct InfoReply {
+ uint16_t sequence{};
+ DPMSMode power_level{};
+ uint8_t state{};
+ };
+
+ using InfoResponse = Response<InfoReply>;
+
+ Future<InfoReply> Info(const InfoRequest& request);
+
+ Future<InfoReply> Info();
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Dpms::DPMSMode operator|(x11::Dpms::DPMSMode l,
+ x11::Dpms::DPMSMode r) {
+ using T = std::underlying_type_t<x11::Dpms::DPMSMode>;
+ return static_cast<x11::Dpms::DPMSMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Dpms::DPMSMode operator&(x11::Dpms::DPMSMode l,
+ x11::Dpms::DPMSMode r) {
+ using T = std::underlying_type_t<x11::Dpms::DPMSMode>;
+ return static_cast<x11::Dpms::DPMSMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_DPMS_H_
diff --git a/chromium/ui/gfx/x/generated_protos/dri2.cc b/chromium/ui/gfx/x/generated_protos/dri2.cc
new file mode 100644
index 00000000000..0e5eca28f06
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/dri2.cc
@@ -0,0 +1,1316 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "dri2.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Dri2::Dri2(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Dri2::BufferSwapCompleteEvent>(
+ Dri2::BufferSwapCompleteEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event_type = (*event_).event_type;
+ auto& drawable = (*event_).drawable;
+ auto& ust_hi = (*event_).ust_hi;
+ auto& ust_lo = (*event_).ust_lo;
+ auto& msc_hi = (*event_).msc_hi;
+ auto& msc_lo = (*event_).msc_lo;
+ auto& sbc = (*event_).sbc;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // event_type
+ uint16_t tmp0;
+ Read(&tmp0, &buf);
+ event_type = static_cast<Dri2::EventType>(tmp0);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // drawable
+ Read(&drawable, &buf);
+
+ // ust_hi
+ Read(&ust_hi, &buf);
+
+ // ust_lo
+ Read(&ust_lo, &buf);
+
+ // msc_hi
+ Read(&msc_hi, &buf);
+
+ // msc_lo
+ Read(&msc_lo, &buf);
+
+ // sbc
+ Read(&sbc, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Dri2::InvalidateBuffersEvent>(
+ Dri2::InvalidateBuffersEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& drawable = (*event_).drawable;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // drawable
+ Read(&drawable, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+Future<Dri2::QueryVersionReply> Dri2::QueryVersion(
+ const Dri2::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major_version = request.major_version;
+ auto& minor_version = request.minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major_version
+ buf.Write(&major_version);
+
+ // minor_version
+ buf.Write(&minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri2::QueryVersionReply>(
+ &buf, "Dri2::QueryVersion", false);
+}
+
+Future<Dri2::QueryVersionReply> Dri2::QueryVersion(
+ const uint32_t& major_version,
+ const uint32_t& minor_version) {
+ return Dri2::QueryVersion(
+ Dri2::QueryVersionRequest{major_version, minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri2::QueryVersionReply> detail::ReadReply<
+ Dri2::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri2::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dri2::ConnectReply> Dri2::Connect(const Dri2::ConnectRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& driver_type = request.driver_type;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // driver_type
+ uint32_t tmp1;
+ tmp1 = static_cast<uint32_t>(driver_type);
+ buf.Write(&tmp1);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri2::ConnectReply>(&buf, "Dri2::Connect",
+ false);
+}
+
+Future<Dri2::ConnectReply> Dri2::Connect(const Window& window,
+ const DriverType& driver_type) {
+ return Dri2::Connect(Dri2::ConnectRequest{window, driver_type});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri2::ConnectReply> detail::ReadReply<Dri2::ConnectReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri2::ConnectReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t driver_name_length{};
+ uint32_t device_name_length{};
+ auto& driver_name = (*reply).driver_name;
+ size_t driver_name_len = driver_name.size();
+ auto& alignment_pad = (*reply).alignment_pad;
+ size_t alignment_pad_len = alignment_pad ? alignment_pad->size() : 0;
+ auto& device_name = (*reply).device_name;
+ size_t device_name_len = device_name.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // driver_name_length
+ Read(&driver_name_length, &buf);
+
+ // device_name_length
+ Read(&device_name_length, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ // driver_name
+ driver_name.resize(driver_name_length);
+ for (auto& driver_name_elem : driver_name) {
+ // driver_name_elem
+ Read(&driver_name_elem, &buf);
+ }
+
+ // alignment_pad
+ alignment_pad = buffer->ReadAndAdvance(
+ (BitAnd((driver_name_length) + (3), BitNot(3))) - (driver_name_length));
+
+ // device_name
+ device_name.resize(device_name_length);
+ for (auto& device_name_elem : device_name) {
+ // device_name_elem
+ Read(&device_name_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dri2::AuthenticateReply> Dri2::Authenticate(
+ const Dri2::AuthenticateRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& magic = request.magic;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // magic
+ buf.Write(&magic);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri2::AuthenticateReply>(
+ &buf, "Dri2::Authenticate", false);
+}
+
+Future<Dri2::AuthenticateReply> Dri2::Authenticate(const Window& window,
+ const uint32_t& magic) {
+ return Dri2::Authenticate(Dri2::AuthenticateRequest{window, magic});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri2::AuthenticateReply> detail::ReadReply<
+ Dri2::AuthenticateReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri2::AuthenticateReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& authenticated = (*reply).authenticated;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // authenticated
+ Read(&authenticated, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Dri2::CreateDrawable(const Dri2::CreateDrawableRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Dri2::CreateDrawable", false);
+}
+
+Future<void> Dri2::CreateDrawable(const Drawable& drawable) {
+ return Dri2::CreateDrawable(Dri2::CreateDrawableRequest{drawable});
+}
+
+Future<void> Dri2::DestroyDrawable(
+ const Dri2::DestroyDrawableRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Dri2::DestroyDrawable", false);
+}
+
+Future<void> Dri2::DestroyDrawable(const Drawable& drawable) {
+ return Dri2::DestroyDrawable(Dri2::DestroyDrawableRequest{drawable});
+}
+
+Future<Dri2::GetBuffersReply> Dri2::GetBuffers(
+ const Dri2::GetBuffersRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& count = request.count;
+ auto& attachments = request.attachments;
+ size_t attachments_len = attachments.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // count
+ buf.Write(&count);
+
+ // attachments
+ DCHECK_EQ(static_cast<size_t>(attachments_len), attachments.size());
+ for (auto& attachments_elem : attachments) {
+ // attachments_elem
+ buf.Write(&attachments_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri2::GetBuffersReply>(
+ &buf, "Dri2::GetBuffers", false);
+}
+
+Future<Dri2::GetBuffersReply> Dri2::GetBuffers(
+ const Drawable& drawable,
+ const uint32_t& count,
+ const std::vector<uint32_t>& attachments) {
+ return Dri2::GetBuffers(
+ Dri2::GetBuffersRequest{drawable, count, attachments});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri2::GetBuffersReply> detail::ReadReply<Dri2::GetBuffersReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri2::GetBuffersReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ uint32_t count{};
+ auto& buffers = (*reply).buffers;
+ size_t buffers_len = buffers.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // count
+ Read(&count, &buf);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // buffers
+ buffers.resize(count);
+ for (auto& buffers_elem : buffers) {
+ // buffers_elem
+ {
+ auto& attachment = buffers_elem.attachment;
+ auto& name = buffers_elem.name;
+ auto& pitch = buffers_elem.pitch;
+ auto& cpp = buffers_elem.cpp;
+ auto& flags = buffers_elem.flags;
+
+ // attachment
+ uint32_t tmp2;
+ Read(&tmp2, &buf);
+ attachment = static_cast<Dri2::Attachment>(tmp2);
+
+ // name
+ Read(&name, &buf);
+
+ // pitch
+ Read(&pitch, &buf);
+
+ // cpp
+ Read(&cpp, &buf);
+
+ // flags
+ Read(&flags, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dri2::CopyRegionReply> Dri2::CopyRegion(
+ const Dri2::CopyRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& region = request.region;
+ auto& dest = request.dest;
+ auto& src = request.src;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // region
+ buf.Write(&region);
+
+ // dest
+ buf.Write(&dest);
+
+ // src
+ buf.Write(&src);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri2::CopyRegionReply>(
+ &buf, "Dri2::CopyRegion", false);
+}
+
+Future<Dri2::CopyRegionReply> Dri2::CopyRegion(const Drawable& drawable,
+ const uint32_t& region,
+ const uint32_t& dest,
+ const uint32_t& src) {
+ return Dri2::CopyRegion(Dri2::CopyRegionRequest{drawable, region, dest, src});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri2::CopyRegionReply> detail::ReadReply<Dri2::CopyRegionReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri2::CopyRegionReply>();
+
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dri2::GetBuffersWithFormatReply> Dri2::GetBuffersWithFormat(
+ const Dri2::GetBuffersWithFormatRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& count = request.count;
+ auto& attachments = request.attachments;
+ size_t attachments_len = attachments.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // count
+ buf.Write(&count);
+
+ // attachments
+ DCHECK_EQ(static_cast<size_t>(attachments_len), attachments.size());
+ for (auto& attachments_elem : attachments) {
+ // attachments_elem
+ {
+ auto& attachment = attachments_elem.attachment;
+ auto& format = attachments_elem.format;
+
+ // attachment
+ uint32_t tmp3;
+ tmp3 = static_cast<uint32_t>(attachment);
+ buf.Write(&tmp3);
+
+ // format
+ buf.Write(&format);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri2::GetBuffersWithFormatReply>(
+ &buf, "Dri2::GetBuffersWithFormat", false);
+}
+
+Future<Dri2::GetBuffersWithFormatReply> Dri2::GetBuffersWithFormat(
+ const Drawable& drawable,
+ const uint32_t& count,
+ const std::vector<AttachFormat>& attachments) {
+ return Dri2::GetBuffersWithFormat(
+ Dri2::GetBuffersWithFormatRequest{drawable, count, attachments});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri2::GetBuffersWithFormatReply> detail::ReadReply<
+ Dri2::GetBuffersWithFormatReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri2::GetBuffersWithFormatReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ uint32_t count{};
+ auto& buffers = (*reply).buffers;
+ size_t buffers_len = buffers.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // count
+ Read(&count, &buf);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // buffers
+ buffers.resize(count);
+ for (auto& buffers_elem : buffers) {
+ // buffers_elem
+ {
+ auto& attachment = buffers_elem.attachment;
+ auto& name = buffers_elem.name;
+ auto& pitch = buffers_elem.pitch;
+ auto& cpp = buffers_elem.cpp;
+ auto& flags = buffers_elem.flags;
+
+ // attachment
+ uint32_t tmp4;
+ Read(&tmp4, &buf);
+ attachment = static_cast<Dri2::Attachment>(tmp4);
+
+ // name
+ Read(&name, &buf);
+
+ // pitch
+ Read(&pitch, &buf);
+
+ // cpp
+ Read(&cpp, &buf);
+
+ // flags
+ Read(&flags, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dri2::SwapBuffersReply> Dri2::SwapBuffers(
+ const Dri2::SwapBuffersRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& target_msc_hi = request.target_msc_hi;
+ auto& target_msc_lo = request.target_msc_lo;
+ auto& divisor_hi = request.divisor_hi;
+ auto& divisor_lo = request.divisor_lo;
+ auto& remainder_hi = request.remainder_hi;
+ auto& remainder_lo = request.remainder_lo;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // target_msc_hi
+ buf.Write(&target_msc_hi);
+
+ // target_msc_lo
+ buf.Write(&target_msc_lo);
+
+ // divisor_hi
+ buf.Write(&divisor_hi);
+
+ // divisor_lo
+ buf.Write(&divisor_lo);
+
+ // remainder_hi
+ buf.Write(&remainder_hi);
+
+ // remainder_lo
+ buf.Write(&remainder_lo);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri2::SwapBuffersReply>(
+ &buf, "Dri2::SwapBuffers", false);
+}
+
+Future<Dri2::SwapBuffersReply> Dri2::SwapBuffers(const Drawable& drawable,
+ const uint32_t& target_msc_hi,
+ const uint32_t& target_msc_lo,
+ const uint32_t& divisor_hi,
+ const uint32_t& divisor_lo,
+ const uint32_t& remainder_hi,
+ const uint32_t& remainder_lo) {
+ return Dri2::SwapBuffers(Dri2::SwapBuffersRequest{
+ drawable, target_msc_hi, target_msc_lo, divisor_hi, divisor_lo,
+ remainder_hi, remainder_lo});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri2::SwapBuffersReply> detail::ReadReply<
+ Dri2::SwapBuffersReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri2::SwapBuffersReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& swap_hi = (*reply).swap_hi;
+ auto& swap_lo = (*reply).swap_lo;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // swap_hi
+ Read(&swap_hi, &buf);
+
+ // swap_lo
+ Read(&swap_lo, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dri2::GetMSCReply> Dri2::GetMSC(const Dri2::GetMSCRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri2::GetMSCReply>(&buf, "Dri2::GetMSC",
+ false);
+}
+
+Future<Dri2::GetMSCReply> Dri2::GetMSC(const Drawable& drawable) {
+ return Dri2::GetMSC(Dri2::GetMSCRequest{drawable});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri2::GetMSCReply> detail::ReadReply<Dri2::GetMSCReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri2::GetMSCReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& ust_hi = (*reply).ust_hi;
+ auto& ust_lo = (*reply).ust_lo;
+ auto& msc_hi = (*reply).msc_hi;
+ auto& msc_lo = (*reply).msc_lo;
+ auto& sbc_hi = (*reply).sbc_hi;
+ auto& sbc_lo = (*reply).sbc_lo;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // ust_hi
+ Read(&ust_hi, &buf);
+
+ // ust_lo
+ Read(&ust_lo, &buf);
+
+ // msc_hi
+ Read(&msc_hi, &buf);
+
+ // msc_lo
+ Read(&msc_lo, &buf);
+
+ // sbc_hi
+ Read(&sbc_hi, &buf);
+
+ // sbc_lo
+ Read(&sbc_lo, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dri2::WaitMSCReply> Dri2::WaitMSC(const Dri2::WaitMSCRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& target_msc_hi = request.target_msc_hi;
+ auto& target_msc_lo = request.target_msc_lo;
+ auto& divisor_hi = request.divisor_hi;
+ auto& divisor_lo = request.divisor_lo;
+ auto& remainder_hi = request.remainder_hi;
+ auto& remainder_lo = request.remainder_lo;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // target_msc_hi
+ buf.Write(&target_msc_hi);
+
+ // target_msc_lo
+ buf.Write(&target_msc_lo);
+
+ // divisor_hi
+ buf.Write(&divisor_hi);
+
+ // divisor_lo
+ buf.Write(&divisor_lo);
+
+ // remainder_hi
+ buf.Write(&remainder_hi);
+
+ // remainder_lo
+ buf.Write(&remainder_lo);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri2::WaitMSCReply>(&buf, "Dri2::WaitMSC",
+ false);
+}
+
+Future<Dri2::WaitMSCReply> Dri2::WaitMSC(const Drawable& drawable,
+ const uint32_t& target_msc_hi,
+ const uint32_t& target_msc_lo,
+ const uint32_t& divisor_hi,
+ const uint32_t& divisor_lo,
+ const uint32_t& remainder_hi,
+ const uint32_t& remainder_lo) {
+ return Dri2::WaitMSC(
+ Dri2::WaitMSCRequest{drawable, target_msc_hi, target_msc_lo, divisor_hi,
+ divisor_lo, remainder_hi, remainder_lo});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri2::WaitMSCReply> detail::ReadReply<Dri2::WaitMSCReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri2::WaitMSCReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& ust_hi = (*reply).ust_hi;
+ auto& ust_lo = (*reply).ust_lo;
+ auto& msc_hi = (*reply).msc_hi;
+ auto& msc_lo = (*reply).msc_lo;
+ auto& sbc_hi = (*reply).sbc_hi;
+ auto& sbc_lo = (*reply).sbc_lo;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // ust_hi
+ Read(&ust_hi, &buf);
+
+ // ust_lo
+ Read(&ust_lo, &buf);
+
+ // msc_hi
+ Read(&msc_hi, &buf);
+
+ // msc_lo
+ Read(&msc_lo, &buf);
+
+ // sbc_hi
+ Read(&sbc_hi, &buf);
+
+ // sbc_lo
+ Read(&sbc_lo, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dri2::WaitSBCReply> Dri2::WaitSBC(const Dri2::WaitSBCRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& target_sbc_hi = request.target_sbc_hi;
+ auto& target_sbc_lo = request.target_sbc_lo;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // target_sbc_hi
+ buf.Write(&target_sbc_hi);
+
+ // target_sbc_lo
+ buf.Write(&target_sbc_lo);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri2::WaitSBCReply>(&buf, "Dri2::WaitSBC",
+ false);
+}
+
+Future<Dri2::WaitSBCReply> Dri2::WaitSBC(const Drawable& drawable,
+ const uint32_t& target_sbc_hi,
+ const uint32_t& target_sbc_lo) {
+ return Dri2::WaitSBC(
+ Dri2::WaitSBCRequest{drawable, target_sbc_hi, target_sbc_lo});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri2::WaitSBCReply> detail::ReadReply<Dri2::WaitSBCReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri2::WaitSBCReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& ust_hi = (*reply).ust_hi;
+ auto& ust_lo = (*reply).ust_lo;
+ auto& msc_hi = (*reply).msc_hi;
+ auto& msc_lo = (*reply).msc_lo;
+ auto& sbc_hi = (*reply).sbc_hi;
+ auto& sbc_lo = (*reply).sbc_lo;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // ust_hi
+ Read(&ust_hi, &buf);
+
+ // ust_lo
+ Read(&ust_lo, &buf);
+
+ // msc_hi
+ Read(&msc_hi, &buf);
+
+ // msc_lo
+ Read(&msc_lo, &buf);
+
+ // sbc_hi
+ Read(&sbc_hi, &buf);
+
+ // sbc_lo
+ Read(&sbc_lo, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Dri2::SwapInterval(const Dri2::SwapIntervalRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& interval = request.interval;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // interval
+ buf.Write(&interval);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Dri2::SwapInterval", false);
+}
+
+Future<void> Dri2::SwapInterval(const Drawable& drawable,
+ const uint32_t& interval) {
+ return Dri2::SwapInterval(Dri2::SwapIntervalRequest{drawable, interval});
+}
+
+Future<Dri2::GetParamReply> Dri2::GetParam(
+ const Dri2::GetParamRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& param = request.param;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // param
+ buf.Write(&param);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri2::GetParamReply>(&buf, "Dri2::GetParam",
+ false);
+}
+
+Future<Dri2::GetParamReply> Dri2::GetParam(const Drawable& drawable,
+ const uint32_t& param) {
+ return Dri2::GetParam(Dri2::GetParamRequest{drawable, param});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri2::GetParamReply> detail::ReadReply<Dri2::GetParamReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri2::GetParamReply>();
+
+ auto& is_param_recognized = (*reply).is_param_recognized;
+ auto& sequence = (*reply).sequence;
+ auto& value_hi = (*reply).value_hi;
+ auto& value_lo = (*reply).value_lo;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // is_param_recognized
+ Read(&is_param_recognized, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // value_hi
+ Read(&value_hi, &buf);
+
+ // value_lo
+ Read(&value_lo, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/dri2.h b/chromium/ui/gfx/x/generated_protos/dri2.h
new file mode 100644
index 00000000000..1db7856c83b
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/dri2.h
@@ -0,0 +1,474 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_DRI2_H_
+#define UI_GFX_X_GENERATED_PROTOS_DRI2_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Dri2 {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 4;
+
+ Dri2(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Attachment : int {
+ BufferFrontLeft = 0,
+ BufferBackLeft = 1,
+ BufferFrontRight = 2,
+ BufferBackRight = 3,
+ BufferDepth = 4,
+ BufferStencil = 5,
+ BufferAccum = 6,
+ BufferFakeFrontLeft = 7,
+ BufferFakeFrontRight = 8,
+ BufferDepthStencil = 9,
+ BufferHiz = 10,
+ };
+
+ enum class DriverType : int {
+ DRI = 0,
+ VDPAU = 1,
+ };
+
+ enum class EventType : int {
+ ExchangeComplete = 1,
+ BlitComplete = 2,
+ FlipComplete = 3,
+ };
+
+ struct DRI2Buffer {
+ Attachment attachment{};
+ uint32_t name{};
+ uint32_t pitch{};
+ uint32_t cpp{};
+ uint32_t flags{};
+ };
+
+ struct AttachFormat {
+ Attachment attachment{};
+ uint32_t format{};
+ };
+
+ struct BufferSwapCompleteEvent {
+ static constexpr int type_id = 2;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ uint16_t sequence{};
+ EventType event_type{};
+ Drawable drawable{};
+ uint32_t ust_hi{};
+ uint32_t ust_lo{};
+ uint32_t msc_hi{};
+ uint32_t msc_lo{};
+ uint32_t sbc{};
+
+ x11::Window* GetWindow() {
+ return reinterpret_cast<x11::Window*>(&drawable);
+ }
+ };
+
+ struct InvalidateBuffersEvent {
+ static constexpr int type_id = 3;
+ static constexpr uint8_t opcode = 1;
+ bool send_event{};
+ uint16_t sequence{};
+ Drawable drawable{};
+
+ x11::Window* GetWindow() {
+ return reinterpret_cast<x11::Window*>(&drawable);
+ }
+ };
+
+ struct QueryVersionRequest {
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(const uint32_t& major_version = {},
+ const uint32_t& minor_version = {});
+
+ struct ConnectRequest {
+ Window window{};
+ DriverType driver_type{};
+ };
+
+ struct ConnectReply {
+ uint16_t sequence{};
+ std::string driver_name{};
+ scoped_refptr<base::RefCountedMemory> alignment_pad{};
+ std::string device_name{};
+ };
+
+ using ConnectResponse = Response<ConnectReply>;
+
+ Future<ConnectReply> Connect(const ConnectRequest& request);
+
+ Future<ConnectReply> Connect(const Window& window = {},
+ const DriverType& driver_type = {});
+
+ struct AuthenticateRequest {
+ Window window{};
+ uint32_t magic{};
+ };
+
+ struct AuthenticateReply {
+ uint16_t sequence{};
+ uint32_t authenticated{};
+ };
+
+ using AuthenticateResponse = Response<AuthenticateReply>;
+
+ Future<AuthenticateReply> Authenticate(const AuthenticateRequest& request);
+
+ Future<AuthenticateReply> Authenticate(const Window& window = {},
+ const uint32_t& magic = {});
+
+ struct CreateDrawableRequest {
+ Drawable drawable{};
+ };
+
+ using CreateDrawableResponse = Response<void>;
+
+ Future<void> CreateDrawable(const CreateDrawableRequest& request);
+
+ Future<void> CreateDrawable(const Drawable& drawable = {});
+
+ struct DestroyDrawableRequest {
+ Drawable drawable{};
+ };
+
+ using DestroyDrawableResponse = Response<void>;
+
+ Future<void> DestroyDrawable(const DestroyDrawableRequest& request);
+
+ Future<void> DestroyDrawable(const Drawable& drawable = {});
+
+ struct GetBuffersRequest {
+ Drawable drawable{};
+ uint32_t count{};
+ std::vector<uint32_t> attachments{};
+ };
+
+ struct GetBuffersReply {
+ uint16_t sequence{};
+ uint32_t width{};
+ uint32_t height{};
+ std::vector<DRI2Buffer> buffers{};
+ };
+
+ using GetBuffersResponse = Response<GetBuffersReply>;
+
+ Future<GetBuffersReply> GetBuffers(const GetBuffersRequest& request);
+
+ Future<GetBuffersReply> GetBuffers(
+ const Drawable& drawable = {},
+ const uint32_t& count = {},
+ const std::vector<uint32_t>& attachments = {});
+
+ struct CopyRegionRequest {
+ Drawable drawable{};
+ uint32_t region{};
+ uint32_t dest{};
+ uint32_t src{};
+ };
+
+ struct CopyRegionReply {
+ uint16_t sequence{};
+ };
+
+ using CopyRegionResponse = Response<CopyRegionReply>;
+
+ Future<CopyRegionReply> CopyRegion(const CopyRegionRequest& request);
+
+ Future<CopyRegionReply> CopyRegion(const Drawable& drawable = {},
+ const uint32_t& region = {},
+ const uint32_t& dest = {},
+ const uint32_t& src = {});
+
+ struct GetBuffersWithFormatRequest {
+ Drawable drawable{};
+ uint32_t count{};
+ std::vector<AttachFormat> attachments{};
+ };
+
+ struct GetBuffersWithFormatReply {
+ uint16_t sequence{};
+ uint32_t width{};
+ uint32_t height{};
+ std::vector<DRI2Buffer> buffers{};
+ };
+
+ using GetBuffersWithFormatResponse = Response<GetBuffersWithFormatReply>;
+
+ Future<GetBuffersWithFormatReply> GetBuffersWithFormat(
+ const GetBuffersWithFormatRequest& request);
+
+ Future<GetBuffersWithFormatReply> GetBuffersWithFormat(
+ const Drawable& drawable = {},
+ const uint32_t& count = {},
+ const std::vector<AttachFormat>& attachments = {});
+
+ struct SwapBuffersRequest {
+ Drawable drawable{};
+ uint32_t target_msc_hi{};
+ uint32_t target_msc_lo{};
+ uint32_t divisor_hi{};
+ uint32_t divisor_lo{};
+ uint32_t remainder_hi{};
+ uint32_t remainder_lo{};
+ };
+
+ struct SwapBuffersReply {
+ uint16_t sequence{};
+ uint32_t swap_hi{};
+ uint32_t swap_lo{};
+ };
+
+ using SwapBuffersResponse = Response<SwapBuffersReply>;
+
+ Future<SwapBuffersReply> SwapBuffers(const SwapBuffersRequest& request);
+
+ Future<SwapBuffersReply> SwapBuffers(const Drawable& drawable = {},
+ const uint32_t& target_msc_hi = {},
+ const uint32_t& target_msc_lo = {},
+ const uint32_t& divisor_hi = {},
+ const uint32_t& divisor_lo = {},
+ const uint32_t& remainder_hi = {},
+ const uint32_t& remainder_lo = {});
+
+ struct GetMSCRequest {
+ Drawable drawable{};
+ };
+
+ struct GetMSCReply {
+ uint16_t sequence{};
+ uint32_t ust_hi{};
+ uint32_t ust_lo{};
+ uint32_t msc_hi{};
+ uint32_t msc_lo{};
+ uint32_t sbc_hi{};
+ uint32_t sbc_lo{};
+ };
+
+ using GetMSCResponse = Response<GetMSCReply>;
+
+ Future<GetMSCReply> GetMSC(const GetMSCRequest& request);
+
+ Future<GetMSCReply> GetMSC(const Drawable& drawable = {});
+
+ struct WaitMSCRequest {
+ Drawable drawable{};
+ uint32_t target_msc_hi{};
+ uint32_t target_msc_lo{};
+ uint32_t divisor_hi{};
+ uint32_t divisor_lo{};
+ uint32_t remainder_hi{};
+ uint32_t remainder_lo{};
+ };
+
+ struct WaitMSCReply {
+ uint16_t sequence{};
+ uint32_t ust_hi{};
+ uint32_t ust_lo{};
+ uint32_t msc_hi{};
+ uint32_t msc_lo{};
+ uint32_t sbc_hi{};
+ uint32_t sbc_lo{};
+ };
+
+ using WaitMSCResponse = Response<WaitMSCReply>;
+
+ Future<WaitMSCReply> WaitMSC(const WaitMSCRequest& request);
+
+ Future<WaitMSCReply> WaitMSC(const Drawable& drawable = {},
+ const uint32_t& target_msc_hi = {},
+ const uint32_t& target_msc_lo = {},
+ const uint32_t& divisor_hi = {},
+ const uint32_t& divisor_lo = {},
+ const uint32_t& remainder_hi = {},
+ const uint32_t& remainder_lo = {});
+
+ struct WaitSBCRequest {
+ Drawable drawable{};
+ uint32_t target_sbc_hi{};
+ uint32_t target_sbc_lo{};
+ };
+
+ struct WaitSBCReply {
+ uint16_t sequence{};
+ uint32_t ust_hi{};
+ uint32_t ust_lo{};
+ uint32_t msc_hi{};
+ uint32_t msc_lo{};
+ uint32_t sbc_hi{};
+ uint32_t sbc_lo{};
+ };
+
+ using WaitSBCResponse = Response<WaitSBCReply>;
+
+ Future<WaitSBCReply> WaitSBC(const WaitSBCRequest& request);
+
+ Future<WaitSBCReply> WaitSBC(const Drawable& drawable = {},
+ const uint32_t& target_sbc_hi = {},
+ const uint32_t& target_sbc_lo = {});
+
+ struct SwapIntervalRequest {
+ Drawable drawable{};
+ uint32_t interval{};
+ };
+
+ using SwapIntervalResponse = Response<void>;
+
+ Future<void> SwapInterval(const SwapIntervalRequest& request);
+
+ Future<void> SwapInterval(const Drawable& drawable = {},
+ const uint32_t& interval = {});
+
+ struct GetParamRequest {
+ Drawable drawable{};
+ uint32_t param{};
+ };
+
+ struct GetParamReply {
+ uint8_t is_param_recognized{};
+ uint16_t sequence{};
+ uint32_t value_hi{};
+ uint32_t value_lo{};
+ };
+
+ using GetParamResponse = Response<GetParamReply>;
+
+ Future<GetParamReply> GetParam(const GetParamRequest& request);
+
+ Future<GetParamReply> GetParam(const Drawable& drawable = {},
+ const uint32_t& param = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Dri2::Attachment operator|(x11::Dri2::Attachment l,
+ x11::Dri2::Attachment r) {
+ using T = std::underlying_type_t<x11::Dri2::Attachment>;
+ return static_cast<x11::Dri2::Attachment>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Dri2::Attachment operator&(x11::Dri2::Attachment l,
+ x11::Dri2::Attachment r) {
+ using T = std::underlying_type_t<x11::Dri2::Attachment>;
+ return static_cast<x11::Dri2::Attachment>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Dri2::DriverType operator|(x11::Dri2::DriverType l,
+ x11::Dri2::DriverType r) {
+ using T = std::underlying_type_t<x11::Dri2::DriverType>;
+ return static_cast<x11::Dri2::DriverType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Dri2::DriverType operator&(x11::Dri2::DriverType l,
+ x11::Dri2::DriverType r) {
+ using T = std::underlying_type_t<x11::Dri2::DriverType>;
+ return static_cast<x11::Dri2::DriverType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Dri2::EventType operator|(x11::Dri2::EventType l,
+ x11::Dri2::EventType r) {
+ using T = std::underlying_type_t<x11::Dri2::EventType>;
+ return static_cast<x11::Dri2::EventType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Dri2::EventType operator&(x11::Dri2::EventType l,
+ x11::Dri2::EventType r) {
+ using T = std::underlying_type_t<x11::Dri2::EventType>;
+ return static_cast<x11::Dri2::EventType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_DRI2_H_
diff --git a/chromium/ui/gfx/x/generated_protos/dri3.cc b/chromium/ui/gfx/x/generated_protos/dri3.cc
new file mode 100644
index 00000000000..158cfdf36cc
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/dri3.cc
@@ -0,0 +1,855 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "dri3.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Dri3::Dri3(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<Dri3::QueryVersionReply> Dri3::QueryVersion(
+ const Dri3::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major_version = request.major_version;
+ auto& minor_version = request.minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major_version
+ buf.Write(&major_version);
+
+ // minor_version
+ buf.Write(&minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri3::QueryVersionReply>(
+ &buf, "Dri3::QueryVersion", false);
+}
+
+Future<Dri3::QueryVersionReply> Dri3::QueryVersion(
+ const uint32_t& major_version,
+ const uint32_t& minor_version) {
+ return Dri3::QueryVersion(
+ Dri3::QueryVersionRequest{major_version, minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri3::QueryVersionReply> detail::ReadReply<
+ Dri3::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri3::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dri3::OpenReply> Dri3::Open(const Dri3::OpenRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& provider = request.provider;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // provider
+ buf.Write(&provider);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri3::OpenReply>(&buf, "Dri3::Open", true);
+}
+
+Future<Dri3::OpenReply> Dri3::Open(const Drawable& drawable,
+ const uint32_t& provider) {
+ return Dri3::Open(Dri3::OpenRequest{drawable, provider});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri3::OpenReply> detail::ReadReply<Dri3::OpenReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri3::OpenReply>();
+
+ auto& nfd = (*reply).nfd;
+ auto& sequence = (*reply).sequence;
+ auto& device_fd = (*reply).device_fd;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // nfd
+ Read(&nfd, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // device_fd
+ device_fd = RefCountedFD(buf.TakeFd());
+
+ // pad0
+ Pad(&buf, 24);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Dri3::PixmapFromBuffer(
+ const Dri3::PixmapFromBufferRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& pixmap = request.pixmap;
+ auto& drawable = request.drawable;
+ auto& size = request.size;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& stride = request.stride;
+ auto& depth = request.depth;
+ auto& bpp = request.bpp;
+ auto& pixmap_fd = request.pixmap_fd;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // pixmap
+ buf.Write(&pixmap);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // size
+ buf.Write(&size);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // stride
+ buf.Write(&stride);
+
+ // depth
+ buf.Write(&depth);
+
+ // bpp
+ buf.Write(&bpp);
+
+ // pixmap_fd
+ buf.fds().push_back(HANDLE_EINTR(dup(pixmap_fd.get())));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Dri3::PixmapFromBuffer", false);
+}
+
+Future<void> Dri3::PixmapFromBuffer(const Pixmap& pixmap,
+ const Drawable& drawable,
+ const uint32_t& size,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint16_t& stride,
+ const uint8_t& depth,
+ const uint8_t& bpp,
+ const RefCountedFD& pixmap_fd) {
+ return Dri3::PixmapFromBuffer(Dri3::PixmapFromBufferRequest{
+ pixmap, drawable, size, width, height, stride, depth, bpp, pixmap_fd});
+}
+
+Future<Dri3::BufferFromPixmapReply> Dri3::BufferFromPixmap(
+ const Dri3::BufferFromPixmapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& pixmap = request.pixmap;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // pixmap
+ buf.Write(&pixmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri3::BufferFromPixmapReply>(
+ &buf, "Dri3::BufferFromPixmap", true);
+}
+
+Future<Dri3::BufferFromPixmapReply> Dri3::BufferFromPixmap(
+ const Pixmap& pixmap) {
+ return Dri3::BufferFromPixmap(Dri3::BufferFromPixmapRequest{pixmap});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri3::BufferFromPixmapReply> detail::ReadReply<
+ Dri3::BufferFromPixmapReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri3::BufferFromPixmapReply>();
+
+ auto& nfd = (*reply).nfd;
+ auto& sequence = (*reply).sequence;
+ auto& size = (*reply).size;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& stride = (*reply).stride;
+ auto& depth = (*reply).depth;
+ auto& bpp = (*reply).bpp;
+ auto& pixmap_fd = (*reply).pixmap_fd;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // nfd
+ Read(&nfd, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // size
+ Read(&size, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // stride
+ Read(&stride, &buf);
+
+ // depth
+ Read(&depth, &buf);
+
+ // bpp
+ Read(&bpp, &buf);
+
+ // pixmap_fd
+ pixmap_fd = RefCountedFD(buf.TakeFd());
+
+ // pad0
+ Pad(&buf, 12);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Dri3::FenceFromFD(const Dri3::FenceFromFDRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& fence = request.fence;
+ auto& initially_triggered = request.initially_triggered;
+ auto& fence_fd = request.fence_fd;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // fence
+ buf.Write(&fence);
+
+ // initially_triggered
+ buf.Write(&initially_triggered);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // fence_fd
+ buf.fds().push_back(HANDLE_EINTR(dup(fence_fd.get())));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Dri3::FenceFromFD", false);
+}
+
+Future<void> Dri3::FenceFromFD(const Drawable& drawable,
+ const uint32_t& fence,
+ const uint8_t& initially_triggered,
+ const RefCountedFD& fence_fd) {
+ return Dri3::FenceFromFD(
+ Dri3::FenceFromFDRequest{drawable, fence, initially_triggered, fence_fd});
+}
+
+Future<Dri3::FDFromFenceReply> Dri3::FDFromFence(
+ const Dri3::FDFromFenceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& fence = request.fence;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // fence
+ buf.Write(&fence);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri3::FDFromFenceReply>(
+ &buf, "Dri3::FDFromFence", true);
+}
+
+Future<Dri3::FDFromFenceReply> Dri3::FDFromFence(const Drawable& drawable,
+ const uint32_t& fence) {
+ return Dri3::FDFromFence(Dri3::FDFromFenceRequest{drawable, fence});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri3::FDFromFenceReply> detail::ReadReply<
+ Dri3::FDFromFenceReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri3::FDFromFenceReply>();
+
+ auto& nfd = (*reply).nfd;
+ auto& sequence = (*reply).sequence;
+ auto& fence_fd = (*reply).fence_fd;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // nfd
+ Read(&nfd, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // fence_fd
+ fence_fd = RefCountedFD(buf.TakeFd());
+
+ // pad0
+ Pad(&buf, 24);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Dri3::GetSupportedModifiersReply> Dri3::GetSupportedModifiers(
+ const Dri3::GetSupportedModifiersRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& depth = request.depth;
+ auto& bpp = request.bpp;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // depth
+ buf.Write(&depth);
+
+ // bpp
+ buf.Write(&bpp);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri3::GetSupportedModifiersReply>(
+ &buf, "Dri3::GetSupportedModifiers", false);
+}
+
+Future<Dri3::GetSupportedModifiersReply> Dri3::GetSupportedModifiers(
+ const uint32_t& window,
+ const uint8_t& depth,
+ const uint8_t& bpp) {
+ return Dri3::GetSupportedModifiers(
+ Dri3::GetSupportedModifiersRequest{window, depth, bpp});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri3::GetSupportedModifiersReply> detail::ReadReply<
+ Dri3::GetSupportedModifiersReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri3::GetSupportedModifiersReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num_window_modifiers{};
+ uint32_t num_screen_modifiers{};
+ auto& window_modifiers = (*reply).window_modifiers;
+ size_t window_modifiers_len = window_modifiers.size();
+ auto& screen_modifiers = (*reply).screen_modifiers;
+ size_t screen_modifiers_len = screen_modifiers.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_window_modifiers
+ Read(&num_window_modifiers, &buf);
+
+ // num_screen_modifiers
+ Read(&num_screen_modifiers, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ // window_modifiers
+ window_modifiers.resize(num_window_modifiers);
+ for (auto& window_modifiers_elem : window_modifiers) {
+ // window_modifiers_elem
+ Read(&window_modifiers_elem, &buf);
+ }
+
+ // screen_modifiers
+ screen_modifiers.resize(num_screen_modifiers);
+ for (auto& screen_modifiers_elem : screen_modifiers) {
+ // screen_modifiers_elem
+ Read(&screen_modifiers_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Dri3::PixmapFromBuffers(
+ const Dri3::PixmapFromBuffersRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& pixmap = request.pixmap;
+ auto& window = request.window;
+ uint8_t num_buffers{};
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& stride0 = request.stride0;
+ auto& offset0 = request.offset0;
+ auto& stride1 = request.stride1;
+ auto& offset1 = request.offset1;
+ auto& stride2 = request.stride2;
+ auto& offset2 = request.offset2;
+ auto& stride3 = request.stride3;
+ auto& offset3 = request.offset3;
+ auto& depth = request.depth;
+ auto& bpp = request.bpp;
+ auto& modifier = request.modifier;
+ auto& buffers = request.buffers;
+ size_t buffers_len = buffers.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // pixmap
+ buf.Write(&pixmap);
+
+ // window
+ buf.Write(&window);
+
+ // num_buffers
+ num_buffers = buffers.size();
+ buf.Write(&num_buffers);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // stride0
+ buf.Write(&stride0);
+
+ // offset0
+ buf.Write(&offset0);
+
+ // stride1
+ buf.Write(&stride1);
+
+ // offset1
+ buf.Write(&offset1);
+
+ // stride2
+ buf.Write(&stride2);
+
+ // offset2
+ buf.Write(&offset2);
+
+ // stride3
+ buf.Write(&stride3);
+
+ // offset3
+ buf.Write(&offset3);
+
+ // depth
+ buf.Write(&depth);
+
+ // bpp
+ buf.Write(&bpp);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // modifier
+ buf.Write(&modifier);
+
+ // buffers
+ DCHECK_EQ(static_cast<size_t>(num_buffers), buffers.size());
+ for (auto& buffers_elem : buffers) {
+ // buffers_elem
+ buf.fds().push_back(HANDLE_EINTR(dup(buffers_elem.get())));
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Dri3::PixmapFromBuffers", false);
+}
+
+Future<void> Dri3::PixmapFromBuffers(const Pixmap& pixmap,
+ const Window& window,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint32_t& stride0,
+ const uint32_t& offset0,
+ const uint32_t& stride1,
+ const uint32_t& offset1,
+ const uint32_t& stride2,
+ const uint32_t& offset2,
+ const uint32_t& stride3,
+ const uint32_t& offset3,
+ const uint8_t& depth,
+ const uint8_t& bpp,
+ const uint64_t& modifier,
+ const std::vector<RefCountedFD>& buffers) {
+ return Dri3::PixmapFromBuffers(Dri3::PixmapFromBuffersRequest{
+ pixmap, window, width, height, stride0, offset0, stride1, offset1,
+ stride2, offset2, stride3, offset3, depth, bpp, modifier, buffers});
+}
+
+Future<Dri3::BuffersFromPixmapReply> Dri3::BuffersFromPixmap(
+ const Dri3::BuffersFromPixmapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& pixmap = request.pixmap;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // pixmap
+ buf.Write(&pixmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Dri3::BuffersFromPixmapReply>(
+ &buf, "Dri3::BuffersFromPixmap", true);
+}
+
+Future<Dri3::BuffersFromPixmapReply> Dri3::BuffersFromPixmap(
+ const Pixmap& pixmap) {
+ return Dri3::BuffersFromPixmap(Dri3::BuffersFromPixmapRequest{pixmap});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Dri3::BuffersFromPixmapReply> detail::ReadReply<
+ Dri3::BuffersFromPixmapReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Dri3::BuffersFromPixmapReply>();
+
+ uint8_t nfd{};
+ auto& sequence = (*reply).sequence;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& modifier = (*reply).modifier;
+ auto& depth = (*reply).depth;
+ auto& bpp = (*reply).bpp;
+ auto& strides = (*reply).strides;
+ size_t strides_len = strides.size();
+ auto& offsets = (*reply).offsets;
+ size_t offsets_len = offsets.size();
+ auto& buffers = (*reply).buffers;
+ size_t buffers_len = buffers.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // nfd
+ Read(&nfd, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // pad0
+ Pad(&buf, 4);
+
+ // modifier
+ Read(&modifier, &buf);
+
+ // depth
+ Read(&depth, &buf);
+
+ // bpp
+ Read(&bpp, &buf);
+
+ // pad1
+ Pad(&buf, 6);
+
+ // strides
+ strides.resize(nfd);
+ for (auto& strides_elem : strides) {
+ // strides_elem
+ Read(&strides_elem, &buf);
+ }
+
+ // offsets
+ offsets.resize(nfd);
+ for (auto& offsets_elem : offsets) {
+ // offsets_elem
+ Read(&offsets_elem, &buf);
+ }
+
+ // buffers
+ buffers.resize(nfd);
+ for (auto& buffers_elem : buffers) {
+ // buffers_elem
+ buffers_elem = RefCountedFD(buf.TakeFd());
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/dri3.h b/chromium/ui/gfx/x/generated_protos/dri3.h
new file mode 100644
index 00000000000..35bc163d0aa
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/dri3.h
@@ -0,0 +1,294 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_DRI3_H_
+#define UI_GFX_X_GENERATED_PROTOS_DRI3_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Dri3 {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 2;
+
+ Dri3(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ struct QueryVersionRequest {
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(const uint32_t& major_version = {},
+ const uint32_t& minor_version = {});
+
+ struct OpenRequest {
+ Drawable drawable{};
+ uint32_t provider{};
+ };
+
+ struct OpenReply {
+ uint8_t nfd{};
+ uint16_t sequence{};
+ RefCountedFD device_fd{};
+ };
+
+ using OpenResponse = Response<OpenReply>;
+
+ Future<OpenReply> Open(const OpenRequest& request);
+
+ Future<OpenReply> Open(const Drawable& drawable = {},
+ const uint32_t& provider = {});
+
+ struct PixmapFromBufferRequest {
+ Pixmap pixmap{};
+ Drawable drawable{};
+ uint32_t size{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t stride{};
+ uint8_t depth{};
+ uint8_t bpp{};
+ RefCountedFD pixmap_fd{};
+ };
+
+ using PixmapFromBufferResponse = Response<void>;
+
+ Future<void> PixmapFromBuffer(const PixmapFromBufferRequest& request);
+
+ Future<void> PixmapFromBuffer(const Pixmap& pixmap = {},
+ const Drawable& drawable = {},
+ const uint32_t& size = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint16_t& stride = {},
+ const uint8_t& depth = {},
+ const uint8_t& bpp = {},
+ const RefCountedFD& pixmap_fd = {});
+
+ struct BufferFromPixmapRequest {
+ Pixmap pixmap{};
+ };
+
+ struct BufferFromPixmapReply {
+ uint8_t nfd{};
+ uint16_t sequence{};
+ uint32_t size{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t stride{};
+ uint8_t depth{};
+ uint8_t bpp{};
+ RefCountedFD pixmap_fd{};
+ };
+
+ using BufferFromPixmapResponse = Response<BufferFromPixmapReply>;
+
+ Future<BufferFromPixmapReply> BufferFromPixmap(
+ const BufferFromPixmapRequest& request);
+
+ Future<BufferFromPixmapReply> BufferFromPixmap(const Pixmap& pixmap = {});
+
+ struct FenceFromFDRequest {
+ Drawable drawable{};
+ uint32_t fence{};
+ uint8_t initially_triggered{};
+ RefCountedFD fence_fd{};
+ };
+
+ using FenceFromFDResponse = Response<void>;
+
+ Future<void> FenceFromFD(const FenceFromFDRequest& request);
+
+ Future<void> FenceFromFD(const Drawable& drawable = {},
+ const uint32_t& fence = {},
+ const uint8_t& initially_triggered = {},
+ const RefCountedFD& fence_fd = {});
+
+ struct FDFromFenceRequest {
+ Drawable drawable{};
+ uint32_t fence{};
+ };
+
+ struct FDFromFenceReply {
+ uint8_t nfd{};
+ uint16_t sequence{};
+ RefCountedFD fence_fd{};
+ };
+
+ using FDFromFenceResponse = Response<FDFromFenceReply>;
+
+ Future<FDFromFenceReply> FDFromFence(const FDFromFenceRequest& request);
+
+ Future<FDFromFenceReply> FDFromFence(const Drawable& drawable = {},
+ const uint32_t& fence = {});
+
+ struct GetSupportedModifiersRequest {
+ uint32_t window{};
+ uint8_t depth{};
+ uint8_t bpp{};
+ };
+
+ struct GetSupportedModifiersReply {
+ uint16_t sequence{};
+ std::vector<uint64_t> window_modifiers{};
+ std::vector<uint64_t> screen_modifiers{};
+ };
+
+ using GetSupportedModifiersResponse = Response<GetSupportedModifiersReply>;
+
+ Future<GetSupportedModifiersReply> GetSupportedModifiers(
+ const GetSupportedModifiersRequest& request);
+
+ Future<GetSupportedModifiersReply> GetSupportedModifiers(
+ const uint32_t& window = {},
+ const uint8_t& depth = {},
+ const uint8_t& bpp = {});
+
+ struct PixmapFromBuffersRequest {
+ Pixmap pixmap{};
+ Window window{};
+ uint16_t width{};
+ uint16_t height{};
+ uint32_t stride0{};
+ uint32_t offset0{};
+ uint32_t stride1{};
+ uint32_t offset1{};
+ uint32_t stride2{};
+ uint32_t offset2{};
+ uint32_t stride3{};
+ uint32_t offset3{};
+ uint8_t depth{};
+ uint8_t bpp{};
+ uint64_t modifier{};
+ std::vector<RefCountedFD> buffers{};
+ };
+
+ using PixmapFromBuffersResponse = Response<void>;
+
+ Future<void> PixmapFromBuffers(const PixmapFromBuffersRequest& request);
+
+ Future<void> PixmapFromBuffers(const Pixmap& pixmap = {},
+ const Window& window = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint32_t& stride0 = {},
+ const uint32_t& offset0 = {},
+ const uint32_t& stride1 = {},
+ const uint32_t& offset1 = {},
+ const uint32_t& stride2 = {},
+ const uint32_t& offset2 = {},
+ const uint32_t& stride3 = {},
+ const uint32_t& offset3 = {},
+ const uint8_t& depth = {},
+ const uint8_t& bpp = {},
+ const uint64_t& modifier = {},
+ const std::vector<RefCountedFD>& buffers = {});
+
+ struct BuffersFromPixmapRequest {
+ Pixmap pixmap{};
+ };
+
+ struct BuffersFromPixmapReply {
+ uint16_t sequence{};
+ uint16_t width{};
+ uint16_t height{};
+ uint64_t modifier{};
+ uint8_t depth{};
+ uint8_t bpp{};
+ std::vector<uint32_t> strides{};
+ std::vector<uint32_t> offsets{};
+ std::vector<RefCountedFD> buffers{};
+ };
+
+ using BuffersFromPixmapResponse = Response<BuffersFromPixmapReply>;
+
+ Future<BuffersFromPixmapReply> BuffersFromPixmap(
+ const BuffersFromPixmapRequest& request);
+
+ Future<BuffersFromPixmapReply> BuffersFromPixmap(const Pixmap& pixmap = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_GENERATED_PROTOS_DRI3_H_
diff --git a/chromium/ui/gfx/x/generated_protos/extension_manager.cc b/chromium/ui/gfx/x/generated_protos/extension_manager.cc
new file mode 100644
index 00000000000..5c680e815e1
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/extension_manager.cc
@@ -0,0 +1,149 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "ui/gfx/x/extension_manager.h"
+
+#include "ui/gfx/x/bigreq.h"
+#include "ui/gfx/x/composite.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/damage.h"
+#include "ui/gfx/x/dpms.h"
+#include "ui/gfx/x/dri2.h"
+#include "ui/gfx/x/dri3.h"
+#include "ui/gfx/x/ge.h"
+#include "ui/gfx/x/glx.h"
+#include "ui/gfx/x/present.h"
+#include "ui/gfx/x/randr.h"
+#include "ui/gfx/x/record.h"
+#include "ui/gfx/x/render.h"
+#include "ui/gfx/x/res.h"
+#include "ui/gfx/x/screensaver.h"
+#include "ui/gfx/x/shape.h"
+#include "ui/gfx/x/shm.h"
+#include "ui/gfx/x/sync.h"
+#include "ui/gfx/x/xc_misc.h"
+#include "ui/gfx/x/xevie.h"
+#include "ui/gfx/x/xf86dri.h"
+#include "ui/gfx/x/xf86vidmode.h"
+#include "ui/gfx/x/xfixes.h"
+#include "ui/gfx/x/xinerama.h"
+#include "ui/gfx/x/xinput.h"
+#include "ui/gfx/x/xkb.h"
+#include "ui/gfx/x/xprint.h"
+#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_internal.h"
+#include "ui/gfx/x/xselinux.h"
+#include "ui/gfx/x/xtest.h"
+#include "ui/gfx/x/xv.h"
+#include "ui/gfx/x/xvmc.h"
+
+namespace x11 {
+
+void ExtensionManager::Init(Connection* conn) {
+ auto bigreq_future = conn->QueryExtension("BIG-REQUESTS");
+ auto composite_future = conn->QueryExtension("Composite");
+ auto damage_future = conn->QueryExtension("DAMAGE");
+ auto dpms_future = conn->QueryExtension("DPMS");
+ auto dri2_future = conn->QueryExtension("DRI2");
+ auto dri3_future = conn->QueryExtension("DRI3");
+ auto ge_future = conn->QueryExtension("Generic Event Extension");
+ auto glx_future = conn->QueryExtension("GLX");
+ auto present_future = conn->QueryExtension("Present");
+ auto randr_future = conn->QueryExtension("RANDR");
+ auto record_future = conn->QueryExtension("RECORD");
+ auto render_future = conn->QueryExtension("RENDER");
+ auto res_future = conn->QueryExtension("X-Resource");
+ auto screensaver_future = conn->QueryExtension("MIT-SCREEN-SAVER");
+ auto shape_future = conn->QueryExtension("SHAPE");
+ auto shm_future = conn->QueryExtension("MIT-SHM");
+ auto sync_future = conn->QueryExtension("SYNC");
+ auto xc_misc_future = conn->QueryExtension("XC-MISC");
+ auto xevie_future = conn->QueryExtension("XEVIE");
+ auto xf86dri_future = conn->QueryExtension("XFree86-DRI");
+ auto xf86vidmode_future = conn->QueryExtension("XFree86-VidModeExtension");
+ auto xfixes_future = conn->QueryExtension("XFIXES");
+ auto xinerama_future = conn->QueryExtension("XINERAMA");
+ auto xinput_future = conn->QueryExtension("XInputExtension");
+ auto xkb_future = conn->QueryExtension("XKEYBOARD");
+ auto xprint_future = conn->QueryExtension("XpExtension");
+ auto xselinux_future = conn->QueryExtension("SELinux");
+ auto xtest_future = conn->QueryExtension("XTEST");
+ auto xv_future = conn->QueryExtension("XVideo");
+ auto xvmc_future = conn->QueryExtension("XVideo-MotionCompensation");
+ conn->Flush();
+
+ bigreq_ = MakeExtension<BigRequests>(conn, std::move(bigreq_future));
+ composite_ = MakeExtension<Composite>(conn, std::move(composite_future));
+ damage_ = MakeExtension<Damage>(conn, std::move(damage_future));
+ dpms_ = MakeExtension<Dpms>(conn, std::move(dpms_future));
+ dri2_ = MakeExtension<Dri2>(conn, std::move(dri2_future));
+ dri3_ = MakeExtension<Dri3>(conn, std::move(dri3_future));
+ ge_ = MakeExtension<GenericEvent>(conn, std::move(ge_future));
+ glx_ = MakeExtension<Glx>(conn, std::move(glx_future));
+ present_ = MakeExtension<Present>(conn, std::move(present_future));
+ randr_ = MakeExtension<RandR>(conn, std::move(randr_future));
+ record_ = MakeExtension<Record>(conn, std::move(record_future));
+ render_ = MakeExtension<Render>(conn, std::move(render_future));
+ res_ = MakeExtension<Res>(conn, std::move(res_future));
+ screensaver_ =
+ MakeExtension<ScreenSaver>(conn, std::move(screensaver_future));
+ shape_ = MakeExtension<Shape>(conn, std::move(shape_future));
+ shm_ = MakeExtension<Shm>(conn, std::move(shm_future));
+ sync_ = MakeExtension<Sync>(conn, std::move(sync_future));
+ xc_misc_ = MakeExtension<XCMisc>(conn, std::move(xc_misc_future));
+ xevie_ = MakeExtension<Xevie>(conn, std::move(xevie_future));
+ xf86dri_ = MakeExtension<XF86Dri>(conn, std::move(xf86dri_future));
+ xf86vidmode_ =
+ MakeExtension<XF86VidMode>(conn, std::move(xf86vidmode_future));
+ xfixes_ = MakeExtension<XFixes>(conn, std::move(xfixes_future));
+ xinerama_ = MakeExtension<Xinerama>(conn, std::move(xinerama_future));
+ xinput_ = MakeExtension<Input>(conn, std::move(xinput_future));
+ xkb_ = MakeExtension<Xkb>(conn, std::move(xkb_future));
+ xprint_ = MakeExtension<XPrint>(conn, std::move(xprint_future));
+ xselinux_ = MakeExtension<SELinux>(conn, std::move(xselinux_future));
+ xtest_ = MakeExtension<Test>(conn, std::move(xtest_future));
+ xv_ = MakeExtension<Xv>(conn, std::move(xv_future));
+ xvmc_ = MakeExtension<XvMC>(conn, std::move(xvmc_future));
+}
+
+ExtensionManager::ExtensionManager() = default;
+ExtensionManager::~ExtensionManager() = default;
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/extension_manager.h b/chromium/ui/gfx/x/generated_protos/extension_manager.h
new file mode 100644
index 00000000000..625301a8bd2
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/extension_manager.h
@@ -0,0 +1,158 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_EXTENSION_MANAGER_H_
+#define UI_GFX_X_GENERATED_PROTOS_EXTENSION_MANAGER_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+
+namespace x11 {
+
+class Connection;
+
+class BigRequests;
+class Composite;
+class Damage;
+class Dpms;
+class Dri2;
+class Dri3;
+class GenericEvent;
+class Glx;
+class Present;
+class RandR;
+class Record;
+class Render;
+class Res;
+class ScreenSaver;
+class Shape;
+class Shm;
+class Sync;
+class XCMisc;
+class Xevie;
+class XF86Dri;
+class XF86VidMode;
+class XFixes;
+class Xinerama;
+class Input;
+class Xkb;
+class XPrint;
+class XProto;
+class SELinux;
+class Test;
+class Xv;
+class XvMC;
+
+class COMPONENT_EXPORT(X11) ExtensionManager {
+ public:
+ ExtensionManager();
+ ~ExtensionManager();
+
+ BigRequests& bigreq() { return *bigreq_; }
+ Composite& composite() { return *composite_; }
+ Damage& damage() { return *damage_; }
+ Dpms& dpms() { return *dpms_; }
+ Dri2& dri2() { return *dri2_; }
+ Dri3& dri3() { return *dri3_; }
+ GenericEvent& ge() { return *ge_; }
+ Glx& glx() { return *glx_; }
+ Present& present() { return *present_; }
+ RandR& randr() { return *randr_; }
+ Record& record() { return *record_; }
+ Render& render() { return *render_; }
+ Res& res() { return *res_; }
+ ScreenSaver& screensaver() { return *screensaver_; }
+ Shape& shape() { return *shape_; }
+ Shm& shm() { return *shm_; }
+ Sync& sync() { return *sync_; }
+ XCMisc& xc_misc() { return *xc_misc_; }
+ Xevie& xevie() { return *xevie_; }
+ XF86Dri& xf86dri() { return *xf86dri_; }
+ XF86VidMode& xf86vidmode() { return *xf86vidmode_; }
+ XFixes& xfixes() { return *xfixes_; }
+ Xinerama& xinerama() { return *xinerama_; }
+ Input& xinput() { return *xinput_; }
+ Xkb& xkb() { return *xkb_; }
+ XPrint& xprint() { return *xprint_; }
+ SELinux& xselinux() { return *xselinux_; }
+ Test& xtest() { return *xtest_; }
+ Xv& xv() { return *xv_; }
+ XvMC& xvmc() { return *xvmc_; }
+
+ protected:
+ void Init(Connection* conn);
+
+ private:
+ std::unique_ptr<BigRequests> bigreq_;
+ std::unique_ptr<Composite> composite_;
+ std::unique_ptr<Damage> damage_;
+ std::unique_ptr<Dpms> dpms_;
+ std::unique_ptr<Dri2> dri2_;
+ std::unique_ptr<Dri3> dri3_;
+ std::unique_ptr<GenericEvent> ge_;
+ std::unique_ptr<Glx> glx_;
+ std::unique_ptr<Present> present_;
+ std::unique_ptr<RandR> randr_;
+ std::unique_ptr<Record> record_;
+ std::unique_ptr<Render> render_;
+ std::unique_ptr<Res> res_;
+ std::unique_ptr<ScreenSaver> screensaver_;
+ std::unique_ptr<Shape> shape_;
+ std::unique_ptr<Shm> shm_;
+ std::unique_ptr<Sync> sync_;
+ std::unique_ptr<XCMisc> xc_misc_;
+ std::unique_ptr<Xevie> xevie_;
+ std::unique_ptr<XF86Dri> xf86dri_;
+ std::unique_ptr<XF86VidMode> xf86vidmode_;
+ std::unique_ptr<XFixes> xfixes_;
+ std::unique_ptr<Xinerama> xinerama_;
+ std::unique_ptr<Input> xinput_;
+ std::unique_ptr<Xkb> xkb_;
+ std::unique_ptr<XPrint> xprint_;
+ std::unique_ptr<SELinux> xselinux_;
+ std::unique_ptr<Test> xtest_;
+ std::unique_ptr<Xv> xv_;
+ std::unique_ptr<XvMC> xvmc_;
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_GENERATED_PROTOS_EXTENSION_MANAGER_H_
diff --git a/chromium/ui/gfx/x/generated_protos/ge.cc b/chromium/ui/gfx/x/generated_protos/ge.cc
new file mode 100644
index 00000000000..8afc628b363
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/ge.cc
@@ -0,0 +1,137 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "ge.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+GenericEvent::GenericEvent(Connection* connection,
+ const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<GenericEvent::QueryVersionReply> GenericEvent::QueryVersion(
+ const GenericEvent::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client_major_version = request.client_major_version;
+ auto& client_minor_version = request.client_minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client_major_version
+ buf.Write(&client_major_version);
+
+ // client_minor_version
+ buf.Write(&client_minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GenericEvent::QueryVersionReply>(
+ &buf, "GenericEvent::QueryVersion", false);
+}
+
+Future<GenericEvent::QueryVersionReply> GenericEvent::QueryVersion(
+ const uint16_t& client_major_version,
+ const uint16_t& client_minor_version) {
+ return GenericEvent::QueryVersion(GenericEvent::QueryVersionRequest{
+ client_major_version, client_minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GenericEvent::QueryVersionReply> detail::ReadReply<
+ GenericEvent::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GenericEvent::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/ge.h b/chromium/ui/gfx/x/generated_protos/ge.h
new file mode 100644
index 00000000000..1a690c9c95a
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/ge.h
@@ -0,0 +1,109 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_GE_H_
+#define UI_GFX_X_GENERATED_PROTOS_GE_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) GenericEvent {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 0;
+
+ GenericEvent(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ struct QueryVersionRequest {
+ uint16_t client_major_version{};
+ uint16_t client_minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint16_t major_version{};
+ uint16_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(
+ const uint16_t& client_major_version = {},
+ const uint16_t& client_minor_version = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_GENERATED_PROTOS_GE_H_
diff --git a/chromium/ui/gfx/x/generated_protos/glx.cc b/chromium/ui/gfx/x/generated_protos/glx.cc
new file mode 100644
index 00000000000..3ae9c18c0bf
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/glx.cc
@@ -0,0 +1,8598 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "glx.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Glx::Glx(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+std::string Glx::GenericError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::GenericError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::GenericError>(Glx::GenericError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadContextError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadContextError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadContextError>(Glx::BadContextError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadContextStateError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadContextStateError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadContextStateError>(Glx::BadContextStateError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadDrawableError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadDrawableError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadDrawableError>(Glx::BadDrawableError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadPixmapError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadPixmapError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadPixmapError>(Glx::BadPixmapError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadContextTagError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadContextTagError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadContextTagError>(Glx::BadContextTagError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadCurrentWindowError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadCurrentWindowError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadCurrentWindowError>(Glx::BadCurrentWindowError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadRenderRequestError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadRenderRequestError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadRenderRequestError>(Glx::BadRenderRequestError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadLargeRequestError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadLargeRequestError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadLargeRequestError>(Glx::BadLargeRequestError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::UnsupportedPrivateRequestError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::UnsupportedPrivateRequestError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::UnsupportedPrivateRequestError>(
+ Glx::UnsupportedPrivateRequestError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadFBConfigError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadFBConfigError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadFBConfigError>(Glx::BadFBConfigError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadPbufferError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadPbufferError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadPbufferError>(Glx::BadPbufferError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadCurrentDrawableError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadCurrentDrawableError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadCurrentDrawableError>(
+ Glx::BadCurrentDrawableError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::BadWindowError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::BadWindowError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::BadWindowError>(Glx::BadWindowError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Glx::GLXBadProfileARBError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Glx::GLXBadProfileARBError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Glx::GLXBadProfileARBError>(Glx::GLXBadProfileARBError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Glx::PbufferClobberEvent>(Glx::PbufferClobberEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event_type = (*event_).event_type;
+ auto& draw_type = (*event_).draw_type;
+ auto& drawable = (*event_).drawable;
+ auto& b_mask = (*event_).b_mask;
+ auto& aux_buffer = (*event_).aux_buffer;
+ auto& x = (*event_).x;
+ auto& y = (*event_).y;
+ auto& width = (*event_).width;
+ auto& height = (*event_).height;
+ auto& count = (*event_).count;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // event_type
+ Read(&event_type, &buf);
+
+ // draw_type
+ Read(&draw_type, &buf);
+
+ // drawable
+ Read(&drawable, &buf);
+
+ // b_mask
+ Read(&b_mask, &buf);
+
+ // aux_buffer
+ Read(&aux_buffer, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // count
+ Read(&count, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Glx::BufferSwapCompleteEvent>(
+ Glx::BufferSwapCompleteEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event_type = (*event_).event_type;
+ auto& drawable = (*event_).drawable;
+ auto& ust_hi = (*event_).ust_hi;
+ auto& ust_lo = (*event_).ust_lo;
+ auto& msc_hi = (*event_).msc_hi;
+ auto& msc_lo = (*event_).msc_lo;
+ auto& sbc = (*event_).sbc;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // event_type
+ Read(&event_type, &buf);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // drawable
+ Read(&drawable, &buf);
+
+ // ust_hi
+ Read(&ust_hi, &buf);
+
+ // ust_lo
+ Read(&ust_lo, &buf);
+
+ // msc_hi
+ Read(&msc_hi, &buf);
+
+ // msc_lo
+ Read(&msc_lo, &buf);
+
+ // sbc
+ Read(&sbc, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+Future<void> Glx::Render(const Glx::RenderRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& data = request.data;
+ size_t data_len = data.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // data
+ DCHECK_EQ(static_cast<size_t>(data_len), data.size());
+ for (auto& data_elem : data) {
+ // data_elem
+ buf.Write(&data_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::Render", false);
+}
+
+Future<void> Glx::Render(const ContextTag& context_tag,
+ const std::vector<uint8_t>& data) {
+ return Glx::Render(Glx::RenderRequest{context_tag, data});
+}
+
+Future<void> Glx::RenderLarge(const Glx::RenderLargeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& request_num = request.request_num;
+ auto& request_total = request.request_total;
+ uint32_t data_len{};
+ auto& data = request.data;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // request_num
+ buf.Write(&request_num);
+
+ // request_total
+ buf.Write(&request_total);
+
+ // data_len
+ data_len = data.size();
+ buf.Write(&data_len);
+
+ // data
+ DCHECK_EQ(static_cast<size_t>(data_len), data.size());
+ for (auto& data_elem : data) {
+ // data_elem
+ buf.Write(&data_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::RenderLarge", false);
+}
+
+Future<void> Glx::RenderLarge(const ContextTag& context_tag,
+ const uint16_t& request_num,
+ const uint16_t& request_total,
+ const std::vector<uint8_t>& data) {
+ return Glx::RenderLarge(
+ Glx::RenderLargeRequest{context_tag, request_num, request_total, data});
+}
+
+Future<void> Glx::CreateContext(const Glx::CreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ auto& visual = request.visual;
+ auto& screen = request.screen;
+ auto& share_list = request.share_list;
+ auto& is_direct = request.is_direct;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // visual
+ buf.Write(&visual);
+
+ // screen
+ buf.Write(&screen);
+
+ // share_list
+ buf.Write(&share_list);
+
+ // is_direct
+ buf.Write(&is_direct);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::CreateContext", false);
+}
+
+Future<void> Glx::CreateContext(const Context& context,
+ const VisualId& visual,
+ const uint32_t& screen,
+ const Context& share_list,
+ const uint8_t& is_direct) {
+ return Glx::CreateContext(Glx::CreateContextRequest{context, visual, screen,
+ share_list, is_direct});
+}
+
+Future<void> Glx::DestroyContext(const Glx::DestroyContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::DestroyContext", false);
+}
+
+Future<void> Glx::DestroyContext(const Context& context) {
+ return Glx::DestroyContext(Glx::DestroyContextRequest{context});
+}
+
+Future<Glx::MakeCurrentReply> Glx::MakeCurrent(
+ const Glx::MakeCurrentRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& context = request.context;
+ auto& old_context_tag = request.old_context_tag;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // context
+ buf.Write(&context);
+
+ // old_context_tag
+ buf.Write(&old_context_tag);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::MakeCurrentReply>(
+ &buf, "Glx::MakeCurrent", false);
+}
+
+Future<Glx::MakeCurrentReply> Glx::MakeCurrent(
+ const Drawable& drawable,
+ const Context& context,
+ const ContextTag& old_context_tag) {
+ return Glx::MakeCurrent(
+ Glx::MakeCurrentRequest{drawable, context, old_context_tag});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::MakeCurrentReply> detail::ReadReply<Glx::MakeCurrentReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::MakeCurrentReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& context_tag = (*reply).context_tag;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_tag
+ Read(&context_tag, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::IsDirectReply> Glx::IsDirect(const Glx::IsDirectRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::IsDirectReply>(&buf, "Glx::IsDirect",
+ false);
+}
+
+Future<Glx::IsDirectReply> Glx::IsDirect(const Context& context) {
+ return Glx::IsDirect(Glx::IsDirectRequest{context});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::IsDirectReply> detail::ReadReply<Glx::IsDirectReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::IsDirectReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& is_direct = (*reply).is_direct;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // is_direct
+ Read(&is_direct, &buf);
+
+ // pad1
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::QueryVersionReply> Glx::QueryVersion(
+ const Glx::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major_version = request.major_version;
+ auto& minor_version = request.minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major_version
+ buf.Write(&major_version);
+
+ // minor_version
+ buf.Write(&minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::QueryVersionReply>(
+ &buf, "Glx::QueryVersion", false);
+}
+
+Future<Glx::QueryVersionReply> Glx::QueryVersion(
+ const uint32_t& major_version,
+ const uint32_t& minor_version) {
+ return Glx::QueryVersion(
+ Glx::QueryVersionRequest{major_version, minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::QueryVersionReply> detail::ReadReply<
+ Glx::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Glx::WaitGL(const Glx::WaitGLRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::WaitGL", false);
+}
+
+Future<void> Glx::WaitGL(const ContextTag& context_tag) {
+ return Glx::WaitGL(Glx::WaitGLRequest{context_tag});
+}
+
+Future<void> Glx::WaitX(const Glx::WaitXRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::WaitX", false);
+}
+
+Future<void> Glx::WaitX(const ContextTag& context_tag) {
+ return Glx::WaitX(Glx::WaitXRequest{context_tag});
+}
+
+Future<void> Glx::CopyContext(const Glx::CopyContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& src = request.src;
+ auto& dest = request.dest;
+ auto& mask = request.mask;
+ auto& src_context_tag = request.src_context_tag;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // src
+ buf.Write(&src);
+
+ // dest
+ buf.Write(&dest);
+
+ // mask
+ buf.Write(&mask);
+
+ // src_context_tag
+ buf.Write(&src_context_tag);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::CopyContext", false);
+}
+
+Future<void> Glx::CopyContext(const Context& src,
+ const Context& dest,
+ const uint32_t& mask,
+ const ContextTag& src_context_tag) {
+ return Glx::CopyContext(
+ Glx::CopyContextRequest{src, dest, mask, src_context_tag});
+}
+
+Future<void> Glx::SwapBuffers(const Glx::SwapBuffersRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::SwapBuffers", false);
+}
+
+Future<void> Glx::SwapBuffers(const ContextTag& context_tag,
+ const Drawable& drawable) {
+ return Glx::SwapBuffers(Glx::SwapBuffersRequest{context_tag, drawable});
+}
+
+Future<void> Glx::UseXFont(const Glx::UseXFontRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& font = request.font;
+ auto& first = request.first;
+ auto& count = request.count;
+ auto& list_base = request.list_base;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // font
+ buf.Write(&font);
+
+ // first
+ buf.Write(&first);
+
+ // count
+ buf.Write(&count);
+
+ // list_base
+ buf.Write(&list_base);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::UseXFont", false);
+}
+
+Future<void> Glx::UseXFont(const ContextTag& context_tag,
+ const Font& font,
+ const uint32_t& first,
+ const uint32_t& count,
+ const uint32_t& list_base) {
+ return Glx::UseXFont(
+ Glx::UseXFontRequest{context_tag, font, first, count, list_base});
+}
+
+Future<void> Glx::CreateGLXPixmap(const Glx::CreateGLXPixmapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& visual = request.visual;
+ auto& pixmap = request.pixmap;
+ auto& glx_pixmap = request.glx_pixmap;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // visual
+ buf.Write(&visual);
+
+ // pixmap
+ buf.Write(&pixmap);
+
+ // glx_pixmap
+ buf.Write(&glx_pixmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::CreateGLXPixmap", false);
+}
+
+Future<void> Glx::CreateGLXPixmap(const uint32_t& screen,
+ const VisualId& visual,
+ const x11::Pixmap& pixmap,
+ const Pixmap& glx_pixmap) {
+ return Glx::CreateGLXPixmap(
+ Glx::CreateGLXPixmapRequest{screen, visual, pixmap, glx_pixmap});
+}
+
+Future<Glx::GetVisualConfigsReply> Glx::GetVisualConfigs(
+ const Glx::GetVisualConfigsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 14;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetVisualConfigsReply>(
+ &buf, "Glx::GetVisualConfigs", false);
+}
+
+Future<Glx::GetVisualConfigsReply> Glx::GetVisualConfigs(
+ const uint32_t& screen) {
+ return Glx::GetVisualConfigs(Glx::GetVisualConfigsRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetVisualConfigsReply> detail::ReadReply<
+ Glx::GetVisualConfigsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetVisualConfigsReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& num_visuals = (*reply).num_visuals;
+ auto& num_properties = (*reply).num_properties;
+ auto& property_list = (*reply).property_list;
+ size_t property_list_len = property_list.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_visuals
+ Read(&num_visuals, &buf);
+
+ // num_properties
+ Read(&num_properties, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ // property_list
+ property_list.resize(length);
+ for (auto& property_list_elem : property_list) {
+ // property_list_elem
+ Read(&property_list_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Glx::DestroyGLXPixmap(
+ const Glx::DestroyGLXPixmapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& glx_pixmap = request.glx_pixmap;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 15;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // glx_pixmap
+ buf.Write(&glx_pixmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::DestroyGLXPixmap", false);
+}
+
+Future<void> Glx::DestroyGLXPixmap(const Pixmap& glx_pixmap) {
+ return Glx::DestroyGLXPixmap(Glx::DestroyGLXPixmapRequest{glx_pixmap});
+}
+
+Future<void> Glx::VendorPrivate(const Glx::VendorPrivateRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& vendor_code = request.vendor_code;
+ auto& context_tag = request.context_tag;
+ auto& data = request.data;
+ size_t data_len = data.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 16;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // vendor_code
+ buf.Write(&vendor_code);
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // data
+ DCHECK_EQ(static_cast<size_t>(data_len), data.size());
+ for (auto& data_elem : data) {
+ // data_elem
+ buf.Write(&data_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::VendorPrivate", false);
+}
+
+Future<void> Glx::VendorPrivate(const uint32_t& vendor_code,
+ const ContextTag& context_tag,
+ const std::vector<uint8_t>& data) {
+ return Glx::VendorPrivate(
+ Glx::VendorPrivateRequest{vendor_code, context_tag, data});
+}
+
+Future<Glx::VendorPrivateWithReplyReply> Glx::VendorPrivateWithReply(
+ const Glx::VendorPrivateWithReplyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& vendor_code = request.vendor_code;
+ auto& context_tag = request.context_tag;
+ auto& data = request.data;
+ size_t data_len = data.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 17;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // vendor_code
+ buf.Write(&vendor_code);
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // data
+ DCHECK_EQ(static_cast<size_t>(data_len), data.size());
+ for (auto& data_elem : data) {
+ // data_elem
+ buf.Write(&data_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::VendorPrivateWithReplyReply>(
+ &buf, "Glx::VendorPrivateWithReply", false);
+}
+
+Future<Glx::VendorPrivateWithReplyReply> Glx::VendorPrivateWithReply(
+ const uint32_t& vendor_code,
+ const ContextTag& context_tag,
+ const std::vector<uint8_t>& data) {
+ return Glx::VendorPrivateWithReply(
+ Glx::VendorPrivateWithReplyRequest{vendor_code, context_tag, data});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::VendorPrivateWithReplyReply> detail::ReadReply<
+ Glx::VendorPrivateWithReplyReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::VendorPrivateWithReplyReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& retval = (*reply).retval;
+ auto& data1 = (*reply).data1;
+ size_t data1_len = data1.size();
+ auto& data2 = (*reply).data2;
+ size_t data2_len = data2.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // retval
+ Read(&retval, &buf);
+
+ // data1
+ for (auto& data1_elem : data1) {
+ // data1_elem
+ Read(&data1_elem, &buf);
+ }
+
+ // data2
+ data2.resize((length) * (4));
+ for (auto& data2_elem : data2) {
+ // data2_elem
+ Read(&data2_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::QueryExtensionsStringReply> Glx::QueryExtensionsString(
+ const Glx::QueryExtensionsStringRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 18;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::QueryExtensionsStringReply>(
+ &buf, "Glx::QueryExtensionsString", false);
+}
+
+Future<Glx::QueryExtensionsStringReply> Glx::QueryExtensionsString(
+ const uint32_t& screen) {
+ return Glx::QueryExtensionsString(Glx::QueryExtensionsStringRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::QueryExtensionsStringReply> detail::ReadReply<
+ Glx::QueryExtensionsStringReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::QueryExtensionsStringReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& n = (*reply).n;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // pad2
+ Pad(&buf, 16);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::QueryServerStringReply> Glx::QueryServerString(
+ const Glx::QueryServerStringRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& name = request.name;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 19;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // name
+ buf.Write(&name);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::QueryServerStringReply>(
+ &buf, "Glx::QueryServerString", false);
+}
+
+Future<Glx::QueryServerStringReply> Glx::QueryServerString(
+ const uint32_t& screen,
+ const uint32_t& name) {
+ return Glx::QueryServerString(Glx::QueryServerStringRequest{screen, name});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::QueryServerStringReply> detail::ReadReply<
+ Glx::QueryServerStringReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::QueryServerStringReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t str_len{};
+ auto& string = (*reply).string;
+ size_t string_len = string.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // str_len
+ Read(&str_len, &buf);
+
+ // pad2
+ Pad(&buf, 16);
+
+ // string
+ string.resize(str_len);
+ for (auto& string_elem : string) {
+ // string_elem
+ Read(&string_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Glx::ClientInfo(const Glx::ClientInfoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major_version = request.major_version;
+ auto& minor_version = request.minor_version;
+ uint32_t str_len{};
+ auto& string = request.string;
+ size_t string_len = string.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 20;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major_version
+ buf.Write(&major_version);
+
+ // minor_version
+ buf.Write(&minor_version);
+
+ // str_len
+ str_len = string.size();
+ buf.Write(&str_len);
+
+ // string
+ DCHECK_EQ(static_cast<size_t>(str_len), string.size());
+ for (auto& string_elem : string) {
+ // string_elem
+ buf.Write(&string_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::ClientInfo", false);
+}
+
+Future<void> Glx::ClientInfo(const uint32_t& major_version,
+ const uint32_t& minor_version,
+ const std::string& string) {
+ return Glx::ClientInfo(
+ Glx::ClientInfoRequest{major_version, minor_version, string});
+}
+
+Future<Glx::GetFBConfigsReply> Glx::GetFBConfigs(
+ const Glx::GetFBConfigsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 21;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetFBConfigsReply>(
+ &buf, "Glx::GetFBConfigs", false);
+}
+
+Future<Glx::GetFBConfigsReply> Glx::GetFBConfigs(const uint32_t& screen) {
+ return Glx::GetFBConfigs(Glx::GetFBConfigsRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetFBConfigsReply> detail::ReadReply<
+ Glx::GetFBConfigsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetFBConfigsReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& num_FB_configs = (*reply).num_FB_configs;
+ auto& num_properties = (*reply).num_properties;
+ auto& property_list = (*reply).property_list;
+ size_t property_list_len = property_list.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_FB_configs
+ Read(&num_FB_configs, &buf);
+
+ // num_properties
+ Read(&num_properties, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ // property_list
+ property_list.resize(length);
+ for (auto& property_list_elem : property_list) {
+ // property_list_elem
+ Read(&property_list_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Glx::CreatePixmap(const Glx::CreatePixmapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& fbconfig = request.fbconfig;
+ auto& pixmap = request.pixmap;
+ auto& glx_pixmap = request.glx_pixmap;
+ auto& num_attribs = request.num_attribs;
+ auto& attribs = request.attribs;
+ size_t attribs_len = attribs.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 22;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // fbconfig
+ buf.Write(&fbconfig);
+
+ // pixmap
+ buf.Write(&pixmap);
+
+ // glx_pixmap
+ buf.Write(&glx_pixmap);
+
+ // num_attribs
+ buf.Write(&num_attribs);
+
+ // attribs
+ DCHECK_EQ(static_cast<size_t>((num_attribs) * (2)), attribs.size());
+ for (auto& attribs_elem : attribs) {
+ // attribs_elem
+ buf.Write(&attribs_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::CreatePixmap", false);
+}
+
+Future<void> Glx::CreatePixmap(const uint32_t& screen,
+ const FbConfig& fbconfig,
+ const x11::Pixmap& pixmap,
+ const Pixmap& glx_pixmap,
+ const uint32_t& num_attribs,
+ const std::vector<uint32_t>& attribs) {
+ return Glx::CreatePixmap(Glx::CreatePixmapRequest{
+ screen, fbconfig, pixmap, glx_pixmap, num_attribs, attribs});
+}
+
+Future<void> Glx::DestroyPixmap(const Glx::DestroyPixmapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& glx_pixmap = request.glx_pixmap;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 23;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // glx_pixmap
+ buf.Write(&glx_pixmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::DestroyPixmap", false);
+}
+
+Future<void> Glx::DestroyPixmap(const Pixmap& glx_pixmap) {
+ return Glx::DestroyPixmap(Glx::DestroyPixmapRequest{glx_pixmap});
+}
+
+Future<void> Glx::CreateNewContext(
+ const Glx::CreateNewContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ auto& fbconfig = request.fbconfig;
+ auto& screen = request.screen;
+ auto& render_type = request.render_type;
+ auto& share_list = request.share_list;
+ auto& is_direct = request.is_direct;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 24;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // fbconfig
+ buf.Write(&fbconfig);
+
+ // screen
+ buf.Write(&screen);
+
+ // render_type
+ buf.Write(&render_type);
+
+ // share_list
+ buf.Write(&share_list);
+
+ // is_direct
+ buf.Write(&is_direct);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::CreateNewContext", false);
+}
+
+Future<void> Glx::CreateNewContext(const Context& context,
+ const FbConfig& fbconfig,
+ const uint32_t& screen,
+ const uint32_t& render_type,
+ const Context& share_list,
+ const uint8_t& is_direct) {
+ return Glx::CreateNewContext(Glx::CreateNewContextRequest{
+ context, fbconfig, screen, render_type, share_list, is_direct});
+}
+
+Future<Glx::QueryContextReply> Glx::QueryContext(
+ const Glx::QueryContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 25;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::QueryContextReply>(
+ &buf, "Glx::QueryContext", false);
+}
+
+Future<Glx::QueryContextReply> Glx::QueryContext(const Context& context) {
+ return Glx::QueryContext(Glx::QueryContextRequest{context});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::QueryContextReply> detail::ReadReply<
+ Glx::QueryContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::QueryContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& num_attribs = (*reply).num_attribs;
+ auto& attribs = (*reply).attribs;
+ size_t attribs_len = attribs.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_attribs
+ Read(&num_attribs, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // attribs
+ attribs.resize((num_attribs) * (2));
+ for (auto& attribs_elem : attribs) {
+ // attribs_elem
+ Read(&attribs_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::MakeContextCurrentReply> Glx::MakeContextCurrent(
+ const Glx::MakeContextCurrentRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& old_context_tag = request.old_context_tag;
+ auto& drawable = request.drawable;
+ auto& read_drawable = request.read_drawable;
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 26;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // old_context_tag
+ buf.Write(&old_context_tag);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // read_drawable
+ buf.Write(&read_drawable);
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::MakeContextCurrentReply>(
+ &buf, "Glx::MakeContextCurrent", false);
+}
+
+Future<Glx::MakeContextCurrentReply> Glx::MakeContextCurrent(
+ const ContextTag& old_context_tag,
+ const Drawable& drawable,
+ const Drawable& read_drawable,
+ const Context& context) {
+ return Glx::MakeContextCurrent(Glx::MakeContextCurrentRequest{
+ old_context_tag, drawable, read_drawable, context});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::MakeContextCurrentReply> detail::ReadReply<
+ Glx::MakeContextCurrentReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::MakeContextCurrentReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& context_tag = (*reply).context_tag;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_tag
+ Read(&context_tag, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Glx::CreatePbuffer(const Glx::CreatePbufferRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& fbconfig = request.fbconfig;
+ auto& pbuffer = request.pbuffer;
+ auto& num_attribs = request.num_attribs;
+ auto& attribs = request.attribs;
+ size_t attribs_len = attribs.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 27;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // fbconfig
+ buf.Write(&fbconfig);
+
+ // pbuffer
+ buf.Write(&pbuffer);
+
+ // num_attribs
+ buf.Write(&num_attribs);
+
+ // attribs
+ DCHECK_EQ(static_cast<size_t>((num_attribs) * (2)), attribs.size());
+ for (auto& attribs_elem : attribs) {
+ // attribs_elem
+ buf.Write(&attribs_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::CreatePbuffer", false);
+}
+
+Future<void> Glx::CreatePbuffer(const uint32_t& screen,
+ const FbConfig& fbconfig,
+ const PBuffer& pbuffer,
+ const uint32_t& num_attribs,
+ const std::vector<uint32_t>& attribs) {
+ return Glx::CreatePbuffer(Glx::CreatePbufferRequest{screen, fbconfig, pbuffer,
+ num_attribs, attribs});
+}
+
+Future<void> Glx::DestroyPbuffer(const Glx::DestroyPbufferRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& pbuffer = request.pbuffer;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 28;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // pbuffer
+ buf.Write(&pbuffer);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::DestroyPbuffer", false);
+}
+
+Future<void> Glx::DestroyPbuffer(const PBuffer& pbuffer) {
+ return Glx::DestroyPbuffer(Glx::DestroyPbufferRequest{pbuffer});
+}
+
+Future<Glx::GetDrawableAttributesReply> Glx::GetDrawableAttributes(
+ const Glx::GetDrawableAttributesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 29;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetDrawableAttributesReply>(
+ &buf, "Glx::GetDrawableAttributes", false);
+}
+
+Future<Glx::GetDrawableAttributesReply> Glx::GetDrawableAttributes(
+ const Drawable& drawable) {
+ return Glx::GetDrawableAttributes(
+ Glx::GetDrawableAttributesRequest{drawable});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetDrawableAttributesReply> detail::ReadReply<
+ Glx::GetDrawableAttributesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetDrawableAttributesReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& num_attribs = (*reply).num_attribs;
+ auto& attribs = (*reply).attribs;
+ size_t attribs_len = attribs.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_attribs
+ Read(&num_attribs, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // attribs
+ attribs.resize((num_attribs) * (2));
+ for (auto& attribs_elem : attribs) {
+ // attribs_elem
+ Read(&attribs_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Glx::ChangeDrawableAttributes(
+ const Glx::ChangeDrawableAttributesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& num_attribs = request.num_attribs;
+ auto& attribs = request.attribs;
+ size_t attribs_len = attribs.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 30;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // num_attribs
+ buf.Write(&num_attribs);
+
+ // attribs
+ DCHECK_EQ(static_cast<size_t>((num_attribs) * (2)), attribs.size());
+ for (auto& attribs_elem : attribs) {
+ // attribs_elem
+ buf.Write(&attribs_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::ChangeDrawableAttributes",
+ false);
+}
+
+Future<void> Glx::ChangeDrawableAttributes(
+ const Drawable& drawable,
+ const uint32_t& num_attribs,
+ const std::vector<uint32_t>& attribs) {
+ return Glx::ChangeDrawableAttributes(
+ Glx::ChangeDrawableAttributesRequest{drawable, num_attribs, attribs});
+}
+
+Future<void> Glx::CreateWindow(const Glx::CreateWindowRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& fbconfig = request.fbconfig;
+ auto& window = request.window;
+ auto& glx_window = request.glx_window;
+ auto& num_attribs = request.num_attribs;
+ auto& attribs = request.attribs;
+ size_t attribs_len = attribs.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 31;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // fbconfig
+ buf.Write(&fbconfig);
+
+ // window
+ buf.Write(&window);
+
+ // glx_window
+ buf.Write(&glx_window);
+
+ // num_attribs
+ buf.Write(&num_attribs);
+
+ // attribs
+ DCHECK_EQ(static_cast<size_t>((num_attribs) * (2)), attribs.size());
+ for (auto& attribs_elem : attribs) {
+ // attribs_elem
+ buf.Write(&attribs_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::CreateWindow", false);
+}
+
+Future<void> Glx::CreateWindow(const uint32_t& screen,
+ const FbConfig& fbconfig,
+ const x11::Window& window,
+ const Window& glx_window,
+ const uint32_t& num_attribs,
+ const std::vector<uint32_t>& attribs) {
+ return Glx::CreateWindow(Glx::CreateWindowRequest{
+ screen, fbconfig, window, glx_window, num_attribs, attribs});
+}
+
+Future<void> Glx::DeleteWindow(const Glx::DeleteWindowRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& glxwindow = request.glxwindow;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 32;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // glxwindow
+ buf.Write(&glxwindow);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::DeleteWindow", false);
+}
+
+Future<void> Glx::DeleteWindow(const Window& glxwindow) {
+ return Glx::DeleteWindow(Glx::DeleteWindowRequest{glxwindow});
+}
+
+Future<void> Glx::SetClientInfoARB(
+ const Glx::SetClientInfoARBRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major_version = request.major_version;
+ auto& minor_version = request.minor_version;
+ auto& num_versions = request.num_versions;
+ uint32_t gl_str_len{};
+ uint32_t glx_str_len{};
+ auto& gl_versions = request.gl_versions;
+ size_t gl_versions_len = gl_versions.size();
+ auto& gl_extension_string = request.gl_extension_string;
+ size_t gl_extension_string_len = gl_extension_string.size();
+ auto& glx_extension_string = request.glx_extension_string;
+ size_t glx_extension_string_len = glx_extension_string.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 33;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major_version
+ buf.Write(&major_version);
+
+ // minor_version
+ buf.Write(&minor_version);
+
+ // num_versions
+ buf.Write(&num_versions);
+
+ // gl_str_len
+ gl_str_len = gl_extension_string.size();
+ buf.Write(&gl_str_len);
+
+ // glx_str_len
+ glx_str_len = glx_extension_string.size();
+ buf.Write(&glx_str_len);
+
+ // gl_versions
+ DCHECK_EQ(static_cast<size_t>((num_versions) * (2)), gl_versions.size());
+ for (auto& gl_versions_elem : gl_versions) {
+ // gl_versions_elem
+ buf.Write(&gl_versions_elem);
+ }
+
+ // gl_extension_string
+ DCHECK_EQ(static_cast<size_t>(gl_str_len), gl_extension_string.size());
+ for (auto& gl_extension_string_elem : gl_extension_string) {
+ // gl_extension_string_elem
+ buf.Write(&gl_extension_string_elem);
+ }
+
+ // glx_extension_string
+ DCHECK_EQ(static_cast<size_t>(glx_str_len), glx_extension_string.size());
+ for (auto& glx_extension_string_elem : glx_extension_string) {
+ // glx_extension_string_elem
+ buf.Write(&glx_extension_string_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::SetClientInfoARB", false);
+}
+
+Future<void> Glx::SetClientInfoARB(const uint32_t& major_version,
+ const uint32_t& minor_version,
+ const uint32_t& num_versions,
+ const std::vector<uint32_t>& gl_versions,
+ const std::string& gl_extension_string,
+ const std::string& glx_extension_string) {
+ return Glx::SetClientInfoARB(Glx::SetClientInfoARBRequest{
+ major_version, minor_version, num_versions, gl_versions,
+ gl_extension_string, glx_extension_string});
+}
+
+Future<void> Glx::CreateContextAttribsARB(
+ const Glx::CreateContextAttribsARBRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ auto& fbconfig = request.fbconfig;
+ auto& screen = request.screen;
+ auto& share_list = request.share_list;
+ auto& is_direct = request.is_direct;
+ auto& num_attribs = request.num_attribs;
+ auto& attribs = request.attribs;
+ size_t attribs_len = attribs.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 34;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // fbconfig
+ buf.Write(&fbconfig);
+
+ // screen
+ buf.Write(&screen);
+
+ // share_list
+ buf.Write(&share_list);
+
+ // is_direct
+ buf.Write(&is_direct);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // num_attribs
+ buf.Write(&num_attribs);
+
+ // attribs
+ DCHECK_EQ(static_cast<size_t>((num_attribs) * (2)), attribs.size());
+ for (auto& attribs_elem : attribs) {
+ // attribs_elem
+ buf.Write(&attribs_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::CreateContextAttribsARB",
+ false);
+}
+
+Future<void> Glx::CreateContextAttribsARB(
+ const Context& context,
+ const FbConfig& fbconfig,
+ const uint32_t& screen,
+ const Context& share_list,
+ const uint8_t& is_direct,
+ const uint32_t& num_attribs,
+ const std::vector<uint32_t>& attribs) {
+ return Glx::CreateContextAttribsARB(Glx::CreateContextAttribsARBRequest{
+ context, fbconfig, screen, share_list, is_direct, num_attribs, attribs});
+}
+
+Future<void> Glx::SetClientInfo2ARB(
+ const Glx::SetClientInfo2ARBRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major_version = request.major_version;
+ auto& minor_version = request.minor_version;
+ auto& num_versions = request.num_versions;
+ uint32_t gl_str_len{};
+ uint32_t glx_str_len{};
+ auto& gl_versions = request.gl_versions;
+ size_t gl_versions_len = gl_versions.size();
+ auto& gl_extension_string = request.gl_extension_string;
+ size_t gl_extension_string_len = gl_extension_string.size();
+ auto& glx_extension_string = request.glx_extension_string;
+ size_t glx_extension_string_len = glx_extension_string.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 35;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major_version
+ buf.Write(&major_version);
+
+ // minor_version
+ buf.Write(&minor_version);
+
+ // num_versions
+ buf.Write(&num_versions);
+
+ // gl_str_len
+ gl_str_len = gl_extension_string.size();
+ buf.Write(&gl_str_len);
+
+ // glx_str_len
+ glx_str_len = glx_extension_string.size();
+ buf.Write(&glx_str_len);
+
+ // gl_versions
+ DCHECK_EQ(static_cast<size_t>((num_versions) * (3)), gl_versions.size());
+ for (auto& gl_versions_elem : gl_versions) {
+ // gl_versions_elem
+ buf.Write(&gl_versions_elem);
+ }
+
+ // gl_extension_string
+ DCHECK_EQ(static_cast<size_t>(gl_str_len), gl_extension_string.size());
+ for (auto& gl_extension_string_elem : gl_extension_string) {
+ // gl_extension_string_elem
+ buf.Write(&gl_extension_string_elem);
+ }
+
+ // glx_extension_string
+ DCHECK_EQ(static_cast<size_t>(glx_str_len), glx_extension_string.size());
+ for (auto& glx_extension_string_elem : glx_extension_string) {
+ // glx_extension_string_elem
+ buf.Write(&glx_extension_string_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::SetClientInfo2ARB", false);
+}
+
+Future<void> Glx::SetClientInfo2ARB(const uint32_t& major_version,
+ const uint32_t& minor_version,
+ const uint32_t& num_versions,
+ const std::vector<uint32_t>& gl_versions,
+ const std::string& gl_extension_string,
+ const std::string& glx_extension_string) {
+ return Glx::SetClientInfo2ARB(Glx::SetClientInfo2ARBRequest{
+ major_version, minor_version, num_versions, gl_versions,
+ gl_extension_string, glx_extension_string});
+}
+
+Future<void> Glx::NewList(const Glx::NewListRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& list = request.list;
+ auto& mode = request.mode;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 101;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // list
+ buf.Write(&list);
+
+ // mode
+ buf.Write(&mode);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::NewList", false);
+}
+
+Future<void> Glx::NewList(const ContextTag& context_tag,
+ const uint32_t& list,
+ const uint32_t& mode) {
+ return Glx::NewList(Glx::NewListRequest{context_tag, list, mode});
+}
+
+Future<void> Glx::EndList(const Glx::EndListRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 102;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::EndList", false);
+}
+
+Future<void> Glx::EndList(const ContextTag& context_tag) {
+ return Glx::EndList(Glx::EndListRequest{context_tag});
+}
+
+Future<void> Glx::DeleteLists(const Glx::DeleteListsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& list = request.list;
+ auto& range = request.range;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 103;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // list
+ buf.Write(&list);
+
+ // range
+ buf.Write(&range);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::DeleteLists", false);
+}
+
+Future<void> Glx::DeleteLists(const ContextTag& context_tag,
+ const uint32_t& list,
+ const int32_t& range) {
+ return Glx::DeleteLists(Glx::DeleteListsRequest{context_tag, list, range});
+}
+
+Future<Glx::GenListsReply> Glx::GenLists(const Glx::GenListsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& range = request.range;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 104;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // range
+ buf.Write(&range);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GenListsReply>(&buf, "Glx::GenLists",
+ false);
+}
+
+Future<Glx::GenListsReply> Glx::GenLists(const ContextTag& context_tag,
+ const int32_t& range) {
+ return Glx::GenLists(Glx::GenListsRequest{context_tag, range});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GenListsReply> detail::ReadReply<Glx::GenListsReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GenListsReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& ret_val = (*reply).ret_val;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // ret_val
+ Read(&ret_val, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Glx::FeedbackBuffer(const Glx::FeedbackBufferRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& size = request.size;
+ auto& type = request.type;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 105;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // size
+ buf.Write(&size);
+
+ // type
+ buf.Write(&type);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::FeedbackBuffer", false);
+}
+
+Future<void> Glx::FeedbackBuffer(const ContextTag& context_tag,
+ const int32_t& size,
+ const int32_t& type) {
+ return Glx::FeedbackBuffer(
+ Glx::FeedbackBufferRequest{context_tag, size, type});
+}
+
+Future<void> Glx::SelectBuffer(const Glx::SelectBufferRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& size = request.size;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 106;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // size
+ buf.Write(&size);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::SelectBuffer", false);
+}
+
+Future<void> Glx::SelectBuffer(const ContextTag& context_tag,
+ const int32_t& size) {
+ return Glx::SelectBuffer(Glx::SelectBufferRequest{context_tag, size});
+}
+
+Future<Glx::RenderModeReply> Glx::RenderMode(
+ const Glx::RenderModeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& mode = request.mode;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 107;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // mode
+ buf.Write(&mode);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::RenderModeReply>(&buf, "Glx::RenderMode",
+ false);
+}
+
+Future<Glx::RenderModeReply> Glx::RenderMode(const ContextTag& context_tag,
+ const uint32_t& mode) {
+ return Glx::RenderMode(Glx::RenderModeRequest{context_tag, mode});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::RenderModeReply> detail::ReadReply<Glx::RenderModeReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::RenderModeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& ret_val = (*reply).ret_val;
+ uint32_t n{};
+ auto& new_mode = (*reply).new_mode;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // ret_val
+ Read(&ret_val, &buf);
+
+ // n
+ Read(&n, &buf);
+
+ // new_mode
+ Read(&new_mode, &buf);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::FinishReply> Glx::Finish(const Glx::FinishRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 108;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::FinishReply>(&buf, "Glx::Finish", false);
+}
+
+Future<Glx::FinishReply> Glx::Finish(const ContextTag& context_tag) {
+ return Glx::Finish(Glx::FinishRequest{context_tag});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::FinishReply> detail::ReadReply<Glx::FinishReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::FinishReply>();
+
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Glx::PixelStoref(const Glx::PixelStorefRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& pname = request.pname;
+ auto& datum = request.datum;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 109;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // pname
+ buf.Write(&pname);
+
+ // datum
+ buf.Write(&datum);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::PixelStoref", false);
+}
+
+Future<void> Glx::PixelStoref(const ContextTag& context_tag,
+ const uint32_t& pname,
+ const float& datum) {
+ return Glx::PixelStoref(Glx::PixelStorefRequest{context_tag, pname, datum});
+}
+
+Future<void> Glx::PixelStorei(const Glx::PixelStoreiRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& pname = request.pname;
+ auto& datum = request.datum;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 110;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // pname
+ buf.Write(&pname);
+
+ // datum
+ buf.Write(&datum);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::PixelStorei", false);
+}
+
+Future<void> Glx::PixelStorei(const ContextTag& context_tag,
+ const uint32_t& pname,
+ const int32_t& datum) {
+ return Glx::PixelStorei(Glx::PixelStoreiRequest{context_tag, pname, datum});
+}
+
+Future<Glx::ReadPixelsReply> Glx::ReadPixels(
+ const Glx::ReadPixelsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& x = request.x;
+ auto& y = request.y;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& format = request.format;
+ auto& type = request.type;
+ auto& swap_bytes = request.swap_bytes;
+ auto& lsb_first = request.lsb_first;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 111;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // format
+ buf.Write(&format);
+
+ // type
+ buf.Write(&type);
+
+ // swap_bytes
+ buf.Write(&swap_bytes);
+
+ // lsb_first
+ buf.Write(&lsb_first);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::ReadPixelsReply>(&buf, "Glx::ReadPixels",
+ false);
+}
+
+Future<Glx::ReadPixelsReply> Glx::ReadPixels(const ContextTag& context_tag,
+ const int32_t& x,
+ const int32_t& y,
+ const int32_t& width,
+ const int32_t& height,
+ const uint32_t& format,
+ const uint32_t& type,
+ const uint8_t& swap_bytes,
+ const uint8_t& lsb_first) {
+ return Glx::ReadPixels(Glx::ReadPixelsRequest{
+ context_tag, x, y, width, height, format, type, swap_bytes, lsb_first});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::ReadPixelsReply> detail::ReadReply<Glx::ReadPixelsReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::ReadPixelsReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 24);
+
+ // data
+ data.resize((length) * (4));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetBooleanvReply> Glx::GetBooleanv(
+ const Glx::GetBooleanvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 112;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetBooleanvReply>(
+ &buf, "Glx::GetBooleanv", false);
+}
+
+Future<Glx::GetBooleanvReply> Glx::GetBooleanv(const ContextTag& context_tag,
+ const int32_t& pname) {
+ return Glx::GetBooleanv(Glx::GetBooleanvRequest{context_tag, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetBooleanvReply> detail::ReadReply<Glx::GetBooleanvReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetBooleanvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 15);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetClipPlaneReply> Glx::GetClipPlane(
+ const Glx::GetClipPlaneRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& plane = request.plane;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 113;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // plane
+ buf.Write(&plane);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetClipPlaneReply>(
+ &buf, "Glx::GetClipPlane", false);
+}
+
+Future<Glx::GetClipPlaneReply> Glx::GetClipPlane(const ContextTag& context_tag,
+ const int32_t& plane) {
+ return Glx::GetClipPlane(Glx::GetClipPlaneRequest{context_tag, plane});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetClipPlaneReply> detail::ReadReply<
+ Glx::GetClipPlaneReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetClipPlaneReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 24);
+
+ // data
+ data.resize((length) / (2));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetDoublevReply> Glx::GetDoublev(
+ const Glx::GetDoublevRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 114;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetDoublevReply>(&buf, "Glx::GetDoublev",
+ false);
+}
+
+Future<Glx::GetDoublevReply> Glx::GetDoublev(const ContextTag& context_tag,
+ const uint32_t& pname) {
+ return Glx::GetDoublev(Glx::GetDoublevRequest{context_tag, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetDoublevReply> detail::ReadReply<Glx::GetDoublevReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetDoublevReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 8);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetErrorReply> Glx::GetError(const Glx::GetErrorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 115;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetErrorReply>(&buf, "Glx::GetError",
+ false);
+}
+
+Future<Glx::GetErrorReply> Glx::GetError(const ContextTag& context_tag) {
+ return Glx::GetError(Glx::GetErrorRequest{context_tag});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetErrorReply> detail::ReadReply<Glx::GetErrorReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetErrorReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& error = (*reply).error;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // error
+ Read(&error, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetFloatvReply> Glx::GetFloatv(
+ const Glx::GetFloatvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 116;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetFloatvReply>(&buf, "Glx::GetFloatv",
+ false);
+}
+
+Future<Glx::GetFloatvReply> Glx::GetFloatv(const ContextTag& context_tag,
+ const uint32_t& pname) {
+ return Glx::GetFloatv(Glx::GetFloatvRequest{context_tag, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetFloatvReply> detail::ReadReply<Glx::GetFloatvReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetFloatvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetIntegervReply> Glx::GetIntegerv(
+ const Glx::GetIntegervRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 117;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetIntegervReply>(
+ &buf, "Glx::GetIntegerv", false);
+}
+
+Future<Glx::GetIntegervReply> Glx::GetIntegerv(const ContextTag& context_tag,
+ const uint32_t& pname) {
+ return Glx::GetIntegerv(Glx::GetIntegervRequest{context_tag, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetIntegervReply> detail::ReadReply<Glx::GetIntegervReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetIntegervReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetLightfvReply> Glx::GetLightfv(
+ const Glx::GetLightfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& light = request.light;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 118;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // light
+ buf.Write(&light);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetLightfvReply>(&buf, "Glx::GetLightfv",
+ false);
+}
+
+Future<Glx::GetLightfvReply> Glx::GetLightfv(const ContextTag& context_tag,
+ const uint32_t& light,
+ const uint32_t& pname) {
+ return Glx::GetLightfv(Glx::GetLightfvRequest{context_tag, light, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetLightfvReply> detail::ReadReply<Glx::GetLightfvReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetLightfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetLightivReply> Glx::GetLightiv(
+ const Glx::GetLightivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& light = request.light;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 119;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // light
+ buf.Write(&light);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetLightivReply>(&buf, "Glx::GetLightiv",
+ false);
+}
+
+Future<Glx::GetLightivReply> Glx::GetLightiv(const ContextTag& context_tag,
+ const uint32_t& light,
+ const uint32_t& pname) {
+ return Glx::GetLightiv(Glx::GetLightivRequest{context_tag, light, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetLightivReply> detail::ReadReply<Glx::GetLightivReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetLightivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetMapdvReply> Glx::GetMapdv(const Glx::GetMapdvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& query = request.query;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 120;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // query
+ buf.Write(&query);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetMapdvReply>(&buf, "Glx::GetMapdv",
+ false);
+}
+
+Future<Glx::GetMapdvReply> Glx::GetMapdv(const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& query) {
+ return Glx::GetMapdv(Glx::GetMapdvRequest{context_tag, target, query});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetMapdvReply> detail::ReadReply<Glx::GetMapdvReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetMapdvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 8);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetMapfvReply> Glx::GetMapfv(const Glx::GetMapfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& query = request.query;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 121;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // query
+ buf.Write(&query);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetMapfvReply>(&buf, "Glx::GetMapfv",
+ false);
+}
+
+Future<Glx::GetMapfvReply> Glx::GetMapfv(const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& query) {
+ return Glx::GetMapfv(Glx::GetMapfvRequest{context_tag, target, query});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetMapfvReply> detail::ReadReply<Glx::GetMapfvReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetMapfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetMapivReply> Glx::GetMapiv(const Glx::GetMapivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& query = request.query;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 122;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // query
+ buf.Write(&query);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetMapivReply>(&buf, "Glx::GetMapiv",
+ false);
+}
+
+Future<Glx::GetMapivReply> Glx::GetMapiv(const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& query) {
+ return Glx::GetMapiv(Glx::GetMapivRequest{context_tag, target, query});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetMapivReply> detail::ReadReply<Glx::GetMapivReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetMapivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetMaterialfvReply> Glx::GetMaterialfv(
+ const Glx::GetMaterialfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& face = request.face;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 123;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // face
+ buf.Write(&face);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetMaterialfvReply>(
+ &buf, "Glx::GetMaterialfv", false);
+}
+
+Future<Glx::GetMaterialfvReply> Glx::GetMaterialfv(
+ const ContextTag& context_tag,
+ const uint32_t& face,
+ const uint32_t& pname) {
+ return Glx::GetMaterialfv(
+ Glx::GetMaterialfvRequest{context_tag, face, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetMaterialfvReply> detail::ReadReply<
+ Glx::GetMaterialfvReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetMaterialfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetMaterialivReply> Glx::GetMaterialiv(
+ const Glx::GetMaterialivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& face = request.face;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 124;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // face
+ buf.Write(&face);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetMaterialivReply>(
+ &buf, "Glx::GetMaterialiv", false);
+}
+
+Future<Glx::GetMaterialivReply> Glx::GetMaterialiv(
+ const ContextTag& context_tag,
+ const uint32_t& face,
+ const uint32_t& pname) {
+ return Glx::GetMaterialiv(
+ Glx::GetMaterialivRequest{context_tag, face, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetMaterialivReply> detail::ReadReply<
+ Glx::GetMaterialivReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetMaterialivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetPixelMapfvReply> Glx::GetPixelMapfv(
+ const Glx::GetPixelMapfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& map = request.map;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 125;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // map
+ buf.Write(&map);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetPixelMapfvReply>(
+ &buf, "Glx::GetPixelMapfv", false);
+}
+
+Future<Glx::GetPixelMapfvReply> Glx::GetPixelMapfv(
+ const ContextTag& context_tag,
+ const uint32_t& map) {
+ return Glx::GetPixelMapfv(Glx::GetPixelMapfvRequest{context_tag, map});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetPixelMapfvReply> detail::ReadReply<
+ Glx::GetPixelMapfvReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetPixelMapfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetPixelMapuivReply> Glx::GetPixelMapuiv(
+ const Glx::GetPixelMapuivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& map = request.map;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 126;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // map
+ buf.Write(&map);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetPixelMapuivReply>(
+ &buf, "Glx::GetPixelMapuiv", false);
+}
+
+Future<Glx::GetPixelMapuivReply> Glx::GetPixelMapuiv(
+ const ContextTag& context_tag,
+ const uint32_t& map) {
+ return Glx::GetPixelMapuiv(Glx::GetPixelMapuivRequest{context_tag, map});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetPixelMapuivReply> detail::ReadReply<
+ Glx::GetPixelMapuivReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetPixelMapuivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetPixelMapusvReply> Glx::GetPixelMapusv(
+ const Glx::GetPixelMapusvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& map = request.map;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 127;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // map
+ buf.Write(&map);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetPixelMapusvReply>(
+ &buf, "Glx::GetPixelMapusv", false);
+}
+
+Future<Glx::GetPixelMapusvReply> Glx::GetPixelMapusv(
+ const ContextTag& context_tag,
+ const uint32_t& map) {
+ return Glx::GetPixelMapusv(Glx::GetPixelMapusvRequest{context_tag, map});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetPixelMapusvReply> detail::ReadReply<
+ Glx::GetPixelMapusvReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetPixelMapusvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 16);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetPolygonStippleReply> Glx::GetPolygonStipple(
+ const Glx::GetPolygonStippleRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& lsb_first = request.lsb_first;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 128;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // lsb_first
+ buf.Write(&lsb_first);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetPolygonStippleReply>(
+ &buf, "Glx::GetPolygonStipple", false);
+}
+
+Future<Glx::GetPolygonStippleReply> Glx::GetPolygonStipple(
+ const ContextTag& context_tag,
+ const uint8_t& lsb_first) {
+ return Glx::GetPolygonStipple(
+ Glx::GetPolygonStippleRequest{context_tag, lsb_first});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetPolygonStippleReply> detail::ReadReply<
+ Glx::GetPolygonStippleReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetPolygonStippleReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 24);
+
+ // data
+ data.resize((length) * (4));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetStringReply> Glx::GetString(
+ const Glx::GetStringRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& name = request.name;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 129;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // name
+ buf.Write(&name);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetStringReply>(&buf, "Glx::GetString",
+ false);
+}
+
+Future<Glx::GetStringReply> Glx::GetString(const ContextTag& context_tag,
+ const uint32_t& name) {
+ return Glx::GetString(Glx::GetStringRequest{context_tag, name});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetStringReply> detail::ReadReply<Glx::GetStringReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetStringReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& string = (*reply).string;
+ size_t string_len = string.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // pad2
+ Pad(&buf, 16);
+
+ // string
+ string.resize(n);
+ for (auto& string_elem : string) {
+ // string_elem
+ Read(&string_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetTexEnvfvReply> Glx::GetTexEnvfv(
+ const Glx::GetTexEnvfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 130;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetTexEnvfvReply>(
+ &buf, "Glx::GetTexEnvfv", false);
+}
+
+Future<Glx::GetTexEnvfvReply> Glx::GetTexEnvfv(const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetTexEnvfv(Glx::GetTexEnvfvRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetTexEnvfvReply> detail::ReadReply<Glx::GetTexEnvfvReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetTexEnvfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetTexEnvivReply> Glx::GetTexEnviv(
+ const Glx::GetTexEnvivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 131;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetTexEnvivReply>(
+ &buf, "Glx::GetTexEnviv", false);
+}
+
+Future<Glx::GetTexEnvivReply> Glx::GetTexEnviv(const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetTexEnviv(Glx::GetTexEnvivRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetTexEnvivReply> detail::ReadReply<Glx::GetTexEnvivReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetTexEnvivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetTexGendvReply> Glx::GetTexGendv(
+ const Glx::GetTexGendvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& coord = request.coord;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 132;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // coord
+ buf.Write(&coord);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetTexGendvReply>(
+ &buf, "Glx::GetTexGendv", false);
+}
+
+Future<Glx::GetTexGendvReply> Glx::GetTexGendv(const ContextTag& context_tag,
+ const uint32_t& coord,
+ const uint32_t& pname) {
+ return Glx::GetTexGendv(Glx::GetTexGendvRequest{context_tag, coord, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetTexGendvReply> detail::ReadReply<Glx::GetTexGendvReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetTexGendvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 8);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetTexGenfvReply> Glx::GetTexGenfv(
+ const Glx::GetTexGenfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& coord = request.coord;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 133;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // coord
+ buf.Write(&coord);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetTexGenfvReply>(
+ &buf, "Glx::GetTexGenfv", false);
+}
+
+Future<Glx::GetTexGenfvReply> Glx::GetTexGenfv(const ContextTag& context_tag,
+ const uint32_t& coord,
+ const uint32_t& pname) {
+ return Glx::GetTexGenfv(Glx::GetTexGenfvRequest{context_tag, coord, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetTexGenfvReply> detail::ReadReply<Glx::GetTexGenfvReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetTexGenfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetTexGenivReply> Glx::GetTexGeniv(
+ const Glx::GetTexGenivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& coord = request.coord;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 134;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // coord
+ buf.Write(&coord);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetTexGenivReply>(
+ &buf, "Glx::GetTexGeniv", false);
+}
+
+Future<Glx::GetTexGenivReply> Glx::GetTexGeniv(const ContextTag& context_tag,
+ const uint32_t& coord,
+ const uint32_t& pname) {
+ return Glx::GetTexGeniv(Glx::GetTexGenivRequest{context_tag, coord, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetTexGenivReply> detail::ReadReply<Glx::GetTexGenivReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetTexGenivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetTexImageReply> Glx::GetTexImage(
+ const Glx::GetTexImageRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& level = request.level;
+ auto& format = request.format;
+ auto& type = request.type;
+ auto& swap_bytes = request.swap_bytes;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 135;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // level
+ buf.Write(&level);
+
+ // format
+ buf.Write(&format);
+
+ // type
+ buf.Write(&type);
+
+ // swap_bytes
+ buf.Write(&swap_bytes);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetTexImageReply>(
+ &buf, "Glx::GetTexImage", false);
+}
+
+Future<Glx::GetTexImageReply> Glx::GetTexImage(const ContextTag& context_tag,
+ const uint32_t& target,
+ const int32_t& level,
+ const uint32_t& format,
+ const uint32_t& type,
+ const uint8_t& swap_bytes) {
+ return Glx::GetTexImage(Glx::GetTexImageRequest{context_tag, target, level,
+ format, type, swap_bytes});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetTexImageReply> detail::ReadReply<Glx::GetTexImageReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetTexImageReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& depth = (*reply).depth;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // depth
+ Read(&depth, &buf);
+
+ // pad2
+ Pad(&buf, 4);
+
+ // data
+ data.resize((length) * (4));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetTexParameterfvReply> Glx::GetTexParameterfv(
+ const Glx::GetTexParameterfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 136;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetTexParameterfvReply>(
+ &buf, "Glx::GetTexParameterfv", false);
+}
+
+Future<Glx::GetTexParameterfvReply> Glx::GetTexParameterfv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetTexParameterfv(
+ Glx::GetTexParameterfvRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetTexParameterfvReply> detail::ReadReply<
+ Glx::GetTexParameterfvReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetTexParameterfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetTexParameterivReply> Glx::GetTexParameteriv(
+ const Glx::GetTexParameterivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 137;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetTexParameterivReply>(
+ &buf, "Glx::GetTexParameteriv", false);
+}
+
+Future<Glx::GetTexParameterivReply> Glx::GetTexParameteriv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetTexParameteriv(
+ Glx::GetTexParameterivRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetTexParameterivReply> detail::ReadReply<
+ Glx::GetTexParameterivReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetTexParameterivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetTexLevelParameterfvReply> Glx::GetTexLevelParameterfv(
+ const Glx::GetTexLevelParameterfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& level = request.level;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 138;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // level
+ buf.Write(&level);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetTexLevelParameterfvReply>(
+ &buf, "Glx::GetTexLevelParameterfv", false);
+}
+
+Future<Glx::GetTexLevelParameterfvReply> Glx::GetTexLevelParameterfv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const int32_t& level,
+ const uint32_t& pname) {
+ return Glx::GetTexLevelParameterfv(
+ Glx::GetTexLevelParameterfvRequest{context_tag, target, level, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetTexLevelParameterfvReply> detail::ReadReply<
+ Glx::GetTexLevelParameterfvReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetTexLevelParameterfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetTexLevelParameterivReply> Glx::GetTexLevelParameteriv(
+ const Glx::GetTexLevelParameterivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& level = request.level;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 139;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // level
+ buf.Write(&level);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetTexLevelParameterivReply>(
+ &buf, "Glx::GetTexLevelParameteriv", false);
+}
+
+Future<Glx::GetTexLevelParameterivReply> Glx::GetTexLevelParameteriv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const int32_t& level,
+ const uint32_t& pname) {
+ return Glx::GetTexLevelParameteriv(
+ Glx::GetTexLevelParameterivRequest{context_tag, target, level, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetTexLevelParameterivReply> detail::ReadReply<
+ Glx::GetTexLevelParameterivReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetTexLevelParameterivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::IsEnabledReply> Glx::IsEnabled(
+ const Glx::IsEnabledRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& capability = request.capability;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 140;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // capability
+ buf.Write(&capability);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::IsEnabledReply>(&buf, "Glx::IsEnabled",
+ false);
+}
+
+Future<Glx::IsEnabledReply> Glx::IsEnabled(const ContextTag& context_tag,
+ const uint32_t& capability) {
+ return Glx::IsEnabled(Glx::IsEnabledRequest{context_tag, capability});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::IsEnabledReply> detail::ReadReply<Glx::IsEnabledReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::IsEnabledReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& ret_val = (*reply).ret_val;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // ret_val
+ Read(&ret_val, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::IsListReply> Glx::IsList(const Glx::IsListRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& list = request.list;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 141;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // list
+ buf.Write(&list);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::IsListReply>(&buf, "Glx::IsList", false);
+}
+
+Future<Glx::IsListReply> Glx::IsList(const ContextTag& context_tag,
+ const uint32_t& list) {
+ return Glx::IsList(Glx::IsListRequest{context_tag, list});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::IsListReply> detail::ReadReply<Glx::IsListReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::IsListReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& ret_val = (*reply).ret_val;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // ret_val
+ Read(&ret_val, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Glx::Flush(const Glx::FlushRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 142;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::Flush", false);
+}
+
+Future<void> Glx::Flush(const ContextTag& context_tag) {
+ return Glx::Flush(Glx::FlushRequest{context_tag});
+}
+
+Future<Glx::AreTexturesResidentReply> Glx::AreTexturesResident(
+ const Glx::AreTexturesResidentRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ int32_t n{};
+ auto& textures = request.textures;
+ size_t textures_len = textures.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 143;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // n
+ n = textures.size();
+ buf.Write(&n);
+
+ // textures
+ DCHECK_EQ(static_cast<size_t>(n), textures.size());
+ for (auto& textures_elem : textures) {
+ // textures_elem
+ buf.Write(&textures_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::AreTexturesResidentReply>(
+ &buf, "Glx::AreTexturesResident", false);
+}
+
+Future<Glx::AreTexturesResidentReply> Glx::AreTexturesResident(
+ const ContextTag& context_tag,
+ const std::vector<uint32_t>& textures) {
+ return Glx::AreTexturesResident(
+ Glx::AreTexturesResidentRequest{context_tag, textures});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::AreTexturesResidentReply> detail::ReadReply<
+ Glx::AreTexturesResidentReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::AreTexturesResidentReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& ret_val = (*reply).ret_val;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // ret_val
+ Read(&ret_val, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // data
+ data.resize((length) * (4));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Glx::DeleteTextures(const Glx::DeleteTexturesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ int32_t n{};
+ auto& textures = request.textures;
+ size_t textures_len = textures.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 144;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // n
+ n = textures.size();
+ buf.Write(&n);
+
+ // textures
+ DCHECK_EQ(static_cast<size_t>(n), textures.size());
+ for (auto& textures_elem : textures) {
+ // textures_elem
+ buf.Write(&textures_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::DeleteTextures", false);
+}
+
+Future<void> Glx::DeleteTextures(const ContextTag& context_tag,
+ const std::vector<uint32_t>& textures) {
+ return Glx::DeleteTextures(Glx::DeleteTexturesRequest{context_tag, textures});
+}
+
+Future<Glx::GenTexturesReply> Glx::GenTextures(
+ const Glx::GenTexturesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& n = request.n;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 145;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // n
+ buf.Write(&n);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GenTexturesReply>(
+ &buf, "Glx::GenTextures", false);
+}
+
+Future<Glx::GenTexturesReply> Glx::GenTextures(const ContextTag& context_tag,
+ const int32_t& n) {
+ return Glx::GenTextures(Glx::GenTexturesRequest{context_tag, n});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GenTexturesReply> detail::ReadReply<Glx::GenTexturesReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GenTexturesReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 24);
+
+ // data
+ data.resize(length);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::IsTextureReply> Glx::IsTexture(
+ const Glx::IsTextureRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& texture = request.texture;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 146;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // texture
+ buf.Write(&texture);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::IsTextureReply>(&buf, "Glx::IsTexture",
+ false);
+}
+
+Future<Glx::IsTextureReply> Glx::IsTexture(const ContextTag& context_tag,
+ const uint32_t& texture) {
+ return Glx::IsTexture(Glx::IsTextureRequest{context_tag, texture});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::IsTextureReply> detail::ReadReply<Glx::IsTextureReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::IsTextureReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& ret_val = (*reply).ret_val;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // ret_val
+ Read(&ret_val, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetColorTableReply> Glx::GetColorTable(
+ const Glx::GetColorTableRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& format = request.format;
+ auto& type = request.type;
+ auto& swap_bytes = request.swap_bytes;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 147;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // format
+ buf.Write(&format);
+
+ // type
+ buf.Write(&type);
+
+ // swap_bytes
+ buf.Write(&swap_bytes);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetColorTableReply>(
+ &buf, "Glx::GetColorTable", false);
+}
+
+Future<Glx::GetColorTableReply> Glx::GetColorTable(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& format,
+ const uint32_t& type,
+ const uint8_t& swap_bytes) {
+ return Glx::GetColorTable(
+ Glx::GetColorTableRequest{context_tag, target, format, type, swap_bytes});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetColorTableReply> detail::ReadReply<
+ Glx::GetColorTableReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetColorTableReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& width = (*reply).width;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // width
+ Read(&width, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize((length) * (4));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetColorTableParameterfvReply> Glx::GetColorTableParameterfv(
+ const Glx::GetColorTableParameterfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 148;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetColorTableParameterfvReply>(
+ &buf, "Glx::GetColorTableParameterfv", false);
+}
+
+Future<Glx::GetColorTableParameterfvReply> Glx::GetColorTableParameterfv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetColorTableParameterfv(
+ Glx::GetColorTableParameterfvRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetColorTableParameterfvReply> detail::ReadReply<
+ Glx::GetColorTableParameterfvReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetColorTableParameterfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetColorTableParameterivReply> Glx::GetColorTableParameteriv(
+ const Glx::GetColorTableParameterivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 149;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetColorTableParameterivReply>(
+ &buf, "Glx::GetColorTableParameteriv", false);
+}
+
+Future<Glx::GetColorTableParameterivReply> Glx::GetColorTableParameteriv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetColorTableParameteriv(
+ Glx::GetColorTableParameterivRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetColorTableParameterivReply> detail::ReadReply<
+ Glx::GetColorTableParameterivReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetColorTableParameterivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetConvolutionFilterReply> Glx::GetConvolutionFilter(
+ const Glx::GetConvolutionFilterRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& format = request.format;
+ auto& type = request.type;
+ auto& swap_bytes = request.swap_bytes;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 150;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // format
+ buf.Write(&format);
+
+ // type
+ buf.Write(&type);
+
+ // swap_bytes
+ buf.Write(&swap_bytes);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetConvolutionFilterReply>(
+ &buf, "Glx::GetConvolutionFilter", false);
+}
+
+Future<Glx::GetConvolutionFilterReply> Glx::GetConvolutionFilter(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& format,
+ const uint32_t& type,
+ const uint8_t& swap_bytes) {
+ return Glx::GetConvolutionFilter(Glx::GetConvolutionFilterRequest{
+ context_tag, target, format, type, swap_bytes});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetConvolutionFilterReply> detail::ReadReply<
+ Glx::GetConvolutionFilterReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetConvolutionFilterReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // pad2
+ Pad(&buf, 8);
+
+ // data
+ data.resize((length) * (4));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetConvolutionParameterfvReply> Glx::GetConvolutionParameterfv(
+ const Glx::GetConvolutionParameterfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 151;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetConvolutionParameterfvReply>(
+ &buf, "Glx::GetConvolutionParameterfv", false);
+}
+
+Future<Glx::GetConvolutionParameterfvReply> Glx::GetConvolutionParameterfv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetConvolutionParameterfv(
+ Glx::GetConvolutionParameterfvRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetConvolutionParameterfvReply> detail::ReadReply<
+ Glx::GetConvolutionParameterfvReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetConvolutionParameterfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetConvolutionParameterivReply> Glx::GetConvolutionParameteriv(
+ const Glx::GetConvolutionParameterivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 152;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetConvolutionParameterivReply>(
+ &buf, "Glx::GetConvolutionParameteriv", false);
+}
+
+Future<Glx::GetConvolutionParameterivReply> Glx::GetConvolutionParameteriv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetConvolutionParameteriv(
+ Glx::GetConvolutionParameterivRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetConvolutionParameterivReply> detail::ReadReply<
+ Glx::GetConvolutionParameterivReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetConvolutionParameterivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetSeparableFilterReply> Glx::GetSeparableFilter(
+ const Glx::GetSeparableFilterRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& format = request.format;
+ auto& type = request.type;
+ auto& swap_bytes = request.swap_bytes;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 153;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // format
+ buf.Write(&format);
+
+ // type
+ buf.Write(&type);
+
+ // swap_bytes
+ buf.Write(&swap_bytes);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetSeparableFilterReply>(
+ &buf, "Glx::GetSeparableFilter", false);
+}
+
+Future<Glx::GetSeparableFilterReply> Glx::GetSeparableFilter(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& format,
+ const uint32_t& type,
+ const uint8_t& swap_bytes) {
+ return Glx::GetSeparableFilter(Glx::GetSeparableFilterRequest{
+ context_tag, target, format, type, swap_bytes});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetSeparableFilterReply> detail::ReadReply<
+ Glx::GetSeparableFilterReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetSeparableFilterReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& row_w = (*reply).row_w;
+ auto& col_h = (*reply).col_h;
+ auto& rows_and_cols = (*reply).rows_and_cols;
+ size_t rows_and_cols_len = rows_and_cols.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // row_w
+ Read(&row_w, &buf);
+
+ // col_h
+ Read(&col_h, &buf);
+
+ // pad2
+ Pad(&buf, 8);
+
+ // rows_and_cols
+ rows_and_cols.resize((length) * (4));
+ for (auto& rows_and_cols_elem : rows_and_cols) {
+ // rows_and_cols_elem
+ Read(&rows_and_cols_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetHistogramReply> Glx::GetHistogram(
+ const Glx::GetHistogramRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& format = request.format;
+ auto& type = request.type;
+ auto& swap_bytes = request.swap_bytes;
+ auto& reset = request.reset;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 154;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // format
+ buf.Write(&format);
+
+ // type
+ buf.Write(&type);
+
+ // swap_bytes
+ buf.Write(&swap_bytes);
+
+ // reset
+ buf.Write(&reset);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetHistogramReply>(
+ &buf, "Glx::GetHistogram", false);
+}
+
+Future<Glx::GetHistogramReply> Glx::GetHistogram(const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& format,
+ const uint32_t& type,
+ const uint8_t& swap_bytes,
+ const uint8_t& reset) {
+ return Glx::GetHistogram(Glx::GetHistogramRequest{context_tag, target, format,
+ type, swap_bytes, reset});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetHistogramReply> detail::ReadReply<
+ Glx::GetHistogramReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetHistogramReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& width = (*reply).width;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // width
+ Read(&width, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize((length) * (4));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetHistogramParameterfvReply> Glx::GetHistogramParameterfv(
+ const Glx::GetHistogramParameterfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 155;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetHistogramParameterfvReply>(
+ &buf, "Glx::GetHistogramParameterfv", false);
+}
+
+Future<Glx::GetHistogramParameterfvReply> Glx::GetHistogramParameterfv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetHistogramParameterfv(
+ Glx::GetHistogramParameterfvRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetHistogramParameterfvReply> detail::ReadReply<
+ Glx::GetHistogramParameterfvReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetHistogramParameterfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetHistogramParameterivReply> Glx::GetHistogramParameteriv(
+ const Glx::GetHistogramParameterivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 156;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetHistogramParameterivReply>(
+ &buf, "Glx::GetHistogramParameteriv", false);
+}
+
+Future<Glx::GetHistogramParameterivReply> Glx::GetHistogramParameteriv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetHistogramParameteriv(
+ Glx::GetHistogramParameterivRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetHistogramParameterivReply> detail::ReadReply<
+ Glx::GetHistogramParameterivReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetHistogramParameterivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetMinmaxReply> Glx::GetMinmax(
+ const Glx::GetMinmaxRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& format = request.format;
+ auto& type = request.type;
+ auto& swap_bytes = request.swap_bytes;
+ auto& reset = request.reset;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 157;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // format
+ buf.Write(&format);
+
+ // type
+ buf.Write(&type);
+
+ // swap_bytes
+ buf.Write(&swap_bytes);
+
+ // reset
+ buf.Write(&reset);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetMinmaxReply>(&buf, "Glx::GetMinmax",
+ false);
+}
+
+Future<Glx::GetMinmaxReply> Glx::GetMinmax(const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& format,
+ const uint32_t& type,
+ const uint8_t& swap_bytes,
+ const uint8_t& reset) {
+ return Glx::GetMinmax(Glx::GetMinmaxRequest{context_tag, target, format, type,
+ swap_bytes, reset});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetMinmaxReply> detail::ReadReply<Glx::GetMinmaxReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetMinmaxReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 24);
+
+ // data
+ data.resize((length) * (4));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetMinmaxParameterfvReply> Glx::GetMinmaxParameterfv(
+ const Glx::GetMinmaxParameterfvRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 158;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetMinmaxParameterfvReply>(
+ &buf, "Glx::GetMinmaxParameterfv", false);
+}
+
+Future<Glx::GetMinmaxParameterfvReply> Glx::GetMinmaxParameterfv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetMinmaxParameterfv(
+ Glx::GetMinmaxParameterfvRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetMinmaxParameterfvReply> detail::ReadReply<
+ Glx::GetMinmaxParameterfvReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetMinmaxParameterfvReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetMinmaxParameterivReply> Glx::GetMinmaxParameteriv(
+ const Glx::GetMinmaxParameterivRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 159;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetMinmaxParameterivReply>(
+ &buf, "Glx::GetMinmaxParameteriv", false);
+}
+
+Future<Glx::GetMinmaxParameterivReply> Glx::GetMinmaxParameteriv(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetMinmaxParameteriv(
+ Glx::GetMinmaxParameterivRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetMinmaxParameterivReply> detail::ReadReply<
+ Glx::GetMinmaxParameterivReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetMinmaxParameterivReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetCompressedTexImageARBReply> Glx::GetCompressedTexImageARB(
+ const Glx::GetCompressedTexImageARBRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& level = request.level;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 160;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // level
+ buf.Write(&level);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetCompressedTexImageARBReply>(
+ &buf, "Glx::GetCompressedTexImageARB", false);
+}
+
+Future<Glx::GetCompressedTexImageARBReply> Glx::GetCompressedTexImageARB(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const int32_t& level) {
+ return Glx::GetCompressedTexImageARB(
+ Glx::GetCompressedTexImageARBRequest{context_tag, target, level});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetCompressedTexImageARBReply> detail::ReadReply<
+ Glx::GetCompressedTexImageARBReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetCompressedTexImageARBReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& size = (*reply).size;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // size
+ Read(&size, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize((length) * (4));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Glx::DeleteQueriesARB(
+ const Glx::DeleteQueriesARBRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ int32_t n{};
+ auto& ids = request.ids;
+ size_t ids_len = ids.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 161;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // n
+ n = ids.size();
+ buf.Write(&n);
+
+ // ids
+ DCHECK_EQ(static_cast<size_t>(n), ids.size());
+ for (auto& ids_elem : ids) {
+ // ids_elem
+ buf.Write(&ids_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Glx::DeleteQueriesARB", false);
+}
+
+Future<void> Glx::DeleteQueriesARB(const ContextTag& context_tag,
+ const std::vector<uint32_t>& ids) {
+ return Glx::DeleteQueriesARB(Glx::DeleteQueriesARBRequest{context_tag, ids});
+}
+
+Future<Glx::GenQueriesARBReply> Glx::GenQueriesARB(
+ const Glx::GenQueriesARBRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& n = request.n;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 162;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // n
+ buf.Write(&n);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GenQueriesARBReply>(
+ &buf, "Glx::GenQueriesARB", false);
+}
+
+Future<Glx::GenQueriesARBReply> Glx::GenQueriesARB(
+ const ContextTag& context_tag,
+ const int32_t& n) {
+ return Glx::GenQueriesARB(Glx::GenQueriesARBRequest{context_tag, n});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GenQueriesARBReply> detail::ReadReply<
+ Glx::GenQueriesARBReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GenQueriesARBReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 24);
+
+ // data
+ data.resize(length);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::IsQueryARBReply> Glx::IsQueryARB(
+ const Glx::IsQueryARBRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& id = request.id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 163;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // id
+ buf.Write(&id);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::IsQueryARBReply>(&buf, "Glx::IsQueryARB",
+ false);
+}
+
+Future<Glx::IsQueryARBReply> Glx::IsQueryARB(const ContextTag& context_tag,
+ const uint32_t& id) {
+ return Glx::IsQueryARB(Glx::IsQueryARBRequest{context_tag, id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::IsQueryARBReply> detail::ReadReply<Glx::IsQueryARBReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::IsQueryARBReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& ret_val = (*reply).ret_val;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // ret_val
+ Read(&ret_val, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetQueryivARBReply> Glx::GetQueryivARB(
+ const Glx::GetQueryivARBRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& target = request.target;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 164;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // target
+ buf.Write(&target);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetQueryivARBReply>(
+ &buf, "Glx::GetQueryivARB", false);
+}
+
+Future<Glx::GetQueryivARBReply> Glx::GetQueryivARB(
+ const ContextTag& context_tag,
+ const uint32_t& target,
+ const uint32_t& pname) {
+ return Glx::GetQueryivARB(
+ Glx::GetQueryivARBRequest{context_tag, target, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetQueryivARBReply> detail::ReadReply<
+ Glx::GetQueryivARBReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetQueryivARBReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetQueryObjectivARBReply> Glx::GetQueryObjectivARB(
+ const Glx::GetQueryObjectivARBRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& id = request.id;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 165;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // id
+ buf.Write(&id);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetQueryObjectivARBReply>(
+ &buf, "Glx::GetQueryObjectivARB", false);
+}
+
+Future<Glx::GetQueryObjectivARBReply> Glx::GetQueryObjectivARB(
+ const ContextTag& context_tag,
+ const uint32_t& id,
+ const uint32_t& pname) {
+ return Glx::GetQueryObjectivARB(
+ Glx::GetQueryObjectivARBRequest{context_tag, id, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetQueryObjectivARBReply> detail::ReadReply<
+ Glx::GetQueryObjectivARBReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetQueryObjectivARBReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Glx::GetQueryObjectuivARBReply> Glx::GetQueryObjectuivARB(
+ const Glx::GetQueryObjectuivARBRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_tag = request.context_tag;
+ auto& id = request.id;
+ auto& pname = request.pname;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 166;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_tag
+ buf.Write(&context_tag);
+
+ // id
+ buf.Write(&id);
+
+ // pname
+ buf.Write(&pname);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Glx::GetQueryObjectuivARBReply>(
+ &buf, "Glx::GetQueryObjectuivARB", false);
+}
+
+Future<Glx::GetQueryObjectuivARBReply> Glx::GetQueryObjectuivARB(
+ const ContextTag& context_tag,
+ const uint32_t& id,
+ const uint32_t& pname) {
+ return Glx::GetQueryObjectuivARB(
+ Glx::GetQueryObjectuivARBRequest{context_tag, id, pname});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Glx::GetQueryObjectuivARBReply> detail::ReadReply<
+ Glx::GetQueryObjectuivARBReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Glx::GetQueryObjectuivARBReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t n{};
+ auto& datum = (*reply).datum;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // n
+ Read(&n, &buf);
+
+ // datum
+ Read(&datum, &buf);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // data
+ data.resize(n);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/glx.h b/chromium/ui/gfx/x/generated_protos/glx.h
new file mode 100644
index 00000000000..d20eec6df74
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/glx.h
@@ -0,0 +1,2235 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_GLX_H_
+#define UI_GFX_X_GENERATED_PROTOS_GLX_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Glx {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 4;
+
+ Glx(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Pixmap : uint32_t {};
+
+ enum class Context : uint32_t {};
+
+ enum class PBuffer : uint32_t {};
+
+ enum class Window : uint32_t {};
+
+ enum class FbConfig : uint32_t {};
+
+ enum class Bool32 : uint32_t {};
+
+ enum class ContextTag : uint32_t {};
+
+ enum class Pbcet : int {
+ Damaged = 32791,
+ Saved = 32792,
+ };
+
+ enum class Pbcdt : int {
+ Window = 32793,
+ Pbuffer = 32794,
+ };
+
+ enum class GraphicsContextAttribute : int {
+ XPROTO_GL_ALL_ATTRIB_BITS = 16777215,
+ XPROTO_GL_CURRENT_BIT = 1 << 0,
+ XPROTO_GL_POINT_BIT = 1 << 1,
+ XPROTO_GL_LINE_BIT = 1 << 2,
+ XPROTO_GL_POLYGON_BIT = 1 << 3,
+ XPROTO_GL_POLYGON_STIPPLE_BIT = 1 << 4,
+ XPROTO_GL_PIXEL_MODE_BIT = 1 << 5,
+ XPROTO_GL_LIGHTING_BIT = 1 << 6,
+ XPROTO_GL_FOG_BIT = 1 << 7,
+ XPROTO_GL_DEPTH_BUFFER_BIT = 1 << 8,
+ XPROTO_GL_ACCUM_BUFFER_BIT = 1 << 9,
+ XPROTO_GL_STENCIL_BUFFER_BIT = 1 << 10,
+ XPROTO_GL_VIEWPORT_BIT = 1 << 11,
+ XPROTO_GL_TRANSFORM_BIT = 1 << 12,
+ XPROTO_GL_ENABLE_BIT = 1 << 13,
+ XPROTO_GL_COLOR_BUFFER_BIT = 1 << 14,
+ XPROTO_GL_HINT_BIT = 1 << 15,
+ XPROTO_GL_EVAL_BIT = 1 << 16,
+ XPROTO_GL_LIST_BIT = 1 << 17,
+ XPROTO_GL_TEXTURE_BIT = 1 << 18,
+ XPROTO_GL_SCISSOR_BIT = 1 << 19,
+ };
+
+ enum class Rm : int {
+ XPROTO_GL_RENDER = 7168,
+ XPROTO_GL_FEEDBACK = 7169,
+ XPROTO_GL_SELECT = 7170,
+ };
+
+ struct Drawable {
+ Drawable() : value{} {}
+
+ Drawable(x11::Window value) : value{static_cast<uint32_t>(value)} {}
+ operator x11::Window() const { return static_cast<x11::Window>(value); }
+
+ Drawable(PBuffer value) : value{static_cast<uint32_t>(value)} {}
+ operator PBuffer() const { return static_cast<PBuffer>(value); }
+
+ Drawable(Pixmap value) : value{static_cast<uint32_t>(value)} {}
+ operator Pixmap() const { return static_cast<Pixmap>(value); }
+
+ Drawable(Window value) : value{static_cast<uint32_t>(value)} {}
+ operator Window() const { return static_cast<Window>(value); }
+
+ uint32_t value{};
+ };
+
+ struct GenericError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadContextError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadContextStateError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadDrawableError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadPixmapError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadContextTagError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadCurrentWindowError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadRenderRequestError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadLargeRequestError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct UnsupportedPrivateRequestError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadFBConfigError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadPbufferError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadCurrentDrawableError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadWindowError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct GLXBadProfileARBError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct PbufferClobberEvent {
+ static constexpr int type_id = 4;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ uint16_t sequence{};
+ uint16_t event_type{};
+ uint16_t draw_type{};
+ Drawable drawable{};
+ uint32_t b_mask{};
+ uint16_t aux_buffer{};
+ uint16_t x{};
+ uint16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t count{};
+
+ x11::Window* GetWindow() {
+ return reinterpret_cast<x11::Window*>(&drawable);
+ }
+ };
+
+ struct BufferSwapCompleteEvent {
+ static constexpr int type_id = 5;
+ static constexpr uint8_t opcode = 1;
+ bool send_event{};
+ uint16_t sequence{};
+ uint16_t event_type{};
+ Drawable drawable{};
+ uint32_t ust_hi{};
+ uint32_t ust_lo{};
+ uint32_t msc_hi{};
+ uint32_t msc_lo{};
+ uint32_t sbc{};
+
+ x11::Window* GetWindow() {
+ return reinterpret_cast<x11::Window*>(&drawable);
+ }
+ };
+
+ struct RenderRequest {
+ ContextTag context_tag{};
+ std::vector<uint8_t> data{};
+ };
+
+ using RenderResponse = Response<void>;
+
+ Future<void> Render(const RenderRequest& request);
+
+ Future<void> Render(const ContextTag& context_tag = {},
+ const std::vector<uint8_t>& data = {});
+
+ struct RenderLargeRequest {
+ ContextTag context_tag{};
+ uint16_t request_num{};
+ uint16_t request_total{};
+ std::vector<uint8_t> data{};
+ };
+
+ using RenderLargeResponse = Response<void>;
+
+ Future<void> RenderLarge(const RenderLargeRequest& request);
+
+ Future<void> RenderLarge(const ContextTag& context_tag = {},
+ const uint16_t& request_num = {},
+ const uint16_t& request_total = {},
+ const std::vector<uint8_t>& data = {});
+
+ struct CreateContextRequest {
+ Context context{};
+ VisualId visual{};
+ uint32_t screen{};
+ Context share_list{};
+ uint8_t is_direct{};
+ };
+
+ using CreateContextResponse = Response<void>;
+
+ Future<void> CreateContext(const CreateContextRequest& request);
+
+ Future<void> CreateContext(const Context& context = {},
+ const VisualId& visual = {},
+ const uint32_t& screen = {},
+ const Context& share_list = {},
+ const uint8_t& is_direct = {});
+
+ struct DestroyContextRequest {
+ Context context{};
+ };
+
+ using DestroyContextResponse = Response<void>;
+
+ Future<void> DestroyContext(const DestroyContextRequest& request);
+
+ Future<void> DestroyContext(const Context& context = {});
+
+ struct MakeCurrentRequest {
+ Drawable drawable{};
+ Context context{};
+ ContextTag old_context_tag{};
+ };
+
+ struct MakeCurrentReply {
+ uint16_t sequence{};
+ ContextTag context_tag{};
+ };
+
+ using MakeCurrentResponse = Response<MakeCurrentReply>;
+
+ Future<MakeCurrentReply> MakeCurrent(const MakeCurrentRequest& request);
+
+ Future<MakeCurrentReply> MakeCurrent(const Drawable& drawable = {},
+ const Context& context = {},
+ const ContextTag& old_context_tag = {});
+
+ struct IsDirectRequest {
+ Context context{};
+ };
+
+ struct IsDirectReply {
+ uint16_t sequence{};
+ uint8_t is_direct{};
+ };
+
+ using IsDirectResponse = Response<IsDirectReply>;
+
+ Future<IsDirectReply> IsDirect(const IsDirectRequest& request);
+
+ Future<IsDirectReply> IsDirect(const Context& context = {});
+
+ struct QueryVersionRequest {
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(const uint32_t& major_version = {},
+ const uint32_t& minor_version = {});
+
+ struct WaitGLRequest {
+ ContextTag context_tag{};
+ };
+
+ using WaitGLResponse = Response<void>;
+
+ Future<void> WaitGL(const WaitGLRequest& request);
+
+ Future<void> WaitGL(const ContextTag& context_tag = {});
+
+ struct WaitXRequest {
+ ContextTag context_tag{};
+ };
+
+ using WaitXResponse = Response<void>;
+
+ Future<void> WaitX(const WaitXRequest& request);
+
+ Future<void> WaitX(const ContextTag& context_tag = {});
+
+ struct CopyContextRequest {
+ Context src{};
+ Context dest{};
+ uint32_t mask{};
+ ContextTag src_context_tag{};
+ };
+
+ using CopyContextResponse = Response<void>;
+
+ Future<void> CopyContext(const CopyContextRequest& request);
+
+ Future<void> CopyContext(const Context& src = {},
+ const Context& dest = {},
+ const uint32_t& mask = {},
+ const ContextTag& src_context_tag = {});
+
+ struct SwapBuffersRequest {
+ ContextTag context_tag{};
+ Drawable drawable{};
+ };
+
+ using SwapBuffersResponse = Response<void>;
+
+ Future<void> SwapBuffers(const SwapBuffersRequest& request);
+
+ Future<void> SwapBuffers(const ContextTag& context_tag = {},
+ const Drawable& drawable = {});
+
+ struct UseXFontRequest {
+ ContextTag context_tag{};
+ Font font{};
+ uint32_t first{};
+ uint32_t count{};
+ uint32_t list_base{};
+ };
+
+ using UseXFontResponse = Response<void>;
+
+ Future<void> UseXFont(const UseXFontRequest& request);
+
+ Future<void> UseXFont(const ContextTag& context_tag = {},
+ const Font& font = {},
+ const uint32_t& first = {},
+ const uint32_t& count = {},
+ const uint32_t& list_base = {});
+
+ struct CreateGLXPixmapRequest {
+ uint32_t screen{};
+ VisualId visual{};
+ x11::Pixmap pixmap{};
+ Pixmap glx_pixmap{};
+ };
+
+ using CreateGLXPixmapResponse = Response<void>;
+
+ Future<void> CreateGLXPixmap(const CreateGLXPixmapRequest& request);
+
+ Future<void> CreateGLXPixmap(const uint32_t& screen = {},
+ const VisualId& visual = {},
+ const x11::Pixmap& pixmap = {},
+ const Pixmap& glx_pixmap = {});
+
+ struct GetVisualConfigsRequest {
+ uint32_t screen{};
+ };
+
+ struct GetVisualConfigsReply {
+ uint16_t sequence{};
+ uint32_t num_visuals{};
+ uint32_t num_properties{};
+ std::vector<uint32_t> property_list{};
+ };
+
+ using GetVisualConfigsResponse = Response<GetVisualConfigsReply>;
+
+ Future<GetVisualConfigsReply> GetVisualConfigs(
+ const GetVisualConfigsRequest& request);
+
+ Future<GetVisualConfigsReply> GetVisualConfigs(const uint32_t& screen = {});
+
+ struct DestroyGLXPixmapRequest {
+ Pixmap glx_pixmap{};
+ };
+
+ using DestroyGLXPixmapResponse = Response<void>;
+
+ Future<void> DestroyGLXPixmap(const DestroyGLXPixmapRequest& request);
+
+ Future<void> DestroyGLXPixmap(const Pixmap& glx_pixmap = {});
+
+ struct VendorPrivateRequest {
+ uint32_t vendor_code{};
+ ContextTag context_tag{};
+ std::vector<uint8_t> data{};
+ };
+
+ using VendorPrivateResponse = Response<void>;
+
+ Future<void> VendorPrivate(const VendorPrivateRequest& request);
+
+ Future<void> VendorPrivate(const uint32_t& vendor_code = {},
+ const ContextTag& context_tag = {},
+ const std::vector<uint8_t>& data = {});
+
+ struct VendorPrivateWithReplyRequest {
+ uint32_t vendor_code{};
+ ContextTag context_tag{};
+ std::vector<uint8_t> data{};
+ };
+
+ struct VendorPrivateWithReplyReply {
+ uint16_t sequence{};
+ uint32_t retval{};
+ std::array<uint8_t, 24> data1{};
+ std::vector<uint8_t> data2{};
+ };
+
+ using VendorPrivateWithReplyResponse = Response<VendorPrivateWithReplyReply>;
+
+ Future<VendorPrivateWithReplyReply> VendorPrivateWithReply(
+ const VendorPrivateWithReplyRequest& request);
+
+ Future<VendorPrivateWithReplyReply> VendorPrivateWithReply(
+ const uint32_t& vendor_code = {},
+ const ContextTag& context_tag = {},
+ const std::vector<uint8_t>& data = {});
+
+ struct QueryExtensionsStringRequest {
+ uint32_t screen{};
+ };
+
+ struct QueryExtensionsStringReply {
+ uint16_t sequence{};
+ uint32_t n{};
+ };
+
+ using QueryExtensionsStringResponse = Response<QueryExtensionsStringReply>;
+
+ Future<QueryExtensionsStringReply> QueryExtensionsString(
+ const QueryExtensionsStringRequest& request);
+
+ Future<QueryExtensionsStringReply> QueryExtensionsString(
+ const uint32_t& screen = {});
+
+ struct QueryServerStringRequest {
+ uint32_t screen{};
+ uint32_t name{};
+ };
+
+ struct QueryServerStringReply {
+ uint16_t sequence{};
+ std::string string{};
+ };
+
+ using QueryServerStringResponse = Response<QueryServerStringReply>;
+
+ Future<QueryServerStringReply> QueryServerString(
+ const QueryServerStringRequest& request);
+
+ Future<QueryServerStringReply> QueryServerString(const uint32_t& screen = {},
+ const uint32_t& name = {});
+
+ struct ClientInfoRequest {
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ std::string string{};
+ };
+
+ using ClientInfoResponse = Response<void>;
+
+ Future<void> ClientInfo(const ClientInfoRequest& request);
+
+ Future<void> ClientInfo(const uint32_t& major_version = {},
+ const uint32_t& minor_version = {},
+ const std::string& string = {});
+
+ struct GetFBConfigsRequest {
+ uint32_t screen{};
+ };
+
+ struct GetFBConfigsReply {
+ uint16_t sequence{};
+ uint32_t num_FB_configs{};
+ uint32_t num_properties{};
+ std::vector<uint32_t> property_list{};
+ };
+
+ using GetFBConfigsResponse = Response<GetFBConfigsReply>;
+
+ Future<GetFBConfigsReply> GetFBConfigs(const GetFBConfigsRequest& request);
+
+ Future<GetFBConfigsReply> GetFBConfigs(const uint32_t& screen = {});
+
+ struct CreatePixmapRequest {
+ uint32_t screen{};
+ FbConfig fbconfig{};
+ x11::Pixmap pixmap{};
+ Pixmap glx_pixmap{};
+ uint32_t num_attribs{};
+ std::vector<uint32_t> attribs{};
+ };
+
+ using CreatePixmapResponse = Response<void>;
+
+ Future<void> CreatePixmap(const CreatePixmapRequest& request);
+
+ Future<void> CreatePixmap(const uint32_t& screen = {},
+ const FbConfig& fbconfig = {},
+ const x11::Pixmap& pixmap = {},
+ const Pixmap& glx_pixmap = {},
+ const uint32_t& num_attribs = {},
+ const std::vector<uint32_t>& attribs = {});
+
+ struct DestroyPixmapRequest {
+ Pixmap glx_pixmap{};
+ };
+
+ using DestroyPixmapResponse = Response<void>;
+
+ Future<void> DestroyPixmap(const DestroyPixmapRequest& request);
+
+ Future<void> DestroyPixmap(const Pixmap& glx_pixmap = {});
+
+ struct CreateNewContextRequest {
+ Context context{};
+ FbConfig fbconfig{};
+ uint32_t screen{};
+ uint32_t render_type{};
+ Context share_list{};
+ uint8_t is_direct{};
+ };
+
+ using CreateNewContextResponse = Response<void>;
+
+ Future<void> CreateNewContext(const CreateNewContextRequest& request);
+
+ Future<void> CreateNewContext(const Context& context = {},
+ const FbConfig& fbconfig = {},
+ const uint32_t& screen = {},
+ const uint32_t& render_type = {},
+ const Context& share_list = {},
+ const uint8_t& is_direct = {});
+
+ struct QueryContextRequest {
+ Context context{};
+ };
+
+ struct QueryContextReply {
+ uint16_t sequence{};
+ uint32_t num_attribs{};
+ std::vector<uint32_t> attribs{};
+ };
+
+ using QueryContextResponse = Response<QueryContextReply>;
+
+ Future<QueryContextReply> QueryContext(const QueryContextRequest& request);
+
+ Future<QueryContextReply> QueryContext(const Context& context = {});
+
+ struct MakeContextCurrentRequest {
+ ContextTag old_context_tag{};
+ Drawable drawable{};
+ Drawable read_drawable{};
+ Context context{};
+ };
+
+ struct MakeContextCurrentReply {
+ uint16_t sequence{};
+ ContextTag context_tag{};
+ };
+
+ using MakeContextCurrentResponse = Response<MakeContextCurrentReply>;
+
+ Future<MakeContextCurrentReply> MakeContextCurrent(
+ const MakeContextCurrentRequest& request);
+
+ Future<MakeContextCurrentReply> MakeContextCurrent(
+ const ContextTag& old_context_tag = {},
+ const Drawable& drawable = {},
+ const Drawable& read_drawable = {},
+ const Context& context = {});
+
+ struct CreatePbufferRequest {
+ uint32_t screen{};
+ FbConfig fbconfig{};
+ PBuffer pbuffer{};
+ uint32_t num_attribs{};
+ std::vector<uint32_t> attribs{};
+ };
+
+ using CreatePbufferResponse = Response<void>;
+
+ Future<void> CreatePbuffer(const CreatePbufferRequest& request);
+
+ Future<void> CreatePbuffer(const uint32_t& screen = {},
+ const FbConfig& fbconfig = {},
+ const PBuffer& pbuffer = {},
+ const uint32_t& num_attribs = {},
+ const std::vector<uint32_t>& attribs = {});
+
+ struct DestroyPbufferRequest {
+ PBuffer pbuffer{};
+ };
+
+ using DestroyPbufferResponse = Response<void>;
+
+ Future<void> DestroyPbuffer(const DestroyPbufferRequest& request);
+
+ Future<void> DestroyPbuffer(const PBuffer& pbuffer = {});
+
+ struct GetDrawableAttributesRequest {
+ Drawable drawable{};
+ };
+
+ struct GetDrawableAttributesReply {
+ uint16_t sequence{};
+ uint32_t num_attribs{};
+ std::vector<uint32_t> attribs{};
+ };
+
+ using GetDrawableAttributesResponse = Response<GetDrawableAttributesReply>;
+
+ Future<GetDrawableAttributesReply> GetDrawableAttributes(
+ const GetDrawableAttributesRequest& request);
+
+ Future<GetDrawableAttributesReply> GetDrawableAttributes(
+ const Drawable& drawable = {});
+
+ struct ChangeDrawableAttributesRequest {
+ Drawable drawable{};
+ uint32_t num_attribs{};
+ std::vector<uint32_t> attribs{};
+ };
+
+ using ChangeDrawableAttributesResponse = Response<void>;
+
+ Future<void> ChangeDrawableAttributes(
+ const ChangeDrawableAttributesRequest& request);
+
+ Future<void> ChangeDrawableAttributes(
+ const Drawable& drawable = {},
+ const uint32_t& num_attribs = {},
+ const std::vector<uint32_t>& attribs = {});
+
+ struct CreateWindowRequest {
+ uint32_t screen{};
+ FbConfig fbconfig{};
+ x11::Window window{};
+ Window glx_window{};
+ uint32_t num_attribs{};
+ std::vector<uint32_t> attribs{};
+ };
+
+ using CreateWindowResponse = Response<void>;
+
+ Future<void> CreateWindow(const CreateWindowRequest& request);
+
+ Future<void> CreateWindow(const uint32_t& screen = {},
+ const FbConfig& fbconfig = {},
+ const x11::Window& window = {},
+ const Window& glx_window = {},
+ const uint32_t& num_attribs = {},
+ const std::vector<uint32_t>& attribs = {});
+
+ struct DeleteWindowRequest {
+ Window glxwindow{};
+ };
+
+ using DeleteWindowResponse = Response<void>;
+
+ Future<void> DeleteWindow(const DeleteWindowRequest& request);
+
+ Future<void> DeleteWindow(const Window& glxwindow = {});
+
+ struct SetClientInfoARBRequest {
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ uint32_t num_versions{};
+ std::vector<uint32_t> gl_versions{};
+ std::string gl_extension_string{};
+ std::string glx_extension_string{};
+ };
+
+ using SetClientInfoARBResponse = Response<void>;
+
+ Future<void> SetClientInfoARB(const SetClientInfoARBRequest& request);
+
+ Future<void> SetClientInfoARB(const uint32_t& major_version = {},
+ const uint32_t& minor_version = {},
+ const uint32_t& num_versions = {},
+ const std::vector<uint32_t>& gl_versions = {},
+ const std::string& gl_extension_string = {},
+ const std::string& glx_extension_string = {});
+
+ struct CreateContextAttribsARBRequest {
+ Context context{};
+ FbConfig fbconfig{};
+ uint32_t screen{};
+ Context share_list{};
+ uint8_t is_direct{};
+ uint32_t num_attribs{};
+ std::vector<uint32_t> attribs{};
+ };
+
+ using CreateContextAttribsARBResponse = Response<void>;
+
+ Future<void> CreateContextAttribsARB(
+ const CreateContextAttribsARBRequest& request);
+
+ Future<void> CreateContextAttribsARB(
+ const Context& context = {},
+ const FbConfig& fbconfig = {},
+ const uint32_t& screen = {},
+ const Context& share_list = {},
+ const uint8_t& is_direct = {},
+ const uint32_t& num_attribs = {},
+ const std::vector<uint32_t>& attribs = {});
+
+ struct SetClientInfo2ARBRequest {
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ uint32_t num_versions{};
+ std::vector<uint32_t> gl_versions{};
+ std::string gl_extension_string{};
+ std::string glx_extension_string{};
+ };
+
+ using SetClientInfo2ARBResponse = Response<void>;
+
+ Future<void> SetClientInfo2ARB(const SetClientInfo2ARBRequest& request);
+
+ Future<void> SetClientInfo2ARB(const uint32_t& major_version = {},
+ const uint32_t& minor_version = {},
+ const uint32_t& num_versions = {},
+ const std::vector<uint32_t>& gl_versions = {},
+ const std::string& gl_extension_string = {},
+ const std::string& glx_extension_string = {});
+
+ struct NewListRequest {
+ ContextTag context_tag{};
+ uint32_t list{};
+ uint32_t mode{};
+ };
+
+ using NewListResponse = Response<void>;
+
+ Future<void> NewList(const NewListRequest& request);
+
+ Future<void> NewList(const ContextTag& context_tag = {},
+ const uint32_t& list = {},
+ const uint32_t& mode = {});
+
+ struct EndListRequest {
+ ContextTag context_tag{};
+ };
+
+ using EndListResponse = Response<void>;
+
+ Future<void> EndList(const EndListRequest& request);
+
+ Future<void> EndList(const ContextTag& context_tag = {});
+
+ struct DeleteListsRequest {
+ ContextTag context_tag{};
+ uint32_t list{};
+ int32_t range{};
+ };
+
+ using DeleteListsResponse = Response<void>;
+
+ Future<void> DeleteLists(const DeleteListsRequest& request);
+
+ Future<void> DeleteLists(const ContextTag& context_tag = {},
+ const uint32_t& list = {},
+ const int32_t& range = {});
+
+ struct GenListsRequest {
+ ContextTag context_tag{};
+ int32_t range{};
+ };
+
+ struct GenListsReply {
+ uint16_t sequence{};
+ uint32_t ret_val{};
+ };
+
+ using GenListsResponse = Response<GenListsReply>;
+
+ Future<GenListsReply> GenLists(const GenListsRequest& request);
+
+ Future<GenListsReply> GenLists(const ContextTag& context_tag = {},
+ const int32_t& range = {});
+
+ struct FeedbackBufferRequest {
+ ContextTag context_tag{};
+ int32_t size{};
+ int32_t type{};
+ };
+
+ using FeedbackBufferResponse = Response<void>;
+
+ Future<void> FeedbackBuffer(const FeedbackBufferRequest& request);
+
+ Future<void> FeedbackBuffer(const ContextTag& context_tag = {},
+ const int32_t& size = {},
+ const int32_t& type = {});
+
+ struct SelectBufferRequest {
+ ContextTag context_tag{};
+ int32_t size{};
+ };
+
+ using SelectBufferResponse = Response<void>;
+
+ Future<void> SelectBuffer(const SelectBufferRequest& request);
+
+ Future<void> SelectBuffer(const ContextTag& context_tag = {},
+ const int32_t& size = {});
+
+ struct RenderModeRequest {
+ ContextTag context_tag{};
+ uint32_t mode{};
+ };
+
+ struct RenderModeReply {
+ uint16_t sequence{};
+ uint32_t ret_val{};
+ uint32_t new_mode{};
+ std::vector<uint32_t> data{};
+ };
+
+ using RenderModeResponse = Response<RenderModeReply>;
+
+ Future<RenderModeReply> RenderMode(const RenderModeRequest& request);
+
+ Future<RenderModeReply> RenderMode(const ContextTag& context_tag = {},
+ const uint32_t& mode = {});
+
+ struct FinishRequest {
+ ContextTag context_tag{};
+ };
+
+ struct FinishReply {
+ uint16_t sequence{};
+ };
+
+ using FinishResponse = Response<FinishReply>;
+
+ Future<FinishReply> Finish(const FinishRequest& request);
+
+ Future<FinishReply> Finish(const ContextTag& context_tag = {});
+
+ struct PixelStorefRequest {
+ ContextTag context_tag{};
+ uint32_t pname{};
+ float datum{};
+ };
+
+ using PixelStorefResponse = Response<void>;
+
+ Future<void> PixelStoref(const PixelStorefRequest& request);
+
+ Future<void> PixelStoref(const ContextTag& context_tag = {},
+ const uint32_t& pname = {},
+ const float& datum = {});
+
+ struct PixelStoreiRequest {
+ ContextTag context_tag{};
+ uint32_t pname{};
+ int32_t datum{};
+ };
+
+ using PixelStoreiResponse = Response<void>;
+
+ Future<void> PixelStorei(const PixelStoreiRequest& request);
+
+ Future<void> PixelStorei(const ContextTag& context_tag = {},
+ const uint32_t& pname = {},
+ const int32_t& datum = {});
+
+ struct ReadPixelsRequest {
+ ContextTag context_tag{};
+ int32_t x{};
+ int32_t y{};
+ int32_t width{};
+ int32_t height{};
+ uint32_t format{};
+ uint32_t type{};
+ uint8_t swap_bytes{};
+ uint8_t lsb_first{};
+ };
+
+ struct ReadPixelsReply {
+ uint16_t sequence{};
+ std::vector<uint8_t> data{};
+ };
+
+ using ReadPixelsResponse = Response<ReadPixelsReply>;
+
+ Future<ReadPixelsReply> ReadPixels(const ReadPixelsRequest& request);
+
+ Future<ReadPixelsReply> ReadPixels(const ContextTag& context_tag = {},
+ const int32_t& x = {},
+ const int32_t& y = {},
+ const int32_t& width = {},
+ const int32_t& height = {},
+ const uint32_t& format = {},
+ const uint32_t& type = {},
+ const uint8_t& swap_bytes = {},
+ const uint8_t& lsb_first = {});
+
+ struct GetBooleanvRequest {
+ ContextTag context_tag{};
+ int32_t pname{};
+ };
+
+ struct GetBooleanvReply {
+ uint16_t sequence{};
+ uint8_t datum{};
+ std::vector<uint8_t> data{};
+ };
+
+ using GetBooleanvResponse = Response<GetBooleanvReply>;
+
+ Future<GetBooleanvReply> GetBooleanv(const GetBooleanvRequest& request);
+
+ Future<GetBooleanvReply> GetBooleanv(const ContextTag& context_tag = {},
+ const int32_t& pname = {});
+
+ struct GetClipPlaneRequest {
+ ContextTag context_tag{};
+ int32_t plane{};
+ };
+
+ struct GetClipPlaneReply {
+ uint16_t sequence{};
+ std::vector<double> data{};
+ };
+
+ using GetClipPlaneResponse = Response<GetClipPlaneReply>;
+
+ Future<GetClipPlaneReply> GetClipPlane(const GetClipPlaneRequest& request);
+
+ Future<GetClipPlaneReply> GetClipPlane(const ContextTag& context_tag = {},
+ const int32_t& plane = {});
+
+ struct GetDoublevRequest {
+ ContextTag context_tag{};
+ uint32_t pname{};
+ };
+
+ struct GetDoublevReply {
+ uint16_t sequence{};
+ double datum{};
+ std::vector<double> data{};
+ };
+
+ using GetDoublevResponse = Response<GetDoublevReply>;
+
+ Future<GetDoublevReply> GetDoublev(const GetDoublevRequest& request);
+
+ Future<GetDoublevReply> GetDoublev(const ContextTag& context_tag = {},
+ const uint32_t& pname = {});
+
+ struct GetErrorRequest {
+ ContextTag context_tag{};
+ };
+
+ struct GetErrorReply {
+ uint16_t sequence{};
+ int32_t error{};
+ };
+
+ using GetErrorResponse = Response<GetErrorReply>;
+
+ Future<GetErrorReply> GetError(const GetErrorRequest& request);
+
+ Future<GetErrorReply> GetError(const ContextTag& context_tag = {});
+
+ struct GetFloatvRequest {
+ ContextTag context_tag{};
+ uint32_t pname{};
+ };
+
+ struct GetFloatvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetFloatvResponse = Response<GetFloatvReply>;
+
+ Future<GetFloatvReply> GetFloatv(const GetFloatvRequest& request);
+
+ Future<GetFloatvReply> GetFloatv(const ContextTag& context_tag = {},
+ const uint32_t& pname = {});
+
+ struct GetIntegervRequest {
+ ContextTag context_tag{};
+ uint32_t pname{};
+ };
+
+ struct GetIntegervReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetIntegervResponse = Response<GetIntegervReply>;
+
+ Future<GetIntegervReply> GetIntegerv(const GetIntegervRequest& request);
+
+ Future<GetIntegervReply> GetIntegerv(const ContextTag& context_tag = {},
+ const uint32_t& pname = {});
+
+ struct GetLightfvRequest {
+ ContextTag context_tag{};
+ uint32_t light{};
+ uint32_t pname{};
+ };
+
+ struct GetLightfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetLightfvResponse = Response<GetLightfvReply>;
+
+ Future<GetLightfvReply> GetLightfv(const GetLightfvRequest& request);
+
+ Future<GetLightfvReply> GetLightfv(const ContextTag& context_tag = {},
+ const uint32_t& light = {},
+ const uint32_t& pname = {});
+
+ struct GetLightivRequest {
+ ContextTag context_tag{};
+ uint32_t light{};
+ uint32_t pname{};
+ };
+
+ struct GetLightivReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetLightivResponse = Response<GetLightivReply>;
+
+ Future<GetLightivReply> GetLightiv(const GetLightivRequest& request);
+
+ Future<GetLightivReply> GetLightiv(const ContextTag& context_tag = {},
+ const uint32_t& light = {},
+ const uint32_t& pname = {});
+
+ struct GetMapdvRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t query{};
+ };
+
+ struct GetMapdvReply {
+ uint16_t sequence{};
+ double datum{};
+ std::vector<double> data{};
+ };
+
+ using GetMapdvResponse = Response<GetMapdvReply>;
+
+ Future<GetMapdvReply> GetMapdv(const GetMapdvRequest& request);
+
+ Future<GetMapdvReply> GetMapdv(const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& query = {});
+
+ struct GetMapfvRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t query{};
+ };
+
+ struct GetMapfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetMapfvResponse = Response<GetMapfvReply>;
+
+ Future<GetMapfvReply> GetMapfv(const GetMapfvRequest& request);
+
+ Future<GetMapfvReply> GetMapfv(const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& query = {});
+
+ struct GetMapivRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t query{};
+ };
+
+ struct GetMapivReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetMapivResponse = Response<GetMapivReply>;
+
+ Future<GetMapivReply> GetMapiv(const GetMapivRequest& request);
+
+ Future<GetMapivReply> GetMapiv(const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& query = {});
+
+ struct GetMaterialfvRequest {
+ ContextTag context_tag{};
+ uint32_t face{};
+ uint32_t pname{};
+ };
+
+ struct GetMaterialfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetMaterialfvResponse = Response<GetMaterialfvReply>;
+
+ Future<GetMaterialfvReply> GetMaterialfv(const GetMaterialfvRequest& request);
+
+ Future<GetMaterialfvReply> GetMaterialfv(const ContextTag& context_tag = {},
+ const uint32_t& face = {},
+ const uint32_t& pname = {});
+
+ struct GetMaterialivRequest {
+ ContextTag context_tag{};
+ uint32_t face{};
+ uint32_t pname{};
+ };
+
+ struct GetMaterialivReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetMaterialivResponse = Response<GetMaterialivReply>;
+
+ Future<GetMaterialivReply> GetMaterialiv(const GetMaterialivRequest& request);
+
+ Future<GetMaterialivReply> GetMaterialiv(const ContextTag& context_tag = {},
+ const uint32_t& face = {},
+ const uint32_t& pname = {});
+
+ struct GetPixelMapfvRequest {
+ ContextTag context_tag{};
+ uint32_t map{};
+ };
+
+ struct GetPixelMapfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetPixelMapfvResponse = Response<GetPixelMapfvReply>;
+
+ Future<GetPixelMapfvReply> GetPixelMapfv(const GetPixelMapfvRequest& request);
+
+ Future<GetPixelMapfvReply> GetPixelMapfv(const ContextTag& context_tag = {},
+ const uint32_t& map = {});
+
+ struct GetPixelMapuivRequest {
+ ContextTag context_tag{};
+ uint32_t map{};
+ };
+
+ struct GetPixelMapuivReply {
+ uint16_t sequence{};
+ uint32_t datum{};
+ std::vector<uint32_t> data{};
+ };
+
+ using GetPixelMapuivResponse = Response<GetPixelMapuivReply>;
+
+ Future<GetPixelMapuivReply> GetPixelMapuiv(
+ const GetPixelMapuivRequest& request);
+
+ Future<GetPixelMapuivReply> GetPixelMapuiv(const ContextTag& context_tag = {},
+ const uint32_t& map = {});
+
+ struct GetPixelMapusvRequest {
+ ContextTag context_tag{};
+ uint32_t map{};
+ };
+
+ struct GetPixelMapusvReply {
+ uint16_t sequence{};
+ uint16_t datum{};
+ std::vector<uint16_t> data{};
+ };
+
+ using GetPixelMapusvResponse = Response<GetPixelMapusvReply>;
+
+ Future<GetPixelMapusvReply> GetPixelMapusv(
+ const GetPixelMapusvRequest& request);
+
+ Future<GetPixelMapusvReply> GetPixelMapusv(const ContextTag& context_tag = {},
+ const uint32_t& map = {});
+
+ struct GetPolygonStippleRequest {
+ ContextTag context_tag{};
+ uint8_t lsb_first{};
+ };
+
+ struct GetPolygonStippleReply {
+ uint16_t sequence{};
+ std::vector<uint8_t> data{};
+ };
+
+ using GetPolygonStippleResponse = Response<GetPolygonStippleReply>;
+
+ Future<GetPolygonStippleReply> GetPolygonStipple(
+ const GetPolygonStippleRequest& request);
+
+ Future<GetPolygonStippleReply> GetPolygonStipple(
+ const ContextTag& context_tag = {},
+ const uint8_t& lsb_first = {});
+
+ struct GetStringRequest {
+ ContextTag context_tag{};
+ uint32_t name{};
+ };
+
+ struct GetStringReply {
+ uint16_t sequence{};
+ std::string string{};
+ };
+
+ using GetStringResponse = Response<GetStringReply>;
+
+ Future<GetStringReply> GetString(const GetStringRequest& request);
+
+ Future<GetStringReply> GetString(const ContextTag& context_tag = {},
+ const uint32_t& name = {});
+
+ struct GetTexEnvfvRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetTexEnvfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetTexEnvfvResponse = Response<GetTexEnvfvReply>;
+
+ Future<GetTexEnvfvReply> GetTexEnvfv(const GetTexEnvfvRequest& request);
+
+ Future<GetTexEnvfvReply> GetTexEnvfv(const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetTexEnvivRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetTexEnvivReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetTexEnvivResponse = Response<GetTexEnvivReply>;
+
+ Future<GetTexEnvivReply> GetTexEnviv(const GetTexEnvivRequest& request);
+
+ Future<GetTexEnvivReply> GetTexEnviv(const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetTexGendvRequest {
+ ContextTag context_tag{};
+ uint32_t coord{};
+ uint32_t pname{};
+ };
+
+ struct GetTexGendvReply {
+ uint16_t sequence{};
+ double datum{};
+ std::vector<double> data{};
+ };
+
+ using GetTexGendvResponse = Response<GetTexGendvReply>;
+
+ Future<GetTexGendvReply> GetTexGendv(const GetTexGendvRequest& request);
+
+ Future<GetTexGendvReply> GetTexGendv(const ContextTag& context_tag = {},
+ const uint32_t& coord = {},
+ const uint32_t& pname = {});
+
+ struct GetTexGenfvRequest {
+ ContextTag context_tag{};
+ uint32_t coord{};
+ uint32_t pname{};
+ };
+
+ struct GetTexGenfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetTexGenfvResponse = Response<GetTexGenfvReply>;
+
+ Future<GetTexGenfvReply> GetTexGenfv(const GetTexGenfvRequest& request);
+
+ Future<GetTexGenfvReply> GetTexGenfv(const ContextTag& context_tag = {},
+ const uint32_t& coord = {},
+ const uint32_t& pname = {});
+
+ struct GetTexGenivRequest {
+ ContextTag context_tag{};
+ uint32_t coord{};
+ uint32_t pname{};
+ };
+
+ struct GetTexGenivReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetTexGenivResponse = Response<GetTexGenivReply>;
+
+ Future<GetTexGenivReply> GetTexGeniv(const GetTexGenivRequest& request);
+
+ Future<GetTexGenivReply> GetTexGeniv(const ContextTag& context_tag = {},
+ const uint32_t& coord = {},
+ const uint32_t& pname = {});
+
+ struct GetTexImageRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ int32_t level{};
+ uint32_t format{};
+ uint32_t type{};
+ uint8_t swap_bytes{};
+ };
+
+ struct GetTexImageReply {
+ uint16_t sequence{};
+ int32_t width{};
+ int32_t height{};
+ int32_t depth{};
+ std::vector<uint8_t> data{};
+ };
+
+ using GetTexImageResponse = Response<GetTexImageReply>;
+
+ Future<GetTexImageReply> GetTexImage(const GetTexImageRequest& request);
+
+ Future<GetTexImageReply> GetTexImage(const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const int32_t& level = {},
+ const uint32_t& format = {},
+ const uint32_t& type = {},
+ const uint8_t& swap_bytes = {});
+
+ struct GetTexParameterfvRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetTexParameterfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetTexParameterfvResponse = Response<GetTexParameterfvReply>;
+
+ Future<GetTexParameterfvReply> GetTexParameterfv(
+ const GetTexParameterfvRequest& request);
+
+ Future<GetTexParameterfvReply> GetTexParameterfv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetTexParameterivRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetTexParameterivReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetTexParameterivResponse = Response<GetTexParameterivReply>;
+
+ Future<GetTexParameterivReply> GetTexParameteriv(
+ const GetTexParameterivRequest& request);
+
+ Future<GetTexParameterivReply> GetTexParameteriv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetTexLevelParameterfvRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ int32_t level{};
+ uint32_t pname{};
+ };
+
+ struct GetTexLevelParameterfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetTexLevelParameterfvResponse = Response<GetTexLevelParameterfvReply>;
+
+ Future<GetTexLevelParameterfvReply> GetTexLevelParameterfv(
+ const GetTexLevelParameterfvRequest& request);
+
+ Future<GetTexLevelParameterfvReply> GetTexLevelParameterfv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const int32_t& level = {},
+ const uint32_t& pname = {});
+
+ struct GetTexLevelParameterivRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ int32_t level{};
+ uint32_t pname{};
+ };
+
+ struct GetTexLevelParameterivReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetTexLevelParameterivResponse = Response<GetTexLevelParameterivReply>;
+
+ Future<GetTexLevelParameterivReply> GetTexLevelParameteriv(
+ const GetTexLevelParameterivRequest& request);
+
+ Future<GetTexLevelParameterivReply> GetTexLevelParameteriv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const int32_t& level = {},
+ const uint32_t& pname = {});
+
+ struct IsEnabledRequest {
+ ContextTag context_tag{};
+ uint32_t capability{};
+ };
+
+ struct IsEnabledReply {
+ uint16_t sequence{};
+ Bool32 ret_val{};
+ };
+
+ using IsEnabledResponse = Response<IsEnabledReply>;
+
+ Future<IsEnabledReply> IsEnabled(const IsEnabledRequest& request);
+
+ Future<IsEnabledReply> IsEnabled(const ContextTag& context_tag = {},
+ const uint32_t& capability = {});
+
+ struct IsListRequest {
+ ContextTag context_tag{};
+ uint32_t list{};
+ };
+
+ struct IsListReply {
+ uint16_t sequence{};
+ Bool32 ret_val{};
+ };
+
+ using IsListResponse = Response<IsListReply>;
+
+ Future<IsListReply> IsList(const IsListRequest& request);
+
+ Future<IsListReply> IsList(const ContextTag& context_tag = {},
+ const uint32_t& list = {});
+
+ struct FlushRequest {
+ ContextTag context_tag{};
+ };
+
+ using FlushResponse = Response<void>;
+
+ Future<void> Flush(const FlushRequest& request);
+
+ Future<void> Flush(const ContextTag& context_tag = {});
+
+ struct AreTexturesResidentRequest {
+ ContextTag context_tag{};
+ std::vector<uint32_t> textures{};
+ };
+
+ struct AreTexturesResidentReply {
+ uint16_t sequence{};
+ Bool32 ret_val{};
+ std::vector<uint8_t> data{};
+ };
+
+ using AreTexturesResidentResponse = Response<AreTexturesResidentReply>;
+
+ Future<AreTexturesResidentReply> AreTexturesResident(
+ const AreTexturesResidentRequest& request);
+
+ Future<AreTexturesResidentReply> AreTexturesResident(
+ const ContextTag& context_tag = {},
+ const std::vector<uint32_t>& textures = {});
+
+ struct DeleteTexturesRequest {
+ ContextTag context_tag{};
+ std::vector<uint32_t> textures{};
+ };
+
+ using DeleteTexturesResponse = Response<void>;
+
+ Future<void> DeleteTextures(const DeleteTexturesRequest& request);
+
+ Future<void> DeleteTextures(const ContextTag& context_tag = {},
+ const std::vector<uint32_t>& textures = {});
+
+ struct GenTexturesRequest {
+ ContextTag context_tag{};
+ int32_t n{};
+ };
+
+ struct GenTexturesReply {
+ uint16_t sequence{};
+ std::vector<uint32_t> data{};
+ };
+
+ using GenTexturesResponse = Response<GenTexturesReply>;
+
+ Future<GenTexturesReply> GenTextures(const GenTexturesRequest& request);
+
+ Future<GenTexturesReply> GenTextures(const ContextTag& context_tag = {},
+ const int32_t& n = {});
+
+ struct IsTextureRequest {
+ ContextTag context_tag{};
+ uint32_t texture{};
+ };
+
+ struct IsTextureReply {
+ uint16_t sequence{};
+ Bool32 ret_val{};
+ };
+
+ using IsTextureResponse = Response<IsTextureReply>;
+
+ Future<IsTextureReply> IsTexture(const IsTextureRequest& request);
+
+ Future<IsTextureReply> IsTexture(const ContextTag& context_tag = {},
+ const uint32_t& texture = {});
+
+ struct GetColorTableRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t format{};
+ uint32_t type{};
+ uint8_t swap_bytes{};
+ };
+
+ struct GetColorTableReply {
+ uint16_t sequence{};
+ int32_t width{};
+ std::vector<uint8_t> data{};
+ };
+
+ using GetColorTableResponse = Response<GetColorTableReply>;
+
+ Future<GetColorTableReply> GetColorTable(const GetColorTableRequest& request);
+
+ Future<GetColorTableReply> GetColorTable(const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& format = {},
+ const uint32_t& type = {},
+ const uint8_t& swap_bytes = {});
+
+ struct GetColorTableParameterfvRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetColorTableParameterfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetColorTableParameterfvResponse =
+ Response<GetColorTableParameterfvReply>;
+
+ Future<GetColorTableParameterfvReply> GetColorTableParameterfv(
+ const GetColorTableParameterfvRequest& request);
+
+ Future<GetColorTableParameterfvReply> GetColorTableParameterfv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetColorTableParameterivRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetColorTableParameterivReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetColorTableParameterivResponse =
+ Response<GetColorTableParameterivReply>;
+
+ Future<GetColorTableParameterivReply> GetColorTableParameteriv(
+ const GetColorTableParameterivRequest& request);
+
+ Future<GetColorTableParameterivReply> GetColorTableParameteriv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetConvolutionFilterRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t format{};
+ uint32_t type{};
+ uint8_t swap_bytes{};
+ };
+
+ struct GetConvolutionFilterReply {
+ uint16_t sequence{};
+ int32_t width{};
+ int32_t height{};
+ std::vector<uint8_t> data{};
+ };
+
+ using GetConvolutionFilterResponse = Response<GetConvolutionFilterReply>;
+
+ Future<GetConvolutionFilterReply> GetConvolutionFilter(
+ const GetConvolutionFilterRequest& request);
+
+ Future<GetConvolutionFilterReply> GetConvolutionFilter(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& format = {},
+ const uint32_t& type = {},
+ const uint8_t& swap_bytes = {});
+
+ struct GetConvolutionParameterfvRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetConvolutionParameterfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetConvolutionParameterfvResponse =
+ Response<GetConvolutionParameterfvReply>;
+
+ Future<GetConvolutionParameterfvReply> GetConvolutionParameterfv(
+ const GetConvolutionParameterfvRequest& request);
+
+ Future<GetConvolutionParameterfvReply> GetConvolutionParameterfv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetConvolutionParameterivRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetConvolutionParameterivReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetConvolutionParameterivResponse =
+ Response<GetConvolutionParameterivReply>;
+
+ Future<GetConvolutionParameterivReply> GetConvolutionParameteriv(
+ const GetConvolutionParameterivRequest& request);
+
+ Future<GetConvolutionParameterivReply> GetConvolutionParameteriv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetSeparableFilterRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t format{};
+ uint32_t type{};
+ uint8_t swap_bytes{};
+ };
+
+ struct GetSeparableFilterReply {
+ uint16_t sequence{};
+ int32_t row_w{};
+ int32_t col_h{};
+ std::vector<uint8_t> rows_and_cols{};
+ };
+
+ using GetSeparableFilterResponse = Response<GetSeparableFilterReply>;
+
+ Future<GetSeparableFilterReply> GetSeparableFilter(
+ const GetSeparableFilterRequest& request);
+
+ Future<GetSeparableFilterReply> GetSeparableFilter(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& format = {},
+ const uint32_t& type = {},
+ const uint8_t& swap_bytes = {});
+
+ struct GetHistogramRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t format{};
+ uint32_t type{};
+ uint8_t swap_bytes{};
+ uint8_t reset{};
+ };
+
+ struct GetHistogramReply {
+ uint16_t sequence{};
+ int32_t width{};
+ std::vector<uint8_t> data{};
+ };
+
+ using GetHistogramResponse = Response<GetHistogramReply>;
+
+ Future<GetHistogramReply> GetHistogram(const GetHistogramRequest& request);
+
+ Future<GetHistogramReply> GetHistogram(const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& format = {},
+ const uint32_t& type = {},
+ const uint8_t& swap_bytes = {},
+ const uint8_t& reset = {});
+
+ struct GetHistogramParameterfvRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetHistogramParameterfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetHistogramParameterfvResponse =
+ Response<GetHistogramParameterfvReply>;
+
+ Future<GetHistogramParameterfvReply> GetHistogramParameterfv(
+ const GetHistogramParameterfvRequest& request);
+
+ Future<GetHistogramParameterfvReply> GetHistogramParameterfv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetHistogramParameterivRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetHistogramParameterivReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetHistogramParameterivResponse =
+ Response<GetHistogramParameterivReply>;
+
+ Future<GetHistogramParameterivReply> GetHistogramParameteriv(
+ const GetHistogramParameterivRequest& request);
+
+ Future<GetHistogramParameterivReply> GetHistogramParameteriv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetMinmaxRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t format{};
+ uint32_t type{};
+ uint8_t swap_bytes{};
+ uint8_t reset{};
+ };
+
+ struct GetMinmaxReply {
+ uint16_t sequence{};
+ std::vector<uint8_t> data{};
+ };
+
+ using GetMinmaxResponse = Response<GetMinmaxReply>;
+
+ Future<GetMinmaxReply> GetMinmax(const GetMinmaxRequest& request);
+
+ Future<GetMinmaxReply> GetMinmax(const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& format = {},
+ const uint32_t& type = {},
+ const uint8_t& swap_bytes = {},
+ const uint8_t& reset = {});
+
+ struct GetMinmaxParameterfvRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetMinmaxParameterfvReply {
+ uint16_t sequence{};
+ float datum{};
+ std::vector<float> data{};
+ };
+
+ using GetMinmaxParameterfvResponse = Response<GetMinmaxParameterfvReply>;
+
+ Future<GetMinmaxParameterfvReply> GetMinmaxParameterfv(
+ const GetMinmaxParameterfvRequest& request);
+
+ Future<GetMinmaxParameterfvReply> GetMinmaxParameterfv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetMinmaxParameterivRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetMinmaxParameterivReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetMinmaxParameterivResponse = Response<GetMinmaxParameterivReply>;
+
+ Future<GetMinmaxParameterivReply> GetMinmaxParameteriv(
+ const GetMinmaxParameterivRequest& request);
+
+ Future<GetMinmaxParameterivReply> GetMinmaxParameteriv(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetCompressedTexImageARBRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ int32_t level{};
+ };
+
+ struct GetCompressedTexImageARBReply {
+ uint16_t sequence{};
+ int32_t size{};
+ std::vector<uint8_t> data{};
+ };
+
+ using GetCompressedTexImageARBResponse =
+ Response<GetCompressedTexImageARBReply>;
+
+ Future<GetCompressedTexImageARBReply> GetCompressedTexImageARB(
+ const GetCompressedTexImageARBRequest& request);
+
+ Future<GetCompressedTexImageARBReply> GetCompressedTexImageARB(
+ const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const int32_t& level = {});
+
+ struct DeleteQueriesARBRequest {
+ ContextTag context_tag{};
+ std::vector<uint32_t> ids{};
+ };
+
+ using DeleteQueriesARBResponse = Response<void>;
+
+ Future<void> DeleteQueriesARB(const DeleteQueriesARBRequest& request);
+
+ Future<void> DeleteQueriesARB(const ContextTag& context_tag = {},
+ const std::vector<uint32_t>& ids = {});
+
+ struct GenQueriesARBRequest {
+ ContextTag context_tag{};
+ int32_t n{};
+ };
+
+ struct GenQueriesARBReply {
+ uint16_t sequence{};
+ std::vector<uint32_t> data{};
+ };
+
+ using GenQueriesARBResponse = Response<GenQueriesARBReply>;
+
+ Future<GenQueriesARBReply> GenQueriesARB(const GenQueriesARBRequest& request);
+
+ Future<GenQueriesARBReply> GenQueriesARB(const ContextTag& context_tag = {},
+ const int32_t& n = {});
+
+ struct IsQueryARBRequest {
+ ContextTag context_tag{};
+ uint32_t id{};
+ };
+
+ struct IsQueryARBReply {
+ uint16_t sequence{};
+ Bool32 ret_val{};
+ };
+
+ using IsQueryARBResponse = Response<IsQueryARBReply>;
+
+ Future<IsQueryARBReply> IsQueryARB(const IsQueryARBRequest& request);
+
+ Future<IsQueryARBReply> IsQueryARB(const ContextTag& context_tag = {},
+ const uint32_t& id = {});
+
+ struct GetQueryivARBRequest {
+ ContextTag context_tag{};
+ uint32_t target{};
+ uint32_t pname{};
+ };
+
+ struct GetQueryivARBReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetQueryivARBResponse = Response<GetQueryivARBReply>;
+
+ Future<GetQueryivARBReply> GetQueryivARB(const GetQueryivARBRequest& request);
+
+ Future<GetQueryivARBReply> GetQueryivARB(const ContextTag& context_tag = {},
+ const uint32_t& target = {},
+ const uint32_t& pname = {});
+
+ struct GetQueryObjectivARBRequest {
+ ContextTag context_tag{};
+ uint32_t id{};
+ uint32_t pname{};
+ };
+
+ struct GetQueryObjectivARBReply {
+ uint16_t sequence{};
+ int32_t datum{};
+ std::vector<int32_t> data{};
+ };
+
+ using GetQueryObjectivARBResponse = Response<GetQueryObjectivARBReply>;
+
+ Future<GetQueryObjectivARBReply> GetQueryObjectivARB(
+ const GetQueryObjectivARBRequest& request);
+
+ Future<GetQueryObjectivARBReply> GetQueryObjectivARB(
+ const ContextTag& context_tag = {},
+ const uint32_t& id = {},
+ const uint32_t& pname = {});
+
+ struct GetQueryObjectuivARBRequest {
+ ContextTag context_tag{};
+ uint32_t id{};
+ uint32_t pname{};
+ };
+
+ struct GetQueryObjectuivARBReply {
+ uint16_t sequence{};
+ uint32_t datum{};
+ std::vector<uint32_t> data{};
+ };
+
+ using GetQueryObjectuivARBResponse = Response<GetQueryObjectuivARBReply>;
+
+ Future<GetQueryObjectuivARBReply> GetQueryObjectuivARB(
+ const GetQueryObjectuivARBRequest& request);
+
+ Future<GetQueryObjectuivARBReply> GetQueryObjectuivARB(
+ const ContextTag& context_tag = {},
+ const uint32_t& id = {},
+ const uint32_t& pname = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Glx::Pbcet operator|(x11::Glx::Pbcet l,
+ x11::Glx::Pbcet r) {
+ using T = std::underlying_type_t<x11::Glx::Pbcet>;
+ return static_cast<x11::Glx::Pbcet>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Glx::Pbcet operator&(x11::Glx::Pbcet l,
+ x11::Glx::Pbcet r) {
+ using T = std::underlying_type_t<x11::Glx::Pbcet>;
+ return static_cast<x11::Glx::Pbcet>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Glx::Pbcdt operator|(x11::Glx::Pbcdt l,
+ x11::Glx::Pbcdt r) {
+ using T = std::underlying_type_t<x11::Glx::Pbcdt>;
+ return static_cast<x11::Glx::Pbcdt>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Glx::Pbcdt operator&(x11::Glx::Pbcdt l,
+ x11::Glx::Pbcdt r) {
+ using T = std::underlying_type_t<x11::Glx::Pbcdt>;
+ return static_cast<x11::Glx::Pbcdt>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Glx::GraphicsContextAttribute operator|(
+ x11::Glx::GraphicsContextAttribute l,
+ x11::Glx::GraphicsContextAttribute r) {
+ using T = std::underlying_type_t<x11::Glx::GraphicsContextAttribute>;
+ return static_cast<x11::Glx::GraphicsContextAttribute>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Glx::GraphicsContextAttribute operator&(
+ x11::Glx::GraphicsContextAttribute l,
+ x11::Glx::GraphicsContextAttribute r) {
+ using T = std::underlying_type_t<x11::Glx::GraphicsContextAttribute>;
+ return static_cast<x11::Glx::GraphicsContextAttribute>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Glx::Rm operator|(x11::Glx::Rm l, x11::Glx::Rm r) {
+ using T = std::underlying_type_t<x11::Glx::Rm>;
+ return static_cast<x11::Glx::Rm>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Glx::Rm operator&(x11::Glx::Rm l, x11::Glx::Rm r) {
+ using T = std::underlying_type_t<x11::Glx::Rm>;
+ return static_cast<x11::Glx::Rm>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_GLX_H_
diff --git a/chromium/ui/gfx/x/generated_protos/present.cc b/chromium/ui/gfx/x/generated_protos/present.cc
new file mode 100644
index 00000000000..b4edda68ec5
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/present.cc
@@ -0,0 +1,825 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "present.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Present::Present(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Present::GenericEvent>(Present::GenericEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& extension = (*event_).extension;
+ auto& sequence = (*event_).sequence;
+ auto& length = (*event_).length;
+ auto& evtype = (*event_).evtype;
+ auto& event = (*event_).event;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ Read(&length, &buf);
+
+ // evtype
+ Read(&evtype, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // event
+ Read(&event, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Present::ConfigureNotifyEvent>(
+ Present::ConfigureNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event = (*event_).event;
+ auto& window = (*event_).window;
+ auto& x = (*event_).x;
+ auto& y = (*event_).y;
+ auto& width = (*event_).width;
+ auto& height = (*event_).height;
+ auto& off_x = (*event_).off_x;
+ auto& off_y = (*event_).off_y;
+ auto& pixmap_width = (*event_).pixmap_width;
+ auto& pixmap_height = (*event_).pixmap_height;
+ auto& pixmap_flags = (*event_).pixmap_flags;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // event
+ Read(&event, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // off_x
+ Read(&off_x, &buf);
+
+ // off_y
+ Read(&off_y, &buf);
+
+ // pixmap_width
+ Read(&pixmap_width, &buf);
+
+ // pixmap_height
+ Read(&pixmap_height, &buf);
+
+ // pixmap_flags
+ Read(&pixmap_flags, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Present::CompleteNotifyEvent>(
+ Present::CompleteNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& kind = (*event_).kind;
+ auto& mode = (*event_).mode;
+ auto& event = (*event_).event;
+ auto& window = (*event_).window;
+ auto& serial = (*event_).serial;
+ auto& ust = (*event_).ust;
+ auto& msc = (*event_).msc;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // kind
+ uint8_t tmp0;
+ Read(&tmp0, &buf);
+ kind = static_cast<Present::CompleteKind>(tmp0);
+
+ // mode
+ uint8_t tmp1;
+ Read(&tmp1, &buf);
+ mode = static_cast<Present::CompleteMode>(tmp1);
+
+ // event
+ Read(&event, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // serial
+ Read(&serial, &buf);
+
+ // ust
+ Read(&ust, &buf);
+
+ // msc
+ Read(&msc, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Present::IdleNotifyEvent>(Present::IdleNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event = (*event_).event;
+ auto& window = (*event_).window;
+ auto& serial = (*event_).serial;
+ auto& pixmap = (*event_).pixmap;
+ auto& idle_fence = (*event_).idle_fence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // event
+ Read(&event, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // serial
+ Read(&serial, &buf);
+
+ // pixmap
+ Read(&pixmap, &buf);
+
+ // idle_fence
+ Read(&idle_fence, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Present::RedirectNotifyEvent>(
+ Present::RedirectNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& update_window = (*event_).update_window;
+ auto& event = (*event_).event;
+ auto& event_window = (*event_).event_window;
+ auto& window = (*event_).window;
+ auto& pixmap = (*event_).pixmap;
+ auto& serial = (*event_).serial;
+ auto& valid_region = (*event_).valid_region;
+ auto& update_region = (*event_).update_region;
+ auto& valid_rect = (*event_).valid_rect;
+ auto& update_rect = (*event_).update_rect;
+ auto& x_off = (*event_).x_off;
+ auto& y_off = (*event_).y_off;
+ auto& target_crtc = (*event_).target_crtc;
+ auto& wait_fence = (*event_).wait_fence;
+ auto& idle_fence = (*event_).idle_fence;
+ auto& options = (*event_).options;
+ auto& target_msc = (*event_).target_msc;
+ auto& divisor = (*event_).divisor;
+ auto& remainder = (*event_).remainder;
+ auto& notifies = (*event_).notifies;
+ size_t notifies_len = notifies.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // update_window
+ Read(&update_window, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // event
+ Read(&event, &buf);
+
+ // event_window
+ Read(&event_window, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // pixmap
+ Read(&pixmap, &buf);
+
+ // serial
+ Read(&serial, &buf);
+
+ // valid_region
+ Read(&valid_region, &buf);
+
+ // update_region
+ Read(&update_region, &buf);
+
+ // valid_rect
+ {
+ auto& x = valid_rect.x;
+ auto& y = valid_rect.y;
+ auto& width = valid_rect.width;
+ auto& height = valid_rect.height;
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+ }
+
+ // update_rect
+ {
+ auto& x = update_rect.x;
+ auto& y = update_rect.y;
+ auto& width = update_rect.width;
+ auto& height = update_rect.height;
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+ }
+
+ // x_off
+ Read(&x_off, &buf);
+
+ // y_off
+ Read(&y_off, &buf);
+
+ // target_crtc
+ Read(&target_crtc, &buf);
+
+ // wait_fence
+ Read(&wait_fence, &buf);
+
+ // idle_fence
+ Read(&idle_fence, &buf);
+
+ // options
+ Read(&options, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // target_msc
+ Read(&target_msc, &buf);
+
+ // divisor
+ Read(&divisor, &buf);
+
+ // remainder
+ Read(&remainder, &buf);
+
+ // notifies
+ notifies.resize(notifies_len);
+ for (auto& notifies_elem : notifies) {
+ // notifies_elem
+ {
+ auto& window = notifies_elem.window;
+ auto& serial = notifies_elem.serial;
+
+ // window
+ Read(&window, &buf);
+
+ // serial
+ Read(&serial, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+Future<Present::QueryVersionReply> Present::QueryVersion(
+ const Present::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major_version = request.major_version;
+ auto& minor_version = request.minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major_version
+ buf.Write(&major_version);
+
+ // minor_version
+ buf.Write(&minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Present::QueryVersionReply>(
+ &buf, "Present::QueryVersion", false);
+}
+
+Future<Present::QueryVersionReply> Present::QueryVersion(
+ const uint32_t& major_version,
+ const uint32_t& minor_version) {
+ return Present::QueryVersion(
+ Present::QueryVersionRequest{major_version, minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Present::QueryVersionReply> detail::ReadReply<
+ Present::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Present::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Present::PresentPixmap(
+ const Present::PresentPixmapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& pixmap = request.pixmap;
+ auto& serial = request.serial;
+ auto& valid = request.valid;
+ auto& update = request.update;
+ auto& x_off = request.x_off;
+ auto& y_off = request.y_off;
+ auto& target_crtc = request.target_crtc;
+ auto& wait_fence = request.wait_fence;
+ auto& idle_fence = request.idle_fence;
+ auto& options = request.options;
+ auto& target_msc = request.target_msc;
+ auto& divisor = request.divisor;
+ auto& remainder = request.remainder;
+ auto& notifies = request.notifies;
+ size_t notifies_len = notifies.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // pixmap
+ buf.Write(&pixmap);
+
+ // serial
+ buf.Write(&serial);
+
+ // valid
+ buf.Write(&valid);
+
+ // update
+ buf.Write(&update);
+
+ // x_off
+ buf.Write(&x_off);
+
+ // y_off
+ buf.Write(&y_off);
+
+ // target_crtc
+ buf.Write(&target_crtc);
+
+ // wait_fence
+ buf.Write(&wait_fence);
+
+ // idle_fence
+ buf.Write(&idle_fence);
+
+ // options
+ buf.Write(&options);
+
+ // pad0
+ Pad(&buf, 4);
+
+ // target_msc
+ buf.Write(&target_msc);
+
+ // divisor
+ buf.Write(&divisor);
+
+ // remainder
+ buf.Write(&remainder);
+
+ // notifies
+ DCHECK_EQ(static_cast<size_t>(notifies_len), notifies.size());
+ for (auto& notifies_elem : notifies) {
+ // notifies_elem
+ {
+ auto& window = notifies_elem.window;
+ auto& serial = notifies_elem.serial;
+
+ // window
+ buf.Write(&window);
+
+ // serial
+ buf.Write(&serial);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Present::PresentPixmap", false);
+}
+
+Future<void> Present::PresentPixmap(const Window& window,
+ const Pixmap& pixmap,
+ const uint32_t& serial,
+ const XFixes::Region& valid,
+ const XFixes::Region& update,
+ const int16_t& x_off,
+ const int16_t& y_off,
+ const RandR::Crtc& target_crtc,
+ const Sync::Fence& wait_fence,
+ const Sync::Fence& idle_fence,
+ const uint32_t& options,
+ const uint64_t& target_msc,
+ const uint64_t& divisor,
+ const uint64_t& remainder,
+ const std::vector<Notify>& notifies) {
+ return Present::PresentPixmap(Present::PresentPixmapRequest{
+ window, pixmap, serial, valid, update, x_off, y_off, target_crtc,
+ wait_fence, idle_fence, options, target_msc, divisor, remainder,
+ notifies});
+}
+
+Future<void> Present::NotifyMSC(const Present::NotifyMSCRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& serial = request.serial;
+ auto& target_msc = request.target_msc;
+ auto& divisor = request.divisor;
+ auto& remainder = request.remainder;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // serial
+ buf.Write(&serial);
+
+ // pad0
+ Pad(&buf, 4);
+
+ // target_msc
+ buf.Write(&target_msc);
+
+ // divisor
+ buf.Write(&divisor);
+
+ // remainder
+ buf.Write(&remainder);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Present::NotifyMSC", false);
+}
+
+Future<void> Present::NotifyMSC(const Window& window,
+ const uint32_t& serial,
+ const uint64_t& target_msc,
+ const uint64_t& divisor,
+ const uint64_t& remainder) {
+ return Present::NotifyMSC(Present::NotifyMSCRequest{
+ window, serial, target_msc, divisor, remainder});
+}
+
+Future<void> Present::SelectInput(const Present::SelectInputRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& eid = request.eid;
+ auto& window = request.window;
+ auto& event_mask = request.event_mask;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // eid
+ buf.Write(&eid);
+
+ // window
+ buf.Write(&window);
+
+ // event_mask
+ uint32_t tmp2;
+ tmp2 = static_cast<uint32_t>(event_mask);
+ buf.Write(&tmp2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Present::SelectInput", false);
+}
+
+Future<void> Present::SelectInput(const Event& eid,
+ const Window& window,
+ const EventMask& event_mask) {
+ return Present::SelectInput(
+ Present::SelectInputRequest{eid, window, event_mask});
+}
+
+Future<Present::QueryCapabilitiesReply> Present::QueryCapabilities(
+ const Present::QueryCapabilitiesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& target = request.target;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // target
+ buf.Write(&target);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Present::QueryCapabilitiesReply>(
+ &buf, "Present::QueryCapabilities", false);
+}
+
+Future<Present::QueryCapabilitiesReply> Present::QueryCapabilities(
+ const uint32_t& target) {
+ return Present::QueryCapabilities(Present::QueryCapabilitiesRequest{target});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Present::QueryCapabilitiesReply> detail::ReadReply<
+ Present::QueryCapabilitiesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Present::QueryCapabilitiesReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& capabilities = (*reply).capabilities;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // capabilities
+ Read(&capabilities, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/present.h b/chromium/ui/gfx/x/generated_protos/present.h
new file mode 100644
index 00000000000..a77befb0479
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/present.h
@@ -0,0 +1,426 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_PRESENT_H_
+#define UI_GFX_X_GENERATED_PROTOS_PRESENT_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "randr.h"
+#include "sync.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xfixes.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Present {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 2;
+
+ Present(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Event : uint32_t {
+ ConfigureNotify = 0,
+ CompleteNotify = 1,
+ IdleNotify = 2,
+ RedirectNotify = 3,
+ };
+
+ enum class EventMask : int {
+ NoEvent = 0,
+ ConfigureNotify = 1 << 0,
+ CompleteNotify = 1 << 1,
+ IdleNotify = 1 << 2,
+ RedirectNotify = 1 << 3,
+ };
+
+ enum class Option : int {
+ None = 0,
+ Async = 1 << 0,
+ Copy = 1 << 1,
+ UST = 1 << 2,
+ Suboptimal = 1 << 3,
+ };
+
+ enum class Capability : int {
+ None = 0,
+ Async = 1 << 0,
+ Fence = 1 << 1,
+ UST = 1 << 2,
+ };
+
+ enum class CompleteKind : int {
+ Pixmap = 0,
+ NotifyMSC = 1,
+ };
+
+ enum class CompleteMode : int {
+ Copy = 0,
+ Flip = 1,
+ Skip = 2,
+ SuboptimalCopy = 3,
+ };
+
+ struct Notify {
+ Window window{};
+ uint32_t serial{};
+ };
+
+ struct GenericEvent {
+ static constexpr int type_id = 6;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ uint8_t extension{};
+ uint16_t sequence{};
+ uint32_t length{};
+ uint16_t evtype{};
+ Event event{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct ConfigureNotifyEvent {
+ static constexpr int type_id = 7;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ uint16_t sequence{};
+ Event event{};
+ Window window{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ int16_t off_x{};
+ int16_t off_y{};
+ uint16_t pixmap_width{};
+ uint16_t pixmap_height{};
+ uint32_t pixmap_flags{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+ };
+
+ struct CompleteNotifyEvent {
+ static constexpr int type_id = 8;
+ static constexpr uint8_t opcode = 1;
+ bool send_event{};
+ uint16_t sequence{};
+ CompleteKind kind{};
+ CompleteMode mode{};
+ Event event{};
+ Window window{};
+ uint32_t serial{};
+ uint64_t ust{};
+ uint64_t msc{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+ };
+
+ struct IdleNotifyEvent {
+ static constexpr int type_id = 9;
+ static constexpr uint8_t opcode = 2;
+ bool send_event{};
+ uint16_t sequence{};
+ Event event{};
+ Window window{};
+ uint32_t serial{};
+ Pixmap pixmap{};
+ Sync::Fence idle_fence{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+ };
+
+ struct RedirectNotifyEvent {
+ static constexpr int type_id = 10;
+ static constexpr uint8_t opcode = 3;
+ bool send_event{};
+ uint16_t sequence{};
+ uint8_t update_window{};
+ Event event{};
+ Window event_window{};
+ Window window{};
+ Pixmap pixmap{};
+ uint32_t serial{};
+ XFixes::Region valid_region{};
+ XFixes::Region update_region{};
+ Rectangle valid_rect{};
+ Rectangle update_rect{};
+ int16_t x_off{};
+ int16_t y_off{};
+ RandR::Crtc target_crtc{};
+ Sync::Fence wait_fence{};
+ Sync::Fence idle_fence{};
+ uint32_t options{};
+ uint64_t target_msc{};
+ uint64_t divisor{};
+ uint64_t remainder{};
+ std::vector<Notify> notifies{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+ };
+
+ struct QueryVersionRequest {
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(const uint32_t& major_version = {},
+ const uint32_t& minor_version = {});
+
+ struct PresentPixmapRequest {
+ Window window{};
+ Pixmap pixmap{};
+ uint32_t serial{};
+ XFixes::Region valid{};
+ XFixes::Region update{};
+ int16_t x_off{};
+ int16_t y_off{};
+ RandR::Crtc target_crtc{};
+ Sync::Fence wait_fence{};
+ Sync::Fence idle_fence{};
+ uint32_t options{};
+ uint64_t target_msc{};
+ uint64_t divisor{};
+ uint64_t remainder{};
+ std::vector<Notify> notifies{};
+ };
+
+ using PresentPixmapResponse = Response<void>;
+
+ Future<void> PresentPixmap(const PresentPixmapRequest& request);
+
+ Future<void> PresentPixmap(const Window& window = {},
+ const Pixmap& pixmap = {},
+ const uint32_t& serial = {},
+ const XFixes::Region& valid = {},
+ const XFixes::Region& update = {},
+ const int16_t& x_off = {},
+ const int16_t& y_off = {},
+ const RandR::Crtc& target_crtc = {},
+ const Sync::Fence& wait_fence = {},
+ const Sync::Fence& idle_fence = {},
+ const uint32_t& options = {},
+ const uint64_t& target_msc = {},
+ const uint64_t& divisor = {},
+ const uint64_t& remainder = {},
+ const std::vector<Notify>& notifies = {});
+
+ struct NotifyMSCRequest {
+ Window window{};
+ uint32_t serial{};
+ uint64_t target_msc{};
+ uint64_t divisor{};
+ uint64_t remainder{};
+ };
+
+ using NotifyMSCResponse = Response<void>;
+
+ Future<void> NotifyMSC(const NotifyMSCRequest& request);
+
+ Future<void> NotifyMSC(const Window& window = {},
+ const uint32_t& serial = {},
+ const uint64_t& target_msc = {},
+ const uint64_t& divisor = {},
+ const uint64_t& remainder = {});
+
+ struct SelectInputRequest {
+ Event eid{};
+ Window window{};
+ EventMask event_mask{};
+ };
+
+ using SelectInputResponse = Response<void>;
+
+ Future<void> SelectInput(const SelectInputRequest& request);
+
+ Future<void> SelectInput(const Event& eid = {},
+ const Window& window = {},
+ const EventMask& event_mask = {});
+
+ struct QueryCapabilitiesRequest {
+ uint32_t target{};
+ };
+
+ struct QueryCapabilitiesReply {
+ uint16_t sequence{};
+ uint32_t capabilities{};
+ };
+
+ using QueryCapabilitiesResponse = Response<QueryCapabilitiesReply>;
+
+ Future<QueryCapabilitiesReply> QueryCapabilities(
+ const QueryCapabilitiesRequest& request);
+
+ Future<QueryCapabilitiesReply> QueryCapabilities(const uint32_t& target = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Present::Event operator|(x11::Present::Event l,
+ x11::Present::Event r) {
+ using T = std::underlying_type_t<x11::Present::Event>;
+ return static_cast<x11::Present::Event>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Present::Event operator&(x11::Present::Event l,
+ x11::Present::Event r) {
+ using T = std::underlying_type_t<x11::Present::Event>;
+ return static_cast<x11::Present::Event>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Present::EventMask operator|(x11::Present::EventMask l,
+ x11::Present::EventMask r) {
+ using T = std::underlying_type_t<x11::Present::EventMask>;
+ return static_cast<x11::Present::EventMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Present::EventMask operator&(x11::Present::EventMask l,
+ x11::Present::EventMask r) {
+ using T = std::underlying_type_t<x11::Present::EventMask>;
+ return static_cast<x11::Present::EventMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Present::Option operator|(x11::Present::Option l,
+ x11::Present::Option r) {
+ using T = std::underlying_type_t<x11::Present::Option>;
+ return static_cast<x11::Present::Option>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Present::Option operator&(x11::Present::Option l,
+ x11::Present::Option r) {
+ using T = std::underlying_type_t<x11::Present::Option>;
+ return static_cast<x11::Present::Option>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Present::Capability operator|(
+ x11::Present::Capability l,
+ x11::Present::Capability r) {
+ using T = std::underlying_type_t<x11::Present::Capability>;
+ return static_cast<x11::Present::Capability>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Present::Capability operator&(
+ x11::Present::Capability l,
+ x11::Present::Capability r) {
+ using T = std::underlying_type_t<x11::Present::Capability>;
+ return static_cast<x11::Present::Capability>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Present::CompleteKind operator|(
+ x11::Present::CompleteKind l,
+ x11::Present::CompleteKind r) {
+ using T = std::underlying_type_t<x11::Present::CompleteKind>;
+ return static_cast<x11::Present::CompleteKind>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Present::CompleteKind operator&(
+ x11::Present::CompleteKind l,
+ x11::Present::CompleteKind r) {
+ using T = std::underlying_type_t<x11::Present::CompleteKind>;
+ return static_cast<x11::Present::CompleteKind>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Present::CompleteMode operator|(
+ x11::Present::CompleteMode l,
+ x11::Present::CompleteMode r) {
+ using T = std::underlying_type_t<x11::Present::CompleteMode>;
+ return static_cast<x11::Present::CompleteMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Present::CompleteMode operator&(
+ x11::Present::CompleteMode l,
+ x11::Present::CompleteMode r) {
+ using T = std::underlying_type_t<x11::Present::CompleteMode>;
+ return static_cast<x11::Present::CompleteMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_PRESENT_H_
diff --git a/chromium/ui/gfx/x/generated_protos/randr.cc b/chromium/ui/gfx/x/generated_protos/randr.cc
new file mode 100644
index 00000000000..7228c86c763
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/randr.cc
@@ -0,0 +1,4599 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "randr.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+RandR::RandR(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+std::string RandR::BadOutputError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "RandR::BadOutputError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<RandR::BadOutputError>(RandR::BadOutputError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string RandR::BadCrtcError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "RandR::BadCrtcError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<RandR::BadCrtcError>(RandR::BadCrtcError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string RandR::BadModeError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "RandR::BadModeError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<RandR::BadModeError>(RandR::BadModeError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string RandR::BadProviderError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "RandR::BadProviderError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<RandR::BadProviderError>(RandR::BadProviderError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<RandR::ScreenChangeNotifyEvent>(
+ RandR::ScreenChangeNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& rotation = (*event_).rotation;
+ auto& sequence = (*event_).sequence;
+ auto& timestamp = (*event_).timestamp;
+ auto& config_timestamp = (*event_).config_timestamp;
+ auto& root = (*event_).root;
+ auto& request_window = (*event_).request_window;
+ auto& sizeID = (*event_).sizeID;
+ auto& subpixel_order = (*event_).subpixel_order;
+ auto& width = (*event_).width;
+ auto& height = (*event_).height;
+ auto& mwidth = (*event_).mwidth;
+ auto& mheight = (*event_).mheight;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // rotation
+ uint8_t tmp0;
+ Read(&tmp0, &buf);
+ rotation = static_cast<RandR::Rotation>(tmp0);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // config_timestamp
+ Read(&config_timestamp, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // request_window
+ Read(&request_window, &buf);
+
+ // sizeID
+ Read(&sizeID, &buf);
+
+ // subpixel_order
+ uint16_t tmp1;
+ Read(&tmp1, &buf);
+ subpixel_order = static_cast<Render::SubPixel>(tmp1);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // mwidth
+ Read(&mwidth, &buf);
+
+ // mheight
+ Read(&mheight, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<RandR::NotifyEvent>(RandR::NotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ RandR::Notify subCode{};
+ auto& sequence = (*event_).sequence;
+ auto& data = (*event_);
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // subCode
+ uint8_t tmp2;
+ Read(&tmp2, &buf);
+ subCode = static_cast<RandR::Notify>(tmp2);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // data
+ auto data_expr = subCode;
+ if (CaseEq(data_expr, RandR::Notify::CrtcChange)) {
+ data.cc.emplace();
+ auto& timestamp = (*data.cc).timestamp;
+ auto& window = (*data.cc).window;
+ auto& crtc = (*data.cc).crtc;
+ auto& mode = (*data.cc).mode;
+ auto& rotation = (*data.cc).rotation;
+ auto& x = (*data.cc).x;
+ auto& y = (*data.cc).y;
+ auto& width = (*data.cc).width;
+ auto& height = (*data.cc).height;
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // crtc
+ Read(&crtc, &buf);
+
+ // mode
+ Read(&mode, &buf);
+
+ // rotation
+ uint16_t tmp3;
+ Read(&tmp3, &buf);
+ rotation = static_cast<RandR::Rotation>(tmp3);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+ }
+ if (CaseEq(data_expr, RandR::Notify::OutputChange)) {
+ data.oc.emplace();
+ auto& timestamp = (*data.oc).timestamp;
+ auto& config_timestamp = (*data.oc).config_timestamp;
+ auto& window = (*data.oc).window;
+ auto& output = (*data.oc).output;
+ auto& crtc = (*data.oc).crtc;
+ auto& mode = (*data.oc).mode;
+ auto& rotation = (*data.oc).rotation;
+ auto& connection = (*data.oc).connection;
+ auto& subpixel_order = (*data.oc).subpixel_order;
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // config_timestamp
+ Read(&config_timestamp, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // output
+ Read(&output, &buf);
+
+ // crtc
+ Read(&crtc, &buf);
+
+ // mode
+ Read(&mode, &buf);
+
+ // rotation
+ uint16_t tmp4;
+ Read(&tmp4, &buf);
+ rotation = static_cast<RandR::Rotation>(tmp4);
+
+ // connection
+ uint8_t tmp5;
+ Read(&tmp5, &buf);
+ connection = static_cast<RandR::RandRConnection>(tmp5);
+
+ // subpixel_order
+ uint8_t tmp6;
+ Read(&tmp6, &buf);
+ subpixel_order = static_cast<Render::SubPixel>(tmp6);
+ }
+ if (CaseEq(data_expr, RandR::Notify::OutputProperty)) {
+ data.op.emplace();
+ auto& window = (*data.op).window;
+ auto& output = (*data.op).output;
+ auto& atom = (*data.op).atom;
+ auto& timestamp = (*data.op).timestamp;
+ auto& status = (*data.op).status;
+
+ // window
+ Read(&window, &buf);
+
+ // output
+ Read(&output, &buf);
+
+ // atom
+ Read(&atom, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // status
+ uint8_t tmp7;
+ Read(&tmp7, &buf);
+ status = static_cast<Property>(tmp7);
+
+ // pad1
+ Pad(&buf, 11);
+ }
+ if (CaseEq(data_expr, RandR::Notify::ProviderChange)) {
+ data.pc.emplace();
+ auto& timestamp = (*data.pc).timestamp;
+ auto& window = (*data.pc).window;
+ auto& provider = (*data.pc).provider;
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // provider
+ Read(&provider, &buf);
+
+ // pad2
+ Pad(&buf, 16);
+ }
+ if (CaseEq(data_expr, RandR::Notify::ProviderProperty)) {
+ data.pp.emplace();
+ auto& window = (*data.pp).window;
+ auto& provider = (*data.pp).provider;
+ auto& atom = (*data.pp).atom;
+ auto& timestamp = (*data.pp).timestamp;
+ auto& state = (*data.pp).state;
+
+ // window
+ Read(&window, &buf);
+
+ // provider
+ Read(&provider, &buf);
+
+ // atom
+ Read(&atom, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // state
+ Read(&state, &buf);
+
+ // pad3
+ Pad(&buf, 11);
+ }
+ if (CaseEq(data_expr, RandR::Notify::ResourceChange)) {
+ data.rc.emplace();
+ auto& timestamp = (*data.rc).timestamp;
+ auto& window = (*data.rc).window;
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // pad4
+ Pad(&buf, 20);
+ }
+ if (CaseEq(data_expr, RandR::Notify::Lease)) {
+ data.lc.emplace();
+ auto& timestamp = (*data.lc).timestamp;
+ auto& window = (*data.lc).window;
+ auto& lease = (*data.lc).lease;
+ auto& created = (*data.lc).created;
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // lease
+ Read(&lease, &buf);
+
+ // created
+ Read(&created, &buf);
+
+ // pad5
+ Pad(&buf, 15);
+ }
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+Future<RandR::QueryVersionReply> RandR::QueryVersion(
+ const RandR::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major_version = request.major_version;
+ auto& minor_version = request.minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major_version
+ buf.Write(&major_version);
+
+ // minor_version
+ buf.Write(&minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::QueryVersionReply>(
+ &buf, "RandR::QueryVersion", false);
+}
+
+Future<RandR::QueryVersionReply> RandR::QueryVersion(
+ const uint32_t& major_version,
+ const uint32_t& minor_version) {
+ return RandR::QueryVersion(
+ RandR::QueryVersionRequest{major_version, minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::QueryVersionReply> detail::ReadReply<
+ RandR::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::SetScreenConfigReply> RandR::SetScreenConfig(
+ const RandR::SetScreenConfigRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& timestamp = request.timestamp;
+ auto& config_timestamp = request.config_timestamp;
+ auto& sizeID = request.sizeID;
+ auto& rotation = request.rotation;
+ auto& rate = request.rate;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // timestamp
+ buf.Write(&timestamp);
+
+ // config_timestamp
+ buf.Write(&config_timestamp);
+
+ // sizeID
+ buf.Write(&sizeID);
+
+ // rotation
+ uint16_t tmp8;
+ tmp8 = static_cast<uint16_t>(rotation);
+ buf.Write(&tmp8);
+
+ // rate
+ buf.Write(&rate);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::SetScreenConfigReply>(
+ &buf, "RandR::SetScreenConfig", false);
+}
+
+Future<RandR::SetScreenConfigReply> RandR::SetScreenConfig(
+ const Window& window,
+ const Time& timestamp,
+ const Time& config_timestamp,
+ const uint16_t& sizeID,
+ const Rotation& rotation,
+ const uint16_t& rate) {
+ return RandR::SetScreenConfig(RandR::SetScreenConfigRequest{
+ window, timestamp, config_timestamp, sizeID, rotation, rate});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::SetScreenConfigReply> detail::ReadReply<
+ RandR::SetScreenConfigReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::SetScreenConfigReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+ auto& new_timestamp = (*reply).new_timestamp;
+ auto& config_timestamp = (*reply).config_timestamp;
+ auto& root = (*reply).root;
+ auto& subpixel_order = (*reply).subpixel_order;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ uint8_t tmp9;
+ Read(&tmp9, &buf);
+ status = static_cast<RandR::SetConfig>(tmp9);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // new_timestamp
+ Read(&new_timestamp, &buf);
+
+ // config_timestamp
+ Read(&config_timestamp, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // subpixel_order
+ uint16_t tmp10;
+ Read(&tmp10, &buf);
+ subpixel_order = static_cast<Render::SubPixel>(tmp10);
+
+ // pad0
+ Pad(&buf, 10);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> RandR::SelectInput(const RandR::SelectInputRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& enable = request.enable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // enable
+ uint16_t tmp11;
+ tmp11 = static_cast<uint16_t>(enable);
+ buf.Write(&tmp11);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::SelectInput", false);
+}
+
+Future<void> RandR::SelectInput(const Window& window,
+ const NotifyMask& enable) {
+ return RandR::SelectInput(RandR::SelectInputRequest{window, enable});
+}
+
+Future<RandR::GetScreenInfoReply> RandR::GetScreenInfo(
+ const RandR::GetScreenInfoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetScreenInfoReply>(
+ &buf, "RandR::GetScreenInfo", false);
+}
+
+Future<RandR::GetScreenInfoReply> RandR::GetScreenInfo(const Window& window) {
+ return RandR::GetScreenInfo(RandR::GetScreenInfoRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetScreenInfoReply> detail::ReadReply<
+ RandR::GetScreenInfoReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetScreenInfoReply>();
+
+ auto& rotations = (*reply).rotations;
+ auto& sequence = (*reply).sequence;
+ auto& root = (*reply).root;
+ auto& timestamp = (*reply).timestamp;
+ auto& config_timestamp = (*reply).config_timestamp;
+ uint16_t nSizes{};
+ auto& sizeID = (*reply).sizeID;
+ auto& rotation = (*reply).rotation;
+ auto& rate = (*reply).rate;
+ auto& nInfo = (*reply).nInfo;
+ auto& sizes = (*reply).sizes;
+ size_t sizes_len = sizes.size();
+ auto& rates = (*reply).rates;
+ size_t rates_len = rates.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // rotations
+ uint8_t tmp12;
+ Read(&tmp12, &buf);
+ rotations = static_cast<RandR::Rotation>(tmp12);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // config_timestamp
+ Read(&config_timestamp, &buf);
+
+ // nSizes
+ Read(&nSizes, &buf);
+
+ // sizeID
+ Read(&sizeID, &buf);
+
+ // rotation
+ uint16_t tmp13;
+ Read(&tmp13, &buf);
+ rotation = static_cast<RandR::Rotation>(tmp13);
+
+ // rate
+ Read(&rate, &buf);
+
+ // nInfo
+ Read(&nInfo, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // sizes
+ sizes.resize(nSizes);
+ for (auto& sizes_elem : sizes) {
+ // sizes_elem
+ {
+ auto& width = sizes_elem.width;
+ auto& height = sizes_elem.height;
+ auto& mwidth = sizes_elem.mwidth;
+ auto& mheight = sizes_elem.mheight;
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // mwidth
+ Read(&mwidth, &buf);
+
+ // mheight
+ Read(&mheight, &buf);
+ }
+ }
+
+ // rates
+ rates.resize((nInfo) - (nSizes));
+ for (auto& rates_elem : rates) {
+ // rates_elem
+ {
+ uint16_t nRates{};
+ auto& rates = rates_elem.rates;
+ size_t rates_len = rates.size();
+
+ // nRates
+ Read(&nRates, &buf);
+
+ // rates
+ rates.resize(nRates);
+ for (auto& rates_elem : rates) {
+ // rates_elem
+ Read(&rates_elem, &buf);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::GetScreenSizeRangeReply> RandR::GetScreenSizeRange(
+ const RandR::GetScreenSizeRangeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetScreenSizeRangeReply>(
+ &buf, "RandR::GetScreenSizeRange", false);
+}
+
+Future<RandR::GetScreenSizeRangeReply> RandR::GetScreenSizeRange(
+ const Window& window) {
+ return RandR::GetScreenSizeRange(RandR::GetScreenSizeRangeRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetScreenSizeRangeReply> detail::ReadReply<
+ RandR::GetScreenSizeRangeReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetScreenSizeRangeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& min_width = (*reply).min_width;
+ auto& min_height = (*reply).min_height;
+ auto& max_width = (*reply).max_width;
+ auto& max_height = (*reply).max_height;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // min_width
+ Read(&min_width, &buf);
+
+ // min_height
+ Read(&min_height, &buf);
+
+ // max_width
+ Read(&max_width, &buf);
+
+ // max_height
+ Read(&max_height, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> RandR::SetScreenSize(const RandR::SetScreenSizeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& mm_width = request.mm_width;
+ auto& mm_height = request.mm_height;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // mm_width
+ buf.Write(&mm_width);
+
+ // mm_height
+ buf.Write(&mm_height);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::SetScreenSize", false);
+}
+
+Future<void> RandR::SetScreenSize(const Window& window,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint32_t& mm_width,
+ const uint32_t& mm_height) {
+ return RandR::SetScreenSize(
+ RandR::SetScreenSizeRequest{window, width, height, mm_width, mm_height});
+}
+
+Future<RandR::GetScreenResourcesReply> RandR::GetScreenResources(
+ const RandR::GetScreenResourcesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetScreenResourcesReply>(
+ &buf, "RandR::GetScreenResources", false);
+}
+
+Future<RandR::GetScreenResourcesReply> RandR::GetScreenResources(
+ const Window& window) {
+ return RandR::GetScreenResources(RandR::GetScreenResourcesRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetScreenResourcesReply> detail::ReadReply<
+ RandR::GetScreenResourcesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetScreenResourcesReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& timestamp = (*reply).timestamp;
+ auto& config_timestamp = (*reply).config_timestamp;
+ uint16_t num_crtcs{};
+ uint16_t num_outputs{};
+ uint16_t num_modes{};
+ uint16_t names_len{};
+ auto& crtcs = (*reply).crtcs;
+ size_t crtcs_len = crtcs.size();
+ auto& outputs = (*reply).outputs;
+ size_t outputs_len = outputs.size();
+ auto& modes = (*reply).modes;
+ size_t modes_len = modes.size();
+ auto& names = (*reply).names;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // config_timestamp
+ Read(&config_timestamp, &buf);
+
+ // num_crtcs
+ Read(&num_crtcs, &buf);
+
+ // num_outputs
+ Read(&num_outputs, &buf);
+
+ // num_modes
+ Read(&num_modes, &buf);
+
+ // names_len
+ Read(&names_len, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // crtcs
+ crtcs.resize(num_crtcs);
+ for (auto& crtcs_elem : crtcs) {
+ // crtcs_elem
+ Read(&crtcs_elem, &buf);
+ }
+
+ // outputs
+ outputs.resize(num_outputs);
+ for (auto& outputs_elem : outputs) {
+ // outputs_elem
+ Read(&outputs_elem, &buf);
+ }
+
+ // modes
+ modes.resize(num_modes);
+ for (auto& modes_elem : modes) {
+ // modes_elem
+ {
+ auto& id = modes_elem.id;
+ auto& width = modes_elem.width;
+ auto& height = modes_elem.height;
+ auto& dot_clock = modes_elem.dot_clock;
+ auto& hsync_start = modes_elem.hsync_start;
+ auto& hsync_end = modes_elem.hsync_end;
+ auto& htotal = modes_elem.htotal;
+ auto& hskew = modes_elem.hskew;
+ auto& vsync_start = modes_elem.vsync_start;
+ auto& vsync_end = modes_elem.vsync_end;
+ auto& vtotal = modes_elem.vtotal;
+ auto& name_len = modes_elem.name_len;
+ auto& mode_flags = modes_elem.mode_flags;
+
+ // id
+ Read(&id, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // dot_clock
+ Read(&dot_clock, &buf);
+
+ // hsync_start
+ Read(&hsync_start, &buf);
+
+ // hsync_end
+ Read(&hsync_end, &buf);
+
+ // htotal
+ Read(&htotal, &buf);
+
+ // hskew
+ Read(&hskew, &buf);
+
+ // vsync_start
+ Read(&vsync_start, &buf);
+
+ // vsync_end
+ Read(&vsync_end, &buf);
+
+ // vtotal
+ Read(&vtotal, &buf);
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // mode_flags
+ uint32_t tmp14;
+ Read(&tmp14, &buf);
+ mode_flags = static_cast<RandR::ModeFlag>(tmp14);
+ }
+ }
+
+ // names
+ names.resize(names_len);
+ for (auto& names_elem : names) {
+ // names_elem
+ Read(&names_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::GetOutputInfoReply> RandR::GetOutputInfo(
+ const RandR::GetOutputInfoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& output = request.output;
+ auto& config_timestamp = request.config_timestamp;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // output
+ buf.Write(&output);
+
+ // config_timestamp
+ buf.Write(&config_timestamp);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetOutputInfoReply>(
+ &buf, "RandR::GetOutputInfo", false);
+}
+
+Future<RandR::GetOutputInfoReply> RandR::GetOutputInfo(
+ const Output& output,
+ const Time& config_timestamp) {
+ return RandR::GetOutputInfo(
+ RandR::GetOutputInfoRequest{output, config_timestamp});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetOutputInfoReply> detail::ReadReply<
+ RandR::GetOutputInfoReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetOutputInfoReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+ auto& timestamp = (*reply).timestamp;
+ auto& crtc = (*reply).crtc;
+ auto& mm_width = (*reply).mm_width;
+ auto& mm_height = (*reply).mm_height;
+ auto& connection = (*reply).connection;
+ auto& subpixel_order = (*reply).subpixel_order;
+ uint16_t num_crtcs{};
+ uint16_t num_modes{};
+ auto& num_preferred = (*reply).num_preferred;
+ uint16_t num_clones{};
+ uint16_t name_len{};
+ auto& crtcs = (*reply).crtcs;
+ size_t crtcs_len = crtcs.size();
+ auto& modes = (*reply).modes;
+ size_t modes_len = modes.size();
+ auto& clones = (*reply).clones;
+ size_t clones_len = clones.size();
+ auto& name = (*reply).name;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ uint8_t tmp15;
+ Read(&tmp15, &buf);
+ status = static_cast<RandR::SetConfig>(tmp15);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // crtc
+ Read(&crtc, &buf);
+
+ // mm_width
+ Read(&mm_width, &buf);
+
+ // mm_height
+ Read(&mm_height, &buf);
+
+ // connection
+ uint8_t tmp16;
+ Read(&tmp16, &buf);
+ connection = static_cast<RandR::RandRConnection>(tmp16);
+
+ // subpixel_order
+ uint8_t tmp17;
+ Read(&tmp17, &buf);
+ subpixel_order = static_cast<Render::SubPixel>(tmp17);
+
+ // num_crtcs
+ Read(&num_crtcs, &buf);
+
+ // num_modes
+ Read(&num_modes, &buf);
+
+ // num_preferred
+ Read(&num_preferred, &buf);
+
+ // num_clones
+ Read(&num_clones, &buf);
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // crtcs
+ crtcs.resize(num_crtcs);
+ for (auto& crtcs_elem : crtcs) {
+ // crtcs_elem
+ Read(&crtcs_elem, &buf);
+ }
+
+ // modes
+ modes.resize(num_modes);
+ for (auto& modes_elem : modes) {
+ // modes_elem
+ Read(&modes_elem, &buf);
+ }
+
+ // clones
+ clones.resize(num_clones);
+ for (auto& clones_elem : clones) {
+ // clones_elem
+ Read(&clones_elem, &buf);
+ }
+
+ // name
+ name.resize(name_len);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::ListOutputPropertiesReply> RandR::ListOutputProperties(
+ const RandR::ListOutputPropertiesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& output = request.output;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // output
+ buf.Write(&output);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::ListOutputPropertiesReply>(
+ &buf, "RandR::ListOutputProperties", false);
+}
+
+Future<RandR::ListOutputPropertiesReply> RandR::ListOutputProperties(
+ const Output& output) {
+ return RandR::ListOutputProperties(
+ RandR::ListOutputPropertiesRequest{output});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::ListOutputPropertiesReply> detail::ReadReply<
+ RandR::ListOutputPropertiesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::ListOutputPropertiesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t num_atoms{};
+ auto& atoms = (*reply).atoms;
+ size_t atoms_len = atoms.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_atoms
+ Read(&num_atoms, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // atoms
+ atoms.resize(num_atoms);
+ for (auto& atoms_elem : atoms) {
+ // atoms_elem
+ Read(&atoms_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::QueryOutputPropertyReply> RandR::QueryOutputProperty(
+ const RandR::QueryOutputPropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& output = request.output;
+ auto& property = request.property;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // output
+ buf.Write(&output);
+
+ // property
+ buf.Write(&property);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::QueryOutputPropertyReply>(
+ &buf, "RandR::QueryOutputProperty", false);
+}
+
+Future<RandR::QueryOutputPropertyReply> RandR::QueryOutputProperty(
+ const Output& output,
+ const Atom& property) {
+ return RandR::QueryOutputProperty(
+ RandR::QueryOutputPropertyRequest{output, property});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::QueryOutputPropertyReply> detail::ReadReply<
+ RandR::QueryOutputPropertyReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::QueryOutputPropertyReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& pending = (*reply).pending;
+ auto& range = (*reply).range;
+ auto& immutable = (*reply).immutable;
+ auto& validValues = (*reply).validValues;
+ size_t validValues_len = validValues.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pending
+ Read(&pending, &buf);
+
+ // range
+ Read(&range, &buf);
+
+ // immutable
+ Read(&immutable, &buf);
+
+ // pad1
+ Pad(&buf, 21);
+
+ // validValues
+ validValues.resize(length);
+ for (auto& validValues_elem : validValues) {
+ // validValues_elem
+ Read(&validValues_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> RandR::ConfigureOutputProperty(
+ const RandR::ConfigureOutputPropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& output = request.output;
+ auto& property = request.property;
+ auto& pending = request.pending;
+ auto& range = request.range;
+ auto& values = request.values;
+ size_t values_len = values.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // output
+ buf.Write(&output);
+
+ // property
+ buf.Write(&property);
+
+ // pending
+ buf.Write(&pending);
+
+ // range
+ buf.Write(&range);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // values
+ DCHECK_EQ(static_cast<size_t>(values_len), values.size());
+ for (auto& values_elem : values) {
+ // values_elem
+ buf.Write(&values_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::ConfigureOutputProperty",
+ false);
+}
+
+Future<void> RandR::ConfigureOutputProperty(
+ const Output& output,
+ const Atom& property,
+ const uint8_t& pending,
+ const uint8_t& range,
+ const std::vector<int32_t>& values) {
+ return RandR::ConfigureOutputProperty(RandR::ConfigureOutputPropertyRequest{
+ output, property, pending, range, values});
+}
+
+Future<void> RandR::ChangeOutputProperty(
+ const RandR::ChangeOutputPropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& output = request.output;
+ auto& property = request.property;
+ auto& type = request.type;
+ auto& format = request.format;
+ auto& mode = request.mode;
+ auto& num_units = request.num_units;
+ auto& data = request.data;
+ size_t data_len = data ? data->size() : 0;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // output
+ buf.Write(&output);
+
+ // property
+ buf.Write(&property);
+
+ // type
+ buf.Write(&type);
+
+ // format
+ buf.Write(&format);
+
+ // mode
+ uint8_t tmp18;
+ tmp18 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp18);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // num_units
+ buf.Write(&num_units);
+
+ // data
+ buf.AppendBuffer(data, ((num_units) * (format)) / (8));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::ChangeOutputProperty",
+ false);
+}
+
+Future<void> RandR::ChangeOutputProperty(
+ const Output& output,
+ const Atom& property,
+ const Atom& type,
+ const uint8_t& format,
+ const PropMode& mode,
+ const uint32_t& num_units,
+ const scoped_refptr<base::RefCountedMemory>& data) {
+ return RandR::ChangeOutputProperty(RandR::ChangeOutputPropertyRequest{
+ output, property, type, format, mode, num_units, data});
+}
+
+Future<void> RandR::DeleteOutputProperty(
+ const RandR::DeleteOutputPropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& output = request.output;
+ auto& property = request.property;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 14;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // output
+ buf.Write(&output);
+
+ // property
+ buf.Write(&property);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::DeleteOutputProperty",
+ false);
+}
+
+Future<void> RandR::DeleteOutputProperty(const Output& output,
+ const Atom& property) {
+ return RandR::DeleteOutputProperty(
+ RandR::DeleteOutputPropertyRequest{output, property});
+}
+
+Future<RandR::GetOutputPropertyReply> RandR::GetOutputProperty(
+ const RandR::GetOutputPropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& output = request.output;
+ auto& property = request.property;
+ auto& type = request.type;
+ auto& long_offset = request.long_offset;
+ auto& long_length = request.long_length;
+ auto& c_delete = request.c_delete;
+ auto& pending = request.pending;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 15;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // output
+ buf.Write(&output);
+
+ // property
+ buf.Write(&property);
+
+ // type
+ buf.Write(&type);
+
+ // long_offset
+ buf.Write(&long_offset);
+
+ // long_length
+ buf.Write(&long_length);
+
+ // c_delete
+ buf.Write(&c_delete);
+
+ // pending
+ buf.Write(&pending);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetOutputPropertyReply>(
+ &buf, "RandR::GetOutputProperty", false);
+}
+
+Future<RandR::GetOutputPropertyReply> RandR::GetOutputProperty(
+ const Output& output,
+ const Atom& property,
+ const Atom& type,
+ const uint32_t& long_offset,
+ const uint32_t& long_length,
+ const uint8_t& c_delete,
+ const uint8_t& pending) {
+ return RandR::GetOutputProperty(RandR::GetOutputPropertyRequest{
+ output, property, type, long_offset, long_length, c_delete, pending});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetOutputPropertyReply> detail::ReadReply<
+ RandR::GetOutputPropertyReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetOutputPropertyReply>();
+
+ auto& format = (*reply).format;
+ auto& sequence = (*reply).sequence;
+ auto& type = (*reply).type;
+ auto& bytes_after = (*reply).bytes_after;
+ auto& num_items = (*reply).num_items;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // format
+ Read(&format, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // type
+ Read(&type, &buf);
+
+ // bytes_after
+ Read(&bytes_after, &buf);
+
+ // num_items
+ Read(&num_items, &buf);
+
+ // pad0
+ Pad(&buf, 12);
+
+ // data
+ data.resize((num_items) * ((format) / (8)));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::CreateModeReply> RandR::CreateMode(
+ const RandR::CreateModeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& mode_info = request.mode_info;
+ auto& name = request.name;
+ size_t name_len = name.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 16;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // mode_info
+ {
+ auto& id = mode_info.id;
+ auto& width = mode_info.width;
+ auto& height = mode_info.height;
+ auto& dot_clock = mode_info.dot_clock;
+ auto& hsync_start = mode_info.hsync_start;
+ auto& hsync_end = mode_info.hsync_end;
+ auto& htotal = mode_info.htotal;
+ auto& hskew = mode_info.hskew;
+ auto& vsync_start = mode_info.vsync_start;
+ auto& vsync_end = mode_info.vsync_end;
+ auto& vtotal = mode_info.vtotal;
+ auto& name_len = mode_info.name_len;
+ auto& mode_flags = mode_info.mode_flags;
+
+ // id
+ buf.Write(&id);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // dot_clock
+ buf.Write(&dot_clock);
+
+ // hsync_start
+ buf.Write(&hsync_start);
+
+ // hsync_end
+ buf.Write(&hsync_end);
+
+ // htotal
+ buf.Write(&htotal);
+
+ // hskew
+ buf.Write(&hskew);
+
+ // vsync_start
+ buf.Write(&vsync_start);
+
+ // vsync_end
+ buf.Write(&vsync_end);
+
+ // vtotal
+ buf.Write(&vtotal);
+
+ // name_len
+ buf.Write(&name_len);
+
+ // mode_flags
+ uint32_t tmp19;
+ tmp19 = static_cast<uint32_t>(mode_flags);
+ buf.Write(&tmp19);
+ }
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(name_len), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::CreateModeReply>(
+ &buf, "RandR::CreateMode", false);
+}
+
+Future<RandR::CreateModeReply> RandR::CreateMode(const Window& window,
+ const ModeInfo& mode_info,
+ const std::string& name) {
+ return RandR::CreateMode(RandR::CreateModeRequest{window, mode_info, name});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::CreateModeReply> detail::ReadReply<
+ RandR::CreateModeReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::CreateModeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& mode = (*reply).mode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // mode
+ Read(&mode, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> RandR::DestroyMode(const RandR::DestroyModeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& mode = request.mode;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 17;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // mode
+ buf.Write(&mode);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::DestroyMode", false);
+}
+
+Future<void> RandR::DestroyMode(const Mode& mode) {
+ return RandR::DestroyMode(RandR::DestroyModeRequest{mode});
+}
+
+Future<void> RandR::AddOutputMode(const RandR::AddOutputModeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& output = request.output;
+ auto& mode = request.mode;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 18;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // output
+ buf.Write(&output);
+
+ // mode
+ buf.Write(&mode);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::AddOutputMode", false);
+}
+
+Future<void> RandR::AddOutputMode(const Output& output, const Mode& mode) {
+ return RandR::AddOutputMode(RandR::AddOutputModeRequest{output, mode});
+}
+
+Future<void> RandR::DeleteOutputMode(
+ const RandR::DeleteOutputModeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& output = request.output;
+ auto& mode = request.mode;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 19;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // output
+ buf.Write(&output);
+
+ // mode
+ buf.Write(&mode);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::DeleteOutputMode", false);
+}
+
+Future<void> RandR::DeleteOutputMode(const Output& output, const Mode& mode) {
+ return RandR::DeleteOutputMode(RandR::DeleteOutputModeRequest{output, mode});
+}
+
+Future<RandR::GetCrtcInfoReply> RandR::GetCrtcInfo(
+ const RandR::GetCrtcInfoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& crtc = request.crtc;
+ auto& config_timestamp = request.config_timestamp;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 20;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // crtc
+ buf.Write(&crtc);
+
+ // config_timestamp
+ buf.Write(&config_timestamp);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetCrtcInfoReply>(
+ &buf, "RandR::GetCrtcInfo", false);
+}
+
+Future<RandR::GetCrtcInfoReply> RandR::GetCrtcInfo(
+ const Crtc& crtc,
+ const Time& config_timestamp) {
+ return RandR::GetCrtcInfo(RandR::GetCrtcInfoRequest{crtc, config_timestamp});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetCrtcInfoReply> detail::ReadReply<
+ RandR::GetCrtcInfoReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetCrtcInfoReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+ auto& timestamp = (*reply).timestamp;
+ auto& x = (*reply).x;
+ auto& y = (*reply).y;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& mode = (*reply).mode;
+ auto& rotation = (*reply).rotation;
+ auto& rotations = (*reply).rotations;
+ uint16_t num_outputs{};
+ uint16_t num_possible_outputs{};
+ auto& outputs = (*reply).outputs;
+ size_t outputs_len = outputs.size();
+ auto& possible = (*reply).possible;
+ size_t possible_len = possible.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ uint8_t tmp20;
+ Read(&tmp20, &buf);
+ status = static_cast<RandR::SetConfig>(tmp20);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // mode
+ Read(&mode, &buf);
+
+ // rotation
+ uint16_t tmp21;
+ Read(&tmp21, &buf);
+ rotation = static_cast<RandR::Rotation>(tmp21);
+
+ // rotations
+ uint16_t tmp22;
+ Read(&tmp22, &buf);
+ rotations = static_cast<RandR::Rotation>(tmp22);
+
+ // num_outputs
+ Read(&num_outputs, &buf);
+
+ // num_possible_outputs
+ Read(&num_possible_outputs, &buf);
+
+ // outputs
+ outputs.resize(num_outputs);
+ for (auto& outputs_elem : outputs) {
+ // outputs_elem
+ Read(&outputs_elem, &buf);
+ }
+
+ // possible
+ possible.resize(num_possible_outputs);
+ for (auto& possible_elem : possible) {
+ // possible_elem
+ Read(&possible_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::SetCrtcConfigReply> RandR::SetCrtcConfig(
+ const RandR::SetCrtcConfigRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& crtc = request.crtc;
+ auto& timestamp = request.timestamp;
+ auto& config_timestamp = request.config_timestamp;
+ auto& x = request.x;
+ auto& y = request.y;
+ auto& mode = request.mode;
+ auto& rotation = request.rotation;
+ auto& outputs = request.outputs;
+ size_t outputs_len = outputs.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 21;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // crtc
+ buf.Write(&crtc);
+
+ // timestamp
+ buf.Write(&timestamp);
+
+ // config_timestamp
+ buf.Write(&config_timestamp);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // mode
+ buf.Write(&mode);
+
+ // rotation
+ uint16_t tmp23;
+ tmp23 = static_cast<uint16_t>(rotation);
+ buf.Write(&tmp23);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // outputs
+ DCHECK_EQ(static_cast<size_t>(outputs_len), outputs.size());
+ for (auto& outputs_elem : outputs) {
+ // outputs_elem
+ buf.Write(&outputs_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::SetCrtcConfigReply>(
+ &buf, "RandR::SetCrtcConfig", false);
+}
+
+Future<RandR::SetCrtcConfigReply> RandR::SetCrtcConfig(
+ const Crtc& crtc,
+ const Time& timestamp,
+ const Time& config_timestamp,
+ const int16_t& x,
+ const int16_t& y,
+ const Mode& mode,
+ const Rotation& rotation,
+ const std::vector<Output>& outputs) {
+ return RandR::SetCrtcConfig(RandR::SetCrtcConfigRequest{
+ crtc, timestamp, config_timestamp, x, y, mode, rotation, outputs});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::SetCrtcConfigReply> detail::ReadReply<
+ RandR::SetCrtcConfigReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::SetCrtcConfigReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+ auto& timestamp = (*reply).timestamp;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ uint8_t tmp24;
+ Read(&tmp24, &buf);
+ status = static_cast<RandR::SetConfig>(tmp24);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // pad0
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::GetCrtcGammaSizeReply> RandR::GetCrtcGammaSize(
+ const RandR::GetCrtcGammaSizeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& crtc = request.crtc;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 22;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // crtc
+ buf.Write(&crtc);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetCrtcGammaSizeReply>(
+ &buf, "RandR::GetCrtcGammaSize", false);
+}
+
+Future<RandR::GetCrtcGammaSizeReply> RandR::GetCrtcGammaSize(const Crtc& crtc) {
+ return RandR::GetCrtcGammaSize(RandR::GetCrtcGammaSizeRequest{crtc});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetCrtcGammaSizeReply> detail::ReadReply<
+ RandR::GetCrtcGammaSizeReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetCrtcGammaSizeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& size = (*reply).size;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // size
+ Read(&size, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::GetCrtcGammaReply> RandR::GetCrtcGamma(
+ const RandR::GetCrtcGammaRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& crtc = request.crtc;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 23;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // crtc
+ buf.Write(&crtc);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetCrtcGammaReply>(
+ &buf, "RandR::GetCrtcGamma", false);
+}
+
+Future<RandR::GetCrtcGammaReply> RandR::GetCrtcGamma(const Crtc& crtc) {
+ return RandR::GetCrtcGamma(RandR::GetCrtcGammaRequest{crtc});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetCrtcGammaReply> detail::ReadReply<
+ RandR::GetCrtcGammaReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetCrtcGammaReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t size{};
+ auto& red = (*reply).red;
+ size_t red_len = red.size();
+ auto& green = (*reply).green;
+ size_t green_len = green.size();
+ auto& blue = (*reply).blue;
+ size_t blue_len = blue.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // size
+ Read(&size, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // red
+ red.resize(size);
+ for (auto& red_elem : red) {
+ // red_elem
+ Read(&red_elem, &buf);
+ }
+
+ // green
+ green.resize(size);
+ for (auto& green_elem : green) {
+ // green_elem
+ Read(&green_elem, &buf);
+ }
+
+ // blue
+ blue.resize(size);
+ for (auto& blue_elem : blue) {
+ // blue_elem
+ Read(&blue_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> RandR::SetCrtcGamma(const RandR::SetCrtcGammaRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& crtc = request.crtc;
+ uint16_t size{};
+ auto& red = request.red;
+ size_t red_len = red.size();
+ auto& green = request.green;
+ size_t green_len = green.size();
+ auto& blue = request.blue;
+ size_t blue_len = blue.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 24;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // crtc
+ buf.Write(&crtc);
+
+ // size
+ size = red.size();
+ buf.Write(&size);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // red
+ DCHECK_EQ(static_cast<size_t>(size), red.size());
+ for (auto& red_elem : red) {
+ // red_elem
+ buf.Write(&red_elem);
+ }
+
+ // green
+ DCHECK_EQ(static_cast<size_t>(size), green.size());
+ for (auto& green_elem : green) {
+ // green_elem
+ buf.Write(&green_elem);
+ }
+
+ // blue
+ DCHECK_EQ(static_cast<size_t>(size), blue.size());
+ for (auto& blue_elem : blue) {
+ // blue_elem
+ buf.Write(&blue_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::SetCrtcGamma", false);
+}
+
+Future<void> RandR::SetCrtcGamma(const Crtc& crtc,
+ const std::vector<uint16_t>& red,
+ const std::vector<uint16_t>& green,
+ const std::vector<uint16_t>& blue) {
+ return RandR::SetCrtcGamma(
+ RandR::SetCrtcGammaRequest{crtc, red, green, blue});
+}
+
+Future<RandR::GetScreenResourcesCurrentReply> RandR::GetScreenResourcesCurrent(
+ const RandR::GetScreenResourcesCurrentRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 25;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetScreenResourcesCurrentReply>(
+ &buf, "RandR::GetScreenResourcesCurrent", false);
+}
+
+Future<RandR::GetScreenResourcesCurrentReply> RandR::GetScreenResourcesCurrent(
+ const Window& window) {
+ return RandR::GetScreenResourcesCurrent(
+ RandR::GetScreenResourcesCurrentRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetScreenResourcesCurrentReply> detail::ReadReply<
+ RandR::GetScreenResourcesCurrentReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetScreenResourcesCurrentReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& timestamp = (*reply).timestamp;
+ auto& config_timestamp = (*reply).config_timestamp;
+ uint16_t num_crtcs{};
+ uint16_t num_outputs{};
+ uint16_t num_modes{};
+ uint16_t names_len{};
+ auto& crtcs = (*reply).crtcs;
+ size_t crtcs_len = crtcs.size();
+ auto& outputs = (*reply).outputs;
+ size_t outputs_len = outputs.size();
+ auto& modes = (*reply).modes;
+ size_t modes_len = modes.size();
+ auto& names = (*reply).names;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // config_timestamp
+ Read(&config_timestamp, &buf);
+
+ // num_crtcs
+ Read(&num_crtcs, &buf);
+
+ // num_outputs
+ Read(&num_outputs, &buf);
+
+ // num_modes
+ Read(&num_modes, &buf);
+
+ // names_len
+ Read(&names_len, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // crtcs
+ crtcs.resize(num_crtcs);
+ for (auto& crtcs_elem : crtcs) {
+ // crtcs_elem
+ Read(&crtcs_elem, &buf);
+ }
+
+ // outputs
+ outputs.resize(num_outputs);
+ for (auto& outputs_elem : outputs) {
+ // outputs_elem
+ Read(&outputs_elem, &buf);
+ }
+
+ // modes
+ modes.resize(num_modes);
+ for (auto& modes_elem : modes) {
+ // modes_elem
+ {
+ auto& id = modes_elem.id;
+ auto& width = modes_elem.width;
+ auto& height = modes_elem.height;
+ auto& dot_clock = modes_elem.dot_clock;
+ auto& hsync_start = modes_elem.hsync_start;
+ auto& hsync_end = modes_elem.hsync_end;
+ auto& htotal = modes_elem.htotal;
+ auto& hskew = modes_elem.hskew;
+ auto& vsync_start = modes_elem.vsync_start;
+ auto& vsync_end = modes_elem.vsync_end;
+ auto& vtotal = modes_elem.vtotal;
+ auto& name_len = modes_elem.name_len;
+ auto& mode_flags = modes_elem.mode_flags;
+
+ // id
+ Read(&id, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // dot_clock
+ Read(&dot_clock, &buf);
+
+ // hsync_start
+ Read(&hsync_start, &buf);
+
+ // hsync_end
+ Read(&hsync_end, &buf);
+
+ // htotal
+ Read(&htotal, &buf);
+
+ // hskew
+ Read(&hskew, &buf);
+
+ // vsync_start
+ Read(&vsync_start, &buf);
+
+ // vsync_end
+ Read(&vsync_end, &buf);
+
+ // vtotal
+ Read(&vtotal, &buf);
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // mode_flags
+ uint32_t tmp25;
+ Read(&tmp25, &buf);
+ mode_flags = static_cast<RandR::ModeFlag>(tmp25);
+ }
+ }
+
+ // names
+ names.resize(names_len);
+ for (auto& names_elem : names) {
+ // names_elem
+ Read(&names_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> RandR::SetCrtcTransform(
+ const RandR::SetCrtcTransformRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& crtc = request.crtc;
+ auto& transform = request.transform;
+ uint16_t filter_len{};
+ auto& filter_name = request.filter_name;
+ size_t filter_name_len = filter_name.size();
+ auto& filter_params = request.filter_params;
+ size_t filter_params_len = filter_params.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 26;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // crtc
+ buf.Write(&crtc);
+
+ // transform
+ {
+ auto& matrix11 = transform.matrix11;
+ auto& matrix12 = transform.matrix12;
+ auto& matrix13 = transform.matrix13;
+ auto& matrix21 = transform.matrix21;
+ auto& matrix22 = transform.matrix22;
+ auto& matrix23 = transform.matrix23;
+ auto& matrix31 = transform.matrix31;
+ auto& matrix32 = transform.matrix32;
+ auto& matrix33 = transform.matrix33;
+
+ // matrix11
+ buf.Write(&matrix11);
+
+ // matrix12
+ buf.Write(&matrix12);
+
+ // matrix13
+ buf.Write(&matrix13);
+
+ // matrix21
+ buf.Write(&matrix21);
+
+ // matrix22
+ buf.Write(&matrix22);
+
+ // matrix23
+ buf.Write(&matrix23);
+
+ // matrix31
+ buf.Write(&matrix31);
+
+ // matrix32
+ buf.Write(&matrix32);
+
+ // matrix33
+ buf.Write(&matrix33);
+ }
+
+ // filter_len
+ filter_len = filter_name.size();
+ buf.Write(&filter_len);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // filter_name
+ DCHECK_EQ(static_cast<size_t>(filter_len), filter_name.size());
+ for (auto& filter_name_elem : filter_name) {
+ // filter_name_elem
+ buf.Write(&filter_name_elem);
+ }
+
+ // pad1
+ Align(&buf, 4);
+
+ // filter_params
+ DCHECK_EQ(static_cast<size_t>(filter_params_len), filter_params.size());
+ for (auto& filter_params_elem : filter_params) {
+ // filter_params_elem
+ buf.Write(&filter_params_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::SetCrtcTransform", false);
+}
+
+Future<void> RandR::SetCrtcTransform(
+ const Crtc& crtc,
+ const Render::Transform& transform,
+ const std::string& filter_name,
+ const std::vector<Render::Fixed>& filter_params) {
+ return RandR::SetCrtcTransform(RandR::SetCrtcTransformRequest{
+ crtc, transform, filter_name, filter_params});
+}
+
+Future<RandR::GetCrtcTransformReply> RandR::GetCrtcTransform(
+ const RandR::GetCrtcTransformRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& crtc = request.crtc;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 27;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // crtc
+ buf.Write(&crtc);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetCrtcTransformReply>(
+ &buf, "RandR::GetCrtcTransform", false);
+}
+
+Future<RandR::GetCrtcTransformReply> RandR::GetCrtcTransform(const Crtc& crtc) {
+ return RandR::GetCrtcTransform(RandR::GetCrtcTransformRequest{crtc});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetCrtcTransformReply> detail::ReadReply<
+ RandR::GetCrtcTransformReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetCrtcTransformReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& pending_transform = (*reply).pending_transform;
+ auto& has_transforms = (*reply).has_transforms;
+ auto& current_transform = (*reply).current_transform;
+ uint16_t pending_len{};
+ uint16_t pending_nparams{};
+ uint16_t current_len{};
+ uint16_t current_nparams{};
+ auto& pending_filter_name = (*reply).pending_filter_name;
+ size_t pending_filter_name_len = pending_filter_name.size();
+ auto& pending_params = (*reply).pending_params;
+ size_t pending_params_len = pending_params.size();
+ auto& current_filter_name = (*reply).current_filter_name;
+ size_t current_filter_name_len = current_filter_name.size();
+ auto& current_params = (*reply).current_params;
+ size_t current_params_len = current_params.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pending_transform
+ {
+ auto& matrix11 = pending_transform.matrix11;
+ auto& matrix12 = pending_transform.matrix12;
+ auto& matrix13 = pending_transform.matrix13;
+ auto& matrix21 = pending_transform.matrix21;
+ auto& matrix22 = pending_transform.matrix22;
+ auto& matrix23 = pending_transform.matrix23;
+ auto& matrix31 = pending_transform.matrix31;
+ auto& matrix32 = pending_transform.matrix32;
+ auto& matrix33 = pending_transform.matrix33;
+
+ // matrix11
+ Read(&matrix11, &buf);
+
+ // matrix12
+ Read(&matrix12, &buf);
+
+ // matrix13
+ Read(&matrix13, &buf);
+
+ // matrix21
+ Read(&matrix21, &buf);
+
+ // matrix22
+ Read(&matrix22, &buf);
+
+ // matrix23
+ Read(&matrix23, &buf);
+
+ // matrix31
+ Read(&matrix31, &buf);
+
+ // matrix32
+ Read(&matrix32, &buf);
+
+ // matrix33
+ Read(&matrix33, &buf);
+ }
+
+ // has_transforms
+ Read(&has_transforms, &buf);
+
+ // pad1
+ Pad(&buf, 3);
+
+ // current_transform
+ {
+ auto& matrix11 = current_transform.matrix11;
+ auto& matrix12 = current_transform.matrix12;
+ auto& matrix13 = current_transform.matrix13;
+ auto& matrix21 = current_transform.matrix21;
+ auto& matrix22 = current_transform.matrix22;
+ auto& matrix23 = current_transform.matrix23;
+ auto& matrix31 = current_transform.matrix31;
+ auto& matrix32 = current_transform.matrix32;
+ auto& matrix33 = current_transform.matrix33;
+
+ // matrix11
+ Read(&matrix11, &buf);
+
+ // matrix12
+ Read(&matrix12, &buf);
+
+ // matrix13
+ Read(&matrix13, &buf);
+
+ // matrix21
+ Read(&matrix21, &buf);
+
+ // matrix22
+ Read(&matrix22, &buf);
+
+ // matrix23
+ Read(&matrix23, &buf);
+
+ // matrix31
+ Read(&matrix31, &buf);
+
+ // matrix32
+ Read(&matrix32, &buf);
+
+ // matrix33
+ Read(&matrix33, &buf);
+ }
+
+ // pad2
+ Pad(&buf, 4);
+
+ // pending_len
+ Read(&pending_len, &buf);
+
+ // pending_nparams
+ Read(&pending_nparams, &buf);
+
+ // current_len
+ Read(&current_len, &buf);
+
+ // current_nparams
+ Read(&current_nparams, &buf);
+
+ // pending_filter_name
+ pending_filter_name.resize(pending_len);
+ for (auto& pending_filter_name_elem : pending_filter_name) {
+ // pending_filter_name_elem
+ Read(&pending_filter_name_elem, &buf);
+ }
+
+ // pad3
+ Align(&buf, 4);
+
+ // pending_params
+ pending_params.resize(pending_nparams);
+ for (auto& pending_params_elem : pending_params) {
+ // pending_params_elem
+ Read(&pending_params_elem, &buf);
+ }
+
+ // current_filter_name
+ current_filter_name.resize(current_len);
+ for (auto& current_filter_name_elem : current_filter_name) {
+ // current_filter_name_elem
+ Read(&current_filter_name_elem, &buf);
+ }
+
+ // pad4
+ Align(&buf, 4);
+
+ // current_params
+ current_params.resize(current_nparams);
+ for (auto& current_params_elem : current_params) {
+ // current_params_elem
+ Read(&current_params_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::GetPanningReply> RandR::GetPanning(
+ const RandR::GetPanningRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& crtc = request.crtc;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 28;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // crtc
+ buf.Write(&crtc);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetPanningReply>(
+ &buf, "RandR::GetPanning", false);
+}
+
+Future<RandR::GetPanningReply> RandR::GetPanning(const Crtc& crtc) {
+ return RandR::GetPanning(RandR::GetPanningRequest{crtc});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetPanningReply> detail::ReadReply<
+ RandR::GetPanningReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetPanningReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+ auto& timestamp = (*reply).timestamp;
+ auto& left = (*reply).left;
+ auto& top = (*reply).top;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& track_left = (*reply).track_left;
+ auto& track_top = (*reply).track_top;
+ auto& track_width = (*reply).track_width;
+ auto& track_height = (*reply).track_height;
+ auto& border_left = (*reply).border_left;
+ auto& border_top = (*reply).border_top;
+ auto& border_right = (*reply).border_right;
+ auto& border_bottom = (*reply).border_bottom;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ uint8_t tmp26;
+ Read(&tmp26, &buf);
+ status = static_cast<RandR::SetConfig>(tmp26);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // left
+ Read(&left, &buf);
+
+ // top
+ Read(&top, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // track_left
+ Read(&track_left, &buf);
+
+ // track_top
+ Read(&track_top, &buf);
+
+ // track_width
+ Read(&track_width, &buf);
+
+ // track_height
+ Read(&track_height, &buf);
+
+ // border_left
+ Read(&border_left, &buf);
+
+ // border_top
+ Read(&border_top, &buf);
+
+ // border_right
+ Read(&border_right, &buf);
+
+ // border_bottom
+ Read(&border_bottom, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::SetPanningReply> RandR::SetPanning(
+ const RandR::SetPanningRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& crtc = request.crtc;
+ auto& timestamp = request.timestamp;
+ auto& left = request.left;
+ auto& top = request.top;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& track_left = request.track_left;
+ auto& track_top = request.track_top;
+ auto& track_width = request.track_width;
+ auto& track_height = request.track_height;
+ auto& border_left = request.border_left;
+ auto& border_top = request.border_top;
+ auto& border_right = request.border_right;
+ auto& border_bottom = request.border_bottom;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 29;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // crtc
+ buf.Write(&crtc);
+
+ // timestamp
+ buf.Write(&timestamp);
+
+ // left
+ buf.Write(&left);
+
+ // top
+ buf.Write(&top);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // track_left
+ buf.Write(&track_left);
+
+ // track_top
+ buf.Write(&track_top);
+
+ // track_width
+ buf.Write(&track_width);
+
+ // track_height
+ buf.Write(&track_height);
+
+ // border_left
+ buf.Write(&border_left);
+
+ // border_top
+ buf.Write(&border_top);
+
+ // border_right
+ buf.Write(&border_right);
+
+ // border_bottom
+ buf.Write(&border_bottom);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::SetPanningReply>(
+ &buf, "RandR::SetPanning", false);
+}
+
+Future<RandR::SetPanningReply> RandR::SetPanning(const Crtc& crtc,
+ const Time& timestamp,
+ const uint16_t& left,
+ const uint16_t& top,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint16_t& track_left,
+ const uint16_t& track_top,
+ const uint16_t& track_width,
+ const uint16_t& track_height,
+ const int16_t& border_left,
+ const int16_t& border_top,
+ const int16_t& border_right,
+ const int16_t& border_bottom) {
+ return RandR::SetPanning(RandR::SetPanningRequest{
+ crtc, timestamp, left, top, width, height, track_left, track_top,
+ track_width, track_height, border_left, border_top, border_right,
+ border_bottom});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::SetPanningReply> detail::ReadReply<
+ RandR::SetPanningReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::SetPanningReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+ auto& timestamp = (*reply).timestamp;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ uint8_t tmp27;
+ Read(&tmp27, &buf);
+ status = static_cast<RandR::SetConfig>(tmp27);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> RandR::SetOutputPrimary(
+ const RandR::SetOutputPrimaryRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& output = request.output;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 30;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // output
+ buf.Write(&output);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::SetOutputPrimary", false);
+}
+
+Future<void> RandR::SetOutputPrimary(const Window& window,
+ const Output& output) {
+ return RandR::SetOutputPrimary(
+ RandR::SetOutputPrimaryRequest{window, output});
+}
+
+Future<RandR::GetOutputPrimaryReply> RandR::GetOutputPrimary(
+ const RandR::GetOutputPrimaryRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 31;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetOutputPrimaryReply>(
+ &buf, "RandR::GetOutputPrimary", false);
+}
+
+Future<RandR::GetOutputPrimaryReply> RandR::GetOutputPrimary(
+ const Window& window) {
+ return RandR::GetOutputPrimary(RandR::GetOutputPrimaryRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetOutputPrimaryReply> detail::ReadReply<
+ RandR::GetOutputPrimaryReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetOutputPrimaryReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& output = (*reply).output;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // output
+ Read(&output, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::GetProvidersReply> RandR::GetProviders(
+ const RandR::GetProvidersRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 32;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetProvidersReply>(
+ &buf, "RandR::GetProviders", false);
+}
+
+Future<RandR::GetProvidersReply> RandR::GetProviders(const Window& window) {
+ return RandR::GetProviders(RandR::GetProvidersRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetProvidersReply> detail::ReadReply<
+ RandR::GetProvidersReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetProvidersReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& timestamp = (*reply).timestamp;
+ uint16_t num_providers{};
+ auto& providers = (*reply).providers;
+ size_t providers_len = providers.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // num_providers
+ Read(&num_providers, &buf);
+
+ // pad1
+ Pad(&buf, 18);
+
+ // providers
+ providers.resize(num_providers);
+ for (auto& providers_elem : providers) {
+ // providers_elem
+ Read(&providers_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::GetProviderInfoReply> RandR::GetProviderInfo(
+ const RandR::GetProviderInfoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& provider = request.provider;
+ auto& config_timestamp = request.config_timestamp;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 33;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // provider
+ buf.Write(&provider);
+
+ // config_timestamp
+ buf.Write(&config_timestamp);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetProviderInfoReply>(
+ &buf, "RandR::GetProviderInfo", false);
+}
+
+Future<RandR::GetProviderInfoReply> RandR::GetProviderInfo(
+ const Provider& provider,
+ const Time& config_timestamp) {
+ return RandR::GetProviderInfo(
+ RandR::GetProviderInfoRequest{provider, config_timestamp});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetProviderInfoReply> detail::ReadReply<
+ RandR::GetProviderInfoReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetProviderInfoReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+ auto& timestamp = (*reply).timestamp;
+ auto& capabilities = (*reply).capabilities;
+ uint16_t num_crtcs{};
+ uint16_t num_outputs{};
+ uint16_t num_associated_providers{};
+ uint16_t name_len{};
+ auto& crtcs = (*reply).crtcs;
+ size_t crtcs_len = crtcs.size();
+ auto& outputs = (*reply).outputs;
+ size_t outputs_len = outputs.size();
+ auto& associated_providers = (*reply).associated_providers;
+ size_t associated_providers_len = associated_providers.size();
+ auto& associated_capability = (*reply).associated_capability;
+ size_t associated_capability_len = associated_capability.size();
+ auto& name = (*reply).name;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ Read(&status, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // capabilities
+ uint32_t tmp28;
+ Read(&tmp28, &buf);
+ capabilities = static_cast<RandR::ProviderCapability>(tmp28);
+
+ // num_crtcs
+ Read(&num_crtcs, &buf);
+
+ // num_outputs
+ Read(&num_outputs, &buf);
+
+ // num_associated_providers
+ Read(&num_associated_providers, &buf);
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // pad0
+ Pad(&buf, 8);
+
+ // crtcs
+ crtcs.resize(num_crtcs);
+ for (auto& crtcs_elem : crtcs) {
+ // crtcs_elem
+ Read(&crtcs_elem, &buf);
+ }
+
+ // outputs
+ outputs.resize(num_outputs);
+ for (auto& outputs_elem : outputs) {
+ // outputs_elem
+ Read(&outputs_elem, &buf);
+ }
+
+ // associated_providers
+ associated_providers.resize(num_associated_providers);
+ for (auto& associated_providers_elem : associated_providers) {
+ // associated_providers_elem
+ Read(&associated_providers_elem, &buf);
+ }
+
+ // associated_capability
+ associated_capability.resize(num_associated_providers);
+ for (auto& associated_capability_elem : associated_capability) {
+ // associated_capability_elem
+ Read(&associated_capability_elem, &buf);
+ }
+
+ // name
+ name.resize(name_len);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> RandR::SetProviderOffloadSink(
+ const RandR::SetProviderOffloadSinkRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& provider = request.provider;
+ auto& sink_provider = request.sink_provider;
+ auto& config_timestamp = request.config_timestamp;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 34;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // provider
+ buf.Write(&provider);
+
+ // sink_provider
+ buf.Write(&sink_provider);
+
+ // config_timestamp
+ buf.Write(&config_timestamp);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::SetProviderOffloadSink",
+ false);
+}
+
+Future<void> RandR::SetProviderOffloadSink(const Provider& provider,
+ const Provider& sink_provider,
+ const Time& config_timestamp) {
+ return RandR::SetProviderOffloadSink(RandR::SetProviderOffloadSinkRequest{
+ provider, sink_provider, config_timestamp});
+}
+
+Future<void> RandR::SetProviderOutputSource(
+ const RandR::SetProviderOutputSourceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& provider = request.provider;
+ auto& source_provider = request.source_provider;
+ auto& config_timestamp = request.config_timestamp;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 35;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // provider
+ buf.Write(&provider);
+
+ // source_provider
+ buf.Write(&source_provider);
+
+ // config_timestamp
+ buf.Write(&config_timestamp);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::SetProviderOutputSource",
+ false);
+}
+
+Future<void> RandR::SetProviderOutputSource(const Provider& provider,
+ const Provider& source_provider,
+ const Time& config_timestamp) {
+ return RandR::SetProviderOutputSource(RandR::SetProviderOutputSourceRequest{
+ provider, source_provider, config_timestamp});
+}
+
+Future<RandR::ListProviderPropertiesReply> RandR::ListProviderProperties(
+ const RandR::ListProviderPropertiesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& provider = request.provider;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 36;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // provider
+ buf.Write(&provider);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::ListProviderPropertiesReply>(
+ &buf, "RandR::ListProviderProperties", false);
+}
+
+Future<RandR::ListProviderPropertiesReply> RandR::ListProviderProperties(
+ const Provider& provider) {
+ return RandR::ListProviderProperties(
+ RandR::ListProviderPropertiesRequest{provider});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::ListProviderPropertiesReply> detail::ReadReply<
+ RandR::ListProviderPropertiesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::ListProviderPropertiesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t num_atoms{};
+ auto& atoms = (*reply).atoms;
+ size_t atoms_len = atoms.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_atoms
+ Read(&num_atoms, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // atoms
+ atoms.resize(num_atoms);
+ for (auto& atoms_elem : atoms) {
+ // atoms_elem
+ Read(&atoms_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::QueryProviderPropertyReply> RandR::QueryProviderProperty(
+ const RandR::QueryProviderPropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& provider = request.provider;
+ auto& property = request.property;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 37;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // provider
+ buf.Write(&provider);
+
+ // property
+ buf.Write(&property);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::QueryProviderPropertyReply>(
+ &buf, "RandR::QueryProviderProperty", false);
+}
+
+Future<RandR::QueryProviderPropertyReply> RandR::QueryProviderProperty(
+ const Provider& provider,
+ const Atom& property) {
+ return RandR::QueryProviderProperty(
+ RandR::QueryProviderPropertyRequest{provider, property});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::QueryProviderPropertyReply> detail::ReadReply<
+ RandR::QueryProviderPropertyReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::QueryProviderPropertyReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& pending = (*reply).pending;
+ auto& range = (*reply).range;
+ auto& immutable = (*reply).immutable;
+ auto& valid_values = (*reply).valid_values;
+ size_t valid_values_len = valid_values.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pending
+ Read(&pending, &buf);
+
+ // range
+ Read(&range, &buf);
+
+ // immutable
+ Read(&immutable, &buf);
+
+ // pad1
+ Pad(&buf, 21);
+
+ // valid_values
+ valid_values.resize(length);
+ for (auto& valid_values_elem : valid_values) {
+ // valid_values_elem
+ Read(&valid_values_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> RandR::ConfigureProviderProperty(
+ const RandR::ConfigureProviderPropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& provider = request.provider;
+ auto& property = request.property;
+ auto& pending = request.pending;
+ auto& range = request.range;
+ auto& values = request.values;
+ size_t values_len = values.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 38;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // provider
+ buf.Write(&provider);
+
+ // property
+ buf.Write(&property);
+
+ // pending
+ buf.Write(&pending);
+
+ // range
+ buf.Write(&range);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // values
+ DCHECK_EQ(static_cast<size_t>(values_len), values.size());
+ for (auto& values_elem : values) {
+ // values_elem
+ buf.Write(&values_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(
+ &buf, "RandR::ConfigureProviderProperty", false);
+}
+
+Future<void> RandR::ConfigureProviderProperty(
+ const Provider& provider,
+ const Atom& property,
+ const uint8_t& pending,
+ const uint8_t& range,
+ const std::vector<int32_t>& values) {
+ return RandR::ConfigureProviderProperty(
+ RandR::ConfigureProviderPropertyRequest{provider, property, pending,
+ range, values});
+}
+
+Future<void> RandR::ChangeProviderProperty(
+ const RandR::ChangeProviderPropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& provider = request.provider;
+ auto& property = request.property;
+ auto& type = request.type;
+ auto& format = request.format;
+ auto& mode = request.mode;
+ auto& num_items = request.num_items;
+ auto& data = request.data;
+ size_t data_len = data ? data->size() : 0;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 39;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // provider
+ buf.Write(&provider);
+
+ // property
+ buf.Write(&property);
+
+ // type
+ buf.Write(&type);
+
+ // format
+ buf.Write(&format);
+
+ // mode
+ buf.Write(&mode);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // num_items
+ buf.Write(&num_items);
+
+ // data
+ buf.AppendBuffer(data, (num_items) * ((format) / (8)));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::ChangeProviderProperty",
+ false);
+}
+
+Future<void> RandR::ChangeProviderProperty(
+ const Provider& provider,
+ const Atom& property,
+ const Atom& type,
+ const uint8_t& format,
+ const uint8_t& mode,
+ const uint32_t& num_items,
+ const scoped_refptr<base::RefCountedMemory>& data) {
+ return RandR::ChangeProviderProperty(RandR::ChangeProviderPropertyRequest{
+ provider, property, type, format, mode, num_items, data});
+}
+
+Future<void> RandR::DeleteProviderProperty(
+ const RandR::DeleteProviderPropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& provider = request.provider;
+ auto& property = request.property;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 40;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // provider
+ buf.Write(&provider);
+
+ // property
+ buf.Write(&property);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::DeleteProviderProperty",
+ false);
+}
+
+Future<void> RandR::DeleteProviderProperty(const Provider& provider,
+ const Atom& property) {
+ return RandR::DeleteProviderProperty(
+ RandR::DeleteProviderPropertyRequest{provider, property});
+}
+
+Future<RandR::GetProviderPropertyReply> RandR::GetProviderProperty(
+ const RandR::GetProviderPropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& provider = request.provider;
+ auto& property = request.property;
+ auto& type = request.type;
+ auto& long_offset = request.long_offset;
+ auto& long_length = request.long_length;
+ auto& c_delete = request.c_delete;
+ auto& pending = request.pending;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 41;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // provider
+ buf.Write(&provider);
+
+ // property
+ buf.Write(&property);
+
+ // type
+ buf.Write(&type);
+
+ // long_offset
+ buf.Write(&long_offset);
+
+ // long_length
+ buf.Write(&long_length);
+
+ // c_delete
+ buf.Write(&c_delete);
+
+ // pending
+ buf.Write(&pending);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetProviderPropertyReply>(
+ &buf, "RandR::GetProviderProperty", false);
+}
+
+Future<RandR::GetProviderPropertyReply> RandR::GetProviderProperty(
+ const Provider& provider,
+ const Atom& property,
+ const Atom& type,
+ const uint32_t& long_offset,
+ const uint32_t& long_length,
+ const uint8_t& c_delete,
+ const uint8_t& pending) {
+ return RandR::GetProviderProperty(RandR::GetProviderPropertyRequest{
+ provider, property, type, long_offset, long_length, c_delete, pending});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetProviderPropertyReply> detail::ReadReply<
+ RandR::GetProviderPropertyReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetProviderPropertyReply>();
+
+ auto& format = (*reply).format;
+ auto& sequence = (*reply).sequence;
+ auto& type = (*reply).type;
+ auto& bytes_after = (*reply).bytes_after;
+ auto& num_items = (*reply).num_items;
+ auto& data = (*reply).data;
+ size_t data_len = data ? data->size() : 0;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // format
+ Read(&format, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // type
+ Read(&type, &buf);
+
+ // bytes_after
+ Read(&bytes_after, &buf);
+
+ // num_items
+ Read(&num_items, &buf);
+
+ // pad0
+ Pad(&buf, 12);
+
+ // data
+ data = buffer->ReadAndAdvance((num_items) * ((format) / (8)));
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<RandR::GetMonitorsReply> RandR::GetMonitors(
+ const RandR::GetMonitorsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& get_active = request.get_active;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 42;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // get_active
+ buf.Write(&get_active);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::GetMonitorsReply>(
+ &buf, "RandR::GetMonitors", false);
+}
+
+Future<RandR::GetMonitorsReply> RandR::GetMonitors(const Window& window,
+ const uint8_t& get_active) {
+ return RandR::GetMonitors(RandR::GetMonitorsRequest{window, get_active});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::GetMonitorsReply> detail::ReadReply<
+ RandR::GetMonitorsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::GetMonitorsReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& timestamp = (*reply).timestamp;
+ uint32_t nMonitors{};
+ auto& nOutputs = (*reply).nOutputs;
+ auto& monitors = (*reply).monitors;
+ size_t monitors_len = monitors.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // nMonitors
+ Read(&nMonitors, &buf);
+
+ // nOutputs
+ Read(&nOutputs, &buf);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // monitors
+ monitors.resize(nMonitors);
+ for (auto& monitors_elem : monitors) {
+ // monitors_elem
+ {
+ auto& name = monitors_elem.name;
+ auto& primary = monitors_elem.primary;
+ auto& automatic = monitors_elem.automatic;
+ uint16_t nOutput{};
+ auto& x = monitors_elem.x;
+ auto& y = monitors_elem.y;
+ auto& width = monitors_elem.width;
+ auto& height = monitors_elem.height;
+ auto& width_in_millimeters = monitors_elem.width_in_millimeters;
+ auto& height_in_millimeters = monitors_elem.height_in_millimeters;
+ auto& outputs = monitors_elem.outputs;
+ size_t outputs_len = outputs.size();
+
+ // name
+ Read(&name, &buf);
+
+ // primary
+ Read(&primary, &buf);
+
+ // automatic
+ Read(&automatic, &buf);
+
+ // nOutput
+ Read(&nOutput, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // width_in_millimeters
+ Read(&width_in_millimeters, &buf);
+
+ // height_in_millimeters
+ Read(&height_in_millimeters, &buf);
+
+ // outputs
+ outputs.resize(nOutput);
+ for (auto& outputs_elem : outputs) {
+ // outputs_elem
+ Read(&outputs_elem, &buf);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> RandR::SetMonitor(const RandR::SetMonitorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& monitorinfo = request.monitorinfo;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 43;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // monitorinfo
+ {
+ auto& name = monitorinfo.name;
+ auto& primary = monitorinfo.primary;
+ auto& automatic = monitorinfo.automatic;
+ uint16_t nOutput{};
+ auto& x = monitorinfo.x;
+ auto& y = monitorinfo.y;
+ auto& width = monitorinfo.width;
+ auto& height = monitorinfo.height;
+ auto& width_in_millimeters = monitorinfo.width_in_millimeters;
+ auto& height_in_millimeters = monitorinfo.height_in_millimeters;
+ auto& outputs = monitorinfo.outputs;
+ size_t outputs_len = outputs.size();
+
+ // name
+ buf.Write(&name);
+
+ // primary
+ buf.Write(&primary);
+
+ // automatic
+ buf.Write(&automatic);
+
+ // nOutput
+ nOutput = outputs.size();
+ buf.Write(&nOutput);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // width_in_millimeters
+ buf.Write(&width_in_millimeters);
+
+ // height_in_millimeters
+ buf.Write(&height_in_millimeters);
+
+ // outputs
+ DCHECK_EQ(static_cast<size_t>(nOutput), outputs.size());
+ for (auto& outputs_elem : outputs) {
+ // outputs_elem
+ buf.Write(&outputs_elem);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::SetMonitor", false);
+}
+
+Future<void> RandR::SetMonitor(const Window& window,
+ const MonitorInfo& monitorinfo) {
+ return RandR::SetMonitor(RandR::SetMonitorRequest{window, monitorinfo});
+}
+
+Future<void> RandR::DeleteMonitor(const RandR::DeleteMonitorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& name = request.name;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 44;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // name
+ buf.Write(&name);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::DeleteMonitor", false);
+}
+
+Future<void> RandR::DeleteMonitor(const Window& window, const Atom& name) {
+ return RandR::DeleteMonitor(RandR::DeleteMonitorRequest{window, name});
+}
+
+Future<RandR::CreateLeaseReply> RandR::CreateLease(
+ const RandR::CreateLeaseRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& lid = request.lid;
+ uint16_t num_crtcs{};
+ uint16_t num_outputs{};
+ auto& crtcs = request.crtcs;
+ size_t crtcs_len = crtcs.size();
+ auto& outputs = request.outputs;
+ size_t outputs_len = outputs.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 45;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // lid
+ buf.Write(&lid);
+
+ // num_crtcs
+ num_crtcs = crtcs.size();
+ buf.Write(&num_crtcs);
+
+ // num_outputs
+ num_outputs = outputs.size();
+ buf.Write(&num_outputs);
+
+ // crtcs
+ DCHECK_EQ(static_cast<size_t>(num_crtcs), crtcs.size());
+ for (auto& crtcs_elem : crtcs) {
+ // crtcs_elem
+ buf.Write(&crtcs_elem);
+ }
+
+ // outputs
+ DCHECK_EQ(static_cast<size_t>(num_outputs), outputs.size());
+ for (auto& outputs_elem : outputs) {
+ // outputs_elem
+ buf.Write(&outputs_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<RandR::CreateLeaseReply>(
+ &buf, "RandR::CreateLease", true);
+}
+
+Future<RandR::CreateLeaseReply> RandR::CreateLease(
+ const Window& window,
+ const Lease& lid,
+ const std::vector<Crtc>& crtcs,
+ const std::vector<Output>& outputs) {
+ return RandR::CreateLease(
+ RandR::CreateLeaseRequest{window, lid, crtcs, outputs});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<RandR::CreateLeaseReply> detail::ReadReply<
+ RandR::CreateLeaseReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<RandR::CreateLeaseReply>();
+
+ auto& nfd = (*reply).nfd;
+ auto& sequence = (*reply).sequence;
+ auto& master_fd = (*reply).master_fd;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // nfd
+ Read(&nfd, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // master_fd
+ master_fd = RefCountedFD(buf.TakeFd());
+
+ // pad0
+ Pad(&buf, 24);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> RandR::FreeLease(const RandR::FreeLeaseRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& lid = request.lid;
+ auto& terminate = request.terminate;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 46;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // lid
+ buf.Write(&lid);
+
+ // terminate
+ buf.Write(&terminate);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RandR::FreeLease", false);
+}
+
+Future<void> RandR::FreeLease(const Lease& lid, const uint8_t& terminate) {
+ return RandR::FreeLease(RandR::FreeLeaseRequest{lid, terminate});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/randr.h b/chromium/ui/gfx/x/generated_protos/randr.h
new file mode 100644
index 00000000000..3d618aa925b
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/randr.h
@@ -0,0 +1,1337 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_RANDR_H_
+#define UI_GFX_X_GENERATED_PROTOS_RANDR_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "render.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) RandR {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 6;
+
+ RandR(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Mode : uint32_t {};
+
+ enum class Crtc : uint32_t {};
+
+ enum class Output : uint32_t {};
+
+ enum class Provider : uint32_t {};
+
+ enum class Lease : uint32_t {};
+
+ enum class Rotation : int {
+ Rotate_0 = 1 << 0,
+ Rotate_90 = 1 << 1,
+ Rotate_180 = 1 << 2,
+ Rotate_270 = 1 << 3,
+ Reflect_X = 1 << 4,
+ Reflect_Y = 1 << 5,
+ };
+
+ enum class SetConfig : int {
+ Success = 0,
+ InvalidConfigTime = 1,
+ InvalidTime = 2,
+ Failed = 3,
+ };
+
+ enum class NotifyMask : int {
+ ScreenChange = 1 << 0,
+ CrtcChange = 1 << 1,
+ OutputChange = 1 << 2,
+ OutputProperty = 1 << 3,
+ ProviderChange = 1 << 4,
+ ProviderProperty = 1 << 5,
+ ResourceChange = 1 << 6,
+ Lease = 1 << 7,
+ };
+
+ enum class ModeFlag : int {
+ HsyncPositive = 1 << 0,
+ HsyncNegative = 1 << 1,
+ VsyncPositive = 1 << 2,
+ VsyncNegative = 1 << 3,
+ Interlace = 1 << 4,
+ DoubleScan = 1 << 5,
+ Csync = 1 << 6,
+ CsyncPositive = 1 << 7,
+ CsyncNegative = 1 << 8,
+ HskewPresent = 1 << 9,
+ Bcast = 1 << 10,
+ PixelMultiplex = 1 << 11,
+ DoubleClock = 1 << 12,
+ HalveClock = 1 << 13,
+ };
+
+ enum class RandRConnection : int {
+ Connected = 0,
+ Disconnected = 1,
+ Unknown = 2,
+ };
+
+ enum class Transform : int {
+ Unit = 1 << 0,
+ ScaleUp = 1 << 1,
+ ScaleDown = 1 << 2,
+ Projective = 1 << 3,
+ };
+
+ enum class ProviderCapability : int {
+ SourceOutput = 1 << 0,
+ SinkOutput = 1 << 1,
+ SourceOffload = 1 << 2,
+ SinkOffload = 1 << 3,
+ };
+
+ enum class Notify : int {
+ CrtcChange = 0,
+ OutputChange = 1,
+ OutputProperty = 2,
+ ProviderChange = 3,
+ ProviderProperty = 4,
+ ResourceChange = 5,
+ Lease = 6,
+ };
+
+ struct BadOutputError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadCrtcError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadModeError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadProviderError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct ScreenSize {
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t mwidth{};
+ uint16_t mheight{};
+ };
+
+ struct RefreshRates {
+ std::vector<uint16_t> rates{};
+ };
+
+ struct ModeInfo {
+ uint32_t id{};
+ uint16_t width{};
+ uint16_t height{};
+ uint32_t dot_clock{};
+ uint16_t hsync_start{};
+ uint16_t hsync_end{};
+ uint16_t htotal{};
+ uint16_t hskew{};
+ uint16_t vsync_start{};
+ uint16_t vsync_end{};
+ uint16_t vtotal{};
+ uint16_t name_len{};
+ ModeFlag mode_flags{};
+ };
+
+ struct ScreenChangeNotifyEvent {
+ static constexpr int type_id = 11;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ Rotation rotation{};
+ uint16_t sequence{};
+ Time timestamp{};
+ Time config_timestamp{};
+ Window root{};
+ Window request_window{};
+ uint16_t sizeID{};
+ Render::SubPixel subpixel_order{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t mwidth{};
+ uint16_t mheight{};
+
+ x11::Window* GetWindow() {
+ return reinterpret_cast<x11::Window*>(&request_window);
+ }
+ };
+
+ struct MonitorInfo {
+ Atom name{};
+ uint8_t primary{};
+ uint8_t automatic{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint32_t width_in_millimeters{};
+ uint32_t height_in_millimeters{};
+ std::vector<Output> outputs{};
+ };
+
+ struct NotifyEvent {
+ static constexpr int type_id = 12;
+ static constexpr uint8_t opcode = 1;
+ bool send_event{};
+ uint16_t sequence{};
+ struct Cc {
+ Time timestamp{};
+ Window window{};
+ Crtc crtc{};
+ Mode mode{};
+ Rotation rotation{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ };
+ struct Oc {
+ Time timestamp{};
+ Time config_timestamp{};
+ Window window{};
+ Output output{};
+ Crtc crtc{};
+ Mode mode{};
+ Rotation rotation{};
+ RandRConnection connection{};
+ Render::SubPixel subpixel_order{};
+ };
+ struct Op {
+ Window window{};
+ Output output{};
+ Atom atom{};
+ Time timestamp{};
+ Property status{};
+ };
+ struct Pc {
+ Time timestamp{};
+ Window window{};
+ Provider provider{};
+ };
+ struct Pp {
+ Window window{};
+ Provider provider{};
+ Atom atom{};
+ Time timestamp{};
+ uint8_t state{};
+ };
+ struct Rc {
+ Time timestamp{};
+ Window window{};
+ };
+ struct Lc {
+ Time timestamp{};
+ Window window{};
+ Lease lease{};
+ uint8_t created{};
+ };
+ base::Optional<Cc> cc{};
+ base::Optional<Oc> oc{};
+ base::Optional<Op> op{};
+ base::Optional<Pc> pc{};
+ base::Optional<Pp> pp{};
+ base::Optional<Rc> rc{};
+ base::Optional<Lc> lc{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct QueryVersionRequest {
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(const uint32_t& major_version = {},
+ const uint32_t& minor_version = {});
+
+ struct SetScreenConfigRequest {
+ Window window{};
+ Time timestamp{};
+ Time config_timestamp{};
+ uint16_t sizeID{};
+ Rotation rotation{};
+ uint16_t rate{};
+ };
+
+ struct SetScreenConfigReply {
+ SetConfig status{};
+ uint16_t sequence{};
+ Time new_timestamp{};
+ Time config_timestamp{};
+ Window root{};
+ Render::SubPixel subpixel_order{};
+ };
+
+ using SetScreenConfigResponse = Response<SetScreenConfigReply>;
+
+ Future<SetScreenConfigReply> SetScreenConfig(
+ const SetScreenConfigRequest& request);
+
+ Future<SetScreenConfigReply> SetScreenConfig(
+ const Window& window = {},
+ const Time& timestamp = {},
+ const Time& config_timestamp = {},
+ const uint16_t& sizeID = {},
+ const Rotation& rotation = {},
+ const uint16_t& rate = {});
+
+ struct SelectInputRequest {
+ Window window{};
+ NotifyMask enable{};
+ };
+
+ using SelectInputResponse = Response<void>;
+
+ Future<void> SelectInput(const SelectInputRequest& request);
+
+ Future<void> SelectInput(const Window& window = {},
+ const NotifyMask& enable = {});
+
+ struct GetScreenInfoRequest {
+ Window window{};
+ };
+
+ struct GetScreenInfoReply {
+ Rotation rotations{};
+ uint16_t sequence{};
+ Window root{};
+ Time timestamp{};
+ Time config_timestamp{};
+ uint16_t sizeID{};
+ Rotation rotation{};
+ uint16_t rate{};
+ uint16_t nInfo{};
+ std::vector<ScreenSize> sizes{};
+ std::vector<RefreshRates> rates{};
+ };
+
+ using GetScreenInfoResponse = Response<GetScreenInfoReply>;
+
+ Future<GetScreenInfoReply> GetScreenInfo(const GetScreenInfoRequest& request);
+
+ Future<GetScreenInfoReply> GetScreenInfo(const Window& window = {});
+
+ struct GetScreenSizeRangeRequest {
+ Window window{};
+ };
+
+ struct GetScreenSizeRangeReply {
+ uint16_t sequence{};
+ uint16_t min_width{};
+ uint16_t min_height{};
+ uint16_t max_width{};
+ uint16_t max_height{};
+ };
+
+ using GetScreenSizeRangeResponse = Response<GetScreenSizeRangeReply>;
+
+ Future<GetScreenSizeRangeReply> GetScreenSizeRange(
+ const GetScreenSizeRangeRequest& request);
+
+ Future<GetScreenSizeRangeReply> GetScreenSizeRange(const Window& window = {});
+
+ struct SetScreenSizeRequest {
+ Window window{};
+ uint16_t width{};
+ uint16_t height{};
+ uint32_t mm_width{};
+ uint32_t mm_height{};
+ };
+
+ using SetScreenSizeResponse = Response<void>;
+
+ Future<void> SetScreenSize(const SetScreenSizeRequest& request);
+
+ Future<void> SetScreenSize(const Window& window = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint32_t& mm_width = {},
+ const uint32_t& mm_height = {});
+
+ struct GetScreenResourcesRequest {
+ Window window{};
+ };
+
+ struct GetScreenResourcesReply {
+ uint16_t sequence{};
+ Time timestamp{};
+ Time config_timestamp{};
+ std::vector<Crtc> crtcs{};
+ std::vector<Output> outputs{};
+ std::vector<ModeInfo> modes{};
+ std::vector<uint8_t> names{};
+ };
+
+ using GetScreenResourcesResponse = Response<GetScreenResourcesReply>;
+
+ Future<GetScreenResourcesReply> GetScreenResources(
+ const GetScreenResourcesRequest& request);
+
+ Future<GetScreenResourcesReply> GetScreenResources(const Window& window = {});
+
+ struct GetOutputInfoRequest {
+ Output output{};
+ Time config_timestamp{};
+ };
+
+ struct GetOutputInfoReply {
+ SetConfig status{};
+ uint16_t sequence{};
+ Time timestamp{};
+ Crtc crtc{};
+ uint32_t mm_width{};
+ uint32_t mm_height{};
+ RandRConnection connection{};
+ Render::SubPixel subpixel_order{};
+ uint16_t num_preferred{};
+ std::vector<Crtc> crtcs{};
+ std::vector<Mode> modes{};
+ std::vector<Output> clones{};
+ std::vector<uint8_t> name{};
+ };
+
+ using GetOutputInfoResponse = Response<GetOutputInfoReply>;
+
+ Future<GetOutputInfoReply> GetOutputInfo(const GetOutputInfoRequest& request);
+
+ Future<GetOutputInfoReply> GetOutputInfo(const Output& output = {},
+ const Time& config_timestamp = {});
+
+ struct ListOutputPropertiesRequest {
+ Output output{};
+ };
+
+ struct ListOutputPropertiesReply {
+ uint16_t sequence{};
+ std::vector<Atom> atoms{};
+ };
+
+ using ListOutputPropertiesResponse = Response<ListOutputPropertiesReply>;
+
+ Future<ListOutputPropertiesReply> ListOutputProperties(
+ const ListOutputPropertiesRequest& request);
+
+ Future<ListOutputPropertiesReply> ListOutputProperties(
+ const Output& output = {});
+
+ struct QueryOutputPropertyRequest {
+ Output output{};
+ Atom property{};
+ };
+
+ struct QueryOutputPropertyReply {
+ uint16_t sequence{};
+ uint8_t pending{};
+ uint8_t range{};
+ uint8_t immutable{};
+ std::vector<int32_t> validValues{};
+ };
+
+ using QueryOutputPropertyResponse = Response<QueryOutputPropertyReply>;
+
+ Future<QueryOutputPropertyReply> QueryOutputProperty(
+ const QueryOutputPropertyRequest& request);
+
+ Future<QueryOutputPropertyReply> QueryOutputProperty(
+ const Output& output = {},
+ const Atom& property = {});
+
+ struct ConfigureOutputPropertyRequest {
+ Output output{};
+ Atom property{};
+ uint8_t pending{};
+ uint8_t range{};
+ std::vector<int32_t> values{};
+ };
+
+ using ConfigureOutputPropertyResponse = Response<void>;
+
+ Future<void> ConfigureOutputProperty(
+ const ConfigureOutputPropertyRequest& request);
+
+ Future<void> ConfigureOutputProperty(const Output& output = {},
+ const Atom& property = {},
+ const uint8_t& pending = {},
+ const uint8_t& range = {},
+ const std::vector<int32_t>& values = {});
+
+ struct ChangeOutputPropertyRequest {
+ Output output{};
+ Atom property{};
+ Atom type{};
+ uint8_t format{};
+ PropMode mode{};
+ uint32_t num_units{};
+ scoped_refptr<base::RefCountedMemory> data{};
+ };
+
+ using ChangeOutputPropertyResponse = Response<void>;
+
+ Future<void> ChangeOutputProperty(const ChangeOutputPropertyRequest& request);
+
+ Future<void> ChangeOutputProperty(
+ const Output& output = {},
+ const Atom& property = {},
+ const Atom& type = {},
+ const uint8_t& format = {},
+ const PropMode& mode = {},
+ const uint32_t& num_units = {},
+ const scoped_refptr<base::RefCountedMemory>& data = {});
+
+ struct DeleteOutputPropertyRequest {
+ Output output{};
+ Atom property{};
+ };
+
+ using DeleteOutputPropertyResponse = Response<void>;
+
+ Future<void> DeleteOutputProperty(const DeleteOutputPropertyRequest& request);
+
+ Future<void> DeleteOutputProperty(const Output& output = {},
+ const Atom& property = {});
+
+ struct GetOutputPropertyRequest {
+ Output output{};
+ Atom property{};
+ Atom type{};
+ uint32_t long_offset{};
+ uint32_t long_length{};
+ uint8_t c_delete{};
+ uint8_t pending{};
+ };
+
+ struct GetOutputPropertyReply {
+ uint8_t format{};
+ uint16_t sequence{};
+ Atom type{};
+ uint32_t bytes_after{};
+ uint32_t num_items{};
+ std::vector<uint8_t> data{};
+ };
+
+ using GetOutputPropertyResponse = Response<GetOutputPropertyReply>;
+
+ Future<GetOutputPropertyReply> GetOutputProperty(
+ const GetOutputPropertyRequest& request);
+
+ Future<GetOutputPropertyReply> GetOutputProperty(
+ const Output& output = {},
+ const Atom& property = {},
+ const Atom& type = {},
+ const uint32_t& long_offset = {},
+ const uint32_t& long_length = {},
+ const uint8_t& c_delete = {},
+ const uint8_t& pending = {});
+
+ struct CreateModeRequest {
+ Window window{};
+ ModeInfo mode_info{};
+ std::string name{};
+ };
+
+ struct CreateModeReply {
+ uint16_t sequence{};
+ Mode mode{};
+ };
+
+ using CreateModeResponse = Response<CreateModeReply>;
+
+ Future<CreateModeReply> CreateMode(const CreateModeRequest& request);
+
+ Future<CreateModeReply> CreateMode(
+ const Window& window = {},
+ const ModeInfo& mode_info =
+ {{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}},
+ const std::string& name = {});
+
+ struct DestroyModeRequest {
+ Mode mode{};
+ };
+
+ using DestroyModeResponse = Response<void>;
+
+ Future<void> DestroyMode(const DestroyModeRequest& request);
+
+ Future<void> DestroyMode(const Mode& mode = {});
+
+ struct AddOutputModeRequest {
+ Output output{};
+ Mode mode{};
+ };
+
+ using AddOutputModeResponse = Response<void>;
+
+ Future<void> AddOutputMode(const AddOutputModeRequest& request);
+
+ Future<void> AddOutputMode(const Output& output = {}, const Mode& mode = {});
+
+ struct DeleteOutputModeRequest {
+ Output output{};
+ Mode mode{};
+ };
+
+ using DeleteOutputModeResponse = Response<void>;
+
+ Future<void> DeleteOutputMode(const DeleteOutputModeRequest& request);
+
+ Future<void> DeleteOutputMode(const Output& output = {},
+ const Mode& mode = {});
+
+ struct GetCrtcInfoRequest {
+ Crtc crtc{};
+ Time config_timestamp{};
+ };
+
+ struct GetCrtcInfoReply {
+ SetConfig status{};
+ uint16_t sequence{};
+ Time timestamp{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ Mode mode{};
+ Rotation rotation{};
+ Rotation rotations{};
+ std::vector<Output> outputs{};
+ std::vector<Output> possible{};
+ };
+
+ using GetCrtcInfoResponse = Response<GetCrtcInfoReply>;
+
+ Future<GetCrtcInfoReply> GetCrtcInfo(const GetCrtcInfoRequest& request);
+
+ Future<GetCrtcInfoReply> GetCrtcInfo(const Crtc& crtc = {},
+ const Time& config_timestamp = {});
+
+ struct SetCrtcConfigRequest {
+ Crtc crtc{};
+ Time timestamp{};
+ Time config_timestamp{};
+ int16_t x{};
+ int16_t y{};
+ Mode mode{};
+ Rotation rotation{};
+ std::vector<Output> outputs{};
+ };
+
+ struct SetCrtcConfigReply {
+ SetConfig status{};
+ uint16_t sequence{};
+ Time timestamp{};
+ };
+
+ using SetCrtcConfigResponse = Response<SetCrtcConfigReply>;
+
+ Future<SetCrtcConfigReply> SetCrtcConfig(const SetCrtcConfigRequest& request);
+
+ Future<SetCrtcConfigReply> SetCrtcConfig(
+ const Crtc& crtc = {},
+ const Time& timestamp = {},
+ const Time& config_timestamp = {},
+ const int16_t& x = {},
+ const int16_t& y = {},
+ const Mode& mode = {},
+ const Rotation& rotation = {},
+ const std::vector<Output>& outputs = {});
+
+ struct GetCrtcGammaSizeRequest {
+ Crtc crtc{};
+ };
+
+ struct GetCrtcGammaSizeReply {
+ uint16_t sequence{};
+ uint16_t size{};
+ };
+
+ using GetCrtcGammaSizeResponse = Response<GetCrtcGammaSizeReply>;
+
+ Future<GetCrtcGammaSizeReply> GetCrtcGammaSize(
+ const GetCrtcGammaSizeRequest& request);
+
+ Future<GetCrtcGammaSizeReply> GetCrtcGammaSize(const Crtc& crtc = {});
+
+ struct GetCrtcGammaRequest {
+ Crtc crtc{};
+ };
+
+ struct GetCrtcGammaReply {
+ uint16_t sequence{};
+ std::vector<uint16_t> red{};
+ std::vector<uint16_t> green{};
+ std::vector<uint16_t> blue{};
+ };
+
+ using GetCrtcGammaResponse = Response<GetCrtcGammaReply>;
+
+ Future<GetCrtcGammaReply> GetCrtcGamma(const GetCrtcGammaRequest& request);
+
+ Future<GetCrtcGammaReply> GetCrtcGamma(const Crtc& crtc = {});
+
+ struct SetCrtcGammaRequest {
+ Crtc crtc{};
+ std::vector<uint16_t> red{};
+ std::vector<uint16_t> green{};
+ std::vector<uint16_t> blue{};
+ };
+
+ using SetCrtcGammaResponse = Response<void>;
+
+ Future<void> SetCrtcGamma(const SetCrtcGammaRequest& request);
+
+ Future<void> SetCrtcGamma(const Crtc& crtc = {},
+ const std::vector<uint16_t>& red = {},
+ const std::vector<uint16_t>& green = {},
+ const std::vector<uint16_t>& blue = {});
+
+ struct GetScreenResourcesCurrentRequest {
+ Window window{};
+ };
+
+ struct GetScreenResourcesCurrentReply {
+ uint16_t sequence{};
+ Time timestamp{};
+ Time config_timestamp{};
+ std::vector<Crtc> crtcs{};
+ std::vector<Output> outputs{};
+ std::vector<ModeInfo> modes{};
+ std::vector<uint8_t> names{};
+ };
+
+ using GetScreenResourcesCurrentResponse =
+ Response<GetScreenResourcesCurrentReply>;
+
+ Future<GetScreenResourcesCurrentReply> GetScreenResourcesCurrent(
+ const GetScreenResourcesCurrentRequest& request);
+
+ Future<GetScreenResourcesCurrentReply> GetScreenResourcesCurrent(
+ const Window& window = {});
+
+ struct SetCrtcTransformRequest {
+ Crtc crtc{};
+ Render::Transform transform{};
+ std::string filter_name{};
+ std::vector<Render::Fixed> filter_params{};
+ };
+
+ using SetCrtcTransformResponse = Response<void>;
+
+ Future<void> SetCrtcTransform(const SetCrtcTransformRequest& request);
+
+ Future<void> SetCrtcTransform(
+ const Crtc& crtc = {},
+ const Render::Transform& transform = {{}, {}, {}, {}, {}, {}, {}, {}, {}},
+ const std::string& filter_name = {},
+ const std::vector<Render::Fixed>& filter_params = {});
+
+ struct GetCrtcTransformRequest {
+ Crtc crtc{};
+ };
+
+ struct GetCrtcTransformReply {
+ uint16_t sequence{};
+ Render::Transform pending_transform{};
+ uint8_t has_transforms{};
+ Render::Transform current_transform{};
+ std::string pending_filter_name{};
+ std::vector<Render::Fixed> pending_params{};
+ std::string current_filter_name{};
+ std::vector<Render::Fixed> current_params{};
+ };
+
+ using GetCrtcTransformResponse = Response<GetCrtcTransformReply>;
+
+ Future<GetCrtcTransformReply> GetCrtcTransform(
+ const GetCrtcTransformRequest& request);
+
+ Future<GetCrtcTransformReply> GetCrtcTransform(const Crtc& crtc = {});
+
+ struct GetPanningRequest {
+ Crtc crtc{};
+ };
+
+ struct GetPanningReply {
+ SetConfig status{};
+ uint16_t sequence{};
+ Time timestamp{};
+ uint16_t left{};
+ uint16_t top{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t track_left{};
+ uint16_t track_top{};
+ uint16_t track_width{};
+ uint16_t track_height{};
+ int16_t border_left{};
+ int16_t border_top{};
+ int16_t border_right{};
+ int16_t border_bottom{};
+ };
+
+ using GetPanningResponse = Response<GetPanningReply>;
+
+ Future<GetPanningReply> GetPanning(const GetPanningRequest& request);
+
+ Future<GetPanningReply> GetPanning(const Crtc& crtc = {});
+
+ struct SetPanningRequest {
+ Crtc crtc{};
+ Time timestamp{};
+ uint16_t left{};
+ uint16_t top{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t track_left{};
+ uint16_t track_top{};
+ uint16_t track_width{};
+ uint16_t track_height{};
+ int16_t border_left{};
+ int16_t border_top{};
+ int16_t border_right{};
+ int16_t border_bottom{};
+ };
+
+ struct SetPanningReply {
+ SetConfig status{};
+ uint16_t sequence{};
+ Time timestamp{};
+ };
+
+ using SetPanningResponse = Response<SetPanningReply>;
+
+ Future<SetPanningReply> SetPanning(const SetPanningRequest& request);
+
+ Future<SetPanningReply> SetPanning(const Crtc& crtc = {},
+ const Time& timestamp = {},
+ const uint16_t& left = {},
+ const uint16_t& top = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint16_t& track_left = {},
+ const uint16_t& track_top = {},
+ const uint16_t& track_width = {},
+ const uint16_t& track_height = {},
+ const int16_t& border_left = {},
+ const int16_t& border_top = {},
+ const int16_t& border_right = {},
+ const int16_t& border_bottom = {});
+
+ struct SetOutputPrimaryRequest {
+ Window window{};
+ Output output{};
+ };
+
+ using SetOutputPrimaryResponse = Response<void>;
+
+ Future<void> SetOutputPrimary(const SetOutputPrimaryRequest& request);
+
+ Future<void> SetOutputPrimary(const Window& window = {},
+ const Output& output = {});
+
+ struct GetOutputPrimaryRequest {
+ Window window{};
+ };
+
+ struct GetOutputPrimaryReply {
+ uint16_t sequence{};
+ Output output{};
+ };
+
+ using GetOutputPrimaryResponse = Response<GetOutputPrimaryReply>;
+
+ Future<GetOutputPrimaryReply> GetOutputPrimary(
+ const GetOutputPrimaryRequest& request);
+
+ Future<GetOutputPrimaryReply> GetOutputPrimary(const Window& window = {});
+
+ struct GetProvidersRequest {
+ Window window{};
+ };
+
+ struct GetProvidersReply {
+ uint16_t sequence{};
+ Time timestamp{};
+ std::vector<Provider> providers{};
+ };
+
+ using GetProvidersResponse = Response<GetProvidersReply>;
+
+ Future<GetProvidersReply> GetProviders(const GetProvidersRequest& request);
+
+ Future<GetProvidersReply> GetProviders(const Window& window = {});
+
+ struct GetProviderInfoRequest {
+ Provider provider{};
+ Time config_timestamp{};
+ };
+
+ struct GetProviderInfoReply {
+ uint8_t status{};
+ uint16_t sequence{};
+ Time timestamp{};
+ ProviderCapability capabilities{};
+ std::vector<Crtc> crtcs{};
+ std::vector<Output> outputs{};
+ std::vector<Provider> associated_providers{};
+ std::vector<uint32_t> associated_capability{};
+ std::string name{};
+ };
+
+ using GetProviderInfoResponse = Response<GetProviderInfoReply>;
+
+ Future<GetProviderInfoReply> GetProviderInfo(
+ const GetProviderInfoRequest& request);
+
+ Future<GetProviderInfoReply> GetProviderInfo(
+ const Provider& provider = {},
+ const Time& config_timestamp = {});
+
+ struct SetProviderOffloadSinkRequest {
+ Provider provider{};
+ Provider sink_provider{};
+ Time config_timestamp{};
+ };
+
+ using SetProviderOffloadSinkResponse = Response<void>;
+
+ Future<void> SetProviderOffloadSink(
+ const SetProviderOffloadSinkRequest& request);
+
+ Future<void> SetProviderOffloadSink(const Provider& provider = {},
+ const Provider& sink_provider = {},
+ const Time& config_timestamp = {});
+
+ struct SetProviderOutputSourceRequest {
+ Provider provider{};
+ Provider source_provider{};
+ Time config_timestamp{};
+ };
+
+ using SetProviderOutputSourceResponse = Response<void>;
+
+ Future<void> SetProviderOutputSource(
+ const SetProviderOutputSourceRequest& request);
+
+ Future<void> SetProviderOutputSource(const Provider& provider = {},
+ const Provider& source_provider = {},
+ const Time& config_timestamp = {});
+
+ struct ListProviderPropertiesRequest {
+ Provider provider{};
+ };
+
+ struct ListProviderPropertiesReply {
+ uint16_t sequence{};
+ std::vector<Atom> atoms{};
+ };
+
+ using ListProviderPropertiesResponse = Response<ListProviderPropertiesReply>;
+
+ Future<ListProviderPropertiesReply> ListProviderProperties(
+ const ListProviderPropertiesRequest& request);
+
+ Future<ListProviderPropertiesReply> ListProviderProperties(
+ const Provider& provider = {});
+
+ struct QueryProviderPropertyRequest {
+ Provider provider{};
+ Atom property{};
+ };
+
+ struct QueryProviderPropertyReply {
+ uint16_t sequence{};
+ uint8_t pending{};
+ uint8_t range{};
+ uint8_t immutable{};
+ std::vector<int32_t> valid_values{};
+ };
+
+ using QueryProviderPropertyResponse = Response<QueryProviderPropertyReply>;
+
+ Future<QueryProviderPropertyReply> QueryProviderProperty(
+ const QueryProviderPropertyRequest& request);
+
+ Future<QueryProviderPropertyReply> QueryProviderProperty(
+ const Provider& provider = {},
+ const Atom& property = {});
+
+ struct ConfigureProviderPropertyRequest {
+ Provider provider{};
+ Atom property{};
+ uint8_t pending{};
+ uint8_t range{};
+ std::vector<int32_t> values{};
+ };
+
+ using ConfigureProviderPropertyResponse = Response<void>;
+
+ Future<void> ConfigureProviderProperty(
+ const ConfigureProviderPropertyRequest& request);
+
+ Future<void> ConfigureProviderProperty(
+ const Provider& provider = {},
+ const Atom& property = {},
+ const uint8_t& pending = {},
+ const uint8_t& range = {},
+ const std::vector<int32_t>& values = {});
+
+ struct ChangeProviderPropertyRequest {
+ Provider provider{};
+ Atom property{};
+ Atom type{};
+ uint8_t format{};
+ uint8_t mode{};
+ uint32_t num_items{};
+ scoped_refptr<base::RefCountedMemory> data{};
+ };
+
+ using ChangeProviderPropertyResponse = Response<void>;
+
+ Future<void> ChangeProviderProperty(
+ const ChangeProviderPropertyRequest& request);
+
+ Future<void> ChangeProviderProperty(
+ const Provider& provider = {},
+ const Atom& property = {},
+ const Atom& type = {},
+ const uint8_t& format = {},
+ const uint8_t& mode = {},
+ const uint32_t& num_items = {},
+ const scoped_refptr<base::RefCountedMemory>& data = {});
+
+ struct DeleteProviderPropertyRequest {
+ Provider provider{};
+ Atom property{};
+ };
+
+ using DeleteProviderPropertyResponse = Response<void>;
+
+ Future<void> DeleteProviderProperty(
+ const DeleteProviderPropertyRequest& request);
+
+ Future<void> DeleteProviderProperty(const Provider& provider = {},
+ const Atom& property = {});
+
+ struct GetProviderPropertyRequest {
+ Provider provider{};
+ Atom property{};
+ Atom type{};
+ uint32_t long_offset{};
+ uint32_t long_length{};
+ uint8_t c_delete{};
+ uint8_t pending{};
+ };
+
+ struct GetProviderPropertyReply {
+ uint8_t format{};
+ uint16_t sequence{};
+ Atom type{};
+ uint32_t bytes_after{};
+ uint32_t num_items{};
+ scoped_refptr<base::RefCountedMemory> data{};
+ };
+
+ using GetProviderPropertyResponse = Response<GetProviderPropertyReply>;
+
+ Future<GetProviderPropertyReply> GetProviderProperty(
+ const GetProviderPropertyRequest& request);
+
+ Future<GetProviderPropertyReply> GetProviderProperty(
+ const Provider& provider = {},
+ const Atom& property = {},
+ const Atom& type = {},
+ const uint32_t& long_offset = {},
+ const uint32_t& long_length = {},
+ const uint8_t& c_delete = {},
+ const uint8_t& pending = {});
+
+ struct GetMonitorsRequest {
+ Window window{};
+ uint8_t get_active{};
+ };
+
+ struct GetMonitorsReply {
+ uint16_t sequence{};
+ Time timestamp{};
+ uint32_t nOutputs{};
+ std::vector<MonitorInfo> monitors{};
+ };
+
+ using GetMonitorsResponse = Response<GetMonitorsReply>;
+
+ Future<GetMonitorsReply> GetMonitors(const GetMonitorsRequest& request);
+
+ Future<GetMonitorsReply> GetMonitors(const Window& window = {},
+ const uint8_t& get_active = {});
+
+ struct SetMonitorRequest {
+ Window window{};
+ MonitorInfo monitorinfo{};
+ };
+
+ using SetMonitorResponse = Response<void>;
+
+ Future<void> SetMonitor(const SetMonitorRequest& request);
+
+ Future<void> SetMonitor(const Window& window = {},
+ const MonitorInfo& monitorinfo =
+ {{}, {}, {}, {}, {}, {}, {}, {}, {}, {}});
+
+ struct DeleteMonitorRequest {
+ Window window{};
+ Atom name{};
+ };
+
+ using DeleteMonitorResponse = Response<void>;
+
+ Future<void> DeleteMonitor(const DeleteMonitorRequest& request);
+
+ Future<void> DeleteMonitor(const Window& window = {}, const Atom& name = {});
+
+ struct CreateLeaseRequest {
+ Window window{};
+ Lease lid{};
+ std::vector<Crtc> crtcs{};
+ std::vector<Output> outputs{};
+ };
+
+ struct CreateLeaseReply {
+ uint8_t nfd{};
+ uint16_t sequence{};
+ RefCountedFD master_fd{};
+ };
+
+ using CreateLeaseResponse = Response<CreateLeaseReply>;
+
+ Future<CreateLeaseReply> CreateLease(const CreateLeaseRequest& request);
+
+ Future<CreateLeaseReply> CreateLease(const Window& window = {},
+ const Lease& lid = {},
+ const std::vector<Crtc>& crtcs = {},
+ const std::vector<Output>& outputs = {});
+
+ struct FreeLeaseRequest {
+ Lease lid{};
+ uint8_t terminate{};
+ };
+
+ using FreeLeaseResponse = Response<void>;
+
+ Future<void> FreeLease(const FreeLeaseRequest& request);
+
+ Future<void> FreeLease(const Lease& lid = {}, const uint8_t& terminate = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::RandR::Rotation operator|(x11::RandR::Rotation l,
+ x11::RandR::Rotation r) {
+ using T = std::underlying_type_t<x11::RandR::Rotation>;
+ return static_cast<x11::RandR::Rotation>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::Rotation operator&(x11::RandR::Rotation l,
+ x11::RandR::Rotation r) {
+ using T = std::underlying_type_t<x11::RandR::Rotation>;
+ return static_cast<x11::RandR::Rotation>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::SetConfig operator|(x11::RandR::SetConfig l,
+ x11::RandR::SetConfig r) {
+ using T = std::underlying_type_t<x11::RandR::SetConfig>;
+ return static_cast<x11::RandR::SetConfig>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::SetConfig operator&(x11::RandR::SetConfig l,
+ x11::RandR::SetConfig r) {
+ using T = std::underlying_type_t<x11::RandR::SetConfig>;
+ return static_cast<x11::RandR::SetConfig>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::NotifyMask operator|(x11::RandR::NotifyMask l,
+ x11::RandR::NotifyMask r) {
+ using T = std::underlying_type_t<x11::RandR::NotifyMask>;
+ return static_cast<x11::RandR::NotifyMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::NotifyMask operator&(x11::RandR::NotifyMask l,
+ x11::RandR::NotifyMask r) {
+ using T = std::underlying_type_t<x11::RandR::NotifyMask>;
+ return static_cast<x11::RandR::NotifyMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::ModeFlag operator|(x11::RandR::ModeFlag l,
+ x11::RandR::ModeFlag r) {
+ using T = std::underlying_type_t<x11::RandR::ModeFlag>;
+ return static_cast<x11::RandR::ModeFlag>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::ModeFlag operator&(x11::RandR::ModeFlag l,
+ x11::RandR::ModeFlag r) {
+ using T = std::underlying_type_t<x11::RandR::ModeFlag>;
+ return static_cast<x11::RandR::ModeFlag>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::RandRConnection operator|(
+ x11::RandR::RandRConnection l,
+ x11::RandR::RandRConnection r) {
+ using T = std::underlying_type_t<x11::RandR::RandRConnection>;
+ return static_cast<x11::RandR::RandRConnection>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::RandRConnection operator&(
+ x11::RandR::RandRConnection l,
+ x11::RandR::RandRConnection r) {
+ using T = std::underlying_type_t<x11::RandR::RandRConnection>;
+ return static_cast<x11::RandR::RandRConnection>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::Transform operator|(x11::RandR::Transform l,
+ x11::RandR::Transform r) {
+ using T = std::underlying_type_t<x11::RandR::Transform>;
+ return static_cast<x11::RandR::Transform>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::Transform operator&(x11::RandR::Transform l,
+ x11::RandR::Transform r) {
+ using T = std::underlying_type_t<x11::RandR::Transform>;
+ return static_cast<x11::RandR::Transform>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::ProviderCapability operator|(
+ x11::RandR::ProviderCapability l,
+ x11::RandR::ProviderCapability r) {
+ using T = std::underlying_type_t<x11::RandR::ProviderCapability>;
+ return static_cast<x11::RandR::ProviderCapability>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::ProviderCapability operator&(
+ x11::RandR::ProviderCapability l,
+ x11::RandR::ProviderCapability r) {
+ using T = std::underlying_type_t<x11::RandR::ProviderCapability>;
+ return static_cast<x11::RandR::ProviderCapability>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::Notify operator|(x11::RandR::Notify l,
+ x11::RandR::Notify r) {
+ using T = std::underlying_type_t<x11::RandR::Notify>;
+ return static_cast<x11::RandR::Notify>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::RandR::Notify operator&(x11::RandR::Notify l,
+ x11::RandR::Notify r) {
+ using T = std::underlying_type_t<x11::RandR::Notify>;
+ return static_cast<x11::RandR::Notify>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_RANDR_H_
diff --git a/chromium/ui/gfx/x/generated_protos/read_error.cc b/chromium/ui/gfx/x/generated_protos/read_error.cc
new file mode 100644
index 00000000000..1414180562d
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/read_error.cc
@@ -0,0 +1,530 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+#include "ui/gfx/x/bigreq.h"
+#include "ui/gfx/x/composite.h"
+#include "ui/gfx/x/damage.h"
+#include "ui/gfx/x/dpms.h"
+#include "ui/gfx/x/dri2.h"
+#include "ui/gfx/x/dri3.h"
+#include "ui/gfx/x/ge.h"
+#include "ui/gfx/x/glx.h"
+#include "ui/gfx/x/present.h"
+#include "ui/gfx/x/randr.h"
+#include "ui/gfx/x/record.h"
+#include "ui/gfx/x/render.h"
+#include "ui/gfx/x/res.h"
+#include "ui/gfx/x/screensaver.h"
+#include "ui/gfx/x/shape.h"
+#include "ui/gfx/x/shm.h"
+#include "ui/gfx/x/sync.h"
+#include "ui/gfx/x/xc_misc.h"
+#include "ui/gfx/x/xevie.h"
+#include "ui/gfx/x/xf86dri.h"
+#include "ui/gfx/x/xf86vidmode.h"
+#include "ui/gfx/x/xfixes.h"
+#include "ui/gfx/x/xinerama.h"
+#include "ui/gfx/x/xinput.h"
+#include "ui/gfx/x/xkb.h"
+#include "ui/gfx/x/xprint.h"
+#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xselinux.h"
+#include "ui/gfx/x/xtest.h"
+#include "ui/gfx/x/xv.h"
+#include "ui/gfx/x/xvmc.h"
+
+namespace x11 {
+
+namespace {
+
+template <typename T>
+std::unique_ptr<Error> MakeError(Connection::RawError error_) {
+ ReadBuffer buf(error_);
+ auto error = std::make_unique<T>();
+ ReadError(error.get(), &buf);
+ return error;
+}
+
+} // namespace
+
+void Connection::InitErrorParsers() {
+ uint8_t first_errors[256];
+ memset(first_errors, 0, sizeof(first_errors));
+
+ auto add_parser = [&](uint8_t error_code, uint8_t first_error,
+ ErrorParser parser) {
+ if (!error_parsers_[error_code] || first_error > first_errors[error_code]) {
+ first_errors[error_code] = error_code;
+ error_parsers_[error_code] = parser;
+ }
+ };
+
+ if (damage().present()) {
+ uint8_t first_error = damage().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<Damage::BadDamageError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (glx().present()) {
+ uint8_t first_error = glx().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<Glx::BadContextError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 1;
+ auto parse = MakeError<Glx::BadContextStateError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 2;
+ auto parse = MakeError<Glx::BadDrawableError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 3;
+ auto parse = MakeError<Glx::BadPixmapError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 4;
+ auto parse = MakeError<Glx::BadContextTagError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 5;
+ auto parse = MakeError<Glx::BadCurrentWindowError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 6;
+ auto parse = MakeError<Glx::BadRenderRequestError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 7;
+ auto parse = MakeError<Glx::BadLargeRequestError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 8;
+ auto parse = MakeError<Glx::UnsupportedPrivateRequestError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 9;
+ auto parse = MakeError<Glx::BadFBConfigError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 10;
+ auto parse = MakeError<Glx::BadPbufferError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 11;
+ auto parse = MakeError<Glx::BadCurrentDrawableError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 12;
+ auto parse = MakeError<Glx::BadWindowError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 13;
+ auto parse = MakeError<Glx::GLXBadProfileARBError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (randr().present()) {
+ uint8_t first_error = randr().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<RandR::BadOutputError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 1;
+ auto parse = MakeError<RandR::BadCrtcError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 2;
+ auto parse = MakeError<RandR::BadModeError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 3;
+ auto parse = MakeError<RandR::BadProviderError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (record().present()) {
+ uint8_t first_error = record().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<Record::BadContextError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (render().present()) {
+ uint8_t first_error = render().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<Render::PictFormatError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 1;
+ auto parse = MakeError<Render::PictureError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 2;
+ auto parse = MakeError<Render::PictOpError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 3;
+ auto parse = MakeError<Render::GlyphSetError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 4;
+ auto parse = MakeError<Render::GlyphError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (shm().present()) {
+ uint8_t first_error = shm().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<Shm::BadSegError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 2;
+ auto parse = MakeError<ValueError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 3;
+ auto parse = MakeError<WindowError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 4;
+ auto parse = MakeError<PixmapError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 5;
+ auto parse = MakeError<AtomError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 6;
+ auto parse = MakeError<CursorError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 7;
+ auto parse = MakeError<FontError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 9;
+ auto parse = MakeError<DrawableError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 12;
+ auto parse = MakeError<ColormapError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 13;
+ auto parse = MakeError<GContextError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 14;
+ auto parse = MakeError<IDChoiceError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (sync().present()) {
+ uint8_t first_error = sync().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<Sync::CounterError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 1;
+ auto parse = MakeError<Sync::AlarmError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (xf86vidmode().present()) {
+ uint8_t first_error = xf86vidmode().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<XF86VidMode::BadClockError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 1;
+ auto parse = MakeError<XF86VidMode::BadHTimingsError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 2;
+ auto parse = MakeError<XF86VidMode::BadVTimingsError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 3;
+ auto parse = MakeError<XF86VidMode::ModeUnsuitableError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 4;
+ auto parse = MakeError<XF86VidMode::ExtensionDisabledError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 5;
+ auto parse = MakeError<XF86VidMode::ClientNotLocalError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 6;
+ auto parse = MakeError<XF86VidMode::ZoomLockedError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (xfixes().present()) {
+ uint8_t first_error = xfixes().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<XFixes::BadRegionError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (xinput().present()) {
+ uint8_t first_error = xinput().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<Input::DeviceError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 1;
+ auto parse = MakeError<Input::EventError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 2;
+ auto parse = MakeError<Input::ModeError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 3;
+ auto parse = MakeError<Input::DeviceBusyError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 4;
+ auto parse = MakeError<Input::ClassError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (xkb().present()) {
+ uint8_t first_error = xkb().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<Xkb::KeyboardError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (xprint().present()) {
+ uint8_t first_error = xprint().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<XPrint::BadContextError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 1;
+ auto parse = MakeError<XPrint::BadSequenceError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ {
+ uint8_t first_error = 0;
+ {
+ auto error_code = first_error + 1;
+ auto parse = MakeError<RequestError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 2;
+ auto parse = MakeError<ValueError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 3;
+ auto parse = MakeError<WindowError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 4;
+ auto parse = MakeError<PixmapError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 5;
+ auto parse = MakeError<AtomError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 6;
+ auto parse = MakeError<CursorError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 7;
+ auto parse = MakeError<FontError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 8;
+ auto parse = MakeError<MatchError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 9;
+ auto parse = MakeError<DrawableError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 10;
+ auto parse = MakeError<AccessError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 11;
+ auto parse = MakeError<AllocError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 12;
+ auto parse = MakeError<ColormapError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 13;
+ auto parse = MakeError<GContextError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 14;
+ auto parse = MakeError<IDChoiceError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 15;
+ auto parse = MakeError<NameError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 16;
+ auto parse = MakeError<LengthError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 17;
+ auto parse = MakeError<ImplementationError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+
+ if (xv().present()) {
+ uint8_t first_error = xv().first_error();
+ {
+ auto error_code = first_error + 0;
+ auto parse = MakeError<Xv::BadPortError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 1;
+ auto parse = MakeError<Xv::BadEncodingError>;
+ add_parser(error_code, first_error, parse);
+ }
+ {
+ auto error_code = first_error + 2;
+ auto parse = MakeError<Xv::BadControlError>;
+ add_parser(error_code, first_error, parse);
+ }
+ }
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/read_event.cc b/chromium/ui/gfx/x/generated_protos/read_event.cc
new file mode 100644
index 00000000000..a6a308f6003
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/read_event.cc
@@ -0,0 +1,1260 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "ui/gfx/x/event.h"
+
+#include <xcb/xcb.h>
+
+#include "ui/gfx/x/bigreq.h"
+#include "ui/gfx/x/composite.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/damage.h"
+#include "ui/gfx/x/dpms.h"
+#include "ui/gfx/x/dri2.h"
+#include "ui/gfx/x/dri3.h"
+#include "ui/gfx/x/ge.h"
+#include "ui/gfx/x/glx.h"
+#include "ui/gfx/x/present.h"
+#include "ui/gfx/x/randr.h"
+#include "ui/gfx/x/record.h"
+#include "ui/gfx/x/render.h"
+#include "ui/gfx/x/res.h"
+#include "ui/gfx/x/screensaver.h"
+#include "ui/gfx/x/shape.h"
+#include "ui/gfx/x/shm.h"
+#include "ui/gfx/x/sync.h"
+#include "ui/gfx/x/xc_misc.h"
+#include "ui/gfx/x/xevie.h"
+#include "ui/gfx/x/xf86dri.h"
+#include "ui/gfx/x/xf86vidmode.h"
+#include "ui/gfx/x/xfixes.h"
+#include "ui/gfx/x/xinerama.h"
+#include "ui/gfx/x/xinput.h"
+#include "ui/gfx/x/xkb.h"
+#include "ui/gfx/x/xprint.h"
+#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_types.h"
+#include "ui/gfx/x/xselinux.h"
+#include "ui/gfx/x/xtest.h"
+#include "ui/gfx/x/xv.h"
+#include "ui/gfx/x/xvmc.h"
+
+namespace x11 {
+
+void ReadEvent(Event* event, Connection* conn, ReadBuffer* buffer) {
+ auto* buf = buffer->data->data();
+ auto* ev = reinterpret_cast<const xcb_generic_event_t*>(buf);
+ auto* ge = reinterpret_cast<const xcb_ge_generic_event_t*>(buf);
+ auto evtype = ev->response_type & ~kSendEventMask;
+ bool send_event = ev->response_type & kSendEventMask;
+
+ if (conn->damage().present() &&
+ evtype - conn->damage().first_event() == Damage::NotifyEvent::opcode) {
+ event->type_id_ = 1;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Damage::NotifyEvent*>(event);
+ };
+ auto* event_ = new Damage::NotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->dri2().present() && evtype - conn->dri2().first_event() ==
+ Dri2::BufferSwapCompleteEvent::opcode) {
+ event->type_id_ = 2;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Dri2::BufferSwapCompleteEvent*>(event);
+ };
+ auto* event_ = new Dri2::BufferSwapCompleteEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->dri2().present() && evtype - conn->dri2().first_event() ==
+ Dri2::InvalidateBuffersEvent::opcode) {
+ event->type_id_ = 3;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Dri2::InvalidateBuffersEvent*>(event);
+ };
+ auto* event_ = new Dri2::InvalidateBuffersEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->glx().present() &&
+ evtype - conn->glx().first_event() == Glx::PbufferClobberEvent::opcode) {
+ event->type_id_ = 4;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Glx::PbufferClobberEvent*>(event);
+ };
+ auto* event_ = new Glx::PbufferClobberEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->glx().present() && evtype - conn->glx().first_event() ==
+ Glx::BufferSwapCompleteEvent::opcode) {
+ event->type_id_ = 5;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Glx::BufferSwapCompleteEvent*>(event);
+ };
+ auto* event_ = new Glx::BufferSwapCompleteEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->present().present() &&
+ evtype - conn->present().first_event() == Present::GenericEvent::opcode) {
+ event->type_id_ = 6;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Present::GenericEvent*>(event);
+ };
+ auto* event_ = new Present::GenericEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->present().present() &&
+ ge->extension == conn->present().major_opcode() &&
+ ge->event_type == Present::ConfigureNotifyEvent::opcode) {
+ event->type_id_ = 7;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Present::ConfigureNotifyEvent*>(event);
+ };
+ auto* event_ = new Present::ConfigureNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->present().present() &&
+ ge->extension == conn->present().major_opcode() &&
+ ge->event_type == Present::CompleteNotifyEvent::opcode) {
+ event->type_id_ = 8;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Present::CompleteNotifyEvent*>(event);
+ };
+ auto* event_ = new Present::CompleteNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->present().present() &&
+ ge->extension == conn->present().major_opcode() &&
+ ge->event_type == Present::IdleNotifyEvent::opcode) {
+ event->type_id_ = 9;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Present::IdleNotifyEvent*>(event);
+ };
+ auto* event_ = new Present::IdleNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->present().present() &&
+ ge->extension == conn->present().major_opcode() &&
+ ge->event_type == Present::RedirectNotifyEvent::opcode) {
+ event->type_id_ = 10;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Present::RedirectNotifyEvent*>(event);
+ };
+ auto* event_ = new Present::RedirectNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->randr().present() && evtype - conn->randr().first_event() ==
+ RandR::ScreenChangeNotifyEvent::opcode) {
+ event->type_id_ = 11;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<RandR::ScreenChangeNotifyEvent*>(event);
+ };
+ auto* event_ = new RandR::ScreenChangeNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->randr().present() &&
+ evtype - conn->randr().first_event() == RandR::NotifyEvent::opcode) {
+ event->type_id_ = 12;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<RandR::NotifyEvent*>(event);
+ };
+ auto* event_ = new RandR::NotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->screensaver().present() &&
+ evtype - conn->screensaver().first_event() ==
+ ScreenSaver::NotifyEvent::opcode) {
+ event->type_id_ = 13;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<ScreenSaver::NotifyEvent*>(event);
+ };
+ auto* event_ = new ScreenSaver::NotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->shape().present() &&
+ evtype - conn->shape().first_event() == Shape::NotifyEvent::opcode) {
+ event->type_id_ = 14;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Shape::NotifyEvent*>(event);
+ };
+ auto* event_ = new Shape::NotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->shm().present() &&
+ evtype - conn->shm().first_event() == Shm::CompletionEvent::opcode) {
+ event->type_id_ = 15;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Shm::CompletionEvent*>(event);
+ };
+ auto* event_ = new Shm::CompletionEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->sync().present() &&
+ evtype - conn->sync().first_event() == Sync::CounterNotifyEvent::opcode) {
+ event->type_id_ = 16;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Sync::CounterNotifyEvent*>(event);
+ };
+ auto* event_ = new Sync::CounterNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->sync().present() &&
+ evtype - conn->sync().first_event() == Sync::AlarmNotifyEvent::opcode) {
+ event->type_id_ = 17;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Sync::AlarmNotifyEvent*>(event);
+ };
+ auto* event_ = new Sync::AlarmNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xfixes().present() && evtype - conn->xfixes().first_event() ==
+ XFixes::SelectionNotifyEvent::opcode) {
+ event->type_id_ = 18;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<XFixes::SelectionNotifyEvent*>(event);
+ };
+ auto* event_ = new XFixes::SelectionNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xfixes().present() && evtype - conn->xfixes().first_event() ==
+ XFixes::CursorNotifyEvent::opcode) {
+ event->type_id_ = 19;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<XFixes::CursorNotifyEvent*>(event);
+ };
+ auto* event_ = new XFixes::CursorNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xinput().present() && evtype - conn->xinput().first_event() ==
+ Input::DeviceValuatorEvent::opcode) {
+ event->type_id_ = 20;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::DeviceValuatorEvent*>(event);
+ };
+ auto* event_ = new Input::DeviceValuatorEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xinput().present() &&
+ (evtype - conn->xinput().first_event() ==
+ Input::LegacyDeviceEvent::DeviceButtonRelease ||
+ evtype - conn->xinput().first_event() ==
+ Input::LegacyDeviceEvent::ProximityIn ||
+ evtype - conn->xinput().first_event() ==
+ Input::LegacyDeviceEvent::DeviceKeyRelease ||
+ evtype - conn->xinput().first_event() ==
+ Input::LegacyDeviceEvent::DeviceButtonPress ||
+ evtype - conn->xinput().first_event() ==
+ Input::LegacyDeviceEvent::ProximityOut ||
+ evtype - conn->xinput().first_event() ==
+ Input::LegacyDeviceEvent::DeviceKeyPress ||
+ evtype - conn->xinput().first_event() ==
+ Input::LegacyDeviceEvent::DeviceMotionNotify)) {
+ event->type_id_ = 21;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::LegacyDeviceEvent*>(event);
+ };
+ auto* event_ = new Input::LegacyDeviceEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(
+ evtype - conn->xinput().first_event());
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xinput().present() &&
+ (evtype - conn->xinput().first_event() == Input::DeviceFocusEvent::In ||
+ evtype - conn->xinput().first_event() == Input::DeviceFocusEvent::Out)) {
+ event->type_id_ = 22;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::DeviceFocusEvent*>(event);
+ };
+ auto* event_ = new Input::DeviceFocusEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(
+ evtype - conn->xinput().first_event());
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xinput().present() && evtype - conn->xinput().first_event() ==
+ Input::DeviceStateNotifyEvent::opcode) {
+ event->type_id_ = 23;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::DeviceStateNotifyEvent*>(event);
+ };
+ auto* event_ = new Input::DeviceStateNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xinput().present() && evtype - conn->xinput().first_event() ==
+ Input::DeviceMappingNotifyEvent::opcode) {
+ event->type_id_ = 24;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::DeviceMappingNotifyEvent*>(event);
+ };
+ auto* event_ = new Input::DeviceMappingNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xinput().present() && evtype - conn->xinput().first_event() ==
+ Input::ChangeDeviceNotifyEvent::opcode) {
+ event->type_id_ = 25;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::ChangeDeviceNotifyEvent*>(event);
+ };
+ auto* event_ = new Input::ChangeDeviceNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xinput().present() &&
+ evtype - conn->xinput().first_event() ==
+ Input::DeviceKeyStateNotifyEvent::opcode) {
+ event->type_id_ = 26;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::DeviceKeyStateNotifyEvent*>(event);
+ };
+ auto* event_ = new Input::DeviceKeyStateNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xinput().present() &&
+ evtype - conn->xinput().first_event() ==
+ Input::DeviceButtonStateNotifyEvent::opcode) {
+ event->type_id_ = 27;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::DeviceButtonStateNotifyEvent*>(event);
+ };
+ auto* event_ = new Input::DeviceButtonStateNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xinput().present() &&
+ evtype - conn->xinput().first_event() ==
+ Input::DevicePresenceNotifyEvent::opcode) {
+ event->type_id_ = 28;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::DevicePresenceNotifyEvent*>(event);
+ };
+ auto* event_ = new Input::DevicePresenceNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xinput().present() &&
+ evtype - conn->xinput().first_event() ==
+ Input::DevicePropertyNotifyEvent::opcode) {
+ event->type_id_ = 29;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::DevicePropertyNotifyEvent*>(event);
+ };
+ auto* event_ = new Input::DevicePropertyNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
+ ge->extension == conn->xinput().major_opcode() &&
+ ge->event_type == Input::DeviceChangedEvent::opcode) {
+ event->type_id_ = 30;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::DeviceChangedEvent*>(event);
+ };
+ auto* event_ = new Input::DeviceChangedEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
+ ge->extension == conn->xinput().major_opcode() &&
+ (ge->event_type == Input::DeviceEvent::ButtonPress ||
+ ge->event_type == Input::DeviceEvent::TouchEnd ||
+ ge->event_type == Input::DeviceEvent::KeyRelease ||
+ ge->event_type == Input::DeviceEvent::TouchUpdate ||
+ ge->event_type == Input::DeviceEvent::KeyPress ||
+ ge->event_type == Input::DeviceEvent::Motion ||
+ ge->event_type == Input::DeviceEvent::TouchBegin ||
+ ge->event_type == Input::DeviceEvent::ButtonRelease)) {
+ event->type_id_ = 31;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::DeviceEvent*>(event);
+ };
+ auto* event_ = new Input::DeviceEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(ge->event_type);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
+ ge->extension == conn->xinput().major_opcode() &&
+ (ge->event_type == Input::CrossingEvent::Leave ||
+ ge->event_type == Input::CrossingEvent::FocusIn ||
+ ge->event_type == Input::CrossingEvent::FocusOut ||
+ ge->event_type == Input::CrossingEvent::Enter)) {
+ event->type_id_ = 32;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::CrossingEvent*>(event);
+ };
+ auto* event_ = new Input::CrossingEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(ge->event_type);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
+ ge->extension == conn->xinput().major_opcode() &&
+ ge->event_type == Input::HierarchyEvent::opcode) {
+ event->type_id_ = 33;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::HierarchyEvent*>(event);
+ };
+ auto* event_ = new Input::HierarchyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
+ ge->extension == conn->xinput().major_opcode() &&
+ ge->event_type == Input::PropertyEvent::opcode) {
+ event->type_id_ = 34;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::PropertyEvent*>(event);
+ };
+ auto* event_ = new Input::PropertyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
+ ge->extension == conn->xinput().major_opcode() &&
+ (ge->event_type == Input::RawDeviceEvent::RawTouchEnd ||
+ ge->event_type == Input::RawDeviceEvent::RawTouchUpdate ||
+ ge->event_type == Input::RawDeviceEvent::RawTouchBegin ||
+ ge->event_type == Input::RawDeviceEvent::RawButtonRelease ||
+ ge->event_type == Input::RawDeviceEvent::RawMotion ||
+ ge->event_type == Input::RawDeviceEvent::RawButtonPress ||
+ ge->event_type == Input::RawDeviceEvent::RawKeyRelease ||
+ ge->event_type == Input::RawDeviceEvent::RawKeyPress)) {
+ event->type_id_ = 35;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::RawDeviceEvent*>(event);
+ };
+ auto* event_ = new Input::RawDeviceEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(ge->event_type);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
+ ge->extension == conn->xinput().major_opcode() &&
+ ge->event_type == Input::TouchOwnershipEvent::opcode) {
+ event->type_id_ = 36;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::TouchOwnershipEvent*>(event);
+ };
+ auto* event_ = new Input::TouchOwnershipEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
+ ge->extension == conn->xinput().major_opcode() &&
+ (ge->event_type == Input::BarrierEvent::Leave ||
+ ge->event_type == Input::BarrierEvent::Hit)) {
+ event->type_id_ = 37;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Input::BarrierEvent*>(event);
+ };
+ auto* event_ = new Input::BarrierEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(ge->event_type);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() && evtype - conn->xkb().first_event() ==
+ Xkb::NewKeyboardNotifyEvent::opcode) {
+ event->type_id_ = 38;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::NewKeyboardNotifyEvent*>(event);
+ };
+ auto* event_ = new Xkb::NewKeyboardNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() &&
+ evtype - conn->xkb().first_event() == Xkb::MapNotifyEvent::opcode) {
+ event->type_id_ = 39;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::MapNotifyEvent*>(event);
+ };
+ auto* event_ = new Xkb::MapNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() &&
+ evtype - conn->xkb().first_event() == Xkb::StateNotifyEvent::opcode) {
+ event->type_id_ = 40;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::StateNotifyEvent*>(event);
+ };
+ auto* event_ = new Xkb::StateNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() &&
+ evtype - conn->xkb().first_event() == Xkb::ControlsNotifyEvent::opcode) {
+ event->type_id_ = 41;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::ControlsNotifyEvent*>(event);
+ };
+ auto* event_ = new Xkb::ControlsNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() && evtype - conn->xkb().first_event() ==
+ Xkb::IndicatorStateNotifyEvent::opcode) {
+ event->type_id_ = 42;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::IndicatorStateNotifyEvent*>(event);
+ };
+ auto* event_ = new Xkb::IndicatorStateNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() && evtype - conn->xkb().first_event() ==
+ Xkb::IndicatorMapNotifyEvent::opcode) {
+ event->type_id_ = 43;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::IndicatorMapNotifyEvent*>(event);
+ };
+ auto* event_ = new Xkb::IndicatorMapNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() &&
+ evtype - conn->xkb().first_event() == Xkb::NamesNotifyEvent::opcode) {
+ event->type_id_ = 44;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::NamesNotifyEvent*>(event);
+ };
+ auto* event_ = new Xkb::NamesNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() &&
+ evtype - conn->xkb().first_event() == Xkb::CompatMapNotifyEvent::opcode) {
+ event->type_id_ = 45;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::CompatMapNotifyEvent*>(event);
+ };
+ auto* event_ = new Xkb::CompatMapNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() &&
+ evtype - conn->xkb().first_event() == Xkb::BellNotifyEvent::opcode) {
+ event->type_id_ = 46;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::BellNotifyEvent*>(event);
+ };
+ auto* event_ = new Xkb::BellNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() &&
+ evtype - conn->xkb().first_event() == Xkb::ActionMessageEvent::opcode) {
+ event->type_id_ = 47;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::ActionMessageEvent*>(event);
+ };
+ auto* event_ = new Xkb::ActionMessageEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() &&
+ evtype - conn->xkb().first_event() == Xkb::AccessXNotifyEvent::opcode) {
+ event->type_id_ = 48;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::AccessXNotifyEvent*>(event);
+ };
+ auto* event_ = new Xkb::AccessXNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xkb().present() && evtype - conn->xkb().first_event() ==
+ Xkb::ExtensionDeviceNotifyEvent::opcode) {
+ event->type_id_ = 49;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xkb::ExtensionDeviceNotifyEvent*>(event);
+ };
+ auto* event_ = new Xkb::ExtensionDeviceNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xprint().present() &&
+ evtype - conn->xprint().first_event() == XPrint::NotifyEvent::opcode) {
+ event->type_id_ = 50;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<XPrint::NotifyEvent*>(event);
+ };
+ auto* event_ = new XPrint::NotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xprint().present() && evtype - conn->xprint().first_event() ==
+ XPrint::AttributNotifyEvent::opcode) {
+ event->type_id_ = 51;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<XPrint::AttributNotifyEvent*>(event);
+ };
+ auto* event_ = new XPrint::AttributNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if ((evtype == KeyEvent::Release || evtype == KeyEvent::Press)) {
+ event->type_id_ = 52;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<KeyEvent*>(event);
+ };
+ auto* event_ = new KeyEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(evtype);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if ((evtype == ButtonEvent::Release || evtype == ButtonEvent::Press)) {
+ event->type_id_ = 53;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<ButtonEvent*>(event);
+ };
+ auto* event_ = new ButtonEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(evtype);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == MotionNotifyEvent::opcode) {
+ event->type_id_ = 54;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<MotionNotifyEvent*>(event);
+ };
+ auto* event_ = new MotionNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if ((evtype == CrossingEvent::EnterNotify ||
+ evtype == CrossingEvent::LeaveNotify)) {
+ event->type_id_ = 55;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<CrossingEvent*>(event);
+ };
+ auto* event_ = new CrossingEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(evtype);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if ((evtype == FocusEvent::Out || evtype == FocusEvent::In)) {
+ event->type_id_ = 56;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<FocusEvent*>(event);
+ };
+ auto* event_ = new FocusEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(evtype);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == KeymapNotifyEvent::opcode) {
+ event->type_id_ = 57;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<KeymapNotifyEvent*>(event);
+ };
+ auto* event_ = new KeymapNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == ExposeEvent::opcode) {
+ event->type_id_ = 58;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<ExposeEvent*>(event);
+ };
+ auto* event_ = new ExposeEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GraphicsExposureEvent::opcode) {
+ event->type_id_ = 59;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<GraphicsExposureEvent*>(event);
+ };
+ auto* event_ = new GraphicsExposureEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == NoExposureEvent::opcode) {
+ event->type_id_ = 60;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<NoExposureEvent*>(event);
+ };
+ auto* event_ = new NoExposureEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == VisibilityNotifyEvent::opcode) {
+ event->type_id_ = 61;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<VisibilityNotifyEvent*>(event);
+ };
+ auto* event_ = new VisibilityNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == CreateNotifyEvent::opcode) {
+ event->type_id_ = 62;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<CreateNotifyEvent*>(event);
+ };
+ auto* event_ = new CreateNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == DestroyNotifyEvent::opcode) {
+ event->type_id_ = 63;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<DestroyNotifyEvent*>(event);
+ };
+ auto* event_ = new DestroyNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == UnmapNotifyEvent::opcode) {
+ event->type_id_ = 64;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<UnmapNotifyEvent*>(event);
+ };
+ auto* event_ = new UnmapNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == MapNotifyEvent::opcode) {
+ event->type_id_ = 65;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<MapNotifyEvent*>(event);
+ };
+ auto* event_ = new MapNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == MapRequestEvent::opcode) {
+ event->type_id_ = 66;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<MapRequestEvent*>(event);
+ };
+ auto* event_ = new MapRequestEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == ReparentNotifyEvent::opcode) {
+ event->type_id_ = 67;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<ReparentNotifyEvent*>(event);
+ };
+ auto* event_ = new ReparentNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == ConfigureNotifyEvent::opcode) {
+ event->type_id_ = 68;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<ConfigureNotifyEvent*>(event);
+ };
+ auto* event_ = new ConfigureNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == ConfigureRequestEvent::opcode) {
+ event->type_id_ = 69;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<ConfigureRequestEvent*>(event);
+ };
+ auto* event_ = new ConfigureRequestEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GravityNotifyEvent::opcode) {
+ event->type_id_ = 70;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<GravityNotifyEvent*>(event);
+ };
+ auto* event_ = new GravityNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == ResizeRequestEvent::opcode) {
+ event->type_id_ = 71;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<ResizeRequestEvent*>(event);
+ };
+ auto* event_ = new ResizeRequestEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if ((evtype == CirculateEvent::Request || evtype == CirculateEvent::Notify)) {
+ event->type_id_ = 72;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<CirculateEvent*>(event);
+ };
+ auto* event_ = new CirculateEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(evtype);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == PropertyNotifyEvent::opcode) {
+ event->type_id_ = 73;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<PropertyNotifyEvent*>(event);
+ };
+ auto* event_ = new PropertyNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == SelectionClearEvent::opcode) {
+ event->type_id_ = 74;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<SelectionClearEvent*>(event);
+ };
+ auto* event_ = new SelectionClearEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == SelectionRequestEvent::opcode) {
+ event->type_id_ = 75;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<SelectionRequestEvent*>(event);
+ };
+ auto* event_ = new SelectionRequestEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == SelectionNotifyEvent::opcode) {
+ event->type_id_ = 76;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<SelectionNotifyEvent*>(event);
+ };
+ auto* event_ = new SelectionNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == ColormapNotifyEvent::opcode) {
+ event->type_id_ = 77;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<ColormapNotifyEvent*>(event);
+ };
+ auto* event_ = new ColormapNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == ClientMessageEvent::opcode) {
+ event->type_id_ = 78;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<ClientMessageEvent*>(event);
+ };
+ auto* event_ = new ClientMessageEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == MappingNotifyEvent::opcode) {
+ event->type_id_ = 79;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<MappingNotifyEvent*>(event);
+ };
+ auto* event_ = new MappingNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xv().present() &&
+ evtype - conn->xv().first_event() == Xv::VideoNotifyEvent::opcode) {
+ event->type_id_ = 81;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xv::VideoNotifyEvent*>(event);
+ };
+ auto* event_ = new Xv::VideoNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (conn->xv().present() &&
+ evtype - conn->xv().first_event() == Xv::PortNotifyEvent::opcode) {
+ event->type_id_ = 82;
+ event->deleter_ = [](void* event) {
+ delete reinterpret_cast<Xv::PortNotifyEvent*>(event);
+ };
+ auto* event_ = new Xv::PortNotifyEvent;
+ ReadEvent(event_, buffer);
+ event_->send_event = send_event;
+ event->event_ = event_;
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ NOTREACHED();
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/record.cc b/chromium/ui/gfx/x/generated_protos/record.cc
new file mode 100644
index 00000000000..3976979f671
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/record.cc
@@ -0,0 +1,1040 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "record.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Record::Record(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+std::string Record::BadContextError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Record::BadContextError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".invalid_record = " << static_cast<uint64_t>(invalid_record);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Record::BadContextError>(Record::BadContextError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& invalid_record = (*error_).invalid_record;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // invalid_record
+ Read(&invalid_record, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+Future<Record::QueryVersionReply> Record::QueryVersion(
+ const Record::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major_version = request.major_version;
+ auto& minor_version = request.minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major_version
+ buf.Write(&major_version);
+
+ // minor_version
+ buf.Write(&minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Record::QueryVersionReply>(
+ &buf, "Record::QueryVersion", false);
+}
+
+Future<Record::QueryVersionReply> Record::QueryVersion(
+ const uint16_t& major_version,
+ const uint16_t& minor_version) {
+ return Record::QueryVersion(
+ Record::QueryVersionRequest{major_version, minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Record::QueryVersionReply> detail::ReadReply<
+ Record::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Record::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Record::CreateContext(
+ const Record::CreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ auto& element_header = request.element_header;
+ uint32_t num_client_specs{};
+ uint32_t num_ranges{};
+ auto& client_specs = request.client_specs;
+ size_t client_specs_len = client_specs.size();
+ auto& ranges = request.ranges;
+ size_t ranges_len = ranges.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // element_header
+ buf.Write(&element_header);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // num_client_specs
+ num_client_specs = client_specs.size();
+ buf.Write(&num_client_specs);
+
+ // num_ranges
+ num_ranges = ranges.size();
+ buf.Write(&num_ranges);
+
+ // client_specs
+ DCHECK_EQ(static_cast<size_t>(num_client_specs), client_specs.size());
+ for (auto& client_specs_elem : client_specs) {
+ // client_specs_elem
+ buf.Write(&client_specs_elem);
+ }
+
+ // ranges
+ DCHECK_EQ(static_cast<size_t>(num_ranges), ranges.size());
+ for (auto& ranges_elem : ranges) {
+ // ranges_elem
+ {
+ auto& core_requests = ranges_elem.core_requests;
+ auto& core_replies = ranges_elem.core_replies;
+ auto& ext_requests = ranges_elem.ext_requests;
+ auto& ext_replies = ranges_elem.ext_replies;
+ auto& delivered_events = ranges_elem.delivered_events;
+ auto& device_events = ranges_elem.device_events;
+ auto& errors = ranges_elem.errors;
+ auto& client_started = ranges_elem.client_started;
+ auto& client_died = ranges_elem.client_died;
+
+ // core_requests
+ {
+ auto& first = core_requests.first;
+ auto& last = core_requests.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // core_replies
+ {
+ auto& first = core_replies.first;
+ auto& last = core_replies.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // ext_requests
+ {
+ auto& major = ext_requests.major;
+ auto& minor = ext_requests.minor;
+
+ // major
+ {
+ auto& first = major.first;
+ auto& last = major.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // minor
+ {
+ auto& first = minor.first;
+ auto& last = minor.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+ }
+
+ // ext_replies
+ {
+ auto& major = ext_replies.major;
+ auto& minor = ext_replies.minor;
+
+ // major
+ {
+ auto& first = major.first;
+ auto& last = major.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // minor
+ {
+ auto& first = minor.first;
+ auto& last = minor.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+ }
+
+ // delivered_events
+ {
+ auto& first = delivered_events.first;
+ auto& last = delivered_events.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // device_events
+ {
+ auto& first = device_events.first;
+ auto& last = device_events.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // errors
+ {
+ auto& first = errors.first;
+ auto& last = errors.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // client_started
+ buf.Write(&client_started);
+
+ // client_died
+ buf.Write(&client_died);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Record::CreateContext", false);
+}
+
+Future<void> Record::CreateContext(const Context& context,
+ const ElementHeader& element_header,
+ const std::vector<ClientSpec>& client_specs,
+ const std::vector<Range>& ranges) {
+ return Record::CreateContext(Record::CreateContextRequest{
+ context, element_header, client_specs, ranges});
+}
+
+Future<void> Record::RegisterClients(
+ const Record::RegisterClientsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ auto& element_header = request.element_header;
+ uint32_t num_client_specs{};
+ uint32_t num_ranges{};
+ auto& client_specs = request.client_specs;
+ size_t client_specs_len = client_specs.size();
+ auto& ranges = request.ranges;
+ size_t ranges_len = ranges.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // element_header
+ buf.Write(&element_header);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // num_client_specs
+ num_client_specs = client_specs.size();
+ buf.Write(&num_client_specs);
+
+ // num_ranges
+ num_ranges = ranges.size();
+ buf.Write(&num_ranges);
+
+ // client_specs
+ DCHECK_EQ(static_cast<size_t>(num_client_specs), client_specs.size());
+ for (auto& client_specs_elem : client_specs) {
+ // client_specs_elem
+ buf.Write(&client_specs_elem);
+ }
+
+ // ranges
+ DCHECK_EQ(static_cast<size_t>(num_ranges), ranges.size());
+ for (auto& ranges_elem : ranges) {
+ // ranges_elem
+ {
+ auto& core_requests = ranges_elem.core_requests;
+ auto& core_replies = ranges_elem.core_replies;
+ auto& ext_requests = ranges_elem.ext_requests;
+ auto& ext_replies = ranges_elem.ext_replies;
+ auto& delivered_events = ranges_elem.delivered_events;
+ auto& device_events = ranges_elem.device_events;
+ auto& errors = ranges_elem.errors;
+ auto& client_started = ranges_elem.client_started;
+ auto& client_died = ranges_elem.client_died;
+
+ // core_requests
+ {
+ auto& first = core_requests.first;
+ auto& last = core_requests.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // core_replies
+ {
+ auto& first = core_replies.first;
+ auto& last = core_replies.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // ext_requests
+ {
+ auto& major = ext_requests.major;
+ auto& minor = ext_requests.minor;
+
+ // major
+ {
+ auto& first = major.first;
+ auto& last = major.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // minor
+ {
+ auto& first = minor.first;
+ auto& last = minor.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+ }
+
+ // ext_replies
+ {
+ auto& major = ext_replies.major;
+ auto& minor = ext_replies.minor;
+
+ // major
+ {
+ auto& first = major.first;
+ auto& last = major.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // minor
+ {
+ auto& first = minor.first;
+ auto& last = minor.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+ }
+
+ // delivered_events
+ {
+ auto& first = delivered_events.first;
+ auto& last = delivered_events.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // device_events
+ {
+ auto& first = device_events.first;
+ auto& last = device_events.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // errors
+ {
+ auto& first = errors.first;
+ auto& last = errors.last;
+
+ // first
+ buf.Write(&first);
+
+ // last
+ buf.Write(&last);
+ }
+
+ // client_started
+ buf.Write(&client_started);
+
+ // client_died
+ buf.Write(&client_died);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Record::RegisterClients", false);
+}
+
+Future<void> Record::RegisterClients(
+ const Context& context,
+ const ElementHeader& element_header,
+ const std::vector<ClientSpec>& client_specs,
+ const std::vector<Range>& ranges) {
+ return Record::RegisterClients(Record::RegisterClientsRequest{
+ context, element_header, client_specs, ranges});
+}
+
+Future<void> Record::UnregisterClients(
+ const Record::UnregisterClientsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ uint32_t num_client_specs{};
+ auto& client_specs = request.client_specs;
+ size_t client_specs_len = client_specs.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // num_client_specs
+ num_client_specs = client_specs.size();
+ buf.Write(&num_client_specs);
+
+ // client_specs
+ DCHECK_EQ(static_cast<size_t>(num_client_specs), client_specs.size());
+ for (auto& client_specs_elem : client_specs) {
+ // client_specs_elem
+ buf.Write(&client_specs_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Record::UnregisterClients",
+ false);
+}
+
+Future<void> Record::UnregisterClients(
+ const Context& context,
+ const std::vector<ClientSpec>& client_specs) {
+ return Record::UnregisterClients(
+ Record::UnregisterClientsRequest{context, client_specs});
+}
+
+Future<Record::GetContextReply> Record::GetContext(
+ const Record::GetContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Record::GetContextReply>(
+ &buf, "Record::GetContext", false);
+}
+
+Future<Record::GetContextReply> Record::GetContext(const Context& context) {
+ return Record::GetContext(Record::GetContextRequest{context});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Record::GetContextReply> detail::ReadReply<
+ Record::GetContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Record::GetContextReply>();
+
+ auto& enabled = (*reply).enabled;
+ auto& sequence = (*reply).sequence;
+ auto& element_header = (*reply).element_header;
+ uint32_t num_intercepted_clients{};
+ auto& intercepted_clients = (*reply).intercepted_clients;
+ size_t intercepted_clients_len = intercepted_clients.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // enabled
+ Read(&enabled, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // element_header
+ Read(&element_header, &buf);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // num_intercepted_clients
+ Read(&num_intercepted_clients, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ // intercepted_clients
+ intercepted_clients.resize(num_intercepted_clients);
+ for (auto& intercepted_clients_elem : intercepted_clients) {
+ // intercepted_clients_elem
+ {
+ auto& client_resource = intercepted_clients_elem.client_resource;
+ uint32_t num_ranges{};
+ auto& ranges = intercepted_clients_elem.ranges;
+ size_t ranges_len = ranges.size();
+
+ // client_resource
+ Read(&client_resource, &buf);
+
+ // num_ranges
+ Read(&num_ranges, &buf);
+
+ // ranges
+ ranges.resize(num_ranges);
+ for (auto& ranges_elem : ranges) {
+ // ranges_elem
+ {
+ auto& core_requests = ranges_elem.core_requests;
+ auto& core_replies = ranges_elem.core_replies;
+ auto& ext_requests = ranges_elem.ext_requests;
+ auto& ext_replies = ranges_elem.ext_replies;
+ auto& delivered_events = ranges_elem.delivered_events;
+ auto& device_events = ranges_elem.device_events;
+ auto& errors = ranges_elem.errors;
+ auto& client_started = ranges_elem.client_started;
+ auto& client_died = ranges_elem.client_died;
+
+ // core_requests
+ {
+ auto& first = core_requests.first;
+ auto& last = core_requests.last;
+
+ // first
+ Read(&first, &buf);
+
+ // last
+ Read(&last, &buf);
+ }
+
+ // core_replies
+ {
+ auto& first = core_replies.first;
+ auto& last = core_replies.last;
+
+ // first
+ Read(&first, &buf);
+
+ // last
+ Read(&last, &buf);
+ }
+
+ // ext_requests
+ {
+ auto& major = ext_requests.major;
+ auto& minor = ext_requests.minor;
+
+ // major
+ {
+ auto& first = major.first;
+ auto& last = major.last;
+
+ // first
+ Read(&first, &buf);
+
+ // last
+ Read(&last, &buf);
+ }
+
+ // minor
+ {
+ auto& first = minor.first;
+ auto& last = minor.last;
+
+ // first
+ Read(&first, &buf);
+
+ // last
+ Read(&last, &buf);
+ }
+ }
+
+ // ext_replies
+ {
+ auto& major = ext_replies.major;
+ auto& minor = ext_replies.minor;
+
+ // major
+ {
+ auto& first = major.first;
+ auto& last = major.last;
+
+ // first
+ Read(&first, &buf);
+
+ // last
+ Read(&last, &buf);
+ }
+
+ // minor
+ {
+ auto& first = minor.first;
+ auto& last = minor.last;
+
+ // first
+ Read(&first, &buf);
+
+ // last
+ Read(&last, &buf);
+ }
+ }
+
+ // delivered_events
+ {
+ auto& first = delivered_events.first;
+ auto& last = delivered_events.last;
+
+ // first
+ Read(&first, &buf);
+
+ // last
+ Read(&last, &buf);
+ }
+
+ // device_events
+ {
+ auto& first = device_events.first;
+ auto& last = device_events.last;
+
+ // first
+ Read(&first, &buf);
+
+ // last
+ Read(&last, &buf);
+ }
+
+ // errors
+ {
+ auto& first = errors.first;
+ auto& last = errors.last;
+
+ // first
+ Read(&first, &buf);
+
+ // last
+ Read(&last, &buf);
+ }
+
+ // client_started
+ Read(&client_started, &buf);
+
+ // client_died
+ Read(&client_died, &buf);
+ }
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Record::EnableContextReply> Record::EnableContext(
+ const Record::EnableContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Record::EnableContextReply>(
+ &buf, "Record::EnableContext", false);
+}
+
+Future<Record::EnableContextReply> Record::EnableContext(
+ const Context& context) {
+ return Record::EnableContext(Record::EnableContextRequest{context});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Record::EnableContextReply> detail::ReadReply<
+ Record::EnableContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Record::EnableContextReply>();
+
+ auto& category = (*reply).category;
+ auto& sequence = (*reply).sequence;
+ auto& element_header = (*reply).element_header;
+ auto& client_swapped = (*reply).client_swapped;
+ auto& xid_base = (*reply).xid_base;
+ auto& server_time = (*reply).server_time;
+ auto& rec_sequence_num = (*reply).rec_sequence_num;
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // category
+ Read(&category, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // element_header
+ Read(&element_header, &buf);
+
+ // client_swapped
+ Read(&client_swapped, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // xid_base
+ Read(&xid_base, &buf);
+
+ // server_time
+ Read(&server_time, &buf);
+
+ // rec_sequence_num
+ Read(&rec_sequence_num, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // data
+ data.resize((length) * (4));
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Record::DisableContext(
+ const Record::DisableContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Record::DisableContext", false);
+}
+
+Future<void> Record::DisableContext(const Context& context) {
+ return Record::DisableContext(Record::DisableContextRequest{context});
+}
+
+Future<void> Record::FreeContext(const Record::FreeContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Record::FreeContext", false);
+}
+
+Future<void> Record::FreeContext(const Context& context) {
+ return Record::FreeContext(Record::FreeContextRequest{context});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/record.h b/chromium/ui/gfx/x/generated_protos/record.h
new file mode 100644
index 00000000000..068ac048662
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/record.h
@@ -0,0 +1,292 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_RECORD_H_
+#define UI_GFX_X_GENERATED_PROTOS_RECORD_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Record {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 13;
+
+ Record(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Context : uint32_t {};
+
+ enum class ElementHeader : uint8_t {};
+
+ enum class HType : int {
+ FromServerTime = 1 << 0,
+ FromClientTime = 1 << 1,
+ FromClientSequence = 1 << 2,
+ };
+
+ enum class ClientSpec : uint32_t {
+ CurrentClients = 1,
+ FutureClients = 2,
+ AllClients = 3,
+ };
+
+ struct Range8 {
+ uint8_t first{};
+ uint8_t last{};
+ };
+
+ struct Range16 {
+ uint16_t first{};
+ uint16_t last{};
+ };
+
+ struct ExtRange {
+ Range8 major{};
+ Range16 minor{};
+ };
+
+ struct Range {
+ Range8 core_requests{};
+ Range8 core_replies{};
+ ExtRange ext_requests{};
+ ExtRange ext_replies{};
+ Range8 delivered_events{};
+ Range8 device_events{};
+ Range8 errors{};
+ uint8_t client_started{};
+ uint8_t client_died{};
+ };
+
+ struct ClientInfo {
+ ClientSpec client_resource{};
+ std::vector<Range> ranges{};
+ };
+
+ struct BadContextError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t invalid_record{};
+
+ std::string ToString() const override;
+ };
+
+ struct QueryVersionRequest {
+ uint16_t major_version{};
+ uint16_t minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint16_t major_version{};
+ uint16_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(const uint16_t& major_version = {},
+ const uint16_t& minor_version = {});
+
+ struct CreateContextRequest {
+ Context context{};
+ ElementHeader element_header{};
+ std::vector<ClientSpec> client_specs{};
+ std::vector<Range> ranges{};
+ };
+
+ using CreateContextResponse = Response<void>;
+
+ Future<void> CreateContext(const CreateContextRequest& request);
+
+ Future<void> CreateContext(const Context& context = {},
+ const ElementHeader& element_header = {},
+ const std::vector<ClientSpec>& client_specs = {},
+ const std::vector<Range>& ranges = {});
+
+ struct RegisterClientsRequest {
+ Context context{};
+ ElementHeader element_header{};
+ std::vector<ClientSpec> client_specs{};
+ std::vector<Range> ranges{};
+ };
+
+ using RegisterClientsResponse = Response<void>;
+
+ Future<void> RegisterClients(const RegisterClientsRequest& request);
+
+ Future<void> RegisterClients(const Context& context = {},
+ const ElementHeader& element_header = {},
+ const std::vector<ClientSpec>& client_specs = {},
+ const std::vector<Range>& ranges = {});
+
+ struct UnregisterClientsRequest {
+ Context context{};
+ std::vector<ClientSpec> client_specs{};
+ };
+
+ using UnregisterClientsResponse = Response<void>;
+
+ Future<void> UnregisterClients(const UnregisterClientsRequest& request);
+
+ Future<void> UnregisterClients(
+ const Context& context = {},
+ const std::vector<ClientSpec>& client_specs = {});
+
+ struct GetContextRequest {
+ Context context{};
+ };
+
+ struct GetContextReply {
+ uint8_t enabled{};
+ uint16_t sequence{};
+ ElementHeader element_header{};
+ std::vector<ClientInfo> intercepted_clients{};
+ };
+
+ using GetContextResponse = Response<GetContextReply>;
+
+ Future<GetContextReply> GetContext(const GetContextRequest& request);
+
+ Future<GetContextReply> GetContext(const Context& context = {});
+
+ struct EnableContextRequest {
+ Context context{};
+ };
+
+ struct EnableContextReply {
+ uint8_t category{};
+ uint16_t sequence{};
+ ElementHeader element_header{};
+ uint8_t client_swapped{};
+ uint32_t xid_base{};
+ uint32_t server_time{};
+ uint32_t rec_sequence_num{};
+ std::vector<uint8_t> data{};
+ };
+
+ using EnableContextResponse = Response<EnableContextReply>;
+
+ Future<EnableContextReply> EnableContext(const EnableContextRequest& request);
+
+ Future<EnableContextReply> EnableContext(const Context& context = {});
+
+ struct DisableContextRequest {
+ Context context{};
+ };
+
+ using DisableContextResponse = Response<void>;
+
+ Future<void> DisableContext(const DisableContextRequest& request);
+
+ Future<void> DisableContext(const Context& context = {});
+
+ struct FreeContextRequest {
+ Context context{};
+ };
+
+ using FreeContextResponse = Response<void>;
+
+ Future<void> FreeContext(const FreeContextRequest& request);
+
+ Future<void> FreeContext(const Context& context = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Record::HType operator|(x11::Record::HType l,
+ x11::Record::HType r) {
+ using T = std::underlying_type_t<x11::Record::HType>;
+ return static_cast<x11::Record::HType>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Record::HType operator&(x11::Record::HType l,
+ x11::Record::HType r) {
+ using T = std::underlying_type_t<x11::Record::HType>;
+ return static_cast<x11::Record::HType>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Record::ClientSpec operator|(x11::Record::ClientSpec l,
+ x11::Record::ClientSpec r) {
+ using T = std::underlying_type_t<x11::Record::ClientSpec>;
+ return static_cast<x11::Record::ClientSpec>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Record::ClientSpec operator&(x11::Record::ClientSpec l,
+ x11::Record::ClientSpec r) {
+ using T = std::underlying_type_t<x11::Record::ClientSpec>;
+ return static_cast<x11::Record::ClientSpec>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_RECORD_H_
diff --git a/chromium/ui/gfx/x/generated_protos/render.cc b/chromium/ui/gfx/x/generated_protos/render.cc
new file mode 100644
index 00000000000..7985f551a47
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/render.cc
@@ -0,0 +1,2960 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "render.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Render::Render(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+std::string Render::PictFormatError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Render::PictFormatError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Render::PictFormatError>(Render::PictFormatError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Render::PictureError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Render::PictureError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Render::PictureError>(Render::PictureError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Render::PictOpError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Render::PictOpError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Render::PictOpError>(Render::PictOpError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Render::GlyphSetError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Render::GlyphSetError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Render::GlyphSetError>(Render::GlyphSetError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Render::GlyphError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Render::GlyphError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Render::GlyphError>(Render::GlyphError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+Future<Render::QueryVersionReply> Render::QueryVersion(
+ const Render::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client_major_version = request.client_major_version;
+ auto& client_minor_version = request.client_minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client_major_version
+ buf.Write(&client_major_version);
+
+ // client_minor_version
+ buf.Write(&client_minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Render::QueryVersionReply>(
+ &buf, "Render::QueryVersion", false);
+}
+
+Future<Render::QueryVersionReply> Render::QueryVersion(
+ const uint32_t& client_major_version,
+ const uint32_t& client_minor_version) {
+ return Render::QueryVersion(
+ Render::QueryVersionRequest{client_major_version, client_minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Render::QueryVersionReply> detail::ReadReply<
+ Render::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Render::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Render::QueryPictFormatsReply> Render::QueryPictFormats(
+ const Render::QueryPictFormatsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Render::QueryPictFormatsReply>(
+ &buf, "Render::QueryPictFormats", false);
+}
+
+Future<Render::QueryPictFormatsReply> Render::QueryPictFormats() {
+ return Render::QueryPictFormats(Render::QueryPictFormatsRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Render::QueryPictFormatsReply> detail::ReadReply<
+ Render::QueryPictFormatsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Render::QueryPictFormatsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num_formats{};
+ uint32_t num_screens{};
+ auto& num_depths = (*reply).num_depths;
+ auto& num_visuals = (*reply).num_visuals;
+ uint32_t num_subpixel{};
+ auto& formats = (*reply).formats;
+ size_t formats_len = formats.size();
+ auto& screens = (*reply).screens;
+ size_t screens_len = screens.size();
+ auto& subpixels = (*reply).subpixels;
+ size_t subpixels_len = subpixels.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_formats
+ Read(&num_formats, &buf);
+
+ // num_screens
+ Read(&num_screens, &buf);
+
+ // num_depths
+ Read(&num_depths, &buf);
+
+ // num_visuals
+ Read(&num_visuals, &buf);
+
+ // num_subpixel
+ Read(&num_subpixel, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // formats
+ formats.resize(num_formats);
+ for (auto& formats_elem : formats) {
+ // formats_elem
+ {
+ auto& id = formats_elem.id;
+ auto& type = formats_elem.type;
+ auto& depth = formats_elem.depth;
+ auto& direct = formats_elem.direct;
+ auto& colormap = formats_elem.colormap;
+
+ // id
+ Read(&id, &buf);
+
+ // type
+ uint8_t tmp0;
+ Read(&tmp0, &buf);
+ type = static_cast<Render::PictType>(tmp0);
+
+ // depth
+ Read(&depth, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // direct
+ {
+ auto& red_shift = direct.red_shift;
+ auto& red_mask = direct.red_mask;
+ auto& green_shift = direct.green_shift;
+ auto& green_mask = direct.green_mask;
+ auto& blue_shift = direct.blue_shift;
+ auto& blue_mask = direct.blue_mask;
+ auto& alpha_shift = direct.alpha_shift;
+ auto& alpha_mask = direct.alpha_mask;
+
+ // red_shift
+ Read(&red_shift, &buf);
+
+ // red_mask
+ Read(&red_mask, &buf);
+
+ // green_shift
+ Read(&green_shift, &buf);
+
+ // green_mask
+ Read(&green_mask, &buf);
+
+ // blue_shift
+ Read(&blue_shift, &buf);
+
+ // blue_mask
+ Read(&blue_mask, &buf);
+
+ // alpha_shift
+ Read(&alpha_shift, &buf);
+
+ // alpha_mask
+ Read(&alpha_mask, &buf);
+ }
+
+ // colormap
+ Read(&colormap, &buf);
+ }
+ }
+
+ // screens
+ screens.resize(num_screens);
+ for (auto& screens_elem : screens) {
+ // screens_elem
+ {
+ uint32_t num_depths{};
+ auto& fallback = screens_elem.fallback;
+ auto& depths = screens_elem.depths;
+ size_t depths_len = depths.size();
+
+ // num_depths
+ Read(&num_depths, &buf);
+
+ // fallback
+ Read(&fallback, &buf);
+
+ // depths
+ depths.resize(num_depths);
+ for (auto& depths_elem : depths) {
+ // depths_elem
+ {
+ auto& depth = depths_elem.depth;
+ uint16_t num_visuals{};
+ auto& visuals = depths_elem.visuals;
+ size_t visuals_len = visuals.size();
+
+ // depth
+ Read(&depth, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // num_visuals
+ Read(&num_visuals, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // visuals
+ visuals.resize(num_visuals);
+ for (auto& visuals_elem : visuals) {
+ // visuals_elem
+ {
+ auto& visual = visuals_elem.visual;
+ auto& format = visuals_elem.format;
+
+ // visual
+ Read(&visual, &buf);
+
+ // format
+ Read(&format, &buf);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // subpixels
+ subpixels.resize(num_subpixel);
+ for (auto& subpixels_elem : subpixels) {
+ // subpixels_elem
+ uint32_t tmp1;
+ Read(&tmp1, &buf);
+ subpixels_elem = static_cast<Render::SubPixel>(tmp1);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Render::QueryPictIndexValuesReply> Render::QueryPictIndexValues(
+ const Render::QueryPictIndexValuesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& format = request.format;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // format
+ buf.Write(&format);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Render::QueryPictIndexValuesReply>(
+ &buf, "Render::QueryPictIndexValues", false);
+}
+
+Future<Render::QueryPictIndexValuesReply> Render::QueryPictIndexValues(
+ const PictFormat& format) {
+ return Render::QueryPictIndexValues(
+ Render::QueryPictIndexValuesRequest{format});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Render::QueryPictIndexValuesReply> detail::ReadReply<
+ Render::QueryPictIndexValuesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Render::QueryPictIndexValuesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num_values{};
+ auto& values = (*reply).values;
+ size_t values_len = values.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_values
+ Read(&num_values, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // values
+ values.resize(num_values);
+ for (auto& values_elem : values) {
+ // values_elem
+ {
+ auto& pixel = values_elem.pixel;
+ auto& red = values_elem.red;
+ auto& green = values_elem.green;
+ auto& blue = values_elem.blue;
+ auto& alpha = values_elem.alpha;
+
+ // pixel
+ Read(&pixel, &buf);
+
+ // red
+ Read(&red, &buf);
+
+ // green
+ Read(&green, &buf);
+
+ // blue
+ Read(&blue, &buf);
+
+ // alpha
+ Read(&alpha, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Render::CreatePicture(
+ const Render::CreatePictureRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& pid = request.pid;
+ auto& drawable = request.drawable;
+ auto& format = request.format;
+ CreatePictureAttribute value_mask{};
+ auto& value_list = request;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // pid
+ buf.Write(&pid);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // format
+ buf.Write(&format);
+
+ // value_mask
+ SwitchVar(CreatePictureAttribute::Repeat, value_list.repeat.has_value(), true,
+ &value_mask);
+ SwitchVar(CreatePictureAttribute::AlphaMap, value_list.alphamap.has_value(),
+ true, &value_mask);
+ SwitchVar(CreatePictureAttribute::AlphaXOrigin,
+ value_list.alphaxorigin.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::AlphaYOrigin,
+ value_list.alphayorigin.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::ClipXOrigin,
+ value_list.clipxorigin.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::ClipYOrigin,
+ value_list.clipyorigin.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::ClipMask, value_list.clipmask.has_value(),
+ true, &value_mask);
+ SwitchVar(CreatePictureAttribute::GraphicsExposure,
+ value_list.graphicsexposure.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::SubwindowMode,
+ value_list.subwindowmode.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::PolyEdge, value_list.polyedge.has_value(),
+ true, &value_mask);
+ SwitchVar(CreatePictureAttribute::PolyMode, value_list.polymode.has_value(),
+ true, &value_mask);
+ SwitchVar(CreatePictureAttribute::Dither, value_list.dither.has_value(), true,
+ &value_mask);
+ SwitchVar(CreatePictureAttribute::ComponentAlpha,
+ value_list.componentalpha.has_value(), true, &value_mask);
+ uint32_t tmp2;
+ tmp2 = static_cast<uint32_t>(value_mask);
+ buf.Write(&tmp2);
+
+ // value_list
+ auto value_list_expr = value_mask;
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::Repeat)) {
+ auto& repeat = *value_list.repeat;
+
+ // repeat
+ uint32_t tmp3;
+ tmp3 = static_cast<uint32_t>(repeat);
+ buf.Write(&tmp3);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::AlphaMap)) {
+ auto& alphamap = *value_list.alphamap;
+
+ // alphamap
+ buf.Write(&alphamap);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::AlphaXOrigin)) {
+ auto& alphaxorigin = *value_list.alphaxorigin;
+
+ // alphaxorigin
+ buf.Write(&alphaxorigin);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::AlphaYOrigin)) {
+ auto& alphayorigin = *value_list.alphayorigin;
+
+ // alphayorigin
+ buf.Write(&alphayorigin);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::ClipXOrigin)) {
+ auto& clipxorigin = *value_list.clipxorigin;
+
+ // clipxorigin
+ buf.Write(&clipxorigin);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::ClipYOrigin)) {
+ auto& clipyorigin = *value_list.clipyorigin;
+
+ // clipyorigin
+ buf.Write(&clipyorigin);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::ClipMask)) {
+ auto& clipmask = *value_list.clipmask;
+
+ // clipmask
+ buf.Write(&clipmask);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::GraphicsExposure)) {
+ auto& graphicsexposure = *value_list.graphicsexposure;
+
+ // graphicsexposure
+ buf.Write(&graphicsexposure);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::SubwindowMode)) {
+ auto& subwindowmode = *value_list.subwindowmode;
+
+ // subwindowmode
+ uint32_t tmp4;
+ tmp4 = static_cast<uint32_t>(subwindowmode);
+ buf.Write(&tmp4);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::PolyEdge)) {
+ auto& polyedge = *value_list.polyedge;
+
+ // polyedge
+ uint32_t tmp5;
+ tmp5 = static_cast<uint32_t>(polyedge);
+ buf.Write(&tmp5);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::PolyMode)) {
+ auto& polymode = *value_list.polymode;
+
+ // polymode
+ uint32_t tmp6;
+ tmp6 = static_cast<uint32_t>(polymode);
+ buf.Write(&tmp6);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::Dither)) {
+ auto& dither = *value_list.dither;
+
+ // dither
+ buf.Write(&dither);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::ComponentAlpha)) {
+ auto& componentalpha = *value_list.componentalpha;
+
+ // componentalpha
+ buf.Write(&componentalpha);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::CreatePicture", false);
+}
+
+Future<void> Render::CreatePicture(
+ const Picture& pid,
+ const Drawable& drawable,
+ const PictFormat& format,
+ const base::Optional<Repeat>& repeat,
+ const base::Optional<Picture>& alphamap,
+ const base::Optional<int32_t>& alphaxorigin,
+ const base::Optional<int32_t>& alphayorigin,
+ const base::Optional<int32_t>& clipxorigin,
+ const base::Optional<int32_t>& clipyorigin,
+ const base::Optional<Pixmap>& clipmask,
+ const base::Optional<uint32_t>& graphicsexposure,
+ const base::Optional<SubwindowMode>& subwindowmode,
+ const base::Optional<PolyEdge>& polyedge,
+ const base::Optional<PolyMode>& polymode,
+ const base::Optional<Atom>& dither,
+ const base::Optional<uint32_t>& componentalpha) {
+ return Render::CreatePicture(Render::CreatePictureRequest{
+ pid, drawable, format, repeat, alphamap, alphaxorigin, alphayorigin,
+ clipxorigin, clipyorigin, clipmask, graphicsexposure, subwindowmode,
+ polyedge, polymode, dither, componentalpha});
+}
+
+Future<void> Render::ChangePicture(
+ const Render::ChangePictureRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& picture = request.picture;
+ CreatePictureAttribute value_mask{};
+ auto& value_list = request;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // picture
+ buf.Write(&picture);
+
+ // value_mask
+ SwitchVar(CreatePictureAttribute::Repeat, value_list.repeat.has_value(), true,
+ &value_mask);
+ SwitchVar(CreatePictureAttribute::AlphaMap, value_list.alphamap.has_value(),
+ true, &value_mask);
+ SwitchVar(CreatePictureAttribute::AlphaXOrigin,
+ value_list.alphaxorigin.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::AlphaYOrigin,
+ value_list.alphayorigin.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::ClipXOrigin,
+ value_list.clipxorigin.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::ClipYOrigin,
+ value_list.clipyorigin.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::ClipMask, value_list.clipmask.has_value(),
+ true, &value_mask);
+ SwitchVar(CreatePictureAttribute::GraphicsExposure,
+ value_list.graphicsexposure.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::SubwindowMode,
+ value_list.subwindowmode.has_value(), true, &value_mask);
+ SwitchVar(CreatePictureAttribute::PolyEdge, value_list.polyedge.has_value(),
+ true, &value_mask);
+ SwitchVar(CreatePictureAttribute::PolyMode, value_list.polymode.has_value(),
+ true, &value_mask);
+ SwitchVar(CreatePictureAttribute::Dither, value_list.dither.has_value(), true,
+ &value_mask);
+ SwitchVar(CreatePictureAttribute::ComponentAlpha,
+ value_list.componentalpha.has_value(), true, &value_mask);
+ uint32_t tmp7;
+ tmp7 = static_cast<uint32_t>(value_mask);
+ buf.Write(&tmp7);
+
+ // value_list
+ auto value_list_expr = value_mask;
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::Repeat)) {
+ auto& repeat = *value_list.repeat;
+
+ // repeat
+ uint32_t tmp8;
+ tmp8 = static_cast<uint32_t>(repeat);
+ buf.Write(&tmp8);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::AlphaMap)) {
+ auto& alphamap = *value_list.alphamap;
+
+ // alphamap
+ buf.Write(&alphamap);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::AlphaXOrigin)) {
+ auto& alphaxorigin = *value_list.alphaxorigin;
+
+ // alphaxorigin
+ buf.Write(&alphaxorigin);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::AlphaYOrigin)) {
+ auto& alphayorigin = *value_list.alphayorigin;
+
+ // alphayorigin
+ buf.Write(&alphayorigin);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::ClipXOrigin)) {
+ auto& clipxorigin = *value_list.clipxorigin;
+
+ // clipxorigin
+ buf.Write(&clipxorigin);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::ClipYOrigin)) {
+ auto& clipyorigin = *value_list.clipyorigin;
+
+ // clipyorigin
+ buf.Write(&clipyorigin);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::ClipMask)) {
+ auto& clipmask = *value_list.clipmask;
+
+ // clipmask
+ buf.Write(&clipmask);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::GraphicsExposure)) {
+ auto& graphicsexposure = *value_list.graphicsexposure;
+
+ // graphicsexposure
+ buf.Write(&graphicsexposure);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::SubwindowMode)) {
+ auto& subwindowmode = *value_list.subwindowmode;
+
+ // subwindowmode
+ uint32_t tmp9;
+ tmp9 = static_cast<uint32_t>(subwindowmode);
+ buf.Write(&tmp9);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::PolyEdge)) {
+ auto& polyedge = *value_list.polyedge;
+
+ // polyedge
+ uint32_t tmp10;
+ tmp10 = static_cast<uint32_t>(polyedge);
+ buf.Write(&tmp10);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::PolyMode)) {
+ auto& polymode = *value_list.polymode;
+
+ // polymode
+ uint32_t tmp11;
+ tmp11 = static_cast<uint32_t>(polymode);
+ buf.Write(&tmp11);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::Dither)) {
+ auto& dither = *value_list.dither;
+
+ // dither
+ buf.Write(&dither);
+ }
+ if (CaseAnd(value_list_expr, CreatePictureAttribute::ComponentAlpha)) {
+ auto& componentalpha = *value_list.componentalpha;
+
+ // componentalpha
+ buf.Write(&componentalpha);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::ChangePicture", false);
+}
+
+Future<void> Render::ChangePicture(
+ const Picture& picture,
+ const base::Optional<Repeat>& repeat,
+ const base::Optional<Picture>& alphamap,
+ const base::Optional<int32_t>& alphaxorigin,
+ const base::Optional<int32_t>& alphayorigin,
+ const base::Optional<int32_t>& clipxorigin,
+ const base::Optional<int32_t>& clipyorigin,
+ const base::Optional<Pixmap>& clipmask,
+ const base::Optional<uint32_t>& graphicsexposure,
+ const base::Optional<SubwindowMode>& subwindowmode,
+ const base::Optional<PolyEdge>& polyedge,
+ const base::Optional<PolyMode>& polymode,
+ const base::Optional<Atom>& dither,
+ const base::Optional<uint32_t>& componentalpha) {
+ return Render::ChangePicture(Render::ChangePictureRequest{
+ picture, repeat, alphamap, alphaxorigin, alphayorigin, clipxorigin,
+ clipyorigin, clipmask, graphicsexposure, subwindowmode, polyedge,
+ polymode, dither, componentalpha});
+}
+
+Future<void> Render::SetPictureClipRectangles(
+ const Render::SetPictureClipRectanglesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& picture = request.picture;
+ auto& clip_x_origin = request.clip_x_origin;
+ auto& clip_y_origin = request.clip_y_origin;
+ auto& rectangles = request.rectangles;
+ size_t rectangles_len = rectangles.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // picture
+ buf.Write(&picture);
+
+ // clip_x_origin
+ buf.Write(&clip_x_origin);
+
+ // clip_y_origin
+ buf.Write(&clip_y_origin);
+
+ // rectangles
+ DCHECK_EQ(static_cast<size_t>(rectangles_len), rectangles.size());
+ for (auto& rectangles_elem : rectangles) {
+ // rectangles_elem
+ {
+ auto& x = rectangles_elem.x;
+ auto& y = rectangles_elem.y;
+ auto& width = rectangles_elem.width;
+ auto& height = rectangles_elem.height;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(
+ &buf, "Render::SetPictureClipRectangles", false);
+}
+
+Future<void> Render::SetPictureClipRectangles(
+ const Picture& picture,
+ const int16_t& clip_x_origin,
+ const int16_t& clip_y_origin,
+ const std::vector<Rectangle>& rectangles) {
+ return Render::SetPictureClipRectangles(
+ Render::SetPictureClipRectanglesRequest{picture, clip_x_origin,
+ clip_y_origin, rectangles});
+}
+
+Future<void> Render::FreePicture(const Render::FreePictureRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& picture = request.picture;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // picture
+ buf.Write(&picture);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::FreePicture", false);
+}
+
+Future<void> Render::FreePicture(const Picture& picture) {
+ return Render::FreePicture(Render::FreePictureRequest{picture});
+}
+
+Future<void> Render::Composite(const Render::CompositeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& op = request.op;
+ auto& src = request.src;
+ auto& mask = request.mask;
+ auto& dst = request.dst;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& mask_x = request.mask_x;
+ auto& mask_y = request.mask_y;
+ auto& dst_x = request.dst_x;
+ auto& dst_y = request.dst_y;
+ auto& width = request.width;
+ auto& height = request.height;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // op
+ uint8_t tmp12;
+ tmp12 = static_cast<uint8_t>(op);
+ buf.Write(&tmp12);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // src
+ buf.Write(&src);
+
+ // mask
+ buf.Write(&mask);
+
+ // dst
+ buf.Write(&dst);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // mask_x
+ buf.Write(&mask_x);
+
+ // mask_y
+ buf.Write(&mask_y);
+
+ // dst_x
+ buf.Write(&dst_x);
+
+ // dst_y
+ buf.Write(&dst_y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::Composite", false);
+}
+
+Future<void> Render::Composite(const PictOp& op,
+ const Picture& src,
+ const Picture& mask,
+ const Picture& dst,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const int16_t& mask_x,
+ const int16_t& mask_y,
+ const int16_t& dst_x,
+ const int16_t& dst_y,
+ const uint16_t& width,
+ const uint16_t& height) {
+ return Render::Composite(
+ Render::CompositeRequest{op, src, mask, dst, src_x, src_y, mask_x, mask_y,
+ dst_x, dst_y, width, height});
+}
+
+Future<void> Render::Trapezoids(const Render::TrapezoidsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& op = request.op;
+ auto& src = request.src;
+ auto& dst = request.dst;
+ auto& mask_format = request.mask_format;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& traps = request.traps;
+ size_t traps_len = traps.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // op
+ uint8_t tmp13;
+ tmp13 = static_cast<uint8_t>(op);
+ buf.Write(&tmp13);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // src
+ buf.Write(&src);
+
+ // dst
+ buf.Write(&dst);
+
+ // mask_format
+ buf.Write(&mask_format);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // traps
+ DCHECK_EQ(static_cast<size_t>(traps_len), traps.size());
+ for (auto& traps_elem : traps) {
+ // traps_elem
+ {
+ auto& top = traps_elem.top;
+ auto& bottom = traps_elem.bottom;
+ auto& left = traps_elem.left;
+ auto& right = traps_elem.right;
+
+ // top
+ buf.Write(&top);
+
+ // bottom
+ buf.Write(&bottom);
+
+ // left
+ {
+ auto& p1 = left.p1;
+ auto& p2 = left.p2;
+
+ // p1
+ {
+ auto& x = p1.x;
+ auto& y = p1.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+
+ // p2
+ {
+ auto& x = p2.x;
+ auto& y = p2.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+ }
+
+ // right
+ {
+ auto& p1 = right.p1;
+ auto& p2 = right.p2;
+
+ // p1
+ {
+ auto& x = p1.x;
+ auto& y = p1.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+
+ // p2
+ {
+ auto& x = p2.x;
+ auto& y = p2.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+ }
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::Trapezoids", false);
+}
+
+Future<void> Render::Trapezoids(const PictOp& op,
+ const Picture& src,
+ const Picture& dst,
+ const PictFormat& mask_format,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const std::vector<Trapezoid>& traps) {
+ return Render::Trapezoids(Render::TrapezoidsRequest{op, src, dst, mask_format,
+ src_x, src_y, traps});
+}
+
+Future<void> Render::Triangles(const Render::TrianglesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& op = request.op;
+ auto& src = request.src;
+ auto& dst = request.dst;
+ auto& mask_format = request.mask_format;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& triangles = request.triangles;
+ size_t triangles_len = triangles.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // op
+ uint8_t tmp14;
+ tmp14 = static_cast<uint8_t>(op);
+ buf.Write(&tmp14);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // src
+ buf.Write(&src);
+
+ // dst
+ buf.Write(&dst);
+
+ // mask_format
+ buf.Write(&mask_format);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // triangles
+ DCHECK_EQ(static_cast<size_t>(triangles_len), triangles.size());
+ for (auto& triangles_elem : triangles) {
+ // triangles_elem
+ {
+ auto& p1 = triangles_elem.p1;
+ auto& p2 = triangles_elem.p2;
+ auto& p3 = triangles_elem.p3;
+
+ // p1
+ {
+ auto& x = p1.x;
+ auto& y = p1.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+
+ // p2
+ {
+ auto& x = p2.x;
+ auto& y = p2.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+
+ // p3
+ {
+ auto& x = p3.x;
+ auto& y = p3.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::Triangles", false);
+}
+
+Future<void> Render::Triangles(const PictOp& op,
+ const Picture& src,
+ const Picture& dst,
+ const PictFormat& mask_format,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const std::vector<Triangle>& triangles) {
+ return Render::Triangles(Render::TrianglesRequest{op, src, dst, mask_format,
+ src_x, src_y, triangles});
+}
+
+Future<void> Render::TriStrip(const Render::TriStripRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& op = request.op;
+ auto& src = request.src;
+ auto& dst = request.dst;
+ auto& mask_format = request.mask_format;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& points = request.points;
+ size_t points_len = points.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // op
+ uint8_t tmp15;
+ tmp15 = static_cast<uint8_t>(op);
+ buf.Write(&tmp15);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // src
+ buf.Write(&src);
+
+ // dst
+ buf.Write(&dst);
+
+ // mask_format
+ buf.Write(&mask_format);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // points
+ DCHECK_EQ(static_cast<size_t>(points_len), points.size());
+ for (auto& points_elem : points) {
+ // points_elem
+ {
+ auto& x = points_elem.x;
+ auto& y = points_elem.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::TriStrip", false);
+}
+
+Future<void> Render::TriStrip(const PictOp& op,
+ const Picture& src,
+ const Picture& dst,
+ const PictFormat& mask_format,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const std::vector<PointFix>& points) {
+ return Render::TriStrip(
+ Render::TriStripRequest{op, src, dst, mask_format, src_x, src_y, points});
+}
+
+Future<void> Render::TriFan(const Render::TriFanRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& op = request.op;
+ auto& src = request.src;
+ auto& dst = request.dst;
+ auto& mask_format = request.mask_format;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& points = request.points;
+ size_t points_len = points.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // op
+ uint8_t tmp16;
+ tmp16 = static_cast<uint8_t>(op);
+ buf.Write(&tmp16);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // src
+ buf.Write(&src);
+
+ // dst
+ buf.Write(&dst);
+
+ // mask_format
+ buf.Write(&mask_format);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // points
+ DCHECK_EQ(static_cast<size_t>(points_len), points.size());
+ for (auto& points_elem : points) {
+ // points_elem
+ {
+ auto& x = points_elem.x;
+ auto& y = points_elem.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::TriFan", false);
+}
+
+Future<void> Render::TriFan(const PictOp& op,
+ const Picture& src,
+ const Picture& dst,
+ const PictFormat& mask_format,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const std::vector<PointFix>& points) {
+ return Render::TriFan(
+ Render::TriFanRequest{op, src, dst, mask_format, src_x, src_y, points});
+}
+
+Future<void> Render::CreateGlyphSet(
+ const Render::CreateGlyphSetRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& gsid = request.gsid;
+ auto& format = request.format;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 17;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // gsid
+ buf.Write(&gsid);
+
+ // format
+ buf.Write(&format);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::CreateGlyphSet", false);
+}
+
+Future<void> Render::CreateGlyphSet(const GlyphSet& gsid,
+ const PictFormat& format) {
+ return Render::CreateGlyphSet(Render::CreateGlyphSetRequest{gsid, format});
+}
+
+Future<void> Render::ReferenceGlyphSet(
+ const Render::ReferenceGlyphSetRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& gsid = request.gsid;
+ auto& existing = request.existing;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 18;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // gsid
+ buf.Write(&gsid);
+
+ // existing
+ buf.Write(&existing);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::ReferenceGlyphSet",
+ false);
+}
+
+Future<void> Render::ReferenceGlyphSet(const GlyphSet& gsid,
+ const GlyphSet& existing) {
+ return Render::ReferenceGlyphSet(
+ Render::ReferenceGlyphSetRequest{gsid, existing});
+}
+
+Future<void> Render::FreeGlyphSet(const Render::FreeGlyphSetRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& glyphset = request.glyphset;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 19;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // glyphset
+ buf.Write(&glyphset);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::FreeGlyphSet", false);
+}
+
+Future<void> Render::FreeGlyphSet(const GlyphSet& glyphset) {
+ return Render::FreeGlyphSet(Render::FreeGlyphSetRequest{glyphset});
+}
+
+Future<void> Render::AddGlyphs(const Render::AddGlyphsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& glyphset = request.glyphset;
+ uint32_t glyphs_len{};
+ auto& glyphids = request.glyphids;
+ size_t glyphids_len = glyphids.size();
+ auto& glyphs = request.glyphs;
+ auto& data = request.data;
+ size_t data_len = data.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 20;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // glyphset
+ buf.Write(&glyphset);
+
+ // glyphs_len
+ glyphs_len = glyphs.size();
+ buf.Write(&glyphs_len);
+
+ // glyphids
+ DCHECK_EQ(static_cast<size_t>(glyphs_len), glyphids.size());
+ for (auto& glyphids_elem : glyphids) {
+ // glyphids_elem
+ buf.Write(&glyphids_elem);
+ }
+
+ // glyphs
+ DCHECK_EQ(static_cast<size_t>(glyphs_len), glyphs.size());
+ for (auto& glyphs_elem : glyphs) {
+ // glyphs_elem
+ {
+ auto& width = glyphs_elem.width;
+ auto& height = glyphs_elem.height;
+ auto& x = glyphs_elem.x;
+ auto& y = glyphs_elem.y;
+ auto& x_off = glyphs_elem.x_off;
+ auto& y_off = glyphs_elem.y_off;
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // x_off
+ buf.Write(&x_off);
+
+ // y_off
+ buf.Write(&y_off);
+ }
+ }
+
+ // data
+ DCHECK_EQ(static_cast<size_t>(data_len), data.size());
+ for (auto& data_elem : data) {
+ // data_elem
+ buf.Write(&data_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::AddGlyphs", false);
+}
+
+Future<void> Render::AddGlyphs(const GlyphSet& glyphset,
+ const std::vector<uint32_t>& glyphids,
+ const std::vector<GlyphInfo>& glyphs,
+ const std::vector<uint8_t>& data) {
+ return Render::AddGlyphs(
+ Render::AddGlyphsRequest{glyphset, glyphids, glyphs, data});
+}
+
+Future<void> Render::FreeGlyphs(const Render::FreeGlyphsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& glyphset = request.glyphset;
+ auto& glyphs = request.glyphs;
+ size_t glyphs_len = glyphs.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 22;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // glyphset
+ buf.Write(&glyphset);
+
+ // glyphs
+ DCHECK_EQ(static_cast<size_t>(glyphs_len), glyphs.size());
+ for (auto& glyphs_elem : glyphs) {
+ // glyphs_elem
+ buf.Write(&glyphs_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::FreeGlyphs", false);
+}
+
+Future<void> Render::FreeGlyphs(const GlyphSet& glyphset,
+ const std::vector<Glyph>& glyphs) {
+ return Render::FreeGlyphs(Render::FreeGlyphsRequest{glyphset, glyphs});
+}
+
+Future<void> Render::CompositeGlyphs8(
+ const Render::CompositeGlyphs8Request& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& op = request.op;
+ auto& src = request.src;
+ auto& dst = request.dst;
+ auto& mask_format = request.mask_format;
+ auto& glyphset = request.glyphset;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& glyphcmds = request.glyphcmds;
+ size_t glyphcmds_len = glyphcmds.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 23;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // op
+ uint8_t tmp17;
+ tmp17 = static_cast<uint8_t>(op);
+ buf.Write(&tmp17);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // src
+ buf.Write(&src);
+
+ // dst
+ buf.Write(&dst);
+
+ // mask_format
+ buf.Write(&mask_format);
+
+ // glyphset
+ buf.Write(&glyphset);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // glyphcmds
+ DCHECK_EQ(static_cast<size_t>(glyphcmds_len), glyphcmds.size());
+ for (auto& glyphcmds_elem : glyphcmds) {
+ // glyphcmds_elem
+ buf.Write(&glyphcmds_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::CompositeGlyphs8",
+ false);
+}
+
+Future<void> Render::CompositeGlyphs8(const PictOp& op,
+ const Picture& src,
+ const Picture& dst,
+ const PictFormat& mask_format,
+ const GlyphSet& glyphset,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const std::vector<uint8_t>& glyphcmds) {
+ return Render::CompositeGlyphs8(Render::CompositeGlyphs8Request{
+ op, src, dst, mask_format, glyphset, src_x, src_y, glyphcmds});
+}
+
+Future<void> Render::CompositeGlyphs16(
+ const Render::CompositeGlyphs16Request& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& op = request.op;
+ auto& src = request.src;
+ auto& dst = request.dst;
+ auto& mask_format = request.mask_format;
+ auto& glyphset = request.glyphset;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& glyphcmds = request.glyphcmds;
+ size_t glyphcmds_len = glyphcmds.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 24;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // op
+ uint8_t tmp18;
+ tmp18 = static_cast<uint8_t>(op);
+ buf.Write(&tmp18);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // src
+ buf.Write(&src);
+
+ // dst
+ buf.Write(&dst);
+
+ // mask_format
+ buf.Write(&mask_format);
+
+ // glyphset
+ buf.Write(&glyphset);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // glyphcmds
+ DCHECK_EQ(static_cast<size_t>(glyphcmds_len), glyphcmds.size());
+ for (auto& glyphcmds_elem : glyphcmds) {
+ // glyphcmds_elem
+ buf.Write(&glyphcmds_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::CompositeGlyphs16",
+ false);
+}
+
+Future<void> Render::CompositeGlyphs16(const PictOp& op,
+ const Picture& src,
+ const Picture& dst,
+ const PictFormat& mask_format,
+ const GlyphSet& glyphset,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const std::vector<uint8_t>& glyphcmds) {
+ return Render::CompositeGlyphs16(Render::CompositeGlyphs16Request{
+ op, src, dst, mask_format, glyphset, src_x, src_y, glyphcmds});
+}
+
+Future<void> Render::CompositeGlyphs32(
+ const Render::CompositeGlyphs32Request& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& op = request.op;
+ auto& src = request.src;
+ auto& dst = request.dst;
+ auto& mask_format = request.mask_format;
+ auto& glyphset = request.glyphset;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& glyphcmds = request.glyphcmds;
+ size_t glyphcmds_len = glyphcmds.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 25;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // op
+ uint8_t tmp19;
+ tmp19 = static_cast<uint8_t>(op);
+ buf.Write(&tmp19);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // src
+ buf.Write(&src);
+
+ // dst
+ buf.Write(&dst);
+
+ // mask_format
+ buf.Write(&mask_format);
+
+ // glyphset
+ buf.Write(&glyphset);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // glyphcmds
+ DCHECK_EQ(static_cast<size_t>(glyphcmds_len), glyphcmds.size());
+ for (auto& glyphcmds_elem : glyphcmds) {
+ // glyphcmds_elem
+ buf.Write(&glyphcmds_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::CompositeGlyphs32",
+ false);
+}
+
+Future<void> Render::CompositeGlyphs32(const PictOp& op,
+ const Picture& src,
+ const Picture& dst,
+ const PictFormat& mask_format,
+ const GlyphSet& glyphset,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const std::vector<uint8_t>& glyphcmds) {
+ return Render::CompositeGlyphs32(Render::CompositeGlyphs32Request{
+ op, src, dst, mask_format, glyphset, src_x, src_y, glyphcmds});
+}
+
+Future<void> Render::FillRectangles(
+ const Render::FillRectanglesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& op = request.op;
+ auto& dst = request.dst;
+ auto& color = request.color;
+ auto& rects = request.rects;
+ size_t rects_len = rects.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 26;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // op
+ uint8_t tmp20;
+ tmp20 = static_cast<uint8_t>(op);
+ buf.Write(&tmp20);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // dst
+ buf.Write(&dst);
+
+ // color
+ {
+ auto& red = color.red;
+ auto& green = color.green;
+ auto& blue = color.blue;
+ auto& alpha = color.alpha;
+
+ // red
+ buf.Write(&red);
+
+ // green
+ buf.Write(&green);
+
+ // blue
+ buf.Write(&blue);
+
+ // alpha
+ buf.Write(&alpha);
+ }
+
+ // rects
+ DCHECK_EQ(static_cast<size_t>(rects_len), rects.size());
+ for (auto& rects_elem : rects) {
+ // rects_elem
+ {
+ auto& x = rects_elem.x;
+ auto& y = rects_elem.y;
+ auto& width = rects_elem.width;
+ auto& height = rects_elem.height;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::FillRectangles", false);
+}
+
+Future<void> Render::FillRectangles(const PictOp& op,
+ const Picture& dst,
+ const Color& color,
+ const std::vector<Rectangle>& rects) {
+ return Render::FillRectangles(
+ Render::FillRectanglesRequest{op, dst, color, rects});
+}
+
+Future<void> Render::CreateCursor(const Render::CreateCursorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cid = request.cid;
+ auto& source = request.source;
+ auto& x = request.x;
+ auto& y = request.y;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 27;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cid
+ buf.Write(&cid);
+
+ // source
+ buf.Write(&source);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::CreateCursor", false);
+}
+
+Future<void> Render::CreateCursor(const Cursor& cid,
+ const Picture& source,
+ const uint16_t& x,
+ const uint16_t& y) {
+ return Render::CreateCursor(Render::CreateCursorRequest{cid, source, x, y});
+}
+
+Future<void> Render::SetPictureTransform(
+ const Render::SetPictureTransformRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& picture = request.picture;
+ auto& transform = request.transform;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 28;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // picture
+ buf.Write(&picture);
+
+ // transform
+ {
+ auto& matrix11 = transform.matrix11;
+ auto& matrix12 = transform.matrix12;
+ auto& matrix13 = transform.matrix13;
+ auto& matrix21 = transform.matrix21;
+ auto& matrix22 = transform.matrix22;
+ auto& matrix23 = transform.matrix23;
+ auto& matrix31 = transform.matrix31;
+ auto& matrix32 = transform.matrix32;
+ auto& matrix33 = transform.matrix33;
+
+ // matrix11
+ buf.Write(&matrix11);
+
+ // matrix12
+ buf.Write(&matrix12);
+
+ // matrix13
+ buf.Write(&matrix13);
+
+ // matrix21
+ buf.Write(&matrix21);
+
+ // matrix22
+ buf.Write(&matrix22);
+
+ // matrix23
+ buf.Write(&matrix23);
+
+ // matrix31
+ buf.Write(&matrix31);
+
+ // matrix32
+ buf.Write(&matrix32);
+
+ // matrix33
+ buf.Write(&matrix33);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::SetPictureTransform",
+ false);
+}
+
+Future<void> Render::SetPictureTransform(const Picture& picture,
+ const Transform& transform) {
+ return Render::SetPictureTransform(
+ Render::SetPictureTransformRequest{picture, transform});
+}
+
+Future<Render::QueryFiltersReply> Render::QueryFilters(
+ const Render::QueryFiltersRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 29;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Render::QueryFiltersReply>(
+ &buf, "Render::QueryFilters", false);
+}
+
+Future<Render::QueryFiltersReply> Render::QueryFilters(
+ const Drawable& drawable) {
+ return Render::QueryFilters(Render::QueryFiltersRequest{drawable});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Render::QueryFiltersReply> detail::ReadReply<
+ Render::QueryFiltersReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Render::QueryFiltersReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num_aliases{};
+ uint32_t num_filters{};
+ auto& aliases = (*reply).aliases;
+ size_t aliases_len = aliases.size();
+ auto& filters = (*reply).filters;
+ size_t filters_len = filters.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_aliases
+ Read(&num_aliases, &buf);
+
+ // num_filters
+ Read(&num_filters, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ // aliases
+ aliases.resize(num_aliases);
+ for (auto& aliases_elem : aliases) {
+ // aliases_elem
+ Read(&aliases_elem, &buf);
+ }
+
+ // filters
+ filters.resize(num_filters);
+ for (auto& filters_elem : filters) {
+ // filters_elem
+ {
+ uint8_t name_len{};
+ auto& name = filters_elem.name;
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // name
+ name.resize(name_len);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Render::SetPictureFilter(
+ const Render::SetPictureFilterRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& picture = request.picture;
+ uint16_t filter_len{};
+ auto& filter = request.filter;
+ auto& values = request.values;
+ size_t values_len = values.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 30;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // picture
+ buf.Write(&picture);
+
+ // filter_len
+ filter_len = filter.size();
+ buf.Write(&filter_len);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // filter
+ DCHECK_EQ(static_cast<size_t>(filter_len), filter.size());
+ for (auto& filter_elem : filter) {
+ // filter_elem
+ buf.Write(&filter_elem);
+ }
+
+ // pad1
+ Align(&buf, 4);
+
+ // values
+ DCHECK_EQ(static_cast<size_t>(values_len), values.size());
+ for (auto& values_elem : values) {
+ // values_elem
+ buf.Write(&values_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::SetPictureFilter",
+ false);
+}
+
+Future<void> Render::SetPictureFilter(const Picture& picture,
+ const std::string& filter,
+ const std::vector<Fixed>& values) {
+ return Render::SetPictureFilter(
+ Render::SetPictureFilterRequest{picture, filter, values});
+}
+
+Future<void> Render::CreateAnimCursor(
+ const Render::CreateAnimCursorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cid = request.cid;
+ auto& cursors = request.cursors;
+ size_t cursors_len = cursors.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 31;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cid
+ buf.Write(&cid);
+
+ // cursors
+ DCHECK_EQ(static_cast<size_t>(cursors_len), cursors.size());
+ for (auto& cursors_elem : cursors) {
+ // cursors_elem
+ {
+ auto& cursor = cursors_elem.cursor;
+ auto& delay = cursors_elem.delay;
+
+ // cursor
+ buf.Write(&cursor);
+
+ // delay
+ buf.Write(&delay);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::CreateAnimCursor",
+ false);
+}
+
+Future<void> Render::CreateAnimCursor(
+ const Cursor& cid,
+ const std::vector<AnimationCursorElement>& cursors) {
+ return Render::CreateAnimCursor(
+ Render::CreateAnimCursorRequest{cid, cursors});
+}
+
+Future<void> Render::AddTraps(const Render::AddTrapsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& picture = request.picture;
+ auto& x_off = request.x_off;
+ auto& y_off = request.y_off;
+ auto& traps = request.traps;
+ size_t traps_len = traps.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 32;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // picture
+ buf.Write(&picture);
+
+ // x_off
+ buf.Write(&x_off);
+
+ // y_off
+ buf.Write(&y_off);
+
+ // traps
+ DCHECK_EQ(static_cast<size_t>(traps_len), traps.size());
+ for (auto& traps_elem : traps) {
+ // traps_elem
+ {
+ auto& top = traps_elem.top;
+ auto& bot = traps_elem.bot;
+
+ // top
+ {
+ auto& l = top.l;
+ auto& r = top.r;
+ auto& y = top.y;
+
+ // l
+ buf.Write(&l);
+
+ // r
+ buf.Write(&r);
+
+ // y
+ buf.Write(&y);
+ }
+
+ // bot
+ {
+ auto& l = bot.l;
+ auto& r = bot.r;
+ auto& y = bot.y;
+
+ // l
+ buf.Write(&l);
+
+ // r
+ buf.Write(&r);
+
+ // y
+ buf.Write(&y);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::AddTraps", false);
+}
+
+Future<void> Render::AddTraps(const Picture& picture,
+ const int16_t& x_off,
+ const int16_t& y_off,
+ const std::vector<Trap>& traps) {
+ return Render::AddTraps(
+ Render::AddTrapsRequest{picture, x_off, y_off, traps});
+}
+
+Future<void> Render::CreateSolidFill(
+ const Render::CreateSolidFillRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& picture = request.picture;
+ auto& color = request.color;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 33;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // picture
+ buf.Write(&picture);
+
+ // color
+ {
+ auto& red = color.red;
+ auto& green = color.green;
+ auto& blue = color.blue;
+ auto& alpha = color.alpha;
+
+ // red
+ buf.Write(&red);
+
+ // green
+ buf.Write(&green);
+
+ // blue
+ buf.Write(&blue);
+
+ // alpha
+ buf.Write(&alpha);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::CreateSolidFill", false);
+}
+
+Future<void> Render::CreateSolidFill(const Picture& picture,
+ const Color& color) {
+ return Render::CreateSolidFill(
+ Render::CreateSolidFillRequest{picture, color});
+}
+
+Future<void> Render::CreateLinearGradient(
+ const Render::CreateLinearGradientRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& picture = request.picture;
+ auto& p1 = request.p1;
+ auto& p2 = request.p2;
+ uint32_t num_stops{};
+ auto& stops = request.stops;
+ size_t stops_len = stops.size();
+ auto& colors = request.colors;
+ size_t colors_len = colors.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 34;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // picture
+ buf.Write(&picture);
+
+ // p1
+ {
+ auto& x = p1.x;
+ auto& y = p1.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+
+ // p2
+ {
+ auto& x = p2.x;
+ auto& y = p2.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+
+ // num_stops
+ num_stops = stops.size();
+ buf.Write(&num_stops);
+
+ // stops
+ DCHECK_EQ(static_cast<size_t>(num_stops), stops.size());
+ for (auto& stops_elem : stops) {
+ // stops_elem
+ buf.Write(&stops_elem);
+ }
+
+ // colors
+ DCHECK_EQ(static_cast<size_t>(num_stops), colors.size());
+ for (auto& colors_elem : colors) {
+ // colors_elem
+ {
+ auto& red = colors_elem.red;
+ auto& green = colors_elem.green;
+ auto& blue = colors_elem.blue;
+ auto& alpha = colors_elem.alpha;
+
+ // red
+ buf.Write(&red);
+
+ // green
+ buf.Write(&green);
+
+ // blue
+ buf.Write(&blue);
+
+ // alpha
+ buf.Write(&alpha);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::CreateLinearGradient",
+ false);
+}
+
+Future<void> Render::CreateLinearGradient(const Picture& picture,
+ const PointFix& p1,
+ const PointFix& p2,
+ const std::vector<Fixed>& stops,
+ const std::vector<Color>& colors) {
+ return Render::CreateLinearGradient(
+ Render::CreateLinearGradientRequest{picture, p1, p2, stops, colors});
+}
+
+Future<void> Render::CreateRadialGradient(
+ const Render::CreateRadialGradientRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& picture = request.picture;
+ auto& inner = request.inner;
+ auto& outer = request.outer;
+ auto& inner_radius = request.inner_radius;
+ auto& outer_radius = request.outer_radius;
+ uint32_t num_stops{};
+ auto& stops = request.stops;
+ size_t stops_len = stops.size();
+ auto& colors = request.colors;
+ size_t colors_len = colors.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 35;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // picture
+ buf.Write(&picture);
+
+ // inner
+ {
+ auto& x = inner.x;
+ auto& y = inner.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+
+ // outer
+ {
+ auto& x = outer.x;
+ auto& y = outer.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+
+ // inner_radius
+ buf.Write(&inner_radius);
+
+ // outer_radius
+ buf.Write(&outer_radius);
+
+ // num_stops
+ num_stops = stops.size();
+ buf.Write(&num_stops);
+
+ // stops
+ DCHECK_EQ(static_cast<size_t>(num_stops), stops.size());
+ for (auto& stops_elem : stops) {
+ // stops_elem
+ buf.Write(&stops_elem);
+ }
+
+ // colors
+ DCHECK_EQ(static_cast<size_t>(num_stops), colors.size());
+ for (auto& colors_elem : colors) {
+ // colors_elem
+ {
+ auto& red = colors_elem.red;
+ auto& green = colors_elem.green;
+ auto& blue = colors_elem.blue;
+ auto& alpha = colors_elem.alpha;
+
+ // red
+ buf.Write(&red);
+
+ // green
+ buf.Write(&green);
+
+ // blue
+ buf.Write(&blue);
+
+ // alpha
+ buf.Write(&alpha);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::CreateRadialGradient",
+ false);
+}
+
+Future<void> Render::CreateRadialGradient(const Picture& picture,
+ const PointFix& inner,
+ const PointFix& outer,
+ const Fixed& inner_radius,
+ const Fixed& outer_radius,
+ const std::vector<Fixed>& stops,
+ const std::vector<Color>& colors) {
+ return Render::CreateRadialGradient(Render::CreateRadialGradientRequest{
+ picture, inner, outer, inner_radius, outer_radius, stops, colors});
+}
+
+Future<void> Render::CreateConicalGradient(
+ const Render::CreateConicalGradientRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& picture = request.picture;
+ auto& center = request.center;
+ auto& angle = request.angle;
+ uint32_t num_stops{};
+ auto& stops = request.stops;
+ size_t stops_len = stops.size();
+ auto& colors = request.colors;
+ size_t colors_len = colors.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 36;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // picture
+ buf.Write(&picture);
+
+ // center
+ {
+ auto& x = center.x;
+ auto& y = center.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+
+ // angle
+ buf.Write(&angle);
+
+ // num_stops
+ num_stops = stops.size();
+ buf.Write(&num_stops);
+
+ // stops
+ DCHECK_EQ(static_cast<size_t>(num_stops), stops.size());
+ for (auto& stops_elem : stops) {
+ // stops_elem
+ buf.Write(&stops_elem);
+ }
+
+ // colors
+ DCHECK_EQ(static_cast<size_t>(num_stops), colors.size());
+ for (auto& colors_elem : colors) {
+ // colors_elem
+ {
+ auto& red = colors_elem.red;
+ auto& green = colors_elem.green;
+ auto& blue = colors_elem.blue;
+ auto& alpha = colors_elem.alpha;
+
+ // red
+ buf.Write(&red);
+
+ // green
+ buf.Write(&green);
+
+ // blue
+ buf.Write(&blue);
+
+ // alpha
+ buf.Write(&alpha);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Render::CreateConicalGradient",
+ false);
+}
+
+Future<void> Render::CreateConicalGradient(const Picture& picture,
+ const PointFix& center,
+ const Fixed& angle,
+ const std::vector<Fixed>& stops,
+ const std::vector<Color>& colors) {
+ return Render::CreateConicalGradient(Render::CreateConicalGradientRequest{
+ picture, center, angle, stops, colors});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/render.h b/chromium/ui/gfx/x/generated_protos/render.h
new file mode 100644
index 00000000000..cf372e709c8
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/render.h
@@ -0,0 +1,1047 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_RENDER_H_
+#define UI_GFX_X_GENERATED_PROTOS_RENDER_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Render {
+ public:
+ static constexpr unsigned major_version = 0;
+ static constexpr unsigned minor_version = 11;
+
+ Render(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class PictType : int {
+ Indexed = 0,
+ Direct = 1,
+ };
+
+ enum class Picture : uint32_t {
+ None = 0,
+ };
+
+ enum class PictOp : int {
+ Clear = 0,
+ Src = 1,
+ Dst = 2,
+ Over = 3,
+ OverReverse = 4,
+ In = 5,
+ InReverse = 6,
+ Out = 7,
+ OutReverse = 8,
+ Atop = 9,
+ AtopReverse = 10,
+ Xor = 11,
+ Add = 12,
+ Saturate = 13,
+ DisjointClear = 16,
+ DisjointSrc = 17,
+ DisjointDst = 18,
+ DisjointOver = 19,
+ DisjointOverReverse = 20,
+ DisjointIn = 21,
+ DisjointInReverse = 22,
+ DisjointOut = 23,
+ DisjointOutReverse = 24,
+ DisjointAtop = 25,
+ DisjointAtopReverse = 26,
+ DisjointXor = 27,
+ ConjointClear = 32,
+ ConjointSrc = 33,
+ ConjointDst = 34,
+ ConjointOver = 35,
+ ConjointOverReverse = 36,
+ ConjointIn = 37,
+ ConjointInReverse = 38,
+ ConjointOut = 39,
+ ConjointOutReverse = 40,
+ ConjointAtop = 41,
+ ConjointAtopReverse = 42,
+ ConjointXor = 43,
+ Multiply = 48,
+ Screen = 49,
+ Overlay = 50,
+ Darken = 51,
+ Lighten = 52,
+ ColorDodge = 53,
+ ColorBurn = 54,
+ HardLight = 55,
+ SoftLight = 56,
+ Difference = 57,
+ Exclusion = 58,
+ HSLHue = 59,
+ HSLSaturation = 60,
+ HSLColor = 61,
+ HSLLuminosity = 62,
+ };
+
+ enum class PolyEdge : int {
+ Sharp = 0,
+ Smooth = 1,
+ };
+
+ enum class PolyMode : int {
+ Precise = 0,
+ Imprecise = 1,
+ };
+
+ enum class CreatePictureAttribute : int {
+ Repeat = 1 << 0,
+ AlphaMap = 1 << 1,
+ AlphaXOrigin = 1 << 2,
+ AlphaYOrigin = 1 << 3,
+ ClipXOrigin = 1 << 4,
+ ClipYOrigin = 1 << 5,
+ ClipMask = 1 << 6,
+ GraphicsExposure = 1 << 7,
+ SubwindowMode = 1 << 8,
+ PolyEdge = 1 << 9,
+ PolyMode = 1 << 10,
+ Dither = 1 << 11,
+ ComponentAlpha = 1 << 12,
+ };
+
+ enum class SubPixel : int {
+ Unknown = 0,
+ HorizontalRGB = 1,
+ HorizontalBGR = 2,
+ VerticalRGB = 3,
+ VerticalBGR = 4,
+ None = 5,
+ };
+
+ enum class Repeat : int {
+ None = 0,
+ Normal = 1,
+ Pad = 2,
+ Reflect = 3,
+ };
+
+ enum class Glyph : uint32_t {};
+
+ enum class GlyphSet : uint32_t {};
+
+ enum class PictFormat : uint32_t {};
+
+ enum class Fixed : int32_t {};
+
+ struct PictFormatError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct PictureError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct PictOpError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct GlyphSetError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct GlyphError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct DirectFormat {
+ uint16_t red_shift{};
+ uint16_t red_mask{};
+ uint16_t green_shift{};
+ uint16_t green_mask{};
+ uint16_t blue_shift{};
+ uint16_t blue_mask{};
+ uint16_t alpha_shift{};
+ uint16_t alpha_mask{};
+ };
+
+ struct PictFormInfo {
+ PictFormat id{};
+ PictType type{};
+ uint8_t depth{};
+ DirectFormat direct{};
+ ColorMap colormap{};
+ };
+
+ struct PictVisual {
+ VisualId visual{};
+ PictFormat format{};
+ };
+
+ struct PictDepth {
+ uint8_t depth{};
+ std::vector<PictVisual> visuals{};
+ };
+
+ struct PictScreen {
+ PictFormat fallback{};
+ std::vector<PictDepth> depths{};
+ };
+
+ struct IndexValue {
+ uint32_t pixel{};
+ uint16_t red{};
+ uint16_t green{};
+ uint16_t blue{};
+ uint16_t alpha{};
+ };
+
+ struct Color {
+ uint16_t red{};
+ uint16_t green{};
+ uint16_t blue{};
+ uint16_t alpha{};
+ };
+
+ struct PointFix {
+ Fixed x{};
+ Fixed y{};
+ };
+
+ struct LineFix {
+ PointFix p1{};
+ PointFix p2{};
+ };
+
+ struct Triangle {
+ PointFix p1{};
+ PointFix p2{};
+ PointFix p3{};
+ };
+
+ struct Trapezoid {
+ Fixed top{};
+ Fixed bottom{};
+ LineFix left{};
+ LineFix right{};
+ };
+
+ struct GlyphInfo {
+ uint16_t width{};
+ uint16_t height{};
+ int16_t x{};
+ int16_t y{};
+ int16_t x_off{};
+ int16_t y_off{};
+ };
+
+ struct Transform {
+ Fixed matrix11{};
+ Fixed matrix12{};
+ Fixed matrix13{};
+ Fixed matrix21{};
+ Fixed matrix22{};
+ Fixed matrix23{};
+ Fixed matrix31{};
+ Fixed matrix32{};
+ Fixed matrix33{};
+ };
+
+ struct AnimationCursorElement {
+ Cursor cursor{};
+ uint32_t delay{};
+ };
+
+ struct SpanFix {
+ Fixed l{};
+ Fixed r{};
+ Fixed y{};
+ };
+
+ struct Trap {
+ SpanFix top{};
+ SpanFix bot{};
+ };
+
+ struct QueryVersionRequest {
+ uint32_t client_major_version{};
+ uint32_t client_minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(
+ const uint32_t& client_major_version = {},
+ const uint32_t& client_minor_version = {});
+
+ struct QueryPictFormatsRequest {};
+
+ struct QueryPictFormatsReply {
+ uint16_t sequence{};
+ uint32_t num_depths{};
+ uint32_t num_visuals{};
+ std::vector<PictFormInfo> formats{};
+ std::vector<PictScreen> screens{};
+ std::vector<SubPixel> subpixels{};
+ };
+
+ using QueryPictFormatsResponse = Response<QueryPictFormatsReply>;
+
+ Future<QueryPictFormatsReply> QueryPictFormats(
+ const QueryPictFormatsRequest& request);
+
+ Future<QueryPictFormatsReply> QueryPictFormats();
+
+ struct QueryPictIndexValuesRequest {
+ PictFormat format{};
+ };
+
+ struct QueryPictIndexValuesReply {
+ uint16_t sequence{};
+ std::vector<IndexValue> values{};
+ };
+
+ using QueryPictIndexValuesResponse = Response<QueryPictIndexValuesReply>;
+
+ Future<QueryPictIndexValuesReply> QueryPictIndexValues(
+ const QueryPictIndexValuesRequest& request);
+
+ Future<QueryPictIndexValuesReply> QueryPictIndexValues(
+ const PictFormat& format = {});
+
+ struct CreatePictureRequest {
+ Picture pid{};
+ Drawable drawable{};
+ PictFormat format{};
+ base::Optional<Repeat> repeat{};
+ base::Optional<Picture> alphamap{};
+ base::Optional<int32_t> alphaxorigin{};
+ base::Optional<int32_t> alphayorigin{};
+ base::Optional<int32_t> clipxorigin{};
+ base::Optional<int32_t> clipyorigin{};
+ base::Optional<Pixmap> clipmask{};
+ base::Optional<uint32_t> graphicsexposure{};
+ base::Optional<SubwindowMode> subwindowmode{};
+ base::Optional<PolyEdge> polyedge{};
+ base::Optional<PolyMode> polymode{};
+ base::Optional<Atom> dither{};
+ base::Optional<uint32_t> componentalpha{};
+ };
+
+ using CreatePictureResponse = Response<void>;
+
+ Future<void> CreatePicture(const CreatePictureRequest& request);
+
+ Future<void> CreatePicture(
+ const Picture& pid = {},
+ const Drawable& drawable = {},
+ const PictFormat& format = {},
+ const base::Optional<Repeat>& repeat = base::nullopt,
+ const base::Optional<Picture>& alphamap = base::nullopt,
+ const base::Optional<int32_t>& alphaxorigin = base::nullopt,
+ const base::Optional<int32_t>& alphayorigin = base::nullopt,
+ const base::Optional<int32_t>& clipxorigin = base::nullopt,
+ const base::Optional<int32_t>& clipyorigin = base::nullopt,
+ const base::Optional<Pixmap>& clipmask = base::nullopt,
+ const base::Optional<uint32_t>& graphicsexposure = base::nullopt,
+ const base::Optional<SubwindowMode>& subwindowmode = base::nullopt,
+ const base::Optional<PolyEdge>& polyedge = base::nullopt,
+ const base::Optional<PolyMode>& polymode = base::nullopt,
+ const base::Optional<Atom>& dither = base::nullopt,
+ const base::Optional<uint32_t>& componentalpha = base::nullopt);
+
+ struct ChangePictureRequest {
+ Picture picture{};
+ base::Optional<Repeat> repeat{};
+ base::Optional<Picture> alphamap{};
+ base::Optional<int32_t> alphaxorigin{};
+ base::Optional<int32_t> alphayorigin{};
+ base::Optional<int32_t> clipxorigin{};
+ base::Optional<int32_t> clipyorigin{};
+ base::Optional<Pixmap> clipmask{};
+ base::Optional<uint32_t> graphicsexposure{};
+ base::Optional<SubwindowMode> subwindowmode{};
+ base::Optional<PolyEdge> polyedge{};
+ base::Optional<PolyMode> polymode{};
+ base::Optional<Atom> dither{};
+ base::Optional<uint32_t> componentalpha{};
+ };
+
+ using ChangePictureResponse = Response<void>;
+
+ Future<void> ChangePicture(const ChangePictureRequest& request);
+
+ Future<void> ChangePicture(
+ const Picture& picture = {},
+ const base::Optional<Repeat>& repeat = base::nullopt,
+ const base::Optional<Picture>& alphamap = base::nullopt,
+ const base::Optional<int32_t>& alphaxorigin = base::nullopt,
+ const base::Optional<int32_t>& alphayorigin = base::nullopt,
+ const base::Optional<int32_t>& clipxorigin = base::nullopt,
+ const base::Optional<int32_t>& clipyorigin = base::nullopt,
+ const base::Optional<Pixmap>& clipmask = base::nullopt,
+ const base::Optional<uint32_t>& graphicsexposure = base::nullopt,
+ const base::Optional<SubwindowMode>& subwindowmode = base::nullopt,
+ const base::Optional<PolyEdge>& polyedge = base::nullopt,
+ const base::Optional<PolyMode>& polymode = base::nullopt,
+ const base::Optional<Atom>& dither = base::nullopt,
+ const base::Optional<uint32_t>& componentalpha = base::nullopt);
+
+ struct SetPictureClipRectanglesRequest {
+ Picture picture{};
+ int16_t clip_x_origin{};
+ int16_t clip_y_origin{};
+ std::vector<Rectangle> rectangles{};
+ };
+
+ using SetPictureClipRectanglesResponse = Response<void>;
+
+ Future<void> SetPictureClipRectangles(
+ const SetPictureClipRectanglesRequest& request);
+
+ Future<void> SetPictureClipRectangles(
+ const Picture& picture = {},
+ const int16_t& clip_x_origin = {},
+ const int16_t& clip_y_origin = {},
+ const std::vector<Rectangle>& rectangles = {});
+
+ struct FreePictureRequest {
+ Picture picture{};
+ };
+
+ using FreePictureResponse = Response<void>;
+
+ Future<void> FreePicture(const FreePictureRequest& request);
+
+ Future<void> FreePicture(const Picture& picture = {});
+
+ struct CompositeRequest {
+ PictOp op{};
+ Picture src{};
+ Picture mask{};
+ Picture dst{};
+ int16_t src_x{};
+ int16_t src_y{};
+ int16_t mask_x{};
+ int16_t mask_y{};
+ int16_t dst_x{};
+ int16_t dst_y{};
+ uint16_t width{};
+ uint16_t height{};
+ };
+
+ using CompositeResponse = Response<void>;
+
+ Future<void> Composite(const CompositeRequest& request);
+
+ Future<void> Composite(const PictOp& op = {},
+ const Picture& src = {},
+ const Picture& mask = {},
+ const Picture& dst = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const int16_t& mask_x = {},
+ const int16_t& mask_y = {},
+ const int16_t& dst_x = {},
+ const int16_t& dst_y = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {});
+
+ struct TrapezoidsRequest {
+ PictOp op{};
+ Picture src{};
+ Picture dst{};
+ PictFormat mask_format{};
+ int16_t src_x{};
+ int16_t src_y{};
+ std::vector<Trapezoid> traps{};
+ };
+
+ using TrapezoidsResponse = Response<void>;
+
+ Future<void> Trapezoids(const TrapezoidsRequest& request);
+
+ Future<void> Trapezoids(const PictOp& op = {},
+ const Picture& src = {},
+ const Picture& dst = {},
+ const PictFormat& mask_format = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const std::vector<Trapezoid>& traps = {});
+
+ struct TrianglesRequest {
+ PictOp op{};
+ Picture src{};
+ Picture dst{};
+ PictFormat mask_format{};
+ int16_t src_x{};
+ int16_t src_y{};
+ std::vector<Triangle> triangles{};
+ };
+
+ using TrianglesResponse = Response<void>;
+
+ Future<void> Triangles(const TrianglesRequest& request);
+
+ Future<void> Triangles(const PictOp& op = {},
+ const Picture& src = {},
+ const Picture& dst = {},
+ const PictFormat& mask_format = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const std::vector<Triangle>& triangles = {});
+
+ struct TriStripRequest {
+ PictOp op{};
+ Picture src{};
+ Picture dst{};
+ PictFormat mask_format{};
+ int16_t src_x{};
+ int16_t src_y{};
+ std::vector<PointFix> points{};
+ };
+
+ using TriStripResponse = Response<void>;
+
+ Future<void> TriStrip(const TriStripRequest& request);
+
+ Future<void> TriStrip(const PictOp& op = {},
+ const Picture& src = {},
+ const Picture& dst = {},
+ const PictFormat& mask_format = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const std::vector<PointFix>& points = {});
+
+ struct TriFanRequest {
+ PictOp op{};
+ Picture src{};
+ Picture dst{};
+ PictFormat mask_format{};
+ int16_t src_x{};
+ int16_t src_y{};
+ std::vector<PointFix> points{};
+ };
+
+ using TriFanResponse = Response<void>;
+
+ Future<void> TriFan(const TriFanRequest& request);
+
+ Future<void> TriFan(const PictOp& op = {},
+ const Picture& src = {},
+ const Picture& dst = {},
+ const PictFormat& mask_format = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const std::vector<PointFix>& points = {});
+
+ struct CreateGlyphSetRequest {
+ GlyphSet gsid{};
+ PictFormat format{};
+ };
+
+ using CreateGlyphSetResponse = Response<void>;
+
+ Future<void> CreateGlyphSet(const CreateGlyphSetRequest& request);
+
+ Future<void> CreateGlyphSet(const GlyphSet& gsid = {},
+ const PictFormat& format = {});
+
+ struct ReferenceGlyphSetRequest {
+ GlyphSet gsid{};
+ GlyphSet existing{};
+ };
+
+ using ReferenceGlyphSetResponse = Response<void>;
+
+ Future<void> ReferenceGlyphSet(const ReferenceGlyphSetRequest& request);
+
+ Future<void> ReferenceGlyphSet(const GlyphSet& gsid = {},
+ const GlyphSet& existing = {});
+
+ struct FreeGlyphSetRequest {
+ GlyphSet glyphset{};
+ };
+
+ using FreeGlyphSetResponse = Response<void>;
+
+ Future<void> FreeGlyphSet(const FreeGlyphSetRequest& request);
+
+ Future<void> FreeGlyphSet(const GlyphSet& glyphset = {});
+
+ struct AddGlyphsRequest {
+ GlyphSet glyphset{};
+ std::vector<uint32_t> glyphids{};
+ std::vector<GlyphInfo> glyphs{};
+ std::vector<uint8_t> data{};
+ };
+
+ using AddGlyphsResponse = Response<void>;
+
+ Future<void> AddGlyphs(const AddGlyphsRequest& request);
+
+ Future<void> AddGlyphs(const GlyphSet& glyphset = {},
+ const std::vector<uint32_t>& glyphids = {},
+ const std::vector<GlyphInfo>& glyphs = {},
+ const std::vector<uint8_t>& data = {});
+
+ struct FreeGlyphsRequest {
+ GlyphSet glyphset{};
+ std::vector<Glyph> glyphs{};
+ };
+
+ using FreeGlyphsResponse = Response<void>;
+
+ Future<void> FreeGlyphs(const FreeGlyphsRequest& request);
+
+ Future<void> FreeGlyphs(const GlyphSet& glyphset = {},
+ const std::vector<Glyph>& glyphs = {});
+
+ struct CompositeGlyphs8Request {
+ PictOp op{};
+ Picture src{};
+ Picture dst{};
+ PictFormat mask_format{};
+ GlyphSet glyphset{};
+ int16_t src_x{};
+ int16_t src_y{};
+ std::vector<uint8_t> glyphcmds{};
+ };
+
+ using CompositeGlyphs8Response = Response<void>;
+
+ Future<void> CompositeGlyphs8(const CompositeGlyphs8Request& request);
+
+ Future<void> CompositeGlyphs8(const PictOp& op = {},
+ const Picture& src = {},
+ const Picture& dst = {},
+ const PictFormat& mask_format = {},
+ const GlyphSet& glyphset = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const std::vector<uint8_t>& glyphcmds = {});
+
+ struct CompositeGlyphs16Request {
+ PictOp op{};
+ Picture src{};
+ Picture dst{};
+ PictFormat mask_format{};
+ GlyphSet glyphset{};
+ int16_t src_x{};
+ int16_t src_y{};
+ std::vector<uint8_t> glyphcmds{};
+ };
+
+ using CompositeGlyphs16Response = Response<void>;
+
+ Future<void> CompositeGlyphs16(const CompositeGlyphs16Request& request);
+
+ Future<void> CompositeGlyphs16(const PictOp& op = {},
+ const Picture& src = {},
+ const Picture& dst = {},
+ const PictFormat& mask_format = {},
+ const GlyphSet& glyphset = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const std::vector<uint8_t>& glyphcmds = {});
+
+ struct CompositeGlyphs32Request {
+ PictOp op{};
+ Picture src{};
+ Picture dst{};
+ PictFormat mask_format{};
+ GlyphSet glyphset{};
+ int16_t src_x{};
+ int16_t src_y{};
+ std::vector<uint8_t> glyphcmds{};
+ };
+
+ using CompositeGlyphs32Response = Response<void>;
+
+ Future<void> CompositeGlyphs32(const CompositeGlyphs32Request& request);
+
+ Future<void> CompositeGlyphs32(const PictOp& op = {},
+ const Picture& src = {},
+ const Picture& dst = {},
+ const PictFormat& mask_format = {},
+ const GlyphSet& glyphset = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const std::vector<uint8_t>& glyphcmds = {});
+
+ struct FillRectanglesRequest {
+ PictOp op{};
+ Picture dst{};
+ Color color{};
+ std::vector<Rectangle> rects{};
+ };
+
+ using FillRectanglesResponse = Response<void>;
+
+ Future<void> FillRectangles(const FillRectanglesRequest& request);
+
+ Future<void> FillRectangles(const PictOp& op = {},
+ const Picture& dst = {},
+ const Color& color = {{}, {}, {}, {}},
+ const std::vector<Rectangle>& rects = {});
+
+ struct CreateCursorRequest {
+ Cursor cid{};
+ Picture source{};
+ uint16_t x{};
+ uint16_t y{};
+ };
+
+ using CreateCursorResponse = Response<void>;
+
+ Future<void> CreateCursor(const CreateCursorRequest& request);
+
+ Future<void> CreateCursor(const Cursor& cid = {},
+ const Picture& source = {},
+ const uint16_t& x = {},
+ const uint16_t& y = {});
+
+ struct SetPictureTransformRequest {
+ Picture picture{};
+ Transform transform{};
+ };
+
+ using SetPictureTransformResponse = Response<void>;
+
+ Future<void> SetPictureTransform(const SetPictureTransformRequest& request);
+
+ Future<void> SetPictureTransform(
+ const Picture& picture = {},
+ const Transform& transform = {{}, {}, {}, {}, {}, {}, {}, {}, {}});
+
+ struct QueryFiltersRequest {
+ Drawable drawable{};
+ };
+
+ struct QueryFiltersReply {
+ uint16_t sequence{};
+ std::vector<uint16_t> aliases{};
+ std::vector<Str> filters{};
+ };
+
+ using QueryFiltersResponse = Response<QueryFiltersReply>;
+
+ Future<QueryFiltersReply> QueryFilters(const QueryFiltersRequest& request);
+
+ Future<QueryFiltersReply> QueryFilters(const Drawable& drawable = {});
+
+ struct SetPictureFilterRequest {
+ Picture picture{};
+ std::string filter{};
+ std::vector<Fixed> values{};
+ };
+
+ using SetPictureFilterResponse = Response<void>;
+
+ Future<void> SetPictureFilter(const SetPictureFilterRequest& request);
+
+ Future<void> SetPictureFilter(const Picture& picture = {},
+ const std::string& filter = {},
+ const std::vector<Fixed>& values = {});
+
+ struct CreateAnimCursorRequest {
+ Cursor cid{};
+ std::vector<AnimationCursorElement> cursors{};
+ };
+
+ using CreateAnimCursorResponse = Response<void>;
+
+ Future<void> CreateAnimCursor(const CreateAnimCursorRequest& request);
+
+ Future<void> CreateAnimCursor(
+ const Cursor& cid = {},
+ const std::vector<AnimationCursorElement>& cursors = {});
+
+ struct AddTrapsRequest {
+ Picture picture{};
+ int16_t x_off{};
+ int16_t y_off{};
+ std::vector<Trap> traps{};
+ };
+
+ using AddTrapsResponse = Response<void>;
+
+ Future<void> AddTraps(const AddTrapsRequest& request);
+
+ Future<void> AddTraps(const Picture& picture = {},
+ const int16_t& x_off = {},
+ const int16_t& y_off = {},
+ const std::vector<Trap>& traps = {});
+
+ struct CreateSolidFillRequest {
+ Picture picture{};
+ Color color{};
+ };
+
+ using CreateSolidFillResponse = Response<void>;
+
+ Future<void> CreateSolidFill(const CreateSolidFillRequest& request);
+
+ Future<void> CreateSolidFill(const Picture& picture = {},
+ const Color& color = {{}, {}, {}, {}});
+
+ struct CreateLinearGradientRequest {
+ Picture picture{};
+ PointFix p1{};
+ PointFix p2{};
+ std::vector<Fixed> stops{};
+ std::vector<Color> colors{};
+ };
+
+ using CreateLinearGradientResponse = Response<void>;
+
+ Future<void> CreateLinearGradient(const CreateLinearGradientRequest& request);
+
+ Future<void> CreateLinearGradient(const Picture& picture = {},
+ const PointFix& p1 = {{}, {}},
+ const PointFix& p2 = {{}, {}},
+ const std::vector<Fixed>& stops = {},
+ const std::vector<Color>& colors = {});
+
+ struct CreateRadialGradientRequest {
+ Picture picture{};
+ PointFix inner{};
+ PointFix outer{};
+ Fixed inner_radius{};
+ Fixed outer_radius{};
+ std::vector<Fixed> stops{};
+ std::vector<Color> colors{};
+ };
+
+ using CreateRadialGradientResponse = Response<void>;
+
+ Future<void> CreateRadialGradient(const CreateRadialGradientRequest& request);
+
+ Future<void> CreateRadialGradient(const Picture& picture = {},
+ const PointFix& inner = {{}, {}},
+ const PointFix& outer = {{}, {}},
+ const Fixed& inner_radius = {},
+ const Fixed& outer_radius = {},
+ const std::vector<Fixed>& stops = {},
+ const std::vector<Color>& colors = {});
+
+ struct CreateConicalGradientRequest {
+ Picture picture{};
+ PointFix center{};
+ Fixed angle{};
+ std::vector<Fixed> stops{};
+ std::vector<Color> colors{};
+ };
+
+ using CreateConicalGradientResponse = Response<void>;
+
+ Future<void> CreateConicalGradient(
+ const CreateConicalGradientRequest& request);
+
+ Future<void> CreateConicalGradient(const Picture& picture = {},
+ const PointFix& center = {{}, {}},
+ const Fixed& angle = {},
+ const std::vector<Fixed>& stops = {},
+ const std::vector<Color>& colors = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Render::PictType operator|(x11::Render::PictType l,
+ x11::Render::PictType r) {
+ using T = std::underlying_type_t<x11::Render::PictType>;
+ return static_cast<x11::Render::PictType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::PictType operator&(x11::Render::PictType l,
+ x11::Render::PictType r) {
+ using T = std::underlying_type_t<x11::Render::PictType>;
+ return static_cast<x11::Render::PictType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::Picture operator|(x11::Render::Picture l,
+ x11::Render::Picture r) {
+ using T = std::underlying_type_t<x11::Render::Picture>;
+ return static_cast<x11::Render::Picture>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::Picture operator&(x11::Render::Picture l,
+ x11::Render::Picture r) {
+ using T = std::underlying_type_t<x11::Render::Picture>;
+ return static_cast<x11::Render::Picture>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::PictOp operator|(x11::Render::PictOp l,
+ x11::Render::PictOp r) {
+ using T = std::underlying_type_t<x11::Render::PictOp>;
+ return static_cast<x11::Render::PictOp>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::PictOp operator&(x11::Render::PictOp l,
+ x11::Render::PictOp r) {
+ using T = std::underlying_type_t<x11::Render::PictOp>;
+ return static_cast<x11::Render::PictOp>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::PolyEdge operator|(x11::Render::PolyEdge l,
+ x11::Render::PolyEdge r) {
+ using T = std::underlying_type_t<x11::Render::PolyEdge>;
+ return static_cast<x11::Render::PolyEdge>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::PolyEdge operator&(x11::Render::PolyEdge l,
+ x11::Render::PolyEdge r) {
+ using T = std::underlying_type_t<x11::Render::PolyEdge>;
+ return static_cast<x11::Render::PolyEdge>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::PolyMode operator|(x11::Render::PolyMode l,
+ x11::Render::PolyMode r) {
+ using T = std::underlying_type_t<x11::Render::PolyMode>;
+ return static_cast<x11::Render::PolyMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::PolyMode operator&(x11::Render::PolyMode l,
+ x11::Render::PolyMode r) {
+ using T = std::underlying_type_t<x11::Render::PolyMode>;
+ return static_cast<x11::Render::PolyMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::CreatePictureAttribute operator|(
+ x11::Render::CreatePictureAttribute l,
+ x11::Render::CreatePictureAttribute r) {
+ using T = std::underlying_type_t<x11::Render::CreatePictureAttribute>;
+ return static_cast<x11::Render::CreatePictureAttribute>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::CreatePictureAttribute operator&(
+ x11::Render::CreatePictureAttribute l,
+ x11::Render::CreatePictureAttribute r) {
+ using T = std::underlying_type_t<x11::Render::CreatePictureAttribute>;
+ return static_cast<x11::Render::CreatePictureAttribute>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::SubPixel operator|(x11::Render::SubPixel l,
+ x11::Render::SubPixel r) {
+ using T = std::underlying_type_t<x11::Render::SubPixel>;
+ return static_cast<x11::Render::SubPixel>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::SubPixel operator&(x11::Render::SubPixel l,
+ x11::Render::SubPixel r) {
+ using T = std::underlying_type_t<x11::Render::SubPixel>;
+ return static_cast<x11::Render::SubPixel>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::Repeat operator|(x11::Render::Repeat l,
+ x11::Render::Repeat r) {
+ using T = std::underlying_type_t<x11::Render::Repeat>;
+ return static_cast<x11::Render::Repeat>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Render::Repeat operator&(x11::Render::Repeat l,
+ x11::Render::Repeat r) {
+ using T = std::underlying_type_t<x11::Render::Repeat>;
+ return static_cast<x11::Render::Repeat>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_RENDER_H_
diff --git a/chromium/ui/gfx/x/generated_protos/res.cc b/chromium/ui/gfx/x/generated_protos/res.cc
new file mode 100644
index 00000000000..a17dcfff9e5
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/res.cc
@@ -0,0 +1,680 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "res.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Res::Res(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<Res::QueryVersionReply> Res::QueryVersion(
+ const Res::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client_major = request.client_major;
+ auto& client_minor = request.client_minor;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client_major
+ buf.Write(&client_major);
+
+ // client_minor
+ buf.Write(&client_minor);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Res::QueryVersionReply>(
+ &buf, "Res::QueryVersion", false);
+}
+
+Future<Res::QueryVersionReply> Res::QueryVersion(const uint8_t& client_major,
+ const uint8_t& client_minor) {
+ return Res::QueryVersion(
+ Res::QueryVersionRequest{client_major, client_minor});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Res::QueryVersionReply> detail::ReadReply<
+ Res::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Res::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& server_major = (*reply).server_major;
+ auto& server_minor = (*reply).server_minor;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // server_major
+ Read(&server_major, &buf);
+
+ // server_minor
+ Read(&server_minor, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Res::QueryClientsReply> Res::QueryClients(
+ const Res::QueryClientsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Res::QueryClientsReply>(
+ &buf, "Res::QueryClients", false);
+}
+
+Future<Res::QueryClientsReply> Res::QueryClients() {
+ return Res::QueryClients(Res::QueryClientsRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Res::QueryClientsReply> detail::ReadReply<
+ Res::QueryClientsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Res::QueryClientsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num_clients{};
+ auto& clients = (*reply).clients;
+ size_t clients_len = clients.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_clients
+ Read(&num_clients, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // clients
+ clients.resize(num_clients);
+ for (auto& clients_elem : clients) {
+ // clients_elem
+ {
+ auto& resource_base = clients_elem.resource_base;
+ auto& resource_mask = clients_elem.resource_mask;
+
+ // resource_base
+ Read(&resource_base, &buf);
+
+ // resource_mask
+ Read(&resource_mask, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Res::QueryClientResourcesReply> Res::QueryClientResources(
+ const Res::QueryClientResourcesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& xid = request.xid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // xid
+ buf.Write(&xid);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Res::QueryClientResourcesReply>(
+ &buf, "Res::QueryClientResources", false);
+}
+
+Future<Res::QueryClientResourcesReply> Res::QueryClientResources(
+ const uint32_t& xid) {
+ return Res::QueryClientResources(Res::QueryClientResourcesRequest{xid});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Res::QueryClientResourcesReply> detail::ReadReply<
+ Res::QueryClientResourcesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Res::QueryClientResourcesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num_types{};
+ auto& types = (*reply).types;
+ size_t types_len = types.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_types
+ Read(&num_types, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // types
+ types.resize(num_types);
+ for (auto& types_elem : types) {
+ // types_elem
+ {
+ auto& resource_type = types_elem.resource_type;
+ auto& count = types_elem.count;
+
+ // resource_type
+ Read(&resource_type, &buf);
+
+ // count
+ Read(&count, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Res::QueryClientPixmapBytesReply> Res::QueryClientPixmapBytes(
+ const Res::QueryClientPixmapBytesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& xid = request.xid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // xid
+ buf.Write(&xid);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Res::QueryClientPixmapBytesReply>(
+ &buf, "Res::QueryClientPixmapBytes", false);
+}
+
+Future<Res::QueryClientPixmapBytesReply> Res::QueryClientPixmapBytes(
+ const uint32_t& xid) {
+ return Res::QueryClientPixmapBytes(Res::QueryClientPixmapBytesRequest{xid});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Res::QueryClientPixmapBytesReply> detail::ReadReply<
+ Res::QueryClientPixmapBytesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Res::QueryClientPixmapBytesReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& bytes = (*reply).bytes;
+ auto& bytes_overflow = (*reply).bytes_overflow;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // bytes
+ Read(&bytes, &buf);
+
+ // bytes_overflow
+ Read(&bytes_overflow, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Res::QueryClientIdsReply> Res::QueryClientIds(
+ const Res::QueryClientIdsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint32_t num_specs{};
+ auto& specs = request.specs;
+ size_t specs_len = specs.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // num_specs
+ num_specs = specs.size();
+ buf.Write(&num_specs);
+
+ // specs
+ DCHECK_EQ(static_cast<size_t>(num_specs), specs.size());
+ for (auto& specs_elem : specs) {
+ // specs_elem
+ {
+ auto& client = specs_elem.client;
+ auto& mask = specs_elem.mask;
+
+ // client
+ buf.Write(&client);
+
+ // mask
+ uint32_t tmp0;
+ tmp0 = static_cast<uint32_t>(mask);
+ buf.Write(&tmp0);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Res::QueryClientIdsReply>(
+ &buf, "Res::QueryClientIds", false);
+}
+
+Future<Res::QueryClientIdsReply> Res::QueryClientIds(
+ const std::vector<ClientIdSpec>& specs) {
+ return Res::QueryClientIds(Res::QueryClientIdsRequest{specs});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Res::QueryClientIdsReply> detail::ReadReply<
+ Res::QueryClientIdsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Res::QueryClientIdsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num_ids{};
+ auto& ids = (*reply).ids;
+ size_t ids_len = ids.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_ids
+ Read(&num_ids, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // ids
+ ids.resize(num_ids);
+ for (auto& ids_elem : ids) {
+ // ids_elem
+ {
+ auto& spec = ids_elem.spec;
+ auto& length = ids_elem.length;
+ auto& value = ids_elem.value;
+ size_t value_len = value.size();
+
+ // spec
+ {
+ auto& client = spec.client;
+ auto& mask = spec.mask;
+
+ // client
+ Read(&client, &buf);
+
+ // mask
+ uint32_t tmp1;
+ Read(&tmp1, &buf);
+ mask = static_cast<Res::ClientIdMask>(tmp1);
+ }
+
+ // length
+ Read(&length, &buf);
+
+ // value
+ value.resize((length) / (4));
+ for (auto& value_elem : value) {
+ // value_elem
+ Read(&value_elem, &buf);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Res::QueryResourceBytesReply> Res::QueryResourceBytes(
+ const Res::QueryResourceBytesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client = request.client;
+ uint32_t num_specs{};
+ auto& specs = request.specs;
+ size_t specs_len = specs.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client
+ buf.Write(&client);
+
+ // num_specs
+ num_specs = specs.size();
+ buf.Write(&num_specs);
+
+ // specs
+ DCHECK_EQ(static_cast<size_t>(num_specs), specs.size());
+ for (auto& specs_elem : specs) {
+ // specs_elem
+ {
+ auto& resource = specs_elem.resource;
+ auto& type = specs_elem.type;
+
+ // resource
+ buf.Write(&resource);
+
+ // type
+ buf.Write(&type);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Res::QueryResourceBytesReply>(
+ &buf, "Res::QueryResourceBytes", false);
+}
+
+Future<Res::QueryResourceBytesReply> Res::QueryResourceBytes(
+ const uint32_t& client,
+ const std::vector<ResourceIdSpec>& specs) {
+ return Res::QueryResourceBytes(Res::QueryResourceBytesRequest{client, specs});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Res::QueryResourceBytesReply> detail::ReadReply<
+ Res::QueryResourceBytesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Res::QueryResourceBytesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num_sizes{};
+ auto& sizes = (*reply).sizes;
+ size_t sizes_len = sizes.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_sizes
+ Read(&num_sizes, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // sizes
+ sizes.resize(num_sizes);
+ for (auto& sizes_elem : sizes) {
+ // sizes_elem
+ {
+ auto& size = sizes_elem.size;
+ uint32_t num_cross_references{};
+ auto& cross_references = sizes_elem.cross_references;
+ size_t cross_references_len = cross_references.size();
+
+ // size
+ {
+ auto& spec = size.spec;
+ auto& bytes = size.bytes;
+ auto& ref_count = size.ref_count;
+ auto& use_count = size.use_count;
+
+ // spec
+ {
+ auto& resource = spec.resource;
+ auto& type = spec.type;
+
+ // resource
+ Read(&resource, &buf);
+
+ // type
+ Read(&type, &buf);
+ }
+
+ // bytes
+ Read(&bytes, &buf);
+
+ // ref_count
+ Read(&ref_count, &buf);
+
+ // use_count
+ Read(&use_count, &buf);
+ }
+
+ // num_cross_references
+ Read(&num_cross_references, &buf);
+
+ // cross_references
+ cross_references.resize(num_cross_references);
+ for (auto& cross_references_elem : cross_references) {
+ // cross_references_elem
+ {
+ auto& spec = cross_references_elem.spec;
+ auto& bytes = cross_references_elem.bytes;
+ auto& ref_count = cross_references_elem.ref_count;
+ auto& use_count = cross_references_elem.use_count;
+
+ // spec
+ {
+ auto& resource = spec.resource;
+ auto& type = spec.type;
+
+ // resource
+ Read(&resource, &buf);
+
+ // type
+ Read(&type, &buf);
+ }
+
+ // bytes
+ Read(&bytes, &buf);
+
+ // ref_count
+ Read(&ref_count, &buf);
+
+ // use_count
+ Read(&use_count, &buf);
+ }
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/res.h b/chromium/ui/gfx/x/generated_protos/res.h
new file mode 100644
index 00000000000..da92e06f3f4
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/res.h
@@ -0,0 +1,249 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_RES_H_
+#define UI_GFX_X_GENERATED_PROTOS_RES_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Res {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 2;
+
+ Res(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class ClientIdMask : int {
+ ClientXID = 1 << 0,
+ LocalClientPID = 1 << 1,
+ };
+
+ struct Client {
+ uint32_t resource_base{};
+ uint32_t resource_mask{};
+ };
+
+ struct Type {
+ Atom resource_type{};
+ uint32_t count{};
+ };
+
+ struct ClientIdSpec {
+ uint32_t client{};
+ ClientIdMask mask{};
+ };
+
+ struct ClientIdValue {
+ ClientIdSpec spec{};
+ uint32_t length{};
+ std::vector<uint32_t> value{};
+ };
+
+ struct ResourceIdSpec {
+ uint32_t resource{};
+ uint32_t type{};
+ };
+
+ struct ResourceSizeSpec {
+ ResourceIdSpec spec{};
+ uint32_t bytes{};
+ uint32_t ref_count{};
+ uint32_t use_count{};
+ };
+
+ struct ResourceSizeValue {
+ ResourceSizeSpec size{};
+ std::vector<ResourceSizeSpec> cross_references{};
+ };
+
+ struct QueryVersionRequest {
+ uint8_t client_major{};
+ uint8_t client_minor{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint16_t server_major{};
+ uint16_t server_minor{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(const uint8_t& client_major = {},
+ const uint8_t& client_minor = {});
+
+ struct QueryClientsRequest {};
+
+ struct QueryClientsReply {
+ uint16_t sequence{};
+ std::vector<Client> clients{};
+ };
+
+ using QueryClientsResponse = Response<QueryClientsReply>;
+
+ Future<QueryClientsReply> QueryClients(const QueryClientsRequest& request);
+
+ Future<QueryClientsReply> QueryClients();
+
+ struct QueryClientResourcesRequest {
+ uint32_t xid{};
+ };
+
+ struct QueryClientResourcesReply {
+ uint16_t sequence{};
+ std::vector<Type> types{};
+ };
+
+ using QueryClientResourcesResponse = Response<QueryClientResourcesReply>;
+
+ Future<QueryClientResourcesReply> QueryClientResources(
+ const QueryClientResourcesRequest& request);
+
+ Future<QueryClientResourcesReply> QueryClientResources(
+ const uint32_t& xid = {});
+
+ struct QueryClientPixmapBytesRequest {
+ uint32_t xid{};
+ };
+
+ struct QueryClientPixmapBytesReply {
+ uint16_t sequence{};
+ uint32_t bytes{};
+ uint32_t bytes_overflow{};
+ };
+
+ using QueryClientPixmapBytesResponse = Response<QueryClientPixmapBytesReply>;
+
+ Future<QueryClientPixmapBytesReply> QueryClientPixmapBytes(
+ const QueryClientPixmapBytesRequest& request);
+
+ Future<QueryClientPixmapBytesReply> QueryClientPixmapBytes(
+ const uint32_t& xid = {});
+
+ struct QueryClientIdsRequest {
+ std::vector<ClientIdSpec> specs{};
+ };
+
+ struct QueryClientIdsReply {
+ uint16_t sequence{};
+ std::vector<ClientIdValue> ids{};
+ };
+
+ using QueryClientIdsResponse = Response<QueryClientIdsReply>;
+
+ Future<QueryClientIdsReply> QueryClientIds(
+ const QueryClientIdsRequest& request);
+
+ Future<QueryClientIdsReply> QueryClientIds(
+ const std::vector<ClientIdSpec>& specs = {});
+
+ struct QueryResourceBytesRequest {
+ uint32_t client{};
+ std::vector<ResourceIdSpec> specs{};
+ };
+
+ struct QueryResourceBytesReply {
+ uint16_t sequence{};
+ std::vector<ResourceSizeValue> sizes{};
+ };
+
+ using QueryResourceBytesResponse = Response<QueryResourceBytesReply>;
+
+ Future<QueryResourceBytesReply> QueryResourceBytes(
+ const QueryResourceBytesRequest& request);
+
+ Future<QueryResourceBytesReply> QueryResourceBytes(
+ const uint32_t& client = {},
+ const std::vector<ResourceIdSpec>& specs = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Res::ClientIdMask operator|(x11::Res::ClientIdMask l,
+ x11::Res::ClientIdMask r) {
+ using T = std::underlying_type_t<x11::Res::ClientIdMask>;
+ return static_cast<x11::Res::ClientIdMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Res::ClientIdMask operator&(x11::Res::ClientIdMask l,
+ x11::Res::ClientIdMask r) {
+ using T = std::underlying_type_t<x11::Res::ClientIdMask>;
+ return static_cast<x11::Res::ClientIdMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_RES_H_
diff --git a/chromium/ui/gfx/x/generated_protos/screensaver.cc b/chromium/ui/gfx/x/generated_protos/screensaver.cc
new file mode 100644
index 00000000000..a02c1ef5d8b
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/screensaver.cc
@@ -0,0 +1,644 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "screensaver.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+ScreenSaver::ScreenSaver(Connection* connection,
+ const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<ScreenSaver::NotifyEvent>(ScreenSaver::NotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& state = (*event_).state;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& root = (*event_).root;
+ auto& window = (*event_).window;
+ auto& kind = (*event_).kind;
+ auto& forced = (*event_).forced;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // state
+ uint8_t tmp0;
+ Read(&tmp0, &buf);
+ state = static_cast<ScreenSaver::State>(tmp0);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // kind
+ uint8_t tmp1;
+ Read(&tmp1, &buf);
+ kind = static_cast<ScreenSaver::Kind>(tmp1);
+
+ // forced
+ Read(&forced, &buf);
+
+ // pad0
+ Pad(&buf, 14);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+Future<ScreenSaver::QueryVersionReply> ScreenSaver::QueryVersion(
+ const ScreenSaver::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client_major_version = request.client_major_version;
+ auto& client_minor_version = request.client_minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client_major_version
+ buf.Write(&client_major_version);
+
+ // client_minor_version
+ buf.Write(&client_minor_version);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<ScreenSaver::QueryVersionReply>(
+ &buf, "ScreenSaver::QueryVersion", false);
+}
+
+Future<ScreenSaver::QueryVersionReply> ScreenSaver::QueryVersion(
+ const uint8_t& client_major_version,
+ const uint8_t& client_minor_version) {
+ return ScreenSaver::QueryVersion(ScreenSaver::QueryVersionRequest{
+ client_major_version, client_minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<ScreenSaver::QueryVersionReply> detail::ReadReply<
+ ScreenSaver::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<ScreenSaver::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& server_major_version = (*reply).server_major_version;
+ auto& server_minor_version = (*reply).server_minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // server_major_version
+ Read(&server_major_version, &buf);
+
+ // server_minor_version
+ Read(&server_minor_version, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<ScreenSaver::QueryInfoReply> ScreenSaver::QueryInfo(
+ const ScreenSaver::QueryInfoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<ScreenSaver::QueryInfoReply>(
+ &buf, "ScreenSaver::QueryInfo", false);
+}
+
+Future<ScreenSaver::QueryInfoReply> ScreenSaver::QueryInfo(
+ const Drawable& drawable) {
+ return ScreenSaver::QueryInfo(ScreenSaver::QueryInfoRequest{drawable});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<ScreenSaver::QueryInfoReply> detail::ReadReply<
+ ScreenSaver::QueryInfoReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<ScreenSaver::QueryInfoReply>();
+
+ auto& state = (*reply).state;
+ auto& sequence = (*reply).sequence;
+ auto& saver_window = (*reply).saver_window;
+ auto& ms_until_server = (*reply).ms_until_server;
+ auto& ms_since_user_input = (*reply).ms_since_user_input;
+ auto& event_mask = (*reply).event_mask;
+ auto& kind = (*reply).kind;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // state
+ Read(&state, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // saver_window
+ Read(&saver_window, &buf);
+
+ // ms_until_server
+ Read(&ms_until_server, &buf);
+
+ // ms_since_user_input
+ Read(&ms_since_user_input, &buf);
+
+ // event_mask
+ Read(&event_mask, &buf);
+
+ // kind
+ uint8_t tmp2;
+ Read(&tmp2, &buf);
+ kind = static_cast<ScreenSaver::Kind>(tmp2);
+
+ // pad0
+ Pad(&buf, 7);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> ScreenSaver::SelectInput(
+ const ScreenSaver::SelectInputRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& event_mask = request.event_mask;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // event_mask
+ uint32_t tmp3;
+ tmp3 = static_cast<uint32_t>(event_mask);
+ buf.Write(&tmp3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ScreenSaver::SelectInput",
+ false);
+}
+
+Future<void> ScreenSaver::SelectInput(const Drawable& drawable,
+ const Event& event_mask) {
+ return ScreenSaver::SelectInput(
+ ScreenSaver::SelectInputRequest{drawable, event_mask});
+}
+
+Future<void> ScreenSaver::SetAttributes(
+ const ScreenSaver::SetAttributesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& x = request.x;
+ auto& y = request.y;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& border_width = request.border_width;
+ auto& c_class = request.c_class;
+ auto& depth = request.depth;
+ auto& visual = request.visual;
+ CreateWindowAttribute value_mask{};
+ auto& value_list = request;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // border_width
+ buf.Write(&border_width);
+
+ // c_class
+ uint8_t tmp4;
+ tmp4 = static_cast<uint8_t>(c_class);
+ buf.Write(&tmp4);
+
+ // depth
+ buf.Write(&depth);
+
+ // visual
+ buf.Write(&visual);
+
+ // value_mask
+ SwitchVar(CreateWindowAttribute::BackPixmap,
+ value_list.background_pixmap.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackPixel,
+ value_list.background_pixel.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BorderPixmap,
+ value_list.border_pixmap.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BorderPixel,
+ value_list.border_pixel.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BitGravity,
+ value_list.bit_gravity.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::WinGravity,
+ value_list.win_gravity.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackingStore,
+ value_list.backing_store.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackingPlanes,
+ value_list.backing_planes.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackingPixel,
+ value_list.backing_pixel.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::OverrideRedirect,
+ value_list.override_redirect.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::SaveUnder, value_list.save_under.has_value(),
+ true, &value_mask);
+ SwitchVar(CreateWindowAttribute::EventMask, value_list.event_mask.has_value(),
+ true, &value_mask);
+ SwitchVar(CreateWindowAttribute::DontPropagate,
+ value_list.do_not_propogate_mask.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::Colormap, value_list.colormap.has_value(),
+ true, &value_mask);
+ SwitchVar(CreateWindowAttribute::Cursor, value_list.cursor.has_value(), true,
+ &value_mask);
+ uint32_t tmp5;
+ tmp5 = static_cast<uint32_t>(value_mask);
+ buf.Write(&tmp5);
+
+ // value_list
+ auto value_list_expr = value_mask;
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackPixmap)) {
+ auto& background_pixmap = *value_list.background_pixmap;
+
+ // background_pixmap
+ buf.Write(&background_pixmap);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackPixel)) {
+ auto& background_pixel = *value_list.background_pixel;
+
+ // background_pixel
+ buf.Write(&background_pixel);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BorderPixmap)) {
+ auto& border_pixmap = *value_list.border_pixmap;
+
+ // border_pixmap
+ buf.Write(&border_pixmap);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BorderPixel)) {
+ auto& border_pixel = *value_list.border_pixel;
+
+ // border_pixel
+ buf.Write(&border_pixel);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BitGravity)) {
+ auto& bit_gravity = *value_list.bit_gravity;
+
+ // bit_gravity
+ uint32_t tmp6;
+ tmp6 = static_cast<uint32_t>(bit_gravity);
+ buf.Write(&tmp6);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::WinGravity)) {
+ auto& win_gravity = *value_list.win_gravity;
+
+ // win_gravity
+ uint32_t tmp7;
+ tmp7 = static_cast<uint32_t>(win_gravity);
+ buf.Write(&tmp7);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackingStore)) {
+ auto& backing_store = *value_list.backing_store;
+
+ // backing_store
+ uint32_t tmp8;
+ tmp8 = static_cast<uint32_t>(backing_store);
+ buf.Write(&tmp8);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackingPlanes)) {
+ auto& backing_planes = *value_list.backing_planes;
+
+ // backing_planes
+ buf.Write(&backing_planes);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackingPixel)) {
+ auto& backing_pixel = *value_list.backing_pixel;
+
+ // backing_pixel
+ buf.Write(&backing_pixel);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::OverrideRedirect)) {
+ auto& override_redirect = *value_list.override_redirect;
+
+ // override_redirect
+ buf.Write(&override_redirect);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::SaveUnder)) {
+ auto& save_under = *value_list.save_under;
+
+ // save_under
+ buf.Write(&save_under);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::EventMask)) {
+ auto& event_mask = *value_list.event_mask;
+
+ // event_mask
+ uint32_t tmp9;
+ tmp9 = static_cast<uint32_t>(event_mask);
+ buf.Write(&tmp9);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::DontPropagate)) {
+ auto& do_not_propogate_mask = *value_list.do_not_propogate_mask;
+
+ // do_not_propogate_mask
+ uint32_t tmp10;
+ tmp10 = static_cast<uint32_t>(do_not_propogate_mask);
+ buf.Write(&tmp10);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::Colormap)) {
+ auto& colormap = *value_list.colormap;
+
+ // colormap
+ buf.Write(&colormap);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::Cursor)) {
+ auto& cursor = *value_list.cursor;
+
+ // cursor
+ buf.Write(&cursor);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ScreenSaver::SetAttributes",
+ false);
+}
+
+Future<void> ScreenSaver::SetAttributes(
+ const Drawable& drawable,
+ const int16_t& x,
+ const int16_t& y,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint16_t& border_width,
+ const WindowClass& c_class,
+ const uint8_t& depth,
+ const VisualId& visual,
+ const base::Optional<Pixmap>& background_pixmap,
+ const base::Optional<uint32_t>& background_pixel,
+ const base::Optional<Pixmap>& border_pixmap,
+ const base::Optional<uint32_t>& border_pixel,
+ const base::Optional<Gravity>& bit_gravity,
+ const base::Optional<Gravity>& win_gravity,
+ const base::Optional<BackingStore>& backing_store,
+ const base::Optional<uint32_t>& backing_planes,
+ const base::Optional<uint32_t>& backing_pixel,
+ const base::Optional<Bool32>& override_redirect,
+ const base::Optional<Bool32>& save_under,
+ const base::Optional<EventMask>& event_mask,
+ const base::Optional<EventMask>& do_not_propogate_mask,
+ const base::Optional<ColorMap>& colormap,
+ const base::Optional<Cursor>& cursor) {
+ return ScreenSaver::SetAttributes(
+ ScreenSaver::SetAttributesRequest{drawable,
+ x,
+ y,
+ width,
+ height,
+ border_width,
+ c_class,
+ depth,
+ visual,
+ background_pixmap,
+ background_pixel,
+ border_pixmap,
+ border_pixel,
+ bit_gravity,
+ win_gravity,
+ backing_store,
+ backing_planes,
+ backing_pixel,
+ override_redirect,
+ save_under,
+ event_mask,
+ do_not_propogate_mask,
+ colormap,
+ cursor});
+}
+
+Future<void> ScreenSaver::UnsetAttributes(
+ const ScreenSaver::UnsetAttributesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ScreenSaver::UnsetAttributes",
+ false);
+}
+
+Future<void> ScreenSaver::UnsetAttributes(const Drawable& drawable) {
+ return ScreenSaver::UnsetAttributes(
+ ScreenSaver::UnsetAttributesRequest{drawable});
+}
+
+Future<void> ScreenSaver::Suspend(const ScreenSaver::SuspendRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& suspend = request.suspend;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // suspend
+ buf.Write(&suspend);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ScreenSaver::Suspend", false);
+}
+
+Future<void> ScreenSaver::Suspend(const uint32_t& suspend) {
+ return ScreenSaver::Suspend(ScreenSaver::SuspendRequest{suspend});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/screensaver.h b/chromium/ui/gfx/x/generated_protos/screensaver.h
new file mode 100644
index 00000000000..8c10111cf68
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/screensaver.h
@@ -0,0 +1,293 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_SCREENSAVER_H_
+#define UI_GFX_X_GENERATED_PROTOS_SCREENSAVER_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) ScreenSaver {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 1;
+
+ ScreenSaver(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Kind : int {
+ Blanked = 0,
+ Internal = 1,
+ External = 2,
+ };
+
+ enum class Event : int {
+ NotifyMask = 1 << 0,
+ CycleMask = 1 << 1,
+ };
+
+ enum class State : int {
+ Off = 0,
+ On = 1,
+ Cycle = 2,
+ Disabled = 3,
+ };
+
+ struct NotifyEvent {
+ static constexpr int type_id = 13;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ State state{};
+ uint16_t sequence{};
+ Time time{};
+ Window root{};
+ Window window{};
+ Kind kind{};
+ uint8_t forced{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+ };
+
+ struct QueryVersionRequest {
+ uint8_t client_major_version{};
+ uint8_t client_minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint16_t server_major_version{};
+ uint16_t server_minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(
+ const uint8_t& client_major_version = {},
+ const uint8_t& client_minor_version = {});
+
+ struct QueryInfoRequest {
+ Drawable drawable{};
+ };
+
+ struct QueryInfoReply {
+ uint8_t state{};
+ uint16_t sequence{};
+ Window saver_window{};
+ uint32_t ms_until_server{};
+ uint32_t ms_since_user_input{};
+ uint32_t event_mask{};
+ Kind kind{};
+ };
+
+ using QueryInfoResponse = Response<QueryInfoReply>;
+
+ Future<QueryInfoReply> QueryInfo(const QueryInfoRequest& request);
+
+ Future<QueryInfoReply> QueryInfo(const Drawable& drawable = {});
+
+ struct SelectInputRequest {
+ Drawable drawable{};
+ Event event_mask{};
+ };
+
+ using SelectInputResponse = Response<void>;
+
+ Future<void> SelectInput(const SelectInputRequest& request);
+
+ Future<void> SelectInput(const Drawable& drawable = {},
+ const Event& event_mask = {});
+
+ struct SetAttributesRequest {
+ Drawable drawable{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t border_width{};
+ WindowClass c_class{};
+ uint8_t depth{};
+ VisualId visual{};
+ base::Optional<Pixmap> background_pixmap{};
+ base::Optional<uint32_t> background_pixel{};
+ base::Optional<Pixmap> border_pixmap{};
+ base::Optional<uint32_t> border_pixel{};
+ base::Optional<Gravity> bit_gravity{};
+ base::Optional<Gravity> win_gravity{};
+ base::Optional<BackingStore> backing_store{};
+ base::Optional<uint32_t> backing_planes{};
+ base::Optional<uint32_t> backing_pixel{};
+ base::Optional<Bool32> override_redirect{};
+ base::Optional<Bool32> save_under{};
+ base::Optional<EventMask> event_mask{};
+ base::Optional<EventMask> do_not_propogate_mask{};
+ base::Optional<ColorMap> colormap{};
+ base::Optional<Cursor> cursor{};
+ };
+
+ using SetAttributesResponse = Response<void>;
+
+ Future<void> SetAttributes(const SetAttributesRequest& request);
+
+ Future<void> SetAttributes(
+ const Drawable& drawable = {},
+ const int16_t& x = {},
+ const int16_t& y = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint16_t& border_width = {},
+ const WindowClass& c_class = {},
+ const uint8_t& depth = {},
+ const VisualId& visual = {},
+ const base::Optional<Pixmap>& background_pixmap = base::nullopt,
+ const base::Optional<uint32_t>& background_pixel = base::nullopt,
+ const base::Optional<Pixmap>& border_pixmap = base::nullopt,
+ const base::Optional<uint32_t>& border_pixel = base::nullopt,
+ const base::Optional<Gravity>& bit_gravity = base::nullopt,
+ const base::Optional<Gravity>& win_gravity = base::nullopt,
+ const base::Optional<BackingStore>& backing_store = base::nullopt,
+ const base::Optional<uint32_t>& backing_planes = base::nullopt,
+ const base::Optional<uint32_t>& backing_pixel = base::nullopt,
+ const base::Optional<Bool32>& override_redirect = base::nullopt,
+ const base::Optional<Bool32>& save_under = base::nullopt,
+ const base::Optional<EventMask>& event_mask = base::nullopt,
+ const base::Optional<EventMask>& do_not_propogate_mask = base::nullopt,
+ const base::Optional<ColorMap>& colormap = base::nullopt,
+ const base::Optional<Cursor>& cursor = base::nullopt);
+
+ struct UnsetAttributesRequest {
+ Drawable drawable{};
+ };
+
+ using UnsetAttributesResponse = Response<void>;
+
+ Future<void> UnsetAttributes(const UnsetAttributesRequest& request);
+
+ Future<void> UnsetAttributes(const Drawable& drawable = {});
+
+ struct SuspendRequest {
+ uint32_t suspend{};
+ };
+
+ using SuspendResponse = Response<void>;
+
+ Future<void> Suspend(const SuspendRequest& request);
+
+ Future<void> Suspend(const uint32_t& suspend = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::ScreenSaver::Kind operator|(x11::ScreenSaver::Kind l,
+ x11::ScreenSaver::Kind r) {
+ using T = std::underlying_type_t<x11::ScreenSaver::Kind>;
+ return static_cast<x11::ScreenSaver::Kind>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::ScreenSaver::Kind operator&(x11::ScreenSaver::Kind l,
+ x11::ScreenSaver::Kind r) {
+ using T = std::underlying_type_t<x11::ScreenSaver::Kind>;
+ return static_cast<x11::ScreenSaver::Kind>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::ScreenSaver::Event operator|(x11::ScreenSaver::Event l,
+ x11::ScreenSaver::Event r) {
+ using T = std::underlying_type_t<x11::ScreenSaver::Event>;
+ return static_cast<x11::ScreenSaver::Event>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::ScreenSaver::Event operator&(x11::ScreenSaver::Event l,
+ x11::ScreenSaver::Event r) {
+ using T = std::underlying_type_t<x11::ScreenSaver::Event>;
+ return static_cast<x11::ScreenSaver::Event>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::ScreenSaver::State operator|(x11::ScreenSaver::State l,
+ x11::ScreenSaver::State r) {
+ using T = std::underlying_type_t<x11::ScreenSaver::State>;
+ return static_cast<x11::ScreenSaver::State>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::ScreenSaver::State operator&(x11::ScreenSaver::State l,
+ x11::ScreenSaver::State r) {
+ using T = std::underlying_type_t<x11::ScreenSaver::State>;
+ return static_cast<x11::ScreenSaver::State>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_SCREENSAVER_H_
diff --git a/chromium/ui/gfx/x/generated_protos/shape.cc b/chromium/ui/gfx/x/generated_protos/shape.cc
new file mode 100644
index 00000000000..946080af03d
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/shape.cc
@@ -0,0 +1,784 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "shape.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Shape::Shape(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Shape::NotifyEvent>(Shape::NotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& shape_kind = (*event_).shape_kind;
+ auto& sequence = (*event_).sequence;
+ auto& affected_window = (*event_).affected_window;
+ auto& extents_x = (*event_).extents_x;
+ auto& extents_y = (*event_).extents_y;
+ auto& extents_width = (*event_).extents_width;
+ auto& extents_height = (*event_).extents_height;
+ auto& server_time = (*event_).server_time;
+ auto& shaped = (*event_).shaped;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // shape_kind
+ uint8_t tmp0;
+ Read(&tmp0, &buf);
+ shape_kind = static_cast<Shape::Sk>(tmp0);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // affected_window
+ Read(&affected_window, &buf);
+
+ // extents_x
+ Read(&extents_x, &buf);
+
+ // extents_y
+ Read(&extents_y, &buf);
+
+ // extents_width
+ Read(&extents_width, &buf);
+
+ // extents_height
+ Read(&extents_height, &buf);
+
+ // server_time
+ Read(&server_time, &buf);
+
+ // shaped
+ Read(&shaped, &buf);
+
+ // pad0
+ Pad(&buf, 11);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+Future<Shape::QueryVersionReply> Shape::QueryVersion(
+ const Shape::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Shape::QueryVersionReply>(
+ &buf, "Shape::QueryVersion", false);
+}
+
+Future<Shape::QueryVersionReply> Shape::QueryVersion() {
+ return Shape::QueryVersion(Shape::QueryVersionRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Shape::QueryVersionReply> detail::ReadReply<
+ Shape::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Shape::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Shape::Rectangles(const Shape::RectanglesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& operation = request.operation;
+ auto& destination_kind = request.destination_kind;
+ auto& ordering = request.ordering;
+ auto& destination_window = request.destination_window;
+ auto& x_offset = request.x_offset;
+ auto& y_offset = request.y_offset;
+ auto& rectangles = request.rectangles;
+ size_t rectangles_len = rectangles.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // operation
+ uint8_t tmp1;
+ tmp1 = static_cast<uint8_t>(operation);
+ buf.Write(&tmp1);
+
+ // destination_kind
+ uint8_t tmp2;
+ tmp2 = static_cast<uint8_t>(destination_kind);
+ buf.Write(&tmp2);
+
+ // ordering
+ uint8_t tmp3;
+ tmp3 = static_cast<uint8_t>(ordering);
+ buf.Write(&tmp3);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // destination_window
+ buf.Write(&destination_window);
+
+ // x_offset
+ buf.Write(&x_offset);
+
+ // y_offset
+ buf.Write(&y_offset);
+
+ // rectangles
+ DCHECK_EQ(static_cast<size_t>(rectangles_len), rectangles.size());
+ for (auto& rectangles_elem : rectangles) {
+ // rectangles_elem
+ {
+ auto& x = rectangles_elem.x;
+ auto& y = rectangles_elem.y;
+ auto& width = rectangles_elem.width;
+ auto& height = rectangles_elem.height;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Shape::Rectangles", false);
+}
+
+Future<void> Shape::Rectangles(const So& operation,
+ const Sk& destination_kind,
+ const ClipOrdering& ordering,
+ const Window& destination_window,
+ const int16_t& x_offset,
+ const int16_t& y_offset,
+ const std::vector<Rectangle>& rectangles) {
+ return Shape::Rectangles(Shape::RectanglesRequest{
+ operation, destination_kind, ordering, destination_window, x_offset,
+ y_offset, rectangles});
+}
+
+Future<void> Shape::Mask(const Shape::MaskRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& operation = request.operation;
+ auto& destination_kind = request.destination_kind;
+ auto& destination_window = request.destination_window;
+ auto& x_offset = request.x_offset;
+ auto& y_offset = request.y_offset;
+ auto& source_bitmap = request.source_bitmap;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // operation
+ uint8_t tmp4;
+ tmp4 = static_cast<uint8_t>(operation);
+ buf.Write(&tmp4);
+
+ // destination_kind
+ uint8_t tmp5;
+ tmp5 = static_cast<uint8_t>(destination_kind);
+ buf.Write(&tmp5);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // destination_window
+ buf.Write(&destination_window);
+
+ // x_offset
+ buf.Write(&x_offset);
+
+ // y_offset
+ buf.Write(&y_offset);
+
+ // source_bitmap
+ buf.Write(&source_bitmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Shape::Mask", false);
+}
+
+Future<void> Shape::Mask(const So& operation,
+ const Sk& destination_kind,
+ const Window& destination_window,
+ const int16_t& x_offset,
+ const int16_t& y_offset,
+ const Pixmap& source_bitmap) {
+ return Shape::Mask(Shape::MaskRequest{operation, destination_kind,
+ destination_window, x_offset, y_offset,
+ source_bitmap});
+}
+
+Future<void> Shape::Combine(const Shape::CombineRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& operation = request.operation;
+ auto& destination_kind = request.destination_kind;
+ auto& source_kind = request.source_kind;
+ auto& destination_window = request.destination_window;
+ auto& x_offset = request.x_offset;
+ auto& y_offset = request.y_offset;
+ auto& source_window = request.source_window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // operation
+ uint8_t tmp6;
+ tmp6 = static_cast<uint8_t>(operation);
+ buf.Write(&tmp6);
+
+ // destination_kind
+ uint8_t tmp7;
+ tmp7 = static_cast<uint8_t>(destination_kind);
+ buf.Write(&tmp7);
+
+ // source_kind
+ uint8_t tmp8;
+ tmp8 = static_cast<uint8_t>(source_kind);
+ buf.Write(&tmp8);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // destination_window
+ buf.Write(&destination_window);
+
+ // x_offset
+ buf.Write(&x_offset);
+
+ // y_offset
+ buf.Write(&y_offset);
+
+ // source_window
+ buf.Write(&source_window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Shape::Combine", false);
+}
+
+Future<void> Shape::Combine(const So& operation,
+ const Sk& destination_kind,
+ const Sk& source_kind,
+ const Window& destination_window,
+ const int16_t& x_offset,
+ const int16_t& y_offset,
+ const Window& source_window) {
+ return Shape::Combine(Shape::CombineRequest{
+ operation, destination_kind, source_kind, destination_window, x_offset,
+ y_offset, source_window});
+}
+
+Future<void> Shape::Offset(const Shape::OffsetRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& destination_kind = request.destination_kind;
+ auto& destination_window = request.destination_window;
+ auto& x_offset = request.x_offset;
+ auto& y_offset = request.y_offset;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // destination_kind
+ uint8_t tmp9;
+ tmp9 = static_cast<uint8_t>(destination_kind);
+ buf.Write(&tmp9);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // destination_window
+ buf.Write(&destination_window);
+
+ // x_offset
+ buf.Write(&x_offset);
+
+ // y_offset
+ buf.Write(&y_offset);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Shape::Offset", false);
+}
+
+Future<void> Shape::Offset(const Sk& destination_kind,
+ const Window& destination_window,
+ const int16_t& x_offset,
+ const int16_t& y_offset) {
+ return Shape::Offset(Shape::OffsetRequest{
+ destination_kind, destination_window, x_offset, y_offset});
+}
+
+Future<Shape::QueryExtentsReply> Shape::QueryExtents(
+ const Shape::QueryExtentsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& destination_window = request.destination_window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // destination_window
+ buf.Write(&destination_window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Shape::QueryExtentsReply>(
+ &buf, "Shape::QueryExtents", false);
+}
+
+Future<Shape::QueryExtentsReply> Shape::QueryExtents(
+ const Window& destination_window) {
+ return Shape::QueryExtents(Shape::QueryExtentsRequest{destination_window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Shape::QueryExtentsReply> detail::ReadReply<
+ Shape::QueryExtentsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Shape::QueryExtentsReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& bounding_shaped = (*reply).bounding_shaped;
+ auto& clip_shaped = (*reply).clip_shaped;
+ auto& bounding_shape_extents_x = (*reply).bounding_shape_extents_x;
+ auto& bounding_shape_extents_y = (*reply).bounding_shape_extents_y;
+ auto& bounding_shape_extents_width = (*reply).bounding_shape_extents_width;
+ auto& bounding_shape_extents_height = (*reply).bounding_shape_extents_height;
+ auto& clip_shape_extents_x = (*reply).clip_shape_extents_x;
+ auto& clip_shape_extents_y = (*reply).clip_shape_extents_y;
+ auto& clip_shape_extents_width = (*reply).clip_shape_extents_width;
+ auto& clip_shape_extents_height = (*reply).clip_shape_extents_height;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // bounding_shaped
+ Read(&bounding_shaped, &buf);
+
+ // clip_shaped
+ Read(&clip_shaped, &buf);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // bounding_shape_extents_x
+ Read(&bounding_shape_extents_x, &buf);
+
+ // bounding_shape_extents_y
+ Read(&bounding_shape_extents_y, &buf);
+
+ // bounding_shape_extents_width
+ Read(&bounding_shape_extents_width, &buf);
+
+ // bounding_shape_extents_height
+ Read(&bounding_shape_extents_height, &buf);
+
+ // clip_shape_extents_x
+ Read(&clip_shape_extents_x, &buf);
+
+ // clip_shape_extents_y
+ Read(&clip_shape_extents_y, &buf);
+
+ // clip_shape_extents_width
+ Read(&clip_shape_extents_width, &buf);
+
+ // clip_shape_extents_height
+ Read(&clip_shape_extents_height, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Shape::SelectInput(const Shape::SelectInputRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& destination_window = request.destination_window;
+ auto& enable = request.enable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // destination_window
+ buf.Write(&destination_window);
+
+ // enable
+ buf.Write(&enable);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Shape::SelectInput", false);
+}
+
+Future<void> Shape::SelectInput(const Window& destination_window,
+ const uint8_t& enable) {
+ return Shape::SelectInput(
+ Shape::SelectInputRequest{destination_window, enable});
+}
+
+Future<Shape::InputSelectedReply> Shape::InputSelected(
+ const Shape::InputSelectedRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& destination_window = request.destination_window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // destination_window
+ buf.Write(&destination_window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Shape::InputSelectedReply>(
+ &buf, "Shape::InputSelected", false);
+}
+
+Future<Shape::InputSelectedReply> Shape::InputSelected(
+ const Window& destination_window) {
+ return Shape::InputSelected(Shape::InputSelectedRequest{destination_window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Shape::InputSelectedReply> detail::ReadReply<
+ Shape::InputSelectedReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Shape::InputSelectedReply>();
+
+ auto& enabled = (*reply).enabled;
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // enabled
+ Read(&enabled, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Shape::GetRectanglesReply> Shape::GetRectangles(
+ const Shape::GetRectanglesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& source_kind = request.source_kind;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // source_kind
+ uint8_t tmp10;
+ tmp10 = static_cast<uint8_t>(source_kind);
+ buf.Write(&tmp10);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Shape::GetRectanglesReply>(
+ &buf, "Shape::GetRectangles", false);
+}
+
+Future<Shape::GetRectanglesReply> Shape::GetRectangles(const Window& window,
+ const Sk& source_kind) {
+ return Shape::GetRectangles(Shape::GetRectanglesRequest{window, source_kind});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Shape::GetRectanglesReply> detail::ReadReply<
+ Shape::GetRectanglesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Shape::GetRectanglesReply>();
+
+ auto& ordering = (*reply).ordering;
+ auto& sequence = (*reply).sequence;
+ uint32_t rectangles_len{};
+ auto& rectangles = (*reply).rectangles;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // ordering
+ uint8_t tmp11;
+ Read(&tmp11, &buf);
+ ordering = static_cast<ClipOrdering>(tmp11);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // rectangles_len
+ Read(&rectangles_len, &buf);
+
+ // pad0
+ Pad(&buf, 20);
+
+ // rectangles
+ rectangles.resize(rectangles_len);
+ for (auto& rectangles_elem : rectangles) {
+ // rectangles_elem
+ {
+ auto& x = rectangles_elem.x;
+ auto& y = rectangles_elem.y;
+ auto& width = rectangles_elem.width;
+ auto& height = rectangles_elem.height;
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/shape.h b/chromium/ui/gfx/x/generated_protos/shape.h
new file mode 100644
index 00000000000..33c64b6296e
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/shape.h
@@ -0,0 +1,311 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_SHAPE_H_
+#define UI_GFX_X_GENERATED_PROTOS_SHAPE_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Shape {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 1;
+
+ Shape(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Operation : uint8_t {};
+
+ enum class Kind : uint8_t {};
+
+ enum class So : int {
+ Set = 0,
+ Union = 1,
+ Intersect = 2,
+ Subtract = 3,
+ Invert = 4,
+ };
+
+ enum class Sk : int {
+ Bounding = 0,
+ Clip = 1,
+ Input = 2,
+ };
+
+ struct NotifyEvent {
+ static constexpr int type_id = 14;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ Sk shape_kind{};
+ uint16_t sequence{};
+ Window affected_window{};
+ int16_t extents_x{};
+ int16_t extents_y{};
+ uint16_t extents_width{};
+ uint16_t extents_height{};
+ Time server_time{};
+ uint8_t shaped{};
+
+ x11::Window* GetWindow() {
+ return reinterpret_cast<x11::Window*>(&affected_window);
+ }
+ };
+
+ struct QueryVersionRequest {};
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint16_t major_version{};
+ uint16_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion();
+
+ struct RectanglesRequest {
+ So operation{};
+ Sk destination_kind{};
+ ClipOrdering ordering{};
+ Window destination_window{};
+ int16_t x_offset{};
+ int16_t y_offset{};
+ std::vector<Rectangle> rectangles{};
+ };
+
+ using RectanglesResponse = Response<void>;
+
+ Future<void> Rectangles(const RectanglesRequest& request);
+
+ Future<void> Rectangles(const So& operation = {},
+ const Sk& destination_kind = {},
+ const ClipOrdering& ordering = {},
+ const Window& destination_window = {},
+ const int16_t& x_offset = {},
+ const int16_t& y_offset = {},
+ const std::vector<Rectangle>& rectangles = {});
+
+ struct MaskRequest {
+ So operation{};
+ Sk destination_kind{};
+ Window destination_window{};
+ int16_t x_offset{};
+ int16_t y_offset{};
+ Pixmap source_bitmap{};
+ };
+
+ using MaskResponse = Response<void>;
+
+ Future<void> Mask(const MaskRequest& request);
+
+ Future<void> Mask(const So& operation = {},
+ const Sk& destination_kind = {},
+ const Window& destination_window = {},
+ const int16_t& x_offset = {},
+ const int16_t& y_offset = {},
+ const Pixmap& source_bitmap = {});
+
+ struct CombineRequest {
+ So operation{};
+ Sk destination_kind{};
+ Sk source_kind{};
+ Window destination_window{};
+ int16_t x_offset{};
+ int16_t y_offset{};
+ Window source_window{};
+ };
+
+ using CombineResponse = Response<void>;
+
+ Future<void> Combine(const CombineRequest& request);
+
+ Future<void> Combine(const So& operation = {},
+ const Sk& destination_kind = {},
+ const Sk& source_kind = {},
+ const Window& destination_window = {},
+ const int16_t& x_offset = {},
+ const int16_t& y_offset = {},
+ const Window& source_window = {});
+
+ struct OffsetRequest {
+ Sk destination_kind{};
+ Window destination_window{};
+ int16_t x_offset{};
+ int16_t y_offset{};
+ };
+
+ using OffsetResponse = Response<void>;
+
+ Future<void> Offset(const OffsetRequest& request);
+
+ Future<void> Offset(const Sk& destination_kind = {},
+ const Window& destination_window = {},
+ const int16_t& x_offset = {},
+ const int16_t& y_offset = {});
+
+ struct QueryExtentsRequest {
+ Window destination_window{};
+ };
+
+ struct QueryExtentsReply {
+ uint16_t sequence{};
+ uint8_t bounding_shaped{};
+ uint8_t clip_shaped{};
+ int16_t bounding_shape_extents_x{};
+ int16_t bounding_shape_extents_y{};
+ uint16_t bounding_shape_extents_width{};
+ uint16_t bounding_shape_extents_height{};
+ int16_t clip_shape_extents_x{};
+ int16_t clip_shape_extents_y{};
+ uint16_t clip_shape_extents_width{};
+ uint16_t clip_shape_extents_height{};
+ };
+
+ using QueryExtentsResponse = Response<QueryExtentsReply>;
+
+ Future<QueryExtentsReply> QueryExtents(const QueryExtentsRequest& request);
+
+ Future<QueryExtentsReply> QueryExtents(const Window& destination_window = {});
+
+ struct SelectInputRequest {
+ Window destination_window{};
+ uint8_t enable{};
+ };
+
+ using SelectInputResponse = Response<void>;
+
+ Future<void> SelectInput(const SelectInputRequest& request);
+
+ Future<void> SelectInput(const Window& destination_window = {},
+ const uint8_t& enable = {});
+
+ struct InputSelectedRequest {
+ Window destination_window{};
+ };
+
+ struct InputSelectedReply {
+ uint8_t enabled{};
+ uint16_t sequence{};
+ };
+
+ using InputSelectedResponse = Response<InputSelectedReply>;
+
+ Future<InputSelectedReply> InputSelected(const InputSelectedRequest& request);
+
+ Future<InputSelectedReply> InputSelected(
+ const Window& destination_window = {});
+
+ struct GetRectanglesRequest {
+ Window window{};
+ Sk source_kind{};
+ };
+
+ struct GetRectanglesReply {
+ ClipOrdering ordering{};
+ uint16_t sequence{};
+ std::vector<Rectangle> rectangles{};
+ };
+
+ using GetRectanglesResponse = Response<GetRectanglesReply>;
+
+ Future<GetRectanglesReply> GetRectangles(const GetRectanglesRequest& request);
+
+ Future<GetRectanglesReply> GetRectangles(const Window& window = {},
+ const Sk& source_kind = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Shape::So operator|(x11::Shape::So l, x11::Shape::So r) {
+ using T = std::underlying_type_t<x11::Shape::So>;
+ return static_cast<x11::Shape::So>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Shape::So operator&(x11::Shape::So l, x11::Shape::So r) {
+ using T = std::underlying_type_t<x11::Shape::So>;
+ return static_cast<x11::Shape::So>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Shape::Sk operator|(x11::Shape::Sk l, x11::Shape::Sk r) {
+ using T = std::underlying_type_t<x11::Shape::Sk>;
+ return static_cast<x11::Shape::Sk>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Shape::Sk operator&(x11::Shape::Sk l, x11::Shape::Sk r) {
+ using T = std::underlying_type_t<x11::Shape::Sk>;
+ return static_cast<x11::Shape::Sk>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_SHAPE_H_
diff --git a/chromium/ui/gfx/x/generated_protos/shm.cc b/chromium/ui/gfx/x/generated_protos/shm.cc
new file mode 100644
index 00000000000..fc795c661da
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/shm.cc
@@ -0,0 +1,722 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "shm.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Shm::Shm(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Shm::CompletionEvent>(Shm::CompletionEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& drawable = (*event_).drawable;
+ auto& minor_event = (*event_).minor_event;
+ auto& major_event = (*event_).major_event;
+ auto& shmseg = (*event_).shmseg;
+ auto& offset = (*event_).offset;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // drawable
+ Read(&drawable, &buf);
+
+ // minor_event
+ Read(&minor_event, &buf);
+
+ // major_event
+ Read(&major_event, &buf);
+
+ // pad1
+ Pad(&buf, 1);
+
+ // shmseg
+ Read(&shmseg, &buf);
+
+ // offset
+ Read(&offset, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+std::string Shm::BadSegError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Shm::BadSegError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Shm::BadSegError>(Shm::BadSegError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+Future<Shm::QueryVersionReply> Shm::QueryVersion(
+ const Shm::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Shm::QueryVersionReply>(
+ &buf, "Shm::QueryVersion", false);
+}
+
+Future<Shm::QueryVersionReply> Shm::QueryVersion() {
+ return Shm::QueryVersion(Shm::QueryVersionRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Shm::QueryVersionReply> detail::ReadReply<
+ Shm::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Shm::QueryVersionReply>();
+
+ auto& shared_pixmaps = (*reply).shared_pixmaps;
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+ auto& uid = (*reply).uid;
+ auto& gid = (*reply).gid;
+ auto& pixmap_format = (*reply).pixmap_format;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // shared_pixmaps
+ Read(&shared_pixmaps, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ // uid
+ Read(&uid, &buf);
+
+ // gid
+ Read(&gid, &buf);
+
+ // pixmap_format
+ Read(&pixmap_format, &buf);
+
+ // pad0
+ Pad(&buf, 15);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Shm::Attach(const Shm::AttachRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& shmseg = request.shmseg;
+ auto& shmid = request.shmid;
+ auto& read_only = request.read_only;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // shmseg
+ buf.Write(&shmseg);
+
+ // shmid
+ buf.Write(&shmid);
+
+ // read_only
+ buf.Write(&read_only);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Shm::Attach", false);
+}
+
+Future<void> Shm::Attach(const Seg& shmseg,
+ const uint32_t& shmid,
+ const uint8_t& read_only) {
+ return Shm::Attach(Shm::AttachRequest{shmseg, shmid, read_only});
+}
+
+Future<void> Shm::Detach(const Shm::DetachRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& shmseg = request.shmseg;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // shmseg
+ buf.Write(&shmseg);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Shm::Detach", false);
+}
+
+Future<void> Shm::Detach(const Seg& shmseg) {
+ return Shm::Detach(Shm::DetachRequest{shmseg});
+}
+
+Future<void> Shm::PutImage(const Shm::PutImageRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& total_width = request.total_width;
+ auto& total_height = request.total_height;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& src_width = request.src_width;
+ auto& src_height = request.src_height;
+ auto& dst_x = request.dst_x;
+ auto& dst_y = request.dst_y;
+ auto& depth = request.depth;
+ auto& format = request.format;
+ auto& send_event = request.send_event;
+ auto& shmseg = request.shmseg;
+ auto& offset = request.offset;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // total_width
+ buf.Write(&total_width);
+
+ // total_height
+ buf.Write(&total_height);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // src_width
+ buf.Write(&src_width);
+
+ // src_height
+ buf.Write(&src_height);
+
+ // dst_x
+ buf.Write(&dst_x);
+
+ // dst_y
+ buf.Write(&dst_y);
+
+ // depth
+ buf.Write(&depth);
+
+ // format
+ uint8_t tmp0;
+ tmp0 = static_cast<uint8_t>(format);
+ buf.Write(&tmp0);
+
+ // send_event
+ buf.Write(&send_event);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // shmseg
+ buf.Write(&shmseg);
+
+ // offset
+ buf.Write(&offset);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Shm::PutImage", false);
+}
+
+Future<void> Shm::PutImage(const Drawable& drawable,
+ const GraphicsContext& gc,
+ const uint16_t& total_width,
+ const uint16_t& total_height,
+ const uint16_t& src_x,
+ const uint16_t& src_y,
+ const uint16_t& src_width,
+ const uint16_t& src_height,
+ const int16_t& dst_x,
+ const int16_t& dst_y,
+ const uint8_t& depth,
+ const ImageFormat& format,
+ const uint8_t& send_event,
+ const Seg& shmseg,
+ const uint32_t& offset) {
+ return Shm::PutImage(Shm::PutImageRequest{
+ drawable, gc, total_width, total_height, src_x, src_y, src_width,
+ src_height, dst_x, dst_y, depth, format, send_event, shmseg, offset});
+}
+
+Future<Shm::GetImageReply> Shm::GetImage(const Shm::GetImageRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& x = request.x;
+ auto& y = request.y;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& plane_mask = request.plane_mask;
+ auto& format = request.format;
+ auto& shmseg = request.shmseg;
+ auto& offset = request.offset;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // plane_mask
+ buf.Write(&plane_mask);
+
+ // format
+ buf.Write(&format);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // shmseg
+ buf.Write(&shmseg);
+
+ // offset
+ buf.Write(&offset);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Shm::GetImageReply>(&buf, "Shm::GetImage",
+ false);
+}
+
+Future<Shm::GetImageReply> Shm::GetImage(const Drawable& drawable,
+ const int16_t& x,
+ const int16_t& y,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint32_t& plane_mask,
+ const uint8_t& format,
+ const Seg& shmseg,
+ const uint32_t& offset) {
+ return Shm::GetImage(Shm::GetImageRequest{
+ drawable, x, y, width, height, plane_mask, format, shmseg, offset});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Shm::GetImageReply> detail::ReadReply<Shm::GetImageReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Shm::GetImageReply>();
+
+ auto& depth = (*reply).depth;
+ auto& sequence = (*reply).sequence;
+ auto& visual = (*reply).visual;
+ auto& size = (*reply).size;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // depth
+ Read(&depth, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // visual
+ Read(&visual, &buf);
+
+ // size
+ Read(&size, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Shm::CreatePixmap(const Shm::CreatePixmapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& pid = request.pid;
+ auto& drawable = request.drawable;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& depth = request.depth;
+ auto& shmseg = request.shmseg;
+ auto& offset = request.offset;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // pid
+ buf.Write(&pid);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // depth
+ buf.Write(&depth);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // shmseg
+ buf.Write(&shmseg);
+
+ // offset
+ buf.Write(&offset);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Shm::CreatePixmap", false);
+}
+
+Future<void> Shm::CreatePixmap(const Pixmap& pid,
+ const Drawable& drawable,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint8_t& depth,
+ const Seg& shmseg,
+ const uint32_t& offset) {
+ return Shm::CreatePixmap(Shm::CreatePixmapRequest{
+ pid, drawable, width, height, depth, shmseg, offset});
+}
+
+Future<void> Shm::AttachFd(const Shm::AttachFdRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& shmseg = request.shmseg;
+ auto& shm_fd = request.shm_fd;
+ auto& read_only = request.read_only;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // shmseg
+ buf.Write(&shmseg);
+
+ // shm_fd
+ buf.fds().push_back(HANDLE_EINTR(dup(shm_fd.get())));
+
+ // read_only
+ buf.Write(&read_only);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Shm::AttachFd", false);
+}
+
+Future<void> Shm::AttachFd(const Seg& shmseg,
+ const RefCountedFD& shm_fd,
+ const uint8_t& read_only) {
+ return Shm::AttachFd(Shm::AttachFdRequest{shmseg, shm_fd, read_only});
+}
+
+Future<Shm::CreateSegmentReply> Shm::CreateSegment(
+ const Shm::CreateSegmentRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& shmseg = request.shmseg;
+ auto& size = request.size;
+ auto& read_only = request.read_only;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // shmseg
+ buf.Write(&shmseg);
+
+ // size
+ buf.Write(&size);
+
+ // read_only
+ buf.Write(&read_only);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Shm::CreateSegmentReply>(
+ &buf, "Shm::CreateSegment", true);
+}
+
+Future<Shm::CreateSegmentReply> Shm::CreateSegment(const Seg& shmseg,
+ const uint32_t& size,
+ const uint8_t& read_only) {
+ return Shm::CreateSegment(Shm::CreateSegmentRequest{shmseg, size, read_only});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Shm::CreateSegmentReply> detail::ReadReply<
+ Shm::CreateSegmentReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Shm::CreateSegmentReply>();
+
+ auto& nfd = (*reply).nfd;
+ auto& sequence = (*reply).sequence;
+ auto& shm_fd = (*reply).shm_fd;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // nfd
+ Read(&nfd, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // shm_fd
+ shm_fd = RefCountedFD(buf.TakeFd());
+
+ // pad0
+ Pad(&buf, 24);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/shm.h b/chromium/ui/gfx/x/generated_protos/shm.h
new file mode 100644
index 00000000000..7766811169b
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/shm.h
@@ -0,0 +1,286 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_SHM_H_
+#define UI_GFX_X_GENERATED_PROTOS_SHM_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Shm {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 2;
+
+ Shm(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Seg : uint32_t {};
+
+ struct CompletionEvent {
+ static constexpr int type_id = 15;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ uint16_t sequence{};
+ Drawable drawable{};
+ uint16_t minor_event{};
+ uint8_t major_event{};
+ Seg shmseg{};
+ uint32_t offset{};
+
+ x11::Window* GetWindow() {
+ return reinterpret_cast<x11::Window*>(&drawable);
+ }
+ };
+
+ struct BadSegError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct QueryVersionRequest {};
+
+ struct QueryVersionReply {
+ uint8_t shared_pixmaps{};
+ uint16_t sequence{};
+ uint16_t major_version{};
+ uint16_t minor_version{};
+ uint16_t uid{};
+ uint16_t gid{};
+ uint8_t pixmap_format{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion();
+
+ struct AttachRequest {
+ Seg shmseg{};
+ uint32_t shmid{};
+ uint8_t read_only{};
+ };
+
+ using AttachResponse = Response<void>;
+
+ Future<void> Attach(const AttachRequest& request);
+
+ Future<void> Attach(const Seg& shmseg = {},
+ const uint32_t& shmid = {},
+ const uint8_t& read_only = {});
+
+ struct DetachRequest {
+ Seg shmseg{};
+ };
+
+ using DetachResponse = Response<void>;
+
+ Future<void> Detach(const DetachRequest& request);
+
+ Future<void> Detach(const Seg& shmseg = {});
+
+ struct PutImageRequest {
+ Drawable drawable{};
+ GraphicsContext gc{};
+ uint16_t total_width{};
+ uint16_t total_height{};
+ uint16_t src_x{};
+ uint16_t src_y{};
+ uint16_t src_width{};
+ uint16_t src_height{};
+ int16_t dst_x{};
+ int16_t dst_y{};
+ uint8_t depth{};
+ ImageFormat format{};
+ uint8_t send_event{};
+ Seg shmseg{};
+ uint32_t offset{};
+ };
+
+ using PutImageResponse = Response<void>;
+
+ Future<void> PutImage(const PutImageRequest& request);
+
+ Future<void> PutImage(const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const uint16_t& total_width = {},
+ const uint16_t& total_height = {},
+ const uint16_t& src_x = {},
+ const uint16_t& src_y = {},
+ const uint16_t& src_width = {},
+ const uint16_t& src_height = {},
+ const int16_t& dst_x = {},
+ const int16_t& dst_y = {},
+ const uint8_t& depth = {},
+ const ImageFormat& format = {},
+ const uint8_t& send_event = {},
+ const Seg& shmseg = {},
+ const uint32_t& offset = {});
+
+ struct GetImageRequest {
+ Drawable drawable{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint32_t plane_mask{};
+ uint8_t format{};
+ Seg shmseg{};
+ uint32_t offset{};
+ };
+
+ struct GetImageReply {
+ uint8_t depth{};
+ uint16_t sequence{};
+ VisualId visual{};
+ uint32_t size{};
+ };
+
+ using GetImageResponse = Response<GetImageReply>;
+
+ Future<GetImageReply> GetImage(const GetImageRequest& request);
+
+ Future<GetImageReply> GetImage(const Drawable& drawable = {},
+ const int16_t& x = {},
+ const int16_t& y = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint32_t& plane_mask = {},
+ const uint8_t& format = {},
+ const Seg& shmseg = {},
+ const uint32_t& offset = {});
+
+ struct CreatePixmapRequest {
+ Pixmap pid{};
+ Drawable drawable{};
+ uint16_t width{};
+ uint16_t height{};
+ uint8_t depth{};
+ Seg shmseg{};
+ uint32_t offset{};
+ };
+
+ using CreatePixmapResponse = Response<void>;
+
+ Future<void> CreatePixmap(const CreatePixmapRequest& request);
+
+ Future<void> CreatePixmap(const Pixmap& pid = {},
+ const Drawable& drawable = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint8_t& depth = {},
+ const Seg& shmseg = {},
+ const uint32_t& offset = {});
+
+ struct AttachFdRequest {
+ Seg shmseg{};
+ RefCountedFD shm_fd{};
+ uint8_t read_only{};
+ };
+
+ using AttachFdResponse = Response<void>;
+
+ Future<void> AttachFd(const AttachFdRequest& request);
+
+ Future<void> AttachFd(const Seg& shmseg = {},
+ const RefCountedFD& shm_fd = {},
+ const uint8_t& read_only = {});
+
+ struct CreateSegmentRequest {
+ Seg shmseg{};
+ uint32_t size{};
+ uint8_t read_only{};
+ };
+
+ struct CreateSegmentReply {
+ uint8_t nfd{};
+ uint16_t sequence{};
+ RefCountedFD shm_fd{};
+ };
+
+ using CreateSegmentResponse = Response<CreateSegmentReply>;
+
+ Future<CreateSegmentReply> CreateSegment(const CreateSegmentRequest& request);
+
+ Future<CreateSegmentReply> CreateSegment(const Seg& shmseg = {},
+ const uint32_t& size = {},
+ const uint8_t& read_only = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_GENERATED_PROTOS_SHM_H_
diff --git a/chromium/ui/gfx/x/generated_protos/sync.cc b/chromium/ui/gfx/x/generated_protos/sync.cc
new file mode 100644
index 00000000000..5b180a91d5c
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/sync.cc
@@ -0,0 +1,1530 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "sync.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Sync::Sync(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+std::string Sync::CounterError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Sync::CounterError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_counter = " << static_cast<uint64_t>(bad_counter) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Sync::CounterError>(Sync::CounterError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_counter = (*error_).bad_counter;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_counter
+ Read(&bad_counter, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Sync::AlarmError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Sync::AlarmError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_alarm = " << static_cast<uint64_t>(bad_alarm) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Sync::AlarmError>(Sync::AlarmError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_alarm = (*error_).bad_alarm;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_alarm
+ Read(&bad_alarm, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Sync::CounterNotifyEvent>(Sync::CounterNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& kind = (*event_).kind;
+ auto& sequence = (*event_).sequence;
+ auto& counter = (*event_).counter;
+ auto& wait_value = (*event_).wait_value;
+ auto& counter_value = (*event_).counter_value;
+ auto& timestamp = (*event_).timestamp;
+ auto& count = (*event_).count;
+ auto& destroyed = (*event_).destroyed;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // kind
+ Read(&kind, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // counter
+ Read(&counter, &buf);
+
+ // wait_value
+ {
+ auto& hi = wait_value.hi;
+ auto& lo = wait_value.lo;
+
+ // hi
+ Read(&hi, &buf);
+
+ // lo
+ Read(&lo, &buf);
+ }
+
+ // counter_value
+ {
+ auto& hi = counter_value.hi;
+ auto& lo = counter_value.lo;
+
+ // hi
+ Read(&hi, &buf);
+
+ // lo
+ Read(&lo, &buf);
+ }
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // count
+ Read(&count, &buf);
+
+ // destroyed
+ Read(&destroyed, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Sync::AlarmNotifyEvent>(Sync::AlarmNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& kind = (*event_).kind;
+ auto& sequence = (*event_).sequence;
+ auto& alarm = (*event_).alarm;
+ auto& counter_value = (*event_).counter_value;
+ auto& alarm_value = (*event_).alarm_value;
+ auto& timestamp = (*event_).timestamp;
+ auto& state = (*event_).state;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // kind
+ Read(&kind, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // alarm
+ Read(&alarm, &buf);
+
+ // counter_value
+ {
+ auto& hi = counter_value.hi;
+ auto& lo = counter_value.lo;
+
+ // hi
+ Read(&hi, &buf);
+
+ // lo
+ Read(&lo, &buf);
+ }
+
+ // alarm_value
+ {
+ auto& hi = alarm_value.hi;
+ auto& lo = alarm_value.lo;
+
+ // hi
+ Read(&hi, &buf);
+
+ // lo
+ Read(&lo, &buf);
+ }
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // state
+ uint8_t tmp0;
+ Read(&tmp0, &buf);
+ state = static_cast<Sync::Alarmstate>(tmp0);
+
+ // pad0
+ Pad(&buf, 3);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+Future<Sync::InitializeReply> Sync::Initialize(
+ const Sync::InitializeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& desired_major_version = request.desired_major_version;
+ auto& desired_minor_version = request.desired_minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // desired_major_version
+ buf.Write(&desired_major_version);
+
+ // desired_minor_version
+ buf.Write(&desired_minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Sync::InitializeReply>(
+ &buf, "Sync::Initialize", false);
+}
+
+Future<Sync::InitializeReply> Sync::Initialize(
+ const uint8_t& desired_major_version,
+ const uint8_t& desired_minor_version) {
+ return Sync::Initialize(
+ Sync::InitializeRequest{desired_major_version, desired_minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Sync::InitializeReply> detail::ReadReply<Sync::InitializeReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Sync::InitializeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Sync::ListSystemCountersReply> Sync::ListSystemCounters(
+ const Sync::ListSystemCountersRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Sync::ListSystemCountersReply>(
+ &buf, "Sync::ListSystemCounters", false);
+}
+
+Future<Sync::ListSystemCountersReply> Sync::ListSystemCounters() {
+ return Sync::ListSystemCounters(Sync::ListSystemCountersRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Sync::ListSystemCountersReply> detail::ReadReply<
+ Sync::ListSystemCountersReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Sync::ListSystemCountersReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t counters_len{};
+ auto& counters = (*reply).counters;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // counters_len
+ Read(&counters_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // counters
+ counters.resize(counters_len);
+ for (auto& counters_elem : counters) {
+ // counters_elem
+ {
+ auto& counter = counters_elem.counter;
+ auto& resolution = counters_elem.resolution;
+ uint16_t name_len{};
+ auto& name = counters_elem.name;
+
+ // counter
+ Read(&counter, &buf);
+
+ // resolution
+ {
+ auto& hi = resolution.hi;
+ auto& lo = resolution.lo;
+
+ // hi
+ Read(&hi, &buf);
+
+ // lo
+ Read(&lo, &buf);
+ }
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // name
+ name.resize(name_len);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ // pad0
+ Align(&buf, 4);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Sync::CreateCounter(const Sync::CreateCounterRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& id = request.id;
+ auto& initial_value = request.initial_value;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // id
+ buf.Write(&id);
+
+ // initial_value
+ {
+ auto& hi = initial_value.hi;
+ auto& lo = initial_value.lo;
+
+ // hi
+ buf.Write(&hi);
+
+ // lo
+ buf.Write(&lo);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::CreateCounter", false);
+}
+
+Future<void> Sync::CreateCounter(const Counter& id,
+ const Int64& initial_value) {
+ return Sync::CreateCounter(Sync::CreateCounterRequest{id, initial_value});
+}
+
+Future<void> Sync::DestroyCounter(const Sync::DestroyCounterRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& counter = request.counter;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // counter
+ buf.Write(&counter);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::DestroyCounter", false);
+}
+
+Future<void> Sync::DestroyCounter(const Counter& counter) {
+ return Sync::DestroyCounter(Sync::DestroyCounterRequest{counter});
+}
+
+Future<Sync::QueryCounterReply> Sync::QueryCounter(
+ const Sync::QueryCounterRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& counter = request.counter;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // counter
+ buf.Write(&counter);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Sync::QueryCounterReply>(
+ &buf, "Sync::QueryCounter", false);
+}
+
+Future<Sync::QueryCounterReply> Sync::QueryCounter(const Counter& counter) {
+ return Sync::QueryCounter(Sync::QueryCounterRequest{counter});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Sync::QueryCounterReply> detail::ReadReply<
+ Sync::QueryCounterReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Sync::QueryCounterReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& counter_value = (*reply).counter_value;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // counter_value
+ {
+ auto& hi = counter_value.hi;
+ auto& lo = counter_value.lo;
+
+ // hi
+ Read(&hi, &buf);
+
+ // lo
+ Read(&lo, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Sync::Await(const Sync::AwaitRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& wait_list = request.wait_list;
+ size_t wait_list_len = wait_list.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // wait_list
+ DCHECK_EQ(static_cast<size_t>(wait_list_len), wait_list.size());
+ for (auto& wait_list_elem : wait_list) {
+ // wait_list_elem
+ {
+ auto& trigger = wait_list_elem.trigger;
+ auto& event_threshold = wait_list_elem.event_threshold;
+
+ // trigger
+ {
+ auto& counter = trigger.counter;
+ auto& wait_type = trigger.wait_type;
+ auto& wait_value = trigger.wait_value;
+ auto& test_type = trigger.test_type;
+
+ // counter
+ buf.Write(&counter);
+
+ // wait_type
+ uint32_t tmp1;
+ tmp1 = static_cast<uint32_t>(wait_type);
+ buf.Write(&tmp1);
+
+ // wait_value
+ {
+ auto& hi = wait_value.hi;
+ auto& lo = wait_value.lo;
+
+ // hi
+ buf.Write(&hi);
+
+ // lo
+ buf.Write(&lo);
+ }
+
+ // test_type
+ uint32_t tmp2;
+ tmp2 = static_cast<uint32_t>(test_type);
+ buf.Write(&tmp2);
+ }
+
+ // event_threshold
+ {
+ auto& hi = event_threshold.hi;
+ auto& lo = event_threshold.lo;
+
+ // hi
+ buf.Write(&hi);
+
+ // lo
+ buf.Write(&lo);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::Await", false);
+}
+
+Future<void> Sync::Await(const std::vector<WaitCondition>& wait_list) {
+ return Sync::Await(Sync::AwaitRequest{wait_list});
+}
+
+Future<void> Sync::ChangeCounter(const Sync::ChangeCounterRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& counter = request.counter;
+ auto& amount = request.amount;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // counter
+ buf.Write(&counter);
+
+ // amount
+ {
+ auto& hi = amount.hi;
+ auto& lo = amount.lo;
+
+ // hi
+ buf.Write(&hi);
+
+ // lo
+ buf.Write(&lo);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::ChangeCounter", false);
+}
+
+Future<void> Sync::ChangeCounter(const Counter& counter, const Int64& amount) {
+ return Sync::ChangeCounter(Sync::ChangeCounterRequest{counter, amount});
+}
+
+Future<void> Sync::SetCounter(const Sync::SetCounterRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& counter = request.counter;
+ auto& value = request.value;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // counter
+ buf.Write(&counter);
+
+ // value
+ {
+ auto& hi = value.hi;
+ auto& lo = value.lo;
+
+ // hi
+ buf.Write(&hi);
+
+ // lo
+ buf.Write(&lo);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::SetCounter", false);
+}
+
+Future<void> Sync::SetCounter(const Counter& counter, const Int64& value) {
+ return Sync::SetCounter(Sync::SetCounterRequest{counter, value});
+}
+
+Future<void> Sync::CreateAlarm(const Sync::CreateAlarmRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& id = request.id;
+ ChangeAlarmAttribute value_mask{};
+ auto& value_list = request;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // id
+ buf.Write(&id);
+
+ // value_mask
+ SwitchVar(ChangeAlarmAttribute::Counter, value_list.counter.has_value(), true,
+ &value_mask);
+ SwitchVar(ChangeAlarmAttribute::ValueType, value_list.valueType.has_value(),
+ true, &value_mask);
+ SwitchVar(ChangeAlarmAttribute::Value, value_list.value.has_value(), true,
+ &value_mask);
+ SwitchVar(ChangeAlarmAttribute::TestType, value_list.testType.has_value(),
+ true, &value_mask);
+ SwitchVar(ChangeAlarmAttribute::Delta, value_list.delta.has_value(), true,
+ &value_mask);
+ SwitchVar(ChangeAlarmAttribute::Events, value_list.events.has_value(), true,
+ &value_mask);
+ uint32_t tmp3;
+ tmp3 = static_cast<uint32_t>(value_mask);
+ buf.Write(&tmp3);
+
+ // value_list
+ auto value_list_expr = value_mask;
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::Counter)) {
+ auto& counter = *value_list.counter;
+
+ // counter
+ buf.Write(&counter);
+ }
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::ValueType)) {
+ auto& valueType = *value_list.valueType;
+
+ // valueType
+ uint32_t tmp4;
+ tmp4 = static_cast<uint32_t>(valueType);
+ buf.Write(&tmp4);
+ }
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::Value)) {
+ auto& value = *value_list.value;
+
+ // value
+ {
+ auto& hi = value.hi;
+ auto& lo = value.lo;
+
+ // hi
+ buf.Write(&hi);
+
+ // lo
+ buf.Write(&lo);
+ }
+ }
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::TestType)) {
+ auto& testType = *value_list.testType;
+
+ // testType
+ uint32_t tmp5;
+ tmp5 = static_cast<uint32_t>(testType);
+ buf.Write(&tmp5);
+ }
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::Delta)) {
+ auto& delta = *value_list.delta;
+
+ // delta
+ {
+ auto& hi = delta.hi;
+ auto& lo = delta.lo;
+
+ // hi
+ buf.Write(&hi);
+
+ // lo
+ buf.Write(&lo);
+ }
+ }
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::Events)) {
+ auto& events = *value_list.events;
+
+ // events
+ buf.Write(&events);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::CreateAlarm", false);
+}
+
+Future<void> Sync::CreateAlarm(const Alarm& id,
+ const base::Optional<Counter>& counter,
+ const base::Optional<Valuetype>& valueType,
+ const base::Optional<Int64>& value,
+ const base::Optional<Testtype>& testType,
+ const base::Optional<Int64>& delta,
+ const base::Optional<uint32_t>& events) {
+ return Sync::CreateAlarm(Sync::CreateAlarmRequest{
+ id, counter, valueType, value, testType, delta, events});
+}
+
+Future<void> Sync::ChangeAlarm(const Sync::ChangeAlarmRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& id = request.id;
+ ChangeAlarmAttribute value_mask{};
+ auto& value_list = request;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // id
+ buf.Write(&id);
+
+ // value_mask
+ SwitchVar(ChangeAlarmAttribute::Counter, value_list.counter.has_value(), true,
+ &value_mask);
+ SwitchVar(ChangeAlarmAttribute::ValueType, value_list.valueType.has_value(),
+ true, &value_mask);
+ SwitchVar(ChangeAlarmAttribute::Value, value_list.value.has_value(), true,
+ &value_mask);
+ SwitchVar(ChangeAlarmAttribute::TestType, value_list.testType.has_value(),
+ true, &value_mask);
+ SwitchVar(ChangeAlarmAttribute::Delta, value_list.delta.has_value(), true,
+ &value_mask);
+ SwitchVar(ChangeAlarmAttribute::Events, value_list.events.has_value(), true,
+ &value_mask);
+ uint32_t tmp6;
+ tmp6 = static_cast<uint32_t>(value_mask);
+ buf.Write(&tmp6);
+
+ // value_list
+ auto value_list_expr = value_mask;
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::Counter)) {
+ auto& counter = *value_list.counter;
+
+ // counter
+ buf.Write(&counter);
+ }
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::ValueType)) {
+ auto& valueType = *value_list.valueType;
+
+ // valueType
+ uint32_t tmp7;
+ tmp7 = static_cast<uint32_t>(valueType);
+ buf.Write(&tmp7);
+ }
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::Value)) {
+ auto& value = *value_list.value;
+
+ // value
+ {
+ auto& hi = value.hi;
+ auto& lo = value.lo;
+
+ // hi
+ buf.Write(&hi);
+
+ // lo
+ buf.Write(&lo);
+ }
+ }
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::TestType)) {
+ auto& testType = *value_list.testType;
+
+ // testType
+ uint32_t tmp8;
+ tmp8 = static_cast<uint32_t>(testType);
+ buf.Write(&tmp8);
+ }
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::Delta)) {
+ auto& delta = *value_list.delta;
+
+ // delta
+ {
+ auto& hi = delta.hi;
+ auto& lo = delta.lo;
+
+ // hi
+ buf.Write(&hi);
+
+ // lo
+ buf.Write(&lo);
+ }
+ }
+ if (CaseAnd(value_list_expr, ChangeAlarmAttribute::Events)) {
+ auto& events = *value_list.events;
+
+ // events
+ buf.Write(&events);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::ChangeAlarm", false);
+}
+
+Future<void> Sync::ChangeAlarm(const Alarm& id,
+ const base::Optional<Counter>& counter,
+ const base::Optional<Valuetype>& valueType,
+ const base::Optional<Int64>& value,
+ const base::Optional<Testtype>& testType,
+ const base::Optional<Int64>& delta,
+ const base::Optional<uint32_t>& events) {
+ return Sync::ChangeAlarm(Sync::ChangeAlarmRequest{
+ id, counter, valueType, value, testType, delta, events});
+}
+
+Future<void> Sync::DestroyAlarm(const Sync::DestroyAlarmRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& alarm = request.alarm;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // alarm
+ buf.Write(&alarm);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::DestroyAlarm", false);
+}
+
+Future<void> Sync::DestroyAlarm(const Alarm& alarm) {
+ return Sync::DestroyAlarm(Sync::DestroyAlarmRequest{alarm});
+}
+
+Future<Sync::QueryAlarmReply> Sync::QueryAlarm(
+ const Sync::QueryAlarmRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& alarm = request.alarm;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // alarm
+ buf.Write(&alarm);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Sync::QueryAlarmReply>(
+ &buf, "Sync::QueryAlarm", false);
+}
+
+Future<Sync::QueryAlarmReply> Sync::QueryAlarm(const Alarm& alarm) {
+ return Sync::QueryAlarm(Sync::QueryAlarmRequest{alarm});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Sync::QueryAlarmReply> detail::ReadReply<Sync::QueryAlarmReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Sync::QueryAlarmReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& trigger = (*reply).trigger;
+ auto& delta = (*reply).delta;
+ auto& events = (*reply).events;
+ auto& state = (*reply).state;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // trigger
+ {
+ auto& counter = trigger.counter;
+ auto& wait_type = trigger.wait_type;
+ auto& wait_value = trigger.wait_value;
+ auto& test_type = trigger.test_type;
+
+ // counter
+ Read(&counter, &buf);
+
+ // wait_type
+ uint32_t tmp9;
+ Read(&tmp9, &buf);
+ wait_type = static_cast<Sync::Valuetype>(tmp9);
+
+ // wait_value
+ {
+ auto& hi = wait_value.hi;
+ auto& lo = wait_value.lo;
+
+ // hi
+ Read(&hi, &buf);
+
+ // lo
+ Read(&lo, &buf);
+ }
+
+ // test_type
+ uint32_t tmp10;
+ Read(&tmp10, &buf);
+ test_type = static_cast<Sync::Testtype>(tmp10);
+ }
+
+ // delta
+ {
+ auto& hi = delta.hi;
+ auto& lo = delta.lo;
+
+ // hi
+ Read(&hi, &buf);
+
+ // lo
+ Read(&lo, &buf);
+ }
+
+ // events
+ Read(&events, &buf);
+
+ // state
+ uint8_t tmp11;
+ Read(&tmp11, &buf);
+ state = static_cast<Sync::Alarmstate>(tmp11);
+
+ // pad1
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Sync::SetPriority(const Sync::SetPriorityRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& id = request.id;
+ auto& priority = request.priority;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // id
+ buf.Write(&id);
+
+ // priority
+ buf.Write(&priority);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::SetPriority", false);
+}
+
+Future<void> Sync::SetPriority(const uint32_t& id, const int32_t& priority) {
+ return Sync::SetPriority(Sync::SetPriorityRequest{id, priority});
+}
+
+Future<Sync::GetPriorityReply> Sync::GetPriority(
+ const Sync::GetPriorityRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& id = request.id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // id
+ buf.Write(&id);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Sync::GetPriorityReply>(
+ &buf, "Sync::GetPriority", false);
+}
+
+Future<Sync::GetPriorityReply> Sync::GetPriority(const uint32_t& id) {
+ return Sync::GetPriority(Sync::GetPriorityRequest{id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Sync::GetPriorityReply> detail::ReadReply<
+ Sync::GetPriorityReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Sync::GetPriorityReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& priority = (*reply).priority;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // priority
+ Read(&priority, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Sync::CreateFence(const Sync::CreateFenceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& fence = request.fence;
+ auto& initially_triggered = request.initially_triggered;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 14;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // fence
+ buf.Write(&fence);
+
+ // initially_triggered
+ buf.Write(&initially_triggered);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::CreateFence", false);
+}
+
+Future<void> Sync::CreateFence(const Drawable& drawable,
+ const Fence& fence,
+ const uint8_t& initially_triggered) {
+ return Sync::CreateFence(
+ Sync::CreateFenceRequest{drawable, fence, initially_triggered});
+}
+
+Future<void> Sync::TriggerFence(const Sync::TriggerFenceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& fence = request.fence;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 15;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // fence
+ buf.Write(&fence);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::TriggerFence", false);
+}
+
+Future<void> Sync::TriggerFence(const Fence& fence) {
+ return Sync::TriggerFence(Sync::TriggerFenceRequest{fence});
+}
+
+Future<void> Sync::ResetFence(const Sync::ResetFenceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& fence = request.fence;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 16;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // fence
+ buf.Write(&fence);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::ResetFence", false);
+}
+
+Future<void> Sync::ResetFence(const Fence& fence) {
+ return Sync::ResetFence(Sync::ResetFenceRequest{fence});
+}
+
+Future<void> Sync::DestroyFence(const Sync::DestroyFenceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& fence = request.fence;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 17;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // fence
+ buf.Write(&fence);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::DestroyFence", false);
+}
+
+Future<void> Sync::DestroyFence(const Fence& fence) {
+ return Sync::DestroyFence(Sync::DestroyFenceRequest{fence});
+}
+
+Future<Sync::QueryFenceReply> Sync::QueryFence(
+ const Sync::QueryFenceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& fence = request.fence;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 18;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // fence
+ buf.Write(&fence);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Sync::QueryFenceReply>(
+ &buf, "Sync::QueryFence", false);
+}
+
+Future<Sync::QueryFenceReply> Sync::QueryFence(const Fence& fence) {
+ return Sync::QueryFence(Sync::QueryFenceRequest{fence});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Sync::QueryFenceReply> detail::ReadReply<Sync::QueryFenceReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Sync::QueryFenceReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& triggered = (*reply).triggered;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // triggered
+ Read(&triggered, &buf);
+
+ // pad1
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Sync::AwaitFence(const Sync::AwaitFenceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& fence_list = request.fence_list;
+ size_t fence_list_len = fence_list.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 19;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // fence_list
+ DCHECK_EQ(static_cast<size_t>(fence_list_len), fence_list.size());
+ for (auto& fence_list_elem : fence_list) {
+ // fence_list_elem
+ buf.Write(&fence_list_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Sync::AwaitFence", false);
+}
+
+Future<void> Sync::AwaitFence(const std::vector<Fence>& fence_list) {
+ return Sync::AwaitFence(Sync::AwaitFenceRequest{fence_list});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/sync.h b/chromium/ui/gfx/x/generated_protos/sync.h
new file mode 100644
index 00000000000..f78f7402ece
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/sync.h
@@ -0,0 +1,526 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_SYNC_H_
+#define UI_GFX_X_GENERATED_PROTOS_SYNC_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Sync {
+ public:
+ static constexpr unsigned major_version = 3;
+ static constexpr unsigned minor_version = 1;
+
+ Sync(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Alarm : uint32_t {};
+
+ enum class Alarmstate : int {
+ Active = 0,
+ Inactive = 1,
+ Destroyed = 2,
+ };
+
+ enum class Counter : uint32_t {};
+
+ enum class Fence : uint32_t {};
+
+ enum class Testtype : int {
+ PositiveTransition = 0,
+ NegativeTransition = 1,
+ PositiveComparison = 2,
+ NegativeComparison = 3,
+ };
+
+ enum class Valuetype : int {
+ Absolute = 0,
+ Relative = 1,
+ };
+
+ enum class ChangeAlarmAttribute : int {
+ Counter = 1 << 0,
+ ValueType = 1 << 1,
+ Value = 1 << 2,
+ TestType = 1 << 3,
+ Delta = 1 << 4,
+ Events = 1 << 5,
+ };
+
+ struct Int64 {
+ int32_t hi{};
+ uint32_t lo{};
+ };
+
+ struct SystemCounter {
+ Counter counter{};
+ Int64 resolution{};
+ std::string name{};
+ };
+
+ struct Trigger {
+ Counter counter{};
+ Valuetype wait_type{};
+ Int64 wait_value{};
+ Testtype test_type{};
+ };
+
+ struct WaitCondition {
+ Trigger trigger{};
+ Int64 event_threshold{};
+ };
+
+ struct CounterError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_counter{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct AlarmError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_alarm{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct CounterNotifyEvent {
+ static constexpr int type_id = 16;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ uint8_t kind{};
+ uint16_t sequence{};
+ Counter counter{};
+ Int64 wait_value{};
+ Int64 counter_value{};
+ Time timestamp{};
+ uint16_t count{};
+ uint8_t destroyed{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct AlarmNotifyEvent {
+ static constexpr int type_id = 17;
+ static constexpr uint8_t opcode = 1;
+ bool send_event{};
+ uint8_t kind{};
+ uint16_t sequence{};
+ Alarm alarm{};
+ Int64 counter_value{};
+ Int64 alarm_value{};
+ Time timestamp{};
+ Alarmstate state{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct InitializeRequest {
+ uint8_t desired_major_version{};
+ uint8_t desired_minor_version{};
+ };
+
+ struct InitializeReply {
+ uint16_t sequence{};
+ uint8_t major_version{};
+ uint8_t minor_version{};
+ };
+
+ using InitializeResponse = Response<InitializeReply>;
+
+ Future<InitializeReply> Initialize(const InitializeRequest& request);
+
+ Future<InitializeReply> Initialize(const uint8_t& desired_major_version = {},
+ const uint8_t& desired_minor_version = {});
+
+ struct ListSystemCountersRequest {};
+
+ struct ListSystemCountersReply {
+ uint16_t sequence{};
+ std::vector<SystemCounter> counters{};
+ };
+
+ using ListSystemCountersResponse = Response<ListSystemCountersReply>;
+
+ Future<ListSystemCountersReply> ListSystemCounters(
+ const ListSystemCountersRequest& request);
+
+ Future<ListSystemCountersReply> ListSystemCounters();
+
+ struct CreateCounterRequest {
+ Counter id{};
+ Int64 initial_value{};
+ };
+
+ using CreateCounterResponse = Response<void>;
+
+ Future<void> CreateCounter(const CreateCounterRequest& request);
+
+ Future<void> CreateCounter(const Counter& id = {},
+ const Int64& initial_value = {{}, {}});
+
+ struct DestroyCounterRequest {
+ Counter counter{};
+ };
+
+ using DestroyCounterResponse = Response<void>;
+
+ Future<void> DestroyCounter(const DestroyCounterRequest& request);
+
+ Future<void> DestroyCounter(const Counter& counter = {});
+
+ struct QueryCounterRequest {
+ Counter counter{};
+ };
+
+ struct QueryCounterReply {
+ uint16_t sequence{};
+ Int64 counter_value{};
+ };
+
+ using QueryCounterResponse = Response<QueryCounterReply>;
+
+ Future<QueryCounterReply> QueryCounter(const QueryCounterRequest& request);
+
+ Future<QueryCounterReply> QueryCounter(const Counter& counter = {});
+
+ struct AwaitRequest {
+ std::vector<WaitCondition> wait_list{};
+ };
+
+ using AwaitResponse = Response<void>;
+
+ Future<void> Await(const AwaitRequest& request);
+
+ Future<void> Await(const std::vector<WaitCondition>& wait_list = {});
+
+ struct ChangeCounterRequest {
+ Counter counter{};
+ Int64 amount{};
+ };
+
+ using ChangeCounterResponse = Response<void>;
+
+ Future<void> ChangeCounter(const ChangeCounterRequest& request);
+
+ Future<void> ChangeCounter(const Counter& counter = {},
+ const Int64& amount = {{}, {}});
+
+ struct SetCounterRequest {
+ Counter counter{};
+ Int64 value{};
+ };
+
+ using SetCounterResponse = Response<void>;
+
+ Future<void> SetCounter(const SetCounterRequest& request);
+
+ Future<void> SetCounter(const Counter& counter = {},
+ const Int64& value = {{}, {}});
+
+ struct CreateAlarmRequest {
+ Alarm id{};
+ base::Optional<Counter> counter{};
+ base::Optional<Valuetype> valueType{};
+ base::Optional<Int64> value{};
+ base::Optional<Testtype> testType{};
+ base::Optional<Int64> delta{};
+ base::Optional<uint32_t> events{};
+ };
+
+ using CreateAlarmResponse = Response<void>;
+
+ Future<void> CreateAlarm(const CreateAlarmRequest& request);
+
+ Future<void> CreateAlarm(
+ const Alarm& id = {},
+ const base::Optional<Counter>& counter = base::nullopt,
+ const base::Optional<Valuetype>& valueType = base::nullopt,
+ const base::Optional<Int64>& value = base::nullopt,
+ const base::Optional<Testtype>& testType = base::nullopt,
+ const base::Optional<Int64>& delta = base::nullopt,
+ const base::Optional<uint32_t>& events = base::nullopt);
+
+ struct ChangeAlarmRequest {
+ Alarm id{};
+ base::Optional<Counter> counter{};
+ base::Optional<Valuetype> valueType{};
+ base::Optional<Int64> value{};
+ base::Optional<Testtype> testType{};
+ base::Optional<Int64> delta{};
+ base::Optional<uint32_t> events{};
+ };
+
+ using ChangeAlarmResponse = Response<void>;
+
+ Future<void> ChangeAlarm(const ChangeAlarmRequest& request);
+
+ Future<void> ChangeAlarm(
+ const Alarm& id = {},
+ const base::Optional<Counter>& counter = base::nullopt,
+ const base::Optional<Valuetype>& valueType = base::nullopt,
+ const base::Optional<Int64>& value = base::nullopt,
+ const base::Optional<Testtype>& testType = base::nullopt,
+ const base::Optional<Int64>& delta = base::nullopt,
+ const base::Optional<uint32_t>& events = base::nullopt);
+
+ struct DestroyAlarmRequest {
+ Alarm alarm{};
+ };
+
+ using DestroyAlarmResponse = Response<void>;
+
+ Future<void> DestroyAlarm(const DestroyAlarmRequest& request);
+
+ Future<void> DestroyAlarm(const Alarm& alarm = {});
+
+ struct QueryAlarmRequest {
+ Alarm alarm{};
+ };
+
+ struct QueryAlarmReply {
+ uint16_t sequence{};
+ Trigger trigger{};
+ Int64 delta{};
+ uint8_t events{};
+ Alarmstate state{};
+ };
+
+ using QueryAlarmResponse = Response<QueryAlarmReply>;
+
+ Future<QueryAlarmReply> QueryAlarm(const QueryAlarmRequest& request);
+
+ Future<QueryAlarmReply> QueryAlarm(const Alarm& alarm = {});
+
+ struct SetPriorityRequest {
+ uint32_t id{};
+ int32_t priority{};
+ };
+
+ using SetPriorityResponse = Response<void>;
+
+ Future<void> SetPriority(const SetPriorityRequest& request);
+
+ Future<void> SetPriority(const uint32_t& id = {},
+ const int32_t& priority = {});
+
+ struct GetPriorityRequest {
+ uint32_t id{};
+ };
+
+ struct GetPriorityReply {
+ uint16_t sequence{};
+ int32_t priority{};
+ };
+
+ using GetPriorityResponse = Response<GetPriorityReply>;
+
+ Future<GetPriorityReply> GetPriority(const GetPriorityRequest& request);
+
+ Future<GetPriorityReply> GetPriority(const uint32_t& id = {});
+
+ struct CreateFenceRequest {
+ Drawable drawable{};
+ Fence fence{};
+ uint8_t initially_triggered{};
+ };
+
+ using CreateFenceResponse = Response<void>;
+
+ Future<void> CreateFence(const CreateFenceRequest& request);
+
+ Future<void> CreateFence(const Drawable& drawable = {},
+ const Fence& fence = {},
+ const uint8_t& initially_triggered = {});
+
+ struct TriggerFenceRequest {
+ Fence fence{};
+ };
+
+ using TriggerFenceResponse = Response<void>;
+
+ Future<void> TriggerFence(const TriggerFenceRequest& request);
+
+ Future<void> TriggerFence(const Fence& fence = {});
+
+ struct ResetFenceRequest {
+ Fence fence{};
+ };
+
+ using ResetFenceResponse = Response<void>;
+
+ Future<void> ResetFence(const ResetFenceRequest& request);
+
+ Future<void> ResetFence(const Fence& fence = {});
+
+ struct DestroyFenceRequest {
+ Fence fence{};
+ };
+
+ using DestroyFenceResponse = Response<void>;
+
+ Future<void> DestroyFence(const DestroyFenceRequest& request);
+
+ Future<void> DestroyFence(const Fence& fence = {});
+
+ struct QueryFenceRequest {
+ Fence fence{};
+ };
+
+ struct QueryFenceReply {
+ uint16_t sequence{};
+ uint8_t triggered{};
+ };
+
+ using QueryFenceResponse = Response<QueryFenceReply>;
+
+ Future<QueryFenceReply> QueryFence(const QueryFenceRequest& request);
+
+ Future<QueryFenceReply> QueryFence(const Fence& fence = {});
+
+ struct AwaitFenceRequest {
+ std::vector<Fence> fence_list{};
+ };
+
+ using AwaitFenceResponse = Response<void>;
+
+ Future<void> AwaitFence(const AwaitFenceRequest& request);
+
+ Future<void> AwaitFence(const std::vector<Fence>& fence_list = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Sync::Alarmstate operator|(x11::Sync::Alarmstate l,
+ x11::Sync::Alarmstate r) {
+ using T = std::underlying_type_t<x11::Sync::Alarmstate>;
+ return static_cast<x11::Sync::Alarmstate>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Sync::Alarmstate operator&(x11::Sync::Alarmstate l,
+ x11::Sync::Alarmstate r) {
+ using T = std::underlying_type_t<x11::Sync::Alarmstate>;
+ return static_cast<x11::Sync::Alarmstate>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Sync::Testtype operator|(x11::Sync::Testtype l,
+ x11::Sync::Testtype r) {
+ using T = std::underlying_type_t<x11::Sync::Testtype>;
+ return static_cast<x11::Sync::Testtype>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Sync::Testtype operator&(x11::Sync::Testtype l,
+ x11::Sync::Testtype r) {
+ using T = std::underlying_type_t<x11::Sync::Testtype>;
+ return static_cast<x11::Sync::Testtype>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Sync::Valuetype operator|(x11::Sync::Valuetype l,
+ x11::Sync::Valuetype r) {
+ using T = std::underlying_type_t<x11::Sync::Valuetype>;
+ return static_cast<x11::Sync::Valuetype>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Sync::Valuetype operator&(x11::Sync::Valuetype l,
+ x11::Sync::Valuetype r) {
+ using T = std::underlying_type_t<x11::Sync::Valuetype>;
+ return static_cast<x11::Sync::Valuetype>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Sync::ChangeAlarmAttribute operator|(
+ x11::Sync::ChangeAlarmAttribute l,
+ x11::Sync::ChangeAlarmAttribute r) {
+ using T = std::underlying_type_t<x11::Sync::ChangeAlarmAttribute>;
+ return static_cast<x11::Sync::ChangeAlarmAttribute>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Sync::ChangeAlarmAttribute operator&(
+ x11::Sync::ChangeAlarmAttribute l,
+ x11::Sync::ChangeAlarmAttribute r) {
+ using T = std::underlying_type_t<x11::Sync::ChangeAlarmAttribute>;
+ return static_cast<x11::Sync::ChangeAlarmAttribute>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_SYNC_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xc_misc.cc b/chromium/ui/gfx/x/generated_protos/xc_misc.cc
new file mode 100644
index 00000000000..e75c0a82b99
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xc_misc.cc
@@ -0,0 +1,277 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xc_misc.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+XCMisc::XCMisc(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<XCMisc::GetVersionReply> XCMisc::GetVersion(
+ const XCMisc::GetVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client_major_version = request.client_major_version;
+ auto& client_minor_version = request.client_minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client_major_version
+ buf.Write(&client_major_version);
+
+ // client_minor_version
+ buf.Write(&client_minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XCMisc::GetVersionReply>(
+ &buf, "XCMisc::GetVersion", false);
+}
+
+Future<XCMisc::GetVersionReply> XCMisc::GetVersion(
+ const uint16_t& client_major_version,
+ const uint16_t& client_minor_version) {
+ return XCMisc::GetVersion(
+ XCMisc::GetVersionRequest{client_major_version, client_minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XCMisc::GetVersionReply> detail::ReadReply<
+ XCMisc::GetVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XCMisc::GetVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& server_major_version = (*reply).server_major_version;
+ auto& server_minor_version = (*reply).server_minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // server_major_version
+ Read(&server_major_version, &buf);
+
+ // server_minor_version
+ Read(&server_minor_version, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XCMisc::GetXIDRangeReply> XCMisc::GetXIDRange(
+ const XCMisc::GetXIDRangeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XCMisc::GetXIDRangeReply>(
+ &buf, "XCMisc::GetXIDRange", false);
+}
+
+Future<XCMisc::GetXIDRangeReply> XCMisc::GetXIDRange() {
+ return XCMisc::GetXIDRange(XCMisc::GetXIDRangeRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XCMisc::GetXIDRangeReply> detail::ReadReply<
+ XCMisc::GetXIDRangeReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XCMisc::GetXIDRangeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& start_id = (*reply).start_id;
+ auto& count = (*reply).count;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // start_id
+ Read(&start_id, &buf);
+
+ // count
+ Read(&count, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XCMisc::GetXIDListReply> XCMisc::GetXIDList(
+ const XCMisc::GetXIDListRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& count = request.count;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // count
+ buf.Write(&count);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XCMisc::GetXIDListReply>(
+ &buf, "XCMisc::GetXIDList", false);
+}
+
+Future<XCMisc::GetXIDListReply> XCMisc::GetXIDList(const uint32_t& count) {
+ return XCMisc::GetXIDList(XCMisc::GetXIDListRequest{count});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XCMisc::GetXIDListReply> detail::ReadReply<
+ XCMisc::GetXIDListReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XCMisc::GetXIDListReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t ids_len{};
+ auto& ids = (*reply).ids;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // ids_len
+ Read(&ids_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // ids
+ ids.resize(ids_len);
+ for (auto& ids_elem : ids) {
+ // ids_elem
+ Read(&ids_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xc_misc.h b/chromium/ui/gfx/x/generated_protos/xc_misc.h
new file mode 100644
index 00000000000..cbfc45f3583
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xc_misc.h
@@ -0,0 +1,137 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XC_MISC_H_
+#define UI_GFX_X_GENERATED_PROTOS_XC_MISC_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) XCMisc {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 1;
+
+ XCMisc(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ struct GetVersionRequest {
+ uint16_t client_major_version{};
+ uint16_t client_minor_version{};
+ };
+
+ struct GetVersionReply {
+ uint16_t sequence{};
+ uint16_t server_major_version{};
+ uint16_t server_minor_version{};
+ };
+
+ using GetVersionResponse = Response<GetVersionReply>;
+
+ Future<GetVersionReply> GetVersion(const GetVersionRequest& request);
+
+ Future<GetVersionReply> GetVersion(const uint16_t& client_major_version = {},
+ const uint16_t& client_minor_version = {});
+
+ struct GetXIDRangeRequest {};
+
+ struct GetXIDRangeReply {
+ uint16_t sequence{};
+ uint32_t start_id{};
+ uint32_t count{};
+ };
+
+ using GetXIDRangeResponse = Response<GetXIDRangeReply>;
+
+ Future<GetXIDRangeReply> GetXIDRange(const GetXIDRangeRequest& request);
+
+ Future<GetXIDRangeReply> GetXIDRange();
+
+ struct GetXIDListRequest {
+ uint32_t count{};
+ };
+
+ struct GetXIDListReply {
+ uint16_t sequence{};
+ std::vector<uint32_t> ids{};
+ };
+
+ using GetXIDListResponse = Response<GetXIDListReply>;
+
+ Future<GetXIDListReply> GetXIDList(const GetXIDListRequest& request);
+
+ Future<GetXIDListReply> GetXIDList(const uint32_t& count = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XC_MISC_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xevie.cc b/chromium/ui/gfx/x/generated_protos/xevie.cc
new file mode 100644
index 00000000000..8eeb44dc8ad
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xevie.cc
@@ -0,0 +1,406 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xevie.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Xevie::Xevie(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<Xevie::QueryVersionReply> Xevie::QueryVersion(
+ const Xevie::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client_major_version = request.client_major_version;
+ auto& client_minor_version = request.client_minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client_major_version
+ buf.Write(&client_major_version);
+
+ // client_minor_version
+ buf.Write(&client_minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xevie::QueryVersionReply>(
+ &buf, "Xevie::QueryVersion", false);
+}
+
+Future<Xevie::QueryVersionReply> Xevie::QueryVersion(
+ const uint16_t& client_major_version,
+ const uint16_t& client_minor_version) {
+ return Xevie::QueryVersion(
+ Xevie::QueryVersionRequest{client_major_version, client_minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xevie::QueryVersionReply> detail::ReadReply<
+ Xevie::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xevie::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& server_major_version = (*reply).server_major_version;
+ auto& server_minor_version = (*reply).server_minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // server_major_version
+ Read(&server_major_version, &buf);
+
+ // server_minor_version
+ Read(&server_minor_version, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xevie::StartReply> Xevie::Start(const Xevie::StartRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xevie::StartReply>(&buf, "Xevie::Start",
+ false);
+}
+
+Future<Xevie::StartReply> Xevie::Start(const uint32_t& screen) {
+ return Xevie::Start(Xevie::StartRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xevie::StartReply> detail::ReadReply<Xevie::StartReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xevie::StartReply>();
+
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 24);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xevie::EndReply> Xevie::End(const Xevie::EndRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cmap = request.cmap;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xevie::EndReply>(&buf, "Xevie::End", false);
+}
+
+Future<Xevie::EndReply> Xevie::End(const uint32_t& cmap) {
+ return Xevie::End(Xevie::EndRequest{cmap});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xevie::EndReply> detail::ReadReply<Xevie::EndReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xevie::EndReply>();
+
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 24);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xevie::SendReply> Xevie::Send(const Xevie::SendRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& event = request.event;
+ auto& data_type = request.data_type;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // event
+ {
+ // pad0
+ Pad(&buf, 32);
+ }
+
+ // data_type
+ buf.Write(&data_type);
+
+ // pad0
+ Pad(&buf, 64);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xevie::SendReply>(&buf, "Xevie::Send", false);
+}
+
+Future<Xevie::SendReply> Xevie::Send(const Event& event,
+ const uint32_t& data_type) {
+ return Xevie::Send(Xevie::SendRequest{event, data_type});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xevie::SendReply> detail::ReadReply<Xevie::SendReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xevie::SendReply>();
+
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 24);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xevie::SelectInputReply> Xevie::SelectInput(
+ const Xevie::SelectInputRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& event_mask = request.event_mask;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // event_mask
+ buf.Write(&event_mask);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xevie::SelectInputReply>(
+ &buf, "Xevie::SelectInput", false);
+}
+
+Future<Xevie::SelectInputReply> Xevie::SelectInput(const uint32_t& event_mask) {
+ return Xevie::SelectInput(Xevie::SelectInputRequest{event_mask});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xevie::SelectInputReply> detail::ReadReply<
+ Xevie::SelectInputReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xevie::SelectInputReply>();
+
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 24);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xevie.h b/chromium/ui/gfx/x/generated_protos/xevie.h
new file mode 100644
index 00000000000..f820d2e73fd
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xevie.h
@@ -0,0 +1,188 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XEVIE_H_
+#define UI_GFX_X_GENERATED_PROTOS_XEVIE_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Xevie {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 0;
+
+ Xevie(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Datatype : int {
+ Unmodified = 0,
+ Modified = 1,
+ };
+
+ struct Event {};
+
+ struct QueryVersionRequest {
+ uint16_t client_major_version{};
+ uint16_t client_minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint16_t server_major_version{};
+ uint16_t server_minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(
+ const uint16_t& client_major_version = {},
+ const uint16_t& client_minor_version = {});
+
+ struct StartRequest {
+ uint32_t screen{};
+ };
+
+ struct StartReply {
+ uint16_t sequence{};
+ };
+
+ using StartResponse = Response<StartReply>;
+
+ Future<StartReply> Start(const StartRequest& request);
+
+ Future<StartReply> Start(const uint32_t& screen = {});
+
+ struct EndRequest {
+ uint32_t cmap{};
+ };
+
+ struct EndReply {
+ uint16_t sequence{};
+ };
+
+ using EndResponse = Response<EndReply>;
+
+ Future<EndReply> End(const EndRequest& request);
+
+ Future<EndReply> End(const uint32_t& cmap = {});
+
+ struct SendRequest {
+ Event event{};
+ uint32_t data_type{};
+ };
+
+ struct SendReply {
+ uint16_t sequence{};
+ };
+
+ using SendResponse = Response<SendReply>;
+
+ Future<SendReply> Send(const SendRequest& request);
+
+ Future<SendReply> Send(const Event& event = {},
+ const uint32_t& data_type = {});
+
+ struct SelectInputRequest {
+ uint32_t event_mask{};
+ };
+
+ struct SelectInputReply {
+ uint16_t sequence{};
+ };
+
+ using SelectInputResponse = Response<SelectInputReply>;
+
+ Future<SelectInputReply> SelectInput(const SelectInputRequest& request);
+
+ Future<SelectInputReply> SelectInput(const uint32_t& event_mask = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Xevie::Datatype operator|(x11::Xevie::Datatype l,
+ x11::Xevie::Datatype r) {
+ using T = std::underlying_type_t<x11::Xevie::Datatype>;
+ return static_cast<x11::Xevie::Datatype>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xevie::Datatype operator&(x11::Xevie::Datatype l,
+ x11::Xevie::Datatype r) {
+ using T = std::underlying_type_t<x11::Xevie::Datatype>;
+ return static_cast<x11::Xevie::Datatype>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XEVIE_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xf86dri.cc b/chromium/ui/gfx/x/generated_protos/xf86dri.cc
new file mode 100644
index 00000000000..4acebbeb22d
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xf86dri.cc
@@ -0,0 +1,972 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xf86dri.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+XF86Dri::XF86Dri(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<XF86Dri::QueryVersionReply> XF86Dri::QueryVersion(
+ const XF86Dri::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86Dri::QueryVersionReply>(
+ &buf, "XF86Dri::QueryVersion", false);
+}
+
+Future<XF86Dri::QueryVersionReply> XF86Dri::QueryVersion() {
+ return XF86Dri::QueryVersion(XF86Dri::QueryVersionRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86Dri::QueryVersionReply> detail::ReadReply<
+ XF86Dri::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86Dri::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& dri_major_version = (*reply).dri_major_version;
+ auto& dri_minor_version = (*reply).dri_minor_version;
+ auto& dri_minor_patch = (*reply).dri_minor_patch;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // dri_major_version
+ Read(&dri_major_version, &buf);
+
+ // dri_minor_version
+ Read(&dri_minor_version, &buf);
+
+ // dri_minor_patch
+ Read(&dri_minor_patch, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XF86Dri::QueryDirectRenderingCapableReply>
+XF86Dri::QueryDirectRenderingCapable(
+ const XF86Dri::QueryDirectRenderingCapableRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86Dri::QueryDirectRenderingCapableReply>(
+ &buf, "XF86Dri::QueryDirectRenderingCapable", false);
+}
+
+Future<XF86Dri::QueryDirectRenderingCapableReply>
+XF86Dri::QueryDirectRenderingCapable(const uint32_t& screen) {
+ return XF86Dri::QueryDirectRenderingCapable(
+ XF86Dri::QueryDirectRenderingCapableRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86Dri::QueryDirectRenderingCapableReply> detail::ReadReply<
+ XF86Dri::QueryDirectRenderingCapableReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86Dri::QueryDirectRenderingCapableReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& is_capable = (*reply).is_capable;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // is_capable
+ Read(&is_capable, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XF86Dri::OpenConnectionReply> XF86Dri::OpenConnection(
+ const XF86Dri::OpenConnectionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86Dri::OpenConnectionReply>(
+ &buf, "XF86Dri::OpenConnection", false);
+}
+
+Future<XF86Dri::OpenConnectionReply> XF86Dri::OpenConnection(
+ const uint32_t& screen) {
+ return XF86Dri::OpenConnection(XF86Dri::OpenConnectionRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86Dri::OpenConnectionReply> detail::ReadReply<
+ XF86Dri::OpenConnectionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86Dri::OpenConnectionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& sarea_handle_low = (*reply).sarea_handle_low;
+ auto& sarea_handle_high = (*reply).sarea_handle_high;
+ uint32_t bus_id_len{};
+ auto& bus_id = (*reply).bus_id;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // sarea_handle_low
+ Read(&sarea_handle_low, &buf);
+
+ // sarea_handle_high
+ Read(&sarea_handle_high, &buf);
+
+ // bus_id_len
+ Read(&bus_id_len, &buf);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // bus_id
+ bus_id.resize(bus_id_len);
+ for (auto& bus_id_elem : bus_id) {
+ // bus_id_elem
+ Read(&bus_id_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XF86Dri::CloseConnection(
+ const XF86Dri::CloseConnectionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86Dri::CloseConnection",
+ false);
+}
+
+Future<void> XF86Dri::CloseConnection(const uint32_t& screen) {
+ return XF86Dri::CloseConnection(XF86Dri::CloseConnectionRequest{screen});
+}
+
+Future<XF86Dri::GetClientDriverNameReply> XF86Dri::GetClientDriverName(
+ const XF86Dri::GetClientDriverNameRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86Dri::GetClientDriverNameReply>(
+ &buf, "XF86Dri::GetClientDriverName", false);
+}
+
+Future<XF86Dri::GetClientDriverNameReply> XF86Dri::GetClientDriverName(
+ const uint32_t& screen) {
+ return XF86Dri::GetClientDriverName(
+ XF86Dri::GetClientDriverNameRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86Dri::GetClientDriverNameReply> detail::ReadReply<
+ XF86Dri::GetClientDriverNameReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86Dri::GetClientDriverNameReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& client_driver_major_version = (*reply).client_driver_major_version;
+ auto& client_driver_minor_version = (*reply).client_driver_minor_version;
+ auto& client_driver_patch_version = (*reply).client_driver_patch_version;
+ uint32_t client_driver_name_len{};
+ auto& client_driver_name = (*reply).client_driver_name;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // client_driver_major_version
+ Read(&client_driver_major_version, &buf);
+
+ // client_driver_minor_version
+ Read(&client_driver_minor_version, &buf);
+
+ // client_driver_patch_version
+ Read(&client_driver_patch_version, &buf);
+
+ // client_driver_name_len
+ Read(&client_driver_name_len, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // client_driver_name
+ client_driver_name.resize(client_driver_name_len);
+ for (auto& client_driver_name_elem : client_driver_name) {
+ // client_driver_name_elem
+ Read(&client_driver_name_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XF86Dri::CreateContextReply> XF86Dri::CreateContext(
+ const XF86Dri::CreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& visual = request.visual;
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // visual
+ buf.Write(&visual);
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86Dri::CreateContextReply>(
+ &buf, "XF86Dri::CreateContext", false);
+}
+
+Future<XF86Dri::CreateContextReply> XF86Dri::CreateContext(
+ const uint32_t& screen,
+ const uint32_t& visual,
+ const uint32_t& context) {
+ return XF86Dri::CreateContext(
+ XF86Dri::CreateContextRequest{screen, visual, context});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86Dri::CreateContextReply> detail::ReadReply<
+ XF86Dri::CreateContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86Dri::CreateContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& hw_context = (*reply).hw_context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // hw_context
+ Read(&hw_context, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XF86Dri::DestroyContext(
+ const XF86Dri::DestroyContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86Dri::DestroyContext", false);
+}
+
+Future<void> XF86Dri::DestroyContext(const uint32_t& screen,
+ const uint32_t& context) {
+ return XF86Dri::DestroyContext(
+ XF86Dri::DestroyContextRequest{screen, context});
+}
+
+Future<XF86Dri::CreateDrawableReply> XF86Dri::CreateDrawable(
+ const XF86Dri::CreateDrawableRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86Dri::CreateDrawableReply>(
+ &buf, "XF86Dri::CreateDrawable", false);
+}
+
+Future<XF86Dri::CreateDrawableReply> XF86Dri::CreateDrawable(
+ const uint32_t& screen,
+ const uint32_t& drawable) {
+ return XF86Dri::CreateDrawable(
+ XF86Dri::CreateDrawableRequest{screen, drawable});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86Dri::CreateDrawableReply> detail::ReadReply<
+ XF86Dri::CreateDrawableReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86Dri::CreateDrawableReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& hw_drawable_handle = (*reply).hw_drawable_handle;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // hw_drawable_handle
+ Read(&hw_drawable_handle, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XF86Dri::DestroyDrawable(
+ const XF86Dri::DestroyDrawableRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86Dri::DestroyDrawable",
+ false);
+}
+
+Future<void> XF86Dri::DestroyDrawable(const uint32_t& screen,
+ const uint32_t& drawable) {
+ return XF86Dri::DestroyDrawable(
+ XF86Dri::DestroyDrawableRequest{screen, drawable});
+}
+
+Future<XF86Dri::GetDrawableInfoReply> XF86Dri::GetDrawableInfo(
+ const XF86Dri::GetDrawableInfoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86Dri::GetDrawableInfoReply>(
+ &buf, "XF86Dri::GetDrawableInfo", false);
+}
+
+Future<XF86Dri::GetDrawableInfoReply> XF86Dri::GetDrawableInfo(
+ const uint32_t& screen,
+ const uint32_t& drawable) {
+ return XF86Dri::GetDrawableInfo(
+ XF86Dri::GetDrawableInfoRequest{screen, drawable});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86Dri::GetDrawableInfoReply> detail::ReadReply<
+ XF86Dri::GetDrawableInfoReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86Dri::GetDrawableInfoReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& drawable_table_index = (*reply).drawable_table_index;
+ auto& drawable_table_stamp = (*reply).drawable_table_stamp;
+ auto& drawable_origin_X = (*reply).drawable_origin_X;
+ auto& drawable_origin_Y = (*reply).drawable_origin_Y;
+ auto& drawable_size_W = (*reply).drawable_size_W;
+ auto& drawable_size_H = (*reply).drawable_size_H;
+ uint32_t num_clip_rects{};
+ auto& back_x = (*reply).back_x;
+ auto& back_y = (*reply).back_y;
+ uint32_t num_back_clip_rects{};
+ auto& clip_rects = (*reply).clip_rects;
+ size_t clip_rects_len = clip_rects.size();
+ auto& back_clip_rects = (*reply).back_clip_rects;
+ size_t back_clip_rects_len = back_clip_rects.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // drawable_table_index
+ Read(&drawable_table_index, &buf);
+
+ // drawable_table_stamp
+ Read(&drawable_table_stamp, &buf);
+
+ // drawable_origin_X
+ Read(&drawable_origin_X, &buf);
+
+ // drawable_origin_Y
+ Read(&drawable_origin_Y, &buf);
+
+ // drawable_size_W
+ Read(&drawable_size_W, &buf);
+
+ // drawable_size_H
+ Read(&drawable_size_H, &buf);
+
+ // num_clip_rects
+ Read(&num_clip_rects, &buf);
+
+ // back_x
+ Read(&back_x, &buf);
+
+ // back_y
+ Read(&back_y, &buf);
+
+ // num_back_clip_rects
+ Read(&num_back_clip_rects, &buf);
+
+ // clip_rects
+ clip_rects.resize(num_clip_rects);
+ for (auto& clip_rects_elem : clip_rects) {
+ // clip_rects_elem
+ {
+ auto& x1 = clip_rects_elem.x1;
+ auto& y1 = clip_rects_elem.y1;
+ auto& x2 = clip_rects_elem.x2;
+ auto& x3 = clip_rects_elem.x3;
+
+ // x1
+ Read(&x1, &buf);
+
+ // y1
+ Read(&y1, &buf);
+
+ // x2
+ Read(&x2, &buf);
+
+ // x3
+ Read(&x3, &buf);
+ }
+ }
+
+ // back_clip_rects
+ back_clip_rects.resize(num_back_clip_rects);
+ for (auto& back_clip_rects_elem : back_clip_rects) {
+ // back_clip_rects_elem
+ {
+ auto& x1 = back_clip_rects_elem.x1;
+ auto& y1 = back_clip_rects_elem.y1;
+ auto& x2 = back_clip_rects_elem.x2;
+ auto& x3 = back_clip_rects_elem.x3;
+
+ // x1
+ Read(&x1, &buf);
+
+ // y1
+ Read(&y1, &buf);
+
+ // x2
+ Read(&x2, &buf);
+
+ // x3
+ Read(&x3, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XF86Dri::GetDeviceInfoReply> XF86Dri::GetDeviceInfo(
+ const XF86Dri::GetDeviceInfoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86Dri::GetDeviceInfoReply>(
+ &buf, "XF86Dri::GetDeviceInfo", false);
+}
+
+Future<XF86Dri::GetDeviceInfoReply> XF86Dri::GetDeviceInfo(
+ const uint32_t& screen) {
+ return XF86Dri::GetDeviceInfo(XF86Dri::GetDeviceInfoRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86Dri::GetDeviceInfoReply> detail::ReadReply<
+ XF86Dri::GetDeviceInfoReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86Dri::GetDeviceInfoReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& framebuffer_handle_low = (*reply).framebuffer_handle_low;
+ auto& framebuffer_handle_high = (*reply).framebuffer_handle_high;
+ auto& framebuffer_origin_offset = (*reply).framebuffer_origin_offset;
+ auto& framebuffer_size = (*reply).framebuffer_size;
+ auto& framebuffer_stride = (*reply).framebuffer_stride;
+ uint32_t device_private_size{};
+ auto& device_private = (*reply).device_private;
+ size_t device_private_len = device_private.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // framebuffer_handle_low
+ Read(&framebuffer_handle_low, &buf);
+
+ // framebuffer_handle_high
+ Read(&framebuffer_handle_high, &buf);
+
+ // framebuffer_origin_offset
+ Read(&framebuffer_origin_offset, &buf);
+
+ // framebuffer_size
+ Read(&framebuffer_size, &buf);
+
+ // framebuffer_stride
+ Read(&framebuffer_stride, &buf);
+
+ // device_private_size
+ Read(&device_private_size, &buf);
+
+ // device_private
+ device_private.resize(device_private_size);
+ for (auto& device_private_elem : device_private) {
+ // device_private_elem
+ Read(&device_private_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XF86Dri::AuthConnectionReply> XF86Dri::AuthConnection(
+ const XF86Dri::AuthConnectionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& magic = request.magic;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // magic
+ buf.Write(&magic);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86Dri::AuthConnectionReply>(
+ &buf, "XF86Dri::AuthConnection", false);
+}
+
+Future<XF86Dri::AuthConnectionReply> XF86Dri::AuthConnection(
+ const uint32_t& screen,
+ const uint32_t& magic) {
+ return XF86Dri::AuthConnection(XF86Dri::AuthConnectionRequest{screen, magic});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86Dri::AuthConnectionReply> detail::ReadReply<
+ XF86Dri::AuthConnectionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86Dri::AuthConnectionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& authenticated = (*reply).authenticated;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // authenticated
+ Read(&authenticated, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xf86dri.h b/chromium/ui/gfx/x/generated_protos/xf86dri.h
new file mode 100644
index 00000000000..c290d7c4c1e
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xf86dri.h
@@ -0,0 +1,304 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XF86DRI_H_
+#define UI_GFX_X_GENERATED_PROTOS_XF86DRI_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) XF86Dri {
+ public:
+ static constexpr unsigned major_version = 4;
+ static constexpr unsigned minor_version = 1;
+
+ XF86Dri(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ struct DrmClipRect {
+ int16_t x1{};
+ int16_t y1{};
+ int16_t x2{};
+ int16_t x3{};
+ };
+
+ struct QueryVersionRequest {};
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint16_t dri_major_version{};
+ uint16_t dri_minor_version{};
+ uint32_t dri_minor_patch{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion();
+
+ struct QueryDirectRenderingCapableRequest {
+ uint32_t screen{};
+ };
+
+ struct QueryDirectRenderingCapableReply {
+ uint16_t sequence{};
+ uint8_t is_capable{};
+ };
+
+ using QueryDirectRenderingCapableResponse =
+ Response<QueryDirectRenderingCapableReply>;
+
+ Future<QueryDirectRenderingCapableReply> QueryDirectRenderingCapable(
+ const QueryDirectRenderingCapableRequest& request);
+
+ Future<QueryDirectRenderingCapableReply> QueryDirectRenderingCapable(
+ const uint32_t& screen = {});
+
+ struct OpenConnectionRequest {
+ uint32_t screen{};
+ };
+
+ struct OpenConnectionReply {
+ uint16_t sequence{};
+ uint32_t sarea_handle_low{};
+ uint32_t sarea_handle_high{};
+ std::string bus_id{};
+ };
+
+ using OpenConnectionResponse = Response<OpenConnectionReply>;
+
+ Future<OpenConnectionReply> OpenConnection(
+ const OpenConnectionRequest& request);
+
+ Future<OpenConnectionReply> OpenConnection(const uint32_t& screen = {});
+
+ struct CloseConnectionRequest {
+ uint32_t screen{};
+ };
+
+ using CloseConnectionResponse = Response<void>;
+
+ Future<void> CloseConnection(const CloseConnectionRequest& request);
+
+ Future<void> CloseConnection(const uint32_t& screen = {});
+
+ struct GetClientDriverNameRequest {
+ uint32_t screen{};
+ };
+
+ struct GetClientDriverNameReply {
+ uint16_t sequence{};
+ uint32_t client_driver_major_version{};
+ uint32_t client_driver_minor_version{};
+ uint32_t client_driver_patch_version{};
+ std::string client_driver_name{};
+ };
+
+ using GetClientDriverNameResponse = Response<GetClientDriverNameReply>;
+
+ Future<GetClientDriverNameReply> GetClientDriverName(
+ const GetClientDriverNameRequest& request);
+
+ Future<GetClientDriverNameReply> GetClientDriverName(
+ const uint32_t& screen = {});
+
+ struct CreateContextRequest {
+ uint32_t screen{};
+ uint32_t visual{};
+ uint32_t context{};
+ };
+
+ struct CreateContextReply {
+ uint16_t sequence{};
+ uint32_t hw_context{};
+ };
+
+ using CreateContextResponse = Response<CreateContextReply>;
+
+ Future<CreateContextReply> CreateContext(const CreateContextRequest& request);
+
+ Future<CreateContextReply> CreateContext(const uint32_t& screen = {},
+ const uint32_t& visual = {},
+ const uint32_t& context = {});
+
+ struct DestroyContextRequest {
+ uint32_t screen{};
+ uint32_t context{};
+ };
+
+ using DestroyContextResponse = Response<void>;
+
+ Future<void> DestroyContext(const DestroyContextRequest& request);
+
+ Future<void> DestroyContext(const uint32_t& screen = {},
+ const uint32_t& context = {});
+
+ struct CreateDrawableRequest {
+ uint32_t screen{};
+ uint32_t drawable{};
+ };
+
+ struct CreateDrawableReply {
+ uint16_t sequence{};
+ uint32_t hw_drawable_handle{};
+ };
+
+ using CreateDrawableResponse = Response<CreateDrawableReply>;
+
+ Future<CreateDrawableReply> CreateDrawable(
+ const CreateDrawableRequest& request);
+
+ Future<CreateDrawableReply> CreateDrawable(const uint32_t& screen = {},
+ const uint32_t& drawable = {});
+
+ struct DestroyDrawableRequest {
+ uint32_t screen{};
+ uint32_t drawable{};
+ };
+
+ using DestroyDrawableResponse = Response<void>;
+
+ Future<void> DestroyDrawable(const DestroyDrawableRequest& request);
+
+ Future<void> DestroyDrawable(const uint32_t& screen = {},
+ const uint32_t& drawable = {});
+
+ struct GetDrawableInfoRequest {
+ uint32_t screen{};
+ uint32_t drawable{};
+ };
+
+ struct GetDrawableInfoReply {
+ uint16_t sequence{};
+ uint32_t drawable_table_index{};
+ uint32_t drawable_table_stamp{};
+ int16_t drawable_origin_X{};
+ int16_t drawable_origin_Y{};
+ int16_t drawable_size_W{};
+ int16_t drawable_size_H{};
+ int16_t back_x{};
+ int16_t back_y{};
+ std::vector<DrmClipRect> clip_rects{};
+ std::vector<DrmClipRect> back_clip_rects{};
+ };
+
+ using GetDrawableInfoResponse = Response<GetDrawableInfoReply>;
+
+ Future<GetDrawableInfoReply> GetDrawableInfo(
+ const GetDrawableInfoRequest& request);
+
+ Future<GetDrawableInfoReply> GetDrawableInfo(const uint32_t& screen = {},
+ const uint32_t& drawable = {});
+
+ struct GetDeviceInfoRequest {
+ uint32_t screen{};
+ };
+
+ struct GetDeviceInfoReply {
+ uint16_t sequence{};
+ uint32_t framebuffer_handle_low{};
+ uint32_t framebuffer_handle_high{};
+ uint32_t framebuffer_origin_offset{};
+ uint32_t framebuffer_size{};
+ uint32_t framebuffer_stride{};
+ std::vector<uint32_t> device_private{};
+ };
+
+ using GetDeviceInfoResponse = Response<GetDeviceInfoReply>;
+
+ Future<GetDeviceInfoReply> GetDeviceInfo(const GetDeviceInfoRequest& request);
+
+ Future<GetDeviceInfoReply> GetDeviceInfo(const uint32_t& screen = {});
+
+ struct AuthConnectionRequest {
+ uint32_t screen{};
+ uint32_t magic{};
+ };
+
+ struct AuthConnectionReply {
+ uint16_t sequence{};
+ uint32_t authenticated{};
+ };
+
+ using AuthConnectionResponse = Response<AuthConnectionReply>;
+
+ Future<AuthConnectionReply> AuthConnection(
+ const AuthConnectionRequest& request);
+
+ Future<AuthConnectionReply> AuthConnection(const uint32_t& screen = {},
+ const uint32_t& magic = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XF86DRI_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xf86vidmode.cc b/chromium/ui/gfx/x/generated_protos/xf86vidmode.cc
new file mode 100644
index 00000000000..c08c3363d73
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xf86vidmode.cc
@@ -0,0 +1,2197 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xf86vidmode.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+XF86VidMode::XF86VidMode(Connection* connection,
+ const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+std::string XF86VidMode::BadClockError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "XF86VidMode::BadClockError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<XF86VidMode::BadClockError>(XF86VidMode::BadClockError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string XF86VidMode::BadHTimingsError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "XF86VidMode::BadHTimingsError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<XF86VidMode::BadHTimingsError>(
+ XF86VidMode::BadHTimingsError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string XF86VidMode::BadVTimingsError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "XF86VidMode::BadVTimingsError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<XF86VidMode::BadVTimingsError>(
+ XF86VidMode::BadVTimingsError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string XF86VidMode::ModeUnsuitableError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "XF86VidMode::ModeUnsuitableError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<XF86VidMode::ModeUnsuitableError>(
+ XF86VidMode::ModeUnsuitableError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string XF86VidMode::ExtensionDisabledError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "XF86VidMode::ExtensionDisabledError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<XF86VidMode::ExtensionDisabledError>(
+ XF86VidMode::ExtensionDisabledError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string XF86VidMode::ClientNotLocalError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "XF86VidMode::ClientNotLocalError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<XF86VidMode::ClientNotLocalError>(
+ XF86VidMode::ClientNotLocalError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string XF86VidMode::ZoomLockedError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "XF86VidMode::ZoomLockedError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<XF86VidMode::ZoomLockedError>(
+ XF86VidMode::ZoomLockedError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+Future<XF86VidMode::QueryVersionReply> XF86VidMode::QueryVersion(
+ const XF86VidMode::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86VidMode::QueryVersionReply>(
+ &buf, "XF86VidMode::QueryVersion", false);
+}
+
+Future<XF86VidMode::QueryVersionReply> XF86VidMode::QueryVersion() {
+ return XF86VidMode::QueryVersion(XF86VidMode::QueryVersionRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86VidMode::QueryVersionReply> detail::ReadReply<
+ XF86VidMode::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86VidMode::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XF86VidMode::GetModeLineReply> XF86VidMode::GetModeLine(
+ const XF86VidMode::GetModeLineRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86VidMode::GetModeLineReply>(
+ &buf, "XF86VidMode::GetModeLine", false);
+}
+
+Future<XF86VidMode::GetModeLineReply> XF86VidMode::GetModeLine(
+ const uint16_t& screen) {
+ return XF86VidMode::GetModeLine(XF86VidMode::GetModeLineRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86VidMode::GetModeLineReply> detail::ReadReply<
+ XF86VidMode::GetModeLineReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86VidMode::GetModeLineReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& dotclock = (*reply).dotclock;
+ auto& hdisplay = (*reply).hdisplay;
+ auto& hsyncstart = (*reply).hsyncstart;
+ auto& hsyncend = (*reply).hsyncend;
+ auto& htotal = (*reply).htotal;
+ auto& hskew = (*reply).hskew;
+ auto& vdisplay = (*reply).vdisplay;
+ auto& vsyncstart = (*reply).vsyncstart;
+ auto& vsyncend = (*reply).vsyncend;
+ auto& vtotal = (*reply).vtotal;
+ auto& flags = (*reply).flags;
+ uint32_t privsize{};
+ auto& c_private = (*reply).c_private;
+ size_t c_private_len = c_private.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // dotclock
+ Read(&dotclock, &buf);
+
+ // hdisplay
+ Read(&hdisplay, &buf);
+
+ // hsyncstart
+ Read(&hsyncstart, &buf);
+
+ // hsyncend
+ Read(&hsyncend, &buf);
+
+ // htotal
+ Read(&htotal, &buf);
+
+ // hskew
+ Read(&hskew, &buf);
+
+ // vdisplay
+ Read(&vdisplay, &buf);
+
+ // vsyncstart
+ Read(&vsyncstart, &buf);
+
+ // vsyncend
+ Read(&vsyncend, &buf);
+
+ // vtotal
+ Read(&vtotal, &buf);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // flags
+ uint32_t tmp0;
+ Read(&tmp0, &buf);
+ flags = static_cast<XF86VidMode::ModeFlag>(tmp0);
+
+ // pad2
+ Pad(&buf, 12);
+
+ // privsize
+ Read(&privsize, &buf);
+
+ // c_private
+ c_private.resize(privsize);
+ for (auto& c_private_elem : c_private) {
+ // c_private_elem
+ Read(&c_private_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XF86VidMode::ModModeLine(
+ const XF86VidMode::ModModeLineRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& hdisplay = request.hdisplay;
+ auto& hsyncstart = request.hsyncstart;
+ auto& hsyncend = request.hsyncend;
+ auto& htotal = request.htotal;
+ auto& hskew = request.hskew;
+ auto& vdisplay = request.vdisplay;
+ auto& vsyncstart = request.vsyncstart;
+ auto& vsyncend = request.vsyncend;
+ auto& vtotal = request.vtotal;
+ auto& flags = request.flags;
+ uint32_t privsize{};
+ auto& c_private = request.c_private;
+ size_t c_private_len = c_private.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // hdisplay
+ buf.Write(&hdisplay);
+
+ // hsyncstart
+ buf.Write(&hsyncstart);
+
+ // hsyncend
+ buf.Write(&hsyncend);
+
+ // htotal
+ buf.Write(&htotal);
+
+ // hskew
+ buf.Write(&hskew);
+
+ // vdisplay
+ buf.Write(&vdisplay);
+
+ // vsyncstart
+ buf.Write(&vsyncstart);
+
+ // vsyncend
+ buf.Write(&vsyncend);
+
+ // vtotal
+ buf.Write(&vtotal);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // flags
+ uint32_t tmp1;
+ tmp1 = static_cast<uint32_t>(flags);
+ buf.Write(&tmp1);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // privsize
+ privsize = c_private.size();
+ buf.Write(&privsize);
+
+ // c_private
+ DCHECK_EQ(static_cast<size_t>(privsize), c_private.size());
+ for (auto& c_private_elem : c_private) {
+ // c_private_elem
+ buf.Write(&c_private_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86VidMode::ModModeLine",
+ false);
+}
+
+Future<void> XF86VidMode::ModModeLine(const uint32_t& screen,
+ const uint16_t& hdisplay,
+ const uint16_t& hsyncstart,
+ const uint16_t& hsyncend,
+ const uint16_t& htotal,
+ const uint16_t& hskew,
+ const uint16_t& vdisplay,
+ const uint16_t& vsyncstart,
+ const uint16_t& vsyncend,
+ const uint16_t& vtotal,
+ const ModeFlag& flags,
+ const std::vector<uint8_t>& c_private) {
+ return XF86VidMode::ModModeLine(XF86VidMode::ModModeLineRequest{
+ screen, hdisplay, hsyncstart, hsyncend, htotal, hskew, vdisplay,
+ vsyncstart, vsyncend, vtotal, flags, c_private});
+}
+
+Future<void> XF86VidMode::SwitchMode(
+ const XF86VidMode::SwitchModeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& zoom = request.zoom;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // zoom
+ buf.Write(&zoom);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86VidMode::SwitchMode", false);
+}
+
+Future<void> XF86VidMode::SwitchMode(const uint16_t& screen,
+ const uint16_t& zoom) {
+ return XF86VidMode::SwitchMode(XF86VidMode::SwitchModeRequest{screen, zoom});
+}
+
+Future<XF86VidMode::GetMonitorReply> XF86VidMode::GetMonitor(
+ const XF86VidMode::GetMonitorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86VidMode::GetMonitorReply>(
+ &buf, "XF86VidMode::GetMonitor", false);
+}
+
+Future<XF86VidMode::GetMonitorReply> XF86VidMode::GetMonitor(
+ const uint16_t& screen) {
+ return XF86VidMode::GetMonitor(XF86VidMode::GetMonitorRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86VidMode::GetMonitorReply> detail::ReadReply<
+ XF86VidMode::GetMonitorReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86VidMode::GetMonitorReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint8_t vendor_length{};
+ uint8_t model_length{};
+ uint8_t num_hsync{};
+ uint8_t num_vsync{};
+ auto& hsync = (*reply).hsync;
+ size_t hsync_len = hsync.size();
+ auto& vsync = (*reply).vsync;
+ size_t vsync_len = vsync.size();
+ auto& vendor = (*reply).vendor;
+ size_t vendor_len = vendor.size();
+ auto& alignment_pad = (*reply).alignment_pad;
+ size_t alignment_pad_len = alignment_pad ? alignment_pad->size() : 0;
+ auto& model = (*reply).model;
+ size_t model_len = model.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // vendor_length
+ Read(&vendor_length, &buf);
+
+ // model_length
+ Read(&model_length, &buf);
+
+ // num_hsync
+ Read(&num_hsync, &buf);
+
+ // num_vsync
+ Read(&num_vsync, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // hsync
+ hsync.resize(num_hsync);
+ for (auto& hsync_elem : hsync) {
+ // hsync_elem
+ Read(&hsync_elem, &buf);
+ }
+
+ // vsync
+ vsync.resize(num_vsync);
+ for (auto& vsync_elem : vsync) {
+ // vsync_elem
+ Read(&vsync_elem, &buf);
+ }
+
+ // vendor
+ vendor.resize(vendor_length);
+ for (auto& vendor_elem : vendor) {
+ // vendor_elem
+ Read(&vendor_elem, &buf);
+ }
+
+ // alignment_pad
+ alignment_pad = buffer->ReadAndAdvance(
+ (BitAnd((vendor_length) + (3), BitNot(3))) - (vendor_length));
+
+ // model
+ model.resize(model_length);
+ for (auto& model_elem : model) {
+ // model_elem
+ Read(&model_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XF86VidMode::LockModeSwitch(
+ const XF86VidMode::LockModeSwitchRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& lock = request.lock;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // lock
+ buf.Write(&lock);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86VidMode::LockModeSwitch",
+ false);
+}
+
+Future<void> XF86VidMode::LockModeSwitch(const uint16_t& screen,
+ const uint16_t& lock) {
+ return XF86VidMode::LockModeSwitch(
+ XF86VidMode::LockModeSwitchRequest{screen, lock});
+}
+
+Future<XF86VidMode::GetAllModeLinesReply> XF86VidMode::GetAllModeLines(
+ const XF86VidMode::GetAllModeLinesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86VidMode::GetAllModeLinesReply>(
+ &buf, "XF86VidMode::GetAllModeLines", false);
+}
+
+Future<XF86VidMode::GetAllModeLinesReply> XF86VidMode::GetAllModeLines(
+ const uint16_t& screen) {
+ return XF86VidMode::GetAllModeLines(
+ XF86VidMode::GetAllModeLinesRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86VidMode::GetAllModeLinesReply> detail::ReadReply<
+ XF86VidMode::GetAllModeLinesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86VidMode::GetAllModeLinesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t modecount{};
+ auto& modeinfo = (*reply).modeinfo;
+ size_t modeinfo_len = modeinfo.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // modecount
+ Read(&modecount, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // modeinfo
+ modeinfo.resize(modecount);
+ for (auto& modeinfo_elem : modeinfo) {
+ // modeinfo_elem
+ {
+ auto& dotclock = modeinfo_elem.dotclock;
+ auto& hdisplay = modeinfo_elem.hdisplay;
+ auto& hsyncstart = modeinfo_elem.hsyncstart;
+ auto& hsyncend = modeinfo_elem.hsyncend;
+ auto& htotal = modeinfo_elem.htotal;
+ auto& hskew = modeinfo_elem.hskew;
+ auto& vdisplay = modeinfo_elem.vdisplay;
+ auto& vsyncstart = modeinfo_elem.vsyncstart;
+ auto& vsyncend = modeinfo_elem.vsyncend;
+ auto& vtotal = modeinfo_elem.vtotal;
+ auto& flags = modeinfo_elem.flags;
+ auto& privsize = modeinfo_elem.privsize;
+
+ // dotclock
+ Read(&dotclock, &buf);
+
+ // hdisplay
+ Read(&hdisplay, &buf);
+
+ // hsyncstart
+ Read(&hsyncstart, &buf);
+
+ // hsyncend
+ Read(&hsyncend, &buf);
+
+ // htotal
+ Read(&htotal, &buf);
+
+ // hskew
+ Read(&hskew, &buf);
+
+ // vdisplay
+ Read(&vdisplay, &buf);
+
+ // vsyncstart
+ Read(&vsyncstart, &buf);
+
+ // vsyncend
+ Read(&vsyncend, &buf);
+
+ // vtotal
+ Read(&vtotal, &buf);
+
+ // pad0
+ Pad(&buf, 4);
+
+ // flags
+ uint32_t tmp2;
+ Read(&tmp2, &buf);
+ flags = static_cast<XF86VidMode::ModeFlag>(tmp2);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // privsize
+ Read(&privsize, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XF86VidMode::AddModeLine(
+ const XF86VidMode::AddModeLineRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& dotclock = request.dotclock;
+ auto& hdisplay = request.hdisplay;
+ auto& hsyncstart = request.hsyncstart;
+ auto& hsyncend = request.hsyncend;
+ auto& htotal = request.htotal;
+ auto& hskew = request.hskew;
+ auto& vdisplay = request.vdisplay;
+ auto& vsyncstart = request.vsyncstart;
+ auto& vsyncend = request.vsyncend;
+ auto& vtotal = request.vtotal;
+ auto& flags = request.flags;
+ uint32_t privsize{};
+ auto& after_dotclock = request.after_dotclock;
+ auto& after_hdisplay = request.after_hdisplay;
+ auto& after_hsyncstart = request.after_hsyncstart;
+ auto& after_hsyncend = request.after_hsyncend;
+ auto& after_htotal = request.after_htotal;
+ auto& after_hskew = request.after_hskew;
+ auto& after_vdisplay = request.after_vdisplay;
+ auto& after_vsyncstart = request.after_vsyncstart;
+ auto& after_vsyncend = request.after_vsyncend;
+ auto& after_vtotal = request.after_vtotal;
+ auto& after_flags = request.after_flags;
+ auto& c_private = request.c_private;
+ size_t c_private_len = c_private.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // dotclock
+ buf.Write(&dotclock);
+
+ // hdisplay
+ buf.Write(&hdisplay);
+
+ // hsyncstart
+ buf.Write(&hsyncstart);
+
+ // hsyncend
+ buf.Write(&hsyncend);
+
+ // htotal
+ buf.Write(&htotal);
+
+ // hskew
+ buf.Write(&hskew);
+
+ // vdisplay
+ buf.Write(&vdisplay);
+
+ // vsyncstart
+ buf.Write(&vsyncstart);
+
+ // vsyncend
+ buf.Write(&vsyncend);
+
+ // vtotal
+ buf.Write(&vtotal);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // flags
+ uint32_t tmp3;
+ tmp3 = static_cast<uint32_t>(flags);
+ buf.Write(&tmp3);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // privsize
+ privsize = c_private.size();
+ buf.Write(&privsize);
+
+ // after_dotclock
+ buf.Write(&after_dotclock);
+
+ // after_hdisplay
+ buf.Write(&after_hdisplay);
+
+ // after_hsyncstart
+ buf.Write(&after_hsyncstart);
+
+ // after_hsyncend
+ buf.Write(&after_hsyncend);
+
+ // after_htotal
+ buf.Write(&after_htotal);
+
+ // after_hskew
+ buf.Write(&after_hskew);
+
+ // after_vdisplay
+ buf.Write(&after_vdisplay);
+
+ // after_vsyncstart
+ buf.Write(&after_vsyncstart);
+
+ // after_vsyncend
+ buf.Write(&after_vsyncend);
+
+ // after_vtotal
+ buf.Write(&after_vtotal);
+
+ // pad2
+ Pad(&buf, 2);
+
+ // after_flags
+ uint32_t tmp4;
+ tmp4 = static_cast<uint32_t>(after_flags);
+ buf.Write(&tmp4);
+
+ // pad3
+ Pad(&buf, 12);
+
+ // c_private
+ DCHECK_EQ(static_cast<size_t>(privsize), c_private.size());
+ for (auto& c_private_elem : c_private) {
+ // c_private_elem
+ buf.Write(&c_private_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86VidMode::AddModeLine",
+ false);
+}
+
+Future<void> XF86VidMode::AddModeLine(const uint32_t& screen,
+ const DotClock& dotclock,
+ const uint16_t& hdisplay,
+ const uint16_t& hsyncstart,
+ const uint16_t& hsyncend,
+ const uint16_t& htotal,
+ const uint16_t& hskew,
+ const uint16_t& vdisplay,
+ const uint16_t& vsyncstart,
+ const uint16_t& vsyncend,
+ const uint16_t& vtotal,
+ const ModeFlag& flags,
+ const DotClock& after_dotclock,
+ const uint16_t& after_hdisplay,
+ const uint16_t& after_hsyncstart,
+ const uint16_t& after_hsyncend,
+ const uint16_t& after_htotal,
+ const uint16_t& after_hskew,
+ const uint16_t& after_vdisplay,
+ const uint16_t& after_vsyncstart,
+ const uint16_t& after_vsyncend,
+ const uint16_t& after_vtotal,
+ const ModeFlag& after_flags,
+ const std::vector<uint8_t>& c_private) {
+ return XF86VidMode::AddModeLine(XF86VidMode::AddModeLineRequest{
+ screen, dotclock, hdisplay,
+ hsyncstart, hsyncend, htotal,
+ hskew, vdisplay, vsyncstart,
+ vsyncend, vtotal, flags,
+ after_dotclock, after_hdisplay, after_hsyncstart,
+ after_hsyncend, after_htotal, after_hskew,
+ after_vdisplay, after_vsyncstart, after_vsyncend,
+ after_vtotal, after_flags, c_private});
+}
+
+Future<void> XF86VidMode::DeleteModeLine(
+ const XF86VidMode::DeleteModeLineRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& dotclock = request.dotclock;
+ auto& hdisplay = request.hdisplay;
+ auto& hsyncstart = request.hsyncstart;
+ auto& hsyncend = request.hsyncend;
+ auto& htotal = request.htotal;
+ auto& hskew = request.hskew;
+ auto& vdisplay = request.vdisplay;
+ auto& vsyncstart = request.vsyncstart;
+ auto& vsyncend = request.vsyncend;
+ auto& vtotal = request.vtotal;
+ auto& flags = request.flags;
+ uint32_t privsize{};
+ auto& c_private = request.c_private;
+ size_t c_private_len = c_private.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // dotclock
+ buf.Write(&dotclock);
+
+ // hdisplay
+ buf.Write(&hdisplay);
+
+ // hsyncstart
+ buf.Write(&hsyncstart);
+
+ // hsyncend
+ buf.Write(&hsyncend);
+
+ // htotal
+ buf.Write(&htotal);
+
+ // hskew
+ buf.Write(&hskew);
+
+ // vdisplay
+ buf.Write(&vdisplay);
+
+ // vsyncstart
+ buf.Write(&vsyncstart);
+
+ // vsyncend
+ buf.Write(&vsyncend);
+
+ // vtotal
+ buf.Write(&vtotal);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // flags
+ uint32_t tmp5;
+ tmp5 = static_cast<uint32_t>(flags);
+ buf.Write(&tmp5);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // privsize
+ privsize = c_private.size();
+ buf.Write(&privsize);
+
+ // c_private
+ DCHECK_EQ(static_cast<size_t>(privsize), c_private.size());
+ for (auto& c_private_elem : c_private) {
+ // c_private_elem
+ buf.Write(&c_private_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86VidMode::DeleteModeLine",
+ false);
+}
+
+Future<void> XF86VidMode::DeleteModeLine(
+ const uint32_t& screen,
+ const DotClock& dotclock,
+ const uint16_t& hdisplay,
+ const uint16_t& hsyncstart,
+ const uint16_t& hsyncend,
+ const uint16_t& htotal,
+ const uint16_t& hskew,
+ const uint16_t& vdisplay,
+ const uint16_t& vsyncstart,
+ const uint16_t& vsyncend,
+ const uint16_t& vtotal,
+ const ModeFlag& flags,
+ const std::vector<uint8_t>& c_private) {
+ return XF86VidMode::DeleteModeLine(XF86VidMode::DeleteModeLineRequest{
+ screen, dotclock, hdisplay, hsyncstart, hsyncend, htotal, hskew, vdisplay,
+ vsyncstart, vsyncend, vtotal, flags, c_private});
+}
+
+Future<XF86VidMode::ValidateModeLineReply> XF86VidMode::ValidateModeLine(
+ const XF86VidMode::ValidateModeLineRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& dotclock = request.dotclock;
+ auto& hdisplay = request.hdisplay;
+ auto& hsyncstart = request.hsyncstart;
+ auto& hsyncend = request.hsyncend;
+ auto& htotal = request.htotal;
+ auto& hskew = request.hskew;
+ auto& vdisplay = request.vdisplay;
+ auto& vsyncstart = request.vsyncstart;
+ auto& vsyncend = request.vsyncend;
+ auto& vtotal = request.vtotal;
+ auto& flags = request.flags;
+ uint32_t privsize{};
+ auto& c_private = request.c_private;
+ size_t c_private_len = c_private.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // dotclock
+ buf.Write(&dotclock);
+
+ // hdisplay
+ buf.Write(&hdisplay);
+
+ // hsyncstart
+ buf.Write(&hsyncstart);
+
+ // hsyncend
+ buf.Write(&hsyncend);
+
+ // htotal
+ buf.Write(&htotal);
+
+ // hskew
+ buf.Write(&hskew);
+
+ // vdisplay
+ buf.Write(&vdisplay);
+
+ // vsyncstart
+ buf.Write(&vsyncstart);
+
+ // vsyncend
+ buf.Write(&vsyncend);
+
+ // vtotal
+ buf.Write(&vtotal);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // flags
+ uint32_t tmp6;
+ tmp6 = static_cast<uint32_t>(flags);
+ buf.Write(&tmp6);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // privsize
+ privsize = c_private.size();
+ buf.Write(&privsize);
+
+ // c_private
+ DCHECK_EQ(static_cast<size_t>(privsize), c_private.size());
+ for (auto& c_private_elem : c_private) {
+ // c_private_elem
+ buf.Write(&c_private_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86VidMode::ValidateModeLineReply>(
+ &buf, "XF86VidMode::ValidateModeLine", false);
+}
+
+Future<XF86VidMode::ValidateModeLineReply> XF86VidMode::ValidateModeLine(
+ const uint32_t& screen,
+ const DotClock& dotclock,
+ const uint16_t& hdisplay,
+ const uint16_t& hsyncstart,
+ const uint16_t& hsyncend,
+ const uint16_t& htotal,
+ const uint16_t& hskew,
+ const uint16_t& vdisplay,
+ const uint16_t& vsyncstart,
+ const uint16_t& vsyncend,
+ const uint16_t& vtotal,
+ const ModeFlag& flags,
+ const std::vector<uint8_t>& c_private) {
+ return XF86VidMode::ValidateModeLine(XF86VidMode::ValidateModeLineRequest{
+ screen, dotclock, hdisplay, hsyncstart, hsyncend, htotal, hskew, vdisplay,
+ vsyncstart, vsyncend, vtotal, flags, c_private});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86VidMode::ValidateModeLineReply> detail::ReadReply<
+ XF86VidMode::ValidateModeLineReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86VidMode::ValidateModeLineReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& status = (*reply).status;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status
+ Read(&status, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XF86VidMode::SwitchToMode(
+ const XF86VidMode::SwitchToModeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& dotclock = request.dotclock;
+ auto& hdisplay = request.hdisplay;
+ auto& hsyncstart = request.hsyncstart;
+ auto& hsyncend = request.hsyncend;
+ auto& htotal = request.htotal;
+ auto& hskew = request.hskew;
+ auto& vdisplay = request.vdisplay;
+ auto& vsyncstart = request.vsyncstart;
+ auto& vsyncend = request.vsyncend;
+ auto& vtotal = request.vtotal;
+ auto& flags = request.flags;
+ uint32_t privsize{};
+ auto& c_private = request.c_private;
+ size_t c_private_len = c_private.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // dotclock
+ buf.Write(&dotclock);
+
+ // hdisplay
+ buf.Write(&hdisplay);
+
+ // hsyncstart
+ buf.Write(&hsyncstart);
+
+ // hsyncend
+ buf.Write(&hsyncend);
+
+ // htotal
+ buf.Write(&htotal);
+
+ // hskew
+ buf.Write(&hskew);
+
+ // vdisplay
+ buf.Write(&vdisplay);
+
+ // vsyncstart
+ buf.Write(&vsyncstart);
+
+ // vsyncend
+ buf.Write(&vsyncend);
+
+ // vtotal
+ buf.Write(&vtotal);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // flags
+ uint32_t tmp7;
+ tmp7 = static_cast<uint32_t>(flags);
+ buf.Write(&tmp7);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // privsize
+ privsize = c_private.size();
+ buf.Write(&privsize);
+
+ // c_private
+ DCHECK_EQ(static_cast<size_t>(privsize), c_private.size());
+ for (auto& c_private_elem : c_private) {
+ // c_private_elem
+ buf.Write(&c_private_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86VidMode::SwitchToMode",
+ false);
+}
+
+Future<void> XF86VidMode::SwitchToMode(const uint32_t& screen,
+ const DotClock& dotclock,
+ const uint16_t& hdisplay,
+ const uint16_t& hsyncstart,
+ const uint16_t& hsyncend,
+ const uint16_t& htotal,
+ const uint16_t& hskew,
+ const uint16_t& vdisplay,
+ const uint16_t& vsyncstart,
+ const uint16_t& vsyncend,
+ const uint16_t& vtotal,
+ const ModeFlag& flags,
+ const std::vector<uint8_t>& c_private) {
+ return XF86VidMode::SwitchToMode(XF86VidMode::SwitchToModeRequest{
+ screen, dotclock, hdisplay, hsyncstart, hsyncend, htotal, hskew, vdisplay,
+ vsyncstart, vsyncend, vtotal, flags, c_private});
+}
+
+Future<XF86VidMode::GetViewPortReply> XF86VidMode::GetViewPort(
+ const XF86VidMode::GetViewPortRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86VidMode::GetViewPortReply>(
+ &buf, "XF86VidMode::GetViewPort", false);
+}
+
+Future<XF86VidMode::GetViewPortReply> XF86VidMode::GetViewPort(
+ const uint16_t& screen) {
+ return XF86VidMode::GetViewPort(XF86VidMode::GetViewPortRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86VidMode::GetViewPortReply> detail::ReadReply<
+ XF86VidMode::GetViewPortReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86VidMode::GetViewPortReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& x = (*reply).x;
+ auto& y = (*reply).y;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XF86VidMode::SetViewPort(
+ const XF86VidMode::SetViewPortRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& x = request.x;
+ auto& y = request.y;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86VidMode::SetViewPort",
+ false);
+}
+
+Future<void> XF86VidMode::SetViewPort(const uint16_t& screen,
+ const uint32_t& x,
+ const uint32_t& y) {
+ return XF86VidMode::SetViewPort(
+ XF86VidMode::SetViewPortRequest{screen, x, y});
+}
+
+Future<XF86VidMode::GetDotClocksReply> XF86VidMode::GetDotClocks(
+ const XF86VidMode::GetDotClocksRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86VidMode::GetDotClocksReply>(
+ &buf, "XF86VidMode::GetDotClocks", false);
+}
+
+Future<XF86VidMode::GetDotClocksReply> XF86VidMode::GetDotClocks(
+ const uint16_t& screen) {
+ return XF86VidMode::GetDotClocks(XF86VidMode::GetDotClocksRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86VidMode::GetDotClocksReply> detail::ReadReply<
+ XF86VidMode::GetDotClocksReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86VidMode::GetDotClocksReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& flags = (*reply).flags;
+ auto& clocks = (*reply).clocks;
+ auto& maxclocks = (*reply).maxclocks;
+ auto& clock = (*reply).clock;
+ size_t clock_len = clock.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // flags
+ uint32_t tmp8;
+ Read(&tmp8, &buf);
+ flags = static_cast<XF86VidMode::ClockFlag>(tmp8);
+
+ // clocks
+ Read(&clocks, &buf);
+
+ // maxclocks
+ Read(&maxclocks, &buf);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // clock
+ clock.resize(((1) - (BitAnd(flags, 1))) * (clocks));
+ for (auto& clock_elem : clock) {
+ // clock_elem
+ Read(&clock_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XF86VidMode::SetClientVersion(
+ const XF86VidMode::SetClientVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major = request.major;
+ auto& minor = request.minor;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 14;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major
+ buf.Write(&major);
+
+ // minor
+ buf.Write(&minor);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86VidMode::SetClientVersion",
+ false);
+}
+
+Future<void> XF86VidMode::SetClientVersion(const uint16_t& major,
+ const uint16_t& minor) {
+ return XF86VidMode::SetClientVersion(
+ XF86VidMode::SetClientVersionRequest{major, minor});
+}
+
+Future<void> XF86VidMode::SetGamma(
+ const XF86VidMode::SetGammaRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& red = request.red;
+ auto& green = request.green;
+ auto& blue = request.blue;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 15;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // red
+ buf.Write(&red);
+
+ // green
+ buf.Write(&green);
+
+ // blue
+ buf.Write(&blue);
+
+ // pad1
+ Pad(&buf, 12);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86VidMode::SetGamma", false);
+}
+
+Future<void> XF86VidMode::SetGamma(const uint16_t& screen,
+ const uint32_t& red,
+ const uint32_t& green,
+ const uint32_t& blue) {
+ return XF86VidMode::SetGamma(
+ XF86VidMode::SetGammaRequest{screen, red, green, blue});
+}
+
+Future<XF86VidMode::GetGammaReply> XF86VidMode::GetGamma(
+ const XF86VidMode::GetGammaRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 16;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // pad0
+ Pad(&buf, 26);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86VidMode::GetGammaReply>(
+ &buf, "XF86VidMode::GetGamma", false);
+}
+
+Future<XF86VidMode::GetGammaReply> XF86VidMode::GetGamma(
+ const uint16_t& screen) {
+ return XF86VidMode::GetGamma(XF86VidMode::GetGammaRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86VidMode::GetGammaReply> detail::ReadReply<
+ XF86VidMode::GetGammaReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86VidMode::GetGammaReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& red = (*reply).red;
+ auto& green = (*reply).green;
+ auto& blue = (*reply).blue;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // red
+ Read(&red, &buf);
+
+ // green
+ Read(&green, &buf);
+
+ // blue
+ Read(&blue, &buf);
+
+ // pad1
+ Pad(&buf, 12);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XF86VidMode::GetGammaRampReply> XF86VidMode::GetGammaRamp(
+ const XF86VidMode::GetGammaRampRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& size = request.size;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 17;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // size
+ buf.Write(&size);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86VidMode::GetGammaRampReply>(
+ &buf, "XF86VidMode::GetGammaRamp", false);
+}
+
+Future<XF86VidMode::GetGammaRampReply> XF86VidMode::GetGammaRamp(
+ const uint16_t& screen,
+ const uint16_t& size) {
+ return XF86VidMode::GetGammaRamp(
+ XF86VidMode::GetGammaRampRequest{screen, size});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86VidMode::GetGammaRampReply> detail::ReadReply<
+ XF86VidMode::GetGammaRampReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86VidMode::GetGammaRampReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& size = (*reply).size;
+ auto& red = (*reply).red;
+ size_t red_len = red.size();
+ auto& green = (*reply).green;
+ size_t green_len = green.size();
+ auto& blue = (*reply).blue;
+ size_t blue_len = blue.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // size
+ Read(&size, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // red
+ red.resize(BitAnd((size) + (1), BitNot(1)));
+ for (auto& red_elem : red) {
+ // red_elem
+ Read(&red_elem, &buf);
+ }
+
+ // green
+ green.resize(BitAnd((size) + (1), BitNot(1)));
+ for (auto& green_elem : green) {
+ // green_elem
+ Read(&green_elem, &buf);
+ }
+
+ // blue
+ blue.resize(BitAnd((size) + (1), BitNot(1)));
+ for (auto& blue_elem : blue) {
+ // blue_elem
+ Read(&blue_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XF86VidMode::SetGammaRamp(
+ const XF86VidMode::SetGammaRampRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+ auto& size = request.size;
+ auto& red = request.red;
+ size_t red_len = red.size();
+ auto& green = request.green;
+ size_t green_len = green.size();
+ auto& blue = request.blue;
+ size_t blue_len = blue.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 18;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // size
+ buf.Write(&size);
+
+ // red
+ DCHECK_EQ(static_cast<size_t>(BitAnd((size) + (1), BitNot(1))), red.size());
+ for (auto& red_elem : red) {
+ // red_elem
+ buf.Write(&red_elem);
+ }
+
+ // green
+ DCHECK_EQ(static_cast<size_t>(BitAnd((size) + (1), BitNot(1))), green.size());
+ for (auto& green_elem : green) {
+ // green_elem
+ buf.Write(&green_elem);
+ }
+
+ // blue
+ DCHECK_EQ(static_cast<size_t>(BitAnd((size) + (1), BitNot(1))), blue.size());
+ for (auto& blue_elem : blue) {
+ // blue_elem
+ buf.Write(&blue_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XF86VidMode::SetGammaRamp",
+ false);
+}
+
+Future<void> XF86VidMode::SetGammaRamp(const uint16_t& screen,
+ const uint16_t& size,
+ const std::vector<uint16_t>& red,
+ const std::vector<uint16_t>& green,
+ const std::vector<uint16_t>& blue) {
+ return XF86VidMode::SetGammaRamp(
+ XF86VidMode::SetGammaRampRequest{screen, size, red, green, blue});
+}
+
+Future<XF86VidMode::GetGammaRampSizeReply> XF86VidMode::GetGammaRampSize(
+ const XF86VidMode::GetGammaRampSizeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 19;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86VidMode::GetGammaRampSizeReply>(
+ &buf, "XF86VidMode::GetGammaRampSize", false);
+}
+
+Future<XF86VidMode::GetGammaRampSizeReply> XF86VidMode::GetGammaRampSize(
+ const uint16_t& screen) {
+ return XF86VidMode::GetGammaRampSize(
+ XF86VidMode::GetGammaRampSizeRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86VidMode::GetGammaRampSizeReply> detail::ReadReply<
+ XF86VidMode::GetGammaRampSizeReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86VidMode::GetGammaRampSizeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& size = (*reply).size;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // size
+ Read(&size, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XF86VidMode::GetPermissionsReply> XF86VidMode::GetPermissions(
+ const XF86VidMode::GetPermissionsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 20;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // screen
+ buf.Write(&screen);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XF86VidMode::GetPermissionsReply>(
+ &buf, "XF86VidMode::GetPermissions", false);
+}
+
+Future<XF86VidMode::GetPermissionsReply> XF86VidMode::GetPermissions(
+ const uint16_t& screen) {
+ return XF86VidMode::GetPermissions(
+ XF86VidMode::GetPermissionsRequest{screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XF86VidMode::GetPermissionsReply> detail::ReadReply<
+ XF86VidMode::GetPermissionsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XF86VidMode::GetPermissionsReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& permissions = (*reply).permissions;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // permissions
+ uint32_t tmp9;
+ Read(&tmp9, &buf);
+ permissions = static_cast<XF86VidMode::Permission>(tmp9);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xf86vidmode.h b/chromium/ui/gfx/x/generated_protos/xf86vidmode.h
new file mode 100644
index 00000000000..19e9bbbdc1d
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xf86vidmode.h
@@ -0,0 +1,683 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XF86VIDMODE_H_
+#define UI_GFX_X_GENERATED_PROTOS_XF86VIDMODE_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) XF86VidMode {
+ public:
+ static constexpr unsigned major_version = 2;
+ static constexpr unsigned minor_version = 2;
+
+ XF86VidMode(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Syncrange : uint32_t {};
+
+ enum class DotClock : uint32_t {};
+
+ enum class ModeFlag : int {
+ Positive_HSync = 1 << 0,
+ Negative_HSync = 1 << 1,
+ Positive_VSync = 1 << 2,
+ Negative_VSync = 1 << 3,
+ Interlace = 1 << 4,
+ Composite_Sync = 1 << 5,
+ Positive_CSync = 1 << 6,
+ Negative_CSync = 1 << 7,
+ HSkew = 1 << 8,
+ Broadcast = 1 << 9,
+ Pixmux = 1 << 10,
+ Double_Clock = 1 << 11,
+ Half_Clock = 1 << 12,
+ };
+
+ enum class ClockFlag : int {
+ Programable = 1 << 0,
+ };
+
+ enum class Permission : int {
+ Read = 1 << 0,
+ Write = 1 << 1,
+ };
+
+ struct ModeInfo {
+ DotClock dotclock{};
+ uint16_t hdisplay{};
+ uint16_t hsyncstart{};
+ uint16_t hsyncend{};
+ uint16_t htotal{};
+ uint32_t hskew{};
+ uint16_t vdisplay{};
+ uint16_t vsyncstart{};
+ uint16_t vsyncend{};
+ uint16_t vtotal{};
+ ModeFlag flags{};
+ uint32_t privsize{};
+ };
+
+ struct BadClockError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadHTimingsError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadVTimingsError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct ModeUnsuitableError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct ExtensionDisabledError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct ClientNotLocalError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct ZoomLockedError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct QueryVersionRequest {};
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint16_t major_version{};
+ uint16_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion();
+
+ struct GetModeLineRequest {
+ uint16_t screen{};
+ };
+
+ struct GetModeLineReply {
+ uint16_t sequence{};
+ DotClock dotclock{};
+ uint16_t hdisplay{};
+ uint16_t hsyncstart{};
+ uint16_t hsyncend{};
+ uint16_t htotal{};
+ uint16_t hskew{};
+ uint16_t vdisplay{};
+ uint16_t vsyncstart{};
+ uint16_t vsyncend{};
+ uint16_t vtotal{};
+ ModeFlag flags{};
+ std::vector<uint8_t> c_private{};
+ };
+
+ using GetModeLineResponse = Response<GetModeLineReply>;
+
+ Future<GetModeLineReply> GetModeLine(const GetModeLineRequest& request);
+
+ Future<GetModeLineReply> GetModeLine(const uint16_t& screen = {});
+
+ struct ModModeLineRequest {
+ uint32_t screen{};
+ uint16_t hdisplay{};
+ uint16_t hsyncstart{};
+ uint16_t hsyncend{};
+ uint16_t htotal{};
+ uint16_t hskew{};
+ uint16_t vdisplay{};
+ uint16_t vsyncstart{};
+ uint16_t vsyncend{};
+ uint16_t vtotal{};
+ ModeFlag flags{};
+ std::vector<uint8_t> c_private{};
+ };
+
+ using ModModeLineResponse = Response<void>;
+
+ Future<void> ModModeLine(const ModModeLineRequest& request);
+
+ Future<void> ModModeLine(const uint32_t& screen = {},
+ const uint16_t& hdisplay = {},
+ const uint16_t& hsyncstart = {},
+ const uint16_t& hsyncend = {},
+ const uint16_t& htotal = {},
+ const uint16_t& hskew = {},
+ const uint16_t& vdisplay = {},
+ const uint16_t& vsyncstart = {},
+ const uint16_t& vsyncend = {},
+ const uint16_t& vtotal = {},
+ const ModeFlag& flags = {},
+ const std::vector<uint8_t>& c_private = {});
+
+ struct SwitchModeRequest {
+ uint16_t screen{};
+ uint16_t zoom{};
+ };
+
+ using SwitchModeResponse = Response<void>;
+
+ Future<void> SwitchMode(const SwitchModeRequest& request);
+
+ Future<void> SwitchMode(const uint16_t& screen = {},
+ const uint16_t& zoom = {});
+
+ struct GetMonitorRequest {
+ uint16_t screen{};
+ };
+
+ struct GetMonitorReply {
+ uint16_t sequence{};
+ std::vector<Syncrange> hsync{};
+ std::vector<Syncrange> vsync{};
+ std::string vendor{};
+ scoped_refptr<base::RefCountedMemory> alignment_pad{};
+ std::string model{};
+ };
+
+ using GetMonitorResponse = Response<GetMonitorReply>;
+
+ Future<GetMonitorReply> GetMonitor(const GetMonitorRequest& request);
+
+ Future<GetMonitorReply> GetMonitor(const uint16_t& screen = {});
+
+ struct LockModeSwitchRequest {
+ uint16_t screen{};
+ uint16_t lock{};
+ };
+
+ using LockModeSwitchResponse = Response<void>;
+
+ Future<void> LockModeSwitch(const LockModeSwitchRequest& request);
+
+ Future<void> LockModeSwitch(const uint16_t& screen = {},
+ const uint16_t& lock = {});
+
+ struct GetAllModeLinesRequest {
+ uint16_t screen{};
+ };
+
+ struct GetAllModeLinesReply {
+ uint16_t sequence{};
+ std::vector<ModeInfo> modeinfo{};
+ };
+
+ using GetAllModeLinesResponse = Response<GetAllModeLinesReply>;
+
+ Future<GetAllModeLinesReply> GetAllModeLines(
+ const GetAllModeLinesRequest& request);
+
+ Future<GetAllModeLinesReply> GetAllModeLines(const uint16_t& screen = {});
+
+ struct AddModeLineRequest {
+ uint32_t screen{};
+ DotClock dotclock{};
+ uint16_t hdisplay{};
+ uint16_t hsyncstart{};
+ uint16_t hsyncend{};
+ uint16_t htotal{};
+ uint16_t hskew{};
+ uint16_t vdisplay{};
+ uint16_t vsyncstart{};
+ uint16_t vsyncend{};
+ uint16_t vtotal{};
+ ModeFlag flags{};
+ DotClock after_dotclock{};
+ uint16_t after_hdisplay{};
+ uint16_t after_hsyncstart{};
+ uint16_t after_hsyncend{};
+ uint16_t after_htotal{};
+ uint16_t after_hskew{};
+ uint16_t after_vdisplay{};
+ uint16_t after_vsyncstart{};
+ uint16_t after_vsyncend{};
+ uint16_t after_vtotal{};
+ ModeFlag after_flags{};
+ std::vector<uint8_t> c_private{};
+ };
+
+ using AddModeLineResponse = Response<void>;
+
+ Future<void> AddModeLine(const AddModeLineRequest& request);
+
+ Future<void> AddModeLine(const uint32_t& screen = {},
+ const DotClock& dotclock = {},
+ const uint16_t& hdisplay = {},
+ const uint16_t& hsyncstart = {},
+ const uint16_t& hsyncend = {},
+ const uint16_t& htotal = {},
+ const uint16_t& hskew = {},
+ const uint16_t& vdisplay = {},
+ const uint16_t& vsyncstart = {},
+ const uint16_t& vsyncend = {},
+ const uint16_t& vtotal = {},
+ const ModeFlag& flags = {},
+ const DotClock& after_dotclock = {},
+ const uint16_t& after_hdisplay = {},
+ const uint16_t& after_hsyncstart = {},
+ const uint16_t& after_hsyncend = {},
+ const uint16_t& after_htotal = {},
+ const uint16_t& after_hskew = {},
+ const uint16_t& after_vdisplay = {},
+ const uint16_t& after_vsyncstart = {},
+ const uint16_t& after_vsyncend = {},
+ const uint16_t& after_vtotal = {},
+ const ModeFlag& after_flags = {},
+ const std::vector<uint8_t>& c_private = {});
+
+ struct DeleteModeLineRequest {
+ uint32_t screen{};
+ DotClock dotclock{};
+ uint16_t hdisplay{};
+ uint16_t hsyncstart{};
+ uint16_t hsyncend{};
+ uint16_t htotal{};
+ uint16_t hskew{};
+ uint16_t vdisplay{};
+ uint16_t vsyncstart{};
+ uint16_t vsyncend{};
+ uint16_t vtotal{};
+ ModeFlag flags{};
+ std::vector<uint8_t> c_private{};
+ };
+
+ using DeleteModeLineResponse = Response<void>;
+
+ Future<void> DeleteModeLine(const DeleteModeLineRequest& request);
+
+ Future<void> DeleteModeLine(const uint32_t& screen = {},
+ const DotClock& dotclock = {},
+ const uint16_t& hdisplay = {},
+ const uint16_t& hsyncstart = {},
+ const uint16_t& hsyncend = {},
+ const uint16_t& htotal = {},
+ const uint16_t& hskew = {},
+ const uint16_t& vdisplay = {},
+ const uint16_t& vsyncstart = {},
+ const uint16_t& vsyncend = {},
+ const uint16_t& vtotal = {},
+ const ModeFlag& flags = {},
+ const std::vector<uint8_t>& c_private = {});
+
+ struct ValidateModeLineRequest {
+ uint32_t screen{};
+ DotClock dotclock{};
+ uint16_t hdisplay{};
+ uint16_t hsyncstart{};
+ uint16_t hsyncend{};
+ uint16_t htotal{};
+ uint16_t hskew{};
+ uint16_t vdisplay{};
+ uint16_t vsyncstart{};
+ uint16_t vsyncend{};
+ uint16_t vtotal{};
+ ModeFlag flags{};
+ std::vector<uint8_t> c_private{};
+ };
+
+ struct ValidateModeLineReply {
+ uint16_t sequence{};
+ uint32_t status{};
+ };
+
+ using ValidateModeLineResponse = Response<ValidateModeLineReply>;
+
+ Future<ValidateModeLineReply> ValidateModeLine(
+ const ValidateModeLineRequest& request);
+
+ Future<ValidateModeLineReply> ValidateModeLine(
+ const uint32_t& screen = {},
+ const DotClock& dotclock = {},
+ const uint16_t& hdisplay = {},
+ const uint16_t& hsyncstart = {},
+ const uint16_t& hsyncend = {},
+ const uint16_t& htotal = {},
+ const uint16_t& hskew = {},
+ const uint16_t& vdisplay = {},
+ const uint16_t& vsyncstart = {},
+ const uint16_t& vsyncend = {},
+ const uint16_t& vtotal = {},
+ const ModeFlag& flags = {},
+ const std::vector<uint8_t>& c_private = {});
+
+ struct SwitchToModeRequest {
+ uint32_t screen{};
+ DotClock dotclock{};
+ uint16_t hdisplay{};
+ uint16_t hsyncstart{};
+ uint16_t hsyncend{};
+ uint16_t htotal{};
+ uint16_t hskew{};
+ uint16_t vdisplay{};
+ uint16_t vsyncstart{};
+ uint16_t vsyncend{};
+ uint16_t vtotal{};
+ ModeFlag flags{};
+ std::vector<uint8_t> c_private{};
+ };
+
+ using SwitchToModeResponse = Response<void>;
+
+ Future<void> SwitchToMode(const SwitchToModeRequest& request);
+
+ Future<void> SwitchToMode(const uint32_t& screen = {},
+ const DotClock& dotclock = {},
+ const uint16_t& hdisplay = {},
+ const uint16_t& hsyncstart = {},
+ const uint16_t& hsyncend = {},
+ const uint16_t& htotal = {},
+ const uint16_t& hskew = {},
+ const uint16_t& vdisplay = {},
+ const uint16_t& vsyncstart = {},
+ const uint16_t& vsyncend = {},
+ const uint16_t& vtotal = {},
+ const ModeFlag& flags = {},
+ const std::vector<uint8_t>& c_private = {});
+
+ struct GetViewPortRequest {
+ uint16_t screen{};
+ };
+
+ struct GetViewPortReply {
+ uint16_t sequence{};
+ uint32_t x{};
+ uint32_t y{};
+ };
+
+ using GetViewPortResponse = Response<GetViewPortReply>;
+
+ Future<GetViewPortReply> GetViewPort(const GetViewPortRequest& request);
+
+ Future<GetViewPortReply> GetViewPort(const uint16_t& screen = {});
+
+ struct SetViewPortRequest {
+ uint16_t screen{};
+ uint32_t x{};
+ uint32_t y{};
+ };
+
+ using SetViewPortResponse = Response<void>;
+
+ Future<void> SetViewPort(const SetViewPortRequest& request);
+
+ Future<void> SetViewPort(const uint16_t& screen = {},
+ const uint32_t& x = {},
+ const uint32_t& y = {});
+
+ struct GetDotClocksRequest {
+ uint16_t screen{};
+ };
+
+ struct GetDotClocksReply {
+ uint16_t sequence{};
+ ClockFlag flags{};
+ uint32_t clocks{};
+ uint32_t maxclocks{};
+ std::vector<uint32_t> clock{};
+ };
+
+ using GetDotClocksResponse = Response<GetDotClocksReply>;
+
+ Future<GetDotClocksReply> GetDotClocks(const GetDotClocksRequest& request);
+
+ Future<GetDotClocksReply> GetDotClocks(const uint16_t& screen = {});
+
+ struct SetClientVersionRequest {
+ uint16_t major{};
+ uint16_t minor{};
+ };
+
+ using SetClientVersionResponse = Response<void>;
+
+ Future<void> SetClientVersion(const SetClientVersionRequest& request);
+
+ Future<void> SetClientVersion(const uint16_t& major = {},
+ const uint16_t& minor = {});
+
+ struct SetGammaRequest {
+ uint16_t screen{};
+ uint32_t red{};
+ uint32_t green{};
+ uint32_t blue{};
+ };
+
+ using SetGammaResponse = Response<void>;
+
+ Future<void> SetGamma(const SetGammaRequest& request);
+
+ Future<void> SetGamma(const uint16_t& screen = {},
+ const uint32_t& red = {},
+ const uint32_t& green = {},
+ const uint32_t& blue = {});
+
+ struct GetGammaRequest {
+ uint16_t screen{};
+ };
+
+ struct GetGammaReply {
+ uint16_t sequence{};
+ uint32_t red{};
+ uint32_t green{};
+ uint32_t blue{};
+ };
+
+ using GetGammaResponse = Response<GetGammaReply>;
+
+ Future<GetGammaReply> GetGamma(const GetGammaRequest& request);
+
+ Future<GetGammaReply> GetGamma(const uint16_t& screen = {});
+
+ struct GetGammaRampRequest {
+ uint16_t screen{};
+ uint16_t size{};
+ };
+
+ struct GetGammaRampReply {
+ uint16_t sequence{};
+ uint16_t size{};
+ std::vector<uint16_t> red{};
+ std::vector<uint16_t> green{};
+ std::vector<uint16_t> blue{};
+ };
+
+ using GetGammaRampResponse = Response<GetGammaRampReply>;
+
+ Future<GetGammaRampReply> GetGammaRamp(const GetGammaRampRequest& request);
+
+ Future<GetGammaRampReply> GetGammaRamp(const uint16_t& screen = {},
+ const uint16_t& size = {});
+
+ struct SetGammaRampRequest {
+ uint16_t screen{};
+ uint16_t size{};
+ std::vector<uint16_t> red{};
+ std::vector<uint16_t> green{};
+ std::vector<uint16_t> blue{};
+ };
+
+ using SetGammaRampResponse = Response<void>;
+
+ Future<void> SetGammaRamp(const SetGammaRampRequest& request);
+
+ Future<void> SetGammaRamp(const uint16_t& screen = {},
+ const uint16_t& size = {},
+ const std::vector<uint16_t>& red = {},
+ const std::vector<uint16_t>& green = {},
+ const std::vector<uint16_t>& blue = {});
+
+ struct GetGammaRampSizeRequest {
+ uint16_t screen{};
+ };
+
+ struct GetGammaRampSizeReply {
+ uint16_t sequence{};
+ uint16_t size{};
+ };
+
+ using GetGammaRampSizeResponse = Response<GetGammaRampSizeReply>;
+
+ Future<GetGammaRampSizeReply> GetGammaRampSize(
+ const GetGammaRampSizeRequest& request);
+
+ Future<GetGammaRampSizeReply> GetGammaRampSize(const uint16_t& screen = {});
+
+ struct GetPermissionsRequest {
+ uint16_t screen{};
+ };
+
+ struct GetPermissionsReply {
+ uint16_t sequence{};
+ Permission permissions{};
+ };
+
+ using GetPermissionsResponse = Response<GetPermissionsReply>;
+
+ Future<GetPermissionsReply> GetPermissions(
+ const GetPermissionsRequest& request);
+
+ Future<GetPermissionsReply> GetPermissions(const uint16_t& screen = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::XF86VidMode::ModeFlag operator|(
+ x11::XF86VidMode::ModeFlag l,
+ x11::XF86VidMode::ModeFlag r) {
+ using T = std::underlying_type_t<x11::XF86VidMode::ModeFlag>;
+ return static_cast<x11::XF86VidMode::ModeFlag>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XF86VidMode::ModeFlag operator&(
+ x11::XF86VidMode::ModeFlag l,
+ x11::XF86VidMode::ModeFlag r) {
+ using T = std::underlying_type_t<x11::XF86VidMode::ModeFlag>;
+ return static_cast<x11::XF86VidMode::ModeFlag>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XF86VidMode::ClockFlag operator|(
+ x11::XF86VidMode::ClockFlag l,
+ x11::XF86VidMode::ClockFlag r) {
+ using T = std::underlying_type_t<x11::XF86VidMode::ClockFlag>;
+ return static_cast<x11::XF86VidMode::ClockFlag>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XF86VidMode::ClockFlag operator&(
+ x11::XF86VidMode::ClockFlag l,
+ x11::XF86VidMode::ClockFlag r) {
+ using T = std::underlying_type_t<x11::XF86VidMode::ClockFlag>;
+ return static_cast<x11::XF86VidMode::ClockFlag>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XF86VidMode::Permission operator|(
+ x11::XF86VidMode::Permission l,
+ x11::XF86VidMode::Permission r) {
+ using T = std::underlying_type_t<x11::XF86VidMode::Permission>;
+ return static_cast<x11::XF86VidMode::Permission>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XF86VidMode::Permission operator&(
+ x11::XF86VidMode::Permission l,
+ x11::XF86VidMode::Permission r) {
+ using T = std::underlying_type_t<x11::XF86VidMode::Permission>;
+ return static_cast<x11::XF86VidMode::Permission>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XF86VIDMODE_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xfixes.cc b/chromium/ui/gfx/x/generated_protos/xfixes.cc
new file mode 100644
index 00000000000..88cc3514f42
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xfixes.cc
@@ -0,0 +1,1987 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xfixes.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+XFixes::XFixes(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<XFixes::SelectionNotifyEvent>(
+ XFixes::SelectionNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& subtype = (*event_).subtype;
+ auto& sequence = (*event_).sequence;
+ auto& window = (*event_).window;
+ auto& owner = (*event_).owner;
+ auto& selection = (*event_).selection;
+ auto& timestamp = (*event_).timestamp;
+ auto& selection_timestamp = (*event_).selection_timestamp;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // subtype
+ uint8_t tmp0;
+ Read(&tmp0, &buf);
+ subtype = static_cast<XFixes::SelectionEvent>(tmp0);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // owner
+ Read(&owner, &buf);
+
+ // selection
+ Read(&selection, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // selection_timestamp
+ Read(&selection_timestamp, &buf);
+
+ // pad0
+ Pad(&buf, 8);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<XFixes::CursorNotifyEvent>(XFixes::CursorNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& subtype = (*event_).subtype;
+ auto& sequence = (*event_).sequence;
+ auto& window = (*event_).window;
+ auto& cursor_serial = (*event_).cursor_serial;
+ auto& timestamp = (*event_).timestamp;
+ auto& name = (*event_).name;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // subtype
+ uint8_t tmp1;
+ Read(&tmp1, &buf);
+ subtype = static_cast<XFixes::CursorNotify>(tmp1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // cursor_serial
+ Read(&cursor_serial, &buf);
+
+ // timestamp
+ Read(&timestamp, &buf);
+
+ // name
+ Read(&name, &buf);
+
+ // pad0
+ Pad(&buf, 12);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+std::string XFixes::BadRegionError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "XFixes::BadRegionError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<XFixes::BadRegionError>(XFixes::BadRegionError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+Future<XFixes::QueryVersionReply> XFixes::QueryVersion(
+ const XFixes::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client_major_version = request.client_major_version;
+ auto& client_minor_version = request.client_minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client_major_version
+ buf.Write(&client_major_version);
+
+ // client_minor_version
+ buf.Write(&client_minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XFixes::QueryVersionReply>(
+ &buf, "XFixes::QueryVersion", false);
+}
+
+Future<XFixes::QueryVersionReply> XFixes::QueryVersion(
+ const uint32_t& client_major_version,
+ const uint32_t& client_minor_version) {
+ return XFixes::QueryVersion(
+ XFixes::QueryVersionRequest{client_major_version, client_minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XFixes::QueryVersionReply> detail::ReadReply<
+ XFixes::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XFixes::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XFixes::ChangeSaveSet(
+ const XFixes::ChangeSaveSetRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& mode = request.mode;
+ auto& target = request.target;
+ auto& map = request.map;
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // mode
+ uint8_t tmp2;
+ tmp2 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp2);
+
+ // target
+ uint8_t tmp3;
+ tmp3 = static_cast<uint8_t>(target);
+ buf.Write(&tmp3);
+
+ // map
+ uint8_t tmp4;
+ tmp4 = static_cast<uint8_t>(map);
+ buf.Write(&tmp4);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::ChangeSaveSet", false);
+}
+
+Future<void> XFixes::ChangeSaveSet(const SaveSetMode& mode,
+ const SaveSetTarget& target,
+ const SaveSetMapping& map,
+ const Window& window) {
+ return XFixes::ChangeSaveSet(
+ XFixes::ChangeSaveSetRequest{mode, target, map, window});
+}
+
+Future<void> XFixes::SelectSelectionInput(
+ const XFixes::SelectSelectionInputRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& selection = request.selection;
+ auto& event_mask = request.event_mask;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // selection
+ buf.Write(&selection);
+
+ // event_mask
+ uint32_t tmp5;
+ tmp5 = static_cast<uint32_t>(event_mask);
+ buf.Write(&tmp5);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::SelectSelectionInput",
+ false);
+}
+
+Future<void> XFixes::SelectSelectionInput(
+ const Window& window,
+ const Atom& selection,
+ const SelectionEventMask& event_mask) {
+ return XFixes::SelectSelectionInput(
+ XFixes::SelectSelectionInputRequest{window, selection, event_mask});
+}
+
+Future<void> XFixes::SelectCursorInput(
+ const XFixes::SelectCursorInputRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& event_mask = request.event_mask;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // event_mask
+ uint32_t tmp6;
+ tmp6 = static_cast<uint32_t>(event_mask);
+ buf.Write(&tmp6);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::SelectCursorInput",
+ false);
+}
+
+Future<void> XFixes::SelectCursorInput(const Window& window,
+ const CursorNotifyMask& event_mask) {
+ return XFixes::SelectCursorInput(
+ XFixes::SelectCursorInputRequest{window, event_mask});
+}
+
+Future<XFixes::GetCursorImageReply> XFixes::GetCursorImage(
+ const XFixes::GetCursorImageRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XFixes::GetCursorImageReply>(
+ &buf, "XFixes::GetCursorImage", false);
+}
+
+Future<XFixes::GetCursorImageReply> XFixes::GetCursorImage() {
+ return XFixes::GetCursorImage(XFixes::GetCursorImageRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XFixes::GetCursorImageReply> detail::ReadReply<
+ XFixes::GetCursorImageReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XFixes::GetCursorImageReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& x = (*reply).x;
+ auto& y = (*reply).y;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& xhot = (*reply).xhot;
+ auto& yhot = (*reply).yhot;
+ auto& cursor_serial = (*reply).cursor_serial;
+ auto& cursor_image = (*reply).cursor_image;
+ size_t cursor_image_len = cursor_image.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // xhot
+ Read(&xhot, &buf);
+
+ // yhot
+ Read(&yhot, &buf);
+
+ // cursor_serial
+ Read(&cursor_serial, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // cursor_image
+ cursor_image.resize((width) * (height));
+ for (auto& cursor_image_elem : cursor_image) {
+ // cursor_image_elem
+ Read(&cursor_image_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XFixes::CreateRegion(const XFixes::CreateRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& region = request.region;
+ auto& rectangles = request.rectangles;
+ size_t rectangles_len = rectangles.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // region
+ buf.Write(&region);
+
+ // rectangles
+ DCHECK_EQ(static_cast<size_t>(rectangles_len), rectangles.size());
+ for (auto& rectangles_elem : rectangles) {
+ // rectangles_elem
+ {
+ auto& x = rectangles_elem.x;
+ auto& y = rectangles_elem.y;
+ auto& width = rectangles_elem.width;
+ auto& height = rectangles_elem.height;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::CreateRegion", false);
+}
+
+Future<void> XFixes::CreateRegion(const Region& region,
+ const std::vector<Rectangle>& rectangles) {
+ return XFixes::CreateRegion(XFixes::CreateRegionRequest{region, rectangles});
+}
+
+Future<void> XFixes::CreateRegionFromBitmap(
+ const XFixes::CreateRegionFromBitmapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& region = request.region;
+ auto& bitmap = request.bitmap;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // region
+ buf.Write(&region);
+
+ // bitmap
+ buf.Write(&bitmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::CreateRegionFromBitmap",
+ false);
+}
+
+Future<void> XFixes::CreateRegionFromBitmap(const Region& region,
+ const Pixmap& bitmap) {
+ return XFixes::CreateRegionFromBitmap(
+ XFixes::CreateRegionFromBitmapRequest{region, bitmap});
+}
+
+Future<void> XFixes::CreateRegionFromWindow(
+ const XFixes::CreateRegionFromWindowRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& region = request.region;
+ auto& window = request.window;
+ auto& kind = request.kind;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // region
+ buf.Write(&region);
+
+ // window
+ buf.Write(&window);
+
+ // kind
+ uint8_t tmp7;
+ tmp7 = static_cast<uint8_t>(kind);
+ buf.Write(&tmp7);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::CreateRegionFromWindow",
+ false);
+}
+
+Future<void> XFixes::CreateRegionFromWindow(const Region& region,
+ const Window& window,
+ const Shape::Sk& kind) {
+ return XFixes::CreateRegionFromWindow(
+ XFixes::CreateRegionFromWindowRequest{region, window, kind});
+}
+
+Future<void> XFixes::CreateRegionFromGC(
+ const XFixes::CreateRegionFromGCRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& region = request.region;
+ auto& gc = request.gc;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // region
+ buf.Write(&region);
+
+ // gc
+ buf.Write(&gc);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::CreateRegionFromGC",
+ false);
+}
+
+Future<void> XFixes::CreateRegionFromGC(const Region& region,
+ const GraphicsContext& gc) {
+ return XFixes::CreateRegionFromGC(
+ XFixes::CreateRegionFromGCRequest{region, gc});
+}
+
+Future<void> XFixes::CreateRegionFromPicture(
+ const XFixes::CreateRegionFromPictureRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& region = request.region;
+ auto& picture = request.picture;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // region
+ buf.Write(&region);
+
+ // picture
+ buf.Write(&picture);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::CreateRegionFromPicture",
+ false);
+}
+
+Future<void> XFixes::CreateRegionFromPicture(const Region& region,
+ const Render::Picture& picture) {
+ return XFixes::CreateRegionFromPicture(
+ XFixes::CreateRegionFromPictureRequest{region, picture});
+}
+
+Future<void> XFixes::DestroyRegion(
+ const XFixes::DestroyRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& region = request.region;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // region
+ buf.Write(&region);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::DestroyRegion", false);
+}
+
+Future<void> XFixes::DestroyRegion(const Region& region) {
+ return XFixes::DestroyRegion(XFixes::DestroyRegionRequest{region});
+}
+
+Future<void> XFixes::SetRegion(const XFixes::SetRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& region = request.region;
+ auto& rectangles = request.rectangles;
+ size_t rectangles_len = rectangles.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // region
+ buf.Write(&region);
+
+ // rectangles
+ DCHECK_EQ(static_cast<size_t>(rectangles_len), rectangles.size());
+ for (auto& rectangles_elem : rectangles) {
+ // rectangles_elem
+ {
+ auto& x = rectangles_elem.x;
+ auto& y = rectangles_elem.y;
+ auto& width = rectangles_elem.width;
+ auto& height = rectangles_elem.height;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::SetRegion", false);
+}
+
+Future<void> XFixes::SetRegion(const Region& region,
+ const std::vector<Rectangle>& rectangles) {
+ return XFixes::SetRegion(XFixes::SetRegionRequest{region, rectangles});
+}
+
+Future<void> XFixes::CopyRegion(const XFixes::CopyRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& source = request.source;
+ auto& destination = request.destination;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // source
+ buf.Write(&source);
+
+ // destination
+ buf.Write(&destination);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::CopyRegion", false);
+}
+
+Future<void> XFixes::CopyRegion(const Region& source,
+ const Region& destination) {
+ return XFixes::CopyRegion(XFixes::CopyRegionRequest{source, destination});
+}
+
+Future<void> XFixes::UnionRegion(const XFixes::UnionRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& source1 = request.source1;
+ auto& source2 = request.source2;
+ auto& destination = request.destination;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // source1
+ buf.Write(&source1);
+
+ // source2
+ buf.Write(&source2);
+
+ // destination
+ buf.Write(&destination);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::UnionRegion", false);
+}
+
+Future<void> XFixes::UnionRegion(const Region& source1,
+ const Region& source2,
+ const Region& destination) {
+ return XFixes::UnionRegion(
+ XFixes::UnionRegionRequest{source1, source2, destination});
+}
+
+Future<void> XFixes::IntersectRegion(
+ const XFixes::IntersectRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& source1 = request.source1;
+ auto& source2 = request.source2;
+ auto& destination = request.destination;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 14;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // source1
+ buf.Write(&source1);
+
+ // source2
+ buf.Write(&source2);
+
+ // destination
+ buf.Write(&destination);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::IntersectRegion", false);
+}
+
+Future<void> XFixes::IntersectRegion(const Region& source1,
+ const Region& source2,
+ const Region& destination) {
+ return XFixes::IntersectRegion(
+ XFixes::IntersectRegionRequest{source1, source2, destination});
+}
+
+Future<void> XFixes::SubtractRegion(
+ const XFixes::SubtractRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& source1 = request.source1;
+ auto& source2 = request.source2;
+ auto& destination = request.destination;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 15;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // source1
+ buf.Write(&source1);
+
+ // source2
+ buf.Write(&source2);
+
+ // destination
+ buf.Write(&destination);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::SubtractRegion", false);
+}
+
+Future<void> XFixes::SubtractRegion(const Region& source1,
+ const Region& source2,
+ const Region& destination) {
+ return XFixes::SubtractRegion(
+ XFixes::SubtractRegionRequest{source1, source2, destination});
+}
+
+Future<void> XFixes::InvertRegion(const XFixes::InvertRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& source = request.source;
+ auto& bounds = request.bounds;
+ auto& destination = request.destination;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 16;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // source
+ buf.Write(&source);
+
+ // bounds
+ {
+ auto& x = bounds.x;
+ auto& y = bounds.y;
+ auto& width = bounds.width;
+ auto& height = bounds.height;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+ }
+
+ // destination
+ buf.Write(&destination);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::InvertRegion", false);
+}
+
+Future<void> XFixes::InvertRegion(const Region& source,
+ const Rectangle& bounds,
+ const Region& destination) {
+ return XFixes::InvertRegion(
+ XFixes::InvertRegionRequest{source, bounds, destination});
+}
+
+Future<void> XFixes::TranslateRegion(
+ const XFixes::TranslateRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& region = request.region;
+ auto& dx = request.dx;
+ auto& dy = request.dy;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 17;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // region
+ buf.Write(&region);
+
+ // dx
+ buf.Write(&dx);
+
+ // dy
+ buf.Write(&dy);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::TranslateRegion", false);
+}
+
+Future<void> XFixes::TranslateRegion(const Region& region,
+ const int16_t& dx,
+ const int16_t& dy) {
+ return XFixes::TranslateRegion(
+ XFixes::TranslateRegionRequest{region, dx, dy});
+}
+
+Future<void> XFixes::RegionExtents(
+ const XFixes::RegionExtentsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& source = request.source;
+ auto& destination = request.destination;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 18;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // source
+ buf.Write(&source);
+
+ // destination
+ buf.Write(&destination);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::RegionExtents", false);
+}
+
+Future<void> XFixes::RegionExtents(const Region& source,
+ const Region& destination) {
+ return XFixes::RegionExtents(
+ XFixes::RegionExtentsRequest{source, destination});
+}
+
+Future<XFixes::FetchRegionReply> XFixes::FetchRegion(
+ const XFixes::FetchRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& region = request.region;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 19;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // region
+ buf.Write(&region);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XFixes::FetchRegionReply>(
+ &buf, "XFixes::FetchRegion", false);
+}
+
+Future<XFixes::FetchRegionReply> XFixes::FetchRegion(const Region& region) {
+ return XFixes::FetchRegion(XFixes::FetchRegionRequest{region});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XFixes::FetchRegionReply> detail::ReadReply<
+ XFixes::FetchRegionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XFixes::FetchRegionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& extents = (*reply).extents;
+ auto& rectangles = (*reply).rectangles;
+ size_t rectangles_len = rectangles.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // extents
+ {
+ auto& x = extents.x;
+ auto& y = extents.y;
+ auto& width = extents.width;
+ auto& height = extents.height;
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+ }
+
+ // pad1
+ Pad(&buf, 16);
+
+ // rectangles
+ rectangles.resize((length) / (2));
+ for (auto& rectangles_elem : rectangles) {
+ // rectangles_elem
+ {
+ auto& x = rectangles_elem.x;
+ auto& y = rectangles_elem.y;
+ auto& width = rectangles_elem.width;
+ auto& height = rectangles_elem.height;
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XFixes::SetGCClipRegion(
+ const XFixes::SetGCClipRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& gc = request.gc;
+ auto& region = request.region;
+ auto& x_origin = request.x_origin;
+ auto& y_origin = request.y_origin;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 20;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // gc
+ buf.Write(&gc);
+
+ // region
+ buf.Write(&region);
+
+ // x_origin
+ buf.Write(&x_origin);
+
+ // y_origin
+ buf.Write(&y_origin);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::SetGCClipRegion", false);
+}
+
+Future<void> XFixes::SetGCClipRegion(const GraphicsContext& gc,
+ const Region& region,
+ const int16_t& x_origin,
+ const int16_t& y_origin) {
+ return XFixes::SetGCClipRegion(
+ XFixes::SetGCClipRegionRequest{gc, region, x_origin, y_origin});
+}
+
+Future<void> XFixes::SetWindowShapeRegion(
+ const XFixes::SetWindowShapeRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& dest = request.dest;
+ auto& dest_kind = request.dest_kind;
+ auto& x_offset = request.x_offset;
+ auto& y_offset = request.y_offset;
+ auto& region = request.region;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 21;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // dest
+ buf.Write(&dest);
+
+ // dest_kind
+ uint8_t tmp8;
+ tmp8 = static_cast<uint8_t>(dest_kind);
+ buf.Write(&tmp8);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // x_offset
+ buf.Write(&x_offset);
+
+ // y_offset
+ buf.Write(&y_offset);
+
+ // region
+ buf.Write(&region);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::SetWindowShapeRegion",
+ false);
+}
+
+Future<void> XFixes::SetWindowShapeRegion(const Window& dest,
+ const Shape::Sk& dest_kind,
+ const int16_t& x_offset,
+ const int16_t& y_offset,
+ const Region& region) {
+ return XFixes::SetWindowShapeRegion(XFixes::SetWindowShapeRegionRequest{
+ dest, dest_kind, x_offset, y_offset, region});
+}
+
+Future<void> XFixes::SetPictureClipRegion(
+ const XFixes::SetPictureClipRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& picture = request.picture;
+ auto& region = request.region;
+ auto& x_origin = request.x_origin;
+ auto& y_origin = request.y_origin;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 22;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // picture
+ buf.Write(&picture);
+
+ // region
+ buf.Write(&region);
+
+ // x_origin
+ buf.Write(&x_origin);
+
+ // y_origin
+ buf.Write(&y_origin);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::SetPictureClipRegion",
+ false);
+}
+
+Future<void> XFixes::SetPictureClipRegion(const Render::Picture& picture,
+ const Region& region,
+ const int16_t& x_origin,
+ const int16_t& y_origin) {
+ return XFixes::SetPictureClipRegion(
+ XFixes::SetPictureClipRegionRequest{picture, region, x_origin, y_origin});
+}
+
+Future<void> XFixes::SetCursorName(
+ const XFixes::SetCursorNameRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cursor = request.cursor;
+ uint16_t nbytes{};
+ auto& name = request.name;
+ size_t name_len = name.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 23;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cursor
+ buf.Write(&cursor);
+
+ // nbytes
+ nbytes = name.size();
+ buf.Write(&nbytes);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(nbytes), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::SetCursorName", false);
+}
+
+Future<void> XFixes::SetCursorName(const Cursor& cursor,
+ const std::string& name) {
+ return XFixes::SetCursorName(XFixes::SetCursorNameRequest{cursor, name});
+}
+
+Future<XFixes::GetCursorNameReply> XFixes::GetCursorName(
+ const XFixes::GetCursorNameRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cursor = request.cursor;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 24;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cursor
+ buf.Write(&cursor);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XFixes::GetCursorNameReply>(
+ &buf, "XFixes::GetCursorName", false);
+}
+
+Future<XFixes::GetCursorNameReply> XFixes::GetCursorName(const Cursor& cursor) {
+ return XFixes::GetCursorName(XFixes::GetCursorNameRequest{cursor});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XFixes::GetCursorNameReply> detail::ReadReply<
+ XFixes::GetCursorNameReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XFixes::GetCursorNameReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& atom = (*reply).atom;
+ uint16_t nbytes{};
+ auto& name = (*reply).name;
+ size_t name_len = name.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // atom
+ Read(&atom, &buf);
+
+ // nbytes
+ Read(&nbytes, &buf);
+
+ // pad1
+ Pad(&buf, 18);
+
+ // name
+ name.resize(nbytes);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XFixes::GetCursorImageAndNameReply> XFixes::GetCursorImageAndName(
+ const XFixes::GetCursorImageAndNameRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 25;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XFixes::GetCursorImageAndNameReply>(
+ &buf, "XFixes::GetCursorImageAndName", false);
+}
+
+Future<XFixes::GetCursorImageAndNameReply> XFixes::GetCursorImageAndName() {
+ return XFixes::GetCursorImageAndName(XFixes::GetCursorImageAndNameRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XFixes::GetCursorImageAndNameReply> detail::ReadReply<
+ XFixes::GetCursorImageAndNameReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XFixes::GetCursorImageAndNameReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& x = (*reply).x;
+ auto& y = (*reply).y;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& xhot = (*reply).xhot;
+ auto& yhot = (*reply).yhot;
+ auto& cursor_serial = (*reply).cursor_serial;
+ auto& cursor_atom = (*reply).cursor_atom;
+ uint16_t nbytes{};
+ auto& cursor_image = (*reply).cursor_image;
+ size_t cursor_image_len = cursor_image.size();
+ auto& name = (*reply).name;
+ size_t name_len = name.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // xhot
+ Read(&xhot, &buf);
+
+ // yhot
+ Read(&yhot, &buf);
+
+ // cursor_serial
+ Read(&cursor_serial, &buf);
+
+ // cursor_atom
+ Read(&cursor_atom, &buf);
+
+ // nbytes
+ Read(&nbytes, &buf);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // cursor_image
+ cursor_image.resize((width) * (height));
+ for (auto& cursor_image_elem : cursor_image) {
+ // cursor_image_elem
+ Read(&cursor_image_elem, &buf);
+ }
+
+ // name
+ name.resize(nbytes);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XFixes::ChangeCursor(const XFixes::ChangeCursorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& source = request.source;
+ auto& destination = request.destination;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 26;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // source
+ buf.Write(&source);
+
+ // destination
+ buf.Write(&destination);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::ChangeCursor", false);
+}
+
+Future<void> XFixes::ChangeCursor(const Cursor& source,
+ const Cursor& destination) {
+ return XFixes::ChangeCursor(XFixes::ChangeCursorRequest{source, destination});
+}
+
+Future<void> XFixes::ChangeCursorByName(
+ const XFixes::ChangeCursorByNameRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& src = request.src;
+ uint16_t nbytes{};
+ auto& name = request.name;
+ size_t name_len = name.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 27;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // src
+ buf.Write(&src);
+
+ // nbytes
+ nbytes = name.size();
+ buf.Write(&nbytes);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(nbytes), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::ChangeCursorByName",
+ false);
+}
+
+Future<void> XFixes::ChangeCursorByName(const Cursor& src,
+ const std::string& name) {
+ return XFixes::ChangeCursorByName(
+ XFixes::ChangeCursorByNameRequest{src, name});
+}
+
+Future<void> XFixes::ExpandRegion(const XFixes::ExpandRegionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& source = request.source;
+ auto& destination = request.destination;
+ auto& left = request.left;
+ auto& right = request.right;
+ auto& top = request.top;
+ auto& bottom = request.bottom;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 28;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // source
+ buf.Write(&source);
+
+ // destination
+ buf.Write(&destination);
+
+ // left
+ buf.Write(&left);
+
+ // right
+ buf.Write(&right);
+
+ // top
+ buf.Write(&top);
+
+ // bottom
+ buf.Write(&bottom);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::ExpandRegion", false);
+}
+
+Future<void> XFixes::ExpandRegion(const Region& source,
+ const Region& destination,
+ const uint16_t& left,
+ const uint16_t& right,
+ const uint16_t& top,
+ const uint16_t& bottom) {
+ return XFixes::ExpandRegion(XFixes::ExpandRegionRequest{
+ source, destination, left, right, top, bottom});
+}
+
+Future<void> XFixes::HideCursor(const XFixes::HideCursorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 29;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::HideCursor", false);
+}
+
+Future<void> XFixes::HideCursor(const Window& window) {
+ return XFixes::HideCursor(XFixes::HideCursorRequest{window});
+}
+
+Future<void> XFixes::ShowCursor(const XFixes::ShowCursorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 30;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::ShowCursor", false);
+}
+
+Future<void> XFixes::ShowCursor(const Window& window) {
+ return XFixes::ShowCursor(XFixes::ShowCursorRequest{window});
+}
+
+Future<void> XFixes::CreatePointerBarrier(
+ const XFixes::CreatePointerBarrierRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& barrier = request.barrier;
+ auto& window = request.window;
+ auto& x1 = request.x1;
+ auto& y1 = request.y1;
+ auto& x2 = request.x2;
+ auto& y2 = request.y2;
+ auto& directions = request.directions;
+ uint16_t num_devices{};
+ auto& devices = request.devices;
+ size_t devices_len = devices.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 31;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // barrier
+ buf.Write(&barrier);
+
+ // window
+ buf.Write(&window);
+
+ // x1
+ buf.Write(&x1);
+
+ // y1
+ buf.Write(&y1);
+
+ // x2
+ buf.Write(&x2);
+
+ // y2
+ buf.Write(&y2);
+
+ // directions
+ uint32_t tmp9;
+ tmp9 = static_cast<uint32_t>(directions);
+ buf.Write(&tmp9);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // num_devices
+ num_devices = devices.size();
+ buf.Write(&num_devices);
+
+ // devices
+ DCHECK_EQ(static_cast<size_t>(num_devices), devices.size());
+ for (auto& devices_elem : devices) {
+ // devices_elem
+ buf.Write(&devices_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::CreatePointerBarrier",
+ false);
+}
+
+Future<void> XFixes::CreatePointerBarrier(
+ const Barrier& barrier,
+ const Window& window,
+ const uint16_t& x1,
+ const uint16_t& y1,
+ const uint16_t& x2,
+ const uint16_t& y2,
+ const BarrierDirections& directions,
+ const std::vector<uint16_t>& devices) {
+ return XFixes::CreatePointerBarrier(XFixes::CreatePointerBarrierRequest{
+ barrier, window, x1, y1, x2, y2, directions, devices});
+}
+
+Future<void> XFixes::DeletePointerBarrier(
+ const XFixes::DeletePointerBarrierRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& barrier = request.barrier;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 32;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // barrier
+ buf.Write(&barrier);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::DeletePointerBarrier",
+ false);
+}
+
+Future<void> XFixes::DeletePointerBarrier(const Barrier& barrier) {
+ return XFixes::DeletePointerBarrier(
+ XFixes::DeletePointerBarrierRequest{barrier});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xfixes.h b/chromium/ui/gfx/x/generated_protos/xfixes.h
new file mode 100644
index 00000000000..ed5a58a4549
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xfixes.h
@@ -0,0 +1,795 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XFIXES_H_
+#define UI_GFX_X_GENERATED_PROTOS_XFIXES_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "render.h"
+#include "shape.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) XFixes {
+ public:
+ static constexpr unsigned major_version = 5;
+ static constexpr unsigned minor_version = 0;
+
+ XFixes(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class SaveSetMode : int {
+ Insert = 0,
+ Delete = 1,
+ };
+
+ enum class SaveSetTarget : int {
+ Nearest = 0,
+ Root = 1,
+ };
+
+ enum class SaveSetMapping : int {
+ Map = 0,
+ Unmap = 1,
+ };
+
+ enum class SelectionEvent : int {
+ SetSelectionOwner = 0,
+ SelectionWindowDestroy = 1,
+ SelectionClientClose = 2,
+ };
+
+ enum class SelectionEventMask : int {
+ SetSelectionOwner = 1 << 0,
+ SelectionWindowDestroy = 1 << 1,
+ SelectionClientClose = 1 << 2,
+ };
+
+ enum class CursorNotify : int {
+ DisplayCursor = 0,
+ };
+
+ enum class CursorNotifyMask : int {
+ DisplayCursor = 1 << 0,
+ };
+
+ enum class Region : uint32_t {
+ None = 0,
+ };
+
+ enum class Barrier : uint32_t {};
+
+ enum class BarrierDirections : int {
+ PositiveX = 1 << 0,
+ PositiveY = 1 << 1,
+ NegativeX = 1 << 2,
+ NegativeY = 1 << 3,
+ };
+
+ struct SelectionNotifyEvent {
+ static constexpr int type_id = 18;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ SelectionEvent subtype{};
+ uint16_t sequence{};
+ Window window{};
+ Window owner{};
+ Atom selection{};
+ Time timestamp{};
+ Time selection_timestamp{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+ };
+
+ struct CursorNotifyEvent {
+ static constexpr int type_id = 19;
+ static constexpr uint8_t opcode = 1;
+ bool send_event{};
+ CursorNotify subtype{};
+ uint16_t sequence{};
+ Window window{};
+ uint32_t cursor_serial{};
+ Time timestamp{};
+ Atom name{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+ };
+
+ struct BadRegionError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct QueryVersionRequest {
+ uint32_t client_major_version{};
+ uint32_t client_minor_version{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint32_t major_version{};
+ uint32_t minor_version{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(
+ const uint32_t& client_major_version = {},
+ const uint32_t& client_minor_version = {});
+
+ struct ChangeSaveSetRequest {
+ SaveSetMode mode{};
+ SaveSetTarget target{};
+ SaveSetMapping map{};
+ Window window{};
+ };
+
+ using ChangeSaveSetResponse = Response<void>;
+
+ Future<void> ChangeSaveSet(const ChangeSaveSetRequest& request);
+
+ Future<void> ChangeSaveSet(const SaveSetMode& mode = {},
+ const SaveSetTarget& target = {},
+ const SaveSetMapping& map = {},
+ const Window& window = {});
+
+ struct SelectSelectionInputRequest {
+ Window window{};
+ Atom selection{};
+ SelectionEventMask event_mask{};
+ };
+
+ using SelectSelectionInputResponse = Response<void>;
+
+ Future<void> SelectSelectionInput(const SelectSelectionInputRequest& request);
+
+ Future<void> SelectSelectionInput(const Window& window = {},
+ const Atom& selection = {},
+ const SelectionEventMask& event_mask = {});
+
+ struct SelectCursorInputRequest {
+ Window window{};
+ CursorNotifyMask event_mask{};
+ };
+
+ using SelectCursorInputResponse = Response<void>;
+
+ Future<void> SelectCursorInput(const SelectCursorInputRequest& request);
+
+ Future<void> SelectCursorInput(const Window& window = {},
+ const CursorNotifyMask& event_mask = {});
+
+ struct GetCursorImageRequest {};
+
+ struct GetCursorImageReply {
+ uint16_t sequence{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t xhot{};
+ uint16_t yhot{};
+ uint32_t cursor_serial{};
+ std::vector<uint32_t> cursor_image{};
+ };
+
+ using GetCursorImageResponse = Response<GetCursorImageReply>;
+
+ Future<GetCursorImageReply> GetCursorImage(
+ const GetCursorImageRequest& request);
+
+ Future<GetCursorImageReply> GetCursorImage();
+
+ struct CreateRegionRequest {
+ Region region{};
+ std::vector<Rectangle> rectangles{};
+ };
+
+ using CreateRegionResponse = Response<void>;
+
+ Future<void> CreateRegion(const CreateRegionRequest& request);
+
+ Future<void> CreateRegion(const Region& region = {},
+ const std::vector<Rectangle>& rectangles = {});
+
+ struct CreateRegionFromBitmapRequest {
+ Region region{};
+ Pixmap bitmap{};
+ };
+
+ using CreateRegionFromBitmapResponse = Response<void>;
+
+ Future<void> CreateRegionFromBitmap(
+ const CreateRegionFromBitmapRequest& request);
+
+ Future<void> CreateRegionFromBitmap(const Region& region = {},
+ const Pixmap& bitmap = {});
+
+ struct CreateRegionFromWindowRequest {
+ Region region{};
+ Window window{};
+ Shape::Sk kind{};
+ };
+
+ using CreateRegionFromWindowResponse = Response<void>;
+
+ Future<void> CreateRegionFromWindow(
+ const CreateRegionFromWindowRequest& request);
+
+ Future<void> CreateRegionFromWindow(const Region& region = {},
+ const Window& window = {},
+ const Shape::Sk& kind = {});
+
+ struct CreateRegionFromGCRequest {
+ Region region{};
+ GraphicsContext gc{};
+ };
+
+ using CreateRegionFromGCResponse = Response<void>;
+
+ Future<void> CreateRegionFromGC(const CreateRegionFromGCRequest& request);
+
+ Future<void> CreateRegionFromGC(const Region& region = {},
+ const GraphicsContext& gc = {});
+
+ struct CreateRegionFromPictureRequest {
+ Region region{};
+ Render::Picture picture{};
+ };
+
+ using CreateRegionFromPictureResponse = Response<void>;
+
+ Future<void> CreateRegionFromPicture(
+ const CreateRegionFromPictureRequest& request);
+
+ Future<void> CreateRegionFromPicture(const Region& region = {},
+ const Render::Picture& picture = {});
+
+ struct DestroyRegionRequest {
+ Region region{};
+ };
+
+ using DestroyRegionResponse = Response<void>;
+
+ Future<void> DestroyRegion(const DestroyRegionRequest& request);
+
+ Future<void> DestroyRegion(const Region& region = {});
+
+ struct SetRegionRequest {
+ Region region{};
+ std::vector<Rectangle> rectangles{};
+ };
+
+ using SetRegionResponse = Response<void>;
+
+ Future<void> SetRegion(const SetRegionRequest& request);
+
+ Future<void> SetRegion(const Region& region = {},
+ const std::vector<Rectangle>& rectangles = {});
+
+ struct CopyRegionRequest {
+ Region source{};
+ Region destination{};
+ };
+
+ using CopyRegionResponse = Response<void>;
+
+ Future<void> CopyRegion(const CopyRegionRequest& request);
+
+ Future<void> CopyRegion(const Region& source = {},
+ const Region& destination = {});
+
+ struct UnionRegionRequest {
+ Region source1{};
+ Region source2{};
+ Region destination{};
+ };
+
+ using UnionRegionResponse = Response<void>;
+
+ Future<void> UnionRegion(const UnionRegionRequest& request);
+
+ Future<void> UnionRegion(const Region& source1 = {},
+ const Region& source2 = {},
+ const Region& destination = {});
+
+ struct IntersectRegionRequest {
+ Region source1{};
+ Region source2{};
+ Region destination{};
+ };
+
+ using IntersectRegionResponse = Response<void>;
+
+ Future<void> IntersectRegion(const IntersectRegionRequest& request);
+
+ Future<void> IntersectRegion(const Region& source1 = {},
+ const Region& source2 = {},
+ const Region& destination = {});
+
+ struct SubtractRegionRequest {
+ Region source1{};
+ Region source2{};
+ Region destination{};
+ };
+
+ using SubtractRegionResponse = Response<void>;
+
+ Future<void> SubtractRegion(const SubtractRegionRequest& request);
+
+ Future<void> SubtractRegion(const Region& source1 = {},
+ const Region& source2 = {},
+ const Region& destination = {});
+
+ struct InvertRegionRequest {
+ Region source{};
+ Rectangle bounds{};
+ Region destination{};
+ };
+
+ using InvertRegionResponse = Response<void>;
+
+ Future<void> InvertRegion(const InvertRegionRequest& request);
+
+ Future<void> InvertRegion(const Region& source = {},
+ const Rectangle& bounds = {{}, {}, {}, {}},
+ const Region& destination = {});
+
+ struct TranslateRegionRequest {
+ Region region{};
+ int16_t dx{};
+ int16_t dy{};
+ };
+
+ using TranslateRegionResponse = Response<void>;
+
+ Future<void> TranslateRegion(const TranslateRegionRequest& request);
+
+ Future<void> TranslateRegion(const Region& region = {},
+ const int16_t& dx = {},
+ const int16_t& dy = {});
+
+ struct RegionExtentsRequest {
+ Region source{};
+ Region destination{};
+ };
+
+ using RegionExtentsResponse = Response<void>;
+
+ Future<void> RegionExtents(const RegionExtentsRequest& request);
+
+ Future<void> RegionExtents(const Region& source = {},
+ const Region& destination = {});
+
+ struct FetchRegionRequest {
+ Region region{};
+ };
+
+ struct FetchRegionReply {
+ uint16_t sequence{};
+ Rectangle extents{};
+ std::vector<Rectangle> rectangles{};
+ };
+
+ using FetchRegionResponse = Response<FetchRegionReply>;
+
+ Future<FetchRegionReply> FetchRegion(const FetchRegionRequest& request);
+
+ Future<FetchRegionReply> FetchRegion(const Region& region = {});
+
+ struct SetGCClipRegionRequest {
+ GraphicsContext gc{};
+ Region region{};
+ int16_t x_origin{};
+ int16_t y_origin{};
+ };
+
+ using SetGCClipRegionResponse = Response<void>;
+
+ Future<void> SetGCClipRegion(const SetGCClipRegionRequest& request);
+
+ Future<void> SetGCClipRegion(const GraphicsContext& gc = {},
+ const Region& region = {},
+ const int16_t& x_origin = {},
+ const int16_t& y_origin = {});
+
+ struct SetWindowShapeRegionRequest {
+ Window dest{};
+ Shape::Sk dest_kind{};
+ int16_t x_offset{};
+ int16_t y_offset{};
+ Region region{};
+ };
+
+ using SetWindowShapeRegionResponse = Response<void>;
+
+ Future<void> SetWindowShapeRegion(const SetWindowShapeRegionRequest& request);
+
+ Future<void> SetWindowShapeRegion(const Window& dest = {},
+ const Shape::Sk& dest_kind = {},
+ const int16_t& x_offset = {},
+ const int16_t& y_offset = {},
+ const Region& region = {});
+
+ struct SetPictureClipRegionRequest {
+ Render::Picture picture{};
+ Region region{};
+ int16_t x_origin{};
+ int16_t y_origin{};
+ };
+
+ using SetPictureClipRegionResponse = Response<void>;
+
+ Future<void> SetPictureClipRegion(const SetPictureClipRegionRequest& request);
+
+ Future<void> SetPictureClipRegion(const Render::Picture& picture = {},
+ const Region& region = {},
+ const int16_t& x_origin = {},
+ const int16_t& y_origin = {});
+
+ struct SetCursorNameRequest {
+ Cursor cursor{};
+ std::string name{};
+ };
+
+ using SetCursorNameResponse = Response<void>;
+
+ Future<void> SetCursorName(const SetCursorNameRequest& request);
+
+ Future<void> SetCursorName(const Cursor& cursor = {},
+ const std::string& name = {});
+
+ struct GetCursorNameRequest {
+ Cursor cursor{};
+ };
+
+ struct GetCursorNameReply {
+ uint16_t sequence{};
+ Atom atom{};
+ std::string name{};
+ };
+
+ using GetCursorNameResponse = Response<GetCursorNameReply>;
+
+ Future<GetCursorNameReply> GetCursorName(const GetCursorNameRequest& request);
+
+ Future<GetCursorNameReply> GetCursorName(const Cursor& cursor = {});
+
+ struct GetCursorImageAndNameRequest {};
+
+ struct GetCursorImageAndNameReply {
+ uint16_t sequence{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t xhot{};
+ uint16_t yhot{};
+ uint32_t cursor_serial{};
+ Atom cursor_atom{};
+ std::vector<uint32_t> cursor_image{};
+ std::string name{};
+ };
+
+ using GetCursorImageAndNameResponse = Response<GetCursorImageAndNameReply>;
+
+ Future<GetCursorImageAndNameReply> GetCursorImageAndName(
+ const GetCursorImageAndNameRequest& request);
+
+ Future<GetCursorImageAndNameReply> GetCursorImageAndName();
+
+ struct ChangeCursorRequest {
+ Cursor source{};
+ Cursor destination{};
+ };
+
+ using ChangeCursorResponse = Response<void>;
+
+ Future<void> ChangeCursor(const ChangeCursorRequest& request);
+
+ Future<void> ChangeCursor(const Cursor& source = {},
+ const Cursor& destination = {});
+
+ struct ChangeCursorByNameRequest {
+ Cursor src{};
+ std::string name{};
+ };
+
+ using ChangeCursorByNameResponse = Response<void>;
+
+ Future<void> ChangeCursorByName(const ChangeCursorByNameRequest& request);
+
+ Future<void> ChangeCursorByName(const Cursor& src = {},
+ const std::string& name = {});
+
+ struct ExpandRegionRequest {
+ Region source{};
+ Region destination{};
+ uint16_t left{};
+ uint16_t right{};
+ uint16_t top{};
+ uint16_t bottom{};
+ };
+
+ using ExpandRegionResponse = Response<void>;
+
+ Future<void> ExpandRegion(const ExpandRegionRequest& request);
+
+ Future<void> ExpandRegion(const Region& source = {},
+ const Region& destination = {},
+ const uint16_t& left = {},
+ const uint16_t& right = {},
+ const uint16_t& top = {},
+ const uint16_t& bottom = {});
+
+ struct HideCursorRequest {
+ Window window{};
+ };
+
+ using HideCursorResponse = Response<void>;
+
+ Future<void> HideCursor(const HideCursorRequest& request);
+
+ Future<void> HideCursor(const Window& window = {});
+
+ struct ShowCursorRequest {
+ Window window{};
+ };
+
+ using ShowCursorResponse = Response<void>;
+
+ Future<void> ShowCursor(const ShowCursorRequest& request);
+
+ Future<void> ShowCursor(const Window& window = {});
+
+ struct CreatePointerBarrierRequest {
+ Barrier barrier{};
+ Window window{};
+ uint16_t x1{};
+ uint16_t y1{};
+ uint16_t x2{};
+ uint16_t y2{};
+ BarrierDirections directions{};
+ std::vector<uint16_t> devices{};
+ };
+
+ using CreatePointerBarrierResponse = Response<void>;
+
+ Future<void> CreatePointerBarrier(const CreatePointerBarrierRequest& request);
+
+ Future<void> CreatePointerBarrier(const Barrier& barrier = {},
+ const Window& window = {},
+ const uint16_t& x1 = {},
+ const uint16_t& y1 = {},
+ const uint16_t& x2 = {},
+ const uint16_t& y2 = {},
+ const BarrierDirections& directions = {},
+ const std::vector<uint16_t>& devices = {});
+
+ struct DeletePointerBarrierRequest {
+ Barrier barrier{};
+ };
+
+ using DeletePointerBarrierResponse = Response<void>;
+
+ Future<void> DeletePointerBarrier(const DeletePointerBarrierRequest& request);
+
+ Future<void> DeletePointerBarrier(const Barrier& barrier = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::XFixes::SaveSetMode operator|(
+ x11::XFixes::SaveSetMode l,
+ x11::XFixes::SaveSetMode r) {
+ using T = std::underlying_type_t<x11::XFixes::SaveSetMode>;
+ return static_cast<x11::XFixes::SaveSetMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::SaveSetMode operator&(
+ x11::XFixes::SaveSetMode l,
+ x11::XFixes::SaveSetMode r) {
+ using T = std::underlying_type_t<x11::XFixes::SaveSetMode>;
+ return static_cast<x11::XFixes::SaveSetMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::SaveSetTarget operator|(
+ x11::XFixes::SaveSetTarget l,
+ x11::XFixes::SaveSetTarget r) {
+ using T = std::underlying_type_t<x11::XFixes::SaveSetTarget>;
+ return static_cast<x11::XFixes::SaveSetTarget>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::SaveSetTarget operator&(
+ x11::XFixes::SaveSetTarget l,
+ x11::XFixes::SaveSetTarget r) {
+ using T = std::underlying_type_t<x11::XFixes::SaveSetTarget>;
+ return static_cast<x11::XFixes::SaveSetTarget>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::SaveSetMapping operator|(
+ x11::XFixes::SaveSetMapping l,
+ x11::XFixes::SaveSetMapping r) {
+ using T = std::underlying_type_t<x11::XFixes::SaveSetMapping>;
+ return static_cast<x11::XFixes::SaveSetMapping>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::SaveSetMapping operator&(
+ x11::XFixes::SaveSetMapping l,
+ x11::XFixes::SaveSetMapping r) {
+ using T = std::underlying_type_t<x11::XFixes::SaveSetMapping>;
+ return static_cast<x11::XFixes::SaveSetMapping>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::SelectionEvent operator|(
+ x11::XFixes::SelectionEvent l,
+ x11::XFixes::SelectionEvent r) {
+ using T = std::underlying_type_t<x11::XFixes::SelectionEvent>;
+ return static_cast<x11::XFixes::SelectionEvent>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::SelectionEvent operator&(
+ x11::XFixes::SelectionEvent l,
+ x11::XFixes::SelectionEvent r) {
+ using T = std::underlying_type_t<x11::XFixes::SelectionEvent>;
+ return static_cast<x11::XFixes::SelectionEvent>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::SelectionEventMask operator|(
+ x11::XFixes::SelectionEventMask l,
+ x11::XFixes::SelectionEventMask r) {
+ using T = std::underlying_type_t<x11::XFixes::SelectionEventMask>;
+ return static_cast<x11::XFixes::SelectionEventMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::SelectionEventMask operator&(
+ x11::XFixes::SelectionEventMask l,
+ x11::XFixes::SelectionEventMask r) {
+ using T = std::underlying_type_t<x11::XFixes::SelectionEventMask>;
+ return static_cast<x11::XFixes::SelectionEventMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::CursorNotify operator|(
+ x11::XFixes::CursorNotify l,
+ x11::XFixes::CursorNotify r) {
+ using T = std::underlying_type_t<x11::XFixes::CursorNotify>;
+ return static_cast<x11::XFixes::CursorNotify>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::CursorNotify operator&(
+ x11::XFixes::CursorNotify l,
+ x11::XFixes::CursorNotify r) {
+ using T = std::underlying_type_t<x11::XFixes::CursorNotify>;
+ return static_cast<x11::XFixes::CursorNotify>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::CursorNotifyMask operator|(
+ x11::XFixes::CursorNotifyMask l,
+ x11::XFixes::CursorNotifyMask r) {
+ using T = std::underlying_type_t<x11::XFixes::CursorNotifyMask>;
+ return static_cast<x11::XFixes::CursorNotifyMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::CursorNotifyMask operator&(
+ x11::XFixes::CursorNotifyMask l,
+ x11::XFixes::CursorNotifyMask r) {
+ using T = std::underlying_type_t<x11::XFixes::CursorNotifyMask>;
+ return static_cast<x11::XFixes::CursorNotifyMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::Region operator|(x11::XFixes::Region l,
+ x11::XFixes::Region r) {
+ using T = std::underlying_type_t<x11::XFixes::Region>;
+ return static_cast<x11::XFixes::Region>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::Region operator&(x11::XFixes::Region l,
+ x11::XFixes::Region r) {
+ using T = std::underlying_type_t<x11::XFixes::Region>;
+ return static_cast<x11::XFixes::Region>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::BarrierDirections operator|(
+ x11::XFixes::BarrierDirections l,
+ x11::XFixes::BarrierDirections r) {
+ using T = std::underlying_type_t<x11::XFixes::BarrierDirections>;
+ return static_cast<x11::XFixes::BarrierDirections>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::BarrierDirections operator&(
+ x11::XFixes::BarrierDirections l,
+ x11::XFixes::BarrierDirections r) {
+ using T = std::underlying_type_t<x11::XFixes::BarrierDirections>;
+ return static_cast<x11::XFixes::BarrierDirections>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XFIXES_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xinerama.cc b/chromium/ui/gfx/x/generated_protos/xinerama.cc
new file mode 100644
index 00000000000..e18471407bc
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xinerama.cc
@@ -0,0 +1,508 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xinerama.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Xinerama::Xinerama(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<Xinerama::QueryVersionReply> Xinerama::QueryVersion(
+ const Xinerama::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major = request.major;
+ auto& minor = request.minor;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major
+ buf.Write(&major);
+
+ // minor
+ buf.Write(&minor);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xinerama::QueryVersionReply>(
+ &buf, "Xinerama::QueryVersion", false);
+}
+
+Future<Xinerama::QueryVersionReply> Xinerama::QueryVersion(
+ const uint8_t& major,
+ const uint8_t& minor) {
+ return Xinerama::QueryVersion(Xinerama::QueryVersionRequest{major, minor});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xinerama::QueryVersionReply> detail::ReadReply<
+ Xinerama::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xinerama::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major = (*reply).major;
+ auto& minor = (*reply).minor;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major
+ Read(&major, &buf);
+
+ // minor
+ Read(&minor, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xinerama::GetStateReply> Xinerama::GetState(
+ const Xinerama::GetStateRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xinerama::GetStateReply>(
+ &buf, "Xinerama::GetState", false);
+}
+
+Future<Xinerama::GetStateReply> Xinerama::GetState(const Window& window) {
+ return Xinerama::GetState(Xinerama::GetStateRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xinerama::GetStateReply> detail::ReadReply<
+ Xinerama::GetStateReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xinerama::GetStateReply>();
+
+ auto& state = (*reply).state;
+ auto& sequence = (*reply).sequence;
+ auto& window = (*reply).window;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // state
+ Read(&state, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xinerama::GetScreenCountReply> Xinerama::GetScreenCount(
+ const Xinerama::GetScreenCountRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xinerama::GetScreenCountReply>(
+ &buf, "Xinerama::GetScreenCount", false);
+}
+
+Future<Xinerama::GetScreenCountReply> Xinerama::GetScreenCount(
+ const Window& window) {
+ return Xinerama::GetScreenCount(Xinerama::GetScreenCountRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xinerama::GetScreenCountReply> detail::ReadReply<
+ Xinerama::GetScreenCountReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xinerama::GetScreenCountReply>();
+
+ auto& screen_count = (*reply).screen_count;
+ auto& sequence = (*reply).sequence;
+ auto& window = (*reply).window;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // screen_count
+ Read(&screen_count, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xinerama::GetScreenSizeReply> Xinerama::GetScreenSize(
+ const Xinerama::GetScreenSizeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& screen = request.screen;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // screen
+ buf.Write(&screen);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xinerama::GetScreenSizeReply>(
+ &buf, "Xinerama::GetScreenSize", false);
+}
+
+Future<Xinerama::GetScreenSizeReply> Xinerama::GetScreenSize(
+ const Window& window,
+ const uint32_t& screen) {
+ return Xinerama::GetScreenSize(
+ Xinerama::GetScreenSizeRequest{window, screen});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xinerama::GetScreenSizeReply> detail::ReadReply<
+ Xinerama::GetScreenSizeReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xinerama::GetScreenSizeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& window = (*reply).window;
+ auto& screen = (*reply).screen;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // screen
+ Read(&screen, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xinerama::IsActiveReply> Xinerama::IsActive(
+ const Xinerama::IsActiveRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xinerama::IsActiveReply>(
+ &buf, "Xinerama::IsActive", false);
+}
+
+Future<Xinerama::IsActiveReply> Xinerama::IsActive() {
+ return Xinerama::IsActive(Xinerama::IsActiveRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xinerama::IsActiveReply> detail::ReadReply<
+ Xinerama::IsActiveReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xinerama::IsActiveReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& state = (*reply).state;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // state
+ Read(&state, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xinerama::QueryScreensReply> Xinerama::QueryScreens(
+ const Xinerama::QueryScreensRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xinerama::QueryScreensReply>(
+ &buf, "Xinerama::QueryScreens", false);
+}
+
+Future<Xinerama::QueryScreensReply> Xinerama::QueryScreens() {
+ return Xinerama::QueryScreens(Xinerama::QueryScreensRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xinerama::QueryScreensReply> detail::ReadReply<
+ Xinerama::QueryScreensReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xinerama::QueryScreensReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t number{};
+ auto& screen_info = (*reply).screen_info;
+ size_t screen_info_len = screen_info.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // number
+ Read(&number, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // screen_info
+ screen_info.resize(number);
+ for (auto& screen_info_elem : screen_info) {
+ // screen_info_elem
+ {
+ auto& x_org = screen_info_elem.x_org;
+ auto& y_org = screen_info_elem.y_org;
+ auto& width = screen_info_elem.width;
+ auto& height = screen_info_elem.height;
+
+ // x_org
+ Read(&x_org, &buf);
+
+ // y_org
+ Read(&y_org, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xinerama.h b/chromium/ui/gfx/x/generated_protos/xinerama.h
new file mode 100644
index 00000000000..866616dcf7e
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xinerama.h
@@ -0,0 +1,194 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XINERAMA_H_
+#define UI_GFX_X_GENERATED_PROTOS_XINERAMA_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Xinerama {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 1;
+
+ Xinerama(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ struct ScreenInfo {
+ int16_t x_org{};
+ int16_t y_org{};
+ uint16_t width{};
+ uint16_t height{};
+ };
+
+ struct QueryVersionRequest {
+ uint8_t major{};
+ uint8_t minor{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint16_t major{};
+ uint16_t minor{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(const uint8_t& major = {},
+ const uint8_t& minor = {});
+
+ struct GetStateRequest {
+ Window window{};
+ };
+
+ struct GetStateReply {
+ uint8_t state{};
+ uint16_t sequence{};
+ Window window{};
+ };
+
+ using GetStateResponse = Response<GetStateReply>;
+
+ Future<GetStateReply> GetState(const GetStateRequest& request);
+
+ Future<GetStateReply> GetState(const Window& window = {});
+
+ struct GetScreenCountRequest {
+ Window window{};
+ };
+
+ struct GetScreenCountReply {
+ uint8_t screen_count{};
+ uint16_t sequence{};
+ Window window{};
+ };
+
+ using GetScreenCountResponse = Response<GetScreenCountReply>;
+
+ Future<GetScreenCountReply> GetScreenCount(
+ const GetScreenCountRequest& request);
+
+ Future<GetScreenCountReply> GetScreenCount(const Window& window = {});
+
+ struct GetScreenSizeRequest {
+ Window window{};
+ uint32_t screen{};
+ };
+
+ struct GetScreenSizeReply {
+ uint16_t sequence{};
+ uint32_t width{};
+ uint32_t height{};
+ Window window{};
+ uint32_t screen{};
+ };
+
+ using GetScreenSizeResponse = Response<GetScreenSizeReply>;
+
+ Future<GetScreenSizeReply> GetScreenSize(const GetScreenSizeRequest& request);
+
+ Future<GetScreenSizeReply> GetScreenSize(const Window& window = {},
+ const uint32_t& screen = {});
+
+ struct IsActiveRequest {};
+
+ struct IsActiveReply {
+ uint16_t sequence{};
+ uint32_t state{};
+ };
+
+ using IsActiveResponse = Response<IsActiveReply>;
+
+ Future<IsActiveReply> IsActive(const IsActiveRequest& request);
+
+ Future<IsActiveReply> IsActive();
+
+ struct QueryScreensRequest {};
+
+ struct QueryScreensReply {
+ uint16_t sequence{};
+ std::vector<ScreenInfo> screen_info{};
+ };
+
+ using QueryScreensResponse = Response<QueryScreensReply>;
+
+ Future<QueryScreensReply> QueryScreens(const QueryScreensRequest& request);
+
+ Future<QueryScreensReply> QueryScreens();
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XINERAMA_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xinput.cc b/chromium/ui/gfx/x/generated_protos/xinput.cc
new file mode 100644
index 00000000000..cc97c1745c4
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xinput.cc
@@ -0,0 +1,7683 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xinput.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Input::Input(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::DeviceValuatorEvent>(Input::DeviceValuatorEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& device_id = (*event_).device_id;
+ auto& sequence = (*event_).sequence;
+ auto& device_state = (*event_).device_state;
+ auto& num_valuators = (*event_).num_valuators;
+ auto& first_valuator = (*event_).first_valuator;
+ auto& valuators = (*event_).valuators;
+ size_t valuators_len = valuators.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // device_state
+ Read(&device_state, &buf);
+
+ // num_valuators
+ Read(&num_valuators, &buf);
+
+ // first_valuator
+ Read(&first_valuator, &buf);
+
+ // valuators
+ for (auto& valuators_elem : valuators) {
+ // valuators_elem
+ Read(&valuators_elem, &buf);
+ }
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::LegacyDeviceEvent>(Input::LegacyDeviceEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& detail = (*event_).detail;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& root = (*event_).root;
+ auto& event = (*event_).event;
+ auto& child = (*event_).child;
+ auto& root_x = (*event_).root_x;
+ auto& root_y = (*event_).root_y;
+ auto& event_x = (*event_).event_x;
+ auto& event_y = (*event_).event_y;
+ auto& state = (*event_).state;
+ auto& same_screen = (*event_).same_screen;
+ auto& device_id = (*event_).device_id;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // detail
+ Read(&detail, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // event_x
+ Read(&event_x, &buf);
+
+ // event_y
+ Read(&event_y, &buf);
+
+ // state
+ uint16_t tmp0;
+ Read(&tmp0, &buf);
+ state = static_cast<KeyButMask>(tmp0);
+
+ // same_screen
+ Read(&same_screen, &buf);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::DeviceFocusEvent>(Input::DeviceFocusEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& detail = (*event_).detail;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& window = (*event_).window;
+ auto& mode = (*event_).mode;
+ auto& device_id = (*event_).device_id;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // detail
+ uint8_t tmp1;
+ Read(&tmp1, &buf);
+ detail = static_cast<NotifyDetail>(tmp1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // mode
+ uint8_t tmp2;
+ Read(&tmp2, &buf);
+ mode = static_cast<NotifyMode>(tmp2);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ // pad0
+ Pad(&buf, 18);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::DeviceStateNotifyEvent>(
+ Input::DeviceStateNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& device_id = (*event_).device_id;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& num_keys = (*event_).num_keys;
+ auto& num_buttons = (*event_).num_buttons;
+ auto& num_valuators = (*event_).num_valuators;
+ auto& classes_reported = (*event_).classes_reported;
+ auto& buttons = (*event_).buttons;
+ size_t buttons_len = buttons.size();
+ auto& keys = (*event_).keys;
+ size_t keys_len = keys.size();
+ auto& valuators = (*event_).valuators;
+ size_t valuators_len = valuators.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // num_keys
+ Read(&num_keys, &buf);
+
+ // num_buttons
+ Read(&num_buttons, &buf);
+
+ // num_valuators
+ Read(&num_valuators, &buf);
+
+ // classes_reported
+ uint8_t tmp3;
+ Read(&tmp3, &buf);
+ classes_reported = static_cast<Input::ClassesReportedMask>(tmp3);
+
+ // buttons
+ for (auto& buttons_elem : buttons) {
+ // buttons_elem
+ Read(&buttons_elem, &buf);
+ }
+
+ // keys
+ for (auto& keys_elem : keys) {
+ // keys_elem
+ Read(&keys_elem, &buf);
+ }
+
+ // valuators
+ for (auto& valuators_elem : valuators) {
+ // valuators_elem
+ Read(&valuators_elem, &buf);
+ }
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::DeviceMappingNotifyEvent>(
+ Input::DeviceMappingNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& device_id = (*event_).device_id;
+ auto& sequence = (*event_).sequence;
+ auto& request = (*event_).request;
+ auto& first_keycode = (*event_).first_keycode;
+ auto& count = (*event_).count;
+ auto& time = (*event_).time;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // request
+ uint8_t tmp4;
+ Read(&tmp4, &buf);
+ request = static_cast<Mapping>(tmp4);
+
+ // first_keycode
+ Read(&first_keycode, &buf);
+
+ // count
+ Read(&count, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // time
+ Read(&time, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::ChangeDeviceNotifyEvent>(
+ Input::ChangeDeviceNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& device_id = (*event_).device_id;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& request = (*event_).request;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // request
+ uint8_t tmp5;
+ Read(&tmp5, &buf);
+ request = static_cast<Input::ChangeDevice>(tmp5);
+
+ // pad0
+ Pad(&buf, 23);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::DeviceKeyStateNotifyEvent>(
+ Input::DeviceKeyStateNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& device_id = (*event_).device_id;
+ auto& sequence = (*event_).sequence;
+ auto& keys = (*event_).keys;
+ size_t keys_len = keys.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // keys
+ for (auto& keys_elem : keys) {
+ // keys_elem
+ Read(&keys_elem, &buf);
+ }
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::DeviceButtonStateNotifyEvent>(
+ Input::DeviceButtonStateNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& device_id = (*event_).device_id;
+ auto& sequence = (*event_).sequence;
+ auto& buttons = (*event_).buttons;
+ size_t buttons_len = buttons.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // buttons
+ for (auto& buttons_elem : buttons) {
+ // buttons_elem
+ Read(&buttons_elem, &buf);
+ }
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::DevicePresenceNotifyEvent>(
+ Input::DevicePresenceNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& devchange = (*event_).devchange;
+ auto& device_id = (*event_).device_id;
+ auto& control = (*event_).control;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // devchange
+ uint8_t tmp6;
+ Read(&tmp6, &buf);
+ devchange = static_cast<Input::DeviceChange>(tmp6);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ // control
+ Read(&control, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::DevicePropertyNotifyEvent>(
+ Input::DevicePropertyNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& state = (*event_).state;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& property = (*event_).property;
+ auto& device_id = (*event_).device_id;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // state
+ uint8_t tmp7;
+ Read(&tmp7, &buf);
+ state = static_cast<Property>(tmp7);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // property
+ Read(&property, &buf);
+
+ // pad0
+ Pad(&buf, 19);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::DeviceChangedEvent>(Input::DeviceChangedEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& deviceid = (*event_).deviceid;
+ auto& time = (*event_).time;
+ uint16_t num_classes{};
+ auto& sourceid = (*event_).sourceid;
+ auto& reason = (*event_).reason;
+ auto& classes = (*event_).classes;
+ size_t classes_len = classes.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // num_classes
+ Read(&num_classes, &buf);
+
+ // sourceid
+ Read(&sourceid, &buf);
+
+ // reason
+ uint8_t tmp8;
+ Read(&tmp8, &buf);
+ reason = static_cast<Input::ChangeReason>(tmp8);
+
+ // pad0
+ Pad(&buf, 11);
+
+ // classes
+ classes.resize(num_classes);
+ for (auto& classes_elem : classes) {
+ // classes_elem
+ {
+ Input::DeviceClassType type{};
+ auto& len = classes_elem.len;
+ auto& sourceid = classes_elem.sourceid;
+ auto& data = classes_elem;
+
+ // type
+ uint16_t tmp9;
+ Read(&tmp9, &buf);
+ type = static_cast<Input::DeviceClassType>(tmp9);
+
+ // len
+ Read(&len, &buf);
+
+ // sourceid
+ Read(&sourceid, &buf);
+
+ // data
+ auto data_expr = type;
+ if (CaseEq(data_expr, Input::DeviceClassType::Key)) {
+ data.key.emplace();
+ uint16_t num_keys{};
+ auto& keys = (*data.key).keys;
+ size_t keys_len = keys.size();
+
+ // num_keys
+ Read(&num_keys, &buf);
+
+ // keys
+ keys.resize(num_keys);
+ for (auto& keys_elem : keys) {
+ // keys_elem
+ Read(&keys_elem, &buf);
+ }
+ }
+ if (CaseEq(data_expr, Input::DeviceClassType::Button)) {
+ data.button.emplace();
+ uint16_t num_buttons{};
+ auto& state = (*data.button).state;
+ size_t state_len = state.size();
+ auto& labels = (*data.button).labels;
+ size_t labels_len = labels.size();
+
+ // num_buttons
+ Read(&num_buttons, &buf);
+
+ // state
+ state.resize(((num_buttons) + (31)) / (32));
+ for (auto& state_elem : state) {
+ // state_elem
+ Read(&state_elem, &buf);
+ }
+
+ // labels
+ labels.resize(num_buttons);
+ for (auto& labels_elem : labels) {
+ // labels_elem
+ Read(&labels_elem, &buf);
+ }
+ }
+ if (CaseEq(data_expr, Input::DeviceClassType::Valuator)) {
+ data.valuator.emplace();
+ auto& number = (*data.valuator).number;
+ auto& label = (*data.valuator).label;
+ auto& min = (*data.valuator).min;
+ auto& max = (*data.valuator).max;
+ auto& value = (*data.valuator).value;
+ auto& resolution = (*data.valuator).resolution;
+ auto& mode = (*data.valuator).mode;
+
+ // number
+ Read(&number, &buf);
+
+ // label
+ Read(&label, &buf);
+
+ // min
+ {
+ auto& integral = min.integral;
+ auto& frac = min.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+
+ // max
+ {
+ auto& integral = max.integral;
+ auto& frac = max.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+
+ // value
+ {
+ auto& integral = value.integral;
+ auto& frac = value.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+
+ // resolution
+ Read(&resolution, &buf);
+
+ // mode
+ uint8_t tmp10;
+ Read(&tmp10, &buf);
+ mode = static_cast<Input::ValuatorMode>(tmp10);
+
+ // pad0
+ Pad(&buf, 3);
+ }
+ if (CaseEq(data_expr, Input::DeviceClassType::Scroll)) {
+ data.scroll.emplace();
+ auto& number = (*data.scroll).number;
+ auto& scroll_type = (*data.scroll).scroll_type;
+ auto& flags = (*data.scroll).flags;
+ auto& increment = (*data.scroll).increment;
+
+ // number
+ Read(&number, &buf);
+
+ // scroll_type
+ uint16_t tmp11;
+ Read(&tmp11, &buf);
+ scroll_type = static_cast<Input::ScrollType>(tmp11);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // flags
+ uint32_t tmp12;
+ Read(&tmp12, &buf);
+ flags = static_cast<Input::ScrollFlags>(tmp12);
+
+ // increment
+ {
+ auto& integral = increment.integral;
+ auto& frac = increment.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+ }
+ if (CaseEq(data_expr, Input::DeviceClassType::Touch)) {
+ data.touch.emplace();
+ auto& mode = (*data.touch).mode;
+ auto& num_touches = (*data.touch).num_touches;
+
+ // mode
+ uint8_t tmp13;
+ Read(&tmp13, &buf);
+ mode = static_cast<Input::TouchMode>(tmp13);
+
+ // num_touches
+ Read(&num_touches, &buf);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::DeviceEvent>(Input::DeviceEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& deviceid = (*event_).deviceid;
+ auto& time = (*event_).time;
+ auto& detail = (*event_).detail;
+ auto& root = (*event_).root;
+ auto& event = (*event_).event;
+ auto& child = (*event_).child;
+ auto& root_x = (*event_).root_x;
+ auto& root_y = (*event_).root_y;
+ auto& event_x = (*event_).event_x;
+ auto& event_y = (*event_).event_y;
+ uint16_t buttons_len{};
+ uint16_t valuators_len{};
+ auto& sourceid = (*event_).sourceid;
+ auto& flags = (*event_).flags;
+ auto& mods = (*event_).mods;
+ auto& group = (*event_).group;
+ auto& button_mask = (*event_).button_mask;
+ size_t button_mask_len = button_mask.size();
+ auto& valuator_mask = (*event_).valuator_mask;
+ size_t valuator_mask_len = valuator_mask.size();
+ auto& axisvalues = (*event_).axisvalues;
+ size_t axisvalues_len = axisvalues.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // detail
+ Read(&detail, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // event_x
+ Read(&event_x, &buf);
+
+ // event_y
+ Read(&event_y, &buf);
+
+ // buttons_len
+ Read(&buttons_len, &buf);
+
+ // valuators_len
+ Read(&valuators_len, &buf);
+
+ // sourceid
+ Read(&sourceid, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // flags
+ uint32_t tmp14;
+ Read(&tmp14, &buf);
+ flags = static_cast<Input::KeyEventFlags>(tmp14);
+
+ // mods
+ {
+ auto& base = mods.base;
+ auto& latched = mods.latched;
+ auto& locked = mods.locked;
+ auto& effective = mods.effective;
+
+ // base
+ Read(&base, &buf);
+
+ // latched
+ Read(&latched, &buf);
+
+ // locked
+ Read(&locked, &buf);
+
+ // effective
+ Read(&effective, &buf);
+ }
+
+ // group
+ {
+ auto& base = group.base;
+ auto& latched = group.latched;
+ auto& locked = group.locked;
+ auto& effective = group.effective;
+
+ // base
+ Read(&base, &buf);
+
+ // latched
+ Read(&latched, &buf);
+
+ // locked
+ Read(&locked, &buf);
+
+ // effective
+ Read(&effective, &buf);
+ }
+
+ // button_mask
+ button_mask.resize(buttons_len);
+ for (auto& button_mask_elem : button_mask) {
+ // button_mask_elem
+ Read(&button_mask_elem, &buf);
+ }
+
+ // valuator_mask
+ valuator_mask.resize(valuators_len);
+ for (auto& valuator_mask_elem : valuator_mask) {
+ // valuator_mask_elem
+ Read(&valuator_mask_elem, &buf);
+ }
+
+ // axisvalues
+ auto sum15_ = SumOf([](auto& listelem_ref) { return PopCount(listelem_ref); },
+ valuator_mask);
+ axisvalues.resize(sum15_);
+ for (auto& axisvalues_elem : axisvalues) {
+ // axisvalues_elem
+ {
+ auto& integral = axisvalues_elem.integral;
+ auto& frac = axisvalues_elem.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::CrossingEvent>(Input::CrossingEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& deviceid = (*event_).deviceid;
+ auto& time = (*event_).time;
+ auto& sourceid = (*event_).sourceid;
+ auto& mode = (*event_).mode;
+ auto& detail = (*event_).detail;
+ auto& root = (*event_).root;
+ auto& event = (*event_).event;
+ auto& child = (*event_).child;
+ auto& root_x = (*event_).root_x;
+ auto& root_y = (*event_).root_y;
+ auto& event_x = (*event_).event_x;
+ auto& event_y = (*event_).event_y;
+ auto& same_screen = (*event_).same_screen;
+ auto& focus = (*event_).focus;
+ uint16_t buttons_len{};
+ auto& mods = (*event_).mods;
+ auto& group = (*event_).group;
+ auto& buttons = (*event_).buttons;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // sourceid
+ Read(&sourceid, &buf);
+
+ // mode
+ uint8_t tmp16;
+ Read(&tmp16, &buf);
+ mode = static_cast<Input::NotifyMode>(tmp16);
+
+ // detail
+ uint8_t tmp17;
+ Read(&tmp17, &buf);
+ detail = static_cast<Input::NotifyDetail>(tmp17);
+
+ // root
+ Read(&root, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // event_x
+ Read(&event_x, &buf);
+
+ // event_y
+ Read(&event_y, &buf);
+
+ // same_screen
+ Read(&same_screen, &buf);
+
+ // focus
+ Read(&focus, &buf);
+
+ // buttons_len
+ Read(&buttons_len, &buf);
+
+ // mods
+ {
+ auto& base = mods.base;
+ auto& latched = mods.latched;
+ auto& locked = mods.locked;
+ auto& effective = mods.effective;
+
+ // base
+ Read(&base, &buf);
+
+ // latched
+ Read(&latched, &buf);
+
+ // locked
+ Read(&locked, &buf);
+
+ // effective
+ Read(&effective, &buf);
+ }
+
+ // group
+ {
+ auto& base = group.base;
+ auto& latched = group.latched;
+ auto& locked = group.locked;
+ auto& effective = group.effective;
+
+ // base
+ Read(&base, &buf);
+
+ // latched
+ Read(&latched, &buf);
+
+ // locked
+ Read(&locked, &buf);
+
+ // effective
+ Read(&effective, &buf);
+ }
+
+ // buttons
+ buttons.resize(buttons_len);
+ for (auto& buttons_elem : buttons) {
+ // buttons_elem
+ Read(&buttons_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::HierarchyEvent>(Input::HierarchyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& deviceid = (*event_).deviceid;
+ auto& time = (*event_).time;
+ auto& flags = (*event_).flags;
+ uint16_t num_infos{};
+ auto& infos = (*event_).infos;
+ size_t infos_len = infos.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // flags
+ uint32_t tmp18;
+ Read(&tmp18, &buf);
+ flags = static_cast<Input::HierarchyMask>(tmp18);
+
+ // num_infos
+ Read(&num_infos, &buf);
+
+ // pad0
+ Pad(&buf, 10);
+
+ // infos
+ infos.resize(num_infos);
+ for (auto& infos_elem : infos) {
+ // infos_elem
+ {
+ auto& deviceid = infos_elem.deviceid;
+ auto& attachment = infos_elem.attachment;
+ auto& type = infos_elem.type;
+ auto& enabled = infos_elem.enabled;
+ auto& flags = infos_elem.flags;
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // attachment
+ Read(&attachment, &buf);
+
+ // type
+ uint8_t tmp19;
+ Read(&tmp19, &buf);
+ type = static_cast<Input::DeviceType>(tmp19);
+
+ // enabled
+ Read(&enabled, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // flags
+ uint32_t tmp20;
+ Read(&tmp20, &buf);
+ flags = static_cast<Input::HierarchyMask>(tmp20);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::PropertyEvent>(Input::PropertyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& deviceid = (*event_).deviceid;
+ auto& time = (*event_).time;
+ auto& property = (*event_).property;
+ auto& what = (*event_).what;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // property
+ Read(&property, &buf);
+
+ // what
+ uint8_t tmp21;
+ Read(&tmp21, &buf);
+ what = static_cast<Input::PropertyFlag>(tmp21);
+
+ // pad0
+ Pad(&buf, 11);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::RawDeviceEvent>(Input::RawDeviceEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& deviceid = (*event_).deviceid;
+ auto& time = (*event_).time;
+ auto& detail = (*event_).detail;
+ auto& sourceid = (*event_).sourceid;
+ uint16_t valuators_len{};
+ auto& flags = (*event_).flags;
+ auto& valuator_mask = (*event_).valuator_mask;
+ size_t valuator_mask_len = valuator_mask.size();
+ auto& axisvalues = (*event_).axisvalues;
+ size_t axisvalues_len = axisvalues.size();
+ auto& axisvalues_raw = (*event_).axisvalues_raw;
+ size_t axisvalues_raw_len = axisvalues_raw.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // detail
+ Read(&detail, &buf);
+
+ // sourceid
+ Read(&sourceid, &buf);
+
+ // valuators_len
+ Read(&valuators_len, &buf);
+
+ // flags
+ uint32_t tmp22;
+ Read(&tmp22, &buf);
+ flags = static_cast<Input::KeyEventFlags>(tmp22);
+
+ // pad0
+ Pad(&buf, 4);
+
+ // valuator_mask
+ valuator_mask.resize(valuators_len);
+ for (auto& valuator_mask_elem : valuator_mask) {
+ // valuator_mask_elem
+ Read(&valuator_mask_elem, &buf);
+ }
+
+ // axisvalues
+ auto sum23_ = SumOf([](auto& listelem_ref) { return PopCount(listelem_ref); },
+ valuator_mask);
+ axisvalues.resize(sum23_);
+ for (auto& axisvalues_elem : axisvalues) {
+ // axisvalues_elem
+ {
+ auto& integral = axisvalues_elem.integral;
+ auto& frac = axisvalues_elem.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+ }
+
+ // axisvalues_raw
+ auto sum24_ = SumOf([](auto& listelem_ref) { return PopCount(listelem_ref); },
+ valuator_mask);
+ axisvalues_raw.resize(sum24_);
+ for (auto& axisvalues_raw_elem : axisvalues_raw) {
+ // axisvalues_raw_elem
+ {
+ auto& integral = axisvalues_raw_elem.integral;
+ auto& frac = axisvalues_raw_elem.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::TouchOwnershipEvent>(Input::TouchOwnershipEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& deviceid = (*event_).deviceid;
+ auto& time = (*event_).time;
+ auto& touchid = (*event_).touchid;
+ auto& root = (*event_).root;
+ auto& event = (*event_).event;
+ auto& child = (*event_).child;
+ auto& sourceid = (*event_).sourceid;
+ auto& flags = (*event_).flags;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // touchid
+ Read(&touchid, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // sourceid
+ Read(&sourceid, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // flags
+ uint32_t tmp25;
+ Read(&tmp25, &buf);
+ flags = static_cast<Input::TouchOwnershipFlags>(tmp25);
+
+ // pad1
+ Pad(&buf, 8);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::BarrierEvent>(Input::BarrierEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& deviceid = (*event_).deviceid;
+ auto& time = (*event_).time;
+ auto& eventid = (*event_).eventid;
+ auto& root = (*event_).root;
+ auto& event = (*event_).event;
+ auto& barrier = (*event_).barrier;
+ auto& dtime = (*event_).dtime;
+ auto& flags = (*event_).flags;
+ auto& sourceid = (*event_).sourceid;
+ auto& root_x = (*event_).root_x;
+ auto& root_y = (*event_).root_y;
+ auto& dx = (*event_).dx;
+ auto& dy = (*event_).dy;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // eventid
+ Read(&eventid, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // barrier
+ Read(&barrier, &buf);
+
+ // dtime
+ Read(&dtime, &buf);
+
+ // flags
+ uint32_t tmp26;
+ Read(&tmp26, &buf);
+ flags = static_cast<Input::BarrierFlags>(tmp26);
+
+ // sourceid
+ Read(&sourceid, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // dx
+ {
+ auto& integral = dx.integral;
+ auto& frac = dx.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+
+ // dy
+ {
+ auto& integral = dy.integral;
+ auto& frac = dy.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+std::string Input::DeviceError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Input::DeviceError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Input::DeviceError>(Input::DeviceError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Input::EventError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Input::EventError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Input::EventError>(Input::EventError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Input::ModeError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Input::ModeError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Input::ModeError>(Input::ModeError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Input::DeviceBusyError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Input::DeviceBusyError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Input::DeviceBusyError>(Input::DeviceBusyError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Input::ClassError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Input::ClassError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Input::ClassError>(Input::ClassError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+Future<Input::GetExtensionVersionReply> Input::GetExtensionVersion(
+ const Input::GetExtensionVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint16_t name_len{};
+ auto& name = request.name;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // name_len
+ name_len = name.size();
+ buf.Write(&name_len);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(name_len), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GetExtensionVersionReply>(
+ &buf, "Input::GetExtensionVersion", false);
+}
+
+Future<Input::GetExtensionVersionReply> Input::GetExtensionVersion(
+ const std::string& name) {
+ return Input::GetExtensionVersion(Input::GetExtensionVersionRequest{name});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GetExtensionVersionReply> detail::ReadReply<
+ Input::GetExtensionVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GetExtensionVersionReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& server_major = (*reply).server_major;
+ auto& server_minor = (*reply).server_minor;
+ auto& present = (*reply).present;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // server_major
+ Read(&server_major, &buf);
+
+ // server_minor
+ Read(&server_minor, &buf);
+
+ // present
+ Read(&present, &buf);
+
+ // pad0
+ Pad(&buf, 19);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::ListInputDevicesReply> Input::ListInputDevices(
+ const Input::ListInputDevicesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::ListInputDevicesReply>(
+ &buf, "Input::ListInputDevices", false);
+}
+
+Future<Input::ListInputDevicesReply> Input::ListInputDevices() {
+ return Input::ListInputDevices(Input::ListInputDevicesRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::ListInputDevicesReply> detail::ReadReply<
+ Input::ListInputDevicesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::ListInputDevicesReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ uint8_t devices_len{};
+ auto& devices = (*reply).devices;
+ auto& infos = (*reply).infos;
+ size_t infos_len = infos.size();
+ auto& names = (*reply).names;
+ size_t names_len = names.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // devices_len
+ Read(&devices_len, &buf);
+
+ // pad0
+ Pad(&buf, 23);
+
+ // devices
+ devices.resize(devices_len);
+ for (auto& devices_elem : devices) {
+ // devices_elem
+ {
+ auto& device_type = devices_elem.device_type;
+ auto& device_id = devices_elem.device_id;
+ auto& num_class_info = devices_elem.num_class_info;
+ auto& device_use = devices_elem.device_use;
+
+ // device_type
+ Read(&device_type, &buf);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ // num_class_info
+ Read(&num_class_info, &buf);
+
+ // device_use
+ uint8_t tmp27;
+ Read(&tmp27, &buf);
+ device_use = static_cast<Input::DeviceUse>(tmp27);
+
+ // pad0
+ Pad(&buf, 1);
+ }
+ }
+
+ // infos
+ auto sum28_ = SumOf(
+ [](auto& listelem_ref) {
+ auto& device_type = listelem_ref.device_type;
+ auto& device_id = listelem_ref.device_id;
+ auto& num_class_info = listelem_ref.num_class_info;
+ auto& device_use = listelem_ref.device_use;
+
+ return num_class_info;
+ },
+ devices);
+ infos.resize(sum28_);
+ for (auto& infos_elem : infos) {
+ // infos_elem
+ {
+ Input::InputClass class_id{};
+ auto& len = infos_elem.len;
+ auto& info = infos_elem;
+
+ // class_id
+ uint8_t tmp29;
+ Read(&tmp29, &buf);
+ class_id = static_cast<Input::InputClass>(tmp29);
+
+ // len
+ Read(&len, &buf);
+
+ // info
+ auto info_expr = class_id;
+ if (CaseEq(info_expr, Input::InputClass::Key)) {
+ info.key.emplace();
+ auto& min_keycode = (*info.key).min_keycode;
+ auto& max_keycode = (*info.key).max_keycode;
+ auto& num_keys = (*info.key).num_keys;
+
+ // min_keycode
+ Read(&min_keycode, &buf);
+
+ // max_keycode
+ Read(&max_keycode, &buf);
+
+ // num_keys
+ Read(&num_keys, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+ }
+ if (CaseEq(info_expr, Input::InputClass::Button)) {
+ info.button.emplace();
+ auto& num_buttons = (*info.button).num_buttons;
+
+ // num_buttons
+ Read(&num_buttons, &buf);
+ }
+ if (CaseEq(info_expr, Input::InputClass::Valuator)) {
+ info.valuator.emplace();
+ uint8_t axes_len{};
+ auto& mode = (*info.valuator).mode;
+ auto& motion_size = (*info.valuator).motion_size;
+ auto& axes = (*info.valuator).axes;
+
+ // axes_len
+ Read(&axes_len, &buf);
+
+ // mode
+ uint8_t tmp30;
+ Read(&tmp30, &buf);
+ mode = static_cast<Input::ValuatorMode>(tmp30);
+
+ // motion_size
+ Read(&motion_size, &buf);
+
+ // axes
+ axes.resize(axes_len);
+ for (auto& axes_elem : axes) {
+ // axes_elem
+ {
+ auto& resolution = axes_elem.resolution;
+ auto& minimum = axes_elem.minimum;
+ auto& maximum = axes_elem.maximum;
+
+ // resolution
+ Read(&resolution, &buf);
+
+ // minimum
+ Read(&minimum, &buf);
+
+ // maximum
+ Read(&maximum, &buf);
+ }
+ }
+ }
+ }
+ }
+
+ // names
+ names.resize(devices_len);
+ for (auto& names_elem : names) {
+ // names_elem
+ {
+ uint8_t name_len{};
+ auto& name = names_elem.name;
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // name
+ name.resize(name_len);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+ }
+ }
+
+ // pad1
+ Pad(&buf, 1);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::OpenDeviceReply> Input::OpenDevice(
+ const Input::OpenDeviceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::OpenDeviceReply>(
+ &buf, "Input::OpenDevice", false);
+}
+
+Future<Input::OpenDeviceReply> Input::OpenDevice(const uint8_t& device_id) {
+ return Input::OpenDevice(Input::OpenDeviceRequest{device_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::OpenDeviceReply> detail::ReadReply<
+ Input::OpenDeviceReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::OpenDeviceReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ uint8_t num_classes{};
+ auto& class_info = (*reply).class_info;
+ size_t class_info_len = class_info.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_classes
+ Read(&num_classes, &buf);
+
+ // pad0
+ Pad(&buf, 23);
+
+ // class_info
+ class_info.resize(num_classes);
+ for (auto& class_info_elem : class_info) {
+ // class_info_elem
+ {
+ auto& class_id = class_info_elem.class_id;
+ auto& event_type_base = class_info_elem.event_type_base;
+
+ // class_id
+ uint8_t tmp31;
+ Read(&tmp31, &buf);
+ class_id = static_cast<Input::InputClass>(tmp31);
+
+ // event_type_base
+ Read(&event_type_base, &buf);
+ }
+ }
+
+ // pad1
+ Align(&buf, 4);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::CloseDevice(const Input::CloseDeviceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::CloseDevice", false);
+}
+
+Future<void> Input::CloseDevice(const uint8_t& device_id) {
+ return Input::CloseDevice(Input::CloseDeviceRequest{device_id});
+}
+
+Future<Input::SetDeviceModeReply> Input::SetDeviceMode(
+ const Input::SetDeviceModeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+ auto& mode = request.mode;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // mode
+ uint8_t tmp32;
+ tmp32 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp32);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::SetDeviceModeReply>(
+ &buf, "Input::SetDeviceMode", false);
+}
+
+Future<Input::SetDeviceModeReply> Input::SetDeviceMode(
+ const uint8_t& device_id,
+ const ValuatorMode& mode) {
+ return Input::SetDeviceMode(Input::SetDeviceModeRequest{device_id, mode});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::SetDeviceModeReply> detail::ReadReply<
+ Input::SetDeviceModeReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::SetDeviceModeReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& status = (*reply).status;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status
+ uint8_t tmp33;
+ Read(&tmp33, &buf);
+ status = static_cast<GrabStatus>(tmp33);
+
+ // pad0
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::SelectExtensionEvent(
+ const Input::SelectExtensionEventRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ uint16_t num_classes{};
+ auto& classes = request.classes;
+ size_t classes_len = classes.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // num_classes
+ num_classes = classes.size();
+ buf.Write(&num_classes);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // classes
+ DCHECK_EQ(static_cast<size_t>(num_classes), classes.size());
+ for (auto& classes_elem : classes) {
+ // classes_elem
+ buf.Write(&classes_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::SelectExtensionEvent",
+ false);
+}
+
+Future<void> Input::SelectExtensionEvent(
+ const Window& window,
+ const std::vector<EventClass>& classes) {
+ return Input::SelectExtensionEvent(
+ Input::SelectExtensionEventRequest{window, classes});
+}
+
+Future<Input::GetSelectedExtensionEventsReply>
+Input::GetSelectedExtensionEvents(
+ const Input::GetSelectedExtensionEventsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GetSelectedExtensionEventsReply>(
+ &buf, "Input::GetSelectedExtensionEvents", false);
+}
+
+Future<Input::GetSelectedExtensionEventsReply>
+Input::GetSelectedExtensionEvents(const Window& window) {
+ return Input::GetSelectedExtensionEvents(
+ Input::GetSelectedExtensionEventsRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GetSelectedExtensionEventsReply> detail::ReadReply<
+ Input::GetSelectedExtensionEventsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GetSelectedExtensionEventsReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ uint16_t num_this_classes{};
+ uint16_t num_all_classes{};
+ auto& this_classes = (*reply).this_classes;
+ size_t this_classes_len = this_classes.size();
+ auto& all_classes = (*reply).all_classes;
+ size_t all_classes_len = all_classes.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_this_classes
+ Read(&num_this_classes, &buf);
+
+ // num_all_classes
+ Read(&num_all_classes, &buf);
+
+ // pad0
+ Pad(&buf, 20);
+
+ // this_classes
+ this_classes.resize(num_this_classes);
+ for (auto& this_classes_elem : this_classes) {
+ // this_classes_elem
+ Read(&this_classes_elem, &buf);
+ }
+
+ // all_classes
+ all_classes.resize(num_all_classes);
+ for (auto& all_classes_elem : all_classes) {
+ // all_classes_elem
+ Read(&all_classes_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::ChangeDeviceDontPropagateList(
+ const Input::ChangeDeviceDontPropagateListRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ uint16_t num_classes{};
+ auto& mode = request.mode;
+ auto& classes = request.classes;
+ size_t classes_len = classes.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // num_classes
+ num_classes = classes.size();
+ buf.Write(&num_classes);
+
+ // mode
+ uint8_t tmp34;
+ tmp34 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp34);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // classes
+ DCHECK_EQ(static_cast<size_t>(num_classes), classes.size());
+ for (auto& classes_elem : classes) {
+ // classes_elem
+ buf.Write(&classes_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(
+ &buf, "Input::ChangeDeviceDontPropagateList", false);
+}
+
+Future<void> Input::ChangeDeviceDontPropagateList(
+ const Window& window,
+ const PropagateMode& mode,
+ const std::vector<EventClass>& classes) {
+ return Input::ChangeDeviceDontPropagateList(
+ Input::ChangeDeviceDontPropagateListRequest{window, mode, classes});
+}
+
+Future<Input::GetDeviceDontPropagateListReply>
+Input::GetDeviceDontPropagateList(
+ const Input::GetDeviceDontPropagateListRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GetDeviceDontPropagateListReply>(
+ &buf, "Input::GetDeviceDontPropagateList", false);
+}
+
+Future<Input::GetDeviceDontPropagateListReply>
+Input::GetDeviceDontPropagateList(const Window& window) {
+ return Input::GetDeviceDontPropagateList(
+ Input::GetDeviceDontPropagateListRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GetDeviceDontPropagateListReply> detail::ReadReply<
+ Input::GetDeviceDontPropagateListReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GetDeviceDontPropagateListReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ uint16_t num_classes{};
+ auto& classes = (*reply).classes;
+ size_t classes_len = classes.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_classes
+ Read(&num_classes, &buf);
+
+ // pad0
+ Pad(&buf, 22);
+
+ // classes
+ classes.resize(num_classes);
+ for (auto& classes_elem : classes) {
+ // classes_elem
+ Read(&classes_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::GetDeviceMotionEventsReply> Input::GetDeviceMotionEvents(
+ const Input::GetDeviceMotionEventsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& start = request.start;
+ auto& stop = request.stop;
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // start
+ buf.Write(&start);
+
+ // stop
+ buf.Write(&stop);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GetDeviceMotionEventsReply>(
+ &buf, "Input::GetDeviceMotionEvents", false);
+}
+
+Future<Input::GetDeviceMotionEventsReply> Input::GetDeviceMotionEvents(
+ const Time& start,
+ const Time& stop,
+ const uint8_t& device_id) {
+ return Input::GetDeviceMotionEvents(
+ Input::GetDeviceMotionEventsRequest{start, stop, device_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GetDeviceMotionEventsReply> detail::ReadReply<
+ Input::GetDeviceMotionEventsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GetDeviceMotionEventsReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ uint32_t num_events{};
+ auto& num_axes = (*reply).num_axes;
+ auto& device_mode = (*reply).device_mode;
+ auto& events = (*reply).events;
+ size_t events_len = events.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_events
+ Read(&num_events, &buf);
+
+ // num_axes
+ Read(&num_axes, &buf);
+
+ // device_mode
+ uint8_t tmp35;
+ Read(&tmp35, &buf);
+ device_mode = static_cast<Input::ValuatorMode>(tmp35);
+
+ // pad0
+ Pad(&buf, 18);
+
+ // events
+ events.resize(num_events);
+ for (auto& events_elem : events) {
+ // events_elem
+ {
+ auto& time = events_elem.time;
+ auto& axisvalues = events_elem.axisvalues;
+ size_t axisvalues_len = axisvalues.size();
+
+ // time
+ Read(&time, &buf);
+
+ // axisvalues
+ axisvalues.resize(num_axes);
+ for (auto& axisvalues_elem : axisvalues) {
+ // axisvalues_elem
+ Read(&axisvalues_elem, &buf);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::ChangeKeyboardDeviceReply> Input::ChangeKeyboardDevice(
+ const Input::ChangeKeyboardDeviceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::ChangeKeyboardDeviceReply>(
+ &buf, "Input::ChangeKeyboardDevice", false);
+}
+
+Future<Input::ChangeKeyboardDeviceReply> Input::ChangeKeyboardDevice(
+ const uint8_t& device_id) {
+ return Input::ChangeKeyboardDevice(
+ Input::ChangeKeyboardDeviceRequest{device_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::ChangeKeyboardDeviceReply> detail::ReadReply<
+ Input::ChangeKeyboardDeviceReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::ChangeKeyboardDeviceReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& status = (*reply).status;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status
+ uint8_t tmp36;
+ Read(&tmp36, &buf);
+ status = static_cast<GrabStatus>(tmp36);
+
+ // pad0
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::ChangePointerDeviceReply> Input::ChangePointerDevice(
+ const Input::ChangePointerDeviceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& x_axis = request.x_axis;
+ auto& y_axis = request.y_axis;
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // x_axis
+ buf.Write(&x_axis);
+
+ // y_axis
+ buf.Write(&y_axis);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 1);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::ChangePointerDeviceReply>(
+ &buf, "Input::ChangePointerDevice", false);
+}
+
+Future<Input::ChangePointerDeviceReply> Input::ChangePointerDevice(
+ const uint8_t& x_axis,
+ const uint8_t& y_axis,
+ const uint8_t& device_id) {
+ return Input::ChangePointerDevice(
+ Input::ChangePointerDeviceRequest{x_axis, y_axis, device_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::ChangePointerDeviceReply> detail::ReadReply<
+ Input::ChangePointerDeviceReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::ChangePointerDeviceReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& status = (*reply).status;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status
+ uint8_t tmp37;
+ Read(&tmp37, &buf);
+ status = static_cast<GrabStatus>(tmp37);
+
+ // pad0
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::GrabDeviceReply> Input::GrabDevice(
+ const Input::GrabDeviceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& grab_window = request.grab_window;
+ auto& time = request.time;
+ uint16_t num_classes{};
+ auto& this_device_mode = request.this_device_mode;
+ auto& other_device_mode = request.other_device_mode;
+ auto& owner_events = request.owner_events;
+ auto& device_id = request.device_id;
+ auto& classes = request.classes;
+ size_t classes_len = classes.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // time
+ buf.Write(&time);
+
+ // num_classes
+ num_classes = classes.size();
+ buf.Write(&num_classes);
+
+ // this_device_mode
+ uint8_t tmp38;
+ tmp38 = static_cast<uint8_t>(this_device_mode);
+ buf.Write(&tmp38);
+
+ // other_device_mode
+ uint8_t tmp39;
+ tmp39 = static_cast<uint8_t>(other_device_mode);
+ buf.Write(&tmp39);
+
+ // owner_events
+ buf.Write(&owner_events);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // classes
+ DCHECK_EQ(static_cast<size_t>(num_classes), classes.size());
+ for (auto& classes_elem : classes) {
+ // classes_elem
+ buf.Write(&classes_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GrabDeviceReply>(
+ &buf, "Input::GrabDevice", false);
+}
+
+Future<Input::GrabDeviceReply> Input::GrabDevice(
+ const Window& grab_window,
+ const Time& time,
+ const GrabMode& this_device_mode,
+ const GrabMode& other_device_mode,
+ const uint8_t& owner_events,
+ const uint8_t& device_id,
+ const std::vector<EventClass>& classes) {
+ return Input::GrabDevice(Input::GrabDeviceRequest{
+ grab_window, time, this_device_mode, other_device_mode, owner_events,
+ device_id, classes});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GrabDeviceReply> detail::ReadReply<
+ Input::GrabDeviceReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GrabDeviceReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& status = (*reply).status;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status
+ uint8_t tmp40;
+ Read(&tmp40, &buf);
+ status = static_cast<GrabStatus>(tmp40);
+
+ // pad0
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::UngrabDevice(const Input::UngrabDeviceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& time = request.time;
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 14;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // time
+ buf.Write(&time);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::UngrabDevice", false);
+}
+
+Future<void> Input::UngrabDevice(const Time& time, const uint8_t& device_id) {
+ return Input::UngrabDevice(Input::UngrabDeviceRequest{time, device_id});
+}
+
+Future<void> Input::GrabDeviceKey(const Input::GrabDeviceKeyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& grab_window = request.grab_window;
+ uint16_t num_classes{};
+ auto& modifiers = request.modifiers;
+ auto& modifier_device = request.modifier_device;
+ auto& grabbed_device = request.grabbed_device;
+ auto& key = request.key;
+ auto& this_device_mode = request.this_device_mode;
+ auto& other_device_mode = request.other_device_mode;
+ auto& owner_events = request.owner_events;
+ auto& classes = request.classes;
+ size_t classes_len = classes.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 15;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // num_classes
+ num_classes = classes.size();
+ buf.Write(&num_classes);
+
+ // modifiers
+ uint16_t tmp41;
+ tmp41 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp41);
+
+ // modifier_device
+ buf.Write(&modifier_device);
+
+ // grabbed_device
+ buf.Write(&grabbed_device);
+
+ // key
+ buf.Write(&key);
+
+ // this_device_mode
+ uint8_t tmp42;
+ tmp42 = static_cast<uint8_t>(this_device_mode);
+ buf.Write(&tmp42);
+
+ // other_device_mode
+ uint8_t tmp43;
+ tmp43 = static_cast<uint8_t>(other_device_mode);
+ buf.Write(&tmp43);
+
+ // owner_events
+ buf.Write(&owner_events);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // classes
+ DCHECK_EQ(static_cast<size_t>(num_classes), classes.size());
+ for (auto& classes_elem : classes) {
+ // classes_elem
+ buf.Write(&classes_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::GrabDeviceKey", false);
+}
+
+Future<void> Input::GrabDeviceKey(const Window& grab_window,
+ const ModMask& modifiers,
+ const uint8_t& modifier_device,
+ const uint8_t& grabbed_device,
+ const uint8_t& key,
+ const GrabMode& this_device_mode,
+ const GrabMode& other_device_mode,
+ const uint8_t& owner_events,
+ const std::vector<EventClass>& classes) {
+ return Input::GrabDeviceKey(Input::GrabDeviceKeyRequest{
+ grab_window, modifiers, modifier_device, grabbed_device, key,
+ this_device_mode, other_device_mode, owner_events, classes});
+}
+
+Future<void> Input::UngrabDeviceKey(
+ const Input::UngrabDeviceKeyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& grabWindow = request.grabWindow;
+ auto& modifiers = request.modifiers;
+ auto& modifier_device = request.modifier_device;
+ auto& key = request.key;
+ auto& grabbed_device = request.grabbed_device;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 16;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grabWindow
+ buf.Write(&grabWindow);
+
+ // modifiers
+ uint16_t tmp44;
+ tmp44 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp44);
+
+ // modifier_device
+ buf.Write(&modifier_device);
+
+ // key
+ buf.Write(&key);
+
+ // grabbed_device
+ buf.Write(&grabbed_device);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::UngrabDeviceKey", false);
+}
+
+Future<void> Input::UngrabDeviceKey(const Window& grabWindow,
+ const ModMask& modifiers,
+ const uint8_t& modifier_device,
+ const uint8_t& key,
+ const uint8_t& grabbed_device) {
+ return Input::UngrabDeviceKey(Input::UngrabDeviceKeyRequest{
+ grabWindow, modifiers, modifier_device, key, grabbed_device});
+}
+
+Future<void> Input::GrabDeviceButton(
+ const Input::GrabDeviceButtonRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& grab_window = request.grab_window;
+ auto& grabbed_device = request.grabbed_device;
+ auto& modifier_device = request.modifier_device;
+ uint16_t num_classes{};
+ auto& modifiers = request.modifiers;
+ auto& this_device_mode = request.this_device_mode;
+ auto& other_device_mode = request.other_device_mode;
+ auto& button = request.button;
+ auto& owner_events = request.owner_events;
+ auto& classes = request.classes;
+ size_t classes_len = classes.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 17;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // grabbed_device
+ buf.Write(&grabbed_device);
+
+ // modifier_device
+ buf.Write(&modifier_device);
+
+ // num_classes
+ num_classes = classes.size();
+ buf.Write(&num_classes);
+
+ // modifiers
+ uint16_t tmp45;
+ tmp45 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp45);
+
+ // this_device_mode
+ uint8_t tmp46;
+ tmp46 = static_cast<uint8_t>(this_device_mode);
+ buf.Write(&tmp46);
+
+ // other_device_mode
+ uint8_t tmp47;
+ tmp47 = static_cast<uint8_t>(other_device_mode);
+ buf.Write(&tmp47);
+
+ // button
+ buf.Write(&button);
+
+ // owner_events
+ buf.Write(&owner_events);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // classes
+ DCHECK_EQ(static_cast<size_t>(num_classes), classes.size());
+ for (auto& classes_elem : classes) {
+ // classes_elem
+ buf.Write(&classes_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::GrabDeviceButton", false);
+}
+
+Future<void> Input::GrabDeviceButton(const Window& grab_window,
+ const uint8_t& grabbed_device,
+ const uint8_t& modifier_device,
+ const ModMask& modifiers,
+ const GrabMode& this_device_mode,
+ const GrabMode& other_device_mode,
+ const uint8_t& button,
+ const uint8_t& owner_events,
+ const std::vector<EventClass>& classes) {
+ return Input::GrabDeviceButton(Input::GrabDeviceButtonRequest{
+ grab_window, grabbed_device, modifier_device, modifiers, this_device_mode,
+ other_device_mode, button, owner_events, classes});
+}
+
+Future<void> Input::UngrabDeviceButton(
+ const Input::UngrabDeviceButtonRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& grab_window = request.grab_window;
+ auto& modifiers = request.modifiers;
+ auto& modifier_device = request.modifier_device;
+ auto& button = request.button;
+ auto& grabbed_device = request.grabbed_device;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 18;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // modifiers
+ uint16_t tmp48;
+ tmp48 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp48);
+
+ // modifier_device
+ buf.Write(&modifier_device);
+
+ // button
+ buf.Write(&button);
+
+ // grabbed_device
+ buf.Write(&grabbed_device);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::UngrabDeviceButton",
+ false);
+}
+
+Future<void> Input::UngrabDeviceButton(const Window& grab_window,
+ const ModMask& modifiers,
+ const uint8_t& modifier_device,
+ const uint8_t& button,
+ const uint8_t& grabbed_device) {
+ return Input::UngrabDeviceButton(Input::UngrabDeviceButtonRequest{
+ grab_window, modifiers, modifier_device, button, grabbed_device});
+}
+
+Future<void> Input::AllowDeviceEvents(
+ const Input::AllowDeviceEventsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& time = request.time;
+ auto& mode = request.mode;
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 19;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // time
+ buf.Write(&time);
+
+ // mode
+ uint8_t tmp49;
+ tmp49 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp49);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::AllowDeviceEvents",
+ false);
+}
+
+Future<void> Input::AllowDeviceEvents(const Time& time,
+ const DeviceInputMode& mode,
+ const uint8_t& device_id) {
+ return Input::AllowDeviceEvents(
+ Input::AllowDeviceEventsRequest{time, mode, device_id});
+}
+
+Future<Input::GetDeviceFocusReply> Input::GetDeviceFocus(
+ const Input::GetDeviceFocusRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 20;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GetDeviceFocusReply>(
+ &buf, "Input::GetDeviceFocus", false);
+}
+
+Future<Input::GetDeviceFocusReply> Input::GetDeviceFocus(
+ const uint8_t& device_id) {
+ return Input::GetDeviceFocus(Input::GetDeviceFocusRequest{device_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GetDeviceFocusReply> detail::ReadReply<
+ Input::GetDeviceFocusReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GetDeviceFocusReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& focus = (*reply).focus;
+ auto& time = (*reply).time;
+ auto& revert_to = (*reply).revert_to;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // focus
+ Read(&focus, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // revert_to
+ uint8_t tmp50;
+ Read(&tmp50, &buf);
+ revert_to = static_cast<InputFocus>(tmp50);
+
+ // pad0
+ Pad(&buf, 15);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::SetDeviceFocus(
+ const Input::SetDeviceFocusRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& focus = request.focus;
+ auto& time = request.time;
+ auto& revert_to = request.revert_to;
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 21;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // focus
+ buf.Write(&focus);
+
+ // time
+ buf.Write(&time);
+
+ // revert_to
+ uint8_t tmp51;
+ tmp51 = static_cast<uint8_t>(revert_to);
+ buf.Write(&tmp51);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::SetDeviceFocus", false);
+}
+
+Future<void> Input::SetDeviceFocus(const Window& focus,
+ const Time& time,
+ const InputFocus& revert_to,
+ const uint8_t& device_id) {
+ return Input::SetDeviceFocus(
+ Input::SetDeviceFocusRequest{focus, time, revert_to, device_id});
+}
+
+Future<Input::GetFeedbackControlReply> Input::GetFeedbackControl(
+ const Input::GetFeedbackControlRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 22;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GetFeedbackControlReply>(
+ &buf, "Input::GetFeedbackControl", false);
+}
+
+Future<Input::GetFeedbackControlReply> Input::GetFeedbackControl(
+ const uint8_t& device_id) {
+ return Input::GetFeedbackControl(Input::GetFeedbackControlRequest{device_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GetFeedbackControlReply> detail::ReadReply<
+ Input::GetFeedbackControlReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GetFeedbackControlReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ uint16_t num_feedbacks{};
+ auto& feedbacks = (*reply).feedbacks;
+ size_t feedbacks_len = feedbacks.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_feedbacks
+ Read(&num_feedbacks, &buf);
+
+ // pad0
+ Pad(&buf, 22);
+
+ // feedbacks
+ feedbacks.resize(num_feedbacks);
+ for (auto& feedbacks_elem : feedbacks) {
+ // feedbacks_elem
+ {
+ Input::FeedbackClass class_id{};
+ auto& feedback_id = feedbacks_elem.feedback_id;
+ auto& len = feedbacks_elem.len;
+ auto& data = feedbacks_elem;
+
+ // class_id
+ uint8_t tmp52;
+ Read(&tmp52, &buf);
+ class_id = static_cast<Input::FeedbackClass>(tmp52);
+
+ // feedback_id
+ Read(&feedback_id, &buf);
+
+ // len
+ Read(&len, &buf);
+
+ // data
+ auto data_expr = class_id;
+ if (CaseEq(data_expr, Input::FeedbackClass::Keyboard)) {
+ data.keyboard.emplace();
+ auto& pitch = (*data.keyboard).pitch;
+ auto& duration = (*data.keyboard).duration;
+ auto& led_mask = (*data.keyboard).led_mask;
+ auto& led_values = (*data.keyboard).led_values;
+ auto& global_auto_repeat = (*data.keyboard).global_auto_repeat;
+ auto& click = (*data.keyboard).click;
+ auto& percent = (*data.keyboard).percent;
+ auto& auto_repeats = (*data.keyboard).auto_repeats;
+ size_t auto_repeats_len = auto_repeats.size();
+
+ // pitch
+ Read(&pitch, &buf);
+
+ // duration
+ Read(&duration, &buf);
+
+ // led_mask
+ Read(&led_mask, &buf);
+
+ // led_values
+ Read(&led_values, &buf);
+
+ // global_auto_repeat
+ Read(&global_auto_repeat, &buf);
+
+ // click
+ Read(&click, &buf);
+
+ // percent
+ Read(&percent, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // auto_repeats
+ for (auto& auto_repeats_elem : auto_repeats) {
+ // auto_repeats_elem
+ Read(&auto_repeats_elem, &buf);
+ }
+ }
+ if (CaseEq(data_expr, Input::FeedbackClass::Pointer)) {
+ data.pointer.emplace();
+ auto& accel_num = (*data.pointer).accel_num;
+ auto& accel_denom = (*data.pointer).accel_denom;
+ auto& threshold = (*data.pointer).threshold;
+
+ // pad1
+ Pad(&buf, 2);
+
+ // accel_num
+ Read(&accel_num, &buf);
+
+ // accel_denom
+ Read(&accel_denom, &buf);
+
+ // threshold
+ Read(&threshold, &buf);
+ }
+ if (CaseEq(data_expr, Input::FeedbackClass::String)) {
+ data.string.emplace();
+ auto& max_symbols = (*data.string).max_symbols;
+ uint16_t num_keysyms{};
+ auto& keysyms = (*data.string).keysyms;
+ size_t keysyms_len = keysyms.size();
+
+ // max_symbols
+ Read(&max_symbols, &buf);
+
+ // num_keysyms
+ Read(&num_keysyms, &buf);
+
+ // keysyms
+ keysyms.resize(num_keysyms);
+ for (auto& keysyms_elem : keysyms) {
+ // keysyms_elem
+ Read(&keysyms_elem, &buf);
+ }
+ }
+ if (CaseEq(data_expr, Input::FeedbackClass::Integer)) {
+ data.integer.emplace();
+ auto& resolution = (*data.integer).resolution;
+ auto& min_value = (*data.integer).min_value;
+ auto& max_value = (*data.integer).max_value;
+
+ // resolution
+ Read(&resolution, &buf);
+
+ // min_value
+ Read(&min_value, &buf);
+
+ // max_value
+ Read(&max_value, &buf);
+ }
+ if (CaseEq(data_expr, Input::FeedbackClass::Led)) {
+ data.led.emplace();
+ auto& led_mask = (*data.led).led_mask;
+ auto& led_values = (*data.led).led_values;
+
+ // led_mask
+ Read(&led_mask, &buf);
+
+ // led_values
+ Read(&led_values, &buf);
+ }
+ if (CaseEq(data_expr, Input::FeedbackClass::Bell)) {
+ data.bell.emplace();
+ auto& percent = (*data.bell).percent;
+ auto& pitch = (*data.bell).pitch;
+ auto& duration = (*data.bell).duration;
+
+ // percent
+ Read(&percent, &buf);
+
+ // pad2
+ Pad(&buf, 3);
+
+ // pitch
+ Read(&pitch, &buf);
+
+ // duration
+ Read(&duration, &buf);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::ChangeFeedbackControl(
+ const Input::ChangeFeedbackControlRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& mask = request.mask;
+ auto& device_id = request.device_id;
+ auto& feedback_id = request.feedback_id;
+ auto& feedback = request.feedback;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 23;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // mask
+ uint32_t tmp53;
+ tmp53 = static_cast<uint32_t>(mask);
+ buf.Write(&tmp53);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // feedback_id
+ buf.Write(&feedback_id);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // feedback
+ {
+ FeedbackClass class_id{};
+ auto& feedback_id = feedback.feedback_id;
+ auto& len = feedback.len;
+ auto& data = feedback;
+
+ // class_id
+ SwitchVar(FeedbackClass::Keyboard, data.keyboard.has_value(), false,
+ &class_id);
+ SwitchVar(FeedbackClass::Pointer, data.pointer.has_value(), false,
+ &class_id);
+ SwitchVar(FeedbackClass::String, data.string.has_value(), false, &class_id);
+ SwitchVar(FeedbackClass::Integer, data.integer.has_value(), false,
+ &class_id);
+ SwitchVar(FeedbackClass::Led, data.led.has_value(), false, &class_id);
+ SwitchVar(FeedbackClass::Bell, data.bell.has_value(), false, &class_id);
+ uint8_t tmp54;
+ tmp54 = static_cast<uint8_t>(class_id);
+ buf.Write(&tmp54);
+
+ // feedback_id
+ buf.Write(&feedback_id);
+
+ // len
+ buf.Write(&len);
+
+ // data
+ auto data_expr = class_id;
+ if (CaseEq(data_expr, FeedbackClass::Keyboard)) {
+ auto& key = (*data.keyboard).key;
+ auto& auto_repeat_mode = (*data.keyboard).auto_repeat_mode;
+ auto& key_click_percent = (*data.keyboard).key_click_percent;
+ auto& bell_percent = (*data.keyboard).bell_percent;
+ auto& bell_pitch = (*data.keyboard).bell_pitch;
+ auto& bell_duration = (*data.keyboard).bell_duration;
+ auto& led_mask = (*data.keyboard).led_mask;
+ auto& led_values = (*data.keyboard).led_values;
+
+ // key
+ buf.Write(&key);
+
+ // auto_repeat_mode
+ buf.Write(&auto_repeat_mode);
+
+ // key_click_percent
+ buf.Write(&key_click_percent);
+
+ // bell_percent
+ buf.Write(&bell_percent);
+
+ // bell_pitch
+ buf.Write(&bell_pitch);
+
+ // bell_duration
+ buf.Write(&bell_duration);
+
+ // led_mask
+ buf.Write(&led_mask);
+
+ // led_values
+ buf.Write(&led_values);
+ }
+ if (CaseEq(data_expr, FeedbackClass::Pointer)) {
+ auto& num = (*data.pointer).num;
+ auto& denom = (*data.pointer).denom;
+ auto& threshold = (*data.pointer).threshold;
+
+ // pad0
+ Pad(&buf, 2);
+
+ // num
+ buf.Write(&num);
+
+ // denom
+ buf.Write(&denom);
+
+ // threshold
+ buf.Write(&threshold);
+ }
+ if (CaseEq(data_expr, FeedbackClass::String)) {
+ uint16_t num_keysyms{};
+ auto& keysyms = (*data.string).keysyms;
+ size_t keysyms_len = keysyms.size();
+
+ // pad1
+ Pad(&buf, 2);
+
+ // num_keysyms
+ num_keysyms = keysyms.size();
+ buf.Write(&num_keysyms);
+
+ // keysyms
+ DCHECK_EQ(static_cast<size_t>(num_keysyms), keysyms.size());
+ for (auto& keysyms_elem : keysyms) {
+ // keysyms_elem
+ buf.Write(&keysyms_elem);
+ }
+ }
+ if (CaseEq(data_expr, FeedbackClass::Integer)) {
+ auto& int_to_display = (*data.integer).int_to_display;
+
+ // int_to_display
+ buf.Write(&int_to_display);
+ }
+ if (CaseEq(data_expr, FeedbackClass::Led)) {
+ auto& led_mask = (*data.led).led_mask;
+ auto& led_values = (*data.led).led_values;
+
+ // led_mask
+ buf.Write(&led_mask);
+
+ // led_values
+ buf.Write(&led_values);
+ }
+ if (CaseEq(data_expr, FeedbackClass::Bell)) {
+ auto& percent = (*data.bell).percent;
+ auto& pitch = (*data.bell).pitch;
+ auto& duration = (*data.bell).duration;
+
+ // percent
+ buf.Write(&percent);
+
+ // pad2
+ Pad(&buf, 3);
+
+ // pitch
+ buf.Write(&pitch);
+
+ // duration
+ buf.Write(&duration);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::ChangeFeedbackControl",
+ false);
+}
+
+Future<void> Input::ChangeFeedbackControl(const ChangeFeedbackControlMask& mask,
+ const uint8_t& device_id,
+ const uint8_t& feedback_id,
+ const FeedbackCtl& feedback) {
+ return Input::ChangeFeedbackControl(Input::ChangeFeedbackControlRequest{
+ mask, device_id, feedback_id, feedback});
+}
+
+Future<Input::GetDeviceKeyMappingReply> Input::GetDeviceKeyMapping(
+ const Input::GetDeviceKeyMappingRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+ auto& first_keycode = request.first_keycode;
+ auto& count = request.count;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 24;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // first_keycode
+ buf.Write(&first_keycode);
+
+ // count
+ buf.Write(&count);
+
+ // pad0
+ Pad(&buf, 1);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GetDeviceKeyMappingReply>(
+ &buf, "Input::GetDeviceKeyMapping", false);
+}
+
+Future<Input::GetDeviceKeyMappingReply> Input::GetDeviceKeyMapping(
+ const uint8_t& device_id,
+ const KeyCode& first_keycode,
+ const uint8_t& count) {
+ return Input::GetDeviceKeyMapping(
+ Input::GetDeviceKeyMappingRequest{device_id, first_keycode, count});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GetDeviceKeyMappingReply> detail::ReadReply<
+ Input::GetDeviceKeyMappingReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GetDeviceKeyMappingReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& keysyms_per_keycode = (*reply).keysyms_per_keycode;
+ auto& keysyms = (*reply).keysyms;
+ size_t keysyms_len = keysyms.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // keysyms_per_keycode
+ Read(&keysyms_per_keycode, &buf);
+
+ // pad0
+ Pad(&buf, 23);
+
+ // keysyms
+ keysyms.resize(length);
+ for (auto& keysyms_elem : keysyms) {
+ // keysyms_elem
+ Read(&keysyms_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::ChangeDeviceKeyMapping(
+ const Input::ChangeDeviceKeyMappingRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+ auto& first_keycode = request.first_keycode;
+ auto& keysyms_per_keycode = request.keysyms_per_keycode;
+ auto& keycode_count = request.keycode_count;
+ auto& keysyms = request.keysyms;
+ size_t keysyms_len = keysyms.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 25;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // first_keycode
+ buf.Write(&first_keycode);
+
+ // keysyms_per_keycode
+ buf.Write(&keysyms_per_keycode);
+
+ // keycode_count
+ buf.Write(&keycode_count);
+
+ // keysyms
+ DCHECK_EQ(static_cast<size_t>((keycode_count) * (keysyms_per_keycode)),
+ keysyms.size());
+ for (auto& keysyms_elem : keysyms) {
+ // keysyms_elem
+ buf.Write(&keysyms_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::ChangeDeviceKeyMapping",
+ false);
+}
+
+Future<void> Input::ChangeDeviceKeyMapping(const uint8_t& device_id,
+ const KeyCode& first_keycode,
+ const uint8_t& keysyms_per_keycode,
+ const uint8_t& keycode_count,
+ const std::vector<KeySym>& keysyms) {
+ return Input::ChangeDeviceKeyMapping(Input::ChangeDeviceKeyMappingRequest{
+ device_id, first_keycode, keysyms_per_keycode, keycode_count, keysyms});
+}
+
+Future<Input::GetDeviceModifierMappingReply> Input::GetDeviceModifierMapping(
+ const Input::GetDeviceModifierMappingRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 26;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GetDeviceModifierMappingReply>(
+ &buf, "Input::GetDeviceModifierMapping", false);
+}
+
+Future<Input::GetDeviceModifierMappingReply> Input::GetDeviceModifierMapping(
+ const uint8_t& device_id) {
+ return Input::GetDeviceModifierMapping(
+ Input::GetDeviceModifierMappingRequest{device_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GetDeviceModifierMappingReply> detail::ReadReply<
+ Input::GetDeviceModifierMappingReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GetDeviceModifierMappingReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& keycodes_per_modifier = (*reply).keycodes_per_modifier;
+ auto& keymaps = (*reply).keymaps;
+ size_t keymaps_len = keymaps.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // keycodes_per_modifier
+ Read(&keycodes_per_modifier, &buf);
+
+ // pad0
+ Pad(&buf, 23);
+
+ // keymaps
+ keymaps.resize((keycodes_per_modifier) * (8));
+ for (auto& keymaps_elem : keymaps) {
+ // keymaps_elem
+ Read(&keymaps_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::SetDeviceModifierMappingReply> Input::SetDeviceModifierMapping(
+ const Input::SetDeviceModifierMappingRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+ auto& keycodes_per_modifier = request.keycodes_per_modifier;
+ auto& keymaps = request.keymaps;
+ size_t keymaps_len = keymaps.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 27;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // keycodes_per_modifier
+ buf.Write(&keycodes_per_modifier);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // keymaps
+ DCHECK_EQ(static_cast<size_t>((keycodes_per_modifier) * (8)), keymaps.size());
+ for (auto& keymaps_elem : keymaps) {
+ // keymaps_elem
+ buf.Write(&keymaps_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::SetDeviceModifierMappingReply>(
+ &buf, "Input::SetDeviceModifierMapping", false);
+}
+
+Future<Input::SetDeviceModifierMappingReply> Input::SetDeviceModifierMapping(
+ const uint8_t& device_id,
+ const uint8_t& keycodes_per_modifier,
+ const std::vector<uint8_t>& keymaps) {
+ return Input::SetDeviceModifierMapping(Input::SetDeviceModifierMappingRequest{
+ device_id, keycodes_per_modifier, keymaps});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::SetDeviceModifierMappingReply> detail::ReadReply<
+ Input::SetDeviceModifierMappingReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::SetDeviceModifierMappingReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& status = (*reply).status;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status
+ uint8_t tmp55;
+ Read(&tmp55, &buf);
+ status = static_cast<MappingStatus>(tmp55);
+
+ // pad0
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::GetDeviceButtonMappingReply> Input::GetDeviceButtonMapping(
+ const Input::GetDeviceButtonMappingRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 28;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GetDeviceButtonMappingReply>(
+ &buf, "Input::GetDeviceButtonMapping", false);
+}
+
+Future<Input::GetDeviceButtonMappingReply> Input::GetDeviceButtonMapping(
+ const uint8_t& device_id) {
+ return Input::GetDeviceButtonMapping(
+ Input::GetDeviceButtonMappingRequest{device_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GetDeviceButtonMappingReply> detail::ReadReply<
+ Input::GetDeviceButtonMappingReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GetDeviceButtonMappingReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ uint8_t map_size{};
+ auto& map = (*reply).map;
+ size_t map_len = map.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // map_size
+ Read(&map_size, &buf);
+
+ // pad0
+ Pad(&buf, 23);
+
+ // map
+ map.resize(map_size);
+ for (auto& map_elem : map) {
+ // map_elem
+ Read(&map_elem, &buf);
+ }
+
+ // pad1
+ Align(&buf, 4);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::SetDeviceButtonMappingReply> Input::SetDeviceButtonMapping(
+ const Input::SetDeviceButtonMappingRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+ uint8_t map_size{};
+ auto& map = request.map;
+ size_t map_len = map.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 29;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // map_size
+ map_size = map.size();
+ buf.Write(&map_size);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // map
+ DCHECK_EQ(static_cast<size_t>(map_size), map.size());
+ for (auto& map_elem : map) {
+ // map_elem
+ buf.Write(&map_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::SetDeviceButtonMappingReply>(
+ &buf, "Input::SetDeviceButtonMapping", false);
+}
+
+Future<Input::SetDeviceButtonMappingReply> Input::SetDeviceButtonMapping(
+ const uint8_t& device_id,
+ const std::vector<uint8_t>& map) {
+ return Input::SetDeviceButtonMapping(
+ Input::SetDeviceButtonMappingRequest{device_id, map});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::SetDeviceButtonMappingReply> detail::ReadReply<
+ Input::SetDeviceButtonMappingReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::SetDeviceButtonMappingReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& status = (*reply).status;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status
+ uint8_t tmp56;
+ Read(&tmp56, &buf);
+ status = static_cast<MappingStatus>(tmp56);
+
+ // pad0
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::QueryDeviceStateReply> Input::QueryDeviceState(
+ const Input::QueryDeviceStateRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 30;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::QueryDeviceStateReply>(
+ &buf, "Input::QueryDeviceState", false);
+}
+
+Future<Input::QueryDeviceStateReply> Input::QueryDeviceState(
+ const uint8_t& device_id) {
+ return Input::QueryDeviceState(Input::QueryDeviceStateRequest{device_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::QueryDeviceStateReply> detail::ReadReply<
+ Input::QueryDeviceStateReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::QueryDeviceStateReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ uint8_t num_classes{};
+ auto& classes = (*reply).classes;
+ size_t classes_len = classes.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_classes
+ Read(&num_classes, &buf);
+
+ // pad0
+ Pad(&buf, 23);
+
+ // classes
+ classes.resize(num_classes);
+ for (auto& classes_elem : classes) {
+ // classes_elem
+ {
+ Input::InputClass class_id{};
+ auto& len = classes_elem.len;
+ auto& data = classes_elem;
+
+ // class_id
+ uint8_t tmp57;
+ Read(&tmp57, &buf);
+ class_id = static_cast<Input::InputClass>(tmp57);
+
+ // len
+ Read(&len, &buf);
+
+ // data
+ auto data_expr = class_id;
+ if (CaseEq(data_expr, Input::InputClass::Key)) {
+ data.key.emplace();
+ auto& num_keys = (*data.key).num_keys;
+ auto& keys = (*data.key).keys;
+ size_t keys_len = keys.size();
+
+ // num_keys
+ Read(&num_keys, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // keys
+ for (auto& keys_elem : keys) {
+ // keys_elem
+ Read(&keys_elem, &buf);
+ }
+ }
+ if (CaseEq(data_expr, Input::InputClass::Button)) {
+ data.button.emplace();
+ auto& num_buttons = (*data.button).num_buttons;
+ auto& buttons = (*data.button).buttons;
+ size_t buttons_len = buttons.size();
+
+ // num_buttons
+ Read(&num_buttons, &buf);
+
+ // pad1
+ Pad(&buf, 1);
+
+ // buttons
+ for (auto& buttons_elem : buttons) {
+ // buttons_elem
+ Read(&buttons_elem, &buf);
+ }
+ }
+ if (CaseEq(data_expr, Input::InputClass::Valuator)) {
+ data.valuator.emplace();
+ uint8_t num_valuators{};
+ auto& mode = (*data.valuator).mode;
+ auto& valuators = (*data.valuator).valuators;
+ size_t valuators_len = valuators.size();
+
+ // num_valuators
+ Read(&num_valuators, &buf);
+
+ // mode
+ uint8_t tmp58;
+ Read(&tmp58, &buf);
+ mode = static_cast<Input::ValuatorStateModeMask>(tmp58);
+
+ // valuators
+ valuators.resize(num_valuators);
+ for (auto& valuators_elem : valuators) {
+ // valuators_elem
+ Read(&valuators_elem, &buf);
+ }
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::DeviceBell(const Input::DeviceBellRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+ auto& feedback_id = request.feedback_id;
+ auto& feedback_class = request.feedback_class;
+ auto& percent = request.percent;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 32;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // feedback_id
+ buf.Write(&feedback_id);
+
+ // feedback_class
+ buf.Write(&feedback_class);
+
+ // percent
+ buf.Write(&percent);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::DeviceBell", false);
+}
+
+Future<void> Input::DeviceBell(const uint8_t& device_id,
+ const uint8_t& feedback_id,
+ const uint8_t& feedback_class,
+ const int8_t& percent) {
+ return Input::DeviceBell(Input::DeviceBellRequest{device_id, feedback_id,
+ feedback_class, percent});
+}
+
+Future<Input::SetDeviceValuatorsReply> Input::SetDeviceValuators(
+ const Input::SetDeviceValuatorsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+ auto& first_valuator = request.first_valuator;
+ uint8_t num_valuators{};
+ auto& valuators = request.valuators;
+ size_t valuators_len = valuators.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 33;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // first_valuator
+ buf.Write(&first_valuator);
+
+ // num_valuators
+ num_valuators = valuators.size();
+ buf.Write(&num_valuators);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // valuators
+ DCHECK_EQ(static_cast<size_t>(num_valuators), valuators.size());
+ for (auto& valuators_elem : valuators) {
+ // valuators_elem
+ buf.Write(&valuators_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::SetDeviceValuatorsReply>(
+ &buf, "Input::SetDeviceValuators", false);
+}
+
+Future<Input::SetDeviceValuatorsReply> Input::SetDeviceValuators(
+ const uint8_t& device_id,
+ const uint8_t& first_valuator,
+ const std::vector<int32_t>& valuators) {
+ return Input::SetDeviceValuators(
+ Input::SetDeviceValuatorsRequest{device_id, first_valuator, valuators});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::SetDeviceValuatorsReply> detail::ReadReply<
+ Input::SetDeviceValuatorsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::SetDeviceValuatorsReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& status = (*reply).status;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status
+ uint8_t tmp59;
+ Read(&tmp59, &buf);
+ status = static_cast<GrabStatus>(tmp59);
+
+ // pad0
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::GetDeviceControlReply> Input::GetDeviceControl(
+ const Input::GetDeviceControlRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& control_id = request.control_id;
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 34;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // control_id
+ uint16_t tmp60;
+ tmp60 = static_cast<uint16_t>(control_id);
+ buf.Write(&tmp60);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 1);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GetDeviceControlReply>(
+ &buf, "Input::GetDeviceControl", false);
+}
+
+Future<Input::GetDeviceControlReply> Input::GetDeviceControl(
+ const DeviceControl& control_id,
+ const uint8_t& device_id) {
+ return Input::GetDeviceControl(
+ Input::GetDeviceControlRequest{control_id, device_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GetDeviceControlReply> detail::ReadReply<
+ Input::GetDeviceControlReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GetDeviceControlReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& status = (*reply).status;
+ auto& control = (*reply).control;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status
+ Read(&status, &buf);
+
+ // pad0
+ Pad(&buf, 23);
+
+ // control
+ {
+ Input::DeviceControl control_id{};
+ auto& len = control.len;
+ auto& data = control;
+
+ // control_id
+ uint16_t tmp61;
+ Read(&tmp61, &buf);
+ control_id = static_cast<Input::DeviceControl>(tmp61);
+
+ // len
+ Read(&len, &buf);
+
+ // data
+ auto data_expr = control_id;
+ if (CaseEq(data_expr, Input::DeviceControl::resolution)) {
+ data.resolution.emplace();
+ uint32_t num_valuators{};
+ auto& resolution_values = (*data.resolution).resolution_values;
+ size_t resolution_values_len = resolution_values.size();
+ auto& resolution_min = (*data.resolution).resolution_min;
+ size_t resolution_min_len = resolution_min.size();
+ auto& resolution_max = (*data.resolution).resolution_max;
+ size_t resolution_max_len = resolution_max.size();
+
+ // num_valuators
+ Read(&num_valuators, &buf);
+
+ // resolution_values
+ resolution_values.resize(num_valuators);
+ for (auto& resolution_values_elem : resolution_values) {
+ // resolution_values_elem
+ Read(&resolution_values_elem, &buf);
+ }
+
+ // resolution_min
+ resolution_min.resize(num_valuators);
+ for (auto& resolution_min_elem : resolution_min) {
+ // resolution_min_elem
+ Read(&resolution_min_elem, &buf);
+ }
+
+ // resolution_max
+ resolution_max.resize(num_valuators);
+ for (auto& resolution_max_elem : resolution_max) {
+ // resolution_max_elem
+ Read(&resolution_max_elem, &buf);
+ }
+ }
+ if (CaseEq(data_expr, Input::DeviceControl::abs_calib)) {
+ data.abs_calib.emplace();
+ auto& min_x = (*data.abs_calib).min_x;
+ auto& max_x = (*data.abs_calib).max_x;
+ auto& min_y = (*data.abs_calib).min_y;
+ auto& max_y = (*data.abs_calib).max_y;
+ auto& flip_x = (*data.abs_calib).flip_x;
+ auto& flip_y = (*data.abs_calib).flip_y;
+ auto& rotation = (*data.abs_calib).rotation;
+ auto& button_threshold = (*data.abs_calib).button_threshold;
+
+ // min_x
+ Read(&min_x, &buf);
+
+ // max_x
+ Read(&max_x, &buf);
+
+ // min_y
+ Read(&min_y, &buf);
+
+ // max_y
+ Read(&max_y, &buf);
+
+ // flip_x
+ Read(&flip_x, &buf);
+
+ // flip_y
+ Read(&flip_y, &buf);
+
+ // rotation
+ Read(&rotation, &buf);
+
+ // button_threshold
+ Read(&button_threshold, &buf);
+ }
+ if (CaseEq(data_expr, Input::DeviceControl::core)) {
+ data.core.emplace();
+ auto& status = (*data.core).status;
+ auto& iscore = (*data.core).iscore;
+
+ // status
+ Read(&status, &buf);
+
+ // iscore
+ Read(&iscore, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+ }
+ if (CaseEq(data_expr, Input::DeviceControl::enable)) {
+ data.enable.emplace();
+ auto& enable = (*data.enable).enable;
+
+ // enable
+ Read(&enable, &buf);
+
+ // pad1
+ Pad(&buf, 3);
+ }
+ if (CaseEq(data_expr, Input::DeviceControl::abs_area)) {
+ data.abs_area.emplace();
+ auto& offset_x = (*data.abs_area).offset_x;
+ auto& offset_y = (*data.abs_area).offset_y;
+ auto& width = (*data.abs_area).width;
+ auto& height = (*data.abs_area).height;
+ auto& screen = (*data.abs_area).screen;
+ auto& following = (*data.abs_area).following;
+
+ // offset_x
+ Read(&offset_x, &buf);
+
+ // offset_y
+ Read(&offset_y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // screen
+ Read(&screen, &buf);
+
+ // following
+ Read(&following, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::ChangeDeviceControlReply> Input::ChangeDeviceControl(
+ const Input::ChangeDeviceControlRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& control_id = request.control_id;
+ auto& device_id = request.device_id;
+ auto& control = request.control;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 35;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // control_id
+ uint16_t tmp62;
+ tmp62 = static_cast<uint16_t>(control_id);
+ buf.Write(&tmp62);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // control
+ {
+ DeviceControl control_id{};
+ auto& len = control.len;
+ auto& data = control;
+
+ // control_id
+ SwitchVar(DeviceControl::resolution, data.resolution.has_value(), false,
+ &control_id);
+ SwitchVar(DeviceControl::abs_calib, data.abs_calib.has_value(), false,
+ &control_id);
+ SwitchVar(DeviceControl::core, data.core.has_value(), false, &control_id);
+ SwitchVar(DeviceControl::enable, data.enable.has_value(), false,
+ &control_id);
+ SwitchVar(DeviceControl::abs_area, data.abs_area.has_value(), false,
+ &control_id);
+ uint16_t tmp63;
+ tmp63 = static_cast<uint16_t>(control_id);
+ buf.Write(&tmp63);
+
+ // len
+ buf.Write(&len);
+
+ // data
+ auto data_expr = control_id;
+ if (CaseEq(data_expr, DeviceControl::resolution)) {
+ auto& first_valuator = (*data.resolution).first_valuator;
+ uint8_t num_valuators{};
+ auto& resolution_values = (*data.resolution).resolution_values;
+ size_t resolution_values_len = resolution_values.size();
+
+ // first_valuator
+ buf.Write(&first_valuator);
+
+ // num_valuators
+ num_valuators = resolution_values.size();
+ buf.Write(&num_valuators);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // resolution_values
+ DCHECK_EQ(static_cast<size_t>(num_valuators), resolution_values.size());
+ for (auto& resolution_values_elem : resolution_values) {
+ // resolution_values_elem
+ buf.Write(&resolution_values_elem);
+ }
+ }
+ if (CaseEq(data_expr, DeviceControl::abs_calib)) {
+ auto& min_x = (*data.abs_calib).min_x;
+ auto& max_x = (*data.abs_calib).max_x;
+ auto& min_y = (*data.abs_calib).min_y;
+ auto& max_y = (*data.abs_calib).max_y;
+ auto& flip_x = (*data.abs_calib).flip_x;
+ auto& flip_y = (*data.abs_calib).flip_y;
+ auto& rotation = (*data.abs_calib).rotation;
+ auto& button_threshold = (*data.abs_calib).button_threshold;
+
+ // min_x
+ buf.Write(&min_x);
+
+ // max_x
+ buf.Write(&max_x);
+
+ // min_y
+ buf.Write(&min_y);
+
+ // max_y
+ buf.Write(&max_y);
+
+ // flip_x
+ buf.Write(&flip_x);
+
+ // flip_y
+ buf.Write(&flip_y);
+
+ // rotation
+ buf.Write(&rotation);
+
+ // button_threshold
+ buf.Write(&button_threshold);
+ }
+ if (CaseEq(data_expr, DeviceControl::core)) {
+ auto& status = (*data.core).status;
+
+ // status
+ buf.Write(&status);
+
+ // pad1
+ Pad(&buf, 3);
+ }
+ if (CaseEq(data_expr, DeviceControl::enable)) {
+ auto& enable = (*data.enable).enable;
+
+ // enable
+ buf.Write(&enable);
+
+ // pad2
+ Pad(&buf, 3);
+ }
+ if (CaseEq(data_expr, DeviceControl::abs_area)) {
+ auto& offset_x = (*data.abs_area).offset_x;
+ auto& offset_y = (*data.abs_area).offset_y;
+ auto& width = (*data.abs_area).width;
+ auto& height = (*data.abs_area).height;
+ auto& screen = (*data.abs_area).screen;
+ auto& following = (*data.abs_area).following;
+
+ // offset_x
+ buf.Write(&offset_x);
+
+ // offset_y
+ buf.Write(&offset_y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // screen
+ buf.Write(&screen);
+
+ // following
+ buf.Write(&following);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::ChangeDeviceControlReply>(
+ &buf, "Input::ChangeDeviceControl", false);
+}
+
+Future<Input::ChangeDeviceControlReply> Input::ChangeDeviceControl(
+ const DeviceControl& control_id,
+ const uint8_t& device_id,
+ const DeviceCtl& control) {
+ return Input::ChangeDeviceControl(
+ Input::ChangeDeviceControlRequest{control_id, device_id, control});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::ChangeDeviceControlReply> detail::ReadReply<
+ Input::ChangeDeviceControlReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::ChangeDeviceControlReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& status = (*reply).status;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status
+ Read(&status, &buf);
+
+ // pad0
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::ListDevicePropertiesReply> Input::ListDeviceProperties(
+ const Input::ListDevicePropertiesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 36;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::ListDevicePropertiesReply>(
+ &buf, "Input::ListDeviceProperties", false);
+}
+
+Future<Input::ListDevicePropertiesReply> Input::ListDeviceProperties(
+ const uint8_t& device_id) {
+ return Input::ListDeviceProperties(
+ Input::ListDevicePropertiesRequest{device_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::ListDevicePropertiesReply> detail::ReadReply<
+ Input::ListDevicePropertiesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::ListDevicePropertiesReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ uint16_t num_atoms{};
+ auto& atoms = (*reply).atoms;
+ size_t atoms_len = atoms.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_atoms
+ Read(&num_atoms, &buf);
+
+ // pad0
+ Pad(&buf, 22);
+
+ // atoms
+ atoms.resize(num_atoms);
+ for (auto& atoms_elem : atoms) {
+ // atoms_elem
+ Read(&atoms_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::ChangeDeviceProperty(
+ const Input::ChangeDevicePropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& property = request.property;
+ auto& type = request.type;
+ auto& device_id = request.device_id;
+ PropertyFormat format{};
+ auto& mode = request.mode;
+ auto& num_items = request.num_items;
+ auto& items = request;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 37;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // property
+ buf.Write(&property);
+
+ // type
+ buf.Write(&type);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // format
+ SwitchVar(PropertyFormat::c_8Bits, items.data8.has_value(), false, &format);
+ SwitchVar(PropertyFormat::c_16Bits, items.data16.has_value(), false, &format);
+ SwitchVar(PropertyFormat::c_32Bits, items.data32.has_value(), false, &format);
+ uint8_t tmp64;
+ tmp64 = static_cast<uint8_t>(format);
+ buf.Write(&tmp64);
+
+ // mode
+ uint8_t tmp65;
+ tmp65 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp65);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // num_items
+ buf.Write(&num_items);
+
+ // items
+ auto items_expr = format;
+ if (CaseEq(items_expr, PropertyFormat::c_8Bits)) {
+ auto& data8 = *items.data8;
+ size_t data8_len = data8.size();
+
+ // data8
+ DCHECK_EQ(static_cast<size_t>(num_items), data8.size());
+ for (auto& data8_elem : data8) {
+ // data8_elem
+ buf.Write(&data8_elem);
+ }
+
+ // pad1
+ Align(&buf, 4);
+ }
+ if (CaseEq(items_expr, PropertyFormat::c_16Bits)) {
+ auto& data16 = *items.data16;
+ size_t data16_len = data16.size();
+
+ // data16
+ DCHECK_EQ(static_cast<size_t>(num_items), data16.size());
+ for (auto& data16_elem : data16) {
+ // data16_elem
+ buf.Write(&data16_elem);
+ }
+
+ // pad2
+ Align(&buf, 4);
+ }
+ if (CaseEq(items_expr, PropertyFormat::c_32Bits)) {
+ auto& data32 = *items.data32;
+ size_t data32_len = data32.size();
+
+ // data32
+ DCHECK_EQ(static_cast<size_t>(num_items), data32.size());
+ for (auto& data32_elem : data32) {
+ // data32_elem
+ buf.Write(&data32_elem);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::ChangeDeviceProperty",
+ false);
+}
+
+Future<void> Input::ChangeDeviceProperty(
+ const Atom& property,
+ const Atom& type,
+ const uint8_t& device_id,
+ const PropMode& mode,
+ const uint32_t& num_items,
+ const base::Optional<std::vector<uint8_t>>& data8,
+ const base::Optional<std::vector<uint16_t>>& data16,
+ const base::Optional<std::vector<uint32_t>>& data32) {
+ return Input::ChangeDeviceProperty(Input::ChangeDevicePropertyRequest{
+ property, type, device_id, mode, num_items, data8, data16, data32});
+}
+
+Future<void> Input::DeleteDeviceProperty(
+ const Input::DeleteDevicePropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& property = request.property;
+ auto& device_id = request.device_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 38;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // property
+ buf.Write(&property);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::DeleteDeviceProperty",
+ false);
+}
+
+Future<void> Input::DeleteDeviceProperty(const Atom& property,
+ const uint8_t& device_id) {
+ return Input::DeleteDeviceProperty(
+ Input::DeleteDevicePropertyRequest{property, device_id});
+}
+
+Future<Input::GetDevicePropertyReply> Input::GetDeviceProperty(
+ const Input::GetDevicePropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& property = request.property;
+ auto& type = request.type;
+ auto& offset = request.offset;
+ auto& len = request.len;
+ auto& device_id = request.device_id;
+ auto& c_delete = request.c_delete;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 39;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // property
+ buf.Write(&property);
+
+ // type
+ buf.Write(&type);
+
+ // offset
+ buf.Write(&offset);
+
+ // len
+ buf.Write(&len);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // c_delete
+ buf.Write(&c_delete);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::GetDevicePropertyReply>(
+ &buf, "Input::GetDeviceProperty", false);
+}
+
+Future<Input::GetDevicePropertyReply> Input::GetDeviceProperty(
+ const Atom& property,
+ const Atom& type,
+ const uint32_t& offset,
+ const uint32_t& len,
+ const uint8_t& device_id,
+ const uint8_t& c_delete) {
+ return Input::GetDeviceProperty(Input::GetDevicePropertyRequest{
+ property, type, offset, len, device_id, c_delete});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::GetDevicePropertyReply> detail::ReadReply<
+ Input::GetDevicePropertyReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::GetDevicePropertyReply>();
+
+ auto& xi_reply_type = (*reply).xi_reply_type;
+ auto& sequence = (*reply).sequence;
+ auto& type = (*reply).type;
+ auto& bytes_after = (*reply).bytes_after;
+ auto& num_items = (*reply).num_items;
+ Input::PropertyFormat format{};
+ auto& device_id = (*reply).device_id;
+ auto& items = (*reply);
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xi_reply_type
+ Read(&xi_reply_type, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // type
+ Read(&type, &buf);
+
+ // bytes_after
+ Read(&bytes_after, &buf);
+
+ // num_items
+ Read(&num_items, &buf);
+
+ // format
+ uint8_t tmp66;
+ Read(&tmp66, &buf);
+ format = static_cast<Input::PropertyFormat>(tmp66);
+
+ // device_id
+ Read(&device_id, &buf);
+
+ // pad0
+ Pad(&buf, 10);
+
+ // items
+ auto items_expr = format;
+ if (CaseEq(items_expr, Input::PropertyFormat::c_8Bits)) {
+ items.data8.emplace();
+ auto& data8 = *items.data8;
+ size_t data8_len = data8.size();
+
+ // data8
+ data8.resize(num_items);
+ for (auto& data8_elem : data8) {
+ // data8_elem
+ Read(&data8_elem, &buf);
+ }
+
+ // pad1
+ Align(&buf, 4);
+ }
+ if (CaseEq(items_expr, Input::PropertyFormat::c_16Bits)) {
+ items.data16.emplace();
+ auto& data16 = *items.data16;
+ size_t data16_len = data16.size();
+
+ // data16
+ data16.resize(num_items);
+ for (auto& data16_elem : data16) {
+ // data16_elem
+ Read(&data16_elem, &buf);
+ }
+
+ // pad2
+ Align(&buf, 4);
+ }
+ if (CaseEq(items_expr, Input::PropertyFormat::c_32Bits)) {
+ items.data32.emplace();
+ auto& data32 = *items.data32;
+ size_t data32_len = data32.size();
+
+ // data32
+ data32.resize(num_items);
+ for (auto& data32_elem : data32) {
+ // data32_elem
+ Read(&data32_elem, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::XIQueryPointerReply> Input::XIQueryPointer(
+ const Input::XIQueryPointerRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& deviceid = request.deviceid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 40;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::XIQueryPointerReply>(
+ &buf, "Input::XIQueryPointer", false);
+}
+
+Future<Input::XIQueryPointerReply> Input::XIQueryPointer(
+ const Window& window,
+ const DeviceId& deviceid) {
+ return Input::XIQueryPointer(Input::XIQueryPointerRequest{window, deviceid});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::XIQueryPointerReply> detail::ReadReply<
+ Input::XIQueryPointerReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::XIQueryPointerReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& root = (*reply).root;
+ auto& child = (*reply).child;
+ auto& root_x = (*reply).root_x;
+ auto& root_y = (*reply).root_y;
+ auto& win_x = (*reply).win_x;
+ auto& win_y = (*reply).win_y;
+ auto& same_screen = (*reply).same_screen;
+ uint16_t buttons_len{};
+ auto& mods = (*reply).mods;
+ auto& group = (*reply).group;
+ auto& buttons = (*reply).buttons;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // win_x
+ Read(&win_x, &buf);
+
+ // win_y
+ Read(&win_y, &buf);
+
+ // same_screen
+ Read(&same_screen, &buf);
+
+ // pad1
+ Pad(&buf, 1);
+
+ // buttons_len
+ Read(&buttons_len, &buf);
+
+ // mods
+ {
+ auto& base = mods.base;
+ auto& latched = mods.latched;
+ auto& locked = mods.locked;
+ auto& effective = mods.effective;
+
+ // base
+ Read(&base, &buf);
+
+ // latched
+ Read(&latched, &buf);
+
+ // locked
+ Read(&locked, &buf);
+
+ // effective
+ Read(&effective, &buf);
+ }
+
+ // group
+ {
+ auto& base = group.base;
+ auto& latched = group.latched;
+ auto& locked = group.locked;
+ auto& effective = group.effective;
+
+ // base
+ Read(&base, &buf);
+
+ // latched
+ Read(&latched, &buf);
+
+ // locked
+ Read(&locked, &buf);
+
+ // effective
+ Read(&effective, &buf);
+ }
+
+ // buttons
+ buttons.resize(buttons_len);
+ for (auto& buttons_elem : buttons) {
+ // buttons_elem
+ Read(&buttons_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::XIWarpPointer(const Input::XIWarpPointerRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& src_win = request.src_win;
+ auto& dst_win = request.dst_win;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& src_width = request.src_width;
+ auto& src_height = request.src_height;
+ auto& dst_x = request.dst_x;
+ auto& dst_y = request.dst_y;
+ auto& deviceid = request.deviceid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 41;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // src_win
+ buf.Write(&src_win);
+
+ // dst_win
+ buf.Write(&dst_win);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // src_width
+ buf.Write(&src_width);
+
+ // src_height
+ buf.Write(&src_height);
+
+ // dst_x
+ buf.Write(&dst_x);
+
+ // dst_y
+ buf.Write(&dst_y);
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XIWarpPointer", false);
+}
+
+Future<void> Input::XIWarpPointer(const Window& src_win,
+ const Window& dst_win,
+ const Fp1616& src_x,
+ const Fp1616& src_y,
+ const uint16_t& src_width,
+ const uint16_t& src_height,
+ const Fp1616& dst_x,
+ const Fp1616& dst_y,
+ const DeviceId& deviceid) {
+ return Input::XIWarpPointer(
+ Input::XIWarpPointerRequest{src_win, dst_win, src_x, src_y, src_width,
+ src_height, dst_x, dst_y, deviceid});
+}
+
+Future<void> Input::XIChangeCursor(
+ const Input::XIChangeCursorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& cursor = request.cursor;
+ auto& deviceid = request.deviceid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 42;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // cursor
+ buf.Write(&cursor);
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XIChangeCursor", false);
+}
+
+Future<void> Input::XIChangeCursor(const Window& window,
+ const Cursor& cursor,
+ const DeviceId& deviceid) {
+ return Input::XIChangeCursor(
+ Input::XIChangeCursorRequest{window, cursor, deviceid});
+}
+
+Future<void> Input::XIChangeHierarchy(
+ const Input::XIChangeHierarchyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint8_t num_changes{};
+ auto& changes = request.changes;
+ size_t changes_len = changes.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 43;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // num_changes
+ num_changes = changes.size();
+ buf.Write(&num_changes);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // changes
+ DCHECK_EQ(static_cast<size_t>(num_changes), changes.size());
+ for (auto& changes_elem : changes) {
+ // changes_elem
+ {
+ HierarchyChangeType type{};
+ auto& len = changes_elem.len;
+ auto& data = changes_elem;
+
+ // type
+ SwitchVar(HierarchyChangeType::AddMaster, data.add_master.has_value(),
+ false, &type);
+ SwitchVar(HierarchyChangeType::RemoveMaster,
+ data.remove_master.has_value(), false, &type);
+ SwitchVar(HierarchyChangeType::AttachSlave, data.attach_slave.has_value(),
+ false, &type);
+ SwitchVar(HierarchyChangeType::DetachSlave, data.detach_slave.has_value(),
+ false, &type);
+ uint16_t tmp67;
+ tmp67 = static_cast<uint16_t>(type);
+ buf.Write(&tmp67);
+
+ // len
+ buf.Write(&len);
+
+ // data
+ auto data_expr = type;
+ if (CaseEq(data_expr, HierarchyChangeType::AddMaster)) {
+ uint16_t name_len{};
+ auto& send_core = (*data.add_master).send_core;
+ auto& enable = (*data.add_master).enable;
+ auto& name = (*data.add_master).name;
+
+ // name_len
+ name_len = name.size();
+ buf.Write(&name_len);
+
+ // send_core
+ buf.Write(&send_core);
+
+ // enable
+ buf.Write(&enable);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(name_len), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ // pad0
+ Align(&buf, 4);
+ }
+ if (CaseEq(data_expr, HierarchyChangeType::RemoveMaster)) {
+ auto& deviceid = (*data.remove_master).deviceid;
+ auto& return_mode = (*data.remove_master).return_mode;
+ auto& return_pointer = (*data.remove_master).return_pointer;
+ auto& return_keyboard = (*data.remove_master).return_keyboard;
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // return_mode
+ uint8_t tmp68;
+ tmp68 = static_cast<uint8_t>(return_mode);
+ buf.Write(&tmp68);
+
+ // pad1
+ Pad(&buf, 1);
+
+ // return_pointer
+ buf.Write(&return_pointer);
+
+ // return_keyboard
+ buf.Write(&return_keyboard);
+ }
+ if (CaseEq(data_expr, HierarchyChangeType::AttachSlave)) {
+ auto& deviceid = (*data.attach_slave).deviceid;
+ auto& master = (*data.attach_slave).master;
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // master
+ buf.Write(&master);
+ }
+ if (CaseEq(data_expr, HierarchyChangeType::DetachSlave)) {
+ auto& deviceid = (*data.detach_slave).deviceid;
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad2
+ Pad(&buf, 2);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XIChangeHierarchy",
+ false);
+}
+
+Future<void> Input::XIChangeHierarchy(
+ const std::vector<HierarchyChange>& changes) {
+ return Input::XIChangeHierarchy(Input::XIChangeHierarchyRequest{changes});
+}
+
+Future<void> Input::XISetClientPointer(
+ const Input::XISetClientPointerRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& deviceid = request.deviceid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 44;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XISetClientPointer",
+ false);
+}
+
+Future<void> Input::XISetClientPointer(const Window& window,
+ const DeviceId& deviceid) {
+ return Input::XISetClientPointer(
+ Input::XISetClientPointerRequest{window, deviceid});
+}
+
+Future<Input::XIGetClientPointerReply> Input::XIGetClientPointer(
+ const Input::XIGetClientPointerRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 45;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::XIGetClientPointerReply>(
+ &buf, "Input::XIGetClientPointer", false);
+}
+
+Future<Input::XIGetClientPointerReply> Input::XIGetClientPointer(
+ const Window& window) {
+ return Input::XIGetClientPointer(Input::XIGetClientPointerRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::XIGetClientPointerReply> detail::ReadReply<
+ Input::XIGetClientPointerReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::XIGetClientPointerReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& set = (*reply).set;
+ auto& deviceid = (*reply).deviceid;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // set
+ Read(&set, &buf);
+
+ // pad1
+ Pad(&buf, 1);
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // pad2
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::XISelectEvents(
+ const Input::XISelectEventsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ uint16_t num_mask{};
+ auto& masks = request.masks;
+ size_t masks_len = masks.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 46;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // num_mask
+ num_mask = masks.size();
+ buf.Write(&num_mask);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // masks
+ DCHECK_EQ(static_cast<size_t>(num_mask), masks.size());
+ for (auto& masks_elem : masks) {
+ // masks_elem
+ {
+ auto& deviceid = masks_elem.deviceid;
+ uint16_t mask_len{};
+ auto& mask = masks_elem.mask;
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // mask_len
+ mask_len = mask.size();
+ buf.Write(&mask_len);
+
+ // mask
+ DCHECK_EQ(static_cast<size_t>(mask_len), mask.size());
+ for (auto& mask_elem : mask) {
+ // mask_elem
+ uint32_t tmp69;
+ tmp69 = static_cast<uint32_t>(mask_elem);
+ buf.Write(&tmp69);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XISelectEvents", false);
+}
+
+Future<void> Input::XISelectEvents(const Window& window,
+ const std::vector<EventMask>& masks) {
+ return Input::XISelectEvents(Input::XISelectEventsRequest{window, masks});
+}
+
+Future<Input::XIQueryVersionReply> Input::XIQueryVersion(
+ const Input::XIQueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major_version = request.major_version;
+ auto& minor_version = request.minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 47;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major_version
+ buf.Write(&major_version);
+
+ // minor_version
+ buf.Write(&minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::XIQueryVersionReply>(
+ &buf, "Input::XIQueryVersion", false);
+}
+
+Future<Input::XIQueryVersionReply> Input::XIQueryVersion(
+ const uint16_t& major_version,
+ const uint16_t& minor_version) {
+ return Input::XIQueryVersion(
+ Input::XIQueryVersionRequest{major_version, minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::XIQueryVersionReply> detail::ReadReply<
+ Input::XIQueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::XIQueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::XIQueryDeviceReply> Input::XIQueryDevice(
+ const Input::XIQueryDeviceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceid = request.deviceid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 48;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::XIQueryDeviceReply>(
+ &buf, "Input::XIQueryDevice", false);
+}
+
+Future<Input::XIQueryDeviceReply> Input::XIQueryDevice(
+ const DeviceId& deviceid) {
+ return Input::XIQueryDevice(Input::XIQueryDeviceRequest{deviceid});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::XIQueryDeviceReply> detail::ReadReply<
+ Input::XIQueryDeviceReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::XIQueryDeviceReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t num_infos{};
+ auto& infos = (*reply).infos;
+ size_t infos_len = infos.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_infos
+ Read(&num_infos, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // infos
+ infos.resize(num_infos);
+ for (auto& infos_elem : infos) {
+ // infos_elem
+ {
+ auto& deviceid = infos_elem.deviceid;
+ auto& type = infos_elem.type;
+ auto& attachment = infos_elem.attachment;
+ uint16_t num_classes{};
+ uint16_t name_len{};
+ auto& enabled = infos_elem.enabled;
+ auto& name = infos_elem.name;
+ auto& classes = infos_elem.classes;
+ size_t classes_len = classes.size();
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // type
+ uint16_t tmp70;
+ Read(&tmp70, &buf);
+ type = static_cast<Input::DeviceType>(tmp70);
+
+ // attachment
+ Read(&attachment, &buf);
+
+ // num_classes
+ Read(&num_classes, &buf);
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // enabled
+ Read(&enabled, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // name
+ name.resize(name_len);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ // pad1
+ Align(&buf, 4);
+
+ // classes
+ classes.resize(num_classes);
+ for (auto& classes_elem : classes) {
+ // classes_elem
+ {
+ Input::DeviceClassType type{};
+ auto& len = classes_elem.len;
+ auto& sourceid = classes_elem.sourceid;
+ auto& data = classes_elem;
+
+ // type
+ uint16_t tmp71;
+ Read(&tmp71, &buf);
+ type = static_cast<Input::DeviceClassType>(tmp71);
+
+ // len
+ Read(&len, &buf);
+
+ // sourceid
+ Read(&sourceid, &buf);
+
+ // data
+ auto data_expr = type;
+ if (CaseEq(data_expr, Input::DeviceClassType::Key)) {
+ data.key.emplace();
+ uint16_t num_keys{};
+ auto& keys = (*data.key).keys;
+ size_t keys_len = keys.size();
+
+ // num_keys
+ Read(&num_keys, &buf);
+
+ // keys
+ keys.resize(num_keys);
+ for (auto& keys_elem : keys) {
+ // keys_elem
+ Read(&keys_elem, &buf);
+ }
+ }
+ if (CaseEq(data_expr, Input::DeviceClassType::Button)) {
+ data.button.emplace();
+ uint16_t num_buttons{};
+ auto& state = (*data.button).state;
+ size_t state_len = state.size();
+ auto& labels = (*data.button).labels;
+ size_t labels_len = labels.size();
+
+ // num_buttons
+ Read(&num_buttons, &buf);
+
+ // state
+ state.resize(((num_buttons) + (31)) / (32));
+ for (auto& state_elem : state) {
+ // state_elem
+ Read(&state_elem, &buf);
+ }
+
+ // labels
+ labels.resize(num_buttons);
+ for (auto& labels_elem : labels) {
+ // labels_elem
+ Read(&labels_elem, &buf);
+ }
+ }
+ if (CaseEq(data_expr, Input::DeviceClassType::Valuator)) {
+ data.valuator.emplace();
+ auto& number = (*data.valuator).number;
+ auto& label = (*data.valuator).label;
+ auto& min = (*data.valuator).min;
+ auto& max = (*data.valuator).max;
+ auto& value = (*data.valuator).value;
+ auto& resolution = (*data.valuator).resolution;
+ auto& mode = (*data.valuator).mode;
+
+ // number
+ Read(&number, &buf);
+
+ // label
+ Read(&label, &buf);
+
+ // min
+ {
+ auto& integral = min.integral;
+ auto& frac = min.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+
+ // max
+ {
+ auto& integral = max.integral;
+ auto& frac = max.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+
+ // value
+ {
+ auto& integral = value.integral;
+ auto& frac = value.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+
+ // resolution
+ Read(&resolution, &buf);
+
+ // mode
+ uint8_t tmp72;
+ Read(&tmp72, &buf);
+ mode = static_cast<Input::ValuatorMode>(tmp72);
+
+ // pad0
+ Pad(&buf, 3);
+ }
+ if (CaseEq(data_expr, Input::DeviceClassType::Scroll)) {
+ data.scroll.emplace();
+ auto& number = (*data.scroll).number;
+ auto& scroll_type = (*data.scroll).scroll_type;
+ auto& flags = (*data.scroll).flags;
+ auto& increment = (*data.scroll).increment;
+
+ // number
+ Read(&number, &buf);
+
+ // scroll_type
+ uint16_t tmp73;
+ Read(&tmp73, &buf);
+ scroll_type = static_cast<Input::ScrollType>(tmp73);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // flags
+ uint32_t tmp74;
+ Read(&tmp74, &buf);
+ flags = static_cast<Input::ScrollFlags>(tmp74);
+
+ // increment
+ {
+ auto& integral = increment.integral;
+ auto& frac = increment.frac;
+
+ // integral
+ Read(&integral, &buf);
+
+ // frac
+ Read(&frac, &buf);
+ }
+ }
+ if (CaseEq(data_expr, Input::DeviceClassType::Touch)) {
+ data.touch.emplace();
+ auto& mode = (*data.touch).mode;
+ auto& num_touches = (*data.touch).num_touches;
+
+ // mode
+ uint8_t tmp75;
+ Read(&tmp75, &buf);
+ mode = static_cast<Input::TouchMode>(tmp75);
+
+ // num_touches
+ Read(&num_touches, &buf);
+ }
+ }
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::XISetFocus(const Input::XISetFocusRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& time = request.time;
+ auto& deviceid = request.deviceid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 49;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // time
+ buf.Write(&time);
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XISetFocus", false);
+}
+
+Future<void> Input::XISetFocus(const Window& window,
+ const Time& time,
+ const DeviceId& deviceid) {
+ return Input::XISetFocus(Input::XISetFocusRequest{window, time, deviceid});
+}
+
+Future<Input::XIGetFocusReply> Input::XIGetFocus(
+ const Input::XIGetFocusRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceid = request.deviceid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 50;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::XIGetFocusReply>(
+ &buf, "Input::XIGetFocus", false);
+}
+
+Future<Input::XIGetFocusReply> Input::XIGetFocus(const DeviceId& deviceid) {
+ return Input::XIGetFocus(Input::XIGetFocusRequest{deviceid});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::XIGetFocusReply> detail::ReadReply<
+ Input::XIGetFocusReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::XIGetFocusReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& focus = (*reply).focus;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // focus
+ Read(&focus, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::XIGrabDeviceReply> Input::XIGrabDevice(
+ const Input::XIGrabDeviceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& time = request.time;
+ auto& cursor = request.cursor;
+ auto& deviceid = request.deviceid;
+ auto& mode = request.mode;
+ auto& paired_device_mode = request.paired_device_mode;
+ auto& owner_events = request.owner_events;
+ uint16_t mask_len{};
+ auto& mask = request.mask;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 51;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // time
+ buf.Write(&time);
+
+ // cursor
+ buf.Write(&cursor);
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // mode
+ uint8_t tmp76;
+ tmp76 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp76);
+
+ // paired_device_mode
+ uint8_t tmp77;
+ tmp77 = static_cast<uint8_t>(paired_device_mode);
+ buf.Write(&tmp77);
+
+ // owner_events
+ uint8_t tmp78;
+ tmp78 = static_cast<uint8_t>(owner_events);
+ buf.Write(&tmp78);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // mask_len
+ mask_len = mask.size();
+ buf.Write(&mask_len);
+
+ // mask
+ DCHECK_EQ(static_cast<size_t>(mask_len), mask.size());
+ for (auto& mask_elem : mask) {
+ // mask_elem
+ buf.Write(&mask_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::XIGrabDeviceReply>(
+ &buf, "Input::XIGrabDevice", false);
+}
+
+Future<Input::XIGrabDeviceReply> Input::XIGrabDevice(
+ const Window& window,
+ const Time& time,
+ const Cursor& cursor,
+ const DeviceId& deviceid,
+ const GrabMode& mode,
+ const GrabMode& paired_device_mode,
+ const GrabOwner& owner_events,
+ const std::vector<uint32_t>& mask) {
+ return Input::XIGrabDevice(
+ Input::XIGrabDeviceRequest{window, time, cursor, deviceid, mode,
+ paired_device_mode, owner_events, mask});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::XIGrabDeviceReply> detail::ReadReply<
+ Input::XIGrabDeviceReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::XIGrabDeviceReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& status = (*reply).status;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status
+ uint8_t tmp79;
+ Read(&tmp79, &buf);
+ status = static_cast<GrabStatus>(tmp79);
+
+ // pad1
+ Pad(&buf, 23);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::XIUngrabDevice(
+ const Input::XIUngrabDeviceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& time = request.time;
+ auto& deviceid = request.deviceid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 52;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // time
+ buf.Write(&time);
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XIUngrabDevice", false);
+}
+
+Future<void> Input::XIUngrabDevice(const Time& time, const DeviceId& deviceid) {
+ return Input::XIUngrabDevice(Input::XIUngrabDeviceRequest{time, deviceid});
+}
+
+Future<void> Input::XIAllowEvents(const Input::XIAllowEventsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& time = request.time;
+ auto& deviceid = request.deviceid;
+ auto& event_mode = request.event_mode;
+ auto& touchid = request.touchid;
+ auto& grab_window = request.grab_window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 53;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // time
+ buf.Write(&time);
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // event_mode
+ uint8_t tmp80;
+ tmp80 = static_cast<uint8_t>(event_mode);
+ buf.Write(&tmp80);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // touchid
+ buf.Write(&touchid);
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XIAllowEvents", false);
+}
+
+Future<void> Input::XIAllowEvents(const Time& time,
+ const DeviceId& deviceid,
+ const EventMode& event_mode,
+ const uint32_t& touchid,
+ const Window& grab_window) {
+ return Input::XIAllowEvents(Input::XIAllowEventsRequest{
+ time, deviceid, event_mode, touchid, grab_window});
+}
+
+Future<Input::XIPassiveGrabDeviceReply> Input::XIPassiveGrabDevice(
+ const Input::XIPassiveGrabDeviceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& time = request.time;
+ auto& grab_window = request.grab_window;
+ auto& cursor = request.cursor;
+ auto& detail = request.detail;
+ auto& deviceid = request.deviceid;
+ uint16_t num_modifiers{};
+ uint16_t mask_len{};
+ auto& grab_type = request.grab_type;
+ auto& grab_mode = request.grab_mode;
+ auto& paired_device_mode = request.paired_device_mode;
+ auto& owner_events = request.owner_events;
+ auto& mask = request.mask;
+ auto& modifiers = request.modifiers;
+ size_t modifiers_len = modifiers.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 54;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // time
+ buf.Write(&time);
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // cursor
+ buf.Write(&cursor);
+
+ // detail
+ buf.Write(&detail);
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // num_modifiers
+ num_modifiers = modifiers.size();
+ buf.Write(&num_modifiers);
+
+ // mask_len
+ mask_len = mask.size();
+ buf.Write(&mask_len);
+
+ // grab_type
+ uint8_t tmp81;
+ tmp81 = static_cast<uint8_t>(grab_type);
+ buf.Write(&tmp81);
+
+ // grab_mode
+ uint8_t tmp82;
+ tmp82 = static_cast<uint8_t>(grab_mode);
+ buf.Write(&tmp82);
+
+ // paired_device_mode
+ uint8_t tmp83;
+ tmp83 = static_cast<uint8_t>(paired_device_mode);
+ buf.Write(&tmp83);
+
+ // owner_events
+ uint8_t tmp84;
+ tmp84 = static_cast<uint8_t>(owner_events);
+ buf.Write(&tmp84);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // mask
+ DCHECK_EQ(static_cast<size_t>(mask_len), mask.size());
+ for (auto& mask_elem : mask) {
+ // mask_elem
+ buf.Write(&mask_elem);
+ }
+
+ // modifiers
+ DCHECK_EQ(static_cast<size_t>(num_modifiers), modifiers.size());
+ for (auto& modifiers_elem : modifiers) {
+ // modifiers_elem
+ buf.Write(&modifiers_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::XIPassiveGrabDeviceReply>(
+ &buf, "Input::XIPassiveGrabDevice", false);
+}
+
+Future<Input::XIPassiveGrabDeviceReply> Input::XIPassiveGrabDevice(
+ const Time& time,
+ const Window& grab_window,
+ const Cursor& cursor,
+ const uint32_t& detail,
+ const DeviceId& deviceid,
+ const GrabType& grab_type,
+ const GrabMode22& grab_mode,
+ const GrabMode& paired_device_mode,
+ const GrabOwner& owner_events,
+ const std::vector<uint32_t>& mask,
+ const std::vector<uint32_t>& modifiers) {
+ return Input::XIPassiveGrabDevice(Input::XIPassiveGrabDeviceRequest{
+ time, grab_window, cursor, detail, deviceid, grab_type, grab_mode,
+ paired_device_mode, owner_events, mask, modifiers});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::XIPassiveGrabDeviceReply> detail::ReadReply<
+ Input::XIPassiveGrabDeviceReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::XIPassiveGrabDeviceReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t num_modifiers{};
+ auto& modifiers = (*reply).modifiers;
+ size_t modifiers_len = modifiers.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_modifiers
+ Read(&num_modifiers, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // modifiers
+ modifiers.resize(num_modifiers);
+ for (auto& modifiers_elem : modifiers) {
+ // modifiers_elem
+ {
+ auto& modifiers = modifiers_elem.modifiers;
+ auto& status = modifiers_elem.status;
+
+ // modifiers
+ Read(&modifiers, &buf);
+
+ // status
+ uint8_t tmp85;
+ Read(&tmp85, &buf);
+ status = static_cast<GrabStatus>(tmp85);
+
+ // pad0
+ Pad(&buf, 3);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::XIPassiveUngrabDevice(
+ const Input::XIPassiveUngrabDeviceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& grab_window = request.grab_window;
+ auto& detail = request.detail;
+ auto& deviceid = request.deviceid;
+ uint16_t num_modifiers{};
+ auto& grab_type = request.grab_type;
+ auto& modifiers = request.modifiers;
+ size_t modifiers_len = modifiers.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 55;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // detail
+ buf.Write(&detail);
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // num_modifiers
+ num_modifiers = modifiers.size();
+ buf.Write(&num_modifiers);
+
+ // grab_type
+ uint8_t tmp86;
+ tmp86 = static_cast<uint8_t>(grab_type);
+ buf.Write(&tmp86);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // modifiers
+ DCHECK_EQ(static_cast<size_t>(num_modifiers), modifiers.size());
+ for (auto& modifiers_elem : modifiers) {
+ // modifiers_elem
+ buf.Write(&modifiers_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XIPassiveUngrabDevice",
+ false);
+}
+
+Future<void> Input::XIPassiveUngrabDevice(
+ const Window& grab_window,
+ const uint32_t& detail,
+ const DeviceId& deviceid,
+ const GrabType& grab_type,
+ const std::vector<uint32_t>& modifiers) {
+ return Input::XIPassiveUngrabDevice(Input::XIPassiveUngrabDeviceRequest{
+ grab_window, detail, deviceid, grab_type, modifiers});
+}
+
+Future<Input::XIListPropertiesReply> Input::XIListProperties(
+ const Input::XIListPropertiesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceid = request.deviceid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 56;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::XIListPropertiesReply>(
+ &buf, "Input::XIListProperties", false);
+}
+
+Future<Input::XIListPropertiesReply> Input::XIListProperties(
+ const DeviceId& deviceid) {
+ return Input::XIListProperties(Input::XIListPropertiesRequest{deviceid});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::XIListPropertiesReply> detail::ReadReply<
+ Input::XIListPropertiesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::XIListPropertiesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t num_properties{};
+ auto& properties = (*reply).properties;
+ size_t properties_len = properties.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_properties
+ Read(&num_properties, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // properties
+ properties.resize(num_properties);
+ for (auto& properties_elem : properties) {
+ // properties_elem
+ Read(&properties_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::XIChangeProperty(
+ const Input::XIChangePropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceid = request.deviceid;
+ auto& mode = request.mode;
+ PropertyFormat format{};
+ auto& property = request.property;
+ auto& type = request.type;
+ auto& num_items = request.num_items;
+ auto& items = request;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 57;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // mode
+ uint8_t tmp87;
+ tmp87 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp87);
+
+ // format
+ SwitchVar(PropertyFormat::c_8Bits, items.data8.has_value(), false, &format);
+ SwitchVar(PropertyFormat::c_16Bits, items.data16.has_value(), false, &format);
+ SwitchVar(PropertyFormat::c_32Bits, items.data32.has_value(), false, &format);
+ uint8_t tmp88;
+ tmp88 = static_cast<uint8_t>(format);
+ buf.Write(&tmp88);
+
+ // property
+ buf.Write(&property);
+
+ // type
+ buf.Write(&type);
+
+ // num_items
+ buf.Write(&num_items);
+
+ // items
+ auto items_expr = format;
+ if (CaseEq(items_expr, PropertyFormat::c_8Bits)) {
+ auto& data8 = *items.data8;
+ size_t data8_len = data8.size();
+
+ // data8
+ DCHECK_EQ(static_cast<size_t>(num_items), data8.size());
+ for (auto& data8_elem : data8) {
+ // data8_elem
+ buf.Write(&data8_elem);
+ }
+
+ // pad0
+ Align(&buf, 4);
+ }
+ if (CaseEq(items_expr, PropertyFormat::c_16Bits)) {
+ auto& data16 = *items.data16;
+ size_t data16_len = data16.size();
+
+ // data16
+ DCHECK_EQ(static_cast<size_t>(num_items), data16.size());
+ for (auto& data16_elem : data16) {
+ // data16_elem
+ buf.Write(&data16_elem);
+ }
+
+ // pad1
+ Align(&buf, 4);
+ }
+ if (CaseEq(items_expr, PropertyFormat::c_32Bits)) {
+ auto& data32 = *items.data32;
+ size_t data32_len = data32.size();
+
+ // data32
+ DCHECK_EQ(static_cast<size_t>(num_items), data32.size());
+ for (auto& data32_elem : data32) {
+ // data32_elem
+ buf.Write(&data32_elem);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XIChangeProperty", false);
+}
+
+Future<void> Input::XIChangeProperty(
+ const DeviceId& deviceid,
+ const PropMode& mode,
+ const Atom& property,
+ const Atom& type,
+ const uint32_t& num_items,
+ const base::Optional<std::vector<uint8_t>>& data8,
+ const base::Optional<std::vector<uint16_t>>& data16,
+ const base::Optional<std::vector<uint32_t>>& data32) {
+ return Input::XIChangeProperty(Input::XIChangePropertyRequest{
+ deviceid, mode, property, type, num_items, data8, data16, data32});
+}
+
+Future<void> Input::XIDeleteProperty(
+ const Input::XIDeletePropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceid = request.deviceid;
+ auto& property = request.property;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 58;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // property
+ buf.Write(&property);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XIDeleteProperty", false);
+}
+
+Future<void> Input::XIDeleteProperty(const DeviceId& deviceid,
+ const Atom& property) {
+ return Input::XIDeleteProperty(
+ Input::XIDeletePropertyRequest{deviceid, property});
+}
+
+Future<Input::XIGetPropertyReply> Input::XIGetProperty(
+ const Input::XIGetPropertyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceid = request.deviceid;
+ auto& c_delete = request.c_delete;
+ auto& property = request.property;
+ auto& type = request.type;
+ auto& offset = request.offset;
+ auto& len = request.len;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 59;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // c_delete
+ buf.Write(&c_delete);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // property
+ buf.Write(&property);
+
+ // type
+ buf.Write(&type);
+
+ // offset
+ buf.Write(&offset);
+
+ // len
+ buf.Write(&len);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::XIGetPropertyReply>(
+ &buf, "Input::XIGetProperty", false);
+}
+
+Future<Input::XIGetPropertyReply> Input::XIGetProperty(const DeviceId& deviceid,
+ const uint8_t& c_delete,
+ const Atom& property,
+ const Atom& type,
+ const uint32_t& offset,
+ const uint32_t& len) {
+ return Input::XIGetProperty(Input::XIGetPropertyRequest{
+ deviceid, c_delete, property, type, offset, len});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::XIGetPropertyReply> detail::ReadReply<
+ Input::XIGetPropertyReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::XIGetPropertyReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& type = (*reply).type;
+ auto& bytes_after = (*reply).bytes_after;
+ auto& num_items = (*reply).num_items;
+ Input::PropertyFormat format{};
+ auto& items = (*reply);
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // type
+ Read(&type, &buf);
+
+ // bytes_after
+ Read(&bytes_after, &buf);
+
+ // num_items
+ Read(&num_items, &buf);
+
+ // format
+ uint8_t tmp89;
+ Read(&tmp89, &buf);
+ format = static_cast<Input::PropertyFormat>(tmp89);
+
+ // pad1
+ Pad(&buf, 11);
+
+ // items
+ auto items_expr = format;
+ if (CaseEq(items_expr, Input::PropertyFormat::c_8Bits)) {
+ items.data8.emplace();
+ auto& data8 = *items.data8;
+ size_t data8_len = data8.size();
+
+ // data8
+ data8.resize(num_items);
+ for (auto& data8_elem : data8) {
+ // data8_elem
+ Read(&data8_elem, &buf);
+ }
+
+ // pad2
+ Align(&buf, 4);
+ }
+ if (CaseEq(items_expr, Input::PropertyFormat::c_16Bits)) {
+ items.data16.emplace();
+ auto& data16 = *items.data16;
+ size_t data16_len = data16.size();
+
+ // data16
+ data16.resize(num_items);
+ for (auto& data16_elem : data16) {
+ // data16_elem
+ Read(&data16_elem, &buf);
+ }
+
+ // pad3
+ Align(&buf, 4);
+ }
+ if (CaseEq(items_expr, Input::PropertyFormat::c_32Bits)) {
+ items.data32.emplace();
+ auto& data32 = *items.data32;
+ size_t data32_len = data32.size();
+
+ // data32
+ data32.resize(num_items);
+ for (auto& data32_elem : data32) {
+ // data32_elem
+ Read(&data32_elem, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Input::XIGetSelectedEventsReply> Input::XIGetSelectedEvents(
+ const Input::XIGetSelectedEventsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 60;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Input::XIGetSelectedEventsReply>(
+ &buf, "Input::XIGetSelectedEvents", false);
+}
+
+Future<Input::XIGetSelectedEventsReply> Input::XIGetSelectedEvents(
+ const Window& window) {
+ return Input::XIGetSelectedEvents(Input::XIGetSelectedEventsRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Input::XIGetSelectedEventsReply> detail::ReadReply<
+ Input::XIGetSelectedEventsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Input::XIGetSelectedEventsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t num_masks{};
+ auto& masks = (*reply).masks;
+ size_t masks_len = masks.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_masks
+ Read(&num_masks, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // masks
+ masks.resize(num_masks);
+ for (auto& masks_elem : masks) {
+ // masks_elem
+ {
+ auto& deviceid = masks_elem.deviceid;
+ uint16_t mask_len{};
+ auto& mask = masks_elem.mask;
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // mask_len
+ Read(&mask_len, &buf);
+
+ // mask
+ mask.resize(mask_len);
+ for (auto& mask_elem : mask) {
+ // mask_elem
+ uint32_t tmp90;
+ Read(&tmp90, &buf);
+ mask_elem = static_cast<Input::XIEventMask>(tmp90);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Input::XIBarrierReleasePointer(
+ const Input::XIBarrierReleasePointerRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint32_t num_barriers{};
+ auto& barriers = request.barriers;
+ size_t barriers_len = barriers.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 61;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // num_barriers
+ num_barriers = barriers.size();
+ buf.Write(&num_barriers);
+
+ // barriers
+ DCHECK_EQ(static_cast<size_t>(num_barriers), barriers.size());
+ for (auto& barriers_elem : barriers) {
+ // barriers_elem
+ {
+ auto& deviceid = barriers_elem.deviceid;
+ auto& barrier = barriers_elem.barrier;
+ auto& eventid = barriers_elem.eventid;
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // barrier
+ buf.Write(&barrier);
+
+ // eventid
+ buf.Write(&eventid);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::XIBarrierReleasePointer",
+ false);
+}
+
+Future<void> Input::XIBarrierReleasePointer(
+ const std::vector<BarrierReleasePointerInfo>& barriers) {
+ return Input::XIBarrierReleasePointer(
+ Input::XIBarrierReleasePointerRequest{barriers});
+}
+
+Future<void> Input::SendExtensionEvent(
+ const Input::SendExtensionEventRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& destination = request.destination;
+ auto& device_id = request.device_id;
+ auto& propagate = request.propagate;
+ uint16_t num_classes{};
+ uint8_t num_events{};
+ auto& events = request.events;
+ size_t events_len = events.size();
+ auto& classes = request.classes;
+ size_t classes_len = classes.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 31;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // destination
+ buf.Write(&destination);
+
+ // device_id
+ buf.Write(&device_id);
+
+ // propagate
+ buf.Write(&propagate);
+
+ // num_classes
+ num_classes = classes.size();
+ buf.Write(&num_classes);
+
+ // num_events
+ num_events = events.size();
+ buf.Write(&num_events);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // events
+ DCHECK_EQ(static_cast<size_t>(num_events), events.size());
+ for (auto& events_elem : events) {
+ // events_elem
+ buf.Write(&events_elem);
+ }
+
+ // classes
+ DCHECK_EQ(static_cast<size_t>(num_classes), classes.size());
+ for (auto& classes_elem : classes) {
+ // classes_elem
+ buf.Write(&classes_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Input::SendExtensionEvent",
+ false);
+}
+
+Future<void> Input::SendExtensionEvent(const Window& destination,
+ const uint8_t& device_id,
+ const uint8_t& propagate,
+ const std::vector<EventForSend>& events,
+ const std::vector<EventClass>& classes) {
+ return Input::SendExtensionEvent(Input::SendExtensionEventRequest{
+ destination, device_id, propagate, events, classes});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xinput.h b/chromium/ui/gfx/x/generated_protos/xinput.h
new file mode 100644
index 00000000000..c94010d69d9
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xinput.h
@@ -0,0 +1,3234 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XINPUT_H_
+#define UI_GFX_X_GENERATED_PROTOS_XINPUT_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xfixes.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Input {
+ public:
+ static constexpr unsigned major_version = 2;
+ static constexpr unsigned minor_version = 3;
+
+ Input(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class EventClass : uint32_t {};
+
+ enum class KeyCode : uint8_t {};
+
+ enum class Fp1616 : int32_t {};
+
+ enum class DeviceUse : int {
+ IsXPointer = 0,
+ IsXKeyboard = 1,
+ IsXExtensionDevice = 2,
+ IsXExtensionKeyboard = 3,
+ IsXExtensionPointer = 4,
+ };
+
+ enum class InputClass : int {
+ Key = 0,
+ Button = 1,
+ Valuator = 2,
+ Feedback = 3,
+ Proximity = 4,
+ Focus = 5,
+ Other = 6,
+ };
+
+ enum class ValuatorMode : int {
+ Relative = 0,
+ Absolute = 1,
+ };
+
+ enum class EventTypeBase : uint8_t {};
+
+ enum class PropagateMode : int {
+ AddToList = 0,
+ DeleteFromList = 1,
+ };
+
+ enum class ModifierDevice : int {
+ UseXKeyboard = 255,
+ };
+
+ enum class DeviceInputMode : int {
+ AsyncThisDevice = 0,
+ SyncThisDevice = 1,
+ ReplayThisDevice = 2,
+ AsyncOtherDevices = 3,
+ AsyncAll = 4,
+ SyncAll = 5,
+ };
+
+ enum class FeedbackClass : int {
+ Keyboard = 0,
+ Pointer = 1,
+ String = 2,
+ Integer = 3,
+ Led = 4,
+ Bell = 5,
+ };
+
+ enum class ChangeFeedbackControlMask : int {
+ KeyClickPercent = 1 << 0,
+ Percent = 1 << 1,
+ Pitch = 1 << 2,
+ Duration = 1 << 3,
+ Led = 1 << 4,
+ LedMode = 1 << 5,
+ Key = 1 << 6,
+ AutoRepeatMode = 1 << 7,
+ String = 1 << 0,
+ Integer = 1 << 0,
+ AccelNum = 1 << 0,
+ AccelDenom = 1 << 1,
+ Threshold = 1 << 2,
+ };
+
+ enum class ValuatorStateModeMask : int {
+ DeviceModeAbsolute = 1 << 0,
+ OutOfProximity = 1 << 1,
+ };
+
+ enum class DeviceControl : int {
+ resolution = 1,
+ abs_calib = 2,
+ core = 3,
+ enable = 4,
+ abs_area = 5,
+ };
+
+ enum class PropertyFormat : int {
+ c_8Bits = 8,
+ c_16Bits = 16,
+ c_32Bits = 32,
+ };
+
+ enum class DeviceId : uint16_t {
+ All = 0,
+ AllMaster = 1,
+ };
+
+ enum class HierarchyChangeType : int {
+ AddMaster = 1,
+ RemoveMaster = 2,
+ AttachSlave = 3,
+ DetachSlave = 4,
+ };
+
+ enum class ChangeMode : int {
+ Attach = 1,
+ Float = 2,
+ };
+
+ enum class XIEventMask : int {
+ DeviceChanged = 1 << 1,
+ KeyPress = 1 << 2,
+ KeyRelease = 1 << 3,
+ ButtonPress = 1 << 4,
+ ButtonRelease = 1 << 5,
+ Motion = 1 << 6,
+ Enter = 1 << 7,
+ Leave = 1 << 8,
+ FocusIn = 1 << 9,
+ FocusOut = 1 << 10,
+ Hierarchy = 1 << 11,
+ Property = 1 << 12,
+ RawKeyPress = 1 << 13,
+ RawKeyRelease = 1 << 14,
+ RawButtonPress = 1 << 15,
+ RawButtonRelease = 1 << 16,
+ RawMotion = 1 << 17,
+ TouchBegin = 1 << 18,
+ TouchUpdate = 1 << 19,
+ TouchEnd = 1 << 20,
+ TouchOwnership = 1 << 21,
+ RawTouchBegin = 1 << 22,
+ RawTouchUpdate = 1 << 23,
+ RawTouchEnd = 1 << 24,
+ BarrierHit = 1 << 25,
+ BarrierLeave = 1 << 26,
+ };
+
+ enum class DeviceClassType : int {
+ Key = 0,
+ Button = 1,
+ Valuator = 2,
+ Scroll = 3,
+ Touch = 8,
+ };
+
+ enum class DeviceType : int {
+ MasterPointer = 1,
+ MasterKeyboard = 2,
+ SlavePointer = 3,
+ SlaveKeyboard = 4,
+ FloatingSlave = 5,
+ };
+
+ enum class ScrollFlags : int {
+ NoEmulation = 1 << 0,
+ Preferred = 1 << 1,
+ };
+
+ enum class ScrollType : int {
+ Vertical = 1,
+ Horizontal = 2,
+ };
+
+ enum class TouchMode : int {
+ Direct = 1,
+ Dependent = 2,
+ };
+
+ enum class GrabOwner : int {
+ NoOwner = 0,
+ Owner = 1,
+ };
+
+ enum class EventMode : int {
+ AsyncDevice = 0,
+ SyncDevice = 1,
+ ReplayDevice = 2,
+ AsyncPairedDevice = 3,
+ AsyncPair = 4,
+ SyncPair = 5,
+ AcceptTouch = 6,
+ RejectTouch = 7,
+ };
+
+ enum class GrabMode22 : int {
+ Sync = 0,
+ Async = 1,
+ Touch = 2,
+ };
+
+ enum class GrabType : int {
+ Button = 0,
+ Keycode = 1,
+ Enter = 2,
+ FocusIn = 3,
+ TouchBegin = 4,
+ };
+
+ enum class ModifierMask : int {
+ Any = 1 << 31,
+ };
+
+ enum class MoreEventsMask : int {
+ MoreEvents = 1 << 7,
+ };
+
+ enum class ClassesReportedMask : int {
+ OutOfProximity = 1 << 7,
+ DeviceModeAbsolute = 1 << 6,
+ ReportingValuators = 1 << 2,
+ ReportingButtons = 1 << 1,
+ ReportingKeys = 1 << 0,
+ };
+
+ enum class ChangeDevice : int {
+ NewPointer = 0,
+ NewKeyboard = 1,
+ };
+
+ enum class DeviceChange : int {
+ Added = 0,
+ Removed = 1,
+ Enabled = 2,
+ Disabled = 3,
+ Unrecoverable = 4,
+ ControlChanged = 5,
+ };
+
+ enum class ChangeReason : int {
+ SlaveSwitch = 1,
+ DeviceChange = 2,
+ };
+
+ enum class KeyEventFlags : int {
+ KeyRepeat = 1 << 16,
+ };
+
+ enum class PointerEventFlags : int {
+ PointerEmulated = 1 << 16,
+ };
+
+ enum class NotifyMode : int {
+ Normal = 0,
+ Grab = 1,
+ Ungrab = 2,
+ WhileGrabbed = 3,
+ PassiveGrab = 4,
+ PassiveUngrab = 5,
+ };
+
+ enum class NotifyDetail : int {
+ Ancestor = 0,
+ Virtual = 1,
+ Inferior = 2,
+ Nonlinear = 3,
+ NonlinearVirtual = 4,
+ Pointer = 5,
+ PointerRoot = 6,
+ None = 7,
+ };
+
+ enum class HierarchyMask : int {
+ MasterAdded = 1 << 0,
+ MasterRemoved = 1 << 1,
+ SlaveAdded = 1 << 2,
+ SlaveRemoved = 1 << 3,
+ SlaveAttached = 1 << 4,
+ SlaveDetached = 1 << 5,
+ DeviceEnabled = 1 << 6,
+ DeviceDisabled = 1 << 7,
+ };
+
+ enum class PropertyFlag : int {
+ Deleted = 0,
+ Created = 1,
+ Modified = 2,
+ };
+
+ enum class TouchEventFlags : int {
+ TouchPendingEnd = 1 << 16,
+ TouchEmulatingPointer = 1 << 17,
+ };
+
+ enum class TouchOwnershipFlags : int {
+ None = 0,
+ };
+
+ enum class BarrierFlags : int {
+ PointerReleased = 1 << 0,
+ DeviceIsGrabbed = 1 << 1,
+ };
+
+ struct Fp3232 {
+ int32_t integral{};
+ uint32_t frac{};
+ };
+
+ struct DeviceInfo {
+ Atom device_type{};
+ uint8_t device_id{};
+ uint8_t num_class_info{};
+ DeviceUse device_use{};
+ };
+
+ struct KeyInfo {
+ InputClass class_id{};
+ uint8_t len{};
+ KeyCode min_keycode{};
+ KeyCode max_keycode{};
+ uint16_t num_keys{};
+ };
+
+ struct ButtonInfo {
+ InputClass class_id{};
+ uint8_t len{};
+ uint16_t num_buttons{};
+ };
+
+ struct AxisInfo {
+ uint32_t resolution{};
+ int32_t minimum{};
+ int32_t maximum{};
+ };
+
+ struct ValuatorInfo {
+ InputClass class_id{};
+ uint8_t len{};
+ ValuatorMode mode{};
+ uint32_t motion_size{};
+ std::vector<AxisInfo> axes{};
+ };
+
+ struct InputInfo {
+ uint8_t len{};
+ struct Key {
+ KeyCode min_keycode{};
+ KeyCode max_keycode{};
+ uint16_t num_keys{};
+ };
+ struct Button {
+ uint16_t num_buttons{};
+ };
+ struct Valuator {
+ ValuatorMode mode{};
+ uint32_t motion_size{};
+ std::vector<AxisInfo> axes{};
+ };
+ base::Optional<Key> key{};
+ base::Optional<Button> button{};
+ base::Optional<Valuator> valuator{};
+ };
+
+ struct DeviceName {
+ std::string string{};
+ };
+
+ struct InputClassInfo {
+ InputClass class_id{};
+ EventTypeBase event_type_base{};
+ };
+
+ struct DeviceTimeCoord {
+ Time time{};
+ std::vector<int32_t> axisvalues{};
+ };
+
+ struct KbdFeedbackState {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ uint16_t pitch{};
+ uint16_t duration{};
+ uint32_t led_mask{};
+ uint32_t led_values{};
+ uint8_t global_auto_repeat{};
+ uint8_t click{};
+ uint8_t percent{};
+ std::array<uint8_t, 32> auto_repeats{};
+ };
+
+ struct PtrFeedbackState {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ uint16_t accel_num{};
+ uint16_t accel_denom{};
+ uint16_t threshold{};
+ };
+
+ struct IntegerFeedbackState {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ uint32_t resolution{};
+ int32_t min_value{};
+ int32_t max_value{};
+ };
+
+ struct StringFeedbackState {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ uint16_t max_symbols{};
+ std::vector<KeySym> keysyms{};
+ };
+
+ struct BellFeedbackState {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ uint8_t percent{};
+ uint16_t pitch{};
+ uint16_t duration{};
+ };
+
+ struct LedFeedbackState {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ uint32_t led_mask{};
+ uint32_t led_values{};
+ };
+
+ struct FeedbackState {
+ uint8_t feedback_id{};
+ uint16_t len{};
+ struct Keyboard {
+ uint16_t pitch{};
+ uint16_t duration{};
+ uint32_t led_mask{};
+ uint32_t led_values{};
+ uint8_t global_auto_repeat{};
+ uint8_t click{};
+ uint8_t percent{};
+ std::array<uint8_t, 32> auto_repeats{};
+ };
+ struct Pointer {
+ uint16_t accel_num{};
+ uint16_t accel_denom{};
+ uint16_t threshold{};
+ };
+ struct String {
+ uint16_t max_symbols{};
+ std::vector<KeySym> keysyms{};
+ };
+ struct Integer {
+ uint32_t resolution{};
+ int32_t min_value{};
+ int32_t max_value{};
+ };
+ struct Led {
+ uint32_t led_mask{};
+ uint32_t led_values{};
+ };
+ struct Bell {
+ uint8_t percent{};
+ uint16_t pitch{};
+ uint16_t duration{};
+ };
+ base::Optional<Keyboard> keyboard{};
+ base::Optional<Pointer> pointer{};
+ base::Optional<String> string{};
+ base::Optional<Integer> integer{};
+ base::Optional<Led> led{};
+ base::Optional<Bell> bell{};
+ };
+
+ struct KbdFeedbackCtl {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ KeyCode key{};
+ uint8_t auto_repeat_mode{};
+ int8_t key_click_percent{};
+ int8_t bell_percent{};
+ int16_t bell_pitch{};
+ int16_t bell_duration{};
+ uint32_t led_mask{};
+ uint32_t led_values{};
+ };
+
+ struct PtrFeedbackCtl {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ int16_t num{};
+ int16_t denom{};
+ int16_t threshold{};
+ };
+
+ struct IntegerFeedbackCtl {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ int32_t int_to_display{};
+ };
+
+ struct StringFeedbackCtl {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ std::vector<KeySym> keysyms{};
+ };
+
+ struct BellFeedbackCtl {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ int8_t percent{};
+ int16_t pitch{};
+ int16_t duration{};
+ };
+
+ struct LedFeedbackCtl {
+ FeedbackClass class_id{};
+ uint8_t feedback_id{};
+ uint16_t len{};
+ uint32_t led_mask{};
+ uint32_t led_values{};
+ };
+
+ struct FeedbackCtl {
+ uint8_t feedback_id{};
+ uint16_t len{};
+ struct Keyboard {
+ KeyCode key{};
+ uint8_t auto_repeat_mode{};
+ int8_t key_click_percent{};
+ int8_t bell_percent{};
+ int16_t bell_pitch{};
+ int16_t bell_duration{};
+ uint32_t led_mask{};
+ uint32_t led_values{};
+ };
+ struct Pointer {
+ int16_t num{};
+ int16_t denom{};
+ int16_t threshold{};
+ };
+ struct String {
+ std::vector<KeySym> keysyms{};
+ };
+ struct Integer {
+ int32_t int_to_display{};
+ };
+ struct Led {
+ uint32_t led_mask{};
+ uint32_t led_values{};
+ };
+ struct Bell {
+ int8_t percent{};
+ int16_t pitch{};
+ int16_t duration{};
+ };
+ base::Optional<Keyboard> keyboard{};
+ base::Optional<Pointer> pointer{};
+ base::Optional<String> string{};
+ base::Optional<Integer> integer{};
+ base::Optional<Led> led{};
+ base::Optional<Bell> bell{};
+ };
+
+ struct KeyState {
+ InputClass class_id{};
+ uint8_t len{};
+ uint8_t num_keys{};
+ std::array<uint8_t, 32> keys{};
+ };
+
+ struct ButtonState {
+ InputClass class_id{};
+ uint8_t len{};
+ uint8_t num_buttons{};
+ std::array<uint8_t, 32> buttons{};
+ };
+
+ struct ValuatorState {
+ InputClass class_id{};
+ uint8_t len{};
+ ValuatorStateModeMask mode{};
+ std::vector<int32_t> valuators{};
+ };
+
+ struct InputState {
+ uint8_t len{};
+ struct Key {
+ uint8_t num_keys{};
+ std::array<uint8_t, 32> keys{};
+ };
+ struct Button {
+ uint8_t num_buttons{};
+ std::array<uint8_t, 32> buttons{};
+ };
+ struct Valuator {
+ ValuatorStateModeMask mode{};
+ std::vector<int32_t> valuators{};
+ };
+ base::Optional<Key> key{};
+ base::Optional<Button> button{};
+ base::Optional<Valuator> valuator{};
+ };
+
+ struct DeviceResolutionState {
+ DeviceControl control_id{};
+ uint16_t len{};
+ std::vector<uint32_t> resolution_values{};
+ std::vector<uint32_t> resolution_min{};
+ std::vector<uint32_t> resolution_max{};
+ };
+
+ struct DeviceAbsCalibState {
+ DeviceControl control_id{};
+ uint16_t len{};
+ int32_t min_x{};
+ int32_t max_x{};
+ int32_t min_y{};
+ int32_t max_y{};
+ uint32_t flip_x{};
+ uint32_t flip_y{};
+ uint32_t rotation{};
+ uint32_t button_threshold{};
+ };
+
+ struct DeviceAbsAreaState {
+ DeviceControl control_id{};
+ uint16_t len{};
+ uint32_t offset_x{};
+ uint32_t offset_y{};
+ uint32_t width{};
+ uint32_t height{};
+ uint32_t screen{};
+ uint32_t following{};
+ };
+
+ struct DeviceCoreState {
+ DeviceControl control_id{};
+ uint16_t len{};
+ uint8_t status{};
+ uint8_t iscore{};
+ };
+
+ struct DeviceEnableState {
+ DeviceControl control_id{};
+ uint16_t len{};
+ uint8_t enable{};
+ };
+
+ struct DeviceState {
+ uint16_t len{};
+ struct Resolution {
+ std::vector<uint32_t> resolution_values{};
+ std::vector<uint32_t> resolution_min{};
+ std::vector<uint32_t> resolution_max{};
+ };
+ struct AbsCalib {
+ int32_t min_x{};
+ int32_t max_x{};
+ int32_t min_y{};
+ int32_t max_y{};
+ uint32_t flip_x{};
+ uint32_t flip_y{};
+ uint32_t rotation{};
+ uint32_t button_threshold{};
+ };
+ struct Core {
+ uint8_t status{};
+ uint8_t iscore{};
+ };
+ struct Enable {
+ uint8_t enable{};
+ };
+ struct AbsArea {
+ uint32_t offset_x{};
+ uint32_t offset_y{};
+ uint32_t width{};
+ uint32_t height{};
+ uint32_t screen{};
+ uint32_t following{};
+ };
+ base::Optional<Resolution> resolution{};
+ base::Optional<AbsCalib> abs_calib{};
+ base::Optional<Core> core{};
+ base::Optional<Enable> enable{};
+ base::Optional<AbsArea> abs_area{};
+ };
+
+ struct DeviceResolutionCtl {
+ DeviceControl control_id{};
+ uint16_t len{};
+ uint8_t first_valuator{};
+ std::vector<uint32_t> resolution_values{};
+ };
+
+ struct DeviceAbsCalibCtl {
+ DeviceControl control_id{};
+ uint16_t len{};
+ int32_t min_x{};
+ int32_t max_x{};
+ int32_t min_y{};
+ int32_t max_y{};
+ uint32_t flip_x{};
+ uint32_t flip_y{};
+ uint32_t rotation{};
+ uint32_t button_threshold{};
+ };
+
+ struct DeviceAbsAreaCtrl {
+ DeviceControl control_id{};
+ uint16_t len{};
+ uint32_t offset_x{};
+ uint32_t offset_y{};
+ int32_t width{};
+ int32_t height{};
+ int32_t screen{};
+ uint32_t following{};
+ };
+
+ struct DeviceCoreCtrl {
+ DeviceControl control_id{};
+ uint16_t len{};
+ uint8_t status{};
+ };
+
+ struct DeviceEnableCtrl {
+ DeviceControl control_id{};
+ uint16_t len{};
+ uint8_t enable{};
+ };
+
+ struct DeviceCtl {
+ uint16_t len{};
+ struct Resolution {
+ uint8_t first_valuator{};
+ std::vector<uint32_t> resolution_values{};
+ };
+ struct AbsCalib {
+ int32_t min_x{};
+ int32_t max_x{};
+ int32_t min_y{};
+ int32_t max_y{};
+ uint32_t flip_x{};
+ uint32_t flip_y{};
+ uint32_t rotation{};
+ uint32_t button_threshold{};
+ };
+ struct Core {
+ uint8_t status{};
+ };
+ struct Enable {
+ uint8_t enable{};
+ };
+ struct AbsArea {
+ uint32_t offset_x{};
+ uint32_t offset_y{};
+ int32_t width{};
+ int32_t height{};
+ int32_t screen{};
+ uint32_t following{};
+ };
+ base::Optional<Resolution> resolution{};
+ base::Optional<AbsCalib> abs_calib{};
+ base::Optional<Core> core{};
+ base::Optional<Enable> enable{};
+ base::Optional<AbsArea> abs_area{};
+ };
+
+ struct GroupInfo {
+ uint8_t base{};
+ uint8_t latched{};
+ uint8_t locked{};
+ uint8_t effective{};
+ };
+
+ struct ModifierInfo {
+ uint32_t base{};
+ uint32_t latched{};
+ uint32_t locked{};
+ uint32_t effective{};
+ };
+
+ struct AddMaster {
+ HierarchyChangeType type{};
+ uint16_t len{};
+ uint8_t send_core{};
+ uint8_t enable{};
+ std::string name{};
+ };
+
+ struct RemoveMaster {
+ HierarchyChangeType type{};
+ uint16_t len{};
+ DeviceId deviceid{};
+ ChangeMode return_mode{};
+ DeviceId return_pointer{};
+ DeviceId return_keyboard{};
+ };
+
+ struct AttachSlave {
+ HierarchyChangeType type{};
+ uint16_t len{};
+ DeviceId deviceid{};
+ DeviceId master{};
+ };
+
+ struct DetachSlave {
+ HierarchyChangeType type{};
+ uint16_t len{};
+ DeviceId deviceid{};
+ };
+
+ struct HierarchyChange {
+ uint16_t len{};
+ struct AddMaster {
+ uint8_t send_core{};
+ uint8_t enable{};
+ std::string name{};
+ };
+ struct RemoveMaster {
+ DeviceId deviceid{};
+ ChangeMode return_mode{};
+ DeviceId return_pointer{};
+ DeviceId return_keyboard{};
+ };
+ struct AttachSlave {
+ DeviceId deviceid{};
+ DeviceId master{};
+ };
+ struct DetachSlave {
+ DeviceId deviceid{};
+ };
+ base::Optional<AddMaster> add_master{};
+ base::Optional<RemoveMaster> remove_master{};
+ base::Optional<AttachSlave> attach_slave{};
+ base::Optional<DetachSlave> detach_slave{};
+ };
+
+ struct EventMask {
+ DeviceId deviceid{};
+ std::vector<XIEventMask> mask{};
+ };
+
+ struct ButtonClass {
+ DeviceClassType type{};
+ uint16_t len{};
+ DeviceId sourceid{};
+ std::vector<uint32_t> state{};
+ std::vector<Atom> labels{};
+ };
+
+ struct KeyClass {
+ DeviceClassType type{};
+ uint16_t len{};
+ DeviceId sourceid{};
+ std::vector<uint32_t> keys{};
+ };
+
+ struct ScrollClass {
+ DeviceClassType type{};
+ uint16_t len{};
+ DeviceId sourceid{};
+ uint16_t number{};
+ ScrollType scroll_type{};
+ ScrollFlags flags{};
+ Fp3232 increment{};
+ };
+
+ struct TouchClass {
+ DeviceClassType type{};
+ uint16_t len{};
+ DeviceId sourceid{};
+ TouchMode mode{};
+ uint8_t num_touches{};
+ };
+
+ struct ValuatorClass {
+ DeviceClassType type{};
+ uint16_t len{};
+ DeviceId sourceid{};
+ uint16_t number{};
+ Atom label{};
+ Fp3232 min{};
+ Fp3232 max{};
+ Fp3232 value{};
+ uint32_t resolution{};
+ ValuatorMode mode{};
+ };
+
+ struct DeviceClass {
+ uint16_t len{};
+ DeviceId sourceid{};
+ struct Key {
+ std::vector<uint32_t> keys{};
+ };
+ struct Button {
+ std::vector<uint32_t> state{};
+ std::vector<Atom> labels{};
+ };
+ struct Valuator {
+ uint16_t number{};
+ Atom label{};
+ Fp3232 min{};
+ Fp3232 max{};
+ Fp3232 value{};
+ uint32_t resolution{};
+ ValuatorMode mode{};
+ };
+ struct Scroll {
+ uint16_t number{};
+ ScrollType scroll_type{};
+ ScrollFlags flags{};
+ Fp3232 increment{};
+ };
+ struct Touch {
+ TouchMode mode{};
+ uint8_t num_touches{};
+ };
+ base::Optional<Key> key{};
+ base::Optional<Button> button{};
+ base::Optional<Valuator> valuator{};
+ base::Optional<Scroll> scroll{};
+ base::Optional<Touch> touch{};
+ };
+
+ struct XIDeviceInfo {
+ DeviceId deviceid{};
+ DeviceType type{};
+ DeviceId attachment{};
+ uint8_t enabled{};
+ std::string name{};
+ std::vector<DeviceClass> classes{};
+ };
+
+ struct GrabModifierInfo {
+ uint32_t modifiers{};
+ GrabStatus status{};
+ };
+
+ struct BarrierReleasePointerInfo {
+ DeviceId deviceid{};
+ XFixes::Barrier barrier{};
+ uint32_t eventid{};
+ };
+
+ struct DeviceValuatorEvent {
+ static constexpr int type_id = 20;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ uint8_t device_id{};
+ uint16_t sequence{};
+ uint16_t device_state{};
+ uint8_t num_valuators{};
+ uint8_t first_valuator{};
+ std::array<int32_t, 6> valuators{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct LegacyDeviceEvent {
+ static constexpr int type_id = 21;
+ enum Opcode {
+ DeviceKeyPress = 1,
+ DeviceKeyRelease = 2,
+ DeviceButtonPress = 3,
+ DeviceButtonRelease = 4,
+ DeviceMotionNotify = 5,
+ ProximityIn = 8,
+ ProximityOut = 9,
+ } opcode{};
+ bool send_event{};
+ uint8_t detail{};
+ uint16_t sequence{};
+ Time time{};
+ Window root{};
+ Window event{};
+ Window child{};
+ int16_t root_x{};
+ int16_t root_y{};
+ int16_t event_x{};
+ int16_t event_y{};
+ KeyButMask state{};
+ uint8_t same_screen{};
+ uint8_t device_id{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ };
+
+ struct DeviceFocusEvent {
+ static constexpr int type_id = 22;
+ enum Opcode {
+ In = 6,
+ Out = 7,
+ } opcode{};
+ bool send_event{};
+ x11::NotifyDetail detail{};
+ uint16_t sequence{};
+ Time time{};
+ Window window{};
+ x11::NotifyMode mode{};
+ uint8_t device_id{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+ };
+
+ struct DeviceStateNotifyEvent {
+ static constexpr int type_id = 23;
+ static constexpr uint8_t opcode = 10;
+ bool send_event{};
+ uint8_t device_id{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t num_keys{};
+ uint8_t num_buttons{};
+ uint8_t num_valuators{};
+ ClassesReportedMask classes_reported{};
+ std::array<uint8_t, 4> buttons{};
+ std::array<uint8_t, 4> keys{};
+ std::array<uint32_t, 3> valuators{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct DeviceMappingNotifyEvent {
+ static constexpr int type_id = 24;
+ static constexpr uint8_t opcode = 11;
+ bool send_event{};
+ uint8_t device_id{};
+ uint16_t sequence{};
+ Mapping request{};
+ KeyCode first_keycode{};
+ uint8_t count{};
+ Time time{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct ChangeDeviceNotifyEvent {
+ static constexpr int type_id = 25;
+ static constexpr uint8_t opcode = 12;
+ bool send_event{};
+ uint8_t device_id{};
+ uint16_t sequence{};
+ Time time{};
+ ChangeDevice request{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct DeviceKeyStateNotifyEvent {
+ static constexpr int type_id = 26;
+ static constexpr uint8_t opcode = 13;
+ bool send_event{};
+ uint8_t device_id{};
+ uint16_t sequence{};
+ std::array<uint8_t, 28> keys{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct DeviceButtonStateNotifyEvent {
+ static constexpr int type_id = 27;
+ static constexpr uint8_t opcode = 14;
+ bool send_event{};
+ uint8_t device_id{};
+ uint16_t sequence{};
+ std::array<uint8_t, 28> buttons{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct DevicePresenceNotifyEvent {
+ static constexpr int type_id = 28;
+ static constexpr uint8_t opcode = 15;
+ bool send_event{};
+ uint16_t sequence{};
+ Time time{};
+ DeviceChange devchange{};
+ uint8_t device_id{};
+ uint16_t control{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct DevicePropertyNotifyEvent {
+ static constexpr int type_id = 29;
+ static constexpr uint8_t opcode = 16;
+ bool send_event{};
+ Property state{};
+ uint16_t sequence{};
+ Time time{};
+ Atom property{};
+ uint8_t device_id{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct DeviceChangedEvent {
+ static constexpr int type_id = 30;
+ static constexpr uint8_t opcode = 1;
+ bool send_event{};
+ uint16_t sequence{};
+ DeviceId deviceid{};
+ Time time{};
+ DeviceId sourceid{};
+ ChangeReason reason{};
+ std::vector<DeviceClass> classes{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct DeviceEvent {
+ static constexpr int type_id = 31;
+ enum Opcode {
+ KeyPress = 2,
+ KeyRelease = 3,
+ ButtonPress = 4,
+ ButtonRelease = 5,
+ Motion = 6,
+ TouchBegin = 18,
+ TouchUpdate = 19,
+ TouchEnd = 20,
+ } opcode{};
+ bool send_event{};
+ uint16_t sequence{};
+ DeviceId deviceid{};
+ Time time{};
+ uint32_t detail{};
+ Window root{};
+ Window event{};
+ Window child{};
+ Fp1616 root_x{};
+ Fp1616 root_y{};
+ Fp1616 event_x{};
+ Fp1616 event_y{};
+ DeviceId sourceid{};
+ KeyEventFlags flags{};
+ ModifierInfo mods{};
+ GroupInfo group{};
+ std::vector<uint32_t> button_mask{};
+ std::vector<uint32_t> valuator_mask{};
+ std::vector<Fp3232> axisvalues{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ };
+
+ struct CrossingEvent {
+ static constexpr int type_id = 32;
+ enum Opcode {
+ Enter = 7,
+ Leave = 8,
+ FocusIn = 9,
+ FocusOut = 10,
+ } opcode{};
+ bool send_event{};
+ uint16_t sequence{};
+ DeviceId deviceid{};
+ Time time{};
+ DeviceId sourceid{};
+ NotifyMode mode{};
+ NotifyDetail detail{};
+ Window root{};
+ Window event{};
+ Window child{};
+ Fp1616 root_x{};
+ Fp1616 root_y{};
+ Fp1616 event_x{};
+ Fp1616 event_y{};
+ uint8_t same_screen{};
+ uint8_t focus{};
+ ModifierInfo mods{};
+ GroupInfo group{};
+ std::vector<uint32_t> buttons{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ };
+
+ struct HierarchyInfo {
+ DeviceId deviceid{};
+ DeviceId attachment{};
+ DeviceType type{};
+ uint8_t enabled{};
+ HierarchyMask flags{};
+ };
+
+ struct HierarchyEvent {
+ static constexpr int type_id = 33;
+ static constexpr uint8_t opcode = 11;
+ bool send_event{};
+ uint16_t sequence{};
+ DeviceId deviceid{};
+ Time time{};
+ HierarchyMask flags{};
+ std::vector<HierarchyInfo> infos{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct PropertyEvent {
+ static constexpr int type_id = 34;
+ static constexpr uint8_t opcode = 12;
+ bool send_event{};
+ uint16_t sequence{};
+ DeviceId deviceid{};
+ Time time{};
+ Atom property{};
+ PropertyFlag what{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct RawDeviceEvent {
+ static constexpr int type_id = 35;
+ enum Opcode {
+ RawKeyPress = 13,
+ RawKeyRelease = 14,
+ RawButtonPress = 15,
+ RawButtonRelease = 16,
+ RawMotion = 17,
+ RawTouchBegin = 22,
+ RawTouchUpdate = 23,
+ RawTouchEnd = 24,
+ } opcode{};
+ bool send_event{};
+ uint16_t sequence{};
+ DeviceId deviceid{};
+ Time time{};
+ uint32_t detail{};
+ DeviceId sourceid{};
+ KeyEventFlags flags{};
+ std::vector<uint32_t> valuator_mask{};
+ std::vector<Fp3232> axisvalues{};
+ std::vector<Fp3232> axisvalues_raw{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct TouchOwnershipEvent {
+ static constexpr int type_id = 36;
+ static constexpr uint8_t opcode = 21;
+ bool send_event{};
+ uint16_t sequence{};
+ DeviceId deviceid{};
+ Time time{};
+ uint32_t touchid{};
+ Window root{};
+ Window event{};
+ Window child{};
+ DeviceId sourceid{};
+ TouchOwnershipFlags flags{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ };
+
+ struct BarrierEvent {
+ static constexpr int type_id = 37;
+ enum Opcode {
+ Hit = 25,
+ Leave = 26,
+ } opcode{};
+ bool send_event{};
+ uint16_t sequence{};
+ DeviceId deviceid{};
+ Time time{};
+ uint32_t eventid{};
+ Window root{};
+ Window event{};
+ XFixes::Barrier barrier{};
+ uint32_t dtime{};
+ BarrierFlags flags{};
+ DeviceId sourceid{};
+ Fp1616 root_x{};
+ Fp1616 root_y{};
+ Fp3232 dx{};
+ Fp3232 dy{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ };
+
+ using EventForSend = std::array<uint8_t, 32>;
+ struct DeviceError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct EventError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct ModeError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct DeviceBusyError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct ClassError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct GetExtensionVersionRequest {
+ std::string name{};
+ };
+
+ struct GetExtensionVersionReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ uint16_t server_major{};
+ uint16_t server_minor{};
+ uint8_t present{};
+ };
+
+ using GetExtensionVersionResponse = Response<GetExtensionVersionReply>;
+
+ Future<GetExtensionVersionReply> GetExtensionVersion(
+ const GetExtensionVersionRequest& request);
+
+ Future<GetExtensionVersionReply> GetExtensionVersion(
+ const std::string& name = {});
+
+ struct ListInputDevicesRequest {};
+
+ struct ListInputDevicesReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ std::vector<DeviceInfo> devices{};
+ std::vector<InputInfo> infos{};
+ std::vector<Str> names{};
+ };
+
+ using ListInputDevicesResponse = Response<ListInputDevicesReply>;
+
+ Future<ListInputDevicesReply> ListInputDevices(
+ const ListInputDevicesRequest& request);
+
+ Future<ListInputDevicesReply> ListInputDevices();
+
+ struct OpenDeviceRequest {
+ uint8_t device_id{};
+ };
+
+ struct OpenDeviceReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ std::vector<InputClassInfo> class_info{};
+ };
+
+ using OpenDeviceResponse = Response<OpenDeviceReply>;
+
+ Future<OpenDeviceReply> OpenDevice(const OpenDeviceRequest& request);
+
+ Future<OpenDeviceReply> OpenDevice(const uint8_t& device_id = {});
+
+ struct CloseDeviceRequest {
+ uint8_t device_id{};
+ };
+
+ using CloseDeviceResponse = Response<void>;
+
+ Future<void> CloseDevice(const CloseDeviceRequest& request);
+
+ Future<void> CloseDevice(const uint8_t& device_id = {});
+
+ struct SetDeviceModeRequest {
+ uint8_t device_id{};
+ ValuatorMode mode{};
+ };
+
+ struct SetDeviceModeReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ GrabStatus status{};
+ };
+
+ using SetDeviceModeResponse = Response<SetDeviceModeReply>;
+
+ Future<SetDeviceModeReply> SetDeviceMode(const SetDeviceModeRequest& request);
+
+ Future<SetDeviceModeReply> SetDeviceMode(const uint8_t& device_id = {},
+ const ValuatorMode& mode = {});
+
+ struct SelectExtensionEventRequest {
+ Window window{};
+ std::vector<EventClass> classes{};
+ };
+
+ using SelectExtensionEventResponse = Response<void>;
+
+ Future<void> SelectExtensionEvent(const SelectExtensionEventRequest& request);
+
+ Future<void> SelectExtensionEvent(
+ const Window& window = {},
+ const std::vector<EventClass>& classes = {});
+
+ struct GetSelectedExtensionEventsRequest {
+ Window window{};
+ };
+
+ struct GetSelectedExtensionEventsReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ std::vector<EventClass> this_classes{};
+ std::vector<EventClass> all_classes{};
+ };
+
+ using GetSelectedExtensionEventsResponse =
+ Response<GetSelectedExtensionEventsReply>;
+
+ Future<GetSelectedExtensionEventsReply> GetSelectedExtensionEvents(
+ const GetSelectedExtensionEventsRequest& request);
+
+ Future<GetSelectedExtensionEventsReply> GetSelectedExtensionEvents(
+ const Window& window = {});
+
+ struct ChangeDeviceDontPropagateListRequest {
+ Window window{};
+ PropagateMode mode{};
+ std::vector<EventClass> classes{};
+ };
+
+ using ChangeDeviceDontPropagateListResponse = Response<void>;
+
+ Future<void> ChangeDeviceDontPropagateList(
+ const ChangeDeviceDontPropagateListRequest& request);
+
+ Future<void> ChangeDeviceDontPropagateList(
+ const Window& window = {},
+ const PropagateMode& mode = {},
+ const std::vector<EventClass>& classes = {});
+
+ struct GetDeviceDontPropagateListRequest {
+ Window window{};
+ };
+
+ struct GetDeviceDontPropagateListReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ std::vector<EventClass> classes{};
+ };
+
+ using GetDeviceDontPropagateListResponse =
+ Response<GetDeviceDontPropagateListReply>;
+
+ Future<GetDeviceDontPropagateListReply> GetDeviceDontPropagateList(
+ const GetDeviceDontPropagateListRequest& request);
+
+ Future<GetDeviceDontPropagateListReply> GetDeviceDontPropagateList(
+ const Window& window = {});
+
+ struct GetDeviceMotionEventsRequest {
+ Time start{};
+ Time stop{};
+ uint8_t device_id{};
+ };
+
+ struct GetDeviceMotionEventsReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ uint8_t num_axes{};
+ ValuatorMode device_mode{};
+ std::vector<DeviceTimeCoord> events{};
+ };
+
+ using GetDeviceMotionEventsResponse = Response<GetDeviceMotionEventsReply>;
+
+ Future<GetDeviceMotionEventsReply> GetDeviceMotionEvents(
+ const GetDeviceMotionEventsRequest& request);
+
+ Future<GetDeviceMotionEventsReply> GetDeviceMotionEvents(
+ const Time& start = {},
+ const Time& stop = {},
+ const uint8_t& device_id = {});
+
+ struct ChangeKeyboardDeviceRequest {
+ uint8_t device_id{};
+ };
+
+ struct ChangeKeyboardDeviceReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ GrabStatus status{};
+ };
+
+ using ChangeKeyboardDeviceResponse = Response<ChangeKeyboardDeviceReply>;
+
+ Future<ChangeKeyboardDeviceReply> ChangeKeyboardDevice(
+ const ChangeKeyboardDeviceRequest& request);
+
+ Future<ChangeKeyboardDeviceReply> ChangeKeyboardDevice(
+ const uint8_t& device_id = {});
+
+ struct ChangePointerDeviceRequest {
+ uint8_t x_axis{};
+ uint8_t y_axis{};
+ uint8_t device_id{};
+ };
+
+ struct ChangePointerDeviceReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ GrabStatus status{};
+ };
+
+ using ChangePointerDeviceResponse = Response<ChangePointerDeviceReply>;
+
+ Future<ChangePointerDeviceReply> ChangePointerDevice(
+ const ChangePointerDeviceRequest& request);
+
+ Future<ChangePointerDeviceReply> ChangePointerDevice(
+ const uint8_t& x_axis = {},
+ const uint8_t& y_axis = {},
+ const uint8_t& device_id = {});
+
+ struct GrabDeviceRequest {
+ Window grab_window{};
+ Time time{};
+ GrabMode this_device_mode{};
+ GrabMode other_device_mode{};
+ uint8_t owner_events{};
+ uint8_t device_id{};
+ std::vector<EventClass> classes{};
+ };
+
+ struct GrabDeviceReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ GrabStatus status{};
+ };
+
+ using GrabDeviceResponse = Response<GrabDeviceReply>;
+
+ Future<GrabDeviceReply> GrabDevice(const GrabDeviceRequest& request);
+
+ Future<GrabDeviceReply> GrabDevice(
+ const Window& grab_window = {},
+ const Time& time = {},
+ const GrabMode& this_device_mode = {},
+ const GrabMode& other_device_mode = {},
+ const uint8_t& owner_events = {},
+ const uint8_t& device_id = {},
+ const std::vector<EventClass>& classes = {});
+
+ struct UngrabDeviceRequest {
+ Time time{};
+ uint8_t device_id{};
+ };
+
+ using UngrabDeviceResponse = Response<void>;
+
+ Future<void> UngrabDevice(const UngrabDeviceRequest& request);
+
+ Future<void> UngrabDevice(const Time& time = {},
+ const uint8_t& device_id = {});
+
+ struct GrabDeviceKeyRequest {
+ Window grab_window{};
+ ModMask modifiers{};
+ uint8_t modifier_device{};
+ uint8_t grabbed_device{};
+ uint8_t key{};
+ GrabMode this_device_mode{};
+ GrabMode other_device_mode{};
+ uint8_t owner_events{};
+ std::vector<EventClass> classes{};
+ };
+
+ using GrabDeviceKeyResponse = Response<void>;
+
+ Future<void> GrabDeviceKey(const GrabDeviceKeyRequest& request);
+
+ Future<void> GrabDeviceKey(const Window& grab_window = {},
+ const ModMask& modifiers = {},
+ const uint8_t& modifier_device = {},
+ const uint8_t& grabbed_device = {},
+ const uint8_t& key = {},
+ const GrabMode& this_device_mode = {},
+ const GrabMode& other_device_mode = {},
+ const uint8_t& owner_events = {},
+ const std::vector<EventClass>& classes = {});
+
+ struct UngrabDeviceKeyRequest {
+ Window grabWindow{};
+ ModMask modifiers{};
+ uint8_t modifier_device{};
+ uint8_t key{};
+ uint8_t grabbed_device{};
+ };
+
+ using UngrabDeviceKeyResponse = Response<void>;
+
+ Future<void> UngrabDeviceKey(const UngrabDeviceKeyRequest& request);
+
+ Future<void> UngrabDeviceKey(const Window& grabWindow = {},
+ const ModMask& modifiers = {},
+ const uint8_t& modifier_device = {},
+ const uint8_t& key = {},
+ const uint8_t& grabbed_device = {});
+
+ struct GrabDeviceButtonRequest {
+ Window grab_window{};
+ uint8_t grabbed_device{};
+ uint8_t modifier_device{};
+ ModMask modifiers{};
+ GrabMode this_device_mode{};
+ GrabMode other_device_mode{};
+ uint8_t button{};
+ uint8_t owner_events{};
+ std::vector<EventClass> classes{};
+ };
+
+ using GrabDeviceButtonResponse = Response<void>;
+
+ Future<void> GrabDeviceButton(const GrabDeviceButtonRequest& request);
+
+ Future<void> GrabDeviceButton(const Window& grab_window = {},
+ const uint8_t& grabbed_device = {},
+ const uint8_t& modifier_device = {},
+ const ModMask& modifiers = {},
+ const GrabMode& this_device_mode = {},
+ const GrabMode& other_device_mode = {},
+ const uint8_t& button = {},
+ const uint8_t& owner_events = {},
+ const std::vector<EventClass>& classes = {});
+
+ struct UngrabDeviceButtonRequest {
+ Window grab_window{};
+ ModMask modifiers{};
+ uint8_t modifier_device{};
+ uint8_t button{};
+ uint8_t grabbed_device{};
+ };
+
+ using UngrabDeviceButtonResponse = Response<void>;
+
+ Future<void> UngrabDeviceButton(const UngrabDeviceButtonRequest& request);
+
+ Future<void> UngrabDeviceButton(const Window& grab_window = {},
+ const ModMask& modifiers = {},
+ const uint8_t& modifier_device = {},
+ const uint8_t& button = {},
+ const uint8_t& grabbed_device = {});
+
+ struct AllowDeviceEventsRequest {
+ Time time{};
+ DeviceInputMode mode{};
+ uint8_t device_id{};
+ };
+
+ using AllowDeviceEventsResponse = Response<void>;
+
+ Future<void> AllowDeviceEvents(const AllowDeviceEventsRequest& request);
+
+ Future<void> AllowDeviceEvents(const Time& time = {},
+ const DeviceInputMode& mode = {},
+ const uint8_t& device_id = {});
+
+ struct GetDeviceFocusRequest {
+ uint8_t device_id{};
+ };
+
+ struct GetDeviceFocusReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ Window focus{};
+ Time time{};
+ InputFocus revert_to{};
+ };
+
+ using GetDeviceFocusResponse = Response<GetDeviceFocusReply>;
+
+ Future<GetDeviceFocusReply> GetDeviceFocus(
+ const GetDeviceFocusRequest& request);
+
+ Future<GetDeviceFocusReply> GetDeviceFocus(const uint8_t& device_id = {});
+
+ struct SetDeviceFocusRequest {
+ Window focus{};
+ Time time{};
+ InputFocus revert_to{};
+ uint8_t device_id{};
+ };
+
+ using SetDeviceFocusResponse = Response<void>;
+
+ Future<void> SetDeviceFocus(const SetDeviceFocusRequest& request);
+
+ Future<void> SetDeviceFocus(const Window& focus = {},
+ const Time& time = {},
+ const InputFocus& revert_to = {},
+ const uint8_t& device_id = {});
+
+ struct GetFeedbackControlRequest {
+ uint8_t device_id{};
+ };
+
+ struct GetFeedbackControlReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ std::vector<FeedbackState> feedbacks{};
+ };
+
+ using GetFeedbackControlResponse = Response<GetFeedbackControlReply>;
+
+ Future<GetFeedbackControlReply> GetFeedbackControl(
+ const GetFeedbackControlRequest& request);
+
+ Future<GetFeedbackControlReply> GetFeedbackControl(
+ const uint8_t& device_id = {});
+
+ struct ChangeFeedbackControlRequest {
+ ChangeFeedbackControlMask mask{};
+ uint8_t device_id{};
+ uint8_t feedback_id{};
+ FeedbackCtl feedback{};
+ };
+
+ using ChangeFeedbackControlResponse = Response<void>;
+
+ Future<void> ChangeFeedbackControl(
+ const ChangeFeedbackControlRequest& request);
+
+ struct Keyboard {
+ KeyCode key{};
+ uint8_t auto_repeat_mode{};
+ int8_t key_click_percent{};
+ int8_t bell_percent{};
+ int16_t bell_pitch{};
+ int16_t bell_duration{};
+ uint32_t led_mask{};
+ uint32_t led_values{};
+ };
+ struct Pointer {
+ int16_t num{};
+ int16_t denom{};
+ int16_t threshold{};
+ };
+ struct String {
+ std::vector<KeySym> keysyms{};
+ };
+ struct Integer {
+ int32_t int_to_display{};
+ };
+ struct Led {
+ uint32_t led_mask{};
+ uint32_t led_values{};
+ };
+ struct Bell {
+ int8_t percent{};
+ int16_t pitch{};
+ int16_t duration{};
+ };
+ Future<void> ChangeFeedbackControl(const ChangeFeedbackControlMask& mask = {},
+ const uint8_t& device_id = {},
+ const uint8_t& feedback_id = {},
+ const FeedbackCtl& feedback = {
+ {},
+ {},
+ base::nullopt,
+ base::nullopt,
+ base::nullopt,
+ base::nullopt,
+ base::nullopt,
+ base::nullopt});
+
+ struct GetDeviceKeyMappingRequest {
+ uint8_t device_id{};
+ KeyCode first_keycode{};
+ uint8_t count{};
+ };
+
+ struct GetDeviceKeyMappingReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ uint8_t keysyms_per_keycode{};
+ std::vector<KeySym> keysyms{};
+ };
+
+ using GetDeviceKeyMappingResponse = Response<GetDeviceKeyMappingReply>;
+
+ Future<GetDeviceKeyMappingReply> GetDeviceKeyMapping(
+ const GetDeviceKeyMappingRequest& request);
+
+ Future<GetDeviceKeyMappingReply> GetDeviceKeyMapping(
+ const uint8_t& device_id = {},
+ const KeyCode& first_keycode = {},
+ const uint8_t& count = {});
+
+ struct ChangeDeviceKeyMappingRequest {
+ uint8_t device_id{};
+ KeyCode first_keycode{};
+ uint8_t keysyms_per_keycode{};
+ uint8_t keycode_count{};
+ std::vector<KeySym> keysyms{};
+ };
+
+ using ChangeDeviceKeyMappingResponse = Response<void>;
+
+ Future<void> ChangeDeviceKeyMapping(
+ const ChangeDeviceKeyMappingRequest& request);
+
+ Future<void> ChangeDeviceKeyMapping(const uint8_t& device_id = {},
+ const KeyCode& first_keycode = {},
+ const uint8_t& keysyms_per_keycode = {},
+ const uint8_t& keycode_count = {},
+ const std::vector<KeySym>& keysyms = {});
+
+ struct GetDeviceModifierMappingRequest {
+ uint8_t device_id{};
+ };
+
+ struct GetDeviceModifierMappingReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ uint8_t keycodes_per_modifier{};
+ std::vector<uint8_t> keymaps{};
+ };
+
+ using GetDeviceModifierMappingResponse =
+ Response<GetDeviceModifierMappingReply>;
+
+ Future<GetDeviceModifierMappingReply> GetDeviceModifierMapping(
+ const GetDeviceModifierMappingRequest& request);
+
+ Future<GetDeviceModifierMappingReply> GetDeviceModifierMapping(
+ const uint8_t& device_id = {});
+
+ struct SetDeviceModifierMappingRequest {
+ uint8_t device_id{};
+ uint8_t keycodes_per_modifier{};
+ std::vector<uint8_t> keymaps{};
+ };
+
+ struct SetDeviceModifierMappingReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ MappingStatus status{};
+ };
+
+ using SetDeviceModifierMappingResponse =
+ Response<SetDeviceModifierMappingReply>;
+
+ Future<SetDeviceModifierMappingReply> SetDeviceModifierMapping(
+ const SetDeviceModifierMappingRequest& request);
+
+ Future<SetDeviceModifierMappingReply> SetDeviceModifierMapping(
+ const uint8_t& device_id = {},
+ const uint8_t& keycodes_per_modifier = {},
+ const std::vector<uint8_t>& keymaps = {});
+
+ struct GetDeviceButtonMappingRequest {
+ uint8_t device_id{};
+ };
+
+ struct GetDeviceButtonMappingReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ std::vector<uint8_t> map{};
+ };
+
+ using GetDeviceButtonMappingResponse = Response<GetDeviceButtonMappingReply>;
+
+ Future<GetDeviceButtonMappingReply> GetDeviceButtonMapping(
+ const GetDeviceButtonMappingRequest& request);
+
+ Future<GetDeviceButtonMappingReply> GetDeviceButtonMapping(
+ const uint8_t& device_id = {});
+
+ struct SetDeviceButtonMappingRequest {
+ uint8_t device_id{};
+ std::vector<uint8_t> map{};
+ };
+
+ struct SetDeviceButtonMappingReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ MappingStatus status{};
+ };
+
+ using SetDeviceButtonMappingResponse = Response<SetDeviceButtonMappingReply>;
+
+ Future<SetDeviceButtonMappingReply> SetDeviceButtonMapping(
+ const SetDeviceButtonMappingRequest& request);
+
+ Future<SetDeviceButtonMappingReply> SetDeviceButtonMapping(
+ const uint8_t& device_id = {},
+ const std::vector<uint8_t>& map = {});
+
+ struct QueryDeviceStateRequest {
+ uint8_t device_id{};
+ };
+
+ struct QueryDeviceStateReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ std::vector<InputState> classes{};
+ };
+
+ using QueryDeviceStateResponse = Response<QueryDeviceStateReply>;
+
+ Future<QueryDeviceStateReply> QueryDeviceState(
+ const QueryDeviceStateRequest& request);
+
+ Future<QueryDeviceStateReply> QueryDeviceState(const uint8_t& device_id = {});
+
+ struct DeviceBellRequest {
+ uint8_t device_id{};
+ uint8_t feedback_id{};
+ uint8_t feedback_class{};
+ int8_t percent{};
+ };
+
+ using DeviceBellResponse = Response<void>;
+
+ Future<void> DeviceBell(const DeviceBellRequest& request);
+
+ Future<void> DeviceBell(const uint8_t& device_id = {},
+ const uint8_t& feedback_id = {},
+ const uint8_t& feedback_class = {},
+ const int8_t& percent = {});
+
+ struct SetDeviceValuatorsRequest {
+ uint8_t device_id{};
+ uint8_t first_valuator{};
+ std::vector<int32_t> valuators{};
+ };
+
+ struct SetDeviceValuatorsReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ GrabStatus status{};
+ };
+
+ using SetDeviceValuatorsResponse = Response<SetDeviceValuatorsReply>;
+
+ Future<SetDeviceValuatorsReply> SetDeviceValuators(
+ const SetDeviceValuatorsRequest& request);
+
+ Future<SetDeviceValuatorsReply> SetDeviceValuators(
+ const uint8_t& device_id = {},
+ const uint8_t& first_valuator = {},
+ const std::vector<int32_t>& valuators = {});
+
+ struct GetDeviceControlRequest {
+ DeviceControl control_id{};
+ uint8_t device_id{};
+ };
+
+ struct GetDeviceControlReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ uint8_t status{};
+ DeviceState control{};
+ };
+
+ using GetDeviceControlResponse = Response<GetDeviceControlReply>;
+
+ Future<GetDeviceControlReply> GetDeviceControl(
+ const GetDeviceControlRequest& request);
+
+ Future<GetDeviceControlReply> GetDeviceControl(
+ const DeviceControl& control_id = {},
+ const uint8_t& device_id = {});
+
+ struct ChangeDeviceControlRequest {
+ DeviceControl control_id{};
+ uint8_t device_id{};
+ DeviceCtl control{};
+ };
+
+ struct ChangeDeviceControlReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ uint8_t status{};
+ };
+
+ using ChangeDeviceControlResponse = Response<ChangeDeviceControlReply>;
+
+ Future<ChangeDeviceControlReply> ChangeDeviceControl(
+ const ChangeDeviceControlRequest& request);
+
+ struct Resolution {
+ uint8_t first_valuator{};
+ std::vector<uint32_t> resolution_values{};
+ };
+ struct AbsCalib {
+ int32_t min_x{};
+ int32_t max_x{};
+ int32_t min_y{};
+ int32_t max_y{};
+ uint32_t flip_x{};
+ uint32_t flip_y{};
+ uint32_t rotation{};
+ uint32_t button_threshold{};
+ };
+ struct Core {
+ uint8_t status{};
+ };
+ struct Enable {
+ uint8_t enable{};
+ };
+ struct AbsArea {
+ uint32_t offset_x{};
+ uint32_t offset_y{};
+ int32_t width{};
+ int32_t height{};
+ int32_t screen{};
+ uint32_t following{};
+ };
+ Future<ChangeDeviceControlReply> ChangeDeviceControl(
+ const DeviceControl& control_id = {},
+ const uint8_t& device_id = {},
+ const DeviceCtl& control = {{},
+ base::nullopt,
+ base::nullopt,
+ base::nullopt,
+ base::nullopt,
+ base::nullopt});
+
+ struct ListDevicePropertiesRequest {
+ uint8_t device_id{};
+ };
+
+ struct ListDevicePropertiesReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ std::vector<Atom> atoms{};
+ };
+
+ using ListDevicePropertiesResponse = Response<ListDevicePropertiesReply>;
+
+ Future<ListDevicePropertiesReply> ListDeviceProperties(
+ const ListDevicePropertiesRequest& request);
+
+ Future<ListDevicePropertiesReply> ListDeviceProperties(
+ const uint8_t& device_id = {});
+
+ struct ChangeDevicePropertyRequest {
+ Atom property{};
+ Atom type{};
+ uint8_t device_id{};
+ PropMode mode{};
+ uint32_t num_items{};
+ base::Optional<std::vector<uint8_t>> data8{};
+ base::Optional<std::vector<uint16_t>> data16{};
+ base::Optional<std::vector<uint32_t>> data32{};
+ };
+
+ using ChangeDevicePropertyResponse = Response<void>;
+
+ Future<void> ChangeDeviceProperty(const ChangeDevicePropertyRequest& request);
+
+ Future<void> ChangeDeviceProperty(
+ const Atom& property = {},
+ const Atom& type = {},
+ const uint8_t& device_id = {},
+ const PropMode& mode = {},
+ const uint32_t& num_items = {},
+ const base::Optional<std::vector<uint8_t>>& data8 = base::nullopt,
+ const base::Optional<std::vector<uint16_t>>& data16 = base::nullopt,
+ const base::Optional<std::vector<uint32_t>>& data32 = base::nullopt);
+
+ struct DeleteDevicePropertyRequest {
+ Atom property{};
+ uint8_t device_id{};
+ };
+
+ using DeleteDevicePropertyResponse = Response<void>;
+
+ Future<void> DeleteDeviceProperty(const DeleteDevicePropertyRequest& request);
+
+ Future<void> DeleteDeviceProperty(const Atom& property = {},
+ const uint8_t& device_id = {});
+
+ struct GetDevicePropertyRequest {
+ Atom property{};
+ Atom type{};
+ uint32_t offset{};
+ uint32_t len{};
+ uint8_t device_id{};
+ uint8_t c_delete{};
+ };
+
+ struct GetDevicePropertyReply {
+ uint8_t xi_reply_type{};
+ uint16_t sequence{};
+ Atom type{};
+ uint32_t bytes_after{};
+ uint32_t num_items{};
+ uint8_t device_id{};
+ base::Optional<std::vector<uint8_t>> data8{};
+ base::Optional<std::vector<uint16_t>> data16{};
+ base::Optional<std::vector<uint32_t>> data32{};
+ };
+
+ using GetDevicePropertyResponse = Response<GetDevicePropertyReply>;
+
+ Future<GetDevicePropertyReply> GetDeviceProperty(
+ const GetDevicePropertyRequest& request);
+
+ Future<GetDevicePropertyReply> GetDeviceProperty(
+ const Atom& property = {},
+ const Atom& type = {},
+ const uint32_t& offset = {},
+ const uint32_t& len = {},
+ const uint8_t& device_id = {},
+ const uint8_t& c_delete = {});
+
+ struct XIQueryPointerRequest {
+ Window window{};
+ DeviceId deviceid{};
+ };
+
+ struct XIQueryPointerReply {
+ uint16_t sequence{};
+ Window root{};
+ Window child{};
+ Fp1616 root_x{};
+ Fp1616 root_y{};
+ Fp1616 win_x{};
+ Fp1616 win_y{};
+ uint8_t same_screen{};
+ ModifierInfo mods{};
+ GroupInfo group{};
+ std::vector<uint32_t> buttons{};
+ };
+
+ using XIQueryPointerResponse = Response<XIQueryPointerReply>;
+
+ Future<XIQueryPointerReply> XIQueryPointer(
+ const XIQueryPointerRequest& request);
+
+ Future<XIQueryPointerReply> XIQueryPointer(const Window& window = {},
+ const DeviceId& deviceid = {});
+
+ struct XIWarpPointerRequest {
+ Window src_win{};
+ Window dst_win{};
+ Fp1616 src_x{};
+ Fp1616 src_y{};
+ uint16_t src_width{};
+ uint16_t src_height{};
+ Fp1616 dst_x{};
+ Fp1616 dst_y{};
+ DeviceId deviceid{};
+ };
+
+ using XIWarpPointerResponse = Response<void>;
+
+ Future<void> XIWarpPointer(const XIWarpPointerRequest& request);
+
+ Future<void> XIWarpPointer(const Window& src_win = {},
+ const Window& dst_win = {},
+ const Fp1616& src_x = {},
+ const Fp1616& src_y = {},
+ const uint16_t& src_width = {},
+ const uint16_t& src_height = {},
+ const Fp1616& dst_x = {},
+ const Fp1616& dst_y = {},
+ const DeviceId& deviceid = {});
+
+ struct XIChangeCursorRequest {
+ Window window{};
+ Cursor cursor{};
+ DeviceId deviceid{};
+ };
+
+ using XIChangeCursorResponse = Response<void>;
+
+ Future<void> XIChangeCursor(const XIChangeCursorRequest& request);
+
+ Future<void> XIChangeCursor(const Window& window = {},
+ const Cursor& cursor = {},
+ const DeviceId& deviceid = {});
+
+ struct XIChangeHierarchyRequest {
+ std::vector<HierarchyChange> changes{};
+ };
+
+ using XIChangeHierarchyResponse = Response<void>;
+
+ Future<void> XIChangeHierarchy(const XIChangeHierarchyRequest& request);
+
+ Future<void> XIChangeHierarchy(
+ const std::vector<HierarchyChange>& changes = {});
+
+ struct XISetClientPointerRequest {
+ Window window{};
+ DeviceId deviceid{};
+ };
+
+ using XISetClientPointerResponse = Response<void>;
+
+ Future<void> XISetClientPointer(const XISetClientPointerRequest& request);
+
+ Future<void> XISetClientPointer(const Window& window = {},
+ const DeviceId& deviceid = {});
+
+ struct XIGetClientPointerRequest {
+ Window window{};
+ };
+
+ struct XIGetClientPointerReply {
+ uint16_t sequence{};
+ uint8_t set{};
+ DeviceId deviceid{};
+ };
+
+ using XIGetClientPointerResponse = Response<XIGetClientPointerReply>;
+
+ Future<XIGetClientPointerReply> XIGetClientPointer(
+ const XIGetClientPointerRequest& request);
+
+ Future<XIGetClientPointerReply> XIGetClientPointer(const Window& window = {});
+
+ struct XISelectEventsRequest {
+ Window window{};
+ std::vector<EventMask> masks{};
+ };
+
+ using XISelectEventsResponse = Response<void>;
+
+ Future<void> XISelectEvents(const XISelectEventsRequest& request);
+
+ Future<void> XISelectEvents(const Window& window = {},
+ const std::vector<EventMask>& masks = {});
+
+ struct XIQueryVersionRequest {
+ uint16_t major_version{};
+ uint16_t minor_version{};
+ };
+
+ struct XIQueryVersionReply {
+ uint16_t sequence{};
+ uint16_t major_version{};
+ uint16_t minor_version{};
+ };
+
+ using XIQueryVersionResponse = Response<XIQueryVersionReply>;
+
+ Future<XIQueryVersionReply> XIQueryVersion(
+ const XIQueryVersionRequest& request);
+
+ Future<XIQueryVersionReply> XIQueryVersion(
+ const uint16_t& major_version = {},
+ const uint16_t& minor_version = {});
+
+ struct XIQueryDeviceRequest {
+ DeviceId deviceid{};
+ };
+
+ struct XIQueryDeviceReply {
+ uint16_t sequence{};
+ std::vector<XIDeviceInfo> infos{};
+ };
+
+ using XIQueryDeviceResponse = Response<XIQueryDeviceReply>;
+
+ Future<XIQueryDeviceReply> XIQueryDevice(const XIQueryDeviceRequest& request);
+
+ Future<XIQueryDeviceReply> XIQueryDevice(const DeviceId& deviceid = {});
+
+ struct XISetFocusRequest {
+ Window window{};
+ Time time{};
+ DeviceId deviceid{};
+ };
+
+ using XISetFocusResponse = Response<void>;
+
+ Future<void> XISetFocus(const XISetFocusRequest& request);
+
+ Future<void> XISetFocus(const Window& window = {},
+ const Time& time = {},
+ const DeviceId& deviceid = {});
+
+ struct XIGetFocusRequest {
+ DeviceId deviceid{};
+ };
+
+ struct XIGetFocusReply {
+ uint16_t sequence{};
+ Window focus{};
+ };
+
+ using XIGetFocusResponse = Response<XIGetFocusReply>;
+
+ Future<XIGetFocusReply> XIGetFocus(const XIGetFocusRequest& request);
+
+ Future<XIGetFocusReply> XIGetFocus(const DeviceId& deviceid = {});
+
+ struct XIGrabDeviceRequest {
+ Window window{};
+ Time time{};
+ Cursor cursor{};
+ DeviceId deviceid{};
+ GrabMode mode{};
+ GrabMode paired_device_mode{};
+ GrabOwner owner_events{};
+ std::vector<uint32_t> mask{};
+ };
+
+ struct XIGrabDeviceReply {
+ uint16_t sequence{};
+ GrabStatus status{};
+ };
+
+ using XIGrabDeviceResponse = Response<XIGrabDeviceReply>;
+
+ Future<XIGrabDeviceReply> XIGrabDevice(const XIGrabDeviceRequest& request);
+
+ Future<XIGrabDeviceReply> XIGrabDevice(
+ const Window& window = {},
+ const Time& time = {},
+ const Cursor& cursor = {},
+ const DeviceId& deviceid = {},
+ const GrabMode& mode = {},
+ const GrabMode& paired_device_mode = {},
+ const GrabOwner& owner_events = {},
+ const std::vector<uint32_t>& mask = {});
+
+ struct XIUngrabDeviceRequest {
+ Time time{};
+ DeviceId deviceid{};
+ };
+
+ using XIUngrabDeviceResponse = Response<void>;
+
+ Future<void> XIUngrabDevice(const XIUngrabDeviceRequest& request);
+
+ Future<void> XIUngrabDevice(const Time& time = {},
+ const DeviceId& deviceid = {});
+
+ struct XIAllowEventsRequest {
+ Time time{};
+ DeviceId deviceid{};
+ EventMode event_mode{};
+ uint32_t touchid{};
+ Window grab_window{};
+ };
+
+ using XIAllowEventsResponse = Response<void>;
+
+ Future<void> XIAllowEvents(const XIAllowEventsRequest& request);
+
+ Future<void> XIAllowEvents(const Time& time = {},
+ const DeviceId& deviceid = {},
+ const EventMode& event_mode = {},
+ const uint32_t& touchid = {},
+ const Window& grab_window = {});
+
+ struct XIPassiveGrabDeviceRequest {
+ Time time{};
+ Window grab_window{};
+ Cursor cursor{};
+ uint32_t detail{};
+ DeviceId deviceid{};
+ GrabType grab_type{};
+ GrabMode22 grab_mode{};
+ GrabMode paired_device_mode{};
+ GrabOwner owner_events{};
+ std::vector<uint32_t> mask{};
+ std::vector<uint32_t> modifiers{};
+ };
+
+ struct XIPassiveGrabDeviceReply {
+ uint16_t sequence{};
+ std::vector<GrabModifierInfo> modifiers{};
+ };
+
+ using XIPassiveGrabDeviceResponse = Response<XIPassiveGrabDeviceReply>;
+
+ Future<XIPassiveGrabDeviceReply> XIPassiveGrabDevice(
+ const XIPassiveGrabDeviceRequest& request);
+
+ Future<XIPassiveGrabDeviceReply> XIPassiveGrabDevice(
+ const Time& time = {},
+ const Window& grab_window = {},
+ const Cursor& cursor = {},
+ const uint32_t& detail = {},
+ const DeviceId& deviceid = {},
+ const GrabType& grab_type = {},
+ const GrabMode22& grab_mode = {},
+ const GrabMode& paired_device_mode = {},
+ const GrabOwner& owner_events = {},
+ const std::vector<uint32_t>& mask = {},
+ const std::vector<uint32_t>& modifiers = {});
+
+ struct XIPassiveUngrabDeviceRequest {
+ Window grab_window{};
+ uint32_t detail{};
+ DeviceId deviceid{};
+ GrabType grab_type{};
+ std::vector<uint32_t> modifiers{};
+ };
+
+ using XIPassiveUngrabDeviceResponse = Response<void>;
+
+ Future<void> XIPassiveUngrabDevice(
+ const XIPassiveUngrabDeviceRequest& request);
+
+ Future<void> XIPassiveUngrabDevice(
+ const Window& grab_window = {},
+ const uint32_t& detail = {},
+ const DeviceId& deviceid = {},
+ const GrabType& grab_type = {},
+ const std::vector<uint32_t>& modifiers = {});
+
+ struct XIListPropertiesRequest {
+ DeviceId deviceid{};
+ };
+
+ struct XIListPropertiesReply {
+ uint16_t sequence{};
+ std::vector<Atom> properties{};
+ };
+
+ using XIListPropertiesResponse = Response<XIListPropertiesReply>;
+
+ Future<XIListPropertiesReply> XIListProperties(
+ const XIListPropertiesRequest& request);
+
+ Future<XIListPropertiesReply> XIListProperties(const DeviceId& deviceid = {});
+
+ struct XIChangePropertyRequest {
+ DeviceId deviceid{};
+ PropMode mode{};
+ Atom property{};
+ Atom type{};
+ uint32_t num_items{};
+ base::Optional<std::vector<uint8_t>> data8{};
+ base::Optional<std::vector<uint16_t>> data16{};
+ base::Optional<std::vector<uint32_t>> data32{};
+ };
+
+ using XIChangePropertyResponse = Response<void>;
+
+ Future<void> XIChangeProperty(const XIChangePropertyRequest& request);
+
+ Future<void> XIChangeProperty(
+ const DeviceId& deviceid = {},
+ const PropMode& mode = {},
+ const Atom& property = {},
+ const Atom& type = {},
+ const uint32_t& num_items = {},
+ const base::Optional<std::vector<uint8_t>>& data8 = base::nullopt,
+ const base::Optional<std::vector<uint16_t>>& data16 = base::nullopt,
+ const base::Optional<std::vector<uint32_t>>& data32 = base::nullopt);
+
+ struct XIDeletePropertyRequest {
+ DeviceId deviceid{};
+ Atom property{};
+ };
+
+ using XIDeletePropertyResponse = Response<void>;
+
+ Future<void> XIDeleteProperty(const XIDeletePropertyRequest& request);
+
+ Future<void> XIDeleteProperty(const DeviceId& deviceid = {},
+ const Atom& property = {});
+
+ struct XIGetPropertyRequest {
+ DeviceId deviceid{};
+ uint8_t c_delete{};
+ Atom property{};
+ Atom type{};
+ uint32_t offset{};
+ uint32_t len{};
+ };
+
+ struct XIGetPropertyReply {
+ uint16_t sequence{};
+ Atom type{};
+ uint32_t bytes_after{};
+ uint32_t num_items{};
+ base::Optional<std::vector<uint8_t>> data8{};
+ base::Optional<std::vector<uint16_t>> data16{};
+ base::Optional<std::vector<uint32_t>> data32{};
+ };
+
+ using XIGetPropertyResponse = Response<XIGetPropertyReply>;
+
+ Future<XIGetPropertyReply> XIGetProperty(const XIGetPropertyRequest& request);
+
+ Future<XIGetPropertyReply> XIGetProperty(const DeviceId& deviceid = {},
+ const uint8_t& c_delete = {},
+ const Atom& property = {},
+ const Atom& type = {},
+ const uint32_t& offset = {},
+ const uint32_t& len = {});
+
+ struct XIGetSelectedEventsRequest {
+ Window window{};
+ };
+
+ struct XIGetSelectedEventsReply {
+ uint16_t sequence{};
+ std::vector<EventMask> masks{};
+ };
+
+ using XIGetSelectedEventsResponse = Response<XIGetSelectedEventsReply>;
+
+ Future<XIGetSelectedEventsReply> XIGetSelectedEvents(
+ const XIGetSelectedEventsRequest& request);
+
+ Future<XIGetSelectedEventsReply> XIGetSelectedEvents(
+ const Window& window = {});
+
+ struct XIBarrierReleasePointerRequest {
+ std::vector<BarrierReleasePointerInfo> barriers{};
+ };
+
+ using XIBarrierReleasePointerResponse = Response<void>;
+
+ Future<void> XIBarrierReleasePointer(
+ const XIBarrierReleasePointerRequest& request);
+
+ Future<void> XIBarrierReleasePointer(
+ const std::vector<BarrierReleasePointerInfo>& barriers = {});
+
+ struct SendExtensionEventRequest {
+ Window destination{};
+ uint8_t device_id{};
+ uint8_t propagate{};
+ std::vector<EventForSend> events{};
+ std::vector<EventClass> classes{};
+ };
+
+ using SendExtensionEventResponse = Response<void>;
+
+ Future<void> SendExtensionEvent(const SendExtensionEventRequest& request);
+
+ Future<void> SendExtensionEvent(const Window& destination = {},
+ const uint8_t& device_id = {},
+ const uint8_t& propagate = {},
+ const std::vector<EventForSend>& events = {},
+ const std::vector<EventClass>& classes = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Input::DeviceUse operator|(x11::Input::DeviceUse l,
+ x11::Input::DeviceUse r) {
+ using T = std::underlying_type_t<x11::Input::DeviceUse>;
+ return static_cast<x11::Input::DeviceUse>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceUse operator&(x11::Input::DeviceUse l,
+ x11::Input::DeviceUse r) {
+ using T = std::underlying_type_t<x11::Input::DeviceUse>;
+ return static_cast<x11::Input::DeviceUse>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::InputClass operator|(x11::Input::InputClass l,
+ x11::Input::InputClass r) {
+ using T = std::underlying_type_t<x11::Input::InputClass>;
+ return static_cast<x11::Input::InputClass>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::InputClass operator&(x11::Input::InputClass l,
+ x11::Input::InputClass r) {
+ using T = std::underlying_type_t<x11::Input::InputClass>;
+ return static_cast<x11::Input::InputClass>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ValuatorMode operator|(
+ x11::Input::ValuatorMode l,
+ x11::Input::ValuatorMode r) {
+ using T = std::underlying_type_t<x11::Input::ValuatorMode>;
+ return static_cast<x11::Input::ValuatorMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ValuatorMode operator&(
+ x11::Input::ValuatorMode l,
+ x11::Input::ValuatorMode r) {
+ using T = std::underlying_type_t<x11::Input::ValuatorMode>;
+ return static_cast<x11::Input::ValuatorMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::PropagateMode operator|(
+ x11::Input::PropagateMode l,
+ x11::Input::PropagateMode r) {
+ using T = std::underlying_type_t<x11::Input::PropagateMode>;
+ return static_cast<x11::Input::PropagateMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::PropagateMode operator&(
+ x11::Input::PropagateMode l,
+ x11::Input::PropagateMode r) {
+ using T = std::underlying_type_t<x11::Input::PropagateMode>;
+ return static_cast<x11::Input::PropagateMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ModifierDevice operator|(
+ x11::Input::ModifierDevice l,
+ x11::Input::ModifierDevice r) {
+ using T = std::underlying_type_t<x11::Input::ModifierDevice>;
+ return static_cast<x11::Input::ModifierDevice>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ModifierDevice operator&(
+ x11::Input::ModifierDevice l,
+ x11::Input::ModifierDevice r) {
+ using T = std::underlying_type_t<x11::Input::ModifierDevice>;
+ return static_cast<x11::Input::ModifierDevice>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceInputMode operator|(
+ x11::Input::DeviceInputMode l,
+ x11::Input::DeviceInputMode r) {
+ using T = std::underlying_type_t<x11::Input::DeviceInputMode>;
+ return static_cast<x11::Input::DeviceInputMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceInputMode operator&(
+ x11::Input::DeviceInputMode l,
+ x11::Input::DeviceInputMode r) {
+ using T = std::underlying_type_t<x11::Input::DeviceInputMode>;
+ return static_cast<x11::Input::DeviceInputMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::FeedbackClass operator|(
+ x11::Input::FeedbackClass l,
+ x11::Input::FeedbackClass r) {
+ using T = std::underlying_type_t<x11::Input::FeedbackClass>;
+ return static_cast<x11::Input::FeedbackClass>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::FeedbackClass operator&(
+ x11::Input::FeedbackClass l,
+ x11::Input::FeedbackClass r) {
+ using T = std::underlying_type_t<x11::Input::FeedbackClass>;
+ return static_cast<x11::Input::FeedbackClass>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ChangeFeedbackControlMask operator|(
+ x11::Input::ChangeFeedbackControlMask l,
+ x11::Input::ChangeFeedbackControlMask r) {
+ using T = std::underlying_type_t<x11::Input::ChangeFeedbackControlMask>;
+ return static_cast<x11::Input::ChangeFeedbackControlMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ChangeFeedbackControlMask operator&(
+ x11::Input::ChangeFeedbackControlMask l,
+ x11::Input::ChangeFeedbackControlMask r) {
+ using T = std::underlying_type_t<x11::Input::ChangeFeedbackControlMask>;
+ return static_cast<x11::Input::ChangeFeedbackControlMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ValuatorStateModeMask operator|(
+ x11::Input::ValuatorStateModeMask l,
+ x11::Input::ValuatorStateModeMask r) {
+ using T = std::underlying_type_t<x11::Input::ValuatorStateModeMask>;
+ return static_cast<x11::Input::ValuatorStateModeMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ValuatorStateModeMask operator&(
+ x11::Input::ValuatorStateModeMask l,
+ x11::Input::ValuatorStateModeMask r) {
+ using T = std::underlying_type_t<x11::Input::ValuatorStateModeMask>;
+ return static_cast<x11::Input::ValuatorStateModeMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceControl operator|(
+ x11::Input::DeviceControl l,
+ x11::Input::DeviceControl r) {
+ using T = std::underlying_type_t<x11::Input::DeviceControl>;
+ return static_cast<x11::Input::DeviceControl>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceControl operator&(
+ x11::Input::DeviceControl l,
+ x11::Input::DeviceControl r) {
+ using T = std::underlying_type_t<x11::Input::DeviceControl>;
+ return static_cast<x11::Input::DeviceControl>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::PropertyFormat operator|(
+ x11::Input::PropertyFormat l,
+ x11::Input::PropertyFormat r) {
+ using T = std::underlying_type_t<x11::Input::PropertyFormat>;
+ return static_cast<x11::Input::PropertyFormat>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::PropertyFormat operator&(
+ x11::Input::PropertyFormat l,
+ x11::Input::PropertyFormat r) {
+ using T = std::underlying_type_t<x11::Input::PropertyFormat>;
+ return static_cast<x11::Input::PropertyFormat>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceId operator|(x11::Input::DeviceId l,
+ x11::Input::DeviceId r) {
+ using T = std::underlying_type_t<x11::Input::DeviceId>;
+ return static_cast<x11::Input::DeviceId>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceId operator&(x11::Input::DeviceId l,
+ x11::Input::DeviceId r) {
+ using T = std::underlying_type_t<x11::Input::DeviceId>;
+ return static_cast<x11::Input::DeviceId>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::HierarchyChangeType operator|(
+ x11::Input::HierarchyChangeType l,
+ x11::Input::HierarchyChangeType r) {
+ using T = std::underlying_type_t<x11::Input::HierarchyChangeType>;
+ return static_cast<x11::Input::HierarchyChangeType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::HierarchyChangeType operator&(
+ x11::Input::HierarchyChangeType l,
+ x11::Input::HierarchyChangeType r) {
+ using T = std::underlying_type_t<x11::Input::HierarchyChangeType>;
+ return static_cast<x11::Input::HierarchyChangeType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ChangeMode operator|(x11::Input::ChangeMode l,
+ x11::Input::ChangeMode r) {
+ using T = std::underlying_type_t<x11::Input::ChangeMode>;
+ return static_cast<x11::Input::ChangeMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ChangeMode operator&(x11::Input::ChangeMode l,
+ x11::Input::ChangeMode r) {
+ using T = std::underlying_type_t<x11::Input::ChangeMode>;
+ return static_cast<x11::Input::ChangeMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::XIEventMask operator|(x11::Input::XIEventMask l,
+ x11::Input::XIEventMask r) {
+ using T = std::underlying_type_t<x11::Input::XIEventMask>;
+ return static_cast<x11::Input::XIEventMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::XIEventMask operator&(x11::Input::XIEventMask l,
+ x11::Input::XIEventMask r) {
+ using T = std::underlying_type_t<x11::Input::XIEventMask>;
+ return static_cast<x11::Input::XIEventMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceClassType operator|(
+ x11::Input::DeviceClassType l,
+ x11::Input::DeviceClassType r) {
+ using T = std::underlying_type_t<x11::Input::DeviceClassType>;
+ return static_cast<x11::Input::DeviceClassType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceClassType operator&(
+ x11::Input::DeviceClassType l,
+ x11::Input::DeviceClassType r) {
+ using T = std::underlying_type_t<x11::Input::DeviceClassType>;
+ return static_cast<x11::Input::DeviceClassType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceType operator|(x11::Input::DeviceType l,
+ x11::Input::DeviceType r) {
+ using T = std::underlying_type_t<x11::Input::DeviceType>;
+ return static_cast<x11::Input::DeviceType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceType operator&(x11::Input::DeviceType l,
+ x11::Input::DeviceType r) {
+ using T = std::underlying_type_t<x11::Input::DeviceType>;
+ return static_cast<x11::Input::DeviceType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ScrollFlags operator|(x11::Input::ScrollFlags l,
+ x11::Input::ScrollFlags r) {
+ using T = std::underlying_type_t<x11::Input::ScrollFlags>;
+ return static_cast<x11::Input::ScrollFlags>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ScrollFlags operator&(x11::Input::ScrollFlags l,
+ x11::Input::ScrollFlags r) {
+ using T = std::underlying_type_t<x11::Input::ScrollFlags>;
+ return static_cast<x11::Input::ScrollFlags>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ScrollType operator|(x11::Input::ScrollType l,
+ x11::Input::ScrollType r) {
+ using T = std::underlying_type_t<x11::Input::ScrollType>;
+ return static_cast<x11::Input::ScrollType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ScrollType operator&(x11::Input::ScrollType l,
+ x11::Input::ScrollType r) {
+ using T = std::underlying_type_t<x11::Input::ScrollType>;
+ return static_cast<x11::Input::ScrollType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::TouchMode operator|(x11::Input::TouchMode l,
+ x11::Input::TouchMode r) {
+ using T = std::underlying_type_t<x11::Input::TouchMode>;
+ return static_cast<x11::Input::TouchMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::TouchMode operator&(x11::Input::TouchMode l,
+ x11::Input::TouchMode r) {
+ using T = std::underlying_type_t<x11::Input::TouchMode>;
+ return static_cast<x11::Input::TouchMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::GrabOwner operator|(x11::Input::GrabOwner l,
+ x11::Input::GrabOwner r) {
+ using T = std::underlying_type_t<x11::Input::GrabOwner>;
+ return static_cast<x11::Input::GrabOwner>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::GrabOwner operator&(x11::Input::GrabOwner l,
+ x11::Input::GrabOwner r) {
+ using T = std::underlying_type_t<x11::Input::GrabOwner>;
+ return static_cast<x11::Input::GrabOwner>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::EventMode operator|(x11::Input::EventMode l,
+ x11::Input::EventMode r) {
+ using T = std::underlying_type_t<x11::Input::EventMode>;
+ return static_cast<x11::Input::EventMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::EventMode operator&(x11::Input::EventMode l,
+ x11::Input::EventMode r) {
+ using T = std::underlying_type_t<x11::Input::EventMode>;
+ return static_cast<x11::Input::EventMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::GrabMode22 operator|(x11::Input::GrabMode22 l,
+ x11::Input::GrabMode22 r) {
+ using T = std::underlying_type_t<x11::Input::GrabMode22>;
+ return static_cast<x11::Input::GrabMode22>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::GrabMode22 operator&(x11::Input::GrabMode22 l,
+ x11::Input::GrabMode22 r) {
+ using T = std::underlying_type_t<x11::Input::GrabMode22>;
+ return static_cast<x11::Input::GrabMode22>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::GrabType operator|(x11::Input::GrabType l,
+ x11::Input::GrabType r) {
+ using T = std::underlying_type_t<x11::Input::GrabType>;
+ return static_cast<x11::Input::GrabType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::GrabType operator&(x11::Input::GrabType l,
+ x11::Input::GrabType r) {
+ using T = std::underlying_type_t<x11::Input::GrabType>;
+ return static_cast<x11::Input::GrabType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ModifierMask operator|(
+ x11::Input::ModifierMask l,
+ x11::Input::ModifierMask r) {
+ using T = std::underlying_type_t<x11::Input::ModifierMask>;
+ return static_cast<x11::Input::ModifierMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ModifierMask operator&(
+ x11::Input::ModifierMask l,
+ x11::Input::ModifierMask r) {
+ using T = std::underlying_type_t<x11::Input::ModifierMask>;
+ return static_cast<x11::Input::ModifierMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::MoreEventsMask operator|(
+ x11::Input::MoreEventsMask l,
+ x11::Input::MoreEventsMask r) {
+ using T = std::underlying_type_t<x11::Input::MoreEventsMask>;
+ return static_cast<x11::Input::MoreEventsMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::MoreEventsMask operator&(
+ x11::Input::MoreEventsMask l,
+ x11::Input::MoreEventsMask r) {
+ using T = std::underlying_type_t<x11::Input::MoreEventsMask>;
+ return static_cast<x11::Input::MoreEventsMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ClassesReportedMask operator|(
+ x11::Input::ClassesReportedMask l,
+ x11::Input::ClassesReportedMask r) {
+ using T = std::underlying_type_t<x11::Input::ClassesReportedMask>;
+ return static_cast<x11::Input::ClassesReportedMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ClassesReportedMask operator&(
+ x11::Input::ClassesReportedMask l,
+ x11::Input::ClassesReportedMask r) {
+ using T = std::underlying_type_t<x11::Input::ClassesReportedMask>;
+ return static_cast<x11::Input::ClassesReportedMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ChangeDevice operator|(
+ x11::Input::ChangeDevice l,
+ x11::Input::ChangeDevice r) {
+ using T = std::underlying_type_t<x11::Input::ChangeDevice>;
+ return static_cast<x11::Input::ChangeDevice>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ChangeDevice operator&(
+ x11::Input::ChangeDevice l,
+ x11::Input::ChangeDevice r) {
+ using T = std::underlying_type_t<x11::Input::ChangeDevice>;
+ return static_cast<x11::Input::ChangeDevice>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceChange operator|(
+ x11::Input::DeviceChange l,
+ x11::Input::DeviceChange r) {
+ using T = std::underlying_type_t<x11::Input::DeviceChange>;
+ return static_cast<x11::Input::DeviceChange>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::DeviceChange operator&(
+ x11::Input::DeviceChange l,
+ x11::Input::DeviceChange r) {
+ using T = std::underlying_type_t<x11::Input::DeviceChange>;
+ return static_cast<x11::Input::DeviceChange>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ChangeReason operator|(
+ x11::Input::ChangeReason l,
+ x11::Input::ChangeReason r) {
+ using T = std::underlying_type_t<x11::Input::ChangeReason>;
+ return static_cast<x11::Input::ChangeReason>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::ChangeReason operator&(
+ x11::Input::ChangeReason l,
+ x11::Input::ChangeReason r) {
+ using T = std::underlying_type_t<x11::Input::ChangeReason>;
+ return static_cast<x11::Input::ChangeReason>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::KeyEventFlags operator|(
+ x11::Input::KeyEventFlags l,
+ x11::Input::KeyEventFlags r) {
+ using T = std::underlying_type_t<x11::Input::KeyEventFlags>;
+ return static_cast<x11::Input::KeyEventFlags>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::KeyEventFlags operator&(
+ x11::Input::KeyEventFlags l,
+ x11::Input::KeyEventFlags r) {
+ using T = std::underlying_type_t<x11::Input::KeyEventFlags>;
+ return static_cast<x11::Input::KeyEventFlags>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::PointerEventFlags operator|(
+ x11::Input::PointerEventFlags l,
+ x11::Input::PointerEventFlags r) {
+ using T = std::underlying_type_t<x11::Input::PointerEventFlags>;
+ return static_cast<x11::Input::PointerEventFlags>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::PointerEventFlags operator&(
+ x11::Input::PointerEventFlags l,
+ x11::Input::PointerEventFlags r) {
+ using T = std::underlying_type_t<x11::Input::PointerEventFlags>;
+ return static_cast<x11::Input::PointerEventFlags>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::NotifyMode operator|(x11::Input::NotifyMode l,
+ x11::Input::NotifyMode r) {
+ using T = std::underlying_type_t<x11::Input::NotifyMode>;
+ return static_cast<x11::Input::NotifyMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::NotifyMode operator&(x11::Input::NotifyMode l,
+ x11::Input::NotifyMode r) {
+ using T = std::underlying_type_t<x11::Input::NotifyMode>;
+ return static_cast<x11::Input::NotifyMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::NotifyDetail operator|(
+ x11::Input::NotifyDetail l,
+ x11::Input::NotifyDetail r) {
+ using T = std::underlying_type_t<x11::Input::NotifyDetail>;
+ return static_cast<x11::Input::NotifyDetail>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::NotifyDetail operator&(
+ x11::Input::NotifyDetail l,
+ x11::Input::NotifyDetail r) {
+ using T = std::underlying_type_t<x11::Input::NotifyDetail>;
+ return static_cast<x11::Input::NotifyDetail>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::HierarchyMask operator|(
+ x11::Input::HierarchyMask l,
+ x11::Input::HierarchyMask r) {
+ using T = std::underlying_type_t<x11::Input::HierarchyMask>;
+ return static_cast<x11::Input::HierarchyMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::HierarchyMask operator&(
+ x11::Input::HierarchyMask l,
+ x11::Input::HierarchyMask r) {
+ using T = std::underlying_type_t<x11::Input::HierarchyMask>;
+ return static_cast<x11::Input::HierarchyMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::PropertyFlag operator|(
+ x11::Input::PropertyFlag l,
+ x11::Input::PropertyFlag r) {
+ using T = std::underlying_type_t<x11::Input::PropertyFlag>;
+ return static_cast<x11::Input::PropertyFlag>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::PropertyFlag operator&(
+ x11::Input::PropertyFlag l,
+ x11::Input::PropertyFlag r) {
+ using T = std::underlying_type_t<x11::Input::PropertyFlag>;
+ return static_cast<x11::Input::PropertyFlag>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::TouchEventFlags operator|(
+ x11::Input::TouchEventFlags l,
+ x11::Input::TouchEventFlags r) {
+ using T = std::underlying_type_t<x11::Input::TouchEventFlags>;
+ return static_cast<x11::Input::TouchEventFlags>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::TouchEventFlags operator&(
+ x11::Input::TouchEventFlags l,
+ x11::Input::TouchEventFlags r) {
+ using T = std::underlying_type_t<x11::Input::TouchEventFlags>;
+ return static_cast<x11::Input::TouchEventFlags>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::TouchOwnershipFlags operator|(
+ x11::Input::TouchOwnershipFlags l,
+ x11::Input::TouchOwnershipFlags r) {
+ using T = std::underlying_type_t<x11::Input::TouchOwnershipFlags>;
+ return static_cast<x11::Input::TouchOwnershipFlags>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::TouchOwnershipFlags operator&(
+ x11::Input::TouchOwnershipFlags l,
+ x11::Input::TouchOwnershipFlags r) {
+ using T = std::underlying_type_t<x11::Input::TouchOwnershipFlags>;
+ return static_cast<x11::Input::TouchOwnershipFlags>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::BarrierFlags operator|(
+ x11::Input::BarrierFlags l,
+ x11::Input::BarrierFlags r) {
+ using T = std::underlying_type_t<x11::Input::BarrierFlags>;
+ return static_cast<x11::Input::BarrierFlags>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::BarrierFlags operator&(
+ x11::Input::BarrierFlags l,
+ x11::Input::BarrierFlags r) {
+ using T = std::underlying_type_t<x11::Input::BarrierFlags>;
+ return static_cast<x11::Input::BarrierFlags>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XINPUT_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xkb.cc b/chromium/ui/gfx/x/generated_protos/xkb.cc
new file mode 100644
index 00000000000..ebe1f194827
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xkb.cc
@@ -0,0 +1,6879 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xkb.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Xkb::Xkb(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+std::string Xkb::KeyboardError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Xkb::KeyboardError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".value = " << static_cast<uint64_t>(value) << ", ";
+ ss_ << ".minorOpcode = " << static_cast<uint64_t>(minorOpcode) << ", ";
+ ss_ << ".majorOpcode = " << static_cast<uint64_t>(majorOpcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Xkb::KeyboardError>(Xkb::KeyboardError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& value = (*error_).value;
+ auto& minorOpcode = (*error_).minorOpcode;
+ auto& majorOpcode = (*error_).majorOpcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // value
+ Read(&value, &buf);
+
+ // minorOpcode
+ Read(&minorOpcode, &buf);
+
+ // majorOpcode
+ Read(&majorOpcode, &buf);
+
+ // pad0
+ Pad(&buf, 21);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::NewKeyboardNotifyEvent>(Xkb::NewKeyboardNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& oldDeviceID = (*event_).oldDeviceID;
+ auto& minKeyCode = (*event_).minKeyCode;
+ auto& maxKeyCode = (*event_).maxKeyCode;
+ auto& oldMinKeyCode = (*event_).oldMinKeyCode;
+ auto& oldMaxKeyCode = (*event_).oldMaxKeyCode;
+ auto& requestMajor = (*event_).requestMajor;
+ auto& requestMinor = (*event_).requestMinor;
+ auto& changed = (*event_).changed;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // oldDeviceID
+ Read(&oldDeviceID, &buf);
+
+ // minKeyCode
+ Read(&minKeyCode, &buf);
+
+ // maxKeyCode
+ Read(&maxKeyCode, &buf);
+
+ // oldMinKeyCode
+ Read(&oldMinKeyCode, &buf);
+
+ // oldMaxKeyCode
+ Read(&oldMaxKeyCode, &buf);
+
+ // requestMajor
+ Read(&requestMajor, &buf);
+
+ // requestMinor
+ Read(&requestMinor, &buf);
+
+ // changed
+ uint16_t tmp0;
+ Read(&tmp0, &buf);
+ changed = static_cast<Xkb::NKNDetail>(tmp0);
+
+ // pad0
+ Pad(&buf, 14);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::MapNotifyEvent>(Xkb::MapNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& ptrBtnActions = (*event_).ptrBtnActions;
+ auto& changed = (*event_).changed;
+ auto& minKeyCode = (*event_).minKeyCode;
+ auto& maxKeyCode = (*event_).maxKeyCode;
+ auto& firstType = (*event_).firstType;
+ auto& nTypes = (*event_).nTypes;
+ auto& firstKeySym = (*event_).firstKeySym;
+ auto& nKeySyms = (*event_).nKeySyms;
+ auto& firstKeyAct = (*event_).firstKeyAct;
+ auto& nKeyActs = (*event_).nKeyActs;
+ auto& firstKeyBehavior = (*event_).firstKeyBehavior;
+ auto& nKeyBehavior = (*event_).nKeyBehavior;
+ auto& firstKeyExplicit = (*event_).firstKeyExplicit;
+ auto& nKeyExplicit = (*event_).nKeyExplicit;
+ auto& firstModMapKey = (*event_).firstModMapKey;
+ auto& nModMapKeys = (*event_).nModMapKeys;
+ auto& firstVModMapKey = (*event_).firstVModMapKey;
+ auto& nVModMapKeys = (*event_).nVModMapKeys;
+ auto& virtualMods = (*event_).virtualMods;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // ptrBtnActions
+ Read(&ptrBtnActions, &buf);
+
+ // changed
+ uint16_t tmp1;
+ Read(&tmp1, &buf);
+ changed = static_cast<Xkb::MapPart>(tmp1);
+
+ // minKeyCode
+ Read(&minKeyCode, &buf);
+
+ // maxKeyCode
+ Read(&maxKeyCode, &buf);
+
+ // firstType
+ Read(&firstType, &buf);
+
+ // nTypes
+ Read(&nTypes, &buf);
+
+ // firstKeySym
+ Read(&firstKeySym, &buf);
+
+ // nKeySyms
+ Read(&nKeySyms, &buf);
+
+ // firstKeyAct
+ Read(&firstKeyAct, &buf);
+
+ // nKeyActs
+ Read(&nKeyActs, &buf);
+
+ // firstKeyBehavior
+ Read(&firstKeyBehavior, &buf);
+
+ // nKeyBehavior
+ Read(&nKeyBehavior, &buf);
+
+ // firstKeyExplicit
+ Read(&firstKeyExplicit, &buf);
+
+ // nKeyExplicit
+ Read(&nKeyExplicit, &buf);
+
+ // firstModMapKey
+ Read(&firstModMapKey, &buf);
+
+ // nModMapKeys
+ Read(&nModMapKeys, &buf);
+
+ // firstVModMapKey
+ Read(&firstVModMapKey, &buf);
+
+ // nVModMapKeys
+ Read(&nVModMapKeys, &buf);
+
+ // virtualMods
+ uint16_t tmp2;
+ Read(&tmp2, &buf);
+ virtualMods = static_cast<Xkb::VMod>(tmp2);
+
+ // pad0
+ Pad(&buf, 2);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::StateNotifyEvent>(Xkb::StateNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& mods = (*event_).mods;
+ auto& baseMods = (*event_).baseMods;
+ auto& latchedMods = (*event_).latchedMods;
+ auto& lockedMods = (*event_).lockedMods;
+ auto& group = (*event_).group;
+ auto& baseGroup = (*event_).baseGroup;
+ auto& latchedGroup = (*event_).latchedGroup;
+ auto& lockedGroup = (*event_).lockedGroup;
+ auto& compatState = (*event_).compatState;
+ auto& grabMods = (*event_).grabMods;
+ auto& compatGrabMods = (*event_).compatGrabMods;
+ auto& lookupMods = (*event_).lookupMods;
+ auto& compatLoockupMods = (*event_).compatLoockupMods;
+ auto& ptrBtnState = (*event_).ptrBtnState;
+ auto& changed = (*event_).changed;
+ auto& keycode = (*event_).keycode;
+ auto& eventType = (*event_).eventType;
+ auto& requestMajor = (*event_).requestMajor;
+ auto& requestMinor = (*event_).requestMinor;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // mods
+ uint8_t tmp3;
+ Read(&tmp3, &buf);
+ mods = static_cast<ModMask>(tmp3);
+
+ // baseMods
+ uint8_t tmp4;
+ Read(&tmp4, &buf);
+ baseMods = static_cast<ModMask>(tmp4);
+
+ // latchedMods
+ uint8_t tmp5;
+ Read(&tmp5, &buf);
+ latchedMods = static_cast<ModMask>(tmp5);
+
+ // lockedMods
+ uint8_t tmp6;
+ Read(&tmp6, &buf);
+ lockedMods = static_cast<ModMask>(tmp6);
+
+ // group
+ uint8_t tmp7;
+ Read(&tmp7, &buf);
+ group = static_cast<Xkb::Group>(tmp7);
+
+ // baseGroup
+ Read(&baseGroup, &buf);
+
+ // latchedGroup
+ Read(&latchedGroup, &buf);
+
+ // lockedGroup
+ uint8_t tmp8;
+ Read(&tmp8, &buf);
+ lockedGroup = static_cast<Xkb::Group>(tmp8);
+
+ // compatState
+ uint8_t tmp9;
+ Read(&tmp9, &buf);
+ compatState = static_cast<ModMask>(tmp9);
+
+ // grabMods
+ uint8_t tmp10;
+ Read(&tmp10, &buf);
+ grabMods = static_cast<ModMask>(tmp10);
+
+ // compatGrabMods
+ uint8_t tmp11;
+ Read(&tmp11, &buf);
+ compatGrabMods = static_cast<ModMask>(tmp11);
+
+ // lookupMods
+ uint8_t tmp12;
+ Read(&tmp12, &buf);
+ lookupMods = static_cast<ModMask>(tmp12);
+
+ // compatLoockupMods
+ uint8_t tmp13;
+ Read(&tmp13, &buf);
+ compatLoockupMods = static_cast<ModMask>(tmp13);
+
+ // ptrBtnState
+ uint16_t tmp14;
+ Read(&tmp14, &buf);
+ ptrBtnState = static_cast<KeyButMask>(tmp14);
+
+ // changed
+ uint16_t tmp15;
+ Read(&tmp15, &buf);
+ changed = static_cast<Xkb::StatePart>(tmp15);
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // eventType
+ Read(&eventType, &buf);
+
+ // requestMajor
+ Read(&requestMajor, &buf);
+
+ // requestMinor
+ Read(&requestMinor, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::ControlsNotifyEvent>(Xkb::ControlsNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& numGroups = (*event_).numGroups;
+ auto& changedControls = (*event_).changedControls;
+ auto& enabledControls = (*event_).enabledControls;
+ auto& enabledControlChanges = (*event_).enabledControlChanges;
+ auto& keycode = (*event_).keycode;
+ auto& eventType = (*event_).eventType;
+ auto& requestMajor = (*event_).requestMajor;
+ auto& requestMinor = (*event_).requestMinor;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // numGroups
+ Read(&numGroups, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // changedControls
+ uint32_t tmp16;
+ Read(&tmp16, &buf);
+ changedControls = static_cast<Xkb::Control>(tmp16);
+
+ // enabledControls
+ uint32_t tmp17;
+ Read(&tmp17, &buf);
+ enabledControls = static_cast<Xkb::BoolCtrl>(tmp17);
+
+ // enabledControlChanges
+ uint32_t tmp18;
+ Read(&tmp18, &buf);
+ enabledControlChanges = static_cast<Xkb::BoolCtrl>(tmp18);
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // eventType
+ Read(&eventType, &buf);
+
+ // requestMajor
+ Read(&requestMajor, &buf);
+
+ // requestMinor
+ Read(&requestMinor, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::IndicatorStateNotifyEvent>(
+ Xkb::IndicatorStateNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& state = (*event_).state;
+ auto& stateChanged = (*event_).stateChanged;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // state
+ Read(&state, &buf);
+
+ // stateChanged
+ Read(&stateChanged, &buf);
+
+ // pad1
+ Pad(&buf, 12);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::IndicatorMapNotifyEvent>(
+ Xkb::IndicatorMapNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& state = (*event_).state;
+ auto& mapChanged = (*event_).mapChanged;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // state
+ Read(&state, &buf);
+
+ // mapChanged
+ Read(&mapChanged, &buf);
+
+ // pad1
+ Pad(&buf, 12);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::NamesNotifyEvent>(Xkb::NamesNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& changed = (*event_).changed;
+ auto& firstType = (*event_).firstType;
+ auto& nTypes = (*event_).nTypes;
+ auto& firstLevelName = (*event_).firstLevelName;
+ auto& nLevelNames = (*event_).nLevelNames;
+ auto& nRadioGroups = (*event_).nRadioGroups;
+ auto& nKeyAliases = (*event_).nKeyAliases;
+ auto& changedGroupNames = (*event_).changedGroupNames;
+ auto& changedVirtualMods = (*event_).changedVirtualMods;
+ auto& firstKey = (*event_).firstKey;
+ auto& nKeys = (*event_).nKeys;
+ auto& changedIndicators = (*event_).changedIndicators;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // changed
+ uint16_t tmp19;
+ Read(&tmp19, &buf);
+ changed = static_cast<Xkb::NameDetail>(tmp19);
+
+ // firstType
+ Read(&firstType, &buf);
+
+ // nTypes
+ Read(&nTypes, &buf);
+
+ // firstLevelName
+ Read(&firstLevelName, &buf);
+
+ // nLevelNames
+ Read(&nLevelNames, &buf);
+
+ // pad1
+ Pad(&buf, 1);
+
+ // nRadioGroups
+ Read(&nRadioGroups, &buf);
+
+ // nKeyAliases
+ Read(&nKeyAliases, &buf);
+
+ // changedGroupNames
+ uint8_t tmp20;
+ Read(&tmp20, &buf);
+ changedGroupNames = static_cast<Xkb::SetOfGroup>(tmp20);
+
+ // changedVirtualMods
+ uint16_t tmp21;
+ Read(&tmp21, &buf);
+ changedVirtualMods = static_cast<Xkb::VMod>(tmp21);
+
+ // firstKey
+ Read(&firstKey, &buf);
+
+ // nKeys
+ Read(&nKeys, &buf);
+
+ // changedIndicators
+ Read(&changedIndicators, &buf);
+
+ // pad2
+ Pad(&buf, 4);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::CompatMapNotifyEvent>(Xkb::CompatMapNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& changedGroups = (*event_).changedGroups;
+ auto& firstSI = (*event_).firstSI;
+ auto& nSI = (*event_).nSI;
+ auto& nTotalSI = (*event_).nTotalSI;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // changedGroups
+ uint8_t tmp22;
+ Read(&tmp22, &buf);
+ changedGroups = static_cast<Xkb::SetOfGroup>(tmp22);
+
+ // firstSI
+ Read(&firstSI, &buf);
+
+ // nSI
+ Read(&nSI, &buf);
+
+ // nTotalSI
+ Read(&nTotalSI, &buf);
+
+ // pad0
+ Pad(&buf, 16);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::BellNotifyEvent>(Xkb::BellNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& bellClass = (*event_).bellClass;
+ auto& bellID = (*event_).bellID;
+ auto& percent = (*event_).percent;
+ auto& pitch = (*event_).pitch;
+ auto& duration = (*event_).duration;
+ auto& name = (*event_).name;
+ auto& window = (*event_).window;
+ auto& eventOnly = (*event_).eventOnly;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // bellClass
+ uint8_t tmp23;
+ Read(&tmp23, &buf);
+ bellClass = static_cast<Xkb::BellClassResult>(tmp23);
+
+ // bellID
+ Read(&bellID, &buf);
+
+ // percent
+ Read(&percent, &buf);
+
+ // pitch
+ Read(&pitch, &buf);
+
+ // duration
+ Read(&duration, &buf);
+
+ // name
+ Read(&name, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // eventOnly
+ Read(&eventOnly, &buf);
+
+ // pad0
+ Pad(&buf, 7);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::ActionMessageEvent>(Xkb::ActionMessageEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& keycode = (*event_).keycode;
+ auto& press = (*event_).press;
+ auto& keyEventFollows = (*event_).keyEventFollows;
+ auto& mods = (*event_).mods;
+ auto& group = (*event_).group;
+ auto& message = (*event_).message;
+ size_t message_len = message.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // press
+ Read(&press, &buf);
+
+ // keyEventFollows
+ Read(&keyEventFollows, &buf);
+
+ // mods
+ uint8_t tmp24;
+ Read(&tmp24, &buf);
+ mods = static_cast<ModMask>(tmp24);
+
+ // group
+ uint8_t tmp25;
+ Read(&tmp25, &buf);
+ group = static_cast<Xkb::Group>(tmp25);
+
+ // message
+ for (auto& message_elem : message) {
+ // message_elem
+ Read(&message_elem, &buf);
+ }
+
+ // pad0
+ Pad(&buf, 10);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::AccessXNotifyEvent>(Xkb::AccessXNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& keycode = (*event_).keycode;
+ auto& detailt = (*event_).detailt;
+ auto& slowKeysDelay = (*event_).slowKeysDelay;
+ auto& debounceDelay = (*event_).debounceDelay;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // detailt
+ uint16_t tmp26;
+ Read(&tmp26, &buf);
+ detailt = static_cast<Xkb::AXNDetail>(tmp26);
+
+ // slowKeysDelay
+ Read(&slowKeysDelay, &buf);
+
+ // debounceDelay
+ Read(&debounceDelay, &buf);
+
+ // pad0
+ Pad(&buf, 16);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xkb::ExtensionDeviceNotifyEvent>(
+ Xkb::ExtensionDeviceNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& xkbType = (*event_).xkbType;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& deviceID = (*event_).deviceID;
+ auto& reason = (*event_).reason;
+ auto& ledClass = (*event_).ledClass;
+ auto& ledID = (*event_).ledID;
+ auto& ledsDefined = (*event_).ledsDefined;
+ auto& ledState = (*event_).ledState;
+ auto& firstButton = (*event_).firstButton;
+ auto& nButtons = (*event_).nButtons;
+ auto& supported = (*event_).supported;
+ auto& unsupported = (*event_).unsupported;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // xkbType
+ Read(&xkbType, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // reason
+ uint16_t tmp27;
+ Read(&tmp27, &buf);
+ reason = static_cast<Xkb::XIFeature>(tmp27);
+
+ // ledClass
+ uint16_t tmp28;
+ Read(&tmp28, &buf);
+ ledClass = static_cast<Xkb::LedClassResult>(tmp28);
+
+ // ledID
+ Read(&ledID, &buf);
+
+ // ledsDefined
+ Read(&ledsDefined, &buf);
+
+ // ledState
+ Read(&ledState, &buf);
+
+ // firstButton
+ Read(&firstButton, &buf);
+
+ // nButtons
+ Read(&nButtons, &buf);
+
+ // supported
+ uint16_t tmp29;
+ Read(&tmp29, &buf);
+ supported = static_cast<Xkb::XIFeature>(tmp29);
+
+ // unsupported
+ uint16_t tmp30;
+ Read(&tmp30, &buf);
+ unsupported = static_cast<Xkb::XIFeature>(tmp30);
+
+ // pad1
+ Pad(&buf, 2);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+Future<Xkb::UseExtensionReply> Xkb::UseExtension(
+ const Xkb::UseExtensionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& wantedMajor = request.wantedMajor;
+ auto& wantedMinor = request.wantedMinor;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // wantedMajor
+ buf.Write(&wantedMajor);
+
+ // wantedMinor
+ buf.Write(&wantedMinor);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::UseExtensionReply>(
+ &buf, "Xkb::UseExtension", false);
+}
+
+Future<Xkb::UseExtensionReply> Xkb::UseExtension(const uint16_t& wantedMajor,
+ const uint16_t& wantedMinor) {
+ return Xkb::UseExtension(Xkb::UseExtensionRequest{wantedMajor, wantedMinor});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::UseExtensionReply> detail::ReadReply<
+ Xkb::UseExtensionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::UseExtensionReply>();
+
+ auto& supported = (*reply).supported;
+ auto& sequence = (*reply).sequence;
+ auto& serverMajor = (*reply).serverMajor;
+ auto& serverMinor = (*reply).serverMinor;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // supported
+ Read(&supported, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // serverMajor
+ Read(&serverMajor, &buf);
+
+ // serverMinor
+ Read(&serverMinor, &buf);
+
+ // pad0
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xkb::SelectEvents(const Xkb::SelectEventsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& affectWhich = request.affectWhich;
+ auto& clear = request.clear;
+ auto& selectAll = request.selectAll;
+ auto& affectMap = request.affectMap;
+ auto& map = request.map;
+ auto& details = request;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // affectWhich
+ uint16_t tmp31;
+ tmp31 = static_cast<uint16_t>(affectWhich);
+ buf.Write(&tmp31);
+
+ // clear
+ uint16_t tmp32;
+ tmp32 = static_cast<uint16_t>(clear);
+ buf.Write(&tmp32);
+
+ // selectAll
+ uint16_t tmp33;
+ tmp33 = static_cast<uint16_t>(selectAll);
+ buf.Write(&tmp33);
+
+ // affectMap
+ uint16_t tmp34;
+ tmp34 = static_cast<uint16_t>(affectMap);
+ buf.Write(&tmp34);
+
+ // map
+ uint16_t tmp35;
+ tmp35 = static_cast<uint16_t>(map);
+ buf.Write(&tmp35);
+
+ // details
+ auto details_expr =
+ BitAnd(affectWhich, BitAnd(BitNot(clear), BitNot(selectAll)));
+ if (CaseAnd(details_expr, EventType::NewKeyboardNotify)) {
+ auto& affectNewKeyboard = *details.affectNewKeyboard;
+ auto& newKeyboardDetails = *details.newKeyboardDetails;
+
+ // affectNewKeyboard
+ uint16_t tmp36;
+ tmp36 = static_cast<uint16_t>(affectNewKeyboard);
+ buf.Write(&tmp36);
+
+ // newKeyboardDetails
+ uint16_t tmp37;
+ tmp37 = static_cast<uint16_t>(newKeyboardDetails);
+ buf.Write(&tmp37);
+ }
+ if (CaseAnd(details_expr, EventType::StateNotify)) {
+ auto& affectState = *details.affectState;
+ auto& stateDetails = *details.stateDetails;
+
+ // affectState
+ uint16_t tmp38;
+ tmp38 = static_cast<uint16_t>(affectState);
+ buf.Write(&tmp38);
+
+ // stateDetails
+ uint16_t tmp39;
+ tmp39 = static_cast<uint16_t>(stateDetails);
+ buf.Write(&tmp39);
+ }
+ if (CaseAnd(details_expr, EventType::ControlsNotify)) {
+ auto& affectCtrls = *details.affectCtrls;
+ auto& ctrlDetails = *details.ctrlDetails;
+
+ // affectCtrls
+ uint32_t tmp40;
+ tmp40 = static_cast<uint32_t>(affectCtrls);
+ buf.Write(&tmp40);
+
+ // ctrlDetails
+ uint32_t tmp41;
+ tmp41 = static_cast<uint32_t>(ctrlDetails);
+ buf.Write(&tmp41);
+ }
+ if (CaseAnd(details_expr, EventType::IndicatorStateNotify)) {
+ auto& affectIndicatorState = *details.affectIndicatorState;
+ auto& indicatorStateDetails = *details.indicatorStateDetails;
+
+ // affectIndicatorState
+ buf.Write(&affectIndicatorState);
+
+ // indicatorStateDetails
+ buf.Write(&indicatorStateDetails);
+ }
+ if (CaseAnd(details_expr, EventType::IndicatorMapNotify)) {
+ auto& affectIndicatorMap = *details.affectIndicatorMap;
+ auto& indicatorMapDetails = *details.indicatorMapDetails;
+
+ // affectIndicatorMap
+ buf.Write(&affectIndicatorMap);
+
+ // indicatorMapDetails
+ buf.Write(&indicatorMapDetails);
+ }
+ if (CaseAnd(details_expr, EventType::NamesNotify)) {
+ auto& affectNames = *details.affectNames;
+ auto& namesDetails = *details.namesDetails;
+
+ // affectNames
+ uint16_t tmp42;
+ tmp42 = static_cast<uint16_t>(affectNames);
+ buf.Write(&tmp42);
+
+ // namesDetails
+ uint16_t tmp43;
+ tmp43 = static_cast<uint16_t>(namesDetails);
+ buf.Write(&tmp43);
+ }
+ if (CaseAnd(details_expr, EventType::CompatMapNotify)) {
+ auto& affectCompat = *details.affectCompat;
+ auto& compatDetails = *details.compatDetails;
+
+ // affectCompat
+ uint8_t tmp44;
+ tmp44 = static_cast<uint8_t>(affectCompat);
+ buf.Write(&tmp44);
+
+ // compatDetails
+ uint8_t tmp45;
+ tmp45 = static_cast<uint8_t>(compatDetails);
+ buf.Write(&tmp45);
+ }
+ if (CaseAnd(details_expr, EventType::BellNotify)) {
+ auto& affectBell = *details.affectBell;
+ auto& bellDetails = *details.bellDetails;
+
+ // affectBell
+ buf.Write(&affectBell);
+
+ // bellDetails
+ buf.Write(&bellDetails);
+ }
+ if (CaseAnd(details_expr, EventType::ActionMessage)) {
+ auto& affectMsgDetails = *details.affectMsgDetails;
+ auto& msgDetails = *details.msgDetails;
+
+ // affectMsgDetails
+ buf.Write(&affectMsgDetails);
+
+ // msgDetails
+ buf.Write(&msgDetails);
+ }
+ if (CaseAnd(details_expr, EventType::AccessXNotify)) {
+ auto& affectAccessX = *details.affectAccessX;
+ auto& accessXDetails = *details.accessXDetails;
+
+ // affectAccessX
+ uint16_t tmp46;
+ tmp46 = static_cast<uint16_t>(affectAccessX);
+ buf.Write(&tmp46);
+
+ // accessXDetails
+ uint16_t tmp47;
+ tmp47 = static_cast<uint16_t>(accessXDetails);
+ buf.Write(&tmp47);
+ }
+ if (CaseAnd(details_expr, EventType::ExtensionDeviceNotify)) {
+ auto& affectExtDev = *details.affectExtDev;
+ auto& extdevDetails = *details.extdevDetails;
+
+ // affectExtDev
+ uint16_t tmp48;
+ tmp48 = static_cast<uint16_t>(affectExtDev);
+ buf.Write(&tmp48);
+
+ // extdevDetails
+ uint16_t tmp49;
+ tmp49 = static_cast<uint16_t>(extdevDetails);
+ buf.Write(&tmp49);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xkb::SelectEvents", false);
+}
+
+Future<void> Xkb::SelectEvents(
+ const DeviceSpec& deviceSpec,
+ const EventType& affectWhich,
+ const EventType& clear,
+ const EventType& selectAll,
+ const MapPart& affectMap,
+ const MapPart& map,
+ const base::Optional<NKNDetail>& affectNewKeyboard,
+ const base::Optional<NKNDetail>& newKeyboardDetails,
+ const base::Optional<StatePart>& affectState,
+ const base::Optional<StatePart>& stateDetails,
+ const base::Optional<Control>& affectCtrls,
+ const base::Optional<Control>& ctrlDetails,
+ const base::Optional<uint32_t>& affectIndicatorState,
+ const base::Optional<uint32_t>& indicatorStateDetails,
+ const base::Optional<uint32_t>& affectIndicatorMap,
+ const base::Optional<uint32_t>& indicatorMapDetails,
+ const base::Optional<NameDetail>& affectNames,
+ const base::Optional<NameDetail>& namesDetails,
+ const base::Optional<CMDetail>& affectCompat,
+ const base::Optional<CMDetail>& compatDetails,
+ const base::Optional<uint8_t>& affectBell,
+ const base::Optional<uint8_t>& bellDetails,
+ const base::Optional<uint8_t>& affectMsgDetails,
+ const base::Optional<uint8_t>& msgDetails,
+ const base::Optional<AXNDetail>& affectAccessX,
+ const base::Optional<AXNDetail>& accessXDetails,
+ const base::Optional<XIFeature>& affectExtDev,
+ const base::Optional<XIFeature>& extdevDetails) {
+ return Xkb::SelectEvents(Xkb::SelectEventsRequest{deviceSpec,
+ affectWhich,
+ clear,
+ selectAll,
+ affectMap,
+ map,
+ affectNewKeyboard,
+ newKeyboardDetails,
+ affectState,
+ stateDetails,
+ affectCtrls,
+ ctrlDetails,
+ affectIndicatorState,
+ indicatorStateDetails,
+ affectIndicatorMap,
+ indicatorMapDetails,
+ affectNames,
+ namesDetails,
+ affectCompat,
+ compatDetails,
+ affectBell,
+ bellDetails,
+ affectMsgDetails,
+ msgDetails,
+ affectAccessX,
+ accessXDetails,
+ affectExtDev,
+ extdevDetails});
+}
+
+Future<void> Xkb::Bell(const Xkb::BellRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& bellClass = request.bellClass;
+ auto& bellID = request.bellID;
+ auto& percent = request.percent;
+ auto& forceSound = request.forceSound;
+ auto& eventOnly = request.eventOnly;
+ auto& pitch = request.pitch;
+ auto& duration = request.duration;
+ auto& name = request.name;
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // bellClass
+ buf.Write(&bellClass);
+
+ // bellID
+ buf.Write(&bellID);
+
+ // percent
+ buf.Write(&percent);
+
+ // forceSound
+ buf.Write(&forceSound);
+
+ // eventOnly
+ buf.Write(&eventOnly);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // pitch
+ buf.Write(&pitch);
+
+ // duration
+ buf.Write(&duration);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // name
+ buf.Write(&name);
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xkb::Bell", false);
+}
+
+Future<void> Xkb::Bell(const DeviceSpec& deviceSpec,
+ const BellClassSpec& bellClass,
+ const IDSpec& bellID,
+ const int8_t& percent,
+ const uint8_t& forceSound,
+ const uint8_t& eventOnly,
+ const int16_t& pitch,
+ const int16_t& duration,
+ const Atom& name,
+ const Window& window) {
+ return Xkb::Bell(Xkb::BellRequest{deviceSpec, bellClass, bellID, percent,
+ forceSound, eventOnly, pitch, duration,
+ name, window});
+}
+
+Future<Xkb::GetStateReply> Xkb::GetState(const Xkb::GetStateRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::GetStateReply>(&buf, "Xkb::GetState",
+ false);
+}
+
+Future<Xkb::GetStateReply> Xkb::GetState(const DeviceSpec& deviceSpec) {
+ return Xkb::GetState(Xkb::GetStateRequest{deviceSpec});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::GetStateReply> detail::ReadReply<Xkb::GetStateReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::GetStateReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ auto& mods = (*reply).mods;
+ auto& baseMods = (*reply).baseMods;
+ auto& latchedMods = (*reply).latchedMods;
+ auto& lockedMods = (*reply).lockedMods;
+ auto& group = (*reply).group;
+ auto& lockedGroup = (*reply).lockedGroup;
+ auto& baseGroup = (*reply).baseGroup;
+ auto& latchedGroup = (*reply).latchedGroup;
+ auto& compatState = (*reply).compatState;
+ auto& grabMods = (*reply).grabMods;
+ auto& compatGrabMods = (*reply).compatGrabMods;
+ auto& lookupMods = (*reply).lookupMods;
+ auto& compatLookupMods = (*reply).compatLookupMods;
+ auto& ptrBtnState = (*reply).ptrBtnState;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // mods
+ uint8_t tmp50;
+ Read(&tmp50, &buf);
+ mods = static_cast<ModMask>(tmp50);
+
+ // baseMods
+ uint8_t tmp51;
+ Read(&tmp51, &buf);
+ baseMods = static_cast<ModMask>(tmp51);
+
+ // latchedMods
+ uint8_t tmp52;
+ Read(&tmp52, &buf);
+ latchedMods = static_cast<ModMask>(tmp52);
+
+ // lockedMods
+ uint8_t tmp53;
+ Read(&tmp53, &buf);
+ lockedMods = static_cast<ModMask>(tmp53);
+
+ // group
+ uint8_t tmp54;
+ Read(&tmp54, &buf);
+ group = static_cast<Xkb::Group>(tmp54);
+
+ // lockedGroup
+ uint8_t tmp55;
+ Read(&tmp55, &buf);
+ lockedGroup = static_cast<Xkb::Group>(tmp55);
+
+ // baseGroup
+ Read(&baseGroup, &buf);
+
+ // latchedGroup
+ Read(&latchedGroup, &buf);
+
+ // compatState
+ uint8_t tmp56;
+ Read(&tmp56, &buf);
+ compatState = static_cast<ModMask>(tmp56);
+
+ // grabMods
+ uint8_t tmp57;
+ Read(&tmp57, &buf);
+ grabMods = static_cast<ModMask>(tmp57);
+
+ // compatGrabMods
+ uint8_t tmp58;
+ Read(&tmp58, &buf);
+ compatGrabMods = static_cast<ModMask>(tmp58);
+
+ // lookupMods
+ uint8_t tmp59;
+ Read(&tmp59, &buf);
+ lookupMods = static_cast<ModMask>(tmp59);
+
+ // compatLookupMods
+ uint8_t tmp60;
+ Read(&tmp60, &buf);
+ compatLookupMods = static_cast<ModMask>(tmp60);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // ptrBtnState
+ uint16_t tmp61;
+ Read(&tmp61, &buf);
+ ptrBtnState = static_cast<KeyButMask>(tmp61);
+
+ // pad1
+ Pad(&buf, 6);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xkb::LatchLockState(const Xkb::LatchLockStateRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& affectModLocks = request.affectModLocks;
+ auto& modLocks = request.modLocks;
+ auto& lockGroup = request.lockGroup;
+ auto& groupLock = request.groupLock;
+ auto& affectModLatches = request.affectModLatches;
+ auto& latchGroup = request.latchGroup;
+ auto& groupLatch = request.groupLatch;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // affectModLocks
+ uint8_t tmp62;
+ tmp62 = static_cast<uint8_t>(affectModLocks);
+ buf.Write(&tmp62);
+
+ // modLocks
+ uint8_t tmp63;
+ tmp63 = static_cast<uint8_t>(modLocks);
+ buf.Write(&tmp63);
+
+ // lockGroup
+ buf.Write(&lockGroup);
+
+ // groupLock
+ uint8_t tmp64;
+ tmp64 = static_cast<uint8_t>(groupLock);
+ buf.Write(&tmp64);
+
+ // affectModLatches
+ uint8_t tmp65;
+ tmp65 = static_cast<uint8_t>(affectModLatches);
+ buf.Write(&tmp65);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // pad1
+ Pad(&buf, 1);
+
+ // latchGroup
+ buf.Write(&latchGroup);
+
+ // groupLatch
+ buf.Write(&groupLatch);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xkb::LatchLockState", false);
+}
+
+Future<void> Xkb::LatchLockState(const DeviceSpec& deviceSpec,
+ const ModMask& affectModLocks,
+ const ModMask& modLocks,
+ const uint8_t& lockGroup,
+ const Group& groupLock,
+ const ModMask& affectModLatches,
+ const uint8_t& latchGroup,
+ const uint16_t& groupLatch) {
+ return Xkb::LatchLockState(Xkb::LatchLockStateRequest{
+ deviceSpec, affectModLocks, modLocks, lockGroup, groupLock,
+ affectModLatches, latchGroup, groupLatch});
+}
+
+Future<Xkb::GetControlsReply> Xkb::GetControls(
+ const Xkb::GetControlsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::GetControlsReply>(
+ &buf, "Xkb::GetControls", false);
+}
+
+Future<Xkb::GetControlsReply> Xkb::GetControls(const DeviceSpec& deviceSpec) {
+ return Xkb::GetControls(Xkb::GetControlsRequest{deviceSpec});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::GetControlsReply> detail::ReadReply<Xkb::GetControlsReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::GetControlsReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ auto& mouseKeysDfltBtn = (*reply).mouseKeysDfltBtn;
+ auto& numGroups = (*reply).numGroups;
+ auto& groupsWrap = (*reply).groupsWrap;
+ auto& internalModsMask = (*reply).internalModsMask;
+ auto& ignoreLockModsMask = (*reply).ignoreLockModsMask;
+ auto& internalModsRealMods = (*reply).internalModsRealMods;
+ auto& ignoreLockModsRealMods = (*reply).ignoreLockModsRealMods;
+ auto& internalModsVmods = (*reply).internalModsVmods;
+ auto& ignoreLockModsVmods = (*reply).ignoreLockModsVmods;
+ auto& repeatDelay = (*reply).repeatDelay;
+ auto& repeatInterval = (*reply).repeatInterval;
+ auto& slowKeysDelay = (*reply).slowKeysDelay;
+ auto& debounceDelay = (*reply).debounceDelay;
+ auto& mouseKeysDelay = (*reply).mouseKeysDelay;
+ auto& mouseKeysInterval = (*reply).mouseKeysInterval;
+ auto& mouseKeysTimeToMax = (*reply).mouseKeysTimeToMax;
+ auto& mouseKeysMaxSpeed = (*reply).mouseKeysMaxSpeed;
+ auto& mouseKeysCurve = (*reply).mouseKeysCurve;
+ auto& accessXOption = (*reply).accessXOption;
+ auto& accessXTimeout = (*reply).accessXTimeout;
+ auto& accessXTimeoutOptionsMask = (*reply).accessXTimeoutOptionsMask;
+ auto& accessXTimeoutOptionsValues = (*reply).accessXTimeoutOptionsValues;
+ auto& accessXTimeoutMask = (*reply).accessXTimeoutMask;
+ auto& accessXTimeoutValues = (*reply).accessXTimeoutValues;
+ auto& enabledControls = (*reply).enabledControls;
+ auto& perKeyRepeat = (*reply).perKeyRepeat;
+ size_t perKeyRepeat_len = perKeyRepeat.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // mouseKeysDfltBtn
+ Read(&mouseKeysDfltBtn, &buf);
+
+ // numGroups
+ Read(&numGroups, &buf);
+
+ // groupsWrap
+ Read(&groupsWrap, &buf);
+
+ // internalModsMask
+ uint8_t tmp66;
+ Read(&tmp66, &buf);
+ internalModsMask = static_cast<ModMask>(tmp66);
+
+ // ignoreLockModsMask
+ uint8_t tmp67;
+ Read(&tmp67, &buf);
+ ignoreLockModsMask = static_cast<ModMask>(tmp67);
+
+ // internalModsRealMods
+ uint8_t tmp68;
+ Read(&tmp68, &buf);
+ internalModsRealMods = static_cast<ModMask>(tmp68);
+
+ // ignoreLockModsRealMods
+ uint8_t tmp69;
+ Read(&tmp69, &buf);
+ ignoreLockModsRealMods = static_cast<ModMask>(tmp69);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // internalModsVmods
+ uint16_t tmp70;
+ Read(&tmp70, &buf);
+ internalModsVmods = static_cast<Xkb::VMod>(tmp70);
+
+ // ignoreLockModsVmods
+ uint16_t tmp71;
+ Read(&tmp71, &buf);
+ ignoreLockModsVmods = static_cast<Xkb::VMod>(tmp71);
+
+ // repeatDelay
+ Read(&repeatDelay, &buf);
+
+ // repeatInterval
+ Read(&repeatInterval, &buf);
+
+ // slowKeysDelay
+ Read(&slowKeysDelay, &buf);
+
+ // debounceDelay
+ Read(&debounceDelay, &buf);
+
+ // mouseKeysDelay
+ Read(&mouseKeysDelay, &buf);
+
+ // mouseKeysInterval
+ Read(&mouseKeysInterval, &buf);
+
+ // mouseKeysTimeToMax
+ Read(&mouseKeysTimeToMax, &buf);
+
+ // mouseKeysMaxSpeed
+ Read(&mouseKeysMaxSpeed, &buf);
+
+ // mouseKeysCurve
+ Read(&mouseKeysCurve, &buf);
+
+ // accessXOption
+ uint16_t tmp72;
+ Read(&tmp72, &buf);
+ accessXOption = static_cast<Xkb::AXOption>(tmp72);
+
+ // accessXTimeout
+ Read(&accessXTimeout, &buf);
+
+ // accessXTimeoutOptionsMask
+ uint16_t tmp73;
+ Read(&tmp73, &buf);
+ accessXTimeoutOptionsMask = static_cast<Xkb::AXOption>(tmp73);
+
+ // accessXTimeoutOptionsValues
+ uint16_t tmp74;
+ Read(&tmp74, &buf);
+ accessXTimeoutOptionsValues = static_cast<Xkb::AXOption>(tmp74);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // accessXTimeoutMask
+ uint32_t tmp75;
+ Read(&tmp75, &buf);
+ accessXTimeoutMask = static_cast<Xkb::BoolCtrl>(tmp75);
+
+ // accessXTimeoutValues
+ uint32_t tmp76;
+ Read(&tmp76, &buf);
+ accessXTimeoutValues = static_cast<Xkb::BoolCtrl>(tmp76);
+
+ // enabledControls
+ uint32_t tmp77;
+ Read(&tmp77, &buf);
+ enabledControls = static_cast<Xkb::BoolCtrl>(tmp77);
+
+ // perKeyRepeat
+ for (auto& perKeyRepeat_elem : perKeyRepeat) {
+ // perKeyRepeat_elem
+ Read(&perKeyRepeat_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xkb::SetControls(const Xkb::SetControlsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& affectInternalRealMods = request.affectInternalRealMods;
+ auto& internalRealMods = request.internalRealMods;
+ auto& affectIgnoreLockRealMods = request.affectIgnoreLockRealMods;
+ auto& ignoreLockRealMods = request.ignoreLockRealMods;
+ auto& affectInternalVirtualMods = request.affectInternalVirtualMods;
+ auto& internalVirtualMods = request.internalVirtualMods;
+ auto& affectIgnoreLockVirtualMods = request.affectIgnoreLockVirtualMods;
+ auto& ignoreLockVirtualMods = request.ignoreLockVirtualMods;
+ auto& mouseKeysDfltBtn = request.mouseKeysDfltBtn;
+ auto& groupsWrap = request.groupsWrap;
+ auto& accessXOptions = request.accessXOptions;
+ auto& affectEnabledControls = request.affectEnabledControls;
+ auto& enabledControls = request.enabledControls;
+ auto& changeControls = request.changeControls;
+ auto& repeatDelay = request.repeatDelay;
+ auto& repeatInterval = request.repeatInterval;
+ auto& slowKeysDelay = request.slowKeysDelay;
+ auto& debounceDelay = request.debounceDelay;
+ auto& mouseKeysDelay = request.mouseKeysDelay;
+ auto& mouseKeysInterval = request.mouseKeysInterval;
+ auto& mouseKeysTimeToMax = request.mouseKeysTimeToMax;
+ auto& mouseKeysMaxSpeed = request.mouseKeysMaxSpeed;
+ auto& mouseKeysCurve = request.mouseKeysCurve;
+ auto& accessXTimeout = request.accessXTimeout;
+ auto& accessXTimeoutMask = request.accessXTimeoutMask;
+ auto& accessXTimeoutValues = request.accessXTimeoutValues;
+ auto& accessXTimeoutOptionsMask = request.accessXTimeoutOptionsMask;
+ auto& accessXTimeoutOptionsValues = request.accessXTimeoutOptionsValues;
+ auto& perKeyRepeat = request.perKeyRepeat;
+ size_t perKeyRepeat_len = perKeyRepeat.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // affectInternalRealMods
+ uint8_t tmp78;
+ tmp78 = static_cast<uint8_t>(affectInternalRealMods);
+ buf.Write(&tmp78);
+
+ // internalRealMods
+ uint8_t tmp79;
+ tmp79 = static_cast<uint8_t>(internalRealMods);
+ buf.Write(&tmp79);
+
+ // affectIgnoreLockRealMods
+ uint8_t tmp80;
+ tmp80 = static_cast<uint8_t>(affectIgnoreLockRealMods);
+ buf.Write(&tmp80);
+
+ // ignoreLockRealMods
+ uint8_t tmp81;
+ tmp81 = static_cast<uint8_t>(ignoreLockRealMods);
+ buf.Write(&tmp81);
+
+ // affectInternalVirtualMods
+ uint16_t tmp82;
+ tmp82 = static_cast<uint16_t>(affectInternalVirtualMods);
+ buf.Write(&tmp82);
+
+ // internalVirtualMods
+ uint16_t tmp83;
+ tmp83 = static_cast<uint16_t>(internalVirtualMods);
+ buf.Write(&tmp83);
+
+ // affectIgnoreLockVirtualMods
+ uint16_t tmp84;
+ tmp84 = static_cast<uint16_t>(affectIgnoreLockVirtualMods);
+ buf.Write(&tmp84);
+
+ // ignoreLockVirtualMods
+ uint16_t tmp85;
+ tmp85 = static_cast<uint16_t>(ignoreLockVirtualMods);
+ buf.Write(&tmp85);
+
+ // mouseKeysDfltBtn
+ buf.Write(&mouseKeysDfltBtn);
+
+ // groupsWrap
+ buf.Write(&groupsWrap);
+
+ // accessXOptions
+ uint16_t tmp86;
+ tmp86 = static_cast<uint16_t>(accessXOptions);
+ buf.Write(&tmp86);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // affectEnabledControls
+ uint32_t tmp87;
+ tmp87 = static_cast<uint32_t>(affectEnabledControls);
+ buf.Write(&tmp87);
+
+ // enabledControls
+ uint32_t tmp88;
+ tmp88 = static_cast<uint32_t>(enabledControls);
+ buf.Write(&tmp88);
+
+ // changeControls
+ uint32_t tmp89;
+ tmp89 = static_cast<uint32_t>(changeControls);
+ buf.Write(&tmp89);
+
+ // repeatDelay
+ buf.Write(&repeatDelay);
+
+ // repeatInterval
+ buf.Write(&repeatInterval);
+
+ // slowKeysDelay
+ buf.Write(&slowKeysDelay);
+
+ // debounceDelay
+ buf.Write(&debounceDelay);
+
+ // mouseKeysDelay
+ buf.Write(&mouseKeysDelay);
+
+ // mouseKeysInterval
+ buf.Write(&mouseKeysInterval);
+
+ // mouseKeysTimeToMax
+ buf.Write(&mouseKeysTimeToMax);
+
+ // mouseKeysMaxSpeed
+ buf.Write(&mouseKeysMaxSpeed);
+
+ // mouseKeysCurve
+ buf.Write(&mouseKeysCurve);
+
+ // accessXTimeout
+ buf.Write(&accessXTimeout);
+
+ // accessXTimeoutMask
+ uint32_t tmp90;
+ tmp90 = static_cast<uint32_t>(accessXTimeoutMask);
+ buf.Write(&tmp90);
+
+ // accessXTimeoutValues
+ uint32_t tmp91;
+ tmp91 = static_cast<uint32_t>(accessXTimeoutValues);
+ buf.Write(&tmp91);
+
+ // accessXTimeoutOptionsMask
+ uint16_t tmp92;
+ tmp92 = static_cast<uint16_t>(accessXTimeoutOptionsMask);
+ buf.Write(&tmp92);
+
+ // accessXTimeoutOptionsValues
+ uint16_t tmp93;
+ tmp93 = static_cast<uint16_t>(accessXTimeoutOptionsValues);
+ buf.Write(&tmp93);
+
+ // perKeyRepeat
+ for (auto& perKeyRepeat_elem : perKeyRepeat) {
+ // perKeyRepeat_elem
+ buf.Write(&perKeyRepeat_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xkb::SetControls", false);
+}
+
+Future<void> Xkb::SetControls(const DeviceSpec& deviceSpec,
+ const ModMask& affectInternalRealMods,
+ const ModMask& internalRealMods,
+ const ModMask& affectIgnoreLockRealMods,
+ const ModMask& ignoreLockRealMods,
+ const VMod& affectInternalVirtualMods,
+ const VMod& internalVirtualMods,
+ const VMod& affectIgnoreLockVirtualMods,
+ const VMod& ignoreLockVirtualMods,
+ const uint8_t& mouseKeysDfltBtn,
+ const uint8_t& groupsWrap,
+ const AXOption& accessXOptions,
+ const BoolCtrl& affectEnabledControls,
+ const BoolCtrl& enabledControls,
+ const Control& changeControls,
+ const uint16_t& repeatDelay,
+ const uint16_t& repeatInterval,
+ const uint16_t& slowKeysDelay,
+ const uint16_t& debounceDelay,
+ const uint16_t& mouseKeysDelay,
+ const uint16_t& mouseKeysInterval,
+ const uint16_t& mouseKeysTimeToMax,
+ const uint16_t& mouseKeysMaxSpeed,
+ const int16_t& mouseKeysCurve,
+ const uint16_t& accessXTimeout,
+ const BoolCtrl& accessXTimeoutMask,
+ const BoolCtrl& accessXTimeoutValues,
+ const AXOption& accessXTimeoutOptionsMask,
+ const AXOption& accessXTimeoutOptionsValues,
+ const std::array<uint8_t, 32>& perKeyRepeat) {
+ return Xkb::SetControls(Xkb::SetControlsRequest{deviceSpec,
+ affectInternalRealMods,
+ internalRealMods,
+ affectIgnoreLockRealMods,
+ ignoreLockRealMods,
+ affectInternalVirtualMods,
+ internalVirtualMods,
+ affectIgnoreLockVirtualMods,
+ ignoreLockVirtualMods,
+ mouseKeysDfltBtn,
+ groupsWrap,
+ accessXOptions,
+ affectEnabledControls,
+ enabledControls,
+ changeControls,
+ repeatDelay,
+ repeatInterval,
+ slowKeysDelay,
+ debounceDelay,
+ mouseKeysDelay,
+ mouseKeysInterval,
+ mouseKeysTimeToMax,
+ mouseKeysMaxSpeed,
+ mouseKeysCurve,
+ accessXTimeout,
+ accessXTimeoutMask,
+ accessXTimeoutValues,
+ accessXTimeoutOptionsMask,
+ accessXTimeoutOptionsValues,
+ perKeyRepeat});
+}
+
+Future<Xkb::GetMapReply> Xkb::GetMap(const Xkb::GetMapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& full = request.full;
+ auto& partial = request.partial;
+ auto& firstType = request.firstType;
+ auto& nTypes = request.nTypes;
+ auto& firstKeySym = request.firstKeySym;
+ auto& nKeySyms = request.nKeySyms;
+ auto& firstKeyAction = request.firstKeyAction;
+ auto& nKeyActions = request.nKeyActions;
+ auto& firstKeyBehavior = request.firstKeyBehavior;
+ auto& nKeyBehaviors = request.nKeyBehaviors;
+ auto& virtualMods = request.virtualMods;
+ auto& firstKeyExplicit = request.firstKeyExplicit;
+ auto& nKeyExplicit = request.nKeyExplicit;
+ auto& firstModMapKey = request.firstModMapKey;
+ auto& nModMapKeys = request.nModMapKeys;
+ auto& firstVModMapKey = request.firstVModMapKey;
+ auto& nVModMapKeys = request.nVModMapKeys;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // full
+ uint16_t tmp94;
+ tmp94 = static_cast<uint16_t>(full);
+ buf.Write(&tmp94);
+
+ // partial
+ uint16_t tmp95;
+ tmp95 = static_cast<uint16_t>(partial);
+ buf.Write(&tmp95);
+
+ // firstType
+ buf.Write(&firstType);
+
+ // nTypes
+ buf.Write(&nTypes);
+
+ // firstKeySym
+ buf.Write(&firstKeySym);
+
+ // nKeySyms
+ buf.Write(&nKeySyms);
+
+ // firstKeyAction
+ buf.Write(&firstKeyAction);
+
+ // nKeyActions
+ buf.Write(&nKeyActions);
+
+ // firstKeyBehavior
+ buf.Write(&firstKeyBehavior);
+
+ // nKeyBehaviors
+ buf.Write(&nKeyBehaviors);
+
+ // virtualMods
+ uint16_t tmp96;
+ tmp96 = static_cast<uint16_t>(virtualMods);
+ buf.Write(&tmp96);
+
+ // firstKeyExplicit
+ buf.Write(&firstKeyExplicit);
+
+ // nKeyExplicit
+ buf.Write(&nKeyExplicit);
+
+ // firstModMapKey
+ buf.Write(&firstModMapKey);
+
+ // nModMapKeys
+ buf.Write(&nModMapKeys);
+
+ // firstVModMapKey
+ buf.Write(&firstVModMapKey);
+
+ // nVModMapKeys
+ buf.Write(&nVModMapKeys);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::GetMapReply>(&buf, "Xkb::GetMap", false);
+}
+
+Future<Xkb::GetMapReply> Xkb::GetMap(const DeviceSpec& deviceSpec,
+ const MapPart& full,
+ const MapPart& partial,
+ const uint8_t& firstType,
+ const uint8_t& nTypes,
+ const KeyCode& firstKeySym,
+ const uint8_t& nKeySyms,
+ const KeyCode& firstKeyAction,
+ const uint8_t& nKeyActions,
+ const KeyCode& firstKeyBehavior,
+ const uint8_t& nKeyBehaviors,
+ const VMod& virtualMods,
+ const KeyCode& firstKeyExplicit,
+ const uint8_t& nKeyExplicit,
+ const KeyCode& firstModMapKey,
+ const uint8_t& nModMapKeys,
+ const KeyCode& firstVModMapKey,
+ const uint8_t& nVModMapKeys) {
+ return Xkb::GetMap(Xkb::GetMapRequest{
+ deviceSpec, full, partial, firstType, nTypes, firstKeySym, nKeySyms,
+ firstKeyAction, nKeyActions, firstKeyBehavior, nKeyBehaviors, virtualMods,
+ firstKeyExplicit, nKeyExplicit, firstModMapKey, nModMapKeys,
+ firstVModMapKey, nVModMapKeys});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::GetMapReply> detail::ReadReply<Xkb::GetMapReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::GetMapReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ auto& minKeyCode = (*reply).minKeyCode;
+ auto& maxKeyCode = (*reply).maxKeyCode;
+ Xkb::MapPart present{};
+ auto& firstType = (*reply).firstType;
+ auto& nTypes = (*reply).nTypes;
+ auto& totalTypes = (*reply).totalTypes;
+ auto& firstKeySym = (*reply).firstKeySym;
+ auto& totalSyms = (*reply).totalSyms;
+ auto& nKeySyms = (*reply).nKeySyms;
+ auto& firstKeyAction = (*reply).firstKeyAction;
+ auto& totalActions = (*reply).totalActions;
+ auto& nKeyActions = (*reply).nKeyActions;
+ auto& firstKeyBehavior = (*reply).firstKeyBehavior;
+ auto& nKeyBehaviors = (*reply).nKeyBehaviors;
+ auto& totalKeyBehaviors = (*reply).totalKeyBehaviors;
+ auto& firstKeyExplicit = (*reply).firstKeyExplicit;
+ auto& nKeyExplicit = (*reply).nKeyExplicit;
+ auto& totalKeyExplicit = (*reply).totalKeyExplicit;
+ auto& firstModMapKey = (*reply).firstModMapKey;
+ auto& nModMapKeys = (*reply).nModMapKeys;
+ auto& totalModMapKeys = (*reply).totalModMapKeys;
+ auto& firstVModMapKey = (*reply).firstVModMapKey;
+ auto& nVModMapKeys = (*reply).nVModMapKeys;
+ auto& totalVModMapKeys = (*reply).totalVModMapKeys;
+ auto& virtualMods = (*reply).virtualMods;
+ auto& map = (*reply);
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // minKeyCode
+ Read(&minKeyCode, &buf);
+
+ // maxKeyCode
+ Read(&maxKeyCode, &buf);
+
+ // present
+ uint16_t tmp97;
+ Read(&tmp97, &buf);
+ present = static_cast<Xkb::MapPart>(tmp97);
+
+ // firstType
+ Read(&firstType, &buf);
+
+ // nTypes
+ Read(&nTypes, &buf);
+
+ // totalTypes
+ Read(&totalTypes, &buf);
+
+ // firstKeySym
+ Read(&firstKeySym, &buf);
+
+ // totalSyms
+ Read(&totalSyms, &buf);
+
+ // nKeySyms
+ Read(&nKeySyms, &buf);
+
+ // firstKeyAction
+ Read(&firstKeyAction, &buf);
+
+ // totalActions
+ Read(&totalActions, &buf);
+
+ // nKeyActions
+ Read(&nKeyActions, &buf);
+
+ // firstKeyBehavior
+ Read(&firstKeyBehavior, &buf);
+
+ // nKeyBehaviors
+ Read(&nKeyBehaviors, &buf);
+
+ // totalKeyBehaviors
+ Read(&totalKeyBehaviors, &buf);
+
+ // firstKeyExplicit
+ Read(&firstKeyExplicit, &buf);
+
+ // nKeyExplicit
+ Read(&nKeyExplicit, &buf);
+
+ // totalKeyExplicit
+ Read(&totalKeyExplicit, &buf);
+
+ // firstModMapKey
+ Read(&firstModMapKey, &buf);
+
+ // nModMapKeys
+ Read(&nModMapKeys, &buf);
+
+ // totalModMapKeys
+ Read(&totalModMapKeys, &buf);
+
+ // firstVModMapKey
+ Read(&firstVModMapKey, &buf);
+
+ // nVModMapKeys
+ Read(&nVModMapKeys, &buf);
+
+ // totalVModMapKeys
+ Read(&totalVModMapKeys, &buf);
+
+ // pad1
+ Pad(&buf, 1);
+
+ // virtualMods
+ uint16_t tmp98;
+ Read(&tmp98, &buf);
+ virtualMods = static_cast<Xkb::VMod>(tmp98);
+
+ // map
+ auto map_expr = present;
+ if (CaseAnd(map_expr, Xkb::MapPart::KeyTypes)) {
+ map.types_rtrn.emplace();
+ auto& types_rtrn = *map.types_rtrn;
+ size_t types_rtrn_len = types_rtrn.size();
+
+ // types_rtrn
+ types_rtrn.resize(nTypes);
+ for (auto& types_rtrn_elem : types_rtrn) {
+ // types_rtrn_elem
+ {
+ auto& mods_mask = types_rtrn_elem.mods_mask;
+ auto& mods_mods = types_rtrn_elem.mods_mods;
+ auto& mods_vmods = types_rtrn_elem.mods_vmods;
+ auto& numLevels = types_rtrn_elem.numLevels;
+ uint8_t nMapEntries{};
+ auto& hasPreserve = types_rtrn_elem.hasPreserve;
+ auto& map = types_rtrn_elem.map;
+ size_t map_len = map.size();
+ auto& preserve = types_rtrn_elem.preserve;
+ size_t preserve_len = preserve.size();
+
+ // mods_mask
+ uint8_t tmp99;
+ Read(&tmp99, &buf);
+ mods_mask = static_cast<ModMask>(tmp99);
+
+ // mods_mods
+ uint8_t tmp100;
+ Read(&tmp100, &buf);
+ mods_mods = static_cast<ModMask>(tmp100);
+
+ // mods_vmods
+ uint16_t tmp101;
+ Read(&tmp101, &buf);
+ mods_vmods = static_cast<Xkb::VMod>(tmp101);
+
+ // numLevels
+ Read(&numLevels, &buf);
+
+ // nMapEntries
+ Read(&nMapEntries, &buf);
+
+ // hasPreserve
+ Read(&hasPreserve, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // map
+ map.resize(nMapEntries);
+ for (auto& map_elem : map) {
+ // map_elem
+ {
+ auto& active = map_elem.active;
+ auto& mods_mask = map_elem.mods_mask;
+ auto& level = map_elem.level;
+ auto& mods_mods = map_elem.mods_mods;
+ auto& mods_vmods = map_elem.mods_vmods;
+
+ // active
+ Read(&active, &buf);
+
+ // mods_mask
+ uint8_t tmp102;
+ Read(&tmp102, &buf);
+ mods_mask = static_cast<ModMask>(tmp102);
+
+ // level
+ Read(&level, &buf);
+
+ // mods_mods
+ uint8_t tmp103;
+ Read(&tmp103, &buf);
+ mods_mods = static_cast<ModMask>(tmp103);
+
+ // mods_vmods
+ uint16_t tmp104;
+ Read(&tmp104, &buf);
+ mods_vmods = static_cast<Xkb::VMod>(tmp104);
+
+ // pad0
+ Pad(&buf, 2);
+ }
+ }
+
+ // preserve
+ preserve.resize((hasPreserve) * (nMapEntries));
+ for (auto& preserve_elem : preserve) {
+ // preserve_elem
+ {
+ auto& mask = preserve_elem.mask;
+ auto& realMods = preserve_elem.realMods;
+ auto& vmods = preserve_elem.vmods;
+
+ // mask
+ uint8_t tmp105;
+ Read(&tmp105, &buf);
+ mask = static_cast<ModMask>(tmp105);
+
+ // realMods
+ uint8_t tmp106;
+ Read(&tmp106, &buf);
+ realMods = static_cast<ModMask>(tmp106);
+
+ // vmods
+ uint16_t tmp107;
+ Read(&tmp107, &buf);
+ vmods = static_cast<Xkb::VMod>(tmp107);
+ }
+ }
+ }
+ }
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::KeySyms)) {
+ map.syms_rtrn.emplace();
+ auto& syms_rtrn = *map.syms_rtrn;
+ size_t syms_rtrn_len = syms_rtrn.size();
+
+ // syms_rtrn
+ syms_rtrn.resize(nKeySyms);
+ for (auto& syms_rtrn_elem : syms_rtrn) {
+ // syms_rtrn_elem
+ {
+ auto& kt_index = syms_rtrn_elem.kt_index;
+ size_t kt_index_len = kt_index.size();
+ auto& groupInfo = syms_rtrn_elem.groupInfo;
+ auto& width = syms_rtrn_elem.width;
+ uint16_t nSyms{};
+ auto& syms = syms_rtrn_elem.syms;
+ size_t syms_len = syms.size();
+
+ // kt_index
+ for (auto& kt_index_elem : kt_index) {
+ // kt_index_elem
+ Read(&kt_index_elem, &buf);
+ }
+
+ // groupInfo
+ Read(&groupInfo, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // nSyms
+ Read(&nSyms, &buf);
+
+ // syms
+ syms.resize(nSyms);
+ for (auto& syms_elem : syms) {
+ // syms_elem
+ Read(&syms_elem, &buf);
+ }
+ }
+ }
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::KeyActions)) {
+ map.acts_rtrn_count.emplace();
+ map.acts_rtrn_acts.emplace();
+ auto& acts_rtrn_count = *map.acts_rtrn_count;
+ size_t acts_rtrn_count_len = acts_rtrn_count.size();
+ auto& acts_rtrn_acts = *map.acts_rtrn_acts;
+ size_t acts_rtrn_acts_len = acts_rtrn_acts.size();
+
+ // acts_rtrn_count
+ acts_rtrn_count.resize(nKeyActions);
+ for (auto& acts_rtrn_count_elem : acts_rtrn_count) {
+ // acts_rtrn_count_elem
+ Read(&acts_rtrn_count_elem, &buf);
+ }
+
+ // pad2
+ Align(&buf, 4);
+
+ // acts_rtrn_acts
+ acts_rtrn_acts.resize(totalActions);
+ for (auto& acts_rtrn_acts_elem : acts_rtrn_acts) {
+ // acts_rtrn_acts_elem
+ Read(&acts_rtrn_acts_elem, &buf);
+ }
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::KeyBehaviors)) {
+ map.behaviors_rtrn.emplace();
+ auto& behaviors_rtrn = *map.behaviors_rtrn;
+ size_t behaviors_rtrn_len = behaviors_rtrn.size();
+
+ // behaviors_rtrn
+ behaviors_rtrn.resize(totalKeyBehaviors);
+ for (auto& behaviors_rtrn_elem : behaviors_rtrn) {
+ // behaviors_rtrn_elem
+ {
+ auto& keycode = behaviors_rtrn_elem.keycode;
+ auto& behavior = behaviors_rtrn_elem.behavior;
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // behavior
+ Read(&behavior, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+ }
+ }
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::VirtualMods)) {
+ map.vmods_rtrn.emplace();
+ auto& vmods_rtrn = *map.vmods_rtrn;
+ size_t vmods_rtrn_len = vmods_rtrn.size();
+
+ // vmods_rtrn
+ vmods_rtrn.resize(PopCount(virtualMods));
+ for (auto& vmods_rtrn_elem : vmods_rtrn) {
+ // vmods_rtrn_elem
+ uint8_t tmp108;
+ Read(&tmp108, &buf);
+ vmods_rtrn_elem = static_cast<ModMask>(tmp108);
+ }
+
+ // pad3
+ Align(&buf, 4);
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::ExplicitComponents)) {
+ map.explicit_rtrn.emplace();
+ auto& explicit_rtrn = *map.explicit_rtrn;
+ size_t explicit_rtrn_len = explicit_rtrn.size();
+
+ // explicit_rtrn
+ explicit_rtrn.resize(totalKeyExplicit);
+ for (auto& explicit_rtrn_elem : explicit_rtrn) {
+ // explicit_rtrn_elem
+ {
+ auto& keycode = explicit_rtrn_elem.keycode;
+ auto& c_explicit = explicit_rtrn_elem.c_explicit;
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // c_explicit
+ uint8_t tmp109;
+ Read(&tmp109, &buf);
+ c_explicit = static_cast<Xkb::Explicit>(tmp109);
+ }
+ }
+
+ // pad4
+ Align(&buf, 4);
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::ModifierMap)) {
+ map.modmap_rtrn.emplace();
+ auto& modmap_rtrn = *map.modmap_rtrn;
+ size_t modmap_rtrn_len = modmap_rtrn.size();
+
+ // modmap_rtrn
+ modmap_rtrn.resize(totalModMapKeys);
+ for (auto& modmap_rtrn_elem : modmap_rtrn) {
+ // modmap_rtrn_elem
+ {
+ auto& keycode = modmap_rtrn_elem.keycode;
+ auto& mods = modmap_rtrn_elem.mods;
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // mods
+ uint8_t tmp110;
+ Read(&tmp110, &buf);
+ mods = static_cast<ModMask>(tmp110);
+ }
+ }
+
+ // pad5
+ Align(&buf, 4);
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::VirtualModMap)) {
+ map.vmodmap_rtrn.emplace();
+ auto& vmodmap_rtrn = *map.vmodmap_rtrn;
+ size_t vmodmap_rtrn_len = vmodmap_rtrn.size();
+
+ // vmodmap_rtrn
+ vmodmap_rtrn.resize(totalVModMapKeys);
+ for (auto& vmodmap_rtrn_elem : vmodmap_rtrn) {
+ // vmodmap_rtrn_elem
+ {
+ auto& keycode = vmodmap_rtrn_elem.keycode;
+ auto& vmods = vmodmap_rtrn_elem.vmods;
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // vmods
+ uint16_t tmp111;
+ Read(&tmp111, &buf);
+ vmods = static_cast<Xkb::VMod>(tmp111);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xkb::SetMap(const Xkb::SetMapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ MapPart present{};
+ auto& flags = request.flags;
+ auto& minKeyCode = request.minKeyCode;
+ auto& maxKeyCode = request.maxKeyCode;
+ auto& firstType = request.firstType;
+ auto& nTypes = request.nTypes;
+ auto& firstKeySym = request.firstKeySym;
+ auto& nKeySyms = request.nKeySyms;
+ auto& totalSyms = request.totalSyms;
+ auto& firstKeyAction = request.firstKeyAction;
+ auto& nKeyActions = request.nKeyActions;
+ auto& totalActions = request.totalActions;
+ auto& firstKeyBehavior = request.firstKeyBehavior;
+ auto& nKeyBehaviors = request.nKeyBehaviors;
+ auto& totalKeyBehaviors = request.totalKeyBehaviors;
+ auto& firstKeyExplicit = request.firstKeyExplicit;
+ auto& nKeyExplicit = request.nKeyExplicit;
+ auto& totalKeyExplicit = request.totalKeyExplicit;
+ auto& firstModMapKey = request.firstModMapKey;
+ auto& nModMapKeys = request.nModMapKeys;
+ auto& totalModMapKeys = request.totalModMapKeys;
+ auto& firstVModMapKey = request.firstVModMapKey;
+ auto& nVModMapKeys = request.nVModMapKeys;
+ auto& totalVModMapKeys = request.totalVModMapKeys;
+ auto& virtualMods = request.virtualMods;
+ auto& values = request;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // present
+ SwitchVar(MapPart::KeyTypes, values.types.has_value(), true, &present);
+ SwitchVar(MapPart::KeySyms, values.syms.has_value(), true, &present);
+ SwitchVar(MapPart::KeyActions, values.actionsCount.has_value(), true,
+ &present);
+ SwitchVar(MapPart::KeyBehaviors, values.behaviors.has_value(), true,
+ &present);
+ SwitchVar(MapPart::VirtualMods, values.vmods.has_value(), true, &present);
+ SwitchVar(MapPart::ExplicitComponents, values.c_explicit.has_value(), true,
+ &present);
+ SwitchVar(MapPart::ModifierMap, values.modmap.has_value(), true, &present);
+ SwitchVar(MapPart::VirtualModMap, values.vmodmap.has_value(), true, &present);
+ uint16_t tmp112;
+ tmp112 = static_cast<uint16_t>(present);
+ buf.Write(&tmp112);
+
+ // flags
+ uint16_t tmp113;
+ tmp113 = static_cast<uint16_t>(flags);
+ buf.Write(&tmp113);
+
+ // minKeyCode
+ buf.Write(&minKeyCode);
+
+ // maxKeyCode
+ buf.Write(&maxKeyCode);
+
+ // firstType
+ buf.Write(&firstType);
+
+ // nTypes
+ buf.Write(&nTypes);
+
+ // firstKeySym
+ buf.Write(&firstKeySym);
+
+ // nKeySyms
+ buf.Write(&nKeySyms);
+
+ // totalSyms
+ buf.Write(&totalSyms);
+
+ // firstKeyAction
+ buf.Write(&firstKeyAction);
+
+ // nKeyActions
+ buf.Write(&nKeyActions);
+
+ // totalActions
+ buf.Write(&totalActions);
+
+ // firstKeyBehavior
+ buf.Write(&firstKeyBehavior);
+
+ // nKeyBehaviors
+ buf.Write(&nKeyBehaviors);
+
+ // totalKeyBehaviors
+ buf.Write(&totalKeyBehaviors);
+
+ // firstKeyExplicit
+ buf.Write(&firstKeyExplicit);
+
+ // nKeyExplicit
+ buf.Write(&nKeyExplicit);
+
+ // totalKeyExplicit
+ buf.Write(&totalKeyExplicit);
+
+ // firstModMapKey
+ buf.Write(&firstModMapKey);
+
+ // nModMapKeys
+ buf.Write(&nModMapKeys);
+
+ // totalModMapKeys
+ buf.Write(&totalModMapKeys);
+
+ // firstVModMapKey
+ buf.Write(&firstVModMapKey);
+
+ // nVModMapKeys
+ buf.Write(&nVModMapKeys);
+
+ // totalVModMapKeys
+ buf.Write(&totalVModMapKeys);
+
+ // virtualMods
+ uint16_t tmp114;
+ tmp114 = static_cast<uint16_t>(virtualMods);
+ buf.Write(&tmp114);
+
+ // values
+ auto values_expr = present;
+ if (CaseAnd(values_expr, MapPart::KeyTypes)) {
+ auto& types = *values.types;
+ size_t types_len = types.size();
+
+ // types
+ DCHECK_EQ(static_cast<size_t>(nTypes), types.size());
+ for (auto& types_elem : types) {
+ // types_elem
+ {
+ auto& mask = types_elem.mask;
+ auto& realMods = types_elem.realMods;
+ auto& virtualMods = types_elem.virtualMods;
+ auto& numLevels = types_elem.numLevels;
+ uint8_t nMapEntries{};
+ auto& preserve = types_elem.preserve;
+ auto& entries = types_elem.entries;
+ size_t entries_len = entries.size();
+ auto& preserve_entries = types_elem.preserve_entries;
+ size_t preserve_entries_len = preserve_entries.size();
+
+ // mask
+ uint8_t tmp115;
+ tmp115 = static_cast<uint8_t>(mask);
+ buf.Write(&tmp115);
+
+ // realMods
+ uint8_t tmp116;
+ tmp116 = static_cast<uint8_t>(realMods);
+ buf.Write(&tmp116);
+
+ // virtualMods
+ uint16_t tmp117;
+ tmp117 = static_cast<uint16_t>(virtualMods);
+ buf.Write(&tmp117);
+
+ // numLevels
+ buf.Write(&numLevels);
+
+ // nMapEntries
+ nMapEntries = entries.size();
+ buf.Write(&nMapEntries);
+
+ // preserve
+ buf.Write(&preserve);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // entries
+ DCHECK_EQ(static_cast<size_t>(nMapEntries), entries.size());
+ for (auto& entries_elem : entries) {
+ // entries_elem
+ {
+ auto& level = entries_elem.level;
+ auto& realMods = entries_elem.realMods;
+ auto& virtualMods = entries_elem.virtualMods;
+
+ // level
+ buf.Write(&level);
+
+ // realMods
+ uint8_t tmp118;
+ tmp118 = static_cast<uint8_t>(realMods);
+ buf.Write(&tmp118);
+
+ // virtualMods
+ uint16_t tmp119;
+ tmp119 = static_cast<uint16_t>(virtualMods);
+ buf.Write(&tmp119);
+ }
+ }
+
+ // preserve_entries
+ DCHECK_EQ(static_cast<size_t>((preserve) * (nMapEntries)),
+ preserve_entries.size());
+ for (auto& preserve_entries_elem : preserve_entries) {
+ // preserve_entries_elem
+ {
+ auto& level = preserve_entries_elem.level;
+ auto& realMods = preserve_entries_elem.realMods;
+ auto& virtualMods = preserve_entries_elem.virtualMods;
+
+ // level
+ buf.Write(&level);
+
+ // realMods
+ uint8_t tmp120;
+ tmp120 = static_cast<uint8_t>(realMods);
+ buf.Write(&tmp120);
+
+ // virtualMods
+ uint16_t tmp121;
+ tmp121 = static_cast<uint16_t>(virtualMods);
+ buf.Write(&tmp121);
+ }
+ }
+ }
+ }
+ }
+ if (CaseAnd(values_expr, MapPart::KeySyms)) {
+ auto& syms = *values.syms;
+ size_t syms_len = syms.size();
+
+ // syms
+ DCHECK_EQ(static_cast<size_t>(nKeySyms), syms.size());
+ for (auto& syms_elem : syms) {
+ // syms_elem
+ {
+ auto& kt_index = syms_elem.kt_index;
+ size_t kt_index_len = kt_index.size();
+ auto& groupInfo = syms_elem.groupInfo;
+ auto& width = syms_elem.width;
+ uint16_t nSyms{};
+ auto& syms = syms_elem.syms;
+ size_t syms_len = syms.size();
+
+ // kt_index
+ for (auto& kt_index_elem : kt_index) {
+ // kt_index_elem
+ buf.Write(&kt_index_elem);
+ }
+
+ // groupInfo
+ buf.Write(&groupInfo);
+
+ // width
+ buf.Write(&width);
+
+ // nSyms
+ nSyms = syms.size();
+ buf.Write(&nSyms);
+
+ // syms
+ DCHECK_EQ(static_cast<size_t>(nSyms), syms.size());
+ for (auto& syms_elem : syms) {
+ // syms_elem
+ buf.Write(&syms_elem);
+ }
+ }
+ }
+ }
+ if (CaseAnd(values_expr, MapPart::KeyActions)) {
+ auto& actionsCount = *values.actionsCount;
+ size_t actionsCount_len = actionsCount.size();
+ auto& actions = *values.actions;
+ size_t actions_len = actions.size();
+
+ // actionsCount
+ DCHECK_EQ(static_cast<size_t>(nKeyActions), actionsCount.size());
+ for (auto& actionsCount_elem : actionsCount) {
+ // actionsCount_elem
+ buf.Write(&actionsCount_elem);
+ }
+
+ // pad0
+ Align(&buf, 4);
+
+ // actions
+ DCHECK_EQ(static_cast<size_t>(totalActions), actions.size());
+ for (auto& actions_elem : actions) {
+ // actions_elem
+ buf.Write(&actions_elem);
+ }
+ }
+ if (CaseAnd(values_expr, MapPart::KeyBehaviors)) {
+ auto& behaviors = *values.behaviors;
+ size_t behaviors_len = behaviors.size();
+
+ // behaviors
+ DCHECK_EQ(static_cast<size_t>(totalKeyBehaviors), behaviors.size());
+ for (auto& behaviors_elem : behaviors) {
+ // behaviors_elem
+ {
+ auto& keycode = behaviors_elem.keycode;
+ auto& behavior = behaviors_elem.behavior;
+
+ // keycode
+ buf.Write(&keycode);
+
+ // behavior
+ buf.Write(&behavior);
+
+ // pad0
+ Pad(&buf, 1);
+ }
+ }
+ }
+ if (CaseAnd(values_expr, MapPart::VirtualMods)) {
+ auto& vmods = *values.vmods;
+ size_t vmods_len = vmods.size();
+
+ // vmods
+ DCHECK_EQ(static_cast<size_t>(PopCount(virtualMods)), vmods.size());
+ for (auto& vmods_elem : vmods) {
+ // vmods_elem
+ buf.Write(&vmods_elem);
+ }
+
+ // pad1
+ Align(&buf, 4);
+ }
+ if (CaseAnd(values_expr, MapPart::ExplicitComponents)) {
+ auto& c_explicit = *values.c_explicit;
+ size_t c_explicit_len = c_explicit.size();
+
+ // c_explicit
+ DCHECK_EQ(static_cast<size_t>(totalKeyExplicit), c_explicit.size());
+ for (auto& c_explicit_elem : c_explicit) {
+ // c_explicit_elem
+ {
+ auto& keycode = c_explicit_elem.keycode;
+ auto& c_explicit = c_explicit_elem.c_explicit;
+
+ // keycode
+ buf.Write(&keycode);
+
+ // c_explicit
+ uint8_t tmp122;
+ tmp122 = static_cast<uint8_t>(c_explicit);
+ buf.Write(&tmp122);
+ }
+ }
+ }
+ if (CaseAnd(values_expr, MapPart::ModifierMap)) {
+ auto& modmap = *values.modmap;
+ size_t modmap_len = modmap.size();
+
+ // modmap
+ DCHECK_EQ(static_cast<size_t>(totalModMapKeys), modmap.size());
+ for (auto& modmap_elem : modmap) {
+ // modmap_elem
+ {
+ auto& keycode = modmap_elem.keycode;
+ auto& mods = modmap_elem.mods;
+
+ // keycode
+ buf.Write(&keycode);
+
+ // mods
+ uint8_t tmp123;
+ tmp123 = static_cast<uint8_t>(mods);
+ buf.Write(&tmp123);
+ }
+ }
+ }
+ if (CaseAnd(values_expr, MapPart::VirtualModMap)) {
+ auto& vmodmap = *values.vmodmap;
+ size_t vmodmap_len = vmodmap.size();
+
+ // vmodmap
+ DCHECK_EQ(static_cast<size_t>(totalVModMapKeys), vmodmap.size());
+ for (auto& vmodmap_elem : vmodmap) {
+ // vmodmap_elem
+ {
+ auto& keycode = vmodmap_elem.keycode;
+ auto& vmods = vmodmap_elem.vmods;
+
+ // keycode
+ buf.Write(&keycode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // vmods
+ uint16_t tmp124;
+ tmp124 = static_cast<uint16_t>(vmods);
+ buf.Write(&tmp124);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xkb::SetMap", false);
+}
+
+Future<void> Xkb::SetMap(
+ const DeviceSpec& deviceSpec,
+ const SetMapFlags& flags,
+ const KeyCode& minKeyCode,
+ const KeyCode& maxKeyCode,
+ const uint8_t& firstType,
+ const uint8_t& nTypes,
+ const KeyCode& firstKeySym,
+ const uint8_t& nKeySyms,
+ const uint16_t& totalSyms,
+ const KeyCode& firstKeyAction,
+ const uint8_t& nKeyActions,
+ const uint16_t& totalActions,
+ const KeyCode& firstKeyBehavior,
+ const uint8_t& nKeyBehaviors,
+ const uint8_t& totalKeyBehaviors,
+ const KeyCode& firstKeyExplicit,
+ const uint8_t& nKeyExplicit,
+ const uint8_t& totalKeyExplicit,
+ const KeyCode& firstModMapKey,
+ const uint8_t& nModMapKeys,
+ const uint8_t& totalModMapKeys,
+ const KeyCode& firstVModMapKey,
+ const uint8_t& nVModMapKeys,
+ const uint8_t& totalVModMapKeys,
+ const VMod& virtualMods,
+ const base::Optional<std::vector<SetKeyType>>& types,
+ const base::Optional<std::vector<KeySymMap>>& syms,
+ const base::Optional<std::vector<uint8_t>>& actionsCount,
+ const base::Optional<std::vector<Action>>& actions,
+ const base::Optional<std::vector<SetBehavior>>& behaviors,
+ const base::Optional<std::vector<uint8_t>>& vmods,
+ const base::Optional<std::vector<SetExplicit>>& c_explicit,
+ const base::Optional<std::vector<KeyModMap>>& modmap,
+ const base::Optional<std::vector<KeyVModMap>>& vmodmap) {
+ return Xkb::SetMap(Xkb::SetMapRequest{deviceSpec,
+ flags,
+ minKeyCode,
+ maxKeyCode,
+ firstType,
+ nTypes,
+ firstKeySym,
+ nKeySyms,
+ totalSyms,
+ firstKeyAction,
+ nKeyActions,
+ totalActions,
+ firstKeyBehavior,
+ nKeyBehaviors,
+ totalKeyBehaviors,
+ firstKeyExplicit,
+ nKeyExplicit,
+ totalKeyExplicit,
+ firstModMapKey,
+ nModMapKeys,
+ totalModMapKeys,
+ firstVModMapKey,
+ nVModMapKeys,
+ totalVModMapKeys,
+ virtualMods,
+ types,
+ syms,
+ actionsCount,
+ actions,
+ behaviors,
+ vmods,
+ c_explicit,
+ modmap,
+ vmodmap});
+}
+
+Future<Xkb::GetCompatMapReply> Xkb::GetCompatMap(
+ const Xkb::GetCompatMapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& groups = request.groups;
+ auto& getAllSI = request.getAllSI;
+ auto& firstSI = request.firstSI;
+ auto& nSI = request.nSI;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // groups
+ uint8_t tmp125;
+ tmp125 = static_cast<uint8_t>(groups);
+ buf.Write(&tmp125);
+
+ // getAllSI
+ buf.Write(&getAllSI);
+
+ // firstSI
+ buf.Write(&firstSI);
+
+ // nSI
+ buf.Write(&nSI);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::GetCompatMapReply>(
+ &buf, "Xkb::GetCompatMap", false);
+}
+
+Future<Xkb::GetCompatMapReply> Xkb::GetCompatMap(const DeviceSpec& deviceSpec,
+ const SetOfGroup& groups,
+ const uint8_t& getAllSI,
+ const uint16_t& firstSI,
+ const uint16_t& nSI) {
+ return Xkb::GetCompatMap(
+ Xkb::GetCompatMapRequest{deviceSpec, groups, getAllSI, firstSI, nSI});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::GetCompatMapReply> detail::ReadReply<
+ Xkb::GetCompatMapReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::GetCompatMapReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ auto& groupsRtrn = (*reply).groupsRtrn;
+ auto& firstSIRtrn = (*reply).firstSIRtrn;
+ uint16_t nSIRtrn{};
+ auto& nTotalSI = (*reply).nTotalSI;
+ auto& si_rtrn = (*reply).si_rtrn;
+ size_t si_rtrn_len = si_rtrn.size();
+ auto& group_rtrn = (*reply).group_rtrn;
+ size_t group_rtrn_len = group_rtrn.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // groupsRtrn
+ uint8_t tmp126;
+ Read(&tmp126, &buf);
+ groupsRtrn = static_cast<Xkb::SetOfGroup>(tmp126);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // firstSIRtrn
+ Read(&firstSIRtrn, &buf);
+
+ // nSIRtrn
+ Read(&nSIRtrn, &buf);
+
+ // nTotalSI
+ Read(&nTotalSI, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ // si_rtrn
+ si_rtrn.resize(nSIRtrn);
+ for (auto& si_rtrn_elem : si_rtrn) {
+ // si_rtrn_elem
+ {
+ auto& sym = si_rtrn_elem.sym;
+ auto& mods = si_rtrn_elem.mods;
+ auto& match = si_rtrn_elem.match;
+ auto& virtualMod = si_rtrn_elem.virtualMod;
+ auto& flags = si_rtrn_elem.flags;
+ auto& action = si_rtrn_elem.action;
+
+ // sym
+ Read(&sym, &buf);
+
+ // mods
+ uint8_t tmp127;
+ Read(&tmp127, &buf);
+ mods = static_cast<ModMask>(tmp127);
+
+ // match
+ Read(&match, &buf);
+
+ // virtualMod
+ uint8_t tmp128;
+ Read(&tmp128, &buf);
+ virtualMod = static_cast<Xkb::VModsLow>(tmp128);
+
+ // flags
+ Read(&flags, &buf);
+
+ // action
+ {
+ auto& type = action.type;
+ auto& data = action.data;
+ size_t data_len = data.size();
+
+ // type
+ uint8_t tmp129;
+ Read(&tmp129, &buf);
+ type = static_cast<Xkb::SAType>(tmp129);
+
+ // data
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+ }
+ }
+ }
+
+ // group_rtrn
+ group_rtrn.resize(PopCount(groupsRtrn));
+ for (auto& group_rtrn_elem : group_rtrn) {
+ // group_rtrn_elem
+ {
+ auto& mask = group_rtrn_elem.mask;
+ auto& realMods = group_rtrn_elem.realMods;
+ auto& vmods = group_rtrn_elem.vmods;
+
+ // mask
+ uint8_t tmp130;
+ Read(&tmp130, &buf);
+ mask = static_cast<ModMask>(tmp130);
+
+ // realMods
+ uint8_t tmp131;
+ Read(&tmp131, &buf);
+ realMods = static_cast<ModMask>(tmp131);
+
+ // vmods
+ uint16_t tmp132;
+ Read(&tmp132, &buf);
+ vmods = static_cast<Xkb::VMod>(tmp132);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xkb::SetCompatMap(const Xkb::SetCompatMapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& recomputeActions = request.recomputeActions;
+ auto& truncateSI = request.truncateSI;
+ auto& groups = request.groups;
+ auto& firstSI = request.firstSI;
+ uint16_t nSI{};
+ auto& si = request.si;
+ size_t si_len = si.size();
+ auto& groupMaps = request.groupMaps;
+ size_t groupMaps_len = groupMaps.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // recomputeActions
+ buf.Write(&recomputeActions);
+
+ // truncateSI
+ buf.Write(&truncateSI);
+
+ // groups
+ uint8_t tmp133;
+ tmp133 = static_cast<uint8_t>(groups);
+ buf.Write(&tmp133);
+
+ // firstSI
+ buf.Write(&firstSI);
+
+ // nSI
+ nSI = si.size();
+ buf.Write(&nSI);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // si
+ DCHECK_EQ(static_cast<size_t>(nSI), si.size());
+ for (auto& si_elem : si) {
+ // si_elem
+ {
+ auto& sym = si_elem.sym;
+ auto& mods = si_elem.mods;
+ auto& match = si_elem.match;
+ auto& virtualMod = si_elem.virtualMod;
+ auto& flags = si_elem.flags;
+ auto& action = si_elem.action;
+
+ // sym
+ buf.Write(&sym);
+
+ // mods
+ uint8_t tmp134;
+ tmp134 = static_cast<uint8_t>(mods);
+ buf.Write(&tmp134);
+
+ // match
+ buf.Write(&match);
+
+ // virtualMod
+ uint8_t tmp135;
+ tmp135 = static_cast<uint8_t>(virtualMod);
+ buf.Write(&tmp135);
+
+ // flags
+ buf.Write(&flags);
+
+ // action
+ {
+ auto& type = action.type;
+ auto& data = action.data;
+ size_t data_len = data.size();
+
+ // type
+ uint8_t tmp136;
+ tmp136 = static_cast<uint8_t>(type);
+ buf.Write(&tmp136);
+
+ // data
+ for (auto& data_elem : data) {
+ // data_elem
+ buf.Write(&data_elem);
+ }
+ }
+ }
+ }
+
+ // groupMaps
+ DCHECK_EQ(static_cast<size_t>(PopCount(groups)), groupMaps.size());
+ for (auto& groupMaps_elem : groupMaps) {
+ // groupMaps_elem
+ {
+ auto& mask = groupMaps_elem.mask;
+ auto& realMods = groupMaps_elem.realMods;
+ auto& vmods = groupMaps_elem.vmods;
+
+ // mask
+ uint8_t tmp137;
+ tmp137 = static_cast<uint8_t>(mask);
+ buf.Write(&tmp137);
+
+ // realMods
+ uint8_t tmp138;
+ tmp138 = static_cast<uint8_t>(realMods);
+ buf.Write(&tmp138);
+
+ // vmods
+ uint16_t tmp139;
+ tmp139 = static_cast<uint16_t>(vmods);
+ buf.Write(&tmp139);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xkb::SetCompatMap", false);
+}
+
+Future<void> Xkb::SetCompatMap(const DeviceSpec& deviceSpec,
+ const uint8_t& recomputeActions,
+ const uint8_t& truncateSI,
+ const SetOfGroup& groups,
+ const uint16_t& firstSI,
+ const std::vector<SymInterpret>& si,
+ const std::vector<ModDef>& groupMaps) {
+ return Xkb::SetCompatMap(
+ Xkb::SetCompatMapRequest{deviceSpec, recomputeActions, truncateSI, groups,
+ firstSI, si, groupMaps});
+}
+
+Future<Xkb::GetIndicatorStateReply> Xkb::GetIndicatorState(
+ const Xkb::GetIndicatorStateRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::GetIndicatorStateReply>(
+ &buf, "Xkb::GetIndicatorState", false);
+}
+
+Future<Xkb::GetIndicatorStateReply> Xkb::GetIndicatorState(
+ const DeviceSpec& deviceSpec) {
+ return Xkb::GetIndicatorState(Xkb::GetIndicatorStateRequest{deviceSpec});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::GetIndicatorStateReply> detail::ReadReply<
+ Xkb::GetIndicatorStateReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::GetIndicatorStateReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ auto& state = (*reply).state;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // state
+ Read(&state, &buf);
+
+ // pad0
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xkb::GetIndicatorMapReply> Xkb::GetIndicatorMap(
+ const Xkb::GetIndicatorMapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& which = request.which;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // which
+ buf.Write(&which);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::GetIndicatorMapReply>(
+ &buf, "Xkb::GetIndicatorMap", false);
+}
+
+Future<Xkb::GetIndicatorMapReply> Xkb::GetIndicatorMap(
+ const DeviceSpec& deviceSpec,
+ const uint32_t& which) {
+ return Xkb::GetIndicatorMap(Xkb::GetIndicatorMapRequest{deviceSpec, which});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::GetIndicatorMapReply> detail::ReadReply<
+ Xkb::GetIndicatorMapReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::GetIndicatorMapReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ auto& which = (*reply).which;
+ auto& realIndicators = (*reply).realIndicators;
+ auto& nIndicators = (*reply).nIndicators;
+ auto& maps = (*reply).maps;
+ size_t maps_len = maps.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // which
+ Read(&which, &buf);
+
+ // realIndicators
+ Read(&realIndicators, &buf);
+
+ // nIndicators
+ Read(&nIndicators, &buf);
+
+ // pad0
+ Pad(&buf, 15);
+
+ // maps
+ maps.resize(PopCount(which));
+ for (auto& maps_elem : maps) {
+ // maps_elem
+ {
+ auto& flags = maps_elem.flags;
+ auto& whichGroups = maps_elem.whichGroups;
+ auto& groups = maps_elem.groups;
+ auto& whichMods = maps_elem.whichMods;
+ auto& mods = maps_elem.mods;
+ auto& realMods = maps_elem.realMods;
+ auto& vmods = maps_elem.vmods;
+ auto& ctrls = maps_elem.ctrls;
+
+ // flags
+ uint8_t tmp140;
+ Read(&tmp140, &buf);
+ flags = static_cast<Xkb::IMFlag>(tmp140);
+
+ // whichGroups
+ uint8_t tmp141;
+ Read(&tmp141, &buf);
+ whichGroups = static_cast<Xkb::IMGroupsWhich>(tmp141);
+
+ // groups
+ uint8_t tmp142;
+ Read(&tmp142, &buf);
+ groups = static_cast<Xkb::SetOfGroup>(tmp142);
+
+ // whichMods
+ uint8_t tmp143;
+ Read(&tmp143, &buf);
+ whichMods = static_cast<Xkb::IMModsWhich>(tmp143);
+
+ // mods
+ uint8_t tmp144;
+ Read(&tmp144, &buf);
+ mods = static_cast<ModMask>(tmp144);
+
+ // realMods
+ uint8_t tmp145;
+ Read(&tmp145, &buf);
+ realMods = static_cast<ModMask>(tmp145);
+
+ // vmods
+ uint16_t tmp146;
+ Read(&tmp146, &buf);
+ vmods = static_cast<Xkb::VMod>(tmp146);
+
+ // ctrls
+ uint32_t tmp147;
+ Read(&tmp147, &buf);
+ ctrls = static_cast<Xkb::BoolCtrl>(tmp147);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xkb::SetIndicatorMap(const Xkb::SetIndicatorMapRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& which = request.which;
+ auto& maps = request.maps;
+ size_t maps_len = maps.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 14;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // which
+ buf.Write(&which);
+
+ // maps
+ DCHECK_EQ(static_cast<size_t>(PopCount(which)), maps.size());
+ for (auto& maps_elem : maps) {
+ // maps_elem
+ {
+ auto& flags = maps_elem.flags;
+ auto& whichGroups = maps_elem.whichGroups;
+ auto& groups = maps_elem.groups;
+ auto& whichMods = maps_elem.whichMods;
+ auto& mods = maps_elem.mods;
+ auto& realMods = maps_elem.realMods;
+ auto& vmods = maps_elem.vmods;
+ auto& ctrls = maps_elem.ctrls;
+
+ // flags
+ uint8_t tmp148;
+ tmp148 = static_cast<uint8_t>(flags);
+ buf.Write(&tmp148);
+
+ // whichGroups
+ uint8_t tmp149;
+ tmp149 = static_cast<uint8_t>(whichGroups);
+ buf.Write(&tmp149);
+
+ // groups
+ uint8_t tmp150;
+ tmp150 = static_cast<uint8_t>(groups);
+ buf.Write(&tmp150);
+
+ // whichMods
+ uint8_t tmp151;
+ tmp151 = static_cast<uint8_t>(whichMods);
+ buf.Write(&tmp151);
+
+ // mods
+ uint8_t tmp152;
+ tmp152 = static_cast<uint8_t>(mods);
+ buf.Write(&tmp152);
+
+ // realMods
+ uint8_t tmp153;
+ tmp153 = static_cast<uint8_t>(realMods);
+ buf.Write(&tmp153);
+
+ // vmods
+ uint16_t tmp154;
+ tmp154 = static_cast<uint16_t>(vmods);
+ buf.Write(&tmp154);
+
+ // ctrls
+ uint32_t tmp155;
+ tmp155 = static_cast<uint32_t>(ctrls);
+ buf.Write(&tmp155);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xkb::SetIndicatorMap", false);
+}
+
+Future<void> Xkb::SetIndicatorMap(const DeviceSpec& deviceSpec,
+ const uint32_t& which,
+ const std::vector<IndicatorMap>& maps) {
+ return Xkb::SetIndicatorMap(
+ Xkb::SetIndicatorMapRequest{deviceSpec, which, maps});
+}
+
+Future<Xkb::GetNamedIndicatorReply> Xkb::GetNamedIndicator(
+ const Xkb::GetNamedIndicatorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& ledClass = request.ledClass;
+ auto& ledID = request.ledID;
+ auto& indicator = request.indicator;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 15;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // ledClass
+ uint16_t tmp156;
+ tmp156 = static_cast<uint16_t>(ledClass);
+ buf.Write(&tmp156);
+
+ // ledID
+ buf.Write(&ledID);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // indicator
+ buf.Write(&indicator);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::GetNamedIndicatorReply>(
+ &buf, "Xkb::GetNamedIndicator", false);
+}
+
+Future<Xkb::GetNamedIndicatorReply> Xkb::GetNamedIndicator(
+ const DeviceSpec& deviceSpec,
+ const LedClass& ledClass,
+ const IDSpec& ledID,
+ const Atom& indicator) {
+ return Xkb::GetNamedIndicator(
+ Xkb::GetNamedIndicatorRequest{deviceSpec, ledClass, ledID, indicator});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::GetNamedIndicatorReply> detail::ReadReply<
+ Xkb::GetNamedIndicatorReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::GetNamedIndicatorReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ auto& indicator = (*reply).indicator;
+ auto& found = (*reply).found;
+ auto& on = (*reply).on;
+ auto& realIndicator = (*reply).realIndicator;
+ auto& ndx = (*reply).ndx;
+ auto& map_flags = (*reply).map_flags;
+ auto& map_whichGroups = (*reply).map_whichGroups;
+ auto& map_groups = (*reply).map_groups;
+ auto& map_whichMods = (*reply).map_whichMods;
+ auto& map_mods = (*reply).map_mods;
+ auto& map_realMods = (*reply).map_realMods;
+ auto& map_vmod = (*reply).map_vmod;
+ auto& map_ctrls = (*reply).map_ctrls;
+ auto& supported = (*reply).supported;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // indicator
+ Read(&indicator, &buf);
+
+ // found
+ Read(&found, &buf);
+
+ // on
+ Read(&on, &buf);
+
+ // realIndicator
+ Read(&realIndicator, &buf);
+
+ // ndx
+ Read(&ndx, &buf);
+
+ // map_flags
+ uint8_t tmp157;
+ Read(&tmp157, &buf);
+ map_flags = static_cast<Xkb::IMFlag>(tmp157);
+
+ // map_whichGroups
+ uint8_t tmp158;
+ Read(&tmp158, &buf);
+ map_whichGroups = static_cast<Xkb::IMGroupsWhich>(tmp158);
+
+ // map_groups
+ uint8_t tmp159;
+ Read(&tmp159, &buf);
+ map_groups = static_cast<Xkb::SetOfGroups>(tmp159);
+
+ // map_whichMods
+ uint8_t tmp160;
+ Read(&tmp160, &buf);
+ map_whichMods = static_cast<Xkb::IMModsWhich>(tmp160);
+
+ // map_mods
+ uint8_t tmp161;
+ Read(&tmp161, &buf);
+ map_mods = static_cast<ModMask>(tmp161);
+
+ // map_realMods
+ uint8_t tmp162;
+ Read(&tmp162, &buf);
+ map_realMods = static_cast<ModMask>(tmp162);
+
+ // map_vmod
+ uint16_t tmp163;
+ Read(&tmp163, &buf);
+ map_vmod = static_cast<Xkb::VMod>(tmp163);
+
+ // map_ctrls
+ uint32_t tmp164;
+ Read(&tmp164, &buf);
+ map_ctrls = static_cast<Xkb::BoolCtrl>(tmp164);
+
+ // supported
+ Read(&supported, &buf);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xkb::SetNamedIndicator(
+ const Xkb::SetNamedIndicatorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& ledClass = request.ledClass;
+ auto& ledID = request.ledID;
+ auto& indicator = request.indicator;
+ auto& setState = request.setState;
+ auto& on = request.on;
+ auto& setMap = request.setMap;
+ auto& createMap = request.createMap;
+ auto& map_flags = request.map_flags;
+ auto& map_whichGroups = request.map_whichGroups;
+ auto& map_groups = request.map_groups;
+ auto& map_whichMods = request.map_whichMods;
+ auto& map_realMods = request.map_realMods;
+ auto& map_vmods = request.map_vmods;
+ auto& map_ctrls = request.map_ctrls;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 16;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // ledClass
+ uint16_t tmp165;
+ tmp165 = static_cast<uint16_t>(ledClass);
+ buf.Write(&tmp165);
+
+ // ledID
+ buf.Write(&ledID);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // indicator
+ buf.Write(&indicator);
+
+ // setState
+ buf.Write(&setState);
+
+ // on
+ buf.Write(&on);
+
+ // setMap
+ buf.Write(&setMap);
+
+ // createMap
+ buf.Write(&createMap);
+
+ // pad1
+ Pad(&buf, 1);
+
+ // map_flags
+ uint8_t tmp166;
+ tmp166 = static_cast<uint8_t>(map_flags);
+ buf.Write(&tmp166);
+
+ // map_whichGroups
+ uint8_t tmp167;
+ tmp167 = static_cast<uint8_t>(map_whichGroups);
+ buf.Write(&tmp167);
+
+ // map_groups
+ uint8_t tmp168;
+ tmp168 = static_cast<uint8_t>(map_groups);
+ buf.Write(&tmp168);
+
+ // map_whichMods
+ uint8_t tmp169;
+ tmp169 = static_cast<uint8_t>(map_whichMods);
+ buf.Write(&tmp169);
+
+ // map_realMods
+ uint8_t tmp170;
+ tmp170 = static_cast<uint8_t>(map_realMods);
+ buf.Write(&tmp170);
+
+ // map_vmods
+ uint16_t tmp171;
+ tmp171 = static_cast<uint16_t>(map_vmods);
+ buf.Write(&tmp171);
+
+ // map_ctrls
+ uint32_t tmp172;
+ tmp172 = static_cast<uint32_t>(map_ctrls);
+ buf.Write(&tmp172);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xkb::SetNamedIndicator", false);
+}
+
+Future<void> Xkb::SetNamedIndicator(const DeviceSpec& deviceSpec,
+ const LedClass& ledClass,
+ const IDSpec& ledID,
+ const Atom& indicator,
+ const uint8_t& setState,
+ const uint8_t& on,
+ const uint8_t& setMap,
+ const uint8_t& createMap,
+ const IMFlag& map_flags,
+ const IMGroupsWhich& map_whichGroups,
+ const SetOfGroups& map_groups,
+ const IMModsWhich& map_whichMods,
+ const ModMask& map_realMods,
+ const VMod& map_vmods,
+ const BoolCtrl& map_ctrls) {
+ return Xkb::SetNamedIndicator(Xkb::SetNamedIndicatorRequest{
+ deviceSpec, ledClass, ledID, indicator, setState, on, setMap, createMap,
+ map_flags, map_whichGroups, map_groups, map_whichMods, map_realMods,
+ map_vmods, map_ctrls});
+}
+
+Future<Xkb::GetNamesReply> Xkb::GetNames(const Xkb::GetNamesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& which = request.which;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 17;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // which
+ uint32_t tmp173;
+ tmp173 = static_cast<uint32_t>(which);
+ buf.Write(&tmp173);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::GetNamesReply>(&buf, "Xkb::GetNames",
+ false);
+}
+
+Future<Xkb::GetNamesReply> Xkb::GetNames(const DeviceSpec& deviceSpec,
+ const NameDetail& which) {
+ return Xkb::GetNames(Xkb::GetNamesRequest{deviceSpec, which});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::GetNamesReply> detail::ReadReply<Xkb::GetNamesReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::GetNamesReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ Xkb::NameDetail which{};
+ auto& minKeyCode = (*reply).minKeyCode;
+ auto& maxKeyCode = (*reply).maxKeyCode;
+ auto& nTypes = (*reply).nTypes;
+ auto& groupNames = (*reply).groupNames;
+ auto& virtualMods = (*reply).virtualMods;
+ auto& firstKey = (*reply).firstKey;
+ auto& nKeys = (*reply).nKeys;
+ auto& indicators = (*reply).indicators;
+ auto& nRadioGroups = (*reply).nRadioGroups;
+ auto& nKeyAliases = (*reply).nKeyAliases;
+ auto& nKTLevels = (*reply).nKTLevels;
+ auto& valueList = (*reply);
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // which
+ uint32_t tmp174;
+ Read(&tmp174, &buf);
+ which = static_cast<Xkb::NameDetail>(tmp174);
+
+ // minKeyCode
+ Read(&minKeyCode, &buf);
+
+ // maxKeyCode
+ Read(&maxKeyCode, &buf);
+
+ // nTypes
+ Read(&nTypes, &buf);
+
+ // groupNames
+ uint8_t tmp175;
+ Read(&tmp175, &buf);
+ groupNames = static_cast<Xkb::SetOfGroup>(tmp175);
+
+ // virtualMods
+ uint16_t tmp176;
+ Read(&tmp176, &buf);
+ virtualMods = static_cast<Xkb::VMod>(tmp176);
+
+ // firstKey
+ Read(&firstKey, &buf);
+
+ // nKeys
+ Read(&nKeys, &buf);
+
+ // indicators
+ Read(&indicators, &buf);
+
+ // nRadioGroups
+ Read(&nRadioGroups, &buf);
+
+ // nKeyAliases
+ Read(&nKeyAliases, &buf);
+
+ // nKTLevels
+ Read(&nKTLevels, &buf);
+
+ // pad0
+ Pad(&buf, 4);
+
+ // valueList
+ auto valueList_expr = which;
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::Keycodes)) {
+ valueList.keycodesName.emplace();
+ auto& keycodesName = *valueList.keycodesName;
+
+ // keycodesName
+ Read(&keycodesName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::Geometry)) {
+ valueList.geometryName.emplace();
+ auto& geometryName = *valueList.geometryName;
+
+ // geometryName
+ Read(&geometryName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::Symbols)) {
+ valueList.symbolsName.emplace();
+ auto& symbolsName = *valueList.symbolsName;
+
+ // symbolsName
+ Read(&symbolsName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::PhysSymbols)) {
+ valueList.physSymbolsName.emplace();
+ auto& physSymbolsName = *valueList.physSymbolsName;
+
+ // physSymbolsName
+ Read(&physSymbolsName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::Types)) {
+ valueList.typesName.emplace();
+ auto& typesName = *valueList.typesName;
+
+ // typesName
+ Read(&typesName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::Compat)) {
+ valueList.compatName.emplace();
+ auto& compatName = *valueList.compatName;
+
+ // compatName
+ Read(&compatName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::KeyTypeNames)) {
+ valueList.typeNames.emplace();
+ auto& typeNames = *valueList.typeNames;
+ size_t typeNames_len = typeNames.size();
+
+ // typeNames
+ typeNames.resize(nTypes);
+ for (auto& typeNames_elem : typeNames) {
+ // typeNames_elem
+ Read(&typeNames_elem, &buf);
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::KTLevelNames)) {
+ valueList.nLevelsPerType.emplace();
+ valueList.ktLevelNames.emplace();
+ auto& nLevelsPerType = *valueList.nLevelsPerType;
+ size_t nLevelsPerType_len = nLevelsPerType.size();
+ auto& ktLevelNames = *valueList.ktLevelNames;
+ size_t ktLevelNames_len = ktLevelNames.size();
+
+ // nLevelsPerType
+ nLevelsPerType.resize(nTypes);
+ for (auto& nLevelsPerType_elem : nLevelsPerType) {
+ // nLevelsPerType_elem
+ Read(&nLevelsPerType_elem, &buf);
+ }
+
+ // pad1
+ Align(&buf, 4);
+
+ // ktLevelNames
+ auto sum177_ =
+ SumOf([](auto& listelem_ref) { return listelem_ref; }, nLevelsPerType);
+ ktLevelNames.resize(sum177_);
+ for (auto& ktLevelNames_elem : ktLevelNames) {
+ // ktLevelNames_elem
+ Read(&ktLevelNames_elem, &buf);
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::IndicatorNames)) {
+ valueList.indicatorNames.emplace();
+ auto& indicatorNames = *valueList.indicatorNames;
+ size_t indicatorNames_len = indicatorNames.size();
+
+ // indicatorNames
+ indicatorNames.resize(PopCount(indicators));
+ for (auto& indicatorNames_elem : indicatorNames) {
+ // indicatorNames_elem
+ Read(&indicatorNames_elem, &buf);
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::VirtualModNames)) {
+ valueList.virtualModNames.emplace();
+ auto& virtualModNames = *valueList.virtualModNames;
+ size_t virtualModNames_len = virtualModNames.size();
+
+ // virtualModNames
+ virtualModNames.resize(PopCount(virtualMods));
+ for (auto& virtualModNames_elem : virtualModNames) {
+ // virtualModNames_elem
+ Read(&virtualModNames_elem, &buf);
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::GroupNames)) {
+ valueList.groups.emplace();
+ auto& groups = *valueList.groups;
+ size_t groups_len = groups.size();
+
+ // groups
+ groups.resize(PopCount(groupNames));
+ for (auto& groups_elem : groups) {
+ // groups_elem
+ Read(&groups_elem, &buf);
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::KeyNames)) {
+ valueList.keyNames.emplace();
+ auto& keyNames = *valueList.keyNames;
+ size_t keyNames_len = keyNames.size();
+
+ // keyNames
+ keyNames.resize(nKeys);
+ for (auto& keyNames_elem : keyNames) {
+ // keyNames_elem
+ {
+ auto& name = keyNames_elem.name;
+ size_t name_len = name.size();
+
+ // name
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+ }
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::KeyAliases)) {
+ valueList.keyAliases.emplace();
+ auto& keyAliases = *valueList.keyAliases;
+ size_t keyAliases_len = keyAliases.size();
+
+ // keyAliases
+ keyAliases.resize(nKeyAliases);
+ for (auto& keyAliases_elem : keyAliases) {
+ // keyAliases_elem
+ {
+ auto& real = keyAliases_elem.real;
+ size_t real_len = real.size();
+ auto& alias = keyAliases_elem.alias;
+ size_t alias_len = alias.size();
+
+ // real
+ for (auto& real_elem : real) {
+ // real_elem
+ Read(&real_elem, &buf);
+ }
+
+ // alias
+ for (auto& alias_elem : alias) {
+ // alias_elem
+ Read(&alias_elem, &buf);
+ }
+ }
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::RGNames)) {
+ valueList.radioGroupNames.emplace();
+ auto& radioGroupNames = *valueList.radioGroupNames;
+ size_t radioGroupNames_len = radioGroupNames.size();
+
+ // radioGroupNames
+ radioGroupNames.resize(nRadioGroups);
+ for (auto& radioGroupNames_elem : radioGroupNames) {
+ // radioGroupNames_elem
+ Read(&radioGroupNames_elem, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xkb::SetNames(const Xkb::SetNamesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& virtualMods = request.virtualMods;
+ NameDetail which{};
+ auto& firstType = request.firstType;
+ auto& nTypes = request.nTypes;
+ auto& firstKTLevelt = request.firstKTLevelt;
+ auto& nKTLevels = request.nKTLevels;
+ auto& indicators = request.indicators;
+ auto& groupNames = request.groupNames;
+ auto& nRadioGroups = request.nRadioGroups;
+ auto& firstKey = request.firstKey;
+ auto& nKeys = request.nKeys;
+ auto& nKeyAliases = request.nKeyAliases;
+ auto& totalKTLevelNames = request.totalKTLevelNames;
+ auto& values = request;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 18;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // virtualMods
+ uint16_t tmp178;
+ tmp178 = static_cast<uint16_t>(virtualMods);
+ buf.Write(&tmp178);
+
+ // which
+ SwitchVar(NameDetail::Keycodes, values.keycodesName.has_value(), true,
+ &which);
+ SwitchVar(NameDetail::Geometry, values.geometryName.has_value(), true,
+ &which);
+ SwitchVar(NameDetail::Symbols, values.symbolsName.has_value(), true, &which);
+ SwitchVar(NameDetail::PhysSymbols, values.physSymbolsName.has_value(), true,
+ &which);
+ SwitchVar(NameDetail::Types, values.typesName.has_value(), true, &which);
+ SwitchVar(NameDetail::Compat, values.compatName.has_value(), true, &which);
+ SwitchVar(NameDetail::KeyTypeNames, values.typeNames.has_value(), true,
+ &which);
+ SwitchVar(NameDetail::KTLevelNames, values.nLevelsPerType.has_value(), true,
+ &which);
+ SwitchVar(NameDetail::IndicatorNames, values.indicatorNames.has_value(), true,
+ &which);
+ SwitchVar(NameDetail::VirtualModNames, values.virtualModNames.has_value(),
+ true, &which);
+ SwitchVar(NameDetail::GroupNames, values.groups.has_value(), true, &which);
+ SwitchVar(NameDetail::KeyNames, values.keyNames.has_value(), true, &which);
+ SwitchVar(NameDetail::KeyAliases, values.keyAliases.has_value(), true,
+ &which);
+ SwitchVar(NameDetail::RGNames, values.radioGroupNames.has_value(), true,
+ &which);
+ uint32_t tmp179;
+ tmp179 = static_cast<uint32_t>(which);
+ buf.Write(&tmp179);
+
+ // firstType
+ buf.Write(&firstType);
+
+ // nTypes
+ buf.Write(&nTypes);
+
+ // firstKTLevelt
+ buf.Write(&firstKTLevelt);
+
+ // nKTLevels
+ buf.Write(&nKTLevels);
+
+ // indicators
+ buf.Write(&indicators);
+
+ // groupNames
+ uint8_t tmp180;
+ tmp180 = static_cast<uint8_t>(groupNames);
+ buf.Write(&tmp180);
+
+ // nRadioGroups
+ buf.Write(&nRadioGroups);
+
+ // firstKey
+ buf.Write(&firstKey);
+
+ // nKeys
+ buf.Write(&nKeys);
+
+ // nKeyAliases
+ buf.Write(&nKeyAliases);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // totalKTLevelNames
+ buf.Write(&totalKTLevelNames);
+
+ // values
+ auto values_expr = which;
+ if (CaseAnd(values_expr, NameDetail::Keycodes)) {
+ auto& keycodesName = *values.keycodesName;
+
+ // keycodesName
+ buf.Write(&keycodesName);
+ }
+ if (CaseAnd(values_expr, NameDetail::Geometry)) {
+ auto& geometryName = *values.geometryName;
+
+ // geometryName
+ buf.Write(&geometryName);
+ }
+ if (CaseAnd(values_expr, NameDetail::Symbols)) {
+ auto& symbolsName = *values.symbolsName;
+
+ // symbolsName
+ buf.Write(&symbolsName);
+ }
+ if (CaseAnd(values_expr, NameDetail::PhysSymbols)) {
+ auto& physSymbolsName = *values.physSymbolsName;
+
+ // physSymbolsName
+ buf.Write(&physSymbolsName);
+ }
+ if (CaseAnd(values_expr, NameDetail::Types)) {
+ auto& typesName = *values.typesName;
+
+ // typesName
+ buf.Write(&typesName);
+ }
+ if (CaseAnd(values_expr, NameDetail::Compat)) {
+ auto& compatName = *values.compatName;
+
+ // compatName
+ buf.Write(&compatName);
+ }
+ if (CaseAnd(values_expr, NameDetail::KeyTypeNames)) {
+ auto& typeNames = *values.typeNames;
+ size_t typeNames_len = typeNames.size();
+
+ // typeNames
+ DCHECK_EQ(static_cast<size_t>(nTypes), typeNames.size());
+ for (auto& typeNames_elem : typeNames) {
+ // typeNames_elem
+ buf.Write(&typeNames_elem);
+ }
+ }
+ if (CaseAnd(values_expr, NameDetail::KTLevelNames)) {
+ auto& nLevelsPerType = *values.nLevelsPerType;
+ size_t nLevelsPerType_len = nLevelsPerType.size();
+ auto& ktLevelNames = *values.ktLevelNames;
+ size_t ktLevelNames_len = ktLevelNames.size();
+
+ // nLevelsPerType
+ DCHECK_EQ(static_cast<size_t>(nTypes), nLevelsPerType.size());
+ for (auto& nLevelsPerType_elem : nLevelsPerType) {
+ // nLevelsPerType_elem
+ buf.Write(&nLevelsPerType_elem);
+ }
+
+ // pad1
+ Align(&buf, 4);
+
+ // ktLevelNames
+ auto sum181_ = SumOf([](const auto& listelem_ref) { return listelem_ref; },
+ nLevelsPerType);
+ DCHECK_EQ(static_cast<size_t>(sum181_), ktLevelNames.size());
+ for (auto& ktLevelNames_elem : ktLevelNames) {
+ // ktLevelNames_elem
+ buf.Write(&ktLevelNames_elem);
+ }
+ }
+ if (CaseAnd(values_expr, NameDetail::IndicatorNames)) {
+ auto& indicatorNames = *values.indicatorNames;
+ size_t indicatorNames_len = indicatorNames.size();
+
+ // indicatorNames
+ DCHECK_EQ(static_cast<size_t>(PopCount(indicators)), indicatorNames.size());
+ for (auto& indicatorNames_elem : indicatorNames) {
+ // indicatorNames_elem
+ buf.Write(&indicatorNames_elem);
+ }
+ }
+ if (CaseAnd(values_expr, NameDetail::VirtualModNames)) {
+ auto& virtualModNames = *values.virtualModNames;
+ size_t virtualModNames_len = virtualModNames.size();
+
+ // virtualModNames
+ DCHECK_EQ(static_cast<size_t>(PopCount(virtualMods)),
+ virtualModNames.size());
+ for (auto& virtualModNames_elem : virtualModNames) {
+ // virtualModNames_elem
+ buf.Write(&virtualModNames_elem);
+ }
+ }
+ if (CaseAnd(values_expr, NameDetail::GroupNames)) {
+ auto& groups = *values.groups;
+ size_t groups_len = groups.size();
+
+ // groups
+ DCHECK_EQ(static_cast<size_t>(PopCount(groupNames)), groups.size());
+ for (auto& groups_elem : groups) {
+ // groups_elem
+ buf.Write(&groups_elem);
+ }
+ }
+ if (CaseAnd(values_expr, NameDetail::KeyNames)) {
+ auto& keyNames = *values.keyNames;
+ size_t keyNames_len = keyNames.size();
+
+ // keyNames
+ DCHECK_EQ(static_cast<size_t>(nKeys), keyNames.size());
+ for (auto& keyNames_elem : keyNames) {
+ // keyNames_elem
+ {
+ auto& name = keyNames_elem.name;
+ size_t name_len = name.size();
+
+ // name
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+ }
+ }
+ }
+ if (CaseAnd(values_expr, NameDetail::KeyAliases)) {
+ auto& keyAliases = *values.keyAliases;
+ size_t keyAliases_len = keyAliases.size();
+
+ // keyAliases
+ DCHECK_EQ(static_cast<size_t>(nKeyAliases), keyAliases.size());
+ for (auto& keyAliases_elem : keyAliases) {
+ // keyAliases_elem
+ {
+ auto& real = keyAliases_elem.real;
+ size_t real_len = real.size();
+ auto& alias = keyAliases_elem.alias;
+ size_t alias_len = alias.size();
+
+ // real
+ for (auto& real_elem : real) {
+ // real_elem
+ buf.Write(&real_elem);
+ }
+
+ // alias
+ for (auto& alias_elem : alias) {
+ // alias_elem
+ buf.Write(&alias_elem);
+ }
+ }
+ }
+ }
+ if (CaseAnd(values_expr, NameDetail::RGNames)) {
+ auto& radioGroupNames = *values.radioGroupNames;
+ size_t radioGroupNames_len = radioGroupNames.size();
+
+ // radioGroupNames
+ DCHECK_EQ(static_cast<size_t>(nRadioGroups), radioGroupNames.size());
+ for (auto& radioGroupNames_elem : radioGroupNames) {
+ // radioGroupNames_elem
+ buf.Write(&radioGroupNames_elem);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xkb::SetNames", false);
+}
+
+Future<void> Xkb::SetNames(
+ const DeviceSpec& deviceSpec,
+ const VMod& virtualMods,
+ const uint8_t& firstType,
+ const uint8_t& nTypes,
+ const uint8_t& firstKTLevelt,
+ const uint8_t& nKTLevels,
+ const uint32_t& indicators,
+ const SetOfGroup& groupNames,
+ const uint8_t& nRadioGroups,
+ const KeyCode& firstKey,
+ const uint8_t& nKeys,
+ const uint8_t& nKeyAliases,
+ const uint16_t& totalKTLevelNames,
+ const base::Optional<Atom>& keycodesName,
+ const base::Optional<Atom>& geometryName,
+ const base::Optional<Atom>& symbolsName,
+ const base::Optional<Atom>& physSymbolsName,
+ const base::Optional<Atom>& typesName,
+ const base::Optional<Atom>& compatName,
+ const base::Optional<std::vector<Atom>>& typeNames,
+ const base::Optional<std::vector<uint8_t>>& nLevelsPerType,
+ const base::Optional<std::vector<Atom>>& ktLevelNames,
+ const base::Optional<std::vector<Atom>>& indicatorNames,
+ const base::Optional<std::vector<Atom>>& virtualModNames,
+ const base::Optional<std::vector<Atom>>& groups,
+ const base::Optional<std::vector<KeyName>>& keyNames,
+ const base::Optional<std::vector<KeyAlias>>& keyAliases,
+ const base::Optional<std::vector<Atom>>& radioGroupNames) {
+ return Xkb::SetNames(Xkb::SetNamesRequest{deviceSpec,
+ virtualMods,
+ firstType,
+ nTypes,
+ firstKTLevelt,
+ nKTLevels,
+ indicators,
+ groupNames,
+ nRadioGroups,
+ firstKey,
+ nKeys,
+ nKeyAliases,
+ totalKTLevelNames,
+ keycodesName,
+ geometryName,
+ symbolsName,
+ physSymbolsName,
+ typesName,
+ compatName,
+ typeNames,
+ nLevelsPerType,
+ ktLevelNames,
+ indicatorNames,
+ virtualModNames,
+ groups,
+ keyNames,
+ keyAliases,
+ radioGroupNames});
+}
+
+Future<Xkb::PerClientFlagsReply> Xkb::PerClientFlags(
+ const Xkb::PerClientFlagsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& change = request.change;
+ auto& value = request.value;
+ auto& ctrlsToChange = request.ctrlsToChange;
+ auto& autoCtrls = request.autoCtrls;
+ auto& autoCtrlsValues = request.autoCtrlsValues;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 21;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // change
+ uint32_t tmp182;
+ tmp182 = static_cast<uint32_t>(change);
+ buf.Write(&tmp182);
+
+ // value
+ uint32_t tmp183;
+ tmp183 = static_cast<uint32_t>(value);
+ buf.Write(&tmp183);
+
+ // ctrlsToChange
+ uint32_t tmp184;
+ tmp184 = static_cast<uint32_t>(ctrlsToChange);
+ buf.Write(&tmp184);
+
+ // autoCtrls
+ uint32_t tmp185;
+ tmp185 = static_cast<uint32_t>(autoCtrls);
+ buf.Write(&tmp185);
+
+ // autoCtrlsValues
+ uint32_t tmp186;
+ tmp186 = static_cast<uint32_t>(autoCtrlsValues);
+ buf.Write(&tmp186);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::PerClientFlagsReply>(
+ &buf, "Xkb::PerClientFlags", false);
+}
+
+Future<Xkb::PerClientFlagsReply> Xkb::PerClientFlags(
+ const DeviceSpec& deviceSpec,
+ const PerClientFlag& change,
+ const PerClientFlag& value,
+ const BoolCtrl& ctrlsToChange,
+ const BoolCtrl& autoCtrls,
+ const BoolCtrl& autoCtrlsValues) {
+ return Xkb::PerClientFlags(Xkb::PerClientFlagsRequest{
+ deviceSpec, change, value, ctrlsToChange, autoCtrls, autoCtrlsValues});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::PerClientFlagsReply> detail::ReadReply<
+ Xkb::PerClientFlagsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::PerClientFlagsReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ auto& supported = (*reply).supported;
+ auto& value = (*reply).value;
+ auto& autoCtrls = (*reply).autoCtrls;
+ auto& autoCtrlsValues = (*reply).autoCtrlsValues;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // supported
+ uint32_t tmp187;
+ Read(&tmp187, &buf);
+ supported = static_cast<Xkb::PerClientFlag>(tmp187);
+
+ // value
+ uint32_t tmp188;
+ Read(&tmp188, &buf);
+ value = static_cast<Xkb::PerClientFlag>(tmp188);
+
+ // autoCtrls
+ uint32_t tmp189;
+ Read(&tmp189, &buf);
+ autoCtrls = static_cast<Xkb::BoolCtrl>(tmp189);
+
+ // autoCtrlsValues
+ uint32_t tmp190;
+ Read(&tmp190, &buf);
+ autoCtrlsValues = static_cast<Xkb::BoolCtrl>(tmp190);
+
+ // pad0
+ Pad(&buf, 8);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xkb::ListComponentsReply> Xkb::ListComponents(
+ const Xkb::ListComponentsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& maxNames = request.maxNames;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 22;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // maxNames
+ buf.Write(&maxNames);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::ListComponentsReply>(
+ &buf, "Xkb::ListComponents", false);
+}
+
+Future<Xkb::ListComponentsReply> Xkb::ListComponents(
+ const DeviceSpec& deviceSpec,
+ const uint16_t& maxNames) {
+ return Xkb::ListComponents(Xkb::ListComponentsRequest{deviceSpec, maxNames});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::ListComponentsReply> detail::ReadReply<
+ Xkb::ListComponentsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::ListComponentsReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ uint16_t nKeymaps{};
+ uint16_t nKeycodes{};
+ uint16_t nTypes{};
+ uint16_t nCompatMaps{};
+ uint16_t nSymbols{};
+ uint16_t nGeometries{};
+ auto& extra = (*reply).extra;
+ auto& keymaps = (*reply).keymaps;
+ size_t keymaps_len = keymaps.size();
+ auto& keycodes = (*reply).keycodes;
+ size_t keycodes_len = keycodes.size();
+ auto& types = (*reply).types;
+ size_t types_len = types.size();
+ auto& compatMaps = (*reply).compatMaps;
+ size_t compatMaps_len = compatMaps.size();
+ auto& symbols = (*reply).symbols;
+ size_t symbols_len = symbols.size();
+ auto& geometries = (*reply).geometries;
+ size_t geometries_len = geometries.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // nKeymaps
+ Read(&nKeymaps, &buf);
+
+ // nKeycodes
+ Read(&nKeycodes, &buf);
+
+ // nTypes
+ Read(&nTypes, &buf);
+
+ // nCompatMaps
+ Read(&nCompatMaps, &buf);
+
+ // nSymbols
+ Read(&nSymbols, &buf);
+
+ // nGeometries
+ Read(&nGeometries, &buf);
+
+ // extra
+ Read(&extra, &buf);
+
+ // pad0
+ Pad(&buf, 10);
+
+ // keymaps
+ keymaps.resize(nKeymaps);
+ for (auto& keymaps_elem : keymaps) {
+ // keymaps_elem
+ {
+ auto& flags = keymaps_elem.flags;
+ uint16_t length{};
+ auto& string = keymaps_elem.string;
+ size_t string_len = string.size();
+
+ // flags
+ Read(&flags, &buf);
+
+ // length
+ Read(&length, &buf);
+
+ // string
+ string.resize(length);
+ for (auto& string_elem : string) {
+ // string_elem
+ Read(&string_elem, &buf);
+ }
+
+ // pad0
+ Align(&buf, 2);
+ }
+ }
+
+ // keycodes
+ keycodes.resize(nKeycodes);
+ for (auto& keycodes_elem : keycodes) {
+ // keycodes_elem
+ {
+ auto& flags = keycodes_elem.flags;
+ uint16_t length{};
+ auto& string = keycodes_elem.string;
+ size_t string_len = string.size();
+
+ // flags
+ Read(&flags, &buf);
+
+ // length
+ Read(&length, &buf);
+
+ // string
+ string.resize(length);
+ for (auto& string_elem : string) {
+ // string_elem
+ Read(&string_elem, &buf);
+ }
+
+ // pad0
+ Align(&buf, 2);
+ }
+ }
+
+ // types
+ types.resize(nTypes);
+ for (auto& types_elem : types) {
+ // types_elem
+ {
+ auto& flags = types_elem.flags;
+ uint16_t length{};
+ auto& string = types_elem.string;
+ size_t string_len = string.size();
+
+ // flags
+ Read(&flags, &buf);
+
+ // length
+ Read(&length, &buf);
+
+ // string
+ string.resize(length);
+ for (auto& string_elem : string) {
+ // string_elem
+ Read(&string_elem, &buf);
+ }
+
+ // pad0
+ Align(&buf, 2);
+ }
+ }
+
+ // compatMaps
+ compatMaps.resize(nCompatMaps);
+ for (auto& compatMaps_elem : compatMaps) {
+ // compatMaps_elem
+ {
+ auto& flags = compatMaps_elem.flags;
+ uint16_t length{};
+ auto& string = compatMaps_elem.string;
+ size_t string_len = string.size();
+
+ // flags
+ Read(&flags, &buf);
+
+ // length
+ Read(&length, &buf);
+
+ // string
+ string.resize(length);
+ for (auto& string_elem : string) {
+ // string_elem
+ Read(&string_elem, &buf);
+ }
+
+ // pad0
+ Align(&buf, 2);
+ }
+ }
+
+ // symbols
+ symbols.resize(nSymbols);
+ for (auto& symbols_elem : symbols) {
+ // symbols_elem
+ {
+ auto& flags = symbols_elem.flags;
+ uint16_t length{};
+ auto& string = symbols_elem.string;
+ size_t string_len = string.size();
+
+ // flags
+ Read(&flags, &buf);
+
+ // length
+ Read(&length, &buf);
+
+ // string
+ string.resize(length);
+ for (auto& string_elem : string) {
+ // string_elem
+ Read(&string_elem, &buf);
+ }
+
+ // pad0
+ Align(&buf, 2);
+ }
+ }
+
+ // geometries
+ geometries.resize(nGeometries);
+ for (auto& geometries_elem : geometries) {
+ // geometries_elem
+ {
+ auto& flags = geometries_elem.flags;
+ uint16_t length{};
+ auto& string = geometries_elem.string;
+ size_t string_len = string.size();
+
+ // flags
+ Read(&flags, &buf);
+
+ // length
+ Read(&length, &buf);
+
+ // string
+ string.resize(length);
+ for (auto& string_elem : string) {
+ // string_elem
+ Read(&string_elem, &buf);
+ }
+
+ // pad0
+ Align(&buf, 2);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xkb::GetKbdByNameReply> Xkb::GetKbdByName(
+ const Xkb::GetKbdByNameRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& need = request.need;
+ auto& want = request.want;
+ auto& load = request.load;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 23;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // need
+ uint16_t tmp191;
+ tmp191 = static_cast<uint16_t>(need);
+ buf.Write(&tmp191);
+
+ // want
+ uint16_t tmp192;
+ tmp192 = static_cast<uint16_t>(want);
+ buf.Write(&tmp192);
+
+ // load
+ buf.Write(&load);
+
+ // pad0
+ Pad(&buf, 1);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::GetKbdByNameReply>(
+ &buf, "Xkb::GetKbdByName", false);
+}
+
+Future<Xkb::GetKbdByNameReply> Xkb::GetKbdByName(const DeviceSpec& deviceSpec,
+ const GBNDetail& need,
+ const GBNDetail& want,
+ const uint8_t& load) {
+ return Xkb::GetKbdByName(
+ Xkb::GetKbdByNameRequest{deviceSpec, need, want, load});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::GetKbdByNameReply> detail::ReadReply<
+ Xkb::GetKbdByNameReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::GetKbdByNameReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ auto& minKeyCode = (*reply).minKeyCode;
+ auto& maxKeyCode = (*reply).maxKeyCode;
+ auto& loaded = (*reply).loaded;
+ auto& newKeyboard = (*reply).newKeyboard;
+ auto& found = (*reply).found;
+ Xkb::GBNDetail reported{};
+ auto& replies = (*reply);
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // minKeyCode
+ Read(&minKeyCode, &buf);
+
+ // maxKeyCode
+ Read(&maxKeyCode, &buf);
+
+ // loaded
+ Read(&loaded, &buf);
+
+ // newKeyboard
+ Read(&newKeyboard, &buf);
+
+ // found
+ uint16_t tmp193;
+ Read(&tmp193, &buf);
+ found = static_cast<Xkb::GBNDetail>(tmp193);
+
+ // reported
+ uint16_t tmp194;
+ Read(&tmp194, &buf);
+ reported = static_cast<Xkb::GBNDetail>(tmp194);
+
+ // pad0
+ Pad(&buf, 16);
+
+ // replies
+ auto replies_expr = reported;
+ if (CaseAnd(replies_expr, Xkb::GBNDetail::Types) ||
+ CaseAnd(replies_expr, Xkb::GBNDetail::ClientSymbols) ||
+ CaseAnd(replies_expr, Xkb::GBNDetail::ServerSymbols)) {
+ replies.types.emplace();
+ auto& getmap_type = (*replies.types).getmap_type;
+ auto& typeDeviceID = (*replies.types).typeDeviceID;
+ auto& getmap_sequence = (*replies.types).getmap_sequence;
+ auto& getmap_length = (*replies.types).getmap_length;
+ auto& typeMinKeyCode = (*replies.types).typeMinKeyCode;
+ auto& typeMaxKeyCode = (*replies.types).typeMaxKeyCode;
+ Xkb::MapPart present{};
+ auto& firstType = (*replies.types).firstType;
+ auto& nTypes = (*replies.types).nTypes;
+ auto& totalTypes = (*replies.types).totalTypes;
+ auto& firstKeySym = (*replies.types).firstKeySym;
+ auto& totalSyms = (*replies.types).totalSyms;
+ auto& nKeySyms = (*replies.types).nKeySyms;
+ auto& firstKeyAction = (*replies.types).firstKeyAction;
+ auto& totalActions = (*replies.types).totalActions;
+ auto& nKeyActions = (*replies.types).nKeyActions;
+ auto& firstKeyBehavior = (*replies.types).firstKeyBehavior;
+ auto& nKeyBehaviors = (*replies.types).nKeyBehaviors;
+ auto& totalKeyBehaviors = (*replies.types).totalKeyBehaviors;
+ auto& firstKeyExplicit = (*replies.types).firstKeyExplicit;
+ auto& nKeyExplicit = (*replies.types).nKeyExplicit;
+ auto& totalKeyExplicit = (*replies.types).totalKeyExplicit;
+ auto& firstModMapKey = (*replies.types).firstModMapKey;
+ auto& nModMapKeys = (*replies.types).nModMapKeys;
+ auto& totalModMapKeys = (*replies.types).totalModMapKeys;
+ auto& firstVModMapKey = (*replies.types).firstVModMapKey;
+ auto& nVModMapKeys = (*replies.types).nVModMapKeys;
+ auto& totalVModMapKeys = (*replies.types).totalVModMapKeys;
+ auto& virtualMods = (*replies.types).virtualMods;
+ auto& map = (*replies.types);
+
+ // getmap_type
+ Read(&getmap_type, &buf);
+
+ // typeDeviceID
+ Read(&typeDeviceID, &buf);
+
+ // getmap_sequence
+ Read(&getmap_sequence, &buf);
+
+ // getmap_length
+ Read(&getmap_length, &buf);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // typeMinKeyCode
+ Read(&typeMinKeyCode, &buf);
+
+ // typeMaxKeyCode
+ Read(&typeMaxKeyCode, &buf);
+
+ // present
+ uint16_t tmp195;
+ Read(&tmp195, &buf);
+ present = static_cast<Xkb::MapPart>(tmp195);
+
+ // firstType
+ Read(&firstType, &buf);
+
+ // nTypes
+ Read(&nTypes, &buf);
+
+ // totalTypes
+ Read(&totalTypes, &buf);
+
+ // firstKeySym
+ Read(&firstKeySym, &buf);
+
+ // totalSyms
+ Read(&totalSyms, &buf);
+
+ // nKeySyms
+ Read(&nKeySyms, &buf);
+
+ // firstKeyAction
+ Read(&firstKeyAction, &buf);
+
+ // totalActions
+ Read(&totalActions, &buf);
+
+ // nKeyActions
+ Read(&nKeyActions, &buf);
+
+ // firstKeyBehavior
+ Read(&firstKeyBehavior, &buf);
+
+ // nKeyBehaviors
+ Read(&nKeyBehaviors, &buf);
+
+ // totalKeyBehaviors
+ Read(&totalKeyBehaviors, &buf);
+
+ // firstKeyExplicit
+ Read(&firstKeyExplicit, &buf);
+
+ // nKeyExplicit
+ Read(&nKeyExplicit, &buf);
+
+ // totalKeyExplicit
+ Read(&totalKeyExplicit, &buf);
+
+ // firstModMapKey
+ Read(&firstModMapKey, &buf);
+
+ // nModMapKeys
+ Read(&nModMapKeys, &buf);
+
+ // totalModMapKeys
+ Read(&totalModMapKeys, &buf);
+
+ // firstVModMapKey
+ Read(&firstVModMapKey, &buf);
+
+ // nVModMapKeys
+ Read(&nVModMapKeys, &buf);
+
+ // totalVModMapKeys
+ Read(&totalVModMapKeys, &buf);
+
+ // pad2
+ Pad(&buf, 1);
+
+ // virtualMods
+ uint16_t tmp196;
+ Read(&tmp196, &buf);
+ virtualMods = static_cast<Xkb::VMod>(tmp196);
+
+ // map
+ auto map_expr = present;
+ if (CaseAnd(map_expr, Xkb::MapPart::KeyTypes)) {
+ map.types_rtrn.emplace();
+ auto& types_rtrn = *map.types_rtrn;
+ size_t types_rtrn_len = types_rtrn.size();
+
+ // types_rtrn
+ types_rtrn.resize(nTypes);
+ for (auto& types_rtrn_elem : types_rtrn) {
+ // types_rtrn_elem
+ {
+ auto& mods_mask = types_rtrn_elem.mods_mask;
+ auto& mods_mods = types_rtrn_elem.mods_mods;
+ auto& mods_vmods = types_rtrn_elem.mods_vmods;
+ auto& numLevels = types_rtrn_elem.numLevels;
+ uint8_t nMapEntries{};
+ auto& hasPreserve = types_rtrn_elem.hasPreserve;
+ auto& map = types_rtrn_elem.map;
+ size_t map_len = map.size();
+ auto& preserve = types_rtrn_elem.preserve;
+ size_t preserve_len = preserve.size();
+
+ // mods_mask
+ uint8_t tmp197;
+ Read(&tmp197, &buf);
+ mods_mask = static_cast<ModMask>(tmp197);
+
+ // mods_mods
+ uint8_t tmp198;
+ Read(&tmp198, &buf);
+ mods_mods = static_cast<ModMask>(tmp198);
+
+ // mods_vmods
+ uint16_t tmp199;
+ Read(&tmp199, &buf);
+ mods_vmods = static_cast<Xkb::VMod>(tmp199);
+
+ // numLevels
+ Read(&numLevels, &buf);
+
+ // nMapEntries
+ Read(&nMapEntries, &buf);
+
+ // hasPreserve
+ Read(&hasPreserve, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // map
+ map.resize(nMapEntries);
+ for (auto& map_elem : map) {
+ // map_elem
+ {
+ auto& active = map_elem.active;
+ auto& mods_mask = map_elem.mods_mask;
+ auto& level = map_elem.level;
+ auto& mods_mods = map_elem.mods_mods;
+ auto& mods_vmods = map_elem.mods_vmods;
+
+ // active
+ Read(&active, &buf);
+
+ // mods_mask
+ uint8_t tmp200;
+ Read(&tmp200, &buf);
+ mods_mask = static_cast<ModMask>(tmp200);
+
+ // level
+ Read(&level, &buf);
+
+ // mods_mods
+ uint8_t tmp201;
+ Read(&tmp201, &buf);
+ mods_mods = static_cast<ModMask>(tmp201);
+
+ // mods_vmods
+ uint16_t tmp202;
+ Read(&tmp202, &buf);
+ mods_vmods = static_cast<Xkb::VMod>(tmp202);
+
+ // pad0
+ Pad(&buf, 2);
+ }
+ }
+
+ // preserve
+ preserve.resize((hasPreserve) * (nMapEntries));
+ for (auto& preserve_elem : preserve) {
+ // preserve_elem
+ {
+ auto& mask = preserve_elem.mask;
+ auto& realMods = preserve_elem.realMods;
+ auto& vmods = preserve_elem.vmods;
+
+ // mask
+ uint8_t tmp203;
+ Read(&tmp203, &buf);
+ mask = static_cast<ModMask>(tmp203);
+
+ // realMods
+ uint8_t tmp204;
+ Read(&tmp204, &buf);
+ realMods = static_cast<ModMask>(tmp204);
+
+ // vmods
+ uint16_t tmp205;
+ Read(&tmp205, &buf);
+ vmods = static_cast<Xkb::VMod>(tmp205);
+ }
+ }
+ }
+ }
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::KeySyms)) {
+ map.syms_rtrn.emplace();
+ auto& syms_rtrn = *map.syms_rtrn;
+ size_t syms_rtrn_len = syms_rtrn.size();
+
+ // syms_rtrn
+ syms_rtrn.resize(nKeySyms);
+ for (auto& syms_rtrn_elem : syms_rtrn) {
+ // syms_rtrn_elem
+ {
+ auto& kt_index = syms_rtrn_elem.kt_index;
+ size_t kt_index_len = kt_index.size();
+ auto& groupInfo = syms_rtrn_elem.groupInfo;
+ auto& width = syms_rtrn_elem.width;
+ uint16_t nSyms{};
+ auto& syms = syms_rtrn_elem.syms;
+ size_t syms_len = syms.size();
+
+ // kt_index
+ for (auto& kt_index_elem : kt_index) {
+ // kt_index_elem
+ Read(&kt_index_elem, &buf);
+ }
+
+ // groupInfo
+ Read(&groupInfo, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // nSyms
+ Read(&nSyms, &buf);
+
+ // syms
+ syms.resize(nSyms);
+ for (auto& syms_elem : syms) {
+ // syms_elem
+ Read(&syms_elem, &buf);
+ }
+ }
+ }
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::KeyActions)) {
+ map.acts_rtrn_count.emplace();
+ map.acts_rtrn_acts.emplace();
+ auto& acts_rtrn_count = *map.acts_rtrn_count;
+ size_t acts_rtrn_count_len = acts_rtrn_count.size();
+ auto& acts_rtrn_acts = *map.acts_rtrn_acts;
+ size_t acts_rtrn_acts_len = acts_rtrn_acts.size();
+
+ // acts_rtrn_count
+ acts_rtrn_count.resize(nKeyActions);
+ for (auto& acts_rtrn_count_elem : acts_rtrn_count) {
+ // acts_rtrn_count_elem
+ Read(&acts_rtrn_count_elem, &buf);
+ }
+
+ // pad3
+ Align(&buf, 4);
+
+ // acts_rtrn_acts
+ acts_rtrn_acts.resize(totalActions);
+ for (auto& acts_rtrn_acts_elem : acts_rtrn_acts) {
+ // acts_rtrn_acts_elem
+ Read(&acts_rtrn_acts_elem, &buf);
+ }
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::KeyBehaviors)) {
+ map.behaviors_rtrn.emplace();
+ auto& behaviors_rtrn = *map.behaviors_rtrn;
+ size_t behaviors_rtrn_len = behaviors_rtrn.size();
+
+ // behaviors_rtrn
+ behaviors_rtrn.resize(totalKeyBehaviors);
+ for (auto& behaviors_rtrn_elem : behaviors_rtrn) {
+ // behaviors_rtrn_elem
+ {
+ auto& keycode = behaviors_rtrn_elem.keycode;
+ auto& behavior = behaviors_rtrn_elem.behavior;
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // behavior
+ Read(&behavior, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+ }
+ }
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::VirtualMods)) {
+ map.vmods_rtrn.emplace();
+ auto& vmods_rtrn = *map.vmods_rtrn;
+ size_t vmods_rtrn_len = vmods_rtrn.size();
+
+ // vmods_rtrn
+ vmods_rtrn.resize(PopCount(virtualMods));
+ for (auto& vmods_rtrn_elem : vmods_rtrn) {
+ // vmods_rtrn_elem
+ uint8_t tmp206;
+ Read(&tmp206, &buf);
+ vmods_rtrn_elem = static_cast<ModMask>(tmp206);
+ }
+
+ // pad4
+ Align(&buf, 4);
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::ExplicitComponents)) {
+ map.explicit_rtrn.emplace();
+ auto& explicit_rtrn = *map.explicit_rtrn;
+ size_t explicit_rtrn_len = explicit_rtrn.size();
+
+ // explicit_rtrn
+ explicit_rtrn.resize(totalKeyExplicit);
+ for (auto& explicit_rtrn_elem : explicit_rtrn) {
+ // explicit_rtrn_elem
+ {
+ auto& keycode = explicit_rtrn_elem.keycode;
+ auto& c_explicit = explicit_rtrn_elem.c_explicit;
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // c_explicit
+ uint8_t tmp207;
+ Read(&tmp207, &buf);
+ c_explicit = static_cast<Xkb::Explicit>(tmp207);
+ }
+ }
+
+ // pad5
+ Align(&buf, 4);
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::ModifierMap)) {
+ map.modmap_rtrn.emplace();
+ auto& modmap_rtrn = *map.modmap_rtrn;
+ size_t modmap_rtrn_len = modmap_rtrn.size();
+
+ // modmap_rtrn
+ modmap_rtrn.resize(totalModMapKeys);
+ for (auto& modmap_rtrn_elem : modmap_rtrn) {
+ // modmap_rtrn_elem
+ {
+ auto& keycode = modmap_rtrn_elem.keycode;
+ auto& mods = modmap_rtrn_elem.mods;
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // mods
+ uint8_t tmp208;
+ Read(&tmp208, &buf);
+ mods = static_cast<ModMask>(tmp208);
+ }
+ }
+
+ // pad6
+ Align(&buf, 4);
+ }
+ if (CaseAnd(map_expr, Xkb::MapPart::VirtualModMap)) {
+ map.vmodmap_rtrn.emplace();
+ auto& vmodmap_rtrn = *map.vmodmap_rtrn;
+ size_t vmodmap_rtrn_len = vmodmap_rtrn.size();
+
+ // vmodmap_rtrn
+ vmodmap_rtrn.resize(totalVModMapKeys);
+ for (auto& vmodmap_rtrn_elem : vmodmap_rtrn) {
+ // vmodmap_rtrn_elem
+ {
+ auto& keycode = vmodmap_rtrn_elem.keycode;
+ auto& vmods = vmodmap_rtrn_elem.vmods;
+
+ // keycode
+ Read(&keycode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // vmods
+ uint16_t tmp209;
+ Read(&tmp209, &buf);
+ vmods = static_cast<Xkb::VMod>(tmp209);
+ }
+ }
+ }
+ }
+ if (CaseAnd(replies_expr, Xkb::GBNDetail::CompatMap)) {
+ replies.compat_map.emplace();
+ auto& compatmap_type = (*replies.compat_map).compatmap_type;
+ auto& compatDeviceID = (*replies.compat_map).compatDeviceID;
+ auto& compatmap_sequence = (*replies.compat_map).compatmap_sequence;
+ auto& compatmap_length = (*replies.compat_map).compatmap_length;
+ auto& groupsRtrn = (*replies.compat_map).groupsRtrn;
+ auto& firstSIRtrn = (*replies.compat_map).firstSIRtrn;
+ uint16_t nSIRtrn{};
+ auto& nTotalSI = (*replies.compat_map).nTotalSI;
+ auto& si_rtrn = (*replies.compat_map).si_rtrn;
+ size_t si_rtrn_len = si_rtrn.size();
+ auto& group_rtrn = (*replies.compat_map).group_rtrn;
+ size_t group_rtrn_len = group_rtrn.size();
+
+ // compatmap_type
+ Read(&compatmap_type, &buf);
+
+ // compatDeviceID
+ Read(&compatDeviceID, &buf);
+
+ // compatmap_sequence
+ Read(&compatmap_sequence, &buf);
+
+ // compatmap_length
+ Read(&compatmap_length, &buf);
+
+ // groupsRtrn
+ uint8_t tmp210;
+ Read(&tmp210, &buf);
+ groupsRtrn = static_cast<Xkb::SetOfGroup>(tmp210);
+
+ // pad7
+ Pad(&buf, 1);
+
+ // firstSIRtrn
+ Read(&firstSIRtrn, &buf);
+
+ // nSIRtrn
+ Read(&nSIRtrn, &buf);
+
+ // nTotalSI
+ Read(&nTotalSI, &buf);
+
+ // pad8
+ Pad(&buf, 16);
+
+ // si_rtrn
+ si_rtrn.resize(nSIRtrn);
+ for (auto& si_rtrn_elem : si_rtrn) {
+ // si_rtrn_elem
+ {
+ auto& sym = si_rtrn_elem.sym;
+ auto& mods = si_rtrn_elem.mods;
+ auto& match = si_rtrn_elem.match;
+ auto& virtualMod = si_rtrn_elem.virtualMod;
+ auto& flags = si_rtrn_elem.flags;
+ auto& action = si_rtrn_elem.action;
+
+ // sym
+ Read(&sym, &buf);
+
+ // mods
+ uint8_t tmp211;
+ Read(&tmp211, &buf);
+ mods = static_cast<ModMask>(tmp211);
+
+ // match
+ Read(&match, &buf);
+
+ // virtualMod
+ uint8_t tmp212;
+ Read(&tmp212, &buf);
+ virtualMod = static_cast<Xkb::VModsLow>(tmp212);
+
+ // flags
+ Read(&flags, &buf);
+
+ // action
+ {
+ auto& type = action.type;
+ auto& data = action.data;
+ size_t data_len = data.size();
+
+ // type
+ uint8_t tmp213;
+ Read(&tmp213, &buf);
+ type = static_cast<Xkb::SAType>(tmp213);
+
+ // data
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+ }
+ }
+ }
+
+ // group_rtrn
+ group_rtrn.resize(PopCount(groupsRtrn));
+ for (auto& group_rtrn_elem : group_rtrn) {
+ // group_rtrn_elem
+ {
+ auto& mask = group_rtrn_elem.mask;
+ auto& realMods = group_rtrn_elem.realMods;
+ auto& vmods = group_rtrn_elem.vmods;
+
+ // mask
+ uint8_t tmp214;
+ Read(&tmp214, &buf);
+ mask = static_cast<ModMask>(tmp214);
+
+ // realMods
+ uint8_t tmp215;
+ Read(&tmp215, &buf);
+ realMods = static_cast<ModMask>(tmp215);
+
+ // vmods
+ uint16_t tmp216;
+ Read(&tmp216, &buf);
+ vmods = static_cast<Xkb::VMod>(tmp216);
+ }
+ }
+ }
+ if (CaseAnd(replies_expr, Xkb::GBNDetail::IndicatorMaps)) {
+ replies.indicator_maps.emplace();
+ auto& indicatormap_type = (*replies.indicator_maps).indicatormap_type;
+ auto& indicatorDeviceID = (*replies.indicator_maps).indicatorDeviceID;
+ auto& indicatormap_sequence =
+ (*replies.indicator_maps).indicatormap_sequence;
+ auto& indicatormap_length = (*replies.indicator_maps).indicatormap_length;
+ auto& which = (*replies.indicator_maps).which;
+ auto& realIndicators = (*replies.indicator_maps).realIndicators;
+ uint8_t nIndicators{};
+ auto& maps = (*replies.indicator_maps).maps;
+ size_t maps_len = maps.size();
+
+ // indicatormap_type
+ Read(&indicatormap_type, &buf);
+
+ // indicatorDeviceID
+ Read(&indicatorDeviceID, &buf);
+
+ // indicatormap_sequence
+ Read(&indicatormap_sequence, &buf);
+
+ // indicatormap_length
+ Read(&indicatormap_length, &buf);
+
+ // which
+ Read(&which, &buf);
+
+ // realIndicators
+ Read(&realIndicators, &buf);
+
+ // nIndicators
+ Read(&nIndicators, &buf);
+
+ // pad9
+ Pad(&buf, 15);
+
+ // maps
+ maps.resize(nIndicators);
+ for (auto& maps_elem : maps) {
+ // maps_elem
+ {
+ auto& flags = maps_elem.flags;
+ auto& whichGroups = maps_elem.whichGroups;
+ auto& groups = maps_elem.groups;
+ auto& whichMods = maps_elem.whichMods;
+ auto& mods = maps_elem.mods;
+ auto& realMods = maps_elem.realMods;
+ auto& vmods = maps_elem.vmods;
+ auto& ctrls = maps_elem.ctrls;
+
+ // flags
+ uint8_t tmp217;
+ Read(&tmp217, &buf);
+ flags = static_cast<Xkb::IMFlag>(tmp217);
+
+ // whichGroups
+ uint8_t tmp218;
+ Read(&tmp218, &buf);
+ whichGroups = static_cast<Xkb::IMGroupsWhich>(tmp218);
+
+ // groups
+ uint8_t tmp219;
+ Read(&tmp219, &buf);
+ groups = static_cast<Xkb::SetOfGroup>(tmp219);
+
+ // whichMods
+ uint8_t tmp220;
+ Read(&tmp220, &buf);
+ whichMods = static_cast<Xkb::IMModsWhich>(tmp220);
+
+ // mods
+ uint8_t tmp221;
+ Read(&tmp221, &buf);
+ mods = static_cast<ModMask>(tmp221);
+
+ // realMods
+ uint8_t tmp222;
+ Read(&tmp222, &buf);
+ realMods = static_cast<ModMask>(tmp222);
+
+ // vmods
+ uint16_t tmp223;
+ Read(&tmp223, &buf);
+ vmods = static_cast<Xkb::VMod>(tmp223);
+
+ // ctrls
+ uint32_t tmp224;
+ Read(&tmp224, &buf);
+ ctrls = static_cast<Xkb::BoolCtrl>(tmp224);
+ }
+ }
+ }
+ if (CaseAnd(replies_expr, Xkb::GBNDetail::KeyNames) ||
+ CaseAnd(replies_expr, Xkb::GBNDetail::OtherNames)) {
+ replies.key_names.emplace();
+ auto& keyname_type = (*replies.key_names).keyname_type;
+ auto& keyDeviceID = (*replies.key_names).keyDeviceID;
+ auto& keyname_sequence = (*replies.key_names).keyname_sequence;
+ auto& keyname_length = (*replies.key_names).keyname_length;
+ Xkb::NameDetail which{};
+ auto& keyMinKeyCode = (*replies.key_names).keyMinKeyCode;
+ auto& keyMaxKeyCode = (*replies.key_names).keyMaxKeyCode;
+ auto& nTypes = (*replies.key_names).nTypes;
+ auto& groupNames = (*replies.key_names).groupNames;
+ auto& virtualMods = (*replies.key_names).virtualMods;
+ auto& firstKey = (*replies.key_names).firstKey;
+ auto& nKeys = (*replies.key_names).nKeys;
+ auto& indicators = (*replies.key_names).indicators;
+ auto& nRadioGroups = (*replies.key_names).nRadioGroups;
+ auto& nKeyAliases = (*replies.key_names).nKeyAliases;
+ auto& nKTLevels = (*replies.key_names).nKTLevels;
+ auto& valueList = (*replies.key_names);
+
+ // keyname_type
+ Read(&keyname_type, &buf);
+
+ // keyDeviceID
+ Read(&keyDeviceID, &buf);
+
+ // keyname_sequence
+ Read(&keyname_sequence, &buf);
+
+ // keyname_length
+ Read(&keyname_length, &buf);
+
+ // which
+ uint32_t tmp225;
+ Read(&tmp225, &buf);
+ which = static_cast<Xkb::NameDetail>(tmp225);
+
+ // keyMinKeyCode
+ Read(&keyMinKeyCode, &buf);
+
+ // keyMaxKeyCode
+ Read(&keyMaxKeyCode, &buf);
+
+ // nTypes
+ Read(&nTypes, &buf);
+
+ // groupNames
+ uint8_t tmp226;
+ Read(&tmp226, &buf);
+ groupNames = static_cast<Xkb::SetOfGroup>(tmp226);
+
+ // virtualMods
+ uint16_t tmp227;
+ Read(&tmp227, &buf);
+ virtualMods = static_cast<Xkb::VMod>(tmp227);
+
+ // firstKey
+ Read(&firstKey, &buf);
+
+ // nKeys
+ Read(&nKeys, &buf);
+
+ // indicators
+ Read(&indicators, &buf);
+
+ // nRadioGroups
+ Read(&nRadioGroups, &buf);
+
+ // nKeyAliases
+ Read(&nKeyAliases, &buf);
+
+ // nKTLevels
+ Read(&nKTLevels, &buf);
+
+ // pad10
+ Pad(&buf, 4);
+
+ // valueList
+ auto valueList_expr = which;
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::Keycodes)) {
+ valueList.keycodesName.emplace();
+ auto& keycodesName = *valueList.keycodesName;
+
+ // keycodesName
+ Read(&keycodesName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::Geometry)) {
+ valueList.geometryName.emplace();
+ auto& geometryName = *valueList.geometryName;
+
+ // geometryName
+ Read(&geometryName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::Symbols)) {
+ valueList.symbolsName.emplace();
+ auto& symbolsName = *valueList.symbolsName;
+
+ // symbolsName
+ Read(&symbolsName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::PhysSymbols)) {
+ valueList.physSymbolsName.emplace();
+ auto& physSymbolsName = *valueList.physSymbolsName;
+
+ // physSymbolsName
+ Read(&physSymbolsName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::Types)) {
+ valueList.typesName.emplace();
+ auto& typesName = *valueList.typesName;
+
+ // typesName
+ Read(&typesName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::Compat)) {
+ valueList.compatName.emplace();
+ auto& compatName = *valueList.compatName;
+
+ // compatName
+ Read(&compatName, &buf);
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::KeyTypeNames)) {
+ valueList.typeNames.emplace();
+ auto& typeNames = *valueList.typeNames;
+ size_t typeNames_len = typeNames.size();
+
+ // typeNames
+ typeNames.resize(nTypes);
+ for (auto& typeNames_elem : typeNames) {
+ // typeNames_elem
+ Read(&typeNames_elem, &buf);
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::KTLevelNames)) {
+ valueList.nLevelsPerType.emplace();
+ valueList.ktLevelNames.emplace();
+ auto& nLevelsPerType = *valueList.nLevelsPerType;
+ size_t nLevelsPerType_len = nLevelsPerType.size();
+ auto& ktLevelNames = *valueList.ktLevelNames;
+ size_t ktLevelNames_len = ktLevelNames.size();
+
+ // nLevelsPerType
+ nLevelsPerType.resize(nTypes);
+ for (auto& nLevelsPerType_elem : nLevelsPerType) {
+ // nLevelsPerType_elem
+ Read(&nLevelsPerType_elem, &buf);
+ }
+
+ // pad11
+ Align(&buf, 4);
+
+ // ktLevelNames
+ auto sum228_ = SumOf([](auto& listelem_ref) { return listelem_ref; },
+ nLevelsPerType);
+ ktLevelNames.resize(sum228_);
+ for (auto& ktLevelNames_elem : ktLevelNames) {
+ // ktLevelNames_elem
+ Read(&ktLevelNames_elem, &buf);
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::IndicatorNames)) {
+ valueList.indicatorNames.emplace();
+ auto& indicatorNames = *valueList.indicatorNames;
+ size_t indicatorNames_len = indicatorNames.size();
+
+ // indicatorNames
+ indicatorNames.resize(PopCount(indicators));
+ for (auto& indicatorNames_elem : indicatorNames) {
+ // indicatorNames_elem
+ Read(&indicatorNames_elem, &buf);
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::VirtualModNames)) {
+ valueList.virtualModNames.emplace();
+ auto& virtualModNames = *valueList.virtualModNames;
+ size_t virtualModNames_len = virtualModNames.size();
+
+ // virtualModNames
+ virtualModNames.resize(PopCount(virtualMods));
+ for (auto& virtualModNames_elem : virtualModNames) {
+ // virtualModNames_elem
+ Read(&virtualModNames_elem, &buf);
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::GroupNames)) {
+ valueList.groups.emplace();
+ auto& groups = *valueList.groups;
+ size_t groups_len = groups.size();
+
+ // groups
+ groups.resize(PopCount(groupNames));
+ for (auto& groups_elem : groups) {
+ // groups_elem
+ Read(&groups_elem, &buf);
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::KeyNames)) {
+ valueList.keyNames.emplace();
+ auto& keyNames = *valueList.keyNames;
+ size_t keyNames_len = keyNames.size();
+
+ // keyNames
+ keyNames.resize(nKeys);
+ for (auto& keyNames_elem : keyNames) {
+ // keyNames_elem
+ {
+ auto& name = keyNames_elem.name;
+ size_t name_len = name.size();
+
+ // name
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+ }
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::KeyAliases)) {
+ valueList.keyAliases.emplace();
+ auto& keyAliases = *valueList.keyAliases;
+ size_t keyAliases_len = keyAliases.size();
+
+ // keyAliases
+ keyAliases.resize(nKeyAliases);
+ for (auto& keyAliases_elem : keyAliases) {
+ // keyAliases_elem
+ {
+ auto& real = keyAliases_elem.real;
+ size_t real_len = real.size();
+ auto& alias = keyAliases_elem.alias;
+ size_t alias_len = alias.size();
+
+ // real
+ for (auto& real_elem : real) {
+ // real_elem
+ Read(&real_elem, &buf);
+ }
+
+ // alias
+ for (auto& alias_elem : alias) {
+ // alias_elem
+ Read(&alias_elem, &buf);
+ }
+ }
+ }
+ }
+ if (CaseAnd(valueList_expr, Xkb::NameDetail::RGNames)) {
+ valueList.radioGroupNames.emplace();
+ auto& radioGroupNames = *valueList.radioGroupNames;
+ size_t radioGroupNames_len = radioGroupNames.size();
+
+ // radioGroupNames
+ radioGroupNames.resize(nRadioGroups);
+ for (auto& radioGroupNames_elem : radioGroupNames) {
+ // radioGroupNames_elem
+ Read(&radioGroupNames_elem, &buf);
+ }
+ }
+ }
+ if (CaseAnd(replies_expr, Xkb::GBNDetail::Geometry)) {
+ replies.geometry.emplace();
+ auto& geometry_type = (*replies.geometry).geometry_type;
+ auto& geometryDeviceID = (*replies.geometry).geometryDeviceID;
+ auto& geometry_sequence = (*replies.geometry).geometry_sequence;
+ auto& geometry_length = (*replies.geometry).geometry_length;
+ auto& name = (*replies.geometry).name;
+ auto& geometryFound = (*replies.geometry).geometryFound;
+ auto& widthMM = (*replies.geometry).widthMM;
+ auto& heightMM = (*replies.geometry).heightMM;
+ auto& nProperties = (*replies.geometry).nProperties;
+ auto& nColors = (*replies.geometry).nColors;
+ auto& nShapes = (*replies.geometry).nShapes;
+ auto& nSections = (*replies.geometry).nSections;
+ auto& nDoodads = (*replies.geometry).nDoodads;
+ auto& nKeyAliases = (*replies.geometry).nKeyAliases;
+ auto& baseColorNdx = (*replies.geometry).baseColorNdx;
+ auto& labelColorNdx = (*replies.geometry).labelColorNdx;
+ auto& labelFont = (*replies.geometry).labelFont;
+
+ // geometry_type
+ Read(&geometry_type, &buf);
+
+ // geometryDeviceID
+ Read(&geometryDeviceID, &buf);
+
+ // geometry_sequence
+ Read(&geometry_sequence, &buf);
+
+ // geometry_length
+ Read(&geometry_length, &buf);
+
+ // name
+ Read(&name, &buf);
+
+ // geometryFound
+ Read(&geometryFound, &buf);
+
+ // pad12
+ Pad(&buf, 1);
+
+ // widthMM
+ Read(&widthMM, &buf);
+
+ // heightMM
+ Read(&heightMM, &buf);
+
+ // nProperties
+ Read(&nProperties, &buf);
+
+ // nColors
+ Read(&nColors, &buf);
+
+ // nShapes
+ Read(&nShapes, &buf);
+
+ // nSections
+ Read(&nSections, &buf);
+
+ // nDoodads
+ Read(&nDoodads, &buf);
+
+ // nKeyAliases
+ Read(&nKeyAliases, &buf);
+
+ // baseColorNdx
+ Read(&baseColorNdx, &buf);
+
+ // labelColorNdx
+ Read(&labelColorNdx, &buf);
+
+ // labelFont
+ {
+ uint16_t length{};
+ auto& string = labelFont.string;
+ size_t string_len = string.size();
+ auto& alignment_pad = labelFont.alignment_pad;
+ size_t alignment_pad_len = alignment_pad ? alignment_pad->size() : 0;
+
+ // length
+ Read(&length, &buf);
+
+ // string
+ string.resize(length);
+ for (auto& string_elem : string) {
+ // string_elem
+ Read(&string_elem, &buf);
+ }
+
+ // alignment_pad
+ alignment_pad = buffer->ReadAndAdvance(
+ (BitAnd((length) + (5), BitNot(3))) - ((length) + (2)));
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xkb::GetDeviceInfoReply> Xkb::GetDeviceInfo(
+ const Xkb::GetDeviceInfoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& wanted = request.wanted;
+ auto& allButtons = request.allButtons;
+ auto& firstButton = request.firstButton;
+ auto& nButtons = request.nButtons;
+ auto& ledClass = request.ledClass;
+ auto& ledID = request.ledID;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 24;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // wanted
+ uint16_t tmp229;
+ tmp229 = static_cast<uint16_t>(wanted);
+ buf.Write(&tmp229);
+
+ // allButtons
+ buf.Write(&allButtons);
+
+ // firstButton
+ buf.Write(&firstButton);
+
+ // nButtons
+ buf.Write(&nButtons);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // ledClass
+ uint16_t tmp230;
+ tmp230 = static_cast<uint16_t>(ledClass);
+ buf.Write(&tmp230);
+
+ // ledID
+ buf.Write(&ledID);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::GetDeviceInfoReply>(
+ &buf, "Xkb::GetDeviceInfo", false);
+}
+
+Future<Xkb::GetDeviceInfoReply> Xkb::GetDeviceInfo(const DeviceSpec& deviceSpec,
+ const XIFeature& wanted,
+ const uint8_t& allButtons,
+ const uint8_t& firstButton,
+ const uint8_t& nButtons,
+ const LedClass& ledClass,
+ const IDSpec& ledID) {
+ return Xkb::GetDeviceInfo(Xkb::GetDeviceInfoRequest{
+ deviceSpec, wanted, allButtons, firstButton, nButtons, ledClass, ledID});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::GetDeviceInfoReply> detail::ReadReply<
+ Xkb::GetDeviceInfoReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::GetDeviceInfoReply>();
+
+ auto& deviceID = (*reply).deviceID;
+ auto& sequence = (*reply).sequence;
+ auto& present = (*reply).present;
+ auto& supported = (*reply).supported;
+ auto& unsupported = (*reply).unsupported;
+ uint16_t nDeviceLedFBs{};
+ auto& firstBtnWanted = (*reply).firstBtnWanted;
+ auto& nBtnsWanted = (*reply).nBtnsWanted;
+ auto& firstBtnRtrn = (*reply).firstBtnRtrn;
+ uint8_t nBtnsRtrn{};
+ auto& totalBtns = (*reply).totalBtns;
+ auto& hasOwnState = (*reply).hasOwnState;
+ auto& dfltKbdFB = (*reply).dfltKbdFB;
+ auto& dfltLedFB = (*reply).dfltLedFB;
+ auto& devType = (*reply).devType;
+ uint16_t nameLen{};
+ auto& name = (*reply).name;
+ size_t name_len = name.size();
+ auto& btnActions = (*reply).btnActions;
+ size_t btnActions_len = btnActions.size();
+ auto& leds = (*reply).leds;
+ size_t leds_len = leds.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // deviceID
+ Read(&deviceID, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // present
+ uint16_t tmp231;
+ Read(&tmp231, &buf);
+ present = static_cast<Xkb::XIFeature>(tmp231);
+
+ // supported
+ uint16_t tmp232;
+ Read(&tmp232, &buf);
+ supported = static_cast<Xkb::XIFeature>(tmp232);
+
+ // unsupported
+ uint16_t tmp233;
+ Read(&tmp233, &buf);
+ unsupported = static_cast<Xkb::XIFeature>(tmp233);
+
+ // nDeviceLedFBs
+ Read(&nDeviceLedFBs, &buf);
+
+ // firstBtnWanted
+ Read(&firstBtnWanted, &buf);
+
+ // nBtnsWanted
+ Read(&nBtnsWanted, &buf);
+
+ // firstBtnRtrn
+ Read(&firstBtnRtrn, &buf);
+
+ // nBtnsRtrn
+ Read(&nBtnsRtrn, &buf);
+
+ // totalBtns
+ Read(&totalBtns, &buf);
+
+ // hasOwnState
+ Read(&hasOwnState, &buf);
+
+ // dfltKbdFB
+ Read(&dfltKbdFB, &buf);
+
+ // dfltLedFB
+ Read(&dfltLedFB, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // devType
+ Read(&devType, &buf);
+
+ // nameLen
+ Read(&nameLen, &buf);
+
+ // name
+ name.resize(nameLen);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ // pad1
+ Align(&buf, 4);
+
+ // btnActions
+ btnActions.resize(nBtnsRtrn);
+ for (auto& btnActions_elem : btnActions) {
+ // btnActions_elem
+ Read(&btnActions_elem, &buf);
+ }
+
+ // leds
+ leds.resize(nDeviceLedFBs);
+ for (auto& leds_elem : leds) {
+ // leds_elem
+ {
+ auto& ledClass = leds_elem.ledClass;
+ auto& ledID = leds_elem.ledID;
+ auto& namesPresent = leds_elem.namesPresent;
+ auto& mapsPresent = leds_elem.mapsPresent;
+ auto& physIndicators = leds_elem.physIndicators;
+ auto& state = leds_elem.state;
+ auto& names = leds_elem.names;
+ size_t names_len = names.size();
+ auto& maps = leds_elem.maps;
+ size_t maps_len = maps.size();
+
+ // ledClass
+ uint16_t tmp234;
+ Read(&tmp234, &buf);
+ ledClass = static_cast<Xkb::LedClass>(tmp234);
+
+ // ledID
+ Read(&ledID, &buf);
+
+ // namesPresent
+ Read(&namesPresent, &buf);
+
+ // mapsPresent
+ Read(&mapsPresent, &buf);
+
+ // physIndicators
+ Read(&physIndicators, &buf);
+
+ // state
+ Read(&state, &buf);
+
+ // names
+ names.resize(PopCount(namesPresent));
+ for (auto& names_elem : names) {
+ // names_elem
+ Read(&names_elem, &buf);
+ }
+
+ // maps
+ maps.resize(PopCount(mapsPresent));
+ for (auto& maps_elem : maps) {
+ // maps_elem
+ {
+ auto& flags = maps_elem.flags;
+ auto& whichGroups = maps_elem.whichGroups;
+ auto& groups = maps_elem.groups;
+ auto& whichMods = maps_elem.whichMods;
+ auto& mods = maps_elem.mods;
+ auto& realMods = maps_elem.realMods;
+ auto& vmods = maps_elem.vmods;
+ auto& ctrls = maps_elem.ctrls;
+
+ // flags
+ uint8_t tmp235;
+ Read(&tmp235, &buf);
+ flags = static_cast<Xkb::IMFlag>(tmp235);
+
+ // whichGroups
+ uint8_t tmp236;
+ Read(&tmp236, &buf);
+ whichGroups = static_cast<Xkb::IMGroupsWhich>(tmp236);
+
+ // groups
+ uint8_t tmp237;
+ Read(&tmp237, &buf);
+ groups = static_cast<Xkb::SetOfGroup>(tmp237);
+
+ // whichMods
+ uint8_t tmp238;
+ Read(&tmp238, &buf);
+ whichMods = static_cast<Xkb::IMModsWhich>(tmp238);
+
+ // mods
+ uint8_t tmp239;
+ Read(&tmp239, &buf);
+ mods = static_cast<ModMask>(tmp239);
+
+ // realMods
+ uint8_t tmp240;
+ Read(&tmp240, &buf);
+ realMods = static_cast<ModMask>(tmp240);
+
+ // vmods
+ uint16_t tmp241;
+ Read(&tmp241, &buf);
+ vmods = static_cast<Xkb::VMod>(tmp241);
+
+ // ctrls
+ uint32_t tmp242;
+ Read(&tmp242, &buf);
+ ctrls = static_cast<Xkb::BoolCtrl>(tmp242);
+ }
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xkb::SetDeviceInfo(const Xkb::SetDeviceInfoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& deviceSpec = request.deviceSpec;
+ auto& firstBtn = request.firstBtn;
+ uint8_t nBtns{};
+ auto& change = request.change;
+ uint16_t nDeviceLedFBs{};
+ auto& btnActions = request.btnActions;
+ size_t btnActions_len = btnActions.size();
+ auto& leds = request.leds;
+ size_t leds_len = leds.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 25;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // deviceSpec
+ buf.Write(&deviceSpec);
+
+ // firstBtn
+ buf.Write(&firstBtn);
+
+ // nBtns
+ nBtns = btnActions.size();
+ buf.Write(&nBtns);
+
+ // change
+ uint16_t tmp243;
+ tmp243 = static_cast<uint16_t>(change);
+ buf.Write(&tmp243);
+
+ // nDeviceLedFBs
+ nDeviceLedFBs = leds.size();
+ buf.Write(&nDeviceLedFBs);
+
+ // btnActions
+ DCHECK_EQ(static_cast<size_t>(nBtns), btnActions.size());
+ for (auto& btnActions_elem : btnActions) {
+ // btnActions_elem
+ buf.Write(&btnActions_elem);
+ }
+
+ // leds
+ DCHECK_EQ(static_cast<size_t>(nDeviceLedFBs), leds.size());
+ for (auto& leds_elem : leds) {
+ // leds_elem
+ {
+ auto& ledClass = leds_elem.ledClass;
+ auto& ledID = leds_elem.ledID;
+ auto& namesPresent = leds_elem.namesPresent;
+ auto& mapsPresent = leds_elem.mapsPresent;
+ auto& physIndicators = leds_elem.physIndicators;
+ auto& state = leds_elem.state;
+ auto& names = leds_elem.names;
+ size_t names_len = names.size();
+ auto& maps = leds_elem.maps;
+ size_t maps_len = maps.size();
+
+ // ledClass
+ uint16_t tmp244;
+ tmp244 = static_cast<uint16_t>(ledClass);
+ buf.Write(&tmp244);
+
+ // ledID
+ buf.Write(&ledID);
+
+ // namesPresent
+ buf.Write(&namesPresent);
+
+ // mapsPresent
+ buf.Write(&mapsPresent);
+
+ // physIndicators
+ buf.Write(&physIndicators);
+
+ // state
+ buf.Write(&state);
+
+ // names
+ DCHECK_EQ(static_cast<size_t>(PopCount(namesPresent)), names.size());
+ for (auto& names_elem : names) {
+ // names_elem
+ buf.Write(&names_elem);
+ }
+
+ // maps
+ DCHECK_EQ(static_cast<size_t>(PopCount(mapsPresent)), maps.size());
+ for (auto& maps_elem : maps) {
+ // maps_elem
+ {
+ auto& flags = maps_elem.flags;
+ auto& whichGroups = maps_elem.whichGroups;
+ auto& groups = maps_elem.groups;
+ auto& whichMods = maps_elem.whichMods;
+ auto& mods = maps_elem.mods;
+ auto& realMods = maps_elem.realMods;
+ auto& vmods = maps_elem.vmods;
+ auto& ctrls = maps_elem.ctrls;
+
+ // flags
+ uint8_t tmp245;
+ tmp245 = static_cast<uint8_t>(flags);
+ buf.Write(&tmp245);
+
+ // whichGroups
+ uint8_t tmp246;
+ tmp246 = static_cast<uint8_t>(whichGroups);
+ buf.Write(&tmp246);
+
+ // groups
+ uint8_t tmp247;
+ tmp247 = static_cast<uint8_t>(groups);
+ buf.Write(&tmp247);
+
+ // whichMods
+ uint8_t tmp248;
+ tmp248 = static_cast<uint8_t>(whichMods);
+ buf.Write(&tmp248);
+
+ // mods
+ uint8_t tmp249;
+ tmp249 = static_cast<uint8_t>(mods);
+ buf.Write(&tmp249);
+
+ // realMods
+ uint8_t tmp250;
+ tmp250 = static_cast<uint8_t>(realMods);
+ buf.Write(&tmp250);
+
+ // vmods
+ uint16_t tmp251;
+ tmp251 = static_cast<uint16_t>(vmods);
+ buf.Write(&tmp251);
+
+ // ctrls
+ uint32_t tmp252;
+ tmp252 = static_cast<uint32_t>(ctrls);
+ buf.Write(&tmp252);
+ }
+ }
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xkb::SetDeviceInfo", false);
+}
+
+Future<void> Xkb::SetDeviceInfo(const DeviceSpec& deviceSpec,
+ const uint8_t& firstBtn,
+ const XIFeature& change,
+ const std::vector<Action>& btnActions,
+ const std::vector<DeviceLedInfo>& leds) {
+ return Xkb::SetDeviceInfo(Xkb::SetDeviceInfoRequest{
+ deviceSpec, firstBtn, change, btnActions, leds});
+}
+
+Future<Xkb::SetDebuggingFlagsReply> Xkb::SetDebuggingFlags(
+ const Xkb::SetDebuggingFlagsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint16_t msgLength{};
+ auto& affectFlags = request.affectFlags;
+ auto& flags = request.flags;
+ auto& affectCtrls = request.affectCtrls;
+ auto& ctrls = request.ctrls;
+ auto& message = request.message;
+ size_t message_len = message.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 101;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // msgLength
+ msgLength = message.size();
+ buf.Write(&msgLength);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // affectFlags
+ buf.Write(&affectFlags);
+
+ // flags
+ buf.Write(&flags);
+
+ // affectCtrls
+ buf.Write(&affectCtrls);
+
+ // ctrls
+ buf.Write(&ctrls);
+
+ // message
+ DCHECK_EQ(static_cast<size_t>(msgLength), message.size());
+ for (auto& message_elem : message) {
+ // message_elem
+ buf.Write(&message_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xkb::SetDebuggingFlagsReply>(
+ &buf, "Xkb::SetDebuggingFlags", false);
+}
+
+Future<Xkb::SetDebuggingFlagsReply> Xkb::SetDebuggingFlags(
+ const uint32_t& affectFlags,
+ const uint32_t& flags,
+ const uint32_t& affectCtrls,
+ const uint32_t& ctrls,
+ const std::vector<String8>& message) {
+ return Xkb::SetDebuggingFlags(Xkb::SetDebuggingFlagsRequest{
+ affectFlags, flags, affectCtrls, ctrls, message});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xkb::SetDebuggingFlagsReply> detail::ReadReply<
+ Xkb::SetDebuggingFlagsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xkb::SetDebuggingFlagsReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& currentFlags = (*reply).currentFlags;
+ auto& currentCtrls = (*reply).currentCtrls;
+ auto& supportedFlags = (*reply).supportedFlags;
+ auto& supportedCtrls = (*reply).supportedCtrls;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // currentFlags
+ Read(&currentFlags, &buf);
+
+ // currentCtrls
+ Read(&currentCtrls, &buf);
+
+ // supportedFlags
+ Read(&supportedFlags, &buf);
+
+ // supportedCtrls
+ Read(&supportedCtrls, &buf);
+
+ // pad1
+ Pad(&buf, 8);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xkb.h b/chromium/ui/gfx/x/generated_protos/xkb.h
new file mode 100644
index 00000000000..7d89785b25f
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xkb.h
@@ -0,0 +1,2858 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XKB_H_
+#define UI_GFX_X_GENERATED_PROTOS_XKB_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Xkb {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 0;
+
+ Xkb(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Const : int {
+ MaxLegalKeyCode = 255,
+ PerKeyBitArraySize = 32,
+ KeyNameLength = 4,
+ };
+
+ enum class EventType : int {
+ NewKeyboardNotify = 1 << 0,
+ MapNotify = 1 << 1,
+ StateNotify = 1 << 2,
+ ControlsNotify = 1 << 3,
+ IndicatorStateNotify = 1 << 4,
+ IndicatorMapNotify = 1 << 5,
+ NamesNotify = 1 << 6,
+ CompatMapNotify = 1 << 7,
+ BellNotify = 1 << 8,
+ ActionMessage = 1 << 9,
+ AccessXNotify = 1 << 10,
+ ExtensionDeviceNotify = 1 << 11,
+ };
+
+ enum class NKNDetail : int {
+ Keycodes = 1 << 0,
+ Geometry = 1 << 1,
+ DeviceID = 1 << 2,
+ };
+
+ enum class AXNDetail : int {
+ SKPress = 1 << 0,
+ SKAccept = 1 << 1,
+ SKReject = 1 << 2,
+ SKRelease = 1 << 3,
+ BKAccept = 1 << 4,
+ BKReject = 1 << 5,
+ AXKWarning = 1 << 6,
+ };
+
+ enum class MapPart : int {
+ KeyTypes = 1 << 0,
+ KeySyms = 1 << 1,
+ ModifierMap = 1 << 2,
+ ExplicitComponents = 1 << 3,
+ KeyActions = 1 << 4,
+ KeyBehaviors = 1 << 5,
+ VirtualMods = 1 << 6,
+ VirtualModMap = 1 << 7,
+ };
+
+ enum class SetMapFlags : int {
+ ResizeTypes = 1 << 0,
+ RecomputeActions = 1 << 1,
+ };
+
+ enum class StatePart : int {
+ ModifierState = 1 << 0,
+ ModifierBase = 1 << 1,
+ ModifierLatch = 1 << 2,
+ ModifierLock = 1 << 3,
+ GroupState = 1 << 4,
+ GroupBase = 1 << 5,
+ GroupLatch = 1 << 6,
+ GroupLock = 1 << 7,
+ CompatState = 1 << 8,
+ GrabMods = 1 << 9,
+ CompatGrabMods = 1 << 10,
+ LookupMods = 1 << 11,
+ CompatLookupMods = 1 << 12,
+ PointerButtons = 1 << 13,
+ };
+
+ enum class BoolCtrl : int {
+ RepeatKeys = 1 << 0,
+ SlowKeys = 1 << 1,
+ BounceKeys = 1 << 2,
+ StickyKeys = 1 << 3,
+ MouseKeys = 1 << 4,
+ MouseKeysAccel = 1 << 5,
+ AccessXKeys = 1 << 6,
+ AccessXTimeoutMask = 1 << 7,
+ AccessXFeedbackMask = 1 << 8,
+ AudibleBellMask = 1 << 9,
+ Overlay1Mask = 1 << 10,
+ Overlay2Mask = 1 << 11,
+ IgnoreGroupLockMask = 1 << 12,
+ };
+
+ enum class Control : int {
+ GroupsWrap = 1 << 27,
+ InternalMods = 1 << 28,
+ IgnoreLockMods = 1 << 29,
+ PerKeyRepeat = 1 << 30,
+ ControlsEnabled = 1 << 31,
+ };
+
+ enum class AXOption : int {
+ SKPressFB = 1 << 0,
+ SKAcceptFB = 1 << 1,
+ FeatureFB = 1 << 2,
+ SlowWarnFB = 1 << 3,
+ IndicatorFB = 1 << 4,
+ StickyKeysFB = 1 << 5,
+ TwoKeys = 1 << 6,
+ LatchToLock = 1 << 7,
+ SKReleaseFB = 1 << 8,
+ SKRejectFB = 1 << 9,
+ BKRejectFB = 1 << 10,
+ DumbBell = 1 << 11,
+ };
+
+ enum class DeviceSpec : uint16_t {};
+
+ enum class LedClassResult : int {
+ KbdFeedbackClass = 0,
+ LedFeedbackClass = 4,
+ };
+
+ enum class LedClass : int {
+ KbdFeedbackClass = 0,
+ LedFeedbackClass = 4,
+ DfltXIClass = 768,
+ AllXIClasses = 1280,
+ };
+
+ enum class LedClassSpec : uint16_t {};
+
+ enum class BellClassResult : int {
+ KbdFeedbackClass = 0,
+ BellFeedbackClass = 5,
+ };
+
+ enum class BellClass : int {
+ KbdFeedbackClass = 0,
+ BellFeedbackClass = 5,
+ DfltXIClass = 768,
+ };
+
+ enum class BellClassSpec : uint16_t {};
+
+ enum class Id : int {
+ UseCoreKbd = 256,
+ UseCorePtr = 512,
+ DfltXIClass = 768,
+ DfltXIId = 1024,
+ AllXIClass = 1280,
+ AllXIId = 1536,
+ XINone = 65280,
+ };
+
+ enum class IDSpec : uint16_t {};
+
+ enum class Group : int {
+ c_1 = 0,
+ c_2 = 1,
+ c_3 = 2,
+ c_4 = 3,
+ };
+
+ enum class Groups : int {
+ Any = 254,
+ All = 255,
+ };
+
+ enum class SetOfGroup : int {
+ Group1 = 1 << 0,
+ Group2 = 1 << 1,
+ Group3 = 1 << 2,
+ Group4 = 1 << 3,
+ };
+
+ enum class SetOfGroups : int {
+ Any = 1 << 7,
+ };
+
+ enum class GroupsWrap : int {
+ WrapIntoRange = 0,
+ ClampIntoRange = 1 << 6,
+ RedirectIntoRange = 1 << 7,
+ };
+
+ enum class VModsHigh : int {
+ c_15 = 1 << 7,
+ c_14 = 1 << 6,
+ c_13 = 1 << 5,
+ c_12 = 1 << 4,
+ c_11 = 1 << 3,
+ c_10 = 1 << 2,
+ c_9 = 1 << 1,
+ c_8 = 1 << 0,
+ };
+
+ enum class VModsLow : int {
+ c_7 = 1 << 7,
+ c_6 = 1 << 6,
+ c_5 = 1 << 5,
+ c_4 = 1 << 4,
+ c_3 = 1 << 3,
+ c_2 = 1 << 2,
+ c_1 = 1 << 1,
+ c_0 = 1 << 0,
+ };
+
+ enum class VMod : int {
+ c_15 = 1 << 15,
+ c_14 = 1 << 14,
+ c_13 = 1 << 13,
+ c_12 = 1 << 12,
+ c_11 = 1 << 11,
+ c_10 = 1 << 10,
+ c_9 = 1 << 9,
+ c_8 = 1 << 8,
+ c_7 = 1 << 7,
+ c_6 = 1 << 6,
+ c_5 = 1 << 5,
+ c_4 = 1 << 4,
+ c_3 = 1 << 3,
+ c_2 = 1 << 2,
+ c_1 = 1 << 1,
+ c_0 = 1 << 0,
+ };
+
+ enum class Explicit : int {
+ VModMap = 1 << 7,
+ Behavior = 1 << 6,
+ AutoRepeat = 1 << 5,
+ Interpret = 1 << 4,
+ KeyType4 = 1 << 3,
+ KeyType3 = 1 << 2,
+ KeyType2 = 1 << 1,
+ KeyType1 = 1 << 0,
+ };
+
+ enum class SymInterpretMatch : int {
+ NoneOf = 0,
+ AnyOfOrNone = 1,
+ AnyOf = 2,
+ AllOf = 3,
+ Exactly = 4,
+ };
+
+ enum class SymInterpMatch : int {
+ OpMask = 127,
+ LevelOneOnly = 1 << 7,
+ };
+
+ enum class IMFlag : int {
+ NoExplicit = 1 << 7,
+ NoAutomatic = 1 << 6,
+ LEDDrivesKB = 1 << 5,
+ };
+
+ enum class IMModsWhich : int {
+ UseCompat = 1 << 4,
+ UseEffective = 1 << 3,
+ UseLocked = 1 << 2,
+ UseLatched = 1 << 1,
+ UseBase = 1 << 0,
+ };
+
+ enum class IMGroupsWhich : int {
+ UseCompat = 1 << 4,
+ UseEffective = 1 << 3,
+ UseLocked = 1 << 2,
+ UseLatched = 1 << 1,
+ UseBase = 1 << 0,
+ };
+
+ enum class CMDetail : int {
+ SymInterp = 1 << 0,
+ GroupCompat = 1 << 1,
+ };
+
+ enum class NameDetail : int {
+ Keycodes = 1 << 0,
+ Geometry = 1 << 1,
+ Symbols = 1 << 2,
+ PhysSymbols = 1 << 3,
+ Types = 1 << 4,
+ Compat = 1 << 5,
+ KeyTypeNames = 1 << 6,
+ KTLevelNames = 1 << 7,
+ IndicatorNames = 1 << 8,
+ KeyNames = 1 << 9,
+ KeyAliases = 1 << 10,
+ VirtualModNames = 1 << 11,
+ GroupNames = 1 << 12,
+ RGNames = 1 << 13,
+ };
+
+ enum class GBNDetail : int {
+ Types = 1 << 0,
+ CompatMap = 1 << 1,
+ ClientSymbols = 1 << 2,
+ ServerSymbols = 1 << 3,
+ IndicatorMaps = 1 << 4,
+ KeyNames = 1 << 5,
+ Geometry = 1 << 6,
+ OtherNames = 1 << 7,
+ };
+
+ enum class XIFeature : int {
+ Keyboards = 1 << 0,
+ ButtonActions = 1 << 1,
+ IndicatorNames = 1 << 2,
+ IndicatorMaps = 1 << 3,
+ IndicatorState = 1 << 4,
+ };
+
+ enum class PerClientFlag : int {
+ DetectableAutoRepeat = 1 << 0,
+ GrabsUseXKBState = 1 << 1,
+ AutoResetControls = 1 << 2,
+ LookupStateWhenGrabbed = 1 << 3,
+ SendEventUsesXKBState = 1 << 4,
+ };
+
+ enum class BehaviorType : int {
+ Default = 0,
+ Lock = 1,
+ RadioGroup = 2,
+ Overlay1 = 3,
+ Overlay2 = 4,
+ PermamentLock = 129,
+ PermamentRadioGroup = 130,
+ PermamentOverlay1 = 131,
+ PermamentOverlay2 = 132,
+ };
+
+ enum class String8 : char {};
+
+ enum class DoodadType : int {
+ Outline = 1,
+ Solid = 2,
+ Text = 3,
+ Indicator = 4,
+ Logo = 5,
+ };
+
+ enum class Error : int {
+ BadDevice = 255,
+ BadClass = 254,
+ BadId = 253,
+ };
+
+ enum class Sa : int {
+ ClearLocks = 1 << 0,
+ LatchToLock = 1 << 1,
+ UseModMapMods = 1 << 2,
+ GroupAbsolute = 1 << 2,
+ };
+
+ enum class SAType : int {
+ NoAction = 0,
+ SetMods = 1,
+ LatchMods = 2,
+ LockMods = 3,
+ SetGroup = 4,
+ LatchGroup = 5,
+ LockGroup = 6,
+ MovePtr = 7,
+ PtrBtn = 8,
+ LockPtrBtn = 9,
+ SetPtrDflt = 10,
+ ISOLock = 11,
+ Terminate = 12,
+ SwitchScreen = 13,
+ SetControls = 14,
+ LockControls = 15,
+ ActionMessage = 16,
+ RedirectKey = 17,
+ DeviceBtn = 18,
+ LockDeviceBtn = 19,
+ DeviceValuator = 20,
+ };
+
+ enum class SAMovePtrFlag : int {
+ NoAcceleration = 1 << 0,
+ MoveAbsoluteX = 1 << 1,
+ MoveAbsoluteY = 1 << 2,
+ };
+
+ enum class SASetPtrDfltFlag : int {
+ DfltBtnAbsolute = 1 << 2,
+ AffectDfltButton = 1 << 0,
+ };
+
+ enum class SAIsoLockFlag : int {
+ NoLock = 1 << 0,
+ NoUnlock = 1 << 1,
+ UseModMapMods = 1 << 2,
+ GroupAbsolute = 1 << 2,
+ ISODfltIsGroup = 1 << 3,
+ };
+
+ enum class SAIsoLockNoAffect : int {
+ Ctrls = 1 << 3,
+ Ptr = 1 << 4,
+ Group = 1 << 5,
+ Mods = 1 << 6,
+ };
+
+ enum class SwitchScreenFlag : int {
+ Application = 1 << 0,
+ Absolute = 1 << 2,
+ };
+
+ enum class BoolCtrlsHigh : int {
+ AccessXFeedback = 1 << 0,
+ AudibleBell = 1 << 1,
+ Overlay1 = 1 << 2,
+ Overlay2 = 1 << 3,
+ IgnoreGroupLock = 1 << 4,
+ };
+
+ enum class BoolCtrlsLow : int {
+ RepeatKeys = 1 << 0,
+ SlowKeys = 1 << 1,
+ BounceKeys = 1 << 2,
+ StickyKeys = 1 << 3,
+ MouseKeys = 1 << 4,
+ MouseKeysAccel = 1 << 5,
+ AccessXKeys = 1 << 6,
+ AccessXTimeout = 1 << 7,
+ };
+
+ enum class ActionMessageFlag : int {
+ OnPress = 1 << 0,
+ OnRelease = 1 << 1,
+ GenKeyEvent = 1 << 2,
+ };
+
+ enum class LockDeviceFlags : int {
+ NoLock = 1 << 0,
+ NoUnlock = 1 << 1,
+ };
+
+ enum class SAValWhat : int {
+ IgnoreVal = 0,
+ SetValMin = 1,
+ SetValCenter = 2,
+ SetValMax = 3,
+ SetValRelative = 4,
+ SetValAbsolute = 5,
+ };
+
+ struct IndicatorMap {
+ IMFlag flags{};
+ IMGroupsWhich whichGroups{};
+ SetOfGroup groups{};
+ IMModsWhich whichMods{};
+ ModMask mods{};
+ ModMask realMods{};
+ VMod vmods{};
+ BoolCtrl ctrls{};
+ };
+
+ struct ModDef {
+ ModMask mask{};
+ ModMask realMods{};
+ VMod vmods{};
+ };
+
+ struct KeyName {
+ std::array<char, 4> name{};
+ };
+
+ struct KeyAlias {
+ std::array<char, 4> real{};
+ std::array<char, 4> alias{};
+ };
+
+ struct CountedString16 {
+ std::string string{};
+ scoped_refptr<base::RefCountedMemory> alignment_pad{};
+ };
+
+ struct KTMapEntry {
+ uint8_t active{};
+ ModMask mods_mask{};
+ uint8_t level{};
+ ModMask mods_mods{};
+ VMod mods_vmods{};
+ };
+
+ struct KeyType {
+ ModMask mods_mask{};
+ ModMask mods_mods{};
+ VMod mods_vmods{};
+ uint8_t numLevels{};
+ uint8_t hasPreserve{};
+ std::vector<KTMapEntry> map{};
+ std::vector<ModDef> preserve{};
+ };
+
+ struct KeySymMap {
+ std::array<uint8_t, 4> kt_index{};
+ uint8_t groupInfo{};
+ uint8_t width{};
+ std::vector<KeySym> syms{};
+ };
+
+ struct CommonBehavior {
+ uint8_t type{};
+ uint8_t data{};
+ };
+
+ struct DefaultBehavior {
+ uint8_t type{};
+ };
+
+ struct LockBehavior {
+ uint8_t type{};
+ };
+
+ struct RadioGroupBehavior {
+ uint8_t type{};
+ uint8_t group{};
+ };
+
+ struct OverlayBehavior {
+ uint8_t type{};
+ KeyCode key{};
+ };
+
+ struct PermamentLockBehavior {
+ uint8_t type{};
+ };
+
+ struct PermamentRadioGroupBehavior {
+ uint8_t type{};
+ uint8_t group{};
+ };
+
+ struct PermamentOverlayBehavior {
+ uint8_t type{};
+ KeyCode key{};
+ };
+
+ union Behavior {
+ Behavior() { memset(this, 0, sizeof(*this)); }
+
+ CommonBehavior common;
+ DefaultBehavior c_default;
+ LockBehavior lock;
+ RadioGroupBehavior radioGroup;
+ OverlayBehavior overlay1;
+ OverlayBehavior overlay2;
+ PermamentLockBehavior permamentLock;
+ PermamentRadioGroupBehavior permamentRadioGroup;
+ PermamentOverlayBehavior permamentOverlay1;
+ PermamentOverlayBehavior permamentOverlay2;
+ uint8_t type;
+ };
+ static_assert(std::is_trivially_copyable<Behavior>::value, "");
+
+ struct SetBehavior {
+ KeyCode keycode{};
+ Behavior behavior{};
+ };
+
+ struct SetExplicit {
+ KeyCode keycode{};
+ Explicit c_explicit{};
+ };
+
+ struct KeyModMap {
+ KeyCode keycode{};
+ ModMask mods{};
+ };
+
+ struct KeyVModMap {
+ KeyCode keycode{};
+ VMod vmods{};
+ };
+
+ struct KTSetMapEntry {
+ uint8_t level{};
+ ModMask realMods{};
+ VMod virtualMods{};
+ };
+
+ struct SetKeyType {
+ ModMask mask{};
+ ModMask realMods{};
+ VMod virtualMods{};
+ uint8_t numLevels{};
+ uint8_t preserve{};
+ std::vector<KTSetMapEntry> entries{};
+ std::vector<KTSetMapEntry> preserve_entries{};
+ };
+
+ struct Outline {
+ uint8_t cornerRadius{};
+ std::vector<Point> points{};
+ };
+
+ struct Shape {
+ Atom name{};
+ uint8_t primaryNdx{};
+ uint8_t approxNdx{};
+ std::vector<Outline> outlines{};
+ };
+
+ struct Key {
+ std::array<String8, 4> name{};
+ int16_t gap{};
+ uint8_t shapeNdx{};
+ uint8_t colorNdx{};
+ };
+
+ struct OverlayKey {
+ std::array<String8, 4> over{};
+ std::array<String8, 4> under{};
+ };
+
+ struct OverlayRow {
+ uint8_t rowUnder{};
+ std::vector<OverlayKey> keys{};
+ };
+
+ struct Overlay {
+ Atom name{};
+ std::vector<OverlayRow> rows{};
+ };
+
+ struct Row {
+ int16_t top{};
+ int16_t left{};
+ uint8_t vertical{};
+ std::vector<Key> keys{};
+ };
+
+ struct Listing {
+ uint16_t flags{};
+ std::vector<String8> string{};
+ };
+
+ struct DeviceLedInfo {
+ LedClass ledClass{};
+ IDSpec ledID{};
+ uint32_t namesPresent{};
+ uint32_t mapsPresent{};
+ uint32_t physIndicators{};
+ uint32_t state{};
+ std::vector<Atom> names{};
+ std::vector<IndicatorMap> maps{};
+ };
+
+ struct KeyboardError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t value{};
+ uint16_t minorOpcode{};
+ uint8_t majorOpcode{};
+
+ std::string ToString() const override;
+ };
+
+ struct SANoAction {
+ SAType type{};
+ };
+
+ struct SASetMods {
+ SAType type{};
+ Sa flags{};
+ ModMask mask{};
+ ModMask realMods{};
+ VModsHigh vmodsHigh{};
+ VModsLow vmodsLow{};
+ };
+
+ struct SALatchMods {
+ SAType type{};
+ Sa flags{};
+ ModMask mask{};
+ ModMask realMods{};
+ VModsHigh vmodsHigh{};
+ VModsLow vmodsLow{};
+ };
+
+ struct SALockMods {
+ SAType type{};
+ Sa flags{};
+ ModMask mask{};
+ ModMask realMods{};
+ VModsHigh vmodsHigh{};
+ VModsLow vmodsLow{};
+ };
+
+ struct SASetGroup {
+ SAType type{};
+ Sa flags{};
+ int8_t group{};
+ };
+
+ struct SALatchGroup {
+ SAType type{};
+ Sa flags{};
+ int8_t group{};
+ };
+
+ struct SALockGroup {
+ SAType type{};
+ Sa flags{};
+ int8_t group{};
+ };
+
+ struct SAMovePtr {
+ SAType type{};
+ SAMovePtrFlag flags{};
+ int8_t xHigh{};
+ uint8_t xLow{};
+ int8_t yHigh{};
+ uint8_t yLow{};
+ };
+
+ struct SAPtrBtn {
+ SAType type{};
+ uint8_t flags{};
+ uint8_t count{};
+ uint8_t button{};
+ };
+
+ struct SALockPtrBtn {
+ SAType type{};
+ uint8_t flags{};
+ uint8_t button{};
+ };
+
+ struct SASetPtrDflt {
+ SAType type{};
+ SASetPtrDfltFlag flags{};
+ SASetPtrDfltFlag affect{};
+ int8_t value{};
+ };
+
+ struct SAIsoLock {
+ SAType type{};
+ SAIsoLockFlag flags{};
+ ModMask mask{};
+ ModMask realMods{};
+ int8_t group{};
+ SAIsoLockNoAffect affect{};
+ VModsHigh vmodsHigh{};
+ VModsLow vmodsLow{};
+ };
+
+ struct SATerminate {
+ SAType type{};
+ };
+
+ struct SASwitchScreen {
+ SAType type{};
+ uint8_t flags{};
+ int8_t newScreen{};
+ };
+
+ struct SASetControls {
+ SAType type{};
+ BoolCtrlsHigh boolCtrlsHigh{};
+ BoolCtrlsLow boolCtrlsLow{};
+ };
+
+ struct SALockControls {
+ SAType type{};
+ BoolCtrlsHigh boolCtrlsHigh{};
+ BoolCtrlsLow boolCtrlsLow{};
+ };
+
+ struct SAActionMessage {
+ SAType type{};
+ ActionMessageFlag flags{};
+ std::array<uint8_t, 6> message{};
+ };
+
+ struct SARedirectKey {
+ SAType type{};
+ KeyCode newkey{};
+ ModMask mask{};
+ ModMask realModifiers{};
+ VModsHigh vmodsMaskHigh{};
+ VModsLow vmodsMaskLow{};
+ VModsHigh vmodsHigh{};
+ VModsLow vmodsLow{};
+ };
+
+ struct SADeviceBtn {
+ SAType type{};
+ uint8_t flags{};
+ uint8_t count{};
+ uint8_t button{};
+ uint8_t device{};
+ };
+
+ struct SALockDeviceBtn {
+ SAType type{};
+ LockDeviceFlags flags{};
+ uint8_t button{};
+ uint8_t device{};
+ };
+
+ struct SADeviceValuator {
+ SAType type{};
+ uint8_t device{};
+ SAValWhat val1what{};
+ uint8_t val1index{};
+ uint8_t val1value{};
+ SAValWhat val2what{};
+ uint8_t val2index{};
+ uint8_t val2value{};
+ };
+
+ struct SIAction {
+ SAType type{};
+ std::array<uint8_t, 7> data{};
+ };
+
+ struct SymInterpret {
+ KeySym sym{};
+ ModMask mods{};
+ uint8_t match{};
+ VModsLow virtualMod{};
+ uint8_t flags{};
+ SIAction action{};
+ };
+
+ union Action {
+ Action() { memset(this, 0, sizeof(*this)); }
+
+ SANoAction noaction;
+ SASetMods setmods;
+ SALatchMods latchmods;
+ SALockMods lockmods;
+ SASetGroup setgroup;
+ SALatchGroup latchgroup;
+ SALockGroup lockgroup;
+ SAMovePtr moveptr;
+ SAPtrBtn ptrbtn;
+ SALockPtrBtn lockptrbtn;
+ SASetPtrDflt setptrdflt;
+ SAIsoLock isolock;
+ SATerminate terminate;
+ SASwitchScreen switchscreen;
+ SASetControls setcontrols;
+ SALockControls lockcontrols;
+ SAActionMessage message;
+ SARedirectKey redirect;
+ SADeviceBtn devbtn;
+ SALockDeviceBtn lockdevbtn;
+ SADeviceValuator devval;
+ SAType type;
+ };
+ static_assert(std::is_trivially_copyable<Action>::value, "");
+
+ struct NewKeyboardNotifyEvent {
+ static constexpr int type_id = 38;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ uint8_t oldDeviceID{};
+ KeyCode minKeyCode{};
+ KeyCode maxKeyCode{};
+ KeyCode oldMinKeyCode{};
+ KeyCode oldMaxKeyCode{};
+ uint8_t requestMajor{};
+ uint8_t requestMinor{};
+ NKNDetail changed{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct MapNotifyEvent {
+ static constexpr int type_id = 39;
+ static constexpr uint8_t opcode = 1;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ uint8_t ptrBtnActions{};
+ MapPart changed{};
+ KeyCode minKeyCode{};
+ KeyCode maxKeyCode{};
+ uint8_t firstType{};
+ uint8_t nTypes{};
+ KeyCode firstKeySym{};
+ uint8_t nKeySyms{};
+ KeyCode firstKeyAct{};
+ uint8_t nKeyActs{};
+ KeyCode firstKeyBehavior{};
+ uint8_t nKeyBehavior{};
+ KeyCode firstKeyExplicit{};
+ uint8_t nKeyExplicit{};
+ KeyCode firstModMapKey{};
+ uint8_t nModMapKeys{};
+ KeyCode firstVModMapKey{};
+ uint8_t nVModMapKeys{};
+ VMod virtualMods{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct StateNotifyEvent {
+ static constexpr int type_id = 40;
+ static constexpr uint8_t opcode = 2;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ ModMask mods{};
+ ModMask baseMods{};
+ ModMask latchedMods{};
+ ModMask lockedMods{};
+ Group group{};
+ int16_t baseGroup{};
+ int16_t latchedGroup{};
+ Group lockedGroup{};
+ ModMask compatState{};
+ ModMask grabMods{};
+ ModMask compatGrabMods{};
+ ModMask lookupMods{};
+ ModMask compatLoockupMods{};
+ KeyButMask ptrBtnState{};
+ StatePart changed{};
+ KeyCode keycode{};
+ uint8_t eventType{};
+ uint8_t requestMajor{};
+ uint8_t requestMinor{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct ControlsNotifyEvent {
+ static constexpr int type_id = 41;
+ static constexpr uint8_t opcode = 3;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ uint8_t numGroups{};
+ Control changedControls{};
+ BoolCtrl enabledControls{};
+ BoolCtrl enabledControlChanges{};
+ KeyCode keycode{};
+ uint8_t eventType{};
+ uint8_t requestMajor{};
+ uint8_t requestMinor{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct IndicatorStateNotifyEvent {
+ static constexpr int type_id = 42;
+ static constexpr uint8_t opcode = 4;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ uint32_t state{};
+ uint32_t stateChanged{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct IndicatorMapNotifyEvent {
+ static constexpr int type_id = 43;
+ static constexpr uint8_t opcode = 5;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ uint32_t state{};
+ uint32_t mapChanged{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct NamesNotifyEvent {
+ static constexpr int type_id = 44;
+ static constexpr uint8_t opcode = 6;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ NameDetail changed{};
+ uint8_t firstType{};
+ uint8_t nTypes{};
+ uint8_t firstLevelName{};
+ uint8_t nLevelNames{};
+ uint8_t nRadioGroups{};
+ uint8_t nKeyAliases{};
+ SetOfGroup changedGroupNames{};
+ VMod changedVirtualMods{};
+ KeyCode firstKey{};
+ uint8_t nKeys{};
+ uint32_t changedIndicators{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct CompatMapNotifyEvent {
+ static constexpr int type_id = 45;
+ static constexpr uint8_t opcode = 7;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ SetOfGroup changedGroups{};
+ uint16_t firstSI{};
+ uint16_t nSI{};
+ uint16_t nTotalSI{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct BellNotifyEvent {
+ static constexpr int type_id = 46;
+ static constexpr uint8_t opcode = 8;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ BellClassResult bellClass{};
+ uint8_t bellID{};
+ uint8_t percent{};
+ uint16_t pitch{};
+ uint16_t duration{};
+ Atom name{};
+ Window window{};
+ uint8_t eventOnly{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+ };
+
+ struct ActionMessageEvent {
+ static constexpr int type_id = 47;
+ static constexpr uint8_t opcode = 9;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ KeyCode keycode{};
+ uint8_t press{};
+ uint8_t keyEventFollows{};
+ ModMask mods{};
+ Group group{};
+ std::array<String8, 8> message{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct AccessXNotifyEvent {
+ static constexpr int type_id = 48;
+ static constexpr uint8_t opcode = 10;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ KeyCode keycode{};
+ AXNDetail detailt{};
+ uint16_t slowKeysDelay{};
+ uint16_t debounceDelay{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct ExtensionDeviceNotifyEvent {
+ static constexpr int type_id = 49;
+ static constexpr uint8_t opcode = 11;
+ bool send_event{};
+ uint8_t xkbType{};
+ uint16_t sequence{};
+ Time time{};
+ uint8_t deviceID{};
+ XIFeature reason{};
+ LedClassResult ledClass{};
+ uint16_t ledID{};
+ uint32_t ledsDefined{};
+ uint32_t ledState{};
+ uint8_t firstButton{};
+ uint8_t nButtons{};
+ XIFeature supported{};
+ XIFeature unsupported{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct UseExtensionRequest {
+ uint16_t wantedMajor{};
+ uint16_t wantedMinor{};
+ };
+
+ struct UseExtensionReply {
+ uint8_t supported{};
+ uint16_t sequence{};
+ uint16_t serverMajor{};
+ uint16_t serverMinor{};
+ };
+
+ using UseExtensionResponse = Response<UseExtensionReply>;
+
+ Future<UseExtensionReply> UseExtension(const UseExtensionRequest& request);
+
+ Future<UseExtensionReply> UseExtension(const uint16_t& wantedMajor = {},
+ const uint16_t& wantedMinor = {});
+
+ struct SelectEventsRequest {
+ DeviceSpec deviceSpec{};
+ EventType affectWhich{};
+ EventType clear{};
+ EventType selectAll{};
+ MapPart affectMap{};
+ MapPart map{};
+ base::Optional<NKNDetail> affectNewKeyboard{};
+ base::Optional<NKNDetail> newKeyboardDetails{};
+ base::Optional<StatePart> affectState{};
+ base::Optional<StatePart> stateDetails{};
+ base::Optional<Control> affectCtrls{};
+ base::Optional<Control> ctrlDetails{};
+ base::Optional<uint32_t> affectIndicatorState{};
+ base::Optional<uint32_t> indicatorStateDetails{};
+ base::Optional<uint32_t> affectIndicatorMap{};
+ base::Optional<uint32_t> indicatorMapDetails{};
+ base::Optional<NameDetail> affectNames{};
+ base::Optional<NameDetail> namesDetails{};
+ base::Optional<CMDetail> affectCompat{};
+ base::Optional<CMDetail> compatDetails{};
+ base::Optional<uint8_t> affectBell{};
+ base::Optional<uint8_t> bellDetails{};
+ base::Optional<uint8_t> affectMsgDetails{};
+ base::Optional<uint8_t> msgDetails{};
+ base::Optional<AXNDetail> affectAccessX{};
+ base::Optional<AXNDetail> accessXDetails{};
+ base::Optional<XIFeature> affectExtDev{};
+ base::Optional<XIFeature> extdevDetails{};
+ };
+
+ using SelectEventsResponse = Response<void>;
+
+ Future<void> SelectEvents(const SelectEventsRequest& request);
+
+ Future<void> SelectEvents(
+ const DeviceSpec& deviceSpec = {},
+ const EventType& affectWhich = {},
+ const EventType& clear = {},
+ const EventType& selectAll = {},
+ const MapPart& affectMap = {},
+ const MapPart& map = {},
+ const base::Optional<NKNDetail>& affectNewKeyboard = base::nullopt,
+ const base::Optional<NKNDetail>& newKeyboardDetails = base::nullopt,
+ const base::Optional<StatePart>& affectState = base::nullopt,
+ const base::Optional<StatePart>& stateDetails = base::nullopt,
+ const base::Optional<Control>& affectCtrls = base::nullopt,
+ const base::Optional<Control>& ctrlDetails = base::nullopt,
+ const base::Optional<uint32_t>& affectIndicatorState = base::nullopt,
+ const base::Optional<uint32_t>& indicatorStateDetails = base::nullopt,
+ const base::Optional<uint32_t>& affectIndicatorMap = base::nullopt,
+ const base::Optional<uint32_t>& indicatorMapDetails = base::nullopt,
+ const base::Optional<NameDetail>& affectNames = base::nullopt,
+ const base::Optional<NameDetail>& namesDetails = base::nullopt,
+ const base::Optional<CMDetail>& affectCompat = base::nullopt,
+ const base::Optional<CMDetail>& compatDetails = base::nullopt,
+ const base::Optional<uint8_t>& affectBell = base::nullopt,
+ const base::Optional<uint8_t>& bellDetails = base::nullopt,
+ const base::Optional<uint8_t>& affectMsgDetails = base::nullopt,
+ const base::Optional<uint8_t>& msgDetails = base::nullopt,
+ const base::Optional<AXNDetail>& affectAccessX = base::nullopt,
+ const base::Optional<AXNDetail>& accessXDetails = base::nullopt,
+ const base::Optional<XIFeature>& affectExtDev = base::nullopt,
+ const base::Optional<XIFeature>& extdevDetails = base::nullopt);
+
+ struct BellRequest {
+ DeviceSpec deviceSpec{};
+ BellClassSpec bellClass{};
+ IDSpec bellID{};
+ int8_t percent{};
+ uint8_t forceSound{};
+ uint8_t eventOnly{};
+ int16_t pitch{};
+ int16_t duration{};
+ Atom name{};
+ Window window{};
+ };
+
+ using BellResponse = Response<void>;
+
+ Future<void> Bell(const BellRequest& request);
+
+ Future<void> Bell(const DeviceSpec& deviceSpec = {},
+ const BellClassSpec& bellClass = {},
+ const IDSpec& bellID = {},
+ const int8_t& percent = {},
+ const uint8_t& forceSound = {},
+ const uint8_t& eventOnly = {},
+ const int16_t& pitch = {},
+ const int16_t& duration = {},
+ const Atom& name = {},
+ const Window& window = {});
+
+ struct GetStateRequest {
+ DeviceSpec deviceSpec{};
+ };
+
+ struct GetStateReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ ModMask mods{};
+ ModMask baseMods{};
+ ModMask latchedMods{};
+ ModMask lockedMods{};
+ Group group{};
+ Group lockedGroup{};
+ int16_t baseGroup{};
+ int16_t latchedGroup{};
+ ModMask compatState{};
+ ModMask grabMods{};
+ ModMask compatGrabMods{};
+ ModMask lookupMods{};
+ ModMask compatLookupMods{};
+ KeyButMask ptrBtnState{};
+ };
+
+ using GetStateResponse = Response<GetStateReply>;
+
+ Future<GetStateReply> GetState(const GetStateRequest& request);
+
+ Future<GetStateReply> GetState(const DeviceSpec& deviceSpec = {});
+
+ struct LatchLockStateRequest {
+ DeviceSpec deviceSpec{};
+ ModMask affectModLocks{};
+ ModMask modLocks{};
+ uint8_t lockGroup{};
+ Group groupLock{};
+ ModMask affectModLatches{};
+ uint8_t latchGroup{};
+ uint16_t groupLatch{};
+ };
+
+ using LatchLockStateResponse = Response<void>;
+
+ Future<void> LatchLockState(const LatchLockStateRequest& request);
+
+ Future<void> LatchLockState(const DeviceSpec& deviceSpec = {},
+ const ModMask& affectModLocks = {},
+ const ModMask& modLocks = {},
+ const uint8_t& lockGroup = {},
+ const Group& groupLock = {},
+ const ModMask& affectModLatches = {},
+ const uint8_t& latchGroup = {},
+ const uint16_t& groupLatch = {});
+
+ struct GetControlsRequest {
+ DeviceSpec deviceSpec{};
+ };
+
+ struct GetControlsReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ uint8_t mouseKeysDfltBtn{};
+ uint8_t numGroups{};
+ uint8_t groupsWrap{};
+ ModMask internalModsMask{};
+ ModMask ignoreLockModsMask{};
+ ModMask internalModsRealMods{};
+ ModMask ignoreLockModsRealMods{};
+ VMod internalModsVmods{};
+ VMod ignoreLockModsVmods{};
+ uint16_t repeatDelay{};
+ uint16_t repeatInterval{};
+ uint16_t slowKeysDelay{};
+ uint16_t debounceDelay{};
+ uint16_t mouseKeysDelay{};
+ uint16_t mouseKeysInterval{};
+ uint16_t mouseKeysTimeToMax{};
+ uint16_t mouseKeysMaxSpeed{};
+ int16_t mouseKeysCurve{};
+ AXOption accessXOption{};
+ uint16_t accessXTimeout{};
+ AXOption accessXTimeoutOptionsMask{};
+ AXOption accessXTimeoutOptionsValues{};
+ BoolCtrl accessXTimeoutMask{};
+ BoolCtrl accessXTimeoutValues{};
+ BoolCtrl enabledControls{};
+ std::array<uint8_t, 32> perKeyRepeat{};
+ };
+
+ using GetControlsResponse = Response<GetControlsReply>;
+
+ Future<GetControlsReply> GetControls(const GetControlsRequest& request);
+
+ Future<GetControlsReply> GetControls(const DeviceSpec& deviceSpec = {});
+
+ struct SetControlsRequest {
+ DeviceSpec deviceSpec{};
+ ModMask affectInternalRealMods{};
+ ModMask internalRealMods{};
+ ModMask affectIgnoreLockRealMods{};
+ ModMask ignoreLockRealMods{};
+ VMod affectInternalVirtualMods{};
+ VMod internalVirtualMods{};
+ VMod affectIgnoreLockVirtualMods{};
+ VMod ignoreLockVirtualMods{};
+ uint8_t mouseKeysDfltBtn{};
+ uint8_t groupsWrap{};
+ AXOption accessXOptions{};
+ BoolCtrl affectEnabledControls{};
+ BoolCtrl enabledControls{};
+ Control changeControls{};
+ uint16_t repeatDelay{};
+ uint16_t repeatInterval{};
+ uint16_t slowKeysDelay{};
+ uint16_t debounceDelay{};
+ uint16_t mouseKeysDelay{};
+ uint16_t mouseKeysInterval{};
+ uint16_t mouseKeysTimeToMax{};
+ uint16_t mouseKeysMaxSpeed{};
+ int16_t mouseKeysCurve{};
+ uint16_t accessXTimeout{};
+ BoolCtrl accessXTimeoutMask{};
+ BoolCtrl accessXTimeoutValues{};
+ AXOption accessXTimeoutOptionsMask{};
+ AXOption accessXTimeoutOptionsValues{};
+ std::array<uint8_t, 32> perKeyRepeat{};
+ };
+
+ using SetControlsResponse = Response<void>;
+
+ Future<void> SetControls(const SetControlsRequest& request);
+
+ Future<void> SetControls(const DeviceSpec& deviceSpec = {},
+ const ModMask& affectInternalRealMods = {},
+ const ModMask& internalRealMods = {},
+ const ModMask& affectIgnoreLockRealMods = {},
+ const ModMask& ignoreLockRealMods = {},
+ const VMod& affectInternalVirtualMods = {},
+ const VMod& internalVirtualMods = {},
+ const VMod& affectIgnoreLockVirtualMods = {},
+ const VMod& ignoreLockVirtualMods = {},
+ const uint8_t& mouseKeysDfltBtn = {},
+ const uint8_t& groupsWrap = {},
+ const AXOption& accessXOptions = {},
+ const BoolCtrl& affectEnabledControls = {},
+ const BoolCtrl& enabledControls = {},
+ const Control& changeControls = {},
+ const uint16_t& repeatDelay = {},
+ const uint16_t& repeatInterval = {},
+ const uint16_t& slowKeysDelay = {},
+ const uint16_t& debounceDelay = {},
+ const uint16_t& mouseKeysDelay = {},
+ const uint16_t& mouseKeysInterval = {},
+ const uint16_t& mouseKeysTimeToMax = {},
+ const uint16_t& mouseKeysMaxSpeed = {},
+ const int16_t& mouseKeysCurve = {},
+ const uint16_t& accessXTimeout = {},
+ const BoolCtrl& accessXTimeoutMask = {},
+ const BoolCtrl& accessXTimeoutValues = {},
+ const AXOption& accessXTimeoutOptionsMask = {},
+ const AXOption& accessXTimeoutOptionsValues = {},
+ const std::array<uint8_t, 32>& perKeyRepeat = {});
+
+ struct GetMapRequest {
+ DeviceSpec deviceSpec{};
+ MapPart full{};
+ MapPart partial{};
+ uint8_t firstType{};
+ uint8_t nTypes{};
+ KeyCode firstKeySym{};
+ uint8_t nKeySyms{};
+ KeyCode firstKeyAction{};
+ uint8_t nKeyActions{};
+ KeyCode firstKeyBehavior{};
+ uint8_t nKeyBehaviors{};
+ VMod virtualMods{};
+ KeyCode firstKeyExplicit{};
+ uint8_t nKeyExplicit{};
+ KeyCode firstModMapKey{};
+ uint8_t nModMapKeys{};
+ KeyCode firstVModMapKey{};
+ uint8_t nVModMapKeys{};
+ };
+
+ struct GetMapReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ KeyCode minKeyCode{};
+ KeyCode maxKeyCode{};
+ uint8_t firstType{};
+ uint8_t nTypes{};
+ uint8_t totalTypes{};
+ KeyCode firstKeySym{};
+ uint16_t totalSyms{};
+ uint8_t nKeySyms{};
+ KeyCode firstKeyAction{};
+ uint16_t totalActions{};
+ uint8_t nKeyActions{};
+ KeyCode firstKeyBehavior{};
+ uint8_t nKeyBehaviors{};
+ uint8_t totalKeyBehaviors{};
+ KeyCode firstKeyExplicit{};
+ uint8_t nKeyExplicit{};
+ uint8_t totalKeyExplicit{};
+ KeyCode firstModMapKey{};
+ uint8_t nModMapKeys{};
+ uint8_t totalModMapKeys{};
+ KeyCode firstVModMapKey{};
+ uint8_t nVModMapKeys{};
+ uint8_t totalVModMapKeys{};
+ VMod virtualMods{};
+ base::Optional<std::vector<KeyType>> types_rtrn{};
+ base::Optional<std::vector<KeySymMap>> syms_rtrn{};
+ base::Optional<std::vector<uint8_t>> acts_rtrn_count{};
+ base::Optional<std::vector<Action>> acts_rtrn_acts{};
+ base::Optional<std::vector<SetBehavior>> behaviors_rtrn{};
+ base::Optional<std::vector<ModMask>> vmods_rtrn{};
+ base::Optional<std::vector<SetExplicit>> explicit_rtrn{};
+ base::Optional<std::vector<KeyModMap>> modmap_rtrn{};
+ base::Optional<std::vector<KeyVModMap>> vmodmap_rtrn{};
+ };
+
+ using GetMapResponse = Response<GetMapReply>;
+
+ Future<GetMapReply> GetMap(const GetMapRequest& request);
+
+ Future<GetMapReply> GetMap(const DeviceSpec& deviceSpec = {},
+ const MapPart& full = {},
+ const MapPart& partial = {},
+ const uint8_t& firstType = {},
+ const uint8_t& nTypes = {},
+ const KeyCode& firstKeySym = {},
+ const uint8_t& nKeySyms = {},
+ const KeyCode& firstKeyAction = {},
+ const uint8_t& nKeyActions = {},
+ const KeyCode& firstKeyBehavior = {},
+ const uint8_t& nKeyBehaviors = {},
+ const VMod& virtualMods = {},
+ const KeyCode& firstKeyExplicit = {},
+ const uint8_t& nKeyExplicit = {},
+ const KeyCode& firstModMapKey = {},
+ const uint8_t& nModMapKeys = {},
+ const KeyCode& firstVModMapKey = {},
+ const uint8_t& nVModMapKeys = {});
+
+ struct SetMapRequest {
+ DeviceSpec deviceSpec{};
+ SetMapFlags flags{};
+ KeyCode minKeyCode{};
+ KeyCode maxKeyCode{};
+ uint8_t firstType{};
+ uint8_t nTypes{};
+ KeyCode firstKeySym{};
+ uint8_t nKeySyms{};
+ uint16_t totalSyms{};
+ KeyCode firstKeyAction{};
+ uint8_t nKeyActions{};
+ uint16_t totalActions{};
+ KeyCode firstKeyBehavior{};
+ uint8_t nKeyBehaviors{};
+ uint8_t totalKeyBehaviors{};
+ KeyCode firstKeyExplicit{};
+ uint8_t nKeyExplicit{};
+ uint8_t totalKeyExplicit{};
+ KeyCode firstModMapKey{};
+ uint8_t nModMapKeys{};
+ uint8_t totalModMapKeys{};
+ KeyCode firstVModMapKey{};
+ uint8_t nVModMapKeys{};
+ uint8_t totalVModMapKeys{};
+ VMod virtualMods{};
+ base::Optional<std::vector<SetKeyType>> types{};
+ base::Optional<std::vector<KeySymMap>> syms{};
+ base::Optional<std::vector<uint8_t>> actionsCount{};
+ base::Optional<std::vector<Action>> actions{};
+ base::Optional<std::vector<SetBehavior>> behaviors{};
+ base::Optional<std::vector<uint8_t>> vmods{};
+ base::Optional<std::vector<SetExplicit>> c_explicit{};
+ base::Optional<std::vector<KeyModMap>> modmap{};
+ base::Optional<std::vector<KeyVModMap>> vmodmap{};
+ };
+
+ using SetMapResponse = Response<void>;
+
+ Future<void> SetMap(const SetMapRequest& request);
+
+ Future<void> SetMap(
+ const DeviceSpec& deviceSpec = {},
+ const SetMapFlags& flags = {},
+ const KeyCode& minKeyCode = {},
+ const KeyCode& maxKeyCode = {},
+ const uint8_t& firstType = {},
+ const uint8_t& nTypes = {},
+ const KeyCode& firstKeySym = {},
+ const uint8_t& nKeySyms = {},
+ const uint16_t& totalSyms = {},
+ const KeyCode& firstKeyAction = {},
+ const uint8_t& nKeyActions = {},
+ const uint16_t& totalActions = {},
+ const KeyCode& firstKeyBehavior = {},
+ const uint8_t& nKeyBehaviors = {},
+ const uint8_t& totalKeyBehaviors = {},
+ const KeyCode& firstKeyExplicit = {},
+ const uint8_t& nKeyExplicit = {},
+ const uint8_t& totalKeyExplicit = {},
+ const KeyCode& firstModMapKey = {},
+ const uint8_t& nModMapKeys = {},
+ const uint8_t& totalModMapKeys = {},
+ const KeyCode& firstVModMapKey = {},
+ const uint8_t& nVModMapKeys = {},
+ const uint8_t& totalVModMapKeys = {},
+ const VMod& virtualMods = {},
+ const base::Optional<std::vector<SetKeyType>>& types = base::nullopt,
+ const base::Optional<std::vector<KeySymMap>>& syms = base::nullopt,
+ const base::Optional<std::vector<uint8_t>>& actionsCount = base::nullopt,
+ const base::Optional<std::vector<Action>>& actions = base::nullopt,
+ const base::Optional<std::vector<SetBehavior>>& behaviors = base::nullopt,
+ const base::Optional<std::vector<uint8_t>>& vmods = base::nullopt,
+ const base::Optional<std::vector<SetExplicit>>& c_explicit =
+ base::nullopt,
+ const base::Optional<std::vector<KeyModMap>>& modmap = base::nullopt,
+ const base::Optional<std::vector<KeyVModMap>>& vmodmap = base::nullopt);
+
+ struct GetCompatMapRequest {
+ DeviceSpec deviceSpec{};
+ SetOfGroup groups{};
+ uint8_t getAllSI{};
+ uint16_t firstSI{};
+ uint16_t nSI{};
+ };
+
+ struct GetCompatMapReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ SetOfGroup groupsRtrn{};
+ uint16_t firstSIRtrn{};
+ uint16_t nTotalSI{};
+ std::vector<SymInterpret> si_rtrn{};
+ std::vector<ModDef> group_rtrn{};
+ };
+
+ using GetCompatMapResponse = Response<GetCompatMapReply>;
+
+ Future<GetCompatMapReply> GetCompatMap(const GetCompatMapRequest& request);
+
+ Future<GetCompatMapReply> GetCompatMap(const DeviceSpec& deviceSpec = {},
+ const SetOfGroup& groups = {},
+ const uint8_t& getAllSI = {},
+ const uint16_t& firstSI = {},
+ const uint16_t& nSI = {});
+
+ struct SetCompatMapRequest {
+ DeviceSpec deviceSpec{};
+ uint8_t recomputeActions{};
+ uint8_t truncateSI{};
+ SetOfGroup groups{};
+ uint16_t firstSI{};
+ std::vector<SymInterpret> si{};
+ std::vector<ModDef> groupMaps{};
+ };
+
+ using SetCompatMapResponse = Response<void>;
+
+ Future<void> SetCompatMap(const SetCompatMapRequest& request);
+
+ Future<void> SetCompatMap(const DeviceSpec& deviceSpec = {},
+ const uint8_t& recomputeActions = {},
+ const uint8_t& truncateSI = {},
+ const SetOfGroup& groups = {},
+ const uint16_t& firstSI = {},
+ const std::vector<SymInterpret>& si = {},
+ const std::vector<ModDef>& groupMaps = {});
+
+ struct GetIndicatorStateRequest {
+ DeviceSpec deviceSpec{};
+ };
+
+ struct GetIndicatorStateReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ uint32_t state{};
+ };
+
+ using GetIndicatorStateResponse = Response<GetIndicatorStateReply>;
+
+ Future<GetIndicatorStateReply> GetIndicatorState(
+ const GetIndicatorStateRequest& request);
+
+ Future<GetIndicatorStateReply> GetIndicatorState(
+ const DeviceSpec& deviceSpec = {});
+
+ struct GetIndicatorMapRequest {
+ DeviceSpec deviceSpec{};
+ uint32_t which{};
+ };
+
+ struct GetIndicatorMapReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ uint32_t which{};
+ uint32_t realIndicators{};
+ uint8_t nIndicators{};
+ std::vector<IndicatorMap> maps{};
+ };
+
+ using GetIndicatorMapResponse = Response<GetIndicatorMapReply>;
+
+ Future<GetIndicatorMapReply> GetIndicatorMap(
+ const GetIndicatorMapRequest& request);
+
+ Future<GetIndicatorMapReply> GetIndicatorMap(
+ const DeviceSpec& deviceSpec = {},
+ const uint32_t& which = {});
+
+ struct SetIndicatorMapRequest {
+ DeviceSpec deviceSpec{};
+ uint32_t which{};
+ std::vector<IndicatorMap> maps{};
+ };
+
+ using SetIndicatorMapResponse = Response<void>;
+
+ Future<void> SetIndicatorMap(const SetIndicatorMapRequest& request);
+
+ Future<void> SetIndicatorMap(const DeviceSpec& deviceSpec = {},
+ const uint32_t& which = {},
+ const std::vector<IndicatorMap>& maps = {});
+
+ struct GetNamedIndicatorRequest {
+ DeviceSpec deviceSpec{};
+ LedClass ledClass{};
+ IDSpec ledID{};
+ Atom indicator{};
+ };
+
+ struct GetNamedIndicatorReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ Atom indicator{};
+ uint8_t found{};
+ uint8_t on{};
+ uint8_t realIndicator{};
+ uint8_t ndx{};
+ IMFlag map_flags{};
+ IMGroupsWhich map_whichGroups{};
+ SetOfGroups map_groups{};
+ IMModsWhich map_whichMods{};
+ ModMask map_mods{};
+ ModMask map_realMods{};
+ VMod map_vmod{};
+ BoolCtrl map_ctrls{};
+ uint8_t supported{};
+ };
+
+ using GetNamedIndicatorResponse = Response<GetNamedIndicatorReply>;
+
+ Future<GetNamedIndicatorReply> GetNamedIndicator(
+ const GetNamedIndicatorRequest& request);
+
+ Future<GetNamedIndicatorReply> GetNamedIndicator(
+ const DeviceSpec& deviceSpec = {},
+ const LedClass& ledClass = {},
+ const IDSpec& ledID = {},
+ const Atom& indicator = {});
+
+ struct SetNamedIndicatorRequest {
+ DeviceSpec deviceSpec{};
+ LedClass ledClass{};
+ IDSpec ledID{};
+ Atom indicator{};
+ uint8_t setState{};
+ uint8_t on{};
+ uint8_t setMap{};
+ uint8_t createMap{};
+ IMFlag map_flags{};
+ IMGroupsWhich map_whichGroups{};
+ SetOfGroups map_groups{};
+ IMModsWhich map_whichMods{};
+ ModMask map_realMods{};
+ VMod map_vmods{};
+ BoolCtrl map_ctrls{};
+ };
+
+ using SetNamedIndicatorResponse = Response<void>;
+
+ Future<void> SetNamedIndicator(const SetNamedIndicatorRequest& request);
+
+ Future<void> SetNamedIndicator(const DeviceSpec& deviceSpec = {},
+ const LedClass& ledClass = {},
+ const IDSpec& ledID = {},
+ const Atom& indicator = {},
+ const uint8_t& setState = {},
+ const uint8_t& on = {},
+ const uint8_t& setMap = {},
+ const uint8_t& createMap = {},
+ const IMFlag& map_flags = {},
+ const IMGroupsWhich& map_whichGroups = {},
+ const SetOfGroups& map_groups = {},
+ const IMModsWhich& map_whichMods = {},
+ const ModMask& map_realMods = {},
+ const VMod& map_vmods = {},
+ const BoolCtrl& map_ctrls = {});
+
+ struct GetNamesRequest {
+ DeviceSpec deviceSpec{};
+ NameDetail which{};
+ };
+
+ struct GetNamesReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ KeyCode minKeyCode{};
+ KeyCode maxKeyCode{};
+ uint8_t nTypes{};
+ SetOfGroup groupNames{};
+ VMod virtualMods{};
+ KeyCode firstKey{};
+ uint8_t nKeys{};
+ uint32_t indicators{};
+ uint8_t nRadioGroups{};
+ uint8_t nKeyAliases{};
+ uint16_t nKTLevels{};
+ base::Optional<Atom> keycodesName{};
+ base::Optional<Atom> geometryName{};
+ base::Optional<Atom> symbolsName{};
+ base::Optional<Atom> physSymbolsName{};
+ base::Optional<Atom> typesName{};
+ base::Optional<Atom> compatName{};
+ base::Optional<std::vector<Atom>> typeNames{};
+ base::Optional<std::vector<uint8_t>> nLevelsPerType{};
+ base::Optional<std::vector<Atom>> ktLevelNames{};
+ base::Optional<std::vector<Atom>> indicatorNames{};
+ base::Optional<std::vector<Atom>> virtualModNames{};
+ base::Optional<std::vector<Atom>> groups{};
+ base::Optional<std::vector<KeyName>> keyNames{};
+ base::Optional<std::vector<KeyAlias>> keyAliases{};
+ base::Optional<std::vector<Atom>> radioGroupNames{};
+ };
+
+ using GetNamesResponse = Response<GetNamesReply>;
+
+ Future<GetNamesReply> GetNames(const GetNamesRequest& request);
+
+ Future<GetNamesReply> GetNames(const DeviceSpec& deviceSpec = {},
+ const NameDetail& which = {});
+
+ struct SetNamesRequest {
+ DeviceSpec deviceSpec{};
+ VMod virtualMods{};
+ uint8_t firstType{};
+ uint8_t nTypes{};
+ uint8_t firstKTLevelt{};
+ uint8_t nKTLevels{};
+ uint32_t indicators{};
+ SetOfGroup groupNames{};
+ uint8_t nRadioGroups{};
+ KeyCode firstKey{};
+ uint8_t nKeys{};
+ uint8_t nKeyAliases{};
+ uint16_t totalKTLevelNames{};
+ base::Optional<Atom> keycodesName{};
+ base::Optional<Atom> geometryName{};
+ base::Optional<Atom> symbolsName{};
+ base::Optional<Atom> physSymbolsName{};
+ base::Optional<Atom> typesName{};
+ base::Optional<Atom> compatName{};
+ base::Optional<std::vector<Atom>> typeNames{};
+ base::Optional<std::vector<uint8_t>> nLevelsPerType{};
+ base::Optional<std::vector<Atom>> ktLevelNames{};
+ base::Optional<std::vector<Atom>> indicatorNames{};
+ base::Optional<std::vector<Atom>> virtualModNames{};
+ base::Optional<std::vector<Atom>> groups{};
+ base::Optional<std::vector<KeyName>> keyNames{};
+ base::Optional<std::vector<KeyAlias>> keyAliases{};
+ base::Optional<std::vector<Atom>> radioGroupNames{};
+ };
+
+ using SetNamesResponse = Response<void>;
+
+ Future<void> SetNames(const SetNamesRequest& request);
+
+ Future<void> SetNames(
+ const DeviceSpec& deviceSpec = {},
+ const VMod& virtualMods = {},
+ const uint8_t& firstType = {},
+ const uint8_t& nTypes = {},
+ const uint8_t& firstKTLevelt = {},
+ const uint8_t& nKTLevels = {},
+ const uint32_t& indicators = {},
+ const SetOfGroup& groupNames = {},
+ const uint8_t& nRadioGroups = {},
+ const KeyCode& firstKey = {},
+ const uint8_t& nKeys = {},
+ const uint8_t& nKeyAliases = {},
+ const uint16_t& totalKTLevelNames = {},
+ const base::Optional<Atom>& keycodesName = base::nullopt,
+ const base::Optional<Atom>& geometryName = base::nullopt,
+ const base::Optional<Atom>& symbolsName = base::nullopt,
+ const base::Optional<Atom>& physSymbolsName = base::nullopt,
+ const base::Optional<Atom>& typesName = base::nullopt,
+ const base::Optional<Atom>& compatName = base::nullopt,
+ const base::Optional<std::vector<Atom>>& typeNames = base::nullopt,
+ const base::Optional<std::vector<uint8_t>>& nLevelsPerType =
+ base::nullopt,
+ const base::Optional<std::vector<Atom>>& ktLevelNames = base::nullopt,
+ const base::Optional<std::vector<Atom>>& indicatorNames = base::nullopt,
+ const base::Optional<std::vector<Atom>>& virtualModNames = base::nullopt,
+ const base::Optional<std::vector<Atom>>& groups = base::nullopt,
+ const base::Optional<std::vector<KeyName>>& keyNames = base::nullopt,
+ const base::Optional<std::vector<KeyAlias>>& keyAliases = base::nullopt,
+ const base::Optional<std::vector<Atom>>& radioGroupNames = base::nullopt);
+
+ struct PerClientFlagsRequest {
+ DeviceSpec deviceSpec{};
+ PerClientFlag change{};
+ PerClientFlag value{};
+ BoolCtrl ctrlsToChange{};
+ BoolCtrl autoCtrls{};
+ BoolCtrl autoCtrlsValues{};
+ };
+
+ struct PerClientFlagsReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ PerClientFlag supported{};
+ PerClientFlag value{};
+ BoolCtrl autoCtrls{};
+ BoolCtrl autoCtrlsValues{};
+ };
+
+ using PerClientFlagsResponse = Response<PerClientFlagsReply>;
+
+ Future<PerClientFlagsReply> PerClientFlags(
+ const PerClientFlagsRequest& request);
+
+ Future<PerClientFlagsReply> PerClientFlags(
+ const DeviceSpec& deviceSpec = {},
+ const PerClientFlag& change = {},
+ const PerClientFlag& value = {},
+ const BoolCtrl& ctrlsToChange = {},
+ const BoolCtrl& autoCtrls = {},
+ const BoolCtrl& autoCtrlsValues = {});
+
+ struct ListComponentsRequest {
+ DeviceSpec deviceSpec{};
+ uint16_t maxNames{};
+ };
+
+ struct ListComponentsReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ uint16_t extra{};
+ std::vector<Listing> keymaps{};
+ std::vector<Listing> keycodes{};
+ std::vector<Listing> types{};
+ std::vector<Listing> compatMaps{};
+ std::vector<Listing> symbols{};
+ std::vector<Listing> geometries{};
+ };
+
+ using ListComponentsResponse = Response<ListComponentsReply>;
+
+ Future<ListComponentsReply> ListComponents(
+ const ListComponentsRequest& request);
+
+ Future<ListComponentsReply> ListComponents(const DeviceSpec& deviceSpec = {},
+ const uint16_t& maxNames = {});
+
+ struct GetKbdByNameRequest {
+ DeviceSpec deviceSpec{};
+ GBNDetail need{};
+ GBNDetail want{};
+ uint8_t load{};
+ };
+
+ struct GetKbdByNameReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ KeyCode minKeyCode{};
+ KeyCode maxKeyCode{};
+ uint8_t loaded{};
+ uint8_t newKeyboard{};
+ GBNDetail found{};
+ struct Types {
+ uint8_t getmap_type{};
+ uint8_t typeDeviceID{};
+ uint16_t getmap_sequence{};
+ uint32_t getmap_length{};
+ KeyCode typeMinKeyCode{};
+ KeyCode typeMaxKeyCode{};
+ uint8_t firstType{};
+ uint8_t nTypes{};
+ uint8_t totalTypes{};
+ KeyCode firstKeySym{};
+ uint16_t totalSyms{};
+ uint8_t nKeySyms{};
+ KeyCode firstKeyAction{};
+ uint16_t totalActions{};
+ uint8_t nKeyActions{};
+ KeyCode firstKeyBehavior{};
+ uint8_t nKeyBehaviors{};
+ uint8_t totalKeyBehaviors{};
+ KeyCode firstKeyExplicit{};
+ uint8_t nKeyExplicit{};
+ uint8_t totalKeyExplicit{};
+ KeyCode firstModMapKey{};
+ uint8_t nModMapKeys{};
+ uint8_t totalModMapKeys{};
+ KeyCode firstVModMapKey{};
+ uint8_t nVModMapKeys{};
+ uint8_t totalVModMapKeys{};
+ VMod virtualMods{};
+ base::Optional<std::vector<KeyType>> types_rtrn{};
+ base::Optional<std::vector<KeySymMap>> syms_rtrn{};
+ base::Optional<std::vector<uint8_t>> acts_rtrn_count{};
+ base::Optional<std::vector<Action>> acts_rtrn_acts{};
+ base::Optional<std::vector<SetBehavior>> behaviors_rtrn{};
+ base::Optional<std::vector<ModMask>> vmods_rtrn{};
+ base::Optional<std::vector<SetExplicit>> explicit_rtrn{};
+ base::Optional<std::vector<KeyModMap>> modmap_rtrn{};
+ base::Optional<std::vector<KeyVModMap>> vmodmap_rtrn{};
+ };
+ struct CompatMap {
+ uint8_t compatmap_type{};
+ uint8_t compatDeviceID{};
+ uint16_t compatmap_sequence{};
+ uint32_t compatmap_length{};
+ SetOfGroup groupsRtrn{};
+ uint16_t firstSIRtrn{};
+ uint16_t nTotalSI{};
+ std::vector<SymInterpret> si_rtrn{};
+ std::vector<ModDef> group_rtrn{};
+ };
+ struct IndicatorMaps {
+ uint8_t indicatormap_type{};
+ uint8_t indicatorDeviceID{};
+ uint16_t indicatormap_sequence{};
+ uint32_t indicatormap_length{};
+ uint32_t which{};
+ uint32_t realIndicators{};
+ std::vector<IndicatorMap> maps{};
+ };
+ struct KeyNames {
+ uint8_t keyname_type{};
+ uint8_t keyDeviceID{};
+ uint16_t keyname_sequence{};
+ uint32_t keyname_length{};
+ KeyCode keyMinKeyCode{};
+ KeyCode keyMaxKeyCode{};
+ uint8_t nTypes{};
+ SetOfGroup groupNames{};
+ VMod virtualMods{};
+ KeyCode firstKey{};
+ uint8_t nKeys{};
+ uint32_t indicators{};
+ uint8_t nRadioGroups{};
+ uint8_t nKeyAliases{};
+ uint16_t nKTLevels{};
+ base::Optional<Atom> keycodesName{};
+ base::Optional<Atom> geometryName{};
+ base::Optional<Atom> symbolsName{};
+ base::Optional<Atom> physSymbolsName{};
+ base::Optional<Atom> typesName{};
+ base::Optional<Atom> compatName{};
+ base::Optional<std::vector<Atom>> typeNames{};
+ base::Optional<std::vector<uint8_t>> nLevelsPerType{};
+ base::Optional<std::vector<Atom>> ktLevelNames{};
+ base::Optional<std::vector<Atom>> indicatorNames{};
+ base::Optional<std::vector<Atom>> virtualModNames{};
+ base::Optional<std::vector<Atom>> groups{};
+ base::Optional<std::vector<KeyName>> keyNames{};
+ base::Optional<std::vector<KeyAlias>> keyAliases{};
+ base::Optional<std::vector<Atom>> radioGroupNames{};
+ };
+ struct Geometry {
+ uint8_t geometry_type{};
+ uint8_t geometryDeviceID{};
+ uint16_t geometry_sequence{};
+ uint32_t geometry_length{};
+ Atom name{};
+ uint8_t geometryFound{};
+ uint16_t widthMM{};
+ uint16_t heightMM{};
+ uint16_t nProperties{};
+ uint16_t nColors{};
+ uint16_t nShapes{};
+ uint16_t nSections{};
+ uint16_t nDoodads{};
+ uint16_t nKeyAliases{};
+ uint8_t baseColorNdx{};
+ uint8_t labelColorNdx{};
+ CountedString16 labelFont{};
+ };
+ base::Optional<Types> types{};
+ base::Optional<CompatMap> compat_map{};
+ base::Optional<IndicatorMaps> indicator_maps{};
+ base::Optional<KeyNames> key_names{};
+ base::Optional<Geometry> geometry{};
+ };
+
+ using GetKbdByNameResponse = Response<GetKbdByNameReply>;
+
+ Future<GetKbdByNameReply> GetKbdByName(const GetKbdByNameRequest& request);
+
+ Future<GetKbdByNameReply> GetKbdByName(const DeviceSpec& deviceSpec = {},
+ const GBNDetail& need = {},
+ const GBNDetail& want = {},
+ const uint8_t& load = {});
+
+ struct GetDeviceInfoRequest {
+ DeviceSpec deviceSpec{};
+ XIFeature wanted{};
+ uint8_t allButtons{};
+ uint8_t firstButton{};
+ uint8_t nButtons{};
+ LedClass ledClass{};
+ IDSpec ledID{};
+ };
+
+ struct GetDeviceInfoReply {
+ uint8_t deviceID{};
+ uint16_t sequence{};
+ XIFeature present{};
+ XIFeature supported{};
+ XIFeature unsupported{};
+ uint8_t firstBtnWanted{};
+ uint8_t nBtnsWanted{};
+ uint8_t firstBtnRtrn{};
+ uint8_t totalBtns{};
+ uint8_t hasOwnState{};
+ uint16_t dfltKbdFB{};
+ uint16_t dfltLedFB{};
+ Atom devType{};
+ std::vector<String8> name{};
+ std::vector<Action> btnActions{};
+ std::vector<DeviceLedInfo> leds{};
+ };
+
+ using GetDeviceInfoResponse = Response<GetDeviceInfoReply>;
+
+ Future<GetDeviceInfoReply> GetDeviceInfo(const GetDeviceInfoRequest& request);
+
+ Future<GetDeviceInfoReply> GetDeviceInfo(const DeviceSpec& deviceSpec = {},
+ const XIFeature& wanted = {},
+ const uint8_t& allButtons = {},
+ const uint8_t& firstButton = {},
+ const uint8_t& nButtons = {},
+ const LedClass& ledClass = {},
+ const IDSpec& ledID = {});
+
+ struct SetDeviceInfoRequest {
+ DeviceSpec deviceSpec{};
+ uint8_t firstBtn{};
+ XIFeature change{};
+ std::vector<Action> btnActions{};
+ std::vector<DeviceLedInfo> leds{};
+ };
+
+ using SetDeviceInfoResponse = Response<void>;
+
+ Future<void> SetDeviceInfo(const SetDeviceInfoRequest& request);
+
+ Future<void> SetDeviceInfo(const DeviceSpec& deviceSpec = {},
+ const uint8_t& firstBtn = {},
+ const XIFeature& change = {},
+ const std::vector<Action>& btnActions = {},
+ const std::vector<DeviceLedInfo>& leds = {});
+
+ struct SetDebuggingFlagsRequest {
+ uint32_t affectFlags{};
+ uint32_t flags{};
+ uint32_t affectCtrls{};
+ uint32_t ctrls{};
+ std::vector<String8> message{};
+ };
+
+ struct SetDebuggingFlagsReply {
+ uint16_t sequence{};
+ uint32_t currentFlags{};
+ uint32_t currentCtrls{};
+ uint32_t supportedFlags{};
+ uint32_t supportedCtrls{};
+ };
+
+ using SetDebuggingFlagsResponse = Response<SetDebuggingFlagsReply>;
+
+ Future<SetDebuggingFlagsReply> SetDebuggingFlags(
+ const SetDebuggingFlagsRequest& request);
+
+ Future<SetDebuggingFlagsReply> SetDebuggingFlags(
+ const uint32_t& affectFlags = {},
+ const uint32_t& flags = {},
+ const uint32_t& affectCtrls = {},
+ const uint32_t& ctrls = {},
+ const std::vector<String8>& message = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Xkb::Const operator|(x11::Xkb::Const l,
+ x11::Xkb::Const r) {
+ using T = std::underlying_type_t<x11::Xkb::Const>;
+ return static_cast<x11::Xkb::Const>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Const operator&(x11::Xkb::Const l,
+ x11::Xkb::Const r) {
+ using T = std::underlying_type_t<x11::Xkb::Const>;
+ return static_cast<x11::Xkb::Const>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::EventType operator|(x11::Xkb::EventType l,
+ x11::Xkb::EventType r) {
+ using T = std::underlying_type_t<x11::Xkb::EventType>;
+ return static_cast<x11::Xkb::EventType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::EventType operator&(x11::Xkb::EventType l,
+ x11::Xkb::EventType r) {
+ using T = std::underlying_type_t<x11::Xkb::EventType>;
+ return static_cast<x11::Xkb::EventType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::NKNDetail operator|(x11::Xkb::NKNDetail l,
+ x11::Xkb::NKNDetail r) {
+ using T = std::underlying_type_t<x11::Xkb::NKNDetail>;
+ return static_cast<x11::Xkb::NKNDetail>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::NKNDetail operator&(x11::Xkb::NKNDetail l,
+ x11::Xkb::NKNDetail r) {
+ using T = std::underlying_type_t<x11::Xkb::NKNDetail>;
+ return static_cast<x11::Xkb::NKNDetail>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::AXNDetail operator|(x11::Xkb::AXNDetail l,
+ x11::Xkb::AXNDetail r) {
+ using T = std::underlying_type_t<x11::Xkb::AXNDetail>;
+ return static_cast<x11::Xkb::AXNDetail>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::AXNDetail operator&(x11::Xkb::AXNDetail l,
+ x11::Xkb::AXNDetail r) {
+ using T = std::underlying_type_t<x11::Xkb::AXNDetail>;
+ return static_cast<x11::Xkb::AXNDetail>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::MapPart operator|(x11::Xkb::MapPart l,
+ x11::Xkb::MapPart r) {
+ using T = std::underlying_type_t<x11::Xkb::MapPart>;
+ return static_cast<x11::Xkb::MapPart>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::MapPart operator&(x11::Xkb::MapPart l,
+ x11::Xkb::MapPart r) {
+ using T = std::underlying_type_t<x11::Xkb::MapPart>;
+ return static_cast<x11::Xkb::MapPart>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SetMapFlags operator|(x11::Xkb::SetMapFlags l,
+ x11::Xkb::SetMapFlags r) {
+ using T = std::underlying_type_t<x11::Xkb::SetMapFlags>;
+ return static_cast<x11::Xkb::SetMapFlags>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SetMapFlags operator&(x11::Xkb::SetMapFlags l,
+ x11::Xkb::SetMapFlags r) {
+ using T = std::underlying_type_t<x11::Xkb::SetMapFlags>;
+ return static_cast<x11::Xkb::SetMapFlags>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::StatePart operator|(x11::Xkb::StatePart l,
+ x11::Xkb::StatePart r) {
+ using T = std::underlying_type_t<x11::Xkb::StatePart>;
+ return static_cast<x11::Xkb::StatePart>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::StatePart operator&(x11::Xkb::StatePart l,
+ x11::Xkb::StatePart r) {
+ using T = std::underlying_type_t<x11::Xkb::StatePart>;
+ return static_cast<x11::Xkb::StatePart>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BoolCtrl operator|(x11::Xkb::BoolCtrl l,
+ x11::Xkb::BoolCtrl r) {
+ using T = std::underlying_type_t<x11::Xkb::BoolCtrl>;
+ return static_cast<x11::Xkb::BoolCtrl>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BoolCtrl operator&(x11::Xkb::BoolCtrl l,
+ x11::Xkb::BoolCtrl r) {
+ using T = std::underlying_type_t<x11::Xkb::BoolCtrl>;
+ return static_cast<x11::Xkb::BoolCtrl>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Control operator|(x11::Xkb::Control l,
+ x11::Xkb::Control r) {
+ using T = std::underlying_type_t<x11::Xkb::Control>;
+ return static_cast<x11::Xkb::Control>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Control operator&(x11::Xkb::Control l,
+ x11::Xkb::Control r) {
+ using T = std::underlying_type_t<x11::Xkb::Control>;
+ return static_cast<x11::Xkb::Control>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::AXOption operator|(x11::Xkb::AXOption l,
+ x11::Xkb::AXOption r) {
+ using T = std::underlying_type_t<x11::Xkb::AXOption>;
+ return static_cast<x11::Xkb::AXOption>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::AXOption operator&(x11::Xkb::AXOption l,
+ x11::Xkb::AXOption r) {
+ using T = std::underlying_type_t<x11::Xkb::AXOption>;
+ return static_cast<x11::Xkb::AXOption>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::LedClassResult operator|(
+ x11::Xkb::LedClassResult l,
+ x11::Xkb::LedClassResult r) {
+ using T = std::underlying_type_t<x11::Xkb::LedClassResult>;
+ return static_cast<x11::Xkb::LedClassResult>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::LedClassResult operator&(
+ x11::Xkb::LedClassResult l,
+ x11::Xkb::LedClassResult r) {
+ using T = std::underlying_type_t<x11::Xkb::LedClassResult>;
+ return static_cast<x11::Xkb::LedClassResult>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::LedClass operator|(x11::Xkb::LedClass l,
+ x11::Xkb::LedClass r) {
+ using T = std::underlying_type_t<x11::Xkb::LedClass>;
+ return static_cast<x11::Xkb::LedClass>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::LedClass operator&(x11::Xkb::LedClass l,
+ x11::Xkb::LedClass r) {
+ using T = std::underlying_type_t<x11::Xkb::LedClass>;
+ return static_cast<x11::Xkb::LedClass>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BellClassResult operator|(
+ x11::Xkb::BellClassResult l,
+ x11::Xkb::BellClassResult r) {
+ using T = std::underlying_type_t<x11::Xkb::BellClassResult>;
+ return static_cast<x11::Xkb::BellClassResult>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BellClassResult operator&(
+ x11::Xkb::BellClassResult l,
+ x11::Xkb::BellClassResult r) {
+ using T = std::underlying_type_t<x11::Xkb::BellClassResult>;
+ return static_cast<x11::Xkb::BellClassResult>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BellClass operator|(x11::Xkb::BellClass l,
+ x11::Xkb::BellClass r) {
+ using T = std::underlying_type_t<x11::Xkb::BellClass>;
+ return static_cast<x11::Xkb::BellClass>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BellClass operator&(x11::Xkb::BellClass l,
+ x11::Xkb::BellClass r) {
+ using T = std::underlying_type_t<x11::Xkb::BellClass>;
+ return static_cast<x11::Xkb::BellClass>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Id operator|(x11::Xkb::Id l, x11::Xkb::Id r) {
+ using T = std::underlying_type_t<x11::Xkb::Id>;
+ return static_cast<x11::Xkb::Id>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Id operator&(x11::Xkb::Id l, x11::Xkb::Id r) {
+ using T = std::underlying_type_t<x11::Xkb::Id>;
+ return static_cast<x11::Xkb::Id>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Group operator|(x11::Xkb::Group l,
+ x11::Xkb::Group r) {
+ using T = std::underlying_type_t<x11::Xkb::Group>;
+ return static_cast<x11::Xkb::Group>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Group operator&(x11::Xkb::Group l,
+ x11::Xkb::Group r) {
+ using T = std::underlying_type_t<x11::Xkb::Group>;
+ return static_cast<x11::Xkb::Group>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Groups operator|(x11::Xkb::Groups l,
+ x11::Xkb::Groups r) {
+ using T = std::underlying_type_t<x11::Xkb::Groups>;
+ return static_cast<x11::Xkb::Groups>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Groups operator&(x11::Xkb::Groups l,
+ x11::Xkb::Groups r) {
+ using T = std::underlying_type_t<x11::Xkb::Groups>;
+ return static_cast<x11::Xkb::Groups>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SetOfGroup operator|(x11::Xkb::SetOfGroup l,
+ x11::Xkb::SetOfGroup r) {
+ using T = std::underlying_type_t<x11::Xkb::SetOfGroup>;
+ return static_cast<x11::Xkb::SetOfGroup>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SetOfGroup operator&(x11::Xkb::SetOfGroup l,
+ x11::Xkb::SetOfGroup r) {
+ using T = std::underlying_type_t<x11::Xkb::SetOfGroup>;
+ return static_cast<x11::Xkb::SetOfGroup>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SetOfGroups operator|(x11::Xkb::SetOfGroups l,
+ x11::Xkb::SetOfGroups r) {
+ using T = std::underlying_type_t<x11::Xkb::SetOfGroups>;
+ return static_cast<x11::Xkb::SetOfGroups>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SetOfGroups operator&(x11::Xkb::SetOfGroups l,
+ x11::Xkb::SetOfGroups r) {
+ using T = std::underlying_type_t<x11::Xkb::SetOfGroups>;
+ return static_cast<x11::Xkb::SetOfGroups>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::GroupsWrap operator|(x11::Xkb::GroupsWrap l,
+ x11::Xkb::GroupsWrap r) {
+ using T = std::underlying_type_t<x11::Xkb::GroupsWrap>;
+ return static_cast<x11::Xkb::GroupsWrap>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::GroupsWrap operator&(x11::Xkb::GroupsWrap l,
+ x11::Xkb::GroupsWrap r) {
+ using T = std::underlying_type_t<x11::Xkb::GroupsWrap>;
+ return static_cast<x11::Xkb::GroupsWrap>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::VModsHigh operator|(x11::Xkb::VModsHigh l,
+ x11::Xkb::VModsHigh r) {
+ using T = std::underlying_type_t<x11::Xkb::VModsHigh>;
+ return static_cast<x11::Xkb::VModsHigh>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::VModsHigh operator&(x11::Xkb::VModsHigh l,
+ x11::Xkb::VModsHigh r) {
+ using T = std::underlying_type_t<x11::Xkb::VModsHigh>;
+ return static_cast<x11::Xkb::VModsHigh>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::VModsLow operator|(x11::Xkb::VModsLow l,
+ x11::Xkb::VModsLow r) {
+ using T = std::underlying_type_t<x11::Xkb::VModsLow>;
+ return static_cast<x11::Xkb::VModsLow>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::VModsLow operator&(x11::Xkb::VModsLow l,
+ x11::Xkb::VModsLow r) {
+ using T = std::underlying_type_t<x11::Xkb::VModsLow>;
+ return static_cast<x11::Xkb::VModsLow>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::VMod operator|(x11::Xkb::VMod l, x11::Xkb::VMod r) {
+ using T = std::underlying_type_t<x11::Xkb::VMod>;
+ return static_cast<x11::Xkb::VMod>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::VMod operator&(x11::Xkb::VMod l, x11::Xkb::VMod r) {
+ using T = std::underlying_type_t<x11::Xkb::VMod>;
+ return static_cast<x11::Xkb::VMod>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Explicit operator|(x11::Xkb::Explicit l,
+ x11::Xkb::Explicit r) {
+ using T = std::underlying_type_t<x11::Xkb::Explicit>;
+ return static_cast<x11::Xkb::Explicit>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Explicit operator&(x11::Xkb::Explicit l,
+ x11::Xkb::Explicit r) {
+ using T = std::underlying_type_t<x11::Xkb::Explicit>;
+ return static_cast<x11::Xkb::Explicit>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SymInterpretMatch operator|(
+ x11::Xkb::SymInterpretMatch l,
+ x11::Xkb::SymInterpretMatch r) {
+ using T = std::underlying_type_t<x11::Xkb::SymInterpretMatch>;
+ return static_cast<x11::Xkb::SymInterpretMatch>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SymInterpretMatch operator&(
+ x11::Xkb::SymInterpretMatch l,
+ x11::Xkb::SymInterpretMatch r) {
+ using T = std::underlying_type_t<x11::Xkb::SymInterpretMatch>;
+ return static_cast<x11::Xkb::SymInterpretMatch>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SymInterpMatch operator|(
+ x11::Xkb::SymInterpMatch l,
+ x11::Xkb::SymInterpMatch r) {
+ using T = std::underlying_type_t<x11::Xkb::SymInterpMatch>;
+ return static_cast<x11::Xkb::SymInterpMatch>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SymInterpMatch operator&(
+ x11::Xkb::SymInterpMatch l,
+ x11::Xkb::SymInterpMatch r) {
+ using T = std::underlying_type_t<x11::Xkb::SymInterpMatch>;
+ return static_cast<x11::Xkb::SymInterpMatch>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::IMFlag operator|(x11::Xkb::IMFlag l,
+ x11::Xkb::IMFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::IMFlag>;
+ return static_cast<x11::Xkb::IMFlag>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::IMFlag operator&(x11::Xkb::IMFlag l,
+ x11::Xkb::IMFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::IMFlag>;
+ return static_cast<x11::Xkb::IMFlag>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::IMModsWhich operator|(x11::Xkb::IMModsWhich l,
+ x11::Xkb::IMModsWhich r) {
+ using T = std::underlying_type_t<x11::Xkb::IMModsWhich>;
+ return static_cast<x11::Xkb::IMModsWhich>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::IMModsWhich operator&(x11::Xkb::IMModsWhich l,
+ x11::Xkb::IMModsWhich r) {
+ using T = std::underlying_type_t<x11::Xkb::IMModsWhich>;
+ return static_cast<x11::Xkb::IMModsWhich>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::IMGroupsWhich operator|(x11::Xkb::IMGroupsWhich l,
+ x11::Xkb::IMGroupsWhich r) {
+ using T = std::underlying_type_t<x11::Xkb::IMGroupsWhich>;
+ return static_cast<x11::Xkb::IMGroupsWhich>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::IMGroupsWhich operator&(x11::Xkb::IMGroupsWhich l,
+ x11::Xkb::IMGroupsWhich r) {
+ using T = std::underlying_type_t<x11::Xkb::IMGroupsWhich>;
+ return static_cast<x11::Xkb::IMGroupsWhich>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::CMDetail operator|(x11::Xkb::CMDetail l,
+ x11::Xkb::CMDetail r) {
+ using T = std::underlying_type_t<x11::Xkb::CMDetail>;
+ return static_cast<x11::Xkb::CMDetail>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::CMDetail operator&(x11::Xkb::CMDetail l,
+ x11::Xkb::CMDetail r) {
+ using T = std::underlying_type_t<x11::Xkb::CMDetail>;
+ return static_cast<x11::Xkb::CMDetail>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::NameDetail operator|(x11::Xkb::NameDetail l,
+ x11::Xkb::NameDetail r) {
+ using T = std::underlying_type_t<x11::Xkb::NameDetail>;
+ return static_cast<x11::Xkb::NameDetail>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::NameDetail operator&(x11::Xkb::NameDetail l,
+ x11::Xkb::NameDetail r) {
+ using T = std::underlying_type_t<x11::Xkb::NameDetail>;
+ return static_cast<x11::Xkb::NameDetail>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::GBNDetail operator|(x11::Xkb::GBNDetail l,
+ x11::Xkb::GBNDetail r) {
+ using T = std::underlying_type_t<x11::Xkb::GBNDetail>;
+ return static_cast<x11::Xkb::GBNDetail>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::GBNDetail operator&(x11::Xkb::GBNDetail l,
+ x11::Xkb::GBNDetail r) {
+ using T = std::underlying_type_t<x11::Xkb::GBNDetail>;
+ return static_cast<x11::Xkb::GBNDetail>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::XIFeature operator|(x11::Xkb::XIFeature l,
+ x11::Xkb::XIFeature r) {
+ using T = std::underlying_type_t<x11::Xkb::XIFeature>;
+ return static_cast<x11::Xkb::XIFeature>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::XIFeature operator&(x11::Xkb::XIFeature l,
+ x11::Xkb::XIFeature r) {
+ using T = std::underlying_type_t<x11::Xkb::XIFeature>;
+ return static_cast<x11::Xkb::XIFeature>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::PerClientFlag operator|(x11::Xkb::PerClientFlag l,
+ x11::Xkb::PerClientFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::PerClientFlag>;
+ return static_cast<x11::Xkb::PerClientFlag>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::PerClientFlag operator&(x11::Xkb::PerClientFlag l,
+ x11::Xkb::PerClientFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::PerClientFlag>;
+ return static_cast<x11::Xkb::PerClientFlag>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BehaviorType operator|(x11::Xkb::BehaviorType l,
+ x11::Xkb::BehaviorType r) {
+ using T = std::underlying_type_t<x11::Xkb::BehaviorType>;
+ return static_cast<x11::Xkb::BehaviorType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BehaviorType operator&(x11::Xkb::BehaviorType l,
+ x11::Xkb::BehaviorType r) {
+ using T = std::underlying_type_t<x11::Xkb::BehaviorType>;
+ return static_cast<x11::Xkb::BehaviorType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::DoodadType operator|(x11::Xkb::DoodadType l,
+ x11::Xkb::DoodadType r) {
+ using T = std::underlying_type_t<x11::Xkb::DoodadType>;
+ return static_cast<x11::Xkb::DoodadType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::DoodadType operator&(x11::Xkb::DoodadType l,
+ x11::Xkb::DoodadType r) {
+ using T = std::underlying_type_t<x11::Xkb::DoodadType>;
+ return static_cast<x11::Xkb::DoodadType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Error operator|(x11::Xkb::Error l,
+ x11::Xkb::Error r) {
+ using T = std::underlying_type_t<x11::Xkb::Error>;
+ return static_cast<x11::Xkb::Error>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Error operator&(x11::Xkb::Error l,
+ x11::Xkb::Error r) {
+ using T = std::underlying_type_t<x11::Xkb::Error>;
+ return static_cast<x11::Xkb::Error>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Sa operator|(x11::Xkb::Sa l, x11::Xkb::Sa r) {
+ using T = std::underlying_type_t<x11::Xkb::Sa>;
+ return static_cast<x11::Xkb::Sa>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::Sa operator&(x11::Xkb::Sa l, x11::Xkb::Sa r) {
+ using T = std::underlying_type_t<x11::Xkb::Sa>;
+ return static_cast<x11::Xkb::Sa>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SAType operator|(x11::Xkb::SAType l,
+ x11::Xkb::SAType r) {
+ using T = std::underlying_type_t<x11::Xkb::SAType>;
+ return static_cast<x11::Xkb::SAType>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SAType operator&(x11::Xkb::SAType l,
+ x11::Xkb::SAType r) {
+ using T = std::underlying_type_t<x11::Xkb::SAType>;
+ return static_cast<x11::Xkb::SAType>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SAMovePtrFlag operator|(x11::Xkb::SAMovePtrFlag l,
+ x11::Xkb::SAMovePtrFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::SAMovePtrFlag>;
+ return static_cast<x11::Xkb::SAMovePtrFlag>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SAMovePtrFlag operator&(x11::Xkb::SAMovePtrFlag l,
+ x11::Xkb::SAMovePtrFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::SAMovePtrFlag>;
+ return static_cast<x11::Xkb::SAMovePtrFlag>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SASetPtrDfltFlag operator|(
+ x11::Xkb::SASetPtrDfltFlag l,
+ x11::Xkb::SASetPtrDfltFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::SASetPtrDfltFlag>;
+ return static_cast<x11::Xkb::SASetPtrDfltFlag>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SASetPtrDfltFlag operator&(
+ x11::Xkb::SASetPtrDfltFlag l,
+ x11::Xkb::SASetPtrDfltFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::SASetPtrDfltFlag>;
+ return static_cast<x11::Xkb::SASetPtrDfltFlag>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SAIsoLockFlag operator|(x11::Xkb::SAIsoLockFlag l,
+ x11::Xkb::SAIsoLockFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::SAIsoLockFlag>;
+ return static_cast<x11::Xkb::SAIsoLockFlag>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SAIsoLockFlag operator&(x11::Xkb::SAIsoLockFlag l,
+ x11::Xkb::SAIsoLockFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::SAIsoLockFlag>;
+ return static_cast<x11::Xkb::SAIsoLockFlag>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SAIsoLockNoAffect operator|(
+ x11::Xkb::SAIsoLockNoAffect l,
+ x11::Xkb::SAIsoLockNoAffect r) {
+ using T = std::underlying_type_t<x11::Xkb::SAIsoLockNoAffect>;
+ return static_cast<x11::Xkb::SAIsoLockNoAffect>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SAIsoLockNoAffect operator&(
+ x11::Xkb::SAIsoLockNoAffect l,
+ x11::Xkb::SAIsoLockNoAffect r) {
+ using T = std::underlying_type_t<x11::Xkb::SAIsoLockNoAffect>;
+ return static_cast<x11::Xkb::SAIsoLockNoAffect>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SwitchScreenFlag operator|(
+ x11::Xkb::SwitchScreenFlag l,
+ x11::Xkb::SwitchScreenFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::SwitchScreenFlag>;
+ return static_cast<x11::Xkb::SwitchScreenFlag>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SwitchScreenFlag operator&(
+ x11::Xkb::SwitchScreenFlag l,
+ x11::Xkb::SwitchScreenFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::SwitchScreenFlag>;
+ return static_cast<x11::Xkb::SwitchScreenFlag>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BoolCtrlsHigh operator|(x11::Xkb::BoolCtrlsHigh l,
+ x11::Xkb::BoolCtrlsHigh r) {
+ using T = std::underlying_type_t<x11::Xkb::BoolCtrlsHigh>;
+ return static_cast<x11::Xkb::BoolCtrlsHigh>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BoolCtrlsHigh operator&(x11::Xkb::BoolCtrlsHigh l,
+ x11::Xkb::BoolCtrlsHigh r) {
+ using T = std::underlying_type_t<x11::Xkb::BoolCtrlsHigh>;
+ return static_cast<x11::Xkb::BoolCtrlsHigh>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BoolCtrlsLow operator|(x11::Xkb::BoolCtrlsLow l,
+ x11::Xkb::BoolCtrlsLow r) {
+ using T = std::underlying_type_t<x11::Xkb::BoolCtrlsLow>;
+ return static_cast<x11::Xkb::BoolCtrlsLow>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::BoolCtrlsLow operator&(x11::Xkb::BoolCtrlsLow l,
+ x11::Xkb::BoolCtrlsLow r) {
+ using T = std::underlying_type_t<x11::Xkb::BoolCtrlsLow>;
+ return static_cast<x11::Xkb::BoolCtrlsLow>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::ActionMessageFlag operator|(
+ x11::Xkb::ActionMessageFlag l,
+ x11::Xkb::ActionMessageFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::ActionMessageFlag>;
+ return static_cast<x11::Xkb::ActionMessageFlag>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::ActionMessageFlag operator&(
+ x11::Xkb::ActionMessageFlag l,
+ x11::Xkb::ActionMessageFlag r) {
+ using T = std::underlying_type_t<x11::Xkb::ActionMessageFlag>;
+ return static_cast<x11::Xkb::ActionMessageFlag>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::LockDeviceFlags operator|(
+ x11::Xkb::LockDeviceFlags l,
+ x11::Xkb::LockDeviceFlags r) {
+ using T = std::underlying_type_t<x11::Xkb::LockDeviceFlags>;
+ return static_cast<x11::Xkb::LockDeviceFlags>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::LockDeviceFlags operator&(
+ x11::Xkb::LockDeviceFlags l,
+ x11::Xkb::LockDeviceFlags r) {
+ using T = std::underlying_type_t<x11::Xkb::LockDeviceFlags>;
+ return static_cast<x11::Xkb::LockDeviceFlags>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SAValWhat operator|(x11::Xkb::SAValWhat l,
+ x11::Xkb::SAValWhat r) {
+ using T = std::underlying_type_t<x11::Xkb::SAValWhat>;
+ return static_cast<x11::Xkb::SAValWhat>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xkb::SAValWhat operator&(x11::Xkb::SAValWhat l,
+ x11::Xkb::SAValWhat r) {
+ using T = std::underlying_type_t<x11::Xkb::SAValWhat>;
+ return static_cast<x11::Xkb::SAValWhat>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XKB_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xprint.cc b/chromium/ui/gfx/x/generated_protos/xprint.cc
new file mode 100644
index 00000000000..e6d6d848c0e
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xprint.cc
@@ -0,0 +1,1708 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xprint.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+XPrint::XPrint(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<XPrint::NotifyEvent>(XPrint::NotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& detail = (*event_).detail;
+ auto& sequence = (*event_).sequence;
+ auto& context = (*event_).context;
+ auto& cancel = (*event_).cancel;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // detail
+ Read(&detail, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // context
+ Read(&context, &buf);
+
+ // cancel
+ Read(&cancel, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<XPrint::AttributNotifyEvent>(XPrint::AttributNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& detail = (*event_).detail;
+ auto& sequence = (*event_).sequence;
+ auto& context = (*event_).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // detail
+ Read(&detail, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // context
+ Read(&context, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+std::string XPrint::BadContextError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "XPrint::BadContextError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<XPrint::BadContextError>(XPrint::BadContextError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string XPrint::BadSequenceError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "XPrint::BadSequenceError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<XPrint::BadSequenceError>(XPrint::BadSequenceError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+Future<XPrint::PrintQueryVersionReply> XPrint::PrintQueryVersion(
+ const XPrint::PrintQueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintQueryVersionReply>(
+ &buf, "XPrint::PrintQueryVersion", false);
+}
+
+Future<XPrint::PrintQueryVersionReply> XPrint::PrintQueryVersion() {
+ return XPrint::PrintQueryVersion(XPrint::PrintQueryVersionRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintQueryVersionReply> detail::ReadReply<
+ XPrint::PrintQueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintQueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major_version = (*reply).major_version;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XPrint::PrintGetPrinterListReply> XPrint::PrintGetPrinterList(
+ const XPrint::PrintGetPrinterListRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint32_t printerNameLen{};
+ uint32_t localeLen{};
+ auto& printer_name = request.printer_name;
+ size_t printer_name_len = printer_name.size();
+ auto& locale = request.locale;
+ size_t locale_len = locale.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // printerNameLen
+ printerNameLen = printer_name.size();
+ buf.Write(&printerNameLen);
+
+ // localeLen
+ localeLen = locale.size();
+ buf.Write(&localeLen);
+
+ // printer_name
+ DCHECK_EQ(static_cast<size_t>(printerNameLen), printer_name.size());
+ for (auto& printer_name_elem : printer_name) {
+ // printer_name_elem
+ buf.Write(&printer_name_elem);
+ }
+
+ // locale
+ DCHECK_EQ(static_cast<size_t>(localeLen), locale.size());
+ for (auto& locale_elem : locale) {
+ // locale_elem
+ buf.Write(&locale_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintGetPrinterListReply>(
+ &buf, "XPrint::PrintGetPrinterList", false);
+}
+
+Future<XPrint::PrintGetPrinterListReply> XPrint::PrintGetPrinterList(
+ const std::vector<String8>& printer_name,
+ const std::vector<String8>& locale) {
+ return XPrint::PrintGetPrinterList(
+ XPrint::PrintGetPrinterListRequest{printer_name, locale});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintGetPrinterListReply> detail::ReadReply<
+ XPrint::PrintGetPrinterListReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintGetPrinterListReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t listCount{};
+ auto& printers = (*reply).printers;
+ size_t printers_len = printers.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // listCount
+ Read(&listCount, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // printers
+ printers.resize(listCount);
+ for (auto& printers_elem : printers) {
+ // printers_elem
+ {
+ uint32_t nameLen{};
+ auto& name = printers_elem.name;
+ size_t name_len = name.size();
+ uint32_t descLen{};
+ auto& description = printers_elem.description;
+ size_t description_len = description.size();
+
+ // nameLen
+ Read(&nameLen, &buf);
+
+ // name
+ name.resize(nameLen);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ // pad0
+ Align(&buf, 4);
+
+ // descLen
+ Read(&descLen, &buf);
+
+ // description
+ description.resize(descLen);
+ for (auto& description_elem : description) {
+ // description_elem
+ Read(&description_elem, &buf);
+ }
+
+ // pad1
+ Align(&buf, 4);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XPrint::PrintRehashPrinterList(
+ const XPrint::PrintRehashPrinterListRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 20;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintRehashPrinterList",
+ false);
+}
+
+Future<void> XPrint::PrintRehashPrinterList() {
+ return XPrint::PrintRehashPrinterList(
+ XPrint::PrintRehashPrinterListRequest{});
+}
+
+Future<void> XPrint::CreateContext(
+ const XPrint::CreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_id = request.context_id;
+ uint32_t printerNameLen{};
+ uint32_t localeLen{};
+ auto& printerName = request.printerName;
+ size_t printerName_len = printerName.size();
+ auto& locale = request.locale;
+ size_t locale_len = locale.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_id
+ buf.Write(&context_id);
+
+ // printerNameLen
+ printerNameLen = printerName.size();
+ buf.Write(&printerNameLen);
+
+ // localeLen
+ localeLen = locale.size();
+ buf.Write(&localeLen);
+
+ // printerName
+ DCHECK_EQ(static_cast<size_t>(printerNameLen), printerName.size());
+ for (auto& printerName_elem : printerName) {
+ // printerName_elem
+ buf.Write(&printerName_elem);
+ }
+
+ // locale
+ DCHECK_EQ(static_cast<size_t>(localeLen), locale.size());
+ for (auto& locale_elem : locale) {
+ // locale_elem
+ buf.Write(&locale_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::CreateContext", false);
+}
+
+Future<void> XPrint::CreateContext(const uint32_t& context_id,
+ const std::vector<String8>& printerName,
+ const std::vector<String8>& locale) {
+ return XPrint::CreateContext(
+ XPrint::CreateContextRequest{context_id, printerName, locale});
+}
+
+Future<void> XPrint::PrintSetContext(
+ const XPrint::PrintSetContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintSetContext", false);
+}
+
+Future<void> XPrint::PrintSetContext(const uint32_t& context) {
+ return XPrint::PrintSetContext(XPrint::PrintSetContextRequest{context});
+}
+
+Future<XPrint::PrintGetContextReply> XPrint::PrintGetContext(
+ const XPrint::PrintGetContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintGetContextReply>(
+ &buf, "XPrint::PrintGetContext", false);
+}
+
+Future<XPrint::PrintGetContextReply> XPrint::PrintGetContext() {
+ return XPrint::PrintGetContext(XPrint::PrintGetContextRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintGetContextReply> detail::ReadReply<
+ XPrint::PrintGetContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintGetContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context
+ Read(&context, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XPrint::PrintDestroyContext(
+ const XPrint::PrintDestroyContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintDestroyContext",
+ false);
+}
+
+Future<void> XPrint::PrintDestroyContext(const uint32_t& context) {
+ return XPrint::PrintDestroyContext(
+ XPrint::PrintDestroyContextRequest{context});
+}
+
+Future<XPrint::PrintGetScreenOfContextReply> XPrint::PrintGetScreenOfContext(
+ const XPrint::PrintGetScreenOfContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintGetScreenOfContextReply>(
+ &buf, "XPrint::PrintGetScreenOfContext", false);
+}
+
+Future<XPrint::PrintGetScreenOfContextReply> XPrint::PrintGetScreenOfContext() {
+ return XPrint::PrintGetScreenOfContext(
+ XPrint::PrintGetScreenOfContextRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintGetScreenOfContextReply> detail::ReadReply<
+ XPrint::PrintGetScreenOfContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintGetScreenOfContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& root = (*reply).root;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XPrint::PrintStartJob(
+ const XPrint::PrintStartJobRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& output_mode = request.output_mode;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // output_mode
+ buf.Write(&output_mode);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintStartJob", false);
+}
+
+Future<void> XPrint::PrintStartJob(const uint8_t& output_mode) {
+ return XPrint::PrintStartJob(XPrint::PrintStartJobRequest{output_mode});
+}
+
+Future<void> XPrint::PrintEndJob(const XPrint::PrintEndJobRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cancel = request.cancel;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cancel
+ buf.Write(&cancel);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintEndJob", false);
+}
+
+Future<void> XPrint::PrintEndJob(const uint8_t& cancel) {
+ return XPrint::PrintEndJob(XPrint::PrintEndJobRequest{cancel});
+}
+
+Future<void> XPrint::PrintStartDoc(
+ const XPrint::PrintStartDocRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& driver_mode = request.driver_mode;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // driver_mode
+ buf.Write(&driver_mode);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintStartDoc", false);
+}
+
+Future<void> XPrint::PrintStartDoc(const uint8_t& driver_mode) {
+ return XPrint::PrintStartDoc(XPrint::PrintStartDocRequest{driver_mode});
+}
+
+Future<void> XPrint::PrintEndDoc(const XPrint::PrintEndDocRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cancel = request.cancel;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cancel
+ buf.Write(&cancel);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintEndDoc", false);
+}
+
+Future<void> XPrint::PrintEndDoc(const uint8_t& cancel) {
+ return XPrint::PrintEndDoc(XPrint::PrintEndDocRequest{cancel});
+}
+
+Future<void> XPrint::PrintPutDocumentData(
+ const XPrint::PrintPutDocumentDataRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ uint32_t len_data{};
+ uint16_t len_fmt{};
+ uint16_t len_options{};
+ auto& data = request.data;
+ size_t data_len = data.size();
+ auto& doc_format = request.doc_format;
+ size_t doc_format_len = doc_format.size();
+ auto& options = request.options;
+ size_t options_len = options.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // len_data
+ len_data = data.size();
+ buf.Write(&len_data);
+
+ // len_fmt
+ len_fmt = doc_format.size();
+ buf.Write(&len_fmt);
+
+ // len_options
+ len_options = options.size();
+ buf.Write(&len_options);
+
+ // data
+ DCHECK_EQ(static_cast<size_t>(len_data), data.size());
+ for (auto& data_elem : data) {
+ // data_elem
+ buf.Write(&data_elem);
+ }
+
+ // doc_format
+ DCHECK_EQ(static_cast<size_t>(len_fmt), doc_format.size());
+ for (auto& doc_format_elem : doc_format) {
+ // doc_format_elem
+ buf.Write(&doc_format_elem);
+ }
+
+ // options
+ DCHECK_EQ(static_cast<size_t>(len_options), options.size());
+ for (auto& options_elem : options) {
+ // options_elem
+ buf.Write(&options_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintPutDocumentData",
+ false);
+}
+
+Future<void> XPrint::PrintPutDocumentData(
+ const Drawable& drawable,
+ const std::vector<uint8_t>& data,
+ const std::vector<String8>& doc_format,
+ const std::vector<String8>& options) {
+ return XPrint::PrintPutDocumentData(
+ XPrint::PrintPutDocumentDataRequest{drawable, data, doc_format, options});
+}
+
+Future<XPrint::PrintGetDocumentDataReply> XPrint::PrintGetDocumentData(
+ const XPrint::PrintGetDocumentDataRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ auto& max_bytes = request.max_bytes;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // max_bytes
+ buf.Write(&max_bytes);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintGetDocumentDataReply>(
+ &buf, "XPrint::PrintGetDocumentData", false);
+}
+
+Future<XPrint::PrintGetDocumentDataReply> XPrint::PrintGetDocumentData(
+ const PContext& context,
+ const uint32_t& max_bytes) {
+ return XPrint::PrintGetDocumentData(
+ XPrint::PrintGetDocumentDataRequest{context, max_bytes});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintGetDocumentDataReply> detail::ReadReply<
+ XPrint::PrintGetDocumentDataReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintGetDocumentDataReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& status_code = (*reply).status_code;
+ auto& finished_flag = (*reply).finished_flag;
+ uint32_t dataLen{};
+ auto& data = (*reply).data;
+ size_t data_len = data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // status_code
+ Read(&status_code, &buf);
+
+ // finished_flag
+ Read(&finished_flag, &buf);
+
+ // dataLen
+ Read(&dataLen, &buf);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // data
+ data.resize(dataLen);
+ for (auto& data_elem : data) {
+ // data_elem
+ Read(&data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XPrint::PrintStartPage(
+ const XPrint::PrintStartPageRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintStartPage", false);
+}
+
+Future<void> XPrint::PrintStartPage(const Window& window) {
+ return XPrint::PrintStartPage(XPrint::PrintStartPageRequest{window});
+}
+
+Future<void> XPrint::PrintEndPage(const XPrint::PrintEndPageRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cancel = request.cancel;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 14;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cancel
+ buf.Write(&cancel);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintEndPage", false);
+}
+
+Future<void> XPrint::PrintEndPage(const uint8_t& cancel) {
+ return XPrint::PrintEndPage(XPrint::PrintEndPageRequest{cancel});
+}
+
+Future<void> XPrint::PrintSelectInput(
+ const XPrint::PrintSelectInputRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ auto& event_mask = request.event_mask;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 15;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // event_mask
+ buf.Write(&event_mask);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintSelectInput",
+ false);
+}
+
+Future<void> XPrint::PrintSelectInput(const PContext& context,
+ const uint32_t& event_mask) {
+ return XPrint::PrintSelectInput(
+ XPrint::PrintSelectInputRequest{context, event_mask});
+}
+
+Future<XPrint::PrintInputSelectedReply> XPrint::PrintInputSelected(
+ const XPrint::PrintInputSelectedRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 16;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintInputSelectedReply>(
+ &buf, "XPrint::PrintInputSelected", false);
+}
+
+Future<XPrint::PrintInputSelectedReply> XPrint::PrintInputSelected(
+ const PContext& context) {
+ return XPrint::PrintInputSelected(XPrint::PrintInputSelectedRequest{context});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintInputSelectedReply> detail::ReadReply<
+ XPrint::PrintInputSelectedReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintInputSelectedReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& event_mask = (*reply).event_mask;
+ auto& all_events_mask = (*reply).all_events_mask;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_mask
+ Read(&event_mask, &buf);
+
+ // all_events_mask
+ Read(&all_events_mask, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XPrint::PrintGetAttributesReply> XPrint::PrintGetAttributes(
+ const XPrint::PrintGetAttributesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ auto& pool = request.pool;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 17;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // pool
+ buf.Write(&pool);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintGetAttributesReply>(
+ &buf, "XPrint::PrintGetAttributes", false);
+}
+
+Future<XPrint::PrintGetAttributesReply> XPrint::PrintGetAttributes(
+ const PContext& context,
+ const uint8_t& pool) {
+ return XPrint::PrintGetAttributes(
+ XPrint::PrintGetAttributesRequest{context, pool});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintGetAttributesReply> detail::ReadReply<
+ XPrint::PrintGetAttributesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintGetAttributesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t stringLen{};
+ auto& attributes = (*reply).attributes;
+ size_t attributes_len = attributes.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // stringLen
+ Read(&stringLen, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // attributes
+ attributes.resize(stringLen);
+ for (auto& attributes_elem : attributes) {
+ // attributes_elem
+ Read(&attributes_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XPrint::PrintGetOneAttributesReply> XPrint::PrintGetOneAttributes(
+ const XPrint::PrintGetOneAttributesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ uint32_t nameLen{};
+ auto& pool = request.pool;
+ auto& name = request.name;
+ size_t name_len = name.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 19;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // nameLen
+ nameLen = name.size();
+ buf.Write(&nameLen);
+
+ // pool
+ buf.Write(&pool);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(nameLen), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintGetOneAttributesReply>(
+ &buf, "XPrint::PrintGetOneAttributes", false);
+}
+
+Future<XPrint::PrintGetOneAttributesReply> XPrint::PrintGetOneAttributes(
+ const PContext& context,
+ const uint8_t& pool,
+ const std::vector<String8>& name) {
+ return XPrint::PrintGetOneAttributes(
+ XPrint::PrintGetOneAttributesRequest{context, pool, name});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintGetOneAttributesReply> detail::ReadReply<
+ XPrint::PrintGetOneAttributesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintGetOneAttributesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t valueLen{};
+ auto& value = (*reply).value;
+ size_t value_len = value.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // valueLen
+ Read(&valueLen, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // value
+ value.resize(valueLen);
+ for (auto& value_elem : value) {
+ // value_elem
+ Read(&value_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XPrint::PrintSetAttributes(
+ const XPrint::PrintSetAttributesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ auto& stringLen = request.stringLen;
+ auto& pool = request.pool;
+ auto& rule = request.rule;
+ auto& attributes = request.attributes;
+ size_t attributes_len = attributes.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 18;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // stringLen
+ buf.Write(&stringLen);
+
+ // pool
+ buf.Write(&pool);
+
+ // rule
+ buf.Write(&rule);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // attributes
+ DCHECK_EQ(static_cast<size_t>(attributes_len), attributes.size());
+ for (auto& attributes_elem : attributes) {
+ // attributes_elem
+ buf.Write(&attributes_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XPrint::PrintSetAttributes",
+ false);
+}
+
+Future<void> XPrint::PrintSetAttributes(
+ const PContext& context,
+ const uint32_t& stringLen,
+ const uint8_t& pool,
+ const uint8_t& rule,
+ const std::vector<String8>& attributes) {
+ return XPrint::PrintSetAttributes(XPrint::PrintSetAttributesRequest{
+ context, stringLen, pool, rule, attributes});
+}
+
+Future<XPrint::PrintGetPageDimensionsReply> XPrint::PrintGetPageDimensions(
+ const XPrint::PrintGetPageDimensionsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 21;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintGetPageDimensionsReply>(
+ &buf, "XPrint::PrintGetPageDimensions", false);
+}
+
+Future<XPrint::PrintGetPageDimensionsReply> XPrint::PrintGetPageDimensions(
+ const PContext& context) {
+ return XPrint::PrintGetPageDimensions(
+ XPrint::PrintGetPageDimensionsRequest{context});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintGetPageDimensionsReply> detail::ReadReply<
+ XPrint::PrintGetPageDimensionsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintGetPageDimensionsReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& offset_x = (*reply).offset_x;
+ auto& offset_y = (*reply).offset_y;
+ auto& reproducible_width = (*reply).reproducible_width;
+ auto& reproducible_height = (*reply).reproducible_height;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // offset_x
+ Read(&offset_x, &buf);
+
+ // offset_y
+ Read(&offset_y, &buf);
+
+ // reproducible_width
+ Read(&reproducible_width, &buf);
+
+ // reproducible_height
+ Read(&reproducible_height, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XPrint::PrintQueryScreensReply> XPrint::PrintQueryScreens(
+ const XPrint::PrintQueryScreensRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 22;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintQueryScreensReply>(
+ &buf, "XPrint::PrintQueryScreens", false);
+}
+
+Future<XPrint::PrintQueryScreensReply> XPrint::PrintQueryScreens() {
+ return XPrint::PrintQueryScreens(XPrint::PrintQueryScreensRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintQueryScreensReply> detail::ReadReply<
+ XPrint::PrintQueryScreensReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintQueryScreensReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t listCount{};
+ auto& roots = (*reply).roots;
+ size_t roots_len = roots.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // listCount
+ Read(&listCount, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // roots
+ roots.resize(listCount);
+ for (auto& roots_elem : roots) {
+ // roots_elem
+ Read(&roots_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XPrint::PrintSetImageResolutionReply> XPrint::PrintSetImageResolution(
+ const XPrint::PrintSetImageResolutionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+ auto& image_resolution = request.image_resolution;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 23;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ // image_resolution
+ buf.Write(&image_resolution);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintSetImageResolutionReply>(
+ &buf, "XPrint::PrintSetImageResolution", false);
+}
+
+Future<XPrint::PrintSetImageResolutionReply> XPrint::PrintSetImageResolution(
+ const PContext& context,
+ const uint16_t& image_resolution) {
+ return XPrint::PrintSetImageResolution(
+ XPrint::PrintSetImageResolutionRequest{context, image_resolution});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintSetImageResolutionReply> detail::ReadReply<
+ XPrint::PrintSetImageResolutionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintSetImageResolutionReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+ auto& previous_resolutions = (*reply).previous_resolutions;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ Read(&status, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // previous_resolutions
+ Read(&previous_resolutions, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XPrint::PrintGetImageResolutionReply> XPrint::PrintGetImageResolution(
+ const XPrint::PrintGetImageResolutionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 24;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context
+ buf.Write(&context);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XPrint::PrintGetImageResolutionReply>(
+ &buf, "XPrint::PrintGetImageResolution", false);
+}
+
+Future<XPrint::PrintGetImageResolutionReply> XPrint::PrintGetImageResolution(
+ const PContext& context) {
+ return XPrint::PrintGetImageResolution(
+ XPrint::PrintGetImageResolutionRequest{context});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XPrint::PrintGetImageResolutionReply> detail::ReadReply<
+ XPrint::PrintGetImageResolutionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XPrint::PrintGetImageResolutionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& image_resolution = (*reply).image_resolution;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // image_resolution
+ Read(&image_resolution, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xprint.h b/chromium/ui/gfx/x/generated_protos/xprint.h
new file mode 100644
index 00000000000..0a73811aeb2
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xprint.h
@@ -0,0 +1,584 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XPRINT_H_
+#define UI_GFX_X_GENERATED_PROTOS_XPRINT_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) XPrint {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 0;
+
+ XPrint(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class String8 : char {};
+
+ enum class PContext : uint32_t {};
+
+ enum class GetDoc : int {
+ Finished = 0,
+ SecondConsumer = 1,
+ };
+
+ enum class EvMask : int {
+ NoEventMask = 0,
+ PrintMask = 1 << 0,
+ AttributeMask = 1 << 1,
+ };
+
+ enum class Detail : int {
+ StartJobNotify = 1,
+ EndJobNotify = 2,
+ StartDocNotify = 3,
+ EndDocNotify = 4,
+ StartPageNotify = 5,
+ EndPageNotify = 6,
+ };
+
+ enum class Attr : int {
+ JobAttr = 1,
+ DocAttr = 2,
+ PageAttr = 3,
+ PrinterAttr = 4,
+ ServerAttr = 5,
+ MediumAttr = 6,
+ SpoolerAttr = 7,
+ };
+
+ struct Printer {
+ std::vector<String8> name{};
+ std::vector<String8> description{};
+ };
+
+ struct NotifyEvent {
+ static constexpr int type_id = 50;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ uint8_t detail{};
+ uint16_t sequence{};
+ PContext context{};
+ uint8_t cancel{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct AttributNotifyEvent {
+ static constexpr int type_id = 51;
+ static constexpr uint8_t opcode = 1;
+ bool send_event{};
+ uint8_t detail{};
+ uint16_t sequence{};
+ PContext context{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct BadContextError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadSequenceError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct PrintQueryVersionRequest {};
+
+ struct PrintQueryVersionReply {
+ uint16_t sequence{};
+ uint16_t major_version{};
+ uint16_t minor_version{};
+ };
+
+ using PrintQueryVersionResponse = Response<PrintQueryVersionReply>;
+
+ Future<PrintQueryVersionReply> PrintQueryVersion(
+ const PrintQueryVersionRequest& request);
+
+ Future<PrintQueryVersionReply> PrintQueryVersion();
+
+ struct PrintGetPrinterListRequest {
+ std::vector<String8> printer_name{};
+ std::vector<String8> locale{};
+ };
+
+ struct PrintGetPrinterListReply {
+ uint16_t sequence{};
+ std::vector<Printer> printers{};
+ };
+
+ using PrintGetPrinterListResponse = Response<PrintGetPrinterListReply>;
+
+ Future<PrintGetPrinterListReply> PrintGetPrinterList(
+ const PrintGetPrinterListRequest& request);
+
+ Future<PrintGetPrinterListReply> PrintGetPrinterList(
+ const std::vector<String8>& printer_name = {},
+ const std::vector<String8>& locale = {});
+
+ struct PrintRehashPrinterListRequest {};
+
+ using PrintRehashPrinterListResponse = Response<void>;
+
+ Future<void> PrintRehashPrinterList(
+ const PrintRehashPrinterListRequest& request);
+
+ Future<void> PrintRehashPrinterList();
+
+ struct CreateContextRequest {
+ uint32_t context_id{};
+ std::vector<String8> printerName{};
+ std::vector<String8> locale{};
+ };
+
+ using CreateContextResponse = Response<void>;
+
+ Future<void> CreateContext(const CreateContextRequest& request);
+
+ Future<void> CreateContext(const uint32_t& context_id = {},
+ const std::vector<String8>& printerName = {},
+ const std::vector<String8>& locale = {});
+
+ struct PrintSetContextRequest {
+ uint32_t context{};
+ };
+
+ using PrintSetContextResponse = Response<void>;
+
+ Future<void> PrintSetContext(const PrintSetContextRequest& request);
+
+ Future<void> PrintSetContext(const uint32_t& context = {});
+
+ struct PrintGetContextRequest {};
+
+ struct PrintGetContextReply {
+ uint16_t sequence{};
+ uint32_t context{};
+ };
+
+ using PrintGetContextResponse = Response<PrintGetContextReply>;
+
+ Future<PrintGetContextReply> PrintGetContext(
+ const PrintGetContextRequest& request);
+
+ Future<PrintGetContextReply> PrintGetContext();
+
+ struct PrintDestroyContextRequest {
+ uint32_t context{};
+ };
+
+ using PrintDestroyContextResponse = Response<void>;
+
+ Future<void> PrintDestroyContext(const PrintDestroyContextRequest& request);
+
+ Future<void> PrintDestroyContext(const uint32_t& context = {});
+
+ struct PrintGetScreenOfContextRequest {};
+
+ struct PrintGetScreenOfContextReply {
+ uint16_t sequence{};
+ Window root{};
+ };
+
+ using PrintGetScreenOfContextResponse =
+ Response<PrintGetScreenOfContextReply>;
+
+ Future<PrintGetScreenOfContextReply> PrintGetScreenOfContext(
+ const PrintGetScreenOfContextRequest& request);
+
+ Future<PrintGetScreenOfContextReply> PrintGetScreenOfContext();
+
+ struct PrintStartJobRequest {
+ uint8_t output_mode{};
+ };
+
+ using PrintStartJobResponse = Response<void>;
+
+ Future<void> PrintStartJob(const PrintStartJobRequest& request);
+
+ Future<void> PrintStartJob(const uint8_t& output_mode = {});
+
+ struct PrintEndJobRequest {
+ uint8_t cancel{};
+ };
+
+ using PrintEndJobResponse = Response<void>;
+
+ Future<void> PrintEndJob(const PrintEndJobRequest& request);
+
+ Future<void> PrintEndJob(const uint8_t& cancel = {});
+
+ struct PrintStartDocRequest {
+ uint8_t driver_mode{};
+ };
+
+ using PrintStartDocResponse = Response<void>;
+
+ Future<void> PrintStartDoc(const PrintStartDocRequest& request);
+
+ Future<void> PrintStartDoc(const uint8_t& driver_mode = {});
+
+ struct PrintEndDocRequest {
+ uint8_t cancel{};
+ };
+
+ using PrintEndDocResponse = Response<void>;
+
+ Future<void> PrintEndDoc(const PrintEndDocRequest& request);
+
+ Future<void> PrintEndDoc(const uint8_t& cancel = {});
+
+ struct PrintPutDocumentDataRequest {
+ Drawable drawable{};
+ std::vector<uint8_t> data{};
+ std::vector<String8> doc_format{};
+ std::vector<String8> options{};
+ };
+
+ using PrintPutDocumentDataResponse = Response<void>;
+
+ Future<void> PrintPutDocumentData(const PrintPutDocumentDataRequest& request);
+
+ Future<void> PrintPutDocumentData(const Drawable& drawable = {},
+ const std::vector<uint8_t>& data = {},
+ const std::vector<String8>& doc_format = {},
+ const std::vector<String8>& options = {});
+
+ struct PrintGetDocumentDataRequest {
+ PContext context{};
+ uint32_t max_bytes{};
+ };
+
+ struct PrintGetDocumentDataReply {
+ uint16_t sequence{};
+ uint32_t status_code{};
+ uint32_t finished_flag{};
+ std::vector<uint8_t> data{};
+ };
+
+ using PrintGetDocumentDataResponse = Response<PrintGetDocumentDataReply>;
+
+ Future<PrintGetDocumentDataReply> PrintGetDocumentData(
+ const PrintGetDocumentDataRequest& request);
+
+ Future<PrintGetDocumentDataReply> PrintGetDocumentData(
+ const PContext& context = {},
+ const uint32_t& max_bytes = {});
+
+ struct PrintStartPageRequest {
+ Window window{};
+ };
+
+ using PrintStartPageResponse = Response<void>;
+
+ Future<void> PrintStartPage(const PrintStartPageRequest& request);
+
+ Future<void> PrintStartPage(const Window& window = {});
+
+ struct PrintEndPageRequest {
+ uint8_t cancel{};
+ };
+
+ using PrintEndPageResponse = Response<void>;
+
+ Future<void> PrintEndPage(const PrintEndPageRequest& request);
+
+ Future<void> PrintEndPage(const uint8_t& cancel = {});
+
+ struct PrintSelectInputRequest {
+ PContext context{};
+ uint32_t event_mask{};
+ };
+
+ using PrintSelectInputResponse = Response<void>;
+
+ Future<void> PrintSelectInput(const PrintSelectInputRequest& request);
+
+ Future<void> PrintSelectInput(const PContext& context = {},
+ const uint32_t& event_mask = {});
+
+ struct PrintInputSelectedRequest {
+ PContext context{};
+ };
+
+ struct PrintInputSelectedReply {
+ uint16_t sequence{};
+ uint32_t event_mask{};
+ uint32_t all_events_mask{};
+ };
+
+ using PrintInputSelectedResponse = Response<PrintInputSelectedReply>;
+
+ Future<PrintInputSelectedReply> PrintInputSelected(
+ const PrintInputSelectedRequest& request);
+
+ Future<PrintInputSelectedReply> PrintInputSelected(
+ const PContext& context = {});
+
+ struct PrintGetAttributesRequest {
+ PContext context{};
+ uint8_t pool{};
+ };
+
+ struct PrintGetAttributesReply {
+ uint16_t sequence{};
+ std::vector<String8> attributes{};
+ };
+
+ using PrintGetAttributesResponse = Response<PrintGetAttributesReply>;
+
+ Future<PrintGetAttributesReply> PrintGetAttributes(
+ const PrintGetAttributesRequest& request);
+
+ Future<PrintGetAttributesReply> PrintGetAttributes(
+ const PContext& context = {},
+ const uint8_t& pool = {});
+
+ struct PrintGetOneAttributesRequest {
+ PContext context{};
+ uint8_t pool{};
+ std::vector<String8> name{};
+ };
+
+ struct PrintGetOneAttributesReply {
+ uint16_t sequence{};
+ std::vector<String8> value{};
+ };
+
+ using PrintGetOneAttributesResponse = Response<PrintGetOneAttributesReply>;
+
+ Future<PrintGetOneAttributesReply> PrintGetOneAttributes(
+ const PrintGetOneAttributesRequest& request);
+
+ Future<PrintGetOneAttributesReply> PrintGetOneAttributes(
+ const PContext& context = {},
+ const uint8_t& pool = {},
+ const std::vector<String8>& name = {});
+
+ struct PrintSetAttributesRequest {
+ PContext context{};
+ uint32_t stringLen{};
+ uint8_t pool{};
+ uint8_t rule{};
+ std::vector<String8> attributes{};
+ };
+
+ using PrintSetAttributesResponse = Response<void>;
+
+ Future<void> PrintSetAttributes(const PrintSetAttributesRequest& request);
+
+ Future<void> PrintSetAttributes(const PContext& context = {},
+ const uint32_t& stringLen = {},
+ const uint8_t& pool = {},
+ const uint8_t& rule = {},
+ const std::vector<String8>& attributes = {});
+
+ struct PrintGetPageDimensionsRequest {
+ PContext context{};
+ };
+
+ struct PrintGetPageDimensionsReply {
+ uint16_t sequence{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t offset_x{};
+ uint16_t offset_y{};
+ uint16_t reproducible_width{};
+ uint16_t reproducible_height{};
+ };
+
+ using PrintGetPageDimensionsResponse = Response<PrintGetPageDimensionsReply>;
+
+ Future<PrintGetPageDimensionsReply> PrintGetPageDimensions(
+ const PrintGetPageDimensionsRequest& request);
+
+ Future<PrintGetPageDimensionsReply> PrintGetPageDimensions(
+ const PContext& context = {});
+
+ struct PrintQueryScreensRequest {};
+
+ struct PrintQueryScreensReply {
+ uint16_t sequence{};
+ std::vector<Window> roots{};
+ };
+
+ using PrintQueryScreensResponse = Response<PrintQueryScreensReply>;
+
+ Future<PrintQueryScreensReply> PrintQueryScreens(
+ const PrintQueryScreensRequest& request);
+
+ Future<PrintQueryScreensReply> PrintQueryScreens();
+
+ struct PrintSetImageResolutionRequest {
+ PContext context{};
+ uint16_t image_resolution{};
+ };
+
+ struct PrintSetImageResolutionReply {
+ uint8_t status{};
+ uint16_t sequence{};
+ uint16_t previous_resolutions{};
+ };
+
+ using PrintSetImageResolutionResponse =
+ Response<PrintSetImageResolutionReply>;
+
+ Future<PrintSetImageResolutionReply> PrintSetImageResolution(
+ const PrintSetImageResolutionRequest& request);
+
+ Future<PrintSetImageResolutionReply> PrintSetImageResolution(
+ const PContext& context = {},
+ const uint16_t& image_resolution = {});
+
+ struct PrintGetImageResolutionRequest {
+ PContext context{};
+ };
+
+ struct PrintGetImageResolutionReply {
+ uint16_t sequence{};
+ uint16_t image_resolution{};
+ };
+
+ using PrintGetImageResolutionResponse =
+ Response<PrintGetImageResolutionReply>;
+
+ Future<PrintGetImageResolutionReply> PrintGetImageResolution(
+ const PrintGetImageResolutionRequest& request);
+
+ Future<PrintGetImageResolutionReply> PrintGetImageResolution(
+ const PContext& context = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::XPrint::GetDoc operator|(x11::XPrint::GetDoc l,
+ x11::XPrint::GetDoc r) {
+ using T = std::underlying_type_t<x11::XPrint::GetDoc>;
+ return static_cast<x11::XPrint::GetDoc>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XPrint::GetDoc operator&(x11::XPrint::GetDoc l,
+ x11::XPrint::GetDoc r) {
+ using T = std::underlying_type_t<x11::XPrint::GetDoc>;
+ return static_cast<x11::XPrint::GetDoc>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XPrint::EvMask operator|(x11::XPrint::EvMask l,
+ x11::XPrint::EvMask r) {
+ using T = std::underlying_type_t<x11::XPrint::EvMask>;
+ return static_cast<x11::XPrint::EvMask>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XPrint::EvMask operator&(x11::XPrint::EvMask l,
+ x11::XPrint::EvMask r) {
+ using T = std::underlying_type_t<x11::XPrint::EvMask>;
+ return static_cast<x11::XPrint::EvMask>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XPrint::Detail operator|(x11::XPrint::Detail l,
+ x11::XPrint::Detail r) {
+ using T = std::underlying_type_t<x11::XPrint::Detail>;
+ return static_cast<x11::XPrint::Detail>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XPrint::Detail operator&(x11::XPrint::Detail l,
+ x11::XPrint::Detail r) {
+ using T = std::underlying_type_t<x11::XPrint::Detail>;
+ return static_cast<x11::XPrint::Detail>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XPrint::Attr operator|(x11::XPrint::Attr l,
+ x11::XPrint::Attr r) {
+ using T = std::underlying_type_t<x11::XPrint::Attr>;
+ return static_cast<x11::XPrint::Attr>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::XPrint::Attr operator&(x11::XPrint::Attr l,
+ x11::XPrint::Attr r) {
+ using T = std::underlying_type_t<x11::XPrint::Attr>;
+ return static_cast<x11::XPrint::Attr>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XPRINT_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xproto.cc b/chromium/ui/gfx/x/generated_protos/xproto.cc
new file mode 100644
index 00000000000..161d8d55500
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xproto.cc
@@ -0,0 +1,11439 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xproto.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+XProto::XProto(Connection* connection) : connection_(connection) {}
+
+template <>
+COMPONENT_EXPORT(X11)
+Setup Read<Setup>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ Setup obj;
+
+ auto& status = obj.status;
+ auto& protocol_major_version = obj.protocol_major_version;
+ auto& protocol_minor_version = obj.protocol_minor_version;
+ auto& length = obj.length;
+ auto& release_number = obj.release_number;
+ auto& resource_id_base = obj.resource_id_base;
+ auto& resource_id_mask = obj.resource_id_mask;
+ auto& motion_buffer_size = obj.motion_buffer_size;
+ uint16_t vendor_len{};
+ auto& maximum_request_length = obj.maximum_request_length;
+ uint8_t roots_len{};
+ uint8_t pixmap_formats_len{};
+ auto& image_byte_order = obj.image_byte_order;
+ auto& bitmap_format_bit_order = obj.bitmap_format_bit_order;
+ auto& bitmap_format_scanline_unit = obj.bitmap_format_scanline_unit;
+ auto& bitmap_format_scanline_pad = obj.bitmap_format_scanline_pad;
+ auto& min_keycode = obj.min_keycode;
+ auto& max_keycode = obj.max_keycode;
+ auto& vendor = obj.vendor;
+ auto& pixmap_formats = obj.pixmap_formats;
+ auto& roots = obj.roots;
+
+ // status
+ Read(&status, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // protocol_major_version
+ Read(&protocol_major_version, &buf);
+
+ // protocol_minor_version
+ Read(&protocol_minor_version, &buf);
+
+ // length
+ Read(&length, &buf);
+
+ // release_number
+ Read(&release_number, &buf);
+
+ // resource_id_base
+ Read(&resource_id_base, &buf);
+
+ // resource_id_mask
+ Read(&resource_id_mask, &buf);
+
+ // motion_buffer_size
+ Read(&motion_buffer_size, &buf);
+
+ // vendor_len
+ Read(&vendor_len, &buf);
+
+ // maximum_request_length
+ Read(&maximum_request_length, &buf);
+
+ // roots_len
+ Read(&roots_len, &buf);
+
+ // pixmap_formats_len
+ Read(&pixmap_formats_len, &buf);
+
+ // image_byte_order
+ uint8_t tmp0;
+ Read(&tmp0, &buf);
+ image_byte_order = static_cast<ImageOrder>(tmp0);
+
+ // bitmap_format_bit_order
+ uint8_t tmp1;
+ Read(&tmp1, &buf);
+ bitmap_format_bit_order = static_cast<ImageOrder>(tmp1);
+
+ // bitmap_format_scanline_unit
+ Read(&bitmap_format_scanline_unit, &buf);
+
+ // bitmap_format_scanline_pad
+ Read(&bitmap_format_scanline_pad, &buf);
+
+ // min_keycode
+ Read(&min_keycode, &buf);
+
+ // max_keycode
+ Read(&max_keycode, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // vendor
+ vendor.resize(vendor_len);
+ for (auto& vendor_elem : vendor) {
+ // vendor_elem
+ Read(&vendor_elem, &buf);
+ }
+
+ // pad2
+ Align(&buf, 4);
+
+ // pixmap_formats
+ pixmap_formats.resize(pixmap_formats_len);
+ for (auto& pixmap_formats_elem : pixmap_formats) {
+ // pixmap_formats_elem
+ {
+ auto& depth = pixmap_formats_elem.depth;
+ auto& bits_per_pixel = pixmap_formats_elem.bits_per_pixel;
+ auto& scanline_pad = pixmap_formats_elem.scanline_pad;
+
+ // depth
+ Read(&depth, &buf);
+
+ // bits_per_pixel
+ Read(&bits_per_pixel, &buf);
+
+ // scanline_pad
+ Read(&scanline_pad, &buf);
+
+ // pad0
+ Pad(&buf, 5);
+ }
+ }
+
+ // roots
+ roots.resize(roots_len);
+ for (auto& roots_elem : roots) {
+ // roots_elem
+ {
+ auto& root = roots_elem.root;
+ auto& default_colormap = roots_elem.default_colormap;
+ auto& white_pixel = roots_elem.white_pixel;
+ auto& black_pixel = roots_elem.black_pixel;
+ auto& current_input_masks = roots_elem.current_input_masks;
+ auto& width_in_pixels = roots_elem.width_in_pixels;
+ auto& height_in_pixels = roots_elem.height_in_pixels;
+ auto& width_in_millimeters = roots_elem.width_in_millimeters;
+ auto& height_in_millimeters = roots_elem.height_in_millimeters;
+ auto& min_installed_maps = roots_elem.min_installed_maps;
+ auto& max_installed_maps = roots_elem.max_installed_maps;
+ auto& root_visual = roots_elem.root_visual;
+ auto& backing_stores = roots_elem.backing_stores;
+ auto& save_unders = roots_elem.save_unders;
+ auto& root_depth = roots_elem.root_depth;
+ uint8_t allowed_depths_len{};
+ auto& allowed_depths = roots_elem.allowed_depths;
+
+ // root
+ Read(&root, &buf);
+
+ // default_colormap
+ Read(&default_colormap, &buf);
+
+ // white_pixel
+ Read(&white_pixel, &buf);
+
+ // black_pixel
+ Read(&black_pixel, &buf);
+
+ // current_input_masks
+ uint32_t tmp2;
+ Read(&tmp2, &buf);
+ current_input_masks = static_cast<EventMask>(tmp2);
+
+ // width_in_pixels
+ Read(&width_in_pixels, &buf);
+
+ // height_in_pixels
+ Read(&height_in_pixels, &buf);
+
+ // width_in_millimeters
+ Read(&width_in_millimeters, &buf);
+
+ // height_in_millimeters
+ Read(&height_in_millimeters, &buf);
+
+ // min_installed_maps
+ Read(&min_installed_maps, &buf);
+
+ // max_installed_maps
+ Read(&max_installed_maps, &buf);
+
+ // root_visual
+ Read(&root_visual, &buf);
+
+ // backing_stores
+ uint8_t tmp3;
+ Read(&tmp3, &buf);
+ backing_stores = static_cast<BackingStore>(tmp3);
+
+ // save_unders
+ Read(&save_unders, &buf);
+
+ // root_depth
+ Read(&root_depth, &buf);
+
+ // allowed_depths_len
+ Read(&allowed_depths_len, &buf);
+
+ // allowed_depths
+ allowed_depths.resize(allowed_depths_len);
+ for (auto& allowed_depths_elem : allowed_depths) {
+ // allowed_depths_elem
+ {
+ auto& depth = allowed_depths_elem.depth;
+ uint16_t visuals_len{};
+ auto& visuals = allowed_depths_elem.visuals;
+
+ // depth
+ Read(&depth, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // visuals_len
+ Read(&visuals_len, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // visuals
+ visuals.resize(visuals_len);
+ for (auto& visuals_elem : visuals) {
+ // visuals_elem
+ {
+ auto& visual_id = visuals_elem.visual_id;
+ auto& c_class = visuals_elem.c_class;
+ auto& bits_per_rgb_value = visuals_elem.bits_per_rgb_value;
+ auto& colormap_entries = visuals_elem.colormap_entries;
+ auto& red_mask = visuals_elem.red_mask;
+ auto& green_mask = visuals_elem.green_mask;
+ auto& blue_mask = visuals_elem.blue_mask;
+
+ // visual_id
+ Read(&visual_id, &buf);
+
+ // c_class
+ uint8_t tmp4;
+ Read(&tmp4, &buf);
+ c_class = static_cast<VisualClass>(tmp4);
+
+ // bits_per_rgb_value
+ Read(&bits_per_rgb_value, &buf);
+
+ // colormap_entries
+ Read(&colormap_entries, &buf);
+
+ // red_mask
+ Read(&red_mask, &buf);
+
+ // green_mask
+ Read(&green_mask, &buf);
+
+ // blue_mask
+ Read(&blue_mask, &buf);
+
+ // pad0
+ Pad(&buf, 4);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return obj;
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+WriteBuffer Write<KeyEvent>(const KeyEvent& obj) {
+ WriteBuffer buf;
+
+ auto& detail = obj.detail;
+ auto& sequence = obj.sequence;
+ auto& time = obj.time;
+ auto& root = obj.root;
+ auto& event = obj.event;
+ auto& child = obj.child;
+ auto& root_x = obj.root_x;
+ auto& root_y = obj.root_y;
+ auto& event_x = obj.event_x;
+ auto& event_y = obj.event_y;
+ auto& state = obj.state;
+ auto& same_screen = obj.same_screen;
+
+ // response_type
+ uint8_t response_type = obj.opcode;
+ buf.Write(&response_type);
+
+ // detail
+ buf.Write(&detail);
+
+ // sequence
+ buf.Write(&sequence);
+
+ // time
+ buf.Write(&time);
+
+ // root
+ buf.Write(&root);
+
+ // event
+ buf.Write(&event);
+
+ // child
+ buf.Write(&child);
+
+ // root_x
+ buf.Write(&root_x);
+
+ // root_y
+ buf.Write(&root_y);
+
+ // event_x
+ buf.Write(&event_x);
+
+ // event_y
+ buf.Write(&event_y);
+
+ // state
+ uint16_t tmp5;
+ tmp5 = static_cast<uint16_t>(state);
+ buf.Write(&tmp5);
+
+ // same_screen
+ buf.Write(&same_screen);
+
+ // pad0
+ Pad(&buf, 1);
+
+ return buf;
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<KeyEvent>(KeyEvent* event_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& detail = (*event_).detail;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& root = (*event_).root;
+ auto& event = (*event_).event;
+ auto& child = (*event_).child;
+ auto& root_x = (*event_).root_x;
+ auto& root_y = (*event_).root_y;
+ auto& event_x = (*event_).event_x;
+ auto& event_y = (*event_).event_y;
+ auto& state = (*event_).state;
+ auto& same_screen = (*event_).same_screen;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // detail
+ Read(&detail, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // event_x
+ Read(&event_x, &buf);
+
+ // event_y
+ Read(&event_y, &buf);
+
+ // state
+ uint16_t tmp6;
+ Read(&tmp6, &buf);
+ state = static_cast<KeyButMask>(tmp6);
+
+ // same_screen
+ Read(&same_screen, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+WriteBuffer Write<ButtonEvent>(const ButtonEvent& obj) {
+ WriteBuffer buf;
+
+ auto& detail = obj.detail;
+ auto& sequence = obj.sequence;
+ auto& time = obj.time;
+ auto& root = obj.root;
+ auto& event = obj.event;
+ auto& child = obj.child;
+ auto& root_x = obj.root_x;
+ auto& root_y = obj.root_y;
+ auto& event_x = obj.event_x;
+ auto& event_y = obj.event_y;
+ auto& state = obj.state;
+ auto& same_screen = obj.same_screen;
+
+ // response_type
+ uint8_t response_type = obj.opcode;
+ buf.Write(&response_type);
+
+ // detail
+ buf.Write(&detail);
+
+ // sequence
+ buf.Write(&sequence);
+
+ // time
+ buf.Write(&time);
+
+ // root
+ buf.Write(&root);
+
+ // event
+ buf.Write(&event);
+
+ // child
+ buf.Write(&child);
+
+ // root_x
+ buf.Write(&root_x);
+
+ // root_y
+ buf.Write(&root_y);
+
+ // event_x
+ buf.Write(&event_x);
+
+ // event_y
+ buf.Write(&event_y);
+
+ // state
+ uint16_t tmp7;
+ tmp7 = static_cast<uint16_t>(state);
+ buf.Write(&tmp7);
+
+ // same_screen
+ buf.Write(&same_screen);
+
+ // pad0
+ Pad(&buf, 1);
+
+ return buf;
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<ButtonEvent>(ButtonEvent* event_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& detail = (*event_).detail;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& root = (*event_).root;
+ auto& event = (*event_).event;
+ auto& child = (*event_).child;
+ auto& root_x = (*event_).root_x;
+ auto& root_y = (*event_).root_y;
+ auto& event_x = (*event_).event_x;
+ auto& event_y = (*event_).event_y;
+ auto& state = (*event_).state;
+ auto& same_screen = (*event_).same_screen;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // detail
+ Read(&detail, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // event_x
+ Read(&event_x, &buf);
+
+ // event_y
+ Read(&event_y, &buf);
+
+ // state
+ uint16_t tmp8;
+ Read(&tmp8, &buf);
+ state = static_cast<KeyButMask>(tmp8);
+
+ // same_screen
+ Read(&same_screen, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+WriteBuffer Write<MotionNotifyEvent>(const MotionNotifyEvent& obj) {
+ WriteBuffer buf;
+
+ auto& detail = obj.detail;
+ auto& sequence = obj.sequence;
+ auto& time = obj.time;
+ auto& root = obj.root;
+ auto& event = obj.event;
+ auto& child = obj.child;
+ auto& root_x = obj.root_x;
+ auto& root_y = obj.root_y;
+ auto& event_x = obj.event_x;
+ auto& event_y = obj.event_y;
+ auto& state = obj.state;
+ auto& same_screen = obj.same_screen;
+
+ // response_type
+ uint8_t response_type = 6;
+ buf.Write(&response_type);
+
+ // detail
+ uint8_t tmp9;
+ tmp9 = static_cast<uint8_t>(detail);
+ buf.Write(&tmp9);
+
+ // sequence
+ buf.Write(&sequence);
+
+ // time
+ buf.Write(&time);
+
+ // root
+ buf.Write(&root);
+
+ // event
+ buf.Write(&event);
+
+ // child
+ buf.Write(&child);
+
+ // root_x
+ buf.Write(&root_x);
+
+ // root_y
+ buf.Write(&root_y);
+
+ // event_x
+ buf.Write(&event_x);
+
+ // event_y
+ buf.Write(&event_y);
+
+ // state
+ uint16_t tmp10;
+ tmp10 = static_cast<uint16_t>(state);
+ buf.Write(&tmp10);
+
+ // same_screen
+ buf.Write(&same_screen);
+
+ // pad0
+ Pad(&buf, 1);
+
+ return buf;
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<MotionNotifyEvent>(MotionNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& detail = (*event_).detail;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& root = (*event_).root;
+ auto& event = (*event_).event;
+ auto& child = (*event_).child;
+ auto& root_x = (*event_).root_x;
+ auto& root_y = (*event_).root_y;
+ auto& event_x = (*event_).event_x;
+ auto& event_y = (*event_).event_y;
+ auto& state = (*event_).state;
+ auto& same_screen = (*event_).same_screen;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // detail
+ uint8_t tmp11;
+ Read(&tmp11, &buf);
+ detail = static_cast<Motion>(tmp11);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // event_x
+ Read(&event_x, &buf);
+
+ // event_y
+ Read(&event_y, &buf);
+
+ // state
+ uint16_t tmp12;
+ Read(&tmp12, &buf);
+ state = static_cast<KeyButMask>(tmp12);
+
+ // same_screen
+ Read(&same_screen, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<CrossingEvent>(CrossingEvent* event_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& detail = (*event_).detail;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& root = (*event_).root;
+ auto& event = (*event_).event;
+ auto& child = (*event_).child;
+ auto& root_x = (*event_).root_x;
+ auto& root_y = (*event_).root_y;
+ auto& event_x = (*event_).event_x;
+ auto& event_y = (*event_).event_y;
+ auto& state = (*event_).state;
+ auto& mode = (*event_).mode;
+ auto& same_screen_focus = (*event_).same_screen_focus;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // detail
+ uint8_t tmp13;
+ Read(&tmp13, &buf);
+ detail = static_cast<NotifyDetail>(tmp13);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // event_x
+ Read(&event_x, &buf);
+
+ // event_y
+ Read(&event_y, &buf);
+
+ // state
+ uint16_t tmp14;
+ Read(&tmp14, &buf);
+ state = static_cast<KeyButMask>(tmp14);
+
+ // mode
+ uint8_t tmp15;
+ Read(&tmp15, &buf);
+ mode = static_cast<NotifyMode>(tmp15);
+
+ // same_screen_focus
+ Read(&same_screen_focus, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<FocusEvent>(FocusEvent* event_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& detail = (*event_).detail;
+ auto& sequence = (*event_).sequence;
+ auto& event = (*event_).event;
+ auto& mode = (*event_).mode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // detail
+ uint8_t tmp16;
+ Read(&tmp16, &buf);
+ detail = static_cast<NotifyDetail>(tmp16);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // mode
+ uint8_t tmp17;
+ Read(&tmp17, &buf);
+ mode = static_cast<NotifyMode>(tmp17);
+
+ // pad0
+ Pad(&buf, 3);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<KeymapNotifyEvent>(KeymapNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& keys = (*event_).keys;
+ size_t keys_len = keys.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // keys
+ for (auto& keys_elem : keys) {
+ // keys_elem
+ Read(&keys_elem, &buf);
+ }
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+WriteBuffer Write<ExposeEvent>(const ExposeEvent& obj) {
+ WriteBuffer buf;
+
+ auto& sequence = obj.sequence;
+ auto& window = obj.window;
+ auto& x = obj.x;
+ auto& y = obj.y;
+ auto& width = obj.width;
+ auto& height = obj.height;
+ auto& count = obj.count;
+
+ // response_type
+ uint8_t response_type = 12;
+ buf.Write(&response_type);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ buf.Write(&sequence);
+
+ // window
+ buf.Write(&window);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // count
+ buf.Write(&count);
+
+ // pad1
+ Pad(&buf, 2);
+
+ return buf;
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<ExposeEvent>(ExposeEvent* event_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& window = (*event_).window;
+ auto& x = (*event_).x;
+ auto& y = (*event_).y;
+ auto& width = (*event_).width;
+ auto& height = (*event_).height;
+ auto& count = (*event_).count;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // count
+ Read(&count, &buf);
+
+ // pad1
+ Pad(&buf, 2);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<GraphicsExposureEvent>(GraphicsExposureEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& drawable = (*event_).drawable;
+ auto& x = (*event_).x;
+ auto& y = (*event_).y;
+ auto& width = (*event_).width;
+ auto& height = (*event_).height;
+ auto& minor_opcode = (*event_).minor_opcode;
+ auto& count = (*event_).count;
+ auto& major_opcode = (*event_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // drawable
+ Read(&drawable, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // count
+ Read(&count, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad1
+ Pad(&buf, 3);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<NoExposureEvent>(NoExposureEvent* event_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& drawable = (*event_).drawable;
+ auto& minor_opcode = (*event_).minor_opcode;
+ auto& major_opcode = (*event_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // drawable
+ Read(&drawable, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad1
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<VisibilityNotifyEvent>(VisibilityNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& window = (*event_).window;
+ auto& state = (*event_).state;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // state
+ uint8_t tmp18;
+ Read(&tmp18, &buf);
+ state = static_cast<Visibility>(tmp18);
+
+ // pad1
+ Pad(&buf, 3);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<CreateNotifyEvent>(CreateNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& parent = (*event_).parent;
+ auto& window = (*event_).window;
+ auto& x = (*event_).x;
+ auto& y = (*event_).y;
+ auto& width = (*event_).width;
+ auto& height = (*event_).height;
+ auto& border_width = (*event_).border_width;
+ auto& override_redirect = (*event_).override_redirect;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // parent
+ Read(&parent, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // border_width
+ Read(&border_width, &buf);
+
+ // override_redirect
+ Read(&override_redirect, &buf);
+
+ // pad1
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<DestroyNotifyEvent>(DestroyNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event = (*event_).event;
+ auto& window = (*event_).window;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+WriteBuffer Write<UnmapNotifyEvent>(const UnmapNotifyEvent& obj) {
+ WriteBuffer buf;
+
+ auto& sequence = obj.sequence;
+ auto& event = obj.event;
+ auto& window = obj.window;
+ auto& from_configure = obj.from_configure;
+
+ // response_type
+ uint8_t response_type = 18;
+ buf.Write(&response_type);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ buf.Write(&sequence);
+
+ // event
+ buf.Write(&event);
+
+ // window
+ buf.Write(&window);
+
+ // from_configure
+ buf.Write(&from_configure);
+
+ // pad1
+ Pad(&buf, 3);
+
+ return buf;
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<UnmapNotifyEvent>(UnmapNotifyEvent* event_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event = (*event_).event;
+ auto& window = (*event_).window;
+ auto& from_configure = (*event_).from_configure;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // from_configure
+ Read(&from_configure, &buf);
+
+ // pad1
+ Pad(&buf, 3);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<MapNotifyEvent>(MapNotifyEvent* event_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event = (*event_).event;
+ auto& window = (*event_).window;
+ auto& override_redirect = (*event_).override_redirect;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // override_redirect
+ Read(&override_redirect, &buf);
+
+ // pad1
+ Pad(&buf, 3);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<MapRequestEvent>(MapRequestEvent* event_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& parent = (*event_).parent;
+ auto& window = (*event_).window;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // parent
+ Read(&parent, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<ReparentNotifyEvent>(ReparentNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event = (*event_).event;
+ auto& window = (*event_).window;
+ auto& parent = (*event_).parent;
+ auto& x = (*event_).x;
+ auto& y = (*event_).y;
+ auto& override_redirect = (*event_).override_redirect;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // parent
+ Read(&parent, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // override_redirect
+ Read(&override_redirect, &buf);
+
+ // pad1
+ Pad(&buf, 3);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<ConfigureNotifyEvent>(ConfigureNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event = (*event_).event;
+ auto& window = (*event_).window;
+ auto& above_sibling = (*event_).above_sibling;
+ auto& x = (*event_).x;
+ auto& y = (*event_).y;
+ auto& width = (*event_).width;
+ auto& height = (*event_).height;
+ auto& border_width = (*event_).border_width;
+ auto& override_redirect = (*event_).override_redirect;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // above_sibling
+ Read(&above_sibling, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // border_width
+ Read(&border_width, &buf);
+
+ // override_redirect
+ Read(&override_redirect, &buf);
+
+ // pad1
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<ConfigureRequestEvent>(ConfigureRequestEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& stack_mode = (*event_).stack_mode;
+ auto& sequence = (*event_).sequence;
+ auto& parent = (*event_).parent;
+ auto& window = (*event_).window;
+ auto& sibling = (*event_).sibling;
+ auto& x = (*event_).x;
+ auto& y = (*event_).y;
+ auto& width = (*event_).width;
+ auto& height = (*event_).height;
+ auto& border_width = (*event_).border_width;
+ auto& value_mask = (*event_).value_mask;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // stack_mode
+ uint8_t tmp19;
+ Read(&tmp19, &buf);
+ stack_mode = static_cast<StackMode>(tmp19);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // parent
+ Read(&parent, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // sibling
+ Read(&sibling, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // border_width
+ Read(&border_width, &buf);
+
+ // value_mask
+ uint16_t tmp20;
+ Read(&tmp20, &buf);
+ value_mask = static_cast<ConfigWindow>(tmp20);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<GravityNotifyEvent>(GravityNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event = (*event_).event;
+ auto& window = (*event_).window;
+ auto& x = (*event_).x;
+ auto& y = (*event_).y;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<ResizeRequestEvent>(ResizeRequestEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& window = (*event_).window;
+ auto& width = (*event_).width;
+ auto& height = (*event_).height;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<CirculateEvent>(CirculateEvent* event_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& event = (*event_).event;
+ auto& window = (*event_).window;
+ auto& place = (*event_).place;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // pad1
+ Pad(&buf, 4);
+
+ // place
+ uint8_t tmp21;
+ Read(&tmp21, &buf);
+ place = static_cast<Place>(tmp21);
+
+ // pad2
+ Pad(&buf, 3);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+WriteBuffer Write<PropertyNotifyEvent>(const PropertyNotifyEvent& obj) {
+ WriteBuffer buf;
+
+ auto& sequence = obj.sequence;
+ auto& window = obj.window;
+ auto& atom = obj.atom;
+ auto& time = obj.time;
+ auto& state = obj.state;
+
+ // response_type
+ uint8_t response_type = 28;
+ buf.Write(&response_type);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ buf.Write(&sequence);
+
+ // window
+ buf.Write(&window);
+
+ // atom
+ buf.Write(&atom);
+
+ // time
+ buf.Write(&time);
+
+ // state
+ uint8_t tmp22;
+ tmp22 = static_cast<uint8_t>(state);
+ buf.Write(&tmp22);
+
+ // pad1
+ Pad(&buf, 3);
+
+ return buf;
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<PropertyNotifyEvent>(PropertyNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& window = (*event_).window;
+ auto& atom = (*event_).atom;
+ auto& time = (*event_).time;
+ auto& state = (*event_).state;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // atom
+ Read(&atom, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // state
+ uint8_t tmp23;
+ Read(&tmp23, &buf);
+ state = static_cast<Property>(tmp23);
+
+ // pad1
+ Pad(&buf, 3);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<SelectionClearEvent>(SelectionClearEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& owner = (*event_).owner;
+ auto& selection = (*event_).selection;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // owner
+ Read(&owner, &buf);
+
+ // selection
+ Read(&selection, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<SelectionRequestEvent>(SelectionRequestEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& owner = (*event_).owner;
+ auto& requestor = (*event_).requestor;
+ auto& selection = (*event_).selection;
+ auto& target = (*event_).target;
+ auto& property = (*event_).property;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // owner
+ Read(&owner, &buf);
+
+ // requestor
+ Read(&requestor, &buf);
+
+ // selection
+ Read(&selection, &buf);
+
+ // target
+ Read(&target, &buf);
+
+ // property
+ Read(&property, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+WriteBuffer Write<SelectionNotifyEvent>(const SelectionNotifyEvent& obj) {
+ WriteBuffer buf;
+
+ auto& sequence = obj.sequence;
+ auto& time = obj.time;
+ auto& requestor = obj.requestor;
+ auto& selection = obj.selection;
+ auto& target = obj.target;
+ auto& property = obj.property;
+
+ // response_type
+ uint8_t response_type = 31;
+ buf.Write(&response_type);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ buf.Write(&sequence);
+
+ // time
+ buf.Write(&time);
+
+ // requestor
+ buf.Write(&requestor);
+
+ // selection
+ buf.Write(&selection);
+
+ // target
+ buf.Write(&target);
+
+ // property
+ buf.Write(&property);
+
+ return buf;
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<SelectionNotifyEvent>(SelectionNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& requestor = (*event_).requestor;
+ auto& selection = (*event_).selection;
+ auto& target = (*event_).target;
+ auto& property = (*event_).property;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // requestor
+ Read(&requestor, &buf);
+
+ // selection
+ Read(&selection, &buf);
+
+ // target
+ Read(&target, &buf);
+
+ // property
+ Read(&property, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<ColormapNotifyEvent>(ColormapNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& window = (*event_).window;
+ auto& colormap = (*event_).colormap;
+ auto& c_new = (*event_).c_new;
+ auto& state = (*event_).state;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // colormap
+ Read(&colormap, &buf);
+
+ // c_new
+ Read(&c_new, &buf);
+
+ // state
+ uint8_t tmp24;
+ Read(&tmp24, &buf);
+ state = static_cast<ColormapState>(tmp24);
+
+ // pad1
+ Pad(&buf, 2);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+WriteBuffer Write<ClientMessageEvent>(const ClientMessageEvent& obj) {
+ WriteBuffer buf;
+
+ auto& format = obj.format;
+ auto& sequence = obj.sequence;
+ auto& window = obj.window;
+ auto& type = obj.type;
+ auto& data = obj.data;
+
+ // response_type
+ uint8_t response_type = 33;
+ buf.Write(&response_type);
+
+ // format
+ buf.Write(&format);
+
+ // sequence
+ buf.Write(&sequence);
+
+ // window
+ buf.Write(&window);
+
+ // type
+ buf.Write(&type);
+
+ // data
+ buf.Write(&data);
+
+ return buf;
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<ClientMessageEvent>(ClientMessageEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& format = (*event_).format;
+ auto& sequence = (*event_).sequence;
+ auto& window = (*event_).window;
+ auto& type = (*event_).type;
+ auto& data = (*event_).data;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // format
+ Read(&format, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // window
+ Read(&window, &buf);
+
+ // type
+ Read(&type, &buf);
+
+ // data
+ Read(&data, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<MappingNotifyEvent>(MappingNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& request = (*event_).request;
+ auto& first_keycode = (*event_).first_keycode;
+ auto& count = (*event_).count;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // request
+ uint8_t tmp25;
+ Read(&tmp25, &buf);
+ request = static_cast<Mapping>(tmp25);
+
+ // first_keycode
+ Read(&first_keycode, &buf);
+
+ // count
+ Read(&count, &buf);
+
+ // pad1
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<GeGenericEvent>(GeGenericEvent* event_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // pad0
+ Pad(&buf, 22);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+std::string RequestError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "RequestError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<RequestError>(RequestError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string ValueError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "ValueError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<ValueError>(ValueError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string WindowError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "WindowError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<WindowError>(WindowError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string PixmapError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "PixmapError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<PixmapError>(PixmapError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string AtomError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "AtomError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<AtomError>(AtomError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string CursorError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "CursorError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<CursorError>(CursorError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string FontError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "FontError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<FontError>(FontError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string MatchError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "MatchError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<MatchError>(MatchError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string DrawableError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "DrawableError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<DrawableError>(DrawableError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string AccessError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "AccessError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<AccessError>(AccessError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string AllocError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "AllocError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<AllocError>(AllocError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string ColormapError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "ColormapError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<ColormapError>(ColormapError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string GContextError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "GContextError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<GContextError>(GContextError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string IDChoiceError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "IDChoiceError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<IDChoiceError>(IDChoiceError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string NameError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "NameError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<NameError>(NameError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string LengthError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "LengthError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<LengthError>(LengthError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string ImplementationError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "ImplementationError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<ImplementationError>(ImplementationError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+Future<void> XProto::CreateWindow(const CreateWindowRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& depth = request.depth;
+ auto& wid = request.wid;
+ auto& parent = request.parent;
+ auto& x = request.x;
+ auto& y = request.y;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& border_width = request.border_width;
+ auto& c_class = request.c_class;
+ auto& visual = request.visual;
+ CreateWindowAttribute value_mask{};
+ auto& value_list = request;
+
+ // major_opcode
+ uint8_t major_opcode = 1;
+ buf.Write(&major_opcode);
+
+ // depth
+ buf.Write(&depth);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // wid
+ buf.Write(&wid);
+
+ // parent
+ buf.Write(&parent);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // border_width
+ buf.Write(&border_width);
+
+ // c_class
+ uint16_t tmp26;
+ tmp26 = static_cast<uint16_t>(c_class);
+ buf.Write(&tmp26);
+
+ // visual
+ buf.Write(&visual);
+
+ // value_mask
+ SwitchVar(CreateWindowAttribute::BackPixmap,
+ value_list.background_pixmap.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackPixel,
+ value_list.background_pixel.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BorderPixmap,
+ value_list.border_pixmap.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BorderPixel,
+ value_list.border_pixel.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BitGravity,
+ value_list.bit_gravity.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::WinGravity,
+ value_list.win_gravity.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackingStore,
+ value_list.backing_store.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackingPlanes,
+ value_list.backing_planes.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackingPixel,
+ value_list.backing_pixel.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::OverrideRedirect,
+ value_list.override_redirect.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::SaveUnder, value_list.save_under.has_value(),
+ true, &value_mask);
+ SwitchVar(CreateWindowAttribute::EventMask, value_list.event_mask.has_value(),
+ true, &value_mask);
+ SwitchVar(CreateWindowAttribute::DontPropagate,
+ value_list.do_not_propogate_mask.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::Colormap, value_list.colormap.has_value(),
+ true, &value_mask);
+ SwitchVar(CreateWindowAttribute::Cursor, value_list.cursor.has_value(), true,
+ &value_mask);
+ uint32_t tmp27;
+ tmp27 = static_cast<uint32_t>(value_mask);
+ buf.Write(&tmp27);
+
+ // value_list
+ auto value_list_expr = value_mask;
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackPixmap)) {
+ auto& background_pixmap = *value_list.background_pixmap;
+
+ // background_pixmap
+ buf.Write(&background_pixmap);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackPixel)) {
+ auto& background_pixel = *value_list.background_pixel;
+
+ // background_pixel
+ buf.Write(&background_pixel);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BorderPixmap)) {
+ auto& border_pixmap = *value_list.border_pixmap;
+
+ // border_pixmap
+ buf.Write(&border_pixmap);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BorderPixel)) {
+ auto& border_pixel = *value_list.border_pixel;
+
+ // border_pixel
+ buf.Write(&border_pixel);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BitGravity)) {
+ auto& bit_gravity = *value_list.bit_gravity;
+
+ // bit_gravity
+ uint32_t tmp28;
+ tmp28 = static_cast<uint32_t>(bit_gravity);
+ buf.Write(&tmp28);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::WinGravity)) {
+ auto& win_gravity = *value_list.win_gravity;
+
+ // win_gravity
+ uint32_t tmp29;
+ tmp29 = static_cast<uint32_t>(win_gravity);
+ buf.Write(&tmp29);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackingStore)) {
+ auto& backing_store = *value_list.backing_store;
+
+ // backing_store
+ uint32_t tmp30;
+ tmp30 = static_cast<uint32_t>(backing_store);
+ buf.Write(&tmp30);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackingPlanes)) {
+ auto& backing_planes = *value_list.backing_planes;
+
+ // backing_planes
+ buf.Write(&backing_planes);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackingPixel)) {
+ auto& backing_pixel = *value_list.backing_pixel;
+
+ // backing_pixel
+ buf.Write(&backing_pixel);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::OverrideRedirect)) {
+ auto& override_redirect = *value_list.override_redirect;
+
+ // override_redirect
+ buf.Write(&override_redirect);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::SaveUnder)) {
+ auto& save_under = *value_list.save_under;
+
+ // save_under
+ buf.Write(&save_under);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::EventMask)) {
+ auto& event_mask = *value_list.event_mask;
+
+ // event_mask
+ uint32_t tmp31;
+ tmp31 = static_cast<uint32_t>(event_mask);
+ buf.Write(&tmp31);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::DontPropagate)) {
+ auto& do_not_propogate_mask = *value_list.do_not_propogate_mask;
+
+ // do_not_propogate_mask
+ uint32_t tmp32;
+ tmp32 = static_cast<uint32_t>(do_not_propogate_mask);
+ buf.Write(&tmp32);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::Colormap)) {
+ auto& colormap = *value_list.colormap;
+
+ // colormap
+ buf.Write(&colormap);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::Cursor)) {
+ auto& cursor = *value_list.cursor;
+
+ // cursor
+ buf.Write(&cursor);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CreateWindow", false);
+}
+
+Future<void> XProto::CreateWindow(
+ const uint8_t& depth,
+ const Window& wid,
+ const Window& parent,
+ const int16_t& x,
+ const int16_t& y,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint16_t& border_width,
+ const WindowClass& c_class,
+ const VisualId& visual,
+ const base::Optional<Pixmap>& background_pixmap,
+ const base::Optional<uint32_t>& background_pixel,
+ const base::Optional<Pixmap>& border_pixmap,
+ const base::Optional<uint32_t>& border_pixel,
+ const base::Optional<Gravity>& bit_gravity,
+ const base::Optional<Gravity>& win_gravity,
+ const base::Optional<BackingStore>& backing_store,
+ const base::Optional<uint32_t>& backing_planes,
+ const base::Optional<uint32_t>& backing_pixel,
+ const base::Optional<Bool32>& override_redirect,
+ const base::Optional<Bool32>& save_under,
+ const base::Optional<EventMask>& event_mask,
+ const base::Optional<EventMask>& do_not_propogate_mask,
+ const base::Optional<ColorMap>& colormap,
+ const base::Optional<Cursor>& cursor) {
+ return XProto::CreateWindow(CreateWindowRequest{depth,
+ wid,
+ parent,
+ x,
+ y,
+ width,
+ height,
+ border_width,
+ c_class,
+ visual,
+ background_pixmap,
+ background_pixel,
+ border_pixmap,
+ border_pixel,
+ bit_gravity,
+ win_gravity,
+ backing_store,
+ backing_planes,
+ backing_pixel,
+ override_redirect,
+ save_under,
+ event_mask,
+ do_not_propogate_mask,
+ colormap,
+ cursor});
+}
+
+Future<void> XProto::ChangeWindowAttributes(
+ const ChangeWindowAttributesRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ CreateWindowAttribute value_mask{};
+ auto& value_list = request;
+
+ // major_opcode
+ uint8_t major_opcode = 2;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // value_mask
+ SwitchVar(CreateWindowAttribute::BackPixmap,
+ value_list.background_pixmap.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackPixel,
+ value_list.background_pixel.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BorderPixmap,
+ value_list.border_pixmap.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BorderPixel,
+ value_list.border_pixel.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BitGravity,
+ value_list.bit_gravity.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::WinGravity,
+ value_list.win_gravity.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackingStore,
+ value_list.backing_store.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackingPlanes,
+ value_list.backing_planes.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::BackingPixel,
+ value_list.backing_pixel.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::OverrideRedirect,
+ value_list.override_redirect.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::SaveUnder, value_list.save_under.has_value(),
+ true, &value_mask);
+ SwitchVar(CreateWindowAttribute::EventMask, value_list.event_mask.has_value(),
+ true, &value_mask);
+ SwitchVar(CreateWindowAttribute::DontPropagate,
+ value_list.do_not_propogate_mask.has_value(), true, &value_mask);
+ SwitchVar(CreateWindowAttribute::Colormap, value_list.colormap.has_value(),
+ true, &value_mask);
+ SwitchVar(CreateWindowAttribute::Cursor, value_list.cursor.has_value(), true,
+ &value_mask);
+ uint32_t tmp33;
+ tmp33 = static_cast<uint32_t>(value_mask);
+ buf.Write(&tmp33);
+
+ // value_list
+ auto value_list_expr = value_mask;
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackPixmap)) {
+ auto& background_pixmap = *value_list.background_pixmap;
+
+ // background_pixmap
+ buf.Write(&background_pixmap);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackPixel)) {
+ auto& background_pixel = *value_list.background_pixel;
+
+ // background_pixel
+ buf.Write(&background_pixel);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BorderPixmap)) {
+ auto& border_pixmap = *value_list.border_pixmap;
+
+ // border_pixmap
+ buf.Write(&border_pixmap);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BorderPixel)) {
+ auto& border_pixel = *value_list.border_pixel;
+
+ // border_pixel
+ buf.Write(&border_pixel);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BitGravity)) {
+ auto& bit_gravity = *value_list.bit_gravity;
+
+ // bit_gravity
+ uint32_t tmp34;
+ tmp34 = static_cast<uint32_t>(bit_gravity);
+ buf.Write(&tmp34);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::WinGravity)) {
+ auto& win_gravity = *value_list.win_gravity;
+
+ // win_gravity
+ uint32_t tmp35;
+ tmp35 = static_cast<uint32_t>(win_gravity);
+ buf.Write(&tmp35);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackingStore)) {
+ auto& backing_store = *value_list.backing_store;
+
+ // backing_store
+ uint32_t tmp36;
+ tmp36 = static_cast<uint32_t>(backing_store);
+ buf.Write(&tmp36);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackingPlanes)) {
+ auto& backing_planes = *value_list.backing_planes;
+
+ // backing_planes
+ buf.Write(&backing_planes);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::BackingPixel)) {
+ auto& backing_pixel = *value_list.backing_pixel;
+
+ // backing_pixel
+ buf.Write(&backing_pixel);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::OverrideRedirect)) {
+ auto& override_redirect = *value_list.override_redirect;
+
+ // override_redirect
+ buf.Write(&override_redirect);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::SaveUnder)) {
+ auto& save_under = *value_list.save_under;
+
+ // save_under
+ buf.Write(&save_under);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::EventMask)) {
+ auto& event_mask = *value_list.event_mask;
+
+ // event_mask
+ uint32_t tmp37;
+ tmp37 = static_cast<uint32_t>(event_mask);
+ buf.Write(&tmp37);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::DontPropagate)) {
+ auto& do_not_propogate_mask = *value_list.do_not_propogate_mask;
+
+ // do_not_propogate_mask
+ uint32_t tmp38;
+ tmp38 = static_cast<uint32_t>(do_not_propogate_mask);
+ buf.Write(&tmp38);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::Colormap)) {
+ auto& colormap = *value_list.colormap;
+
+ // colormap
+ buf.Write(&colormap);
+ }
+ if (CaseAnd(value_list_expr, CreateWindowAttribute::Cursor)) {
+ auto& cursor = *value_list.cursor;
+
+ // cursor
+ buf.Write(&cursor);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ChangeWindowAttributes", false);
+}
+
+Future<void> XProto::ChangeWindowAttributes(
+ const Window& window,
+ const base::Optional<Pixmap>& background_pixmap,
+ const base::Optional<uint32_t>& background_pixel,
+ const base::Optional<Pixmap>& border_pixmap,
+ const base::Optional<uint32_t>& border_pixel,
+ const base::Optional<Gravity>& bit_gravity,
+ const base::Optional<Gravity>& win_gravity,
+ const base::Optional<BackingStore>& backing_store,
+ const base::Optional<uint32_t>& backing_planes,
+ const base::Optional<uint32_t>& backing_pixel,
+ const base::Optional<Bool32>& override_redirect,
+ const base::Optional<Bool32>& save_under,
+ const base::Optional<EventMask>& event_mask,
+ const base::Optional<EventMask>& do_not_propogate_mask,
+ const base::Optional<ColorMap>& colormap,
+ const base::Optional<Cursor>& cursor) {
+ return XProto::ChangeWindowAttributes(ChangeWindowAttributesRequest{
+ window, background_pixmap, background_pixel, border_pixmap, border_pixel,
+ bit_gravity, win_gravity, backing_store, backing_planes, backing_pixel,
+ override_redirect, save_under, event_mask, do_not_propogate_mask,
+ colormap, cursor});
+}
+
+Future<GetWindowAttributesReply> XProto::GetWindowAttributes(
+ const GetWindowAttributesRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 3;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetWindowAttributesReply>(
+ &buf, "GetWindowAttributes", false);
+}
+
+Future<GetWindowAttributesReply> XProto::GetWindowAttributes(
+ const Window& window) {
+ return XProto::GetWindowAttributes(GetWindowAttributesRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetWindowAttributesReply> detail::ReadReply<
+ GetWindowAttributesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetWindowAttributesReply>();
+
+ auto& backing_store = (*reply).backing_store;
+ auto& sequence = (*reply).sequence;
+ auto& visual = (*reply).visual;
+ auto& c_class = (*reply).c_class;
+ auto& bit_gravity = (*reply).bit_gravity;
+ auto& win_gravity = (*reply).win_gravity;
+ auto& backing_planes = (*reply).backing_planes;
+ auto& backing_pixel = (*reply).backing_pixel;
+ auto& save_under = (*reply).save_under;
+ auto& map_is_installed = (*reply).map_is_installed;
+ auto& map_state = (*reply).map_state;
+ auto& override_redirect = (*reply).override_redirect;
+ auto& colormap = (*reply).colormap;
+ auto& all_event_masks = (*reply).all_event_masks;
+ auto& your_event_mask = (*reply).your_event_mask;
+ auto& do_not_propagate_mask = (*reply).do_not_propagate_mask;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // backing_store
+ uint8_t tmp39;
+ Read(&tmp39, &buf);
+ backing_store = static_cast<BackingStore>(tmp39);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // visual
+ Read(&visual, &buf);
+
+ // c_class
+ uint16_t tmp40;
+ Read(&tmp40, &buf);
+ c_class = static_cast<WindowClass>(tmp40);
+
+ // bit_gravity
+ uint8_t tmp41;
+ Read(&tmp41, &buf);
+ bit_gravity = static_cast<Gravity>(tmp41);
+
+ // win_gravity
+ uint8_t tmp42;
+ Read(&tmp42, &buf);
+ win_gravity = static_cast<Gravity>(tmp42);
+
+ // backing_planes
+ Read(&backing_planes, &buf);
+
+ // backing_pixel
+ Read(&backing_pixel, &buf);
+
+ // save_under
+ Read(&save_under, &buf);
+
+ // map_is_installed
+ Read(&map_is_installed, &buf);
+
+ // map_state
+ uint8_t tmp43;
+ Read(&tmp43, &buf);
+ map_state = static_cast<MapState>(tmp43);
+
+ // override_redirect
+ Read(&override_redirect, &buf);
+
+ // colormap
+ Read(&colormap, &buf);
+
+ // all_event_masks
+ uint32_t tmp44;
+ Read(&tmp44, &buf);
+ all_event_masks = static_cast<EventMask>(tmp44);
+
+ // your_event_mask
+ uint32_t tmp45;
+ Read(&tmp45, &buf);
+ your_event_mask = static_cast<EventMask>(tmp45);
+
+ // do_not_propagate_mask
+ uint16_t tmp46;
+ Read(&tmp46, &buf);
+ do_not_propagate_mask = static_cast<EventMask>(tmp46);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::DestroyWindow(const DestroyWindowRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 4;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "DestroyWindow", false);
+}
+
+Future<void> XProto::DestroyWindow(const Window& window) {
+ return XProto::DestroyWindow(DestroyWindowRequest{window});
+}
+
+Future<void> XProto::DestroySubwindows(
+ const DestroySubwindowsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 5;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "DestroySubwindows", false);
+}
+
+Future<void> XProto::DestroySubwindows(const Window& window) {
+ return XProto::DestroySubwindows(DestroySubwindowsRequest{window});
+}
+
+Future<void> XProto::ChangeSaveSet(const ChangeSaveSetRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& mode = request.mode;
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 6;
+ buf.Write(&major_opcode);
+
+ // mode
+ uint8_t tmp47;
+ tmp47 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp47);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ChangeSaveSet", false);
+}
+
+Future<void> XProto::ChangeSaveSet(const SetMode& mode, const Window& window) {
+ return XProto::ChangeSaveSet(ChangeSaveSetRequest{mode, window});
+}
+
+Future<void> XProto::ReparentWindow(const ReparentWindowRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& parent = request.parent;
+ auto& x = request.x;
+ auto& y = request.y;
+
+ // major_opcode
+ uint8_t major_opcode = 7;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // parent
+ buf.Write(&parent);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ReparentWindow", false);
+}
+
+Future<void> XProto::ReparentWindow(const Window& window,
+ const Window& parent,
+ const int16_t& x,
+ const int16_t& y) {
+ return XProto::ReparentWindow(ReparentWindowRequest{window, parent, x, y});
+}
+
+Future<void> XProto::MapWindow(const MapWindowRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 8;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "MapWindow", false);
+}
+
+Future<void> XProto::MapWindow(const Window& window) {
+ return XProto::MapWindow(MapWindowRequest{window});
+}
+
+Future<void> XProto::MapSubwindows(const MapSubwindowsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 9;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "MapSubwindows", false);
+}
+
+Future<void> XProto::MapSubwindows(const Window& window) {
+ return XProto::MapSubwindows(MapSubwindowsRequest{window});
+}
+
+Future<void> XProto::UnmapWindow(const UnmapWindowRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 10;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "UnmapWindow", false);
+}
+
+Future<void> XProto::UnmapWindow(const Window& window) {
+ return XProto::UnmapWindow(UnmapWindowRequest{window});
+}
+
+Future<void> XProto::UnmapSubwindows(const UnmapSubwindowsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 11;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "UnmapSubwindows", false);
+}
+
+Future<void> XProto::UnmapSubwindows(const Window& window) {
+ return XProto::UnmapSubwindows(UnmapSubwindowsRequest{window});
+}
+
+Future<void> XProto::ConfigureWindow(const ConfigureWindowRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ ConfigWindow value_mask{};
+ auto& value_list = request;
+
+ // major_opcode
+ uint8_t major_opcode = 12;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // value_mask
+ SwitchVar(ConfigWindow::X, value_list.x.has_value(), true, &value_mask);
+ SwitchVar(ConfigWindow::Y, value_list.y.has_value(), true, &value_mask);
+ SwitchVar(ConfigWindow::Width, value_list.width.has_value(), true,
+ &value_mask);
+ SwitchVar(ConfigWindow::Height, value_list.height.has_value(), true,
+ &value_mask);
+ SwitchVar(ConfigWindow::BorderWidth, value_list.border_width.has_value(),
+ true, &value_mask);
+ SwitchVar(ConfigWindow::Sibling, value_list.sibling.has_value(), true,
+ &value_mask);
+ SwitchVar(ConfigWindow::StackMode, value_list.stack_mode.has_value(), true,
+ &value_mask);
+ uint16_t tmp48;
+ tmp48 = static_cast<uint16_t>(value_mask);
+ buf.Write(&tmp48);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // value_list
+ auto value_list_expr = value_mask;
+ if (CaseAnd(value_list_expr, ConfigWindow::X)) {
+ auto& x = *value_list.x;
+
+ // x
+ buf.Write(&x);
+ }
+ if (CaseAnd(value_list_expr, ConfigWindow::Y)) {
+ auto& y = *value_list.y;
+
+ // y
+ buf.Write(&y);
+ }
+ if (CaseAnd(value_list_expr, ConfigWindow::Width)) {
+ auto& width = *value_list.width;
+
+ // width
+ buf.Write(&width);
+ }
+ if (CaseAnd(value_list_expr, ConfigWindow::Height)) {
+ auto& height = *value_list.height;
+
+ // height
+ buf.Write(&height);
+ }
+ if (CaseAnd(value_list_expr, ConfigWindow::BorderWidth)) {
+ auto& border_width = *value_list.border_width;
+
+ // border_width
+ buf.Write(&border_width);
+ }
+ if (CaseAnd(value_list_expr, ConfigWindow::Sibling)) {
+ auto& sibling = *value_list.sibling;
+
+ // sibling
+ buf.Write(&sibling);
+ }
+ if (CaseAnd(value_list_expr, ConfigWindow::StackMode)) {
+ auto& stack_mode = *value_list.stack_mode;
+
+ // stack_mode
+ uint32_t tmp49;
+ tmp49 = static_cast<uint32_t>(stack_mode);
+ buf.Write(&tmp49);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ConfigureWindow", false);
+}
+
+Future<void> XProto::ConfigureWindow(
+ const Window& window,
+ const base::Optional<int32_t>& x,
+ const base::Optional<int32_t>& y,
+ const base::Optional<uint32_t>& width,
+ const base::Optional<uint32_t>& height,
+ const base::Optional<uint32_t>& border_width,
+ const base::Optional<Window>& sibling,
+ const base::Optional<StackMode>& stack_mode) {
+ return XProto::ConfigureWindow(ConfigureWindowRequest{
+ window, x, y, width, height, border_width, sibling, stack_mode});
+}
+
+Future<void> XProto::CirculateWindow(const CirculateWindowRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& direction = request.direction;
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 13;
+ buf.Write(&major_opcode);
+
+ // direction
+ uint8_t tmp50;
+ tmp50 = static_cast<uint8_t>(direction);
+ buf.Write(&tmp50);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CirculateWindow", false);
+}
+
+Future<void> XProto::CirculateWindow(const Circulate& direction,
+ const Window& window) {
+ return XProto::CirculateWindow(CirculateWindowRequest{direction, window});
+}
+
+Future<GetGeometryReply> XProto::GetGeometry(
+ const GetGeometryRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = 14;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetGeometryReply>(&buf, "GetGeometry", false);
+}
+
+Future<GetGeometryReply> XProto::GetGeometry(const Drawable& drawable) {
+ return XProto::GetGeometry(GetGeometryRequest{drawable});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetGeometryReply> detail::ReadReply<GetGeometryReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetGeometryReply>();
+
+ auto& depth = (*reply).depth;
+ auto& sequence = (*reply).sequence;
+ auto& root = (*reply).root;
+ auto& x = (*reply).x;
+ auto& y = (*reply).y;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& border_width = (*reply).border_width;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // depth
+ Read(&depth, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // border_width
+ Read(&border_width, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<QueryTreeReply> XProto::QueryTree(const QueryTreeRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 15;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<QueryTreeReply>(&buf, "QueryTree", false);
+}
+
+Future<QueryTreeReply> XProto::QueryTree(const Window& window) {
+ return XProto::QueryTree(QueryTreeRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<QueryTreeReply> detail::ReadReply<QueryTreeReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<QueryTreeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& root = (*reply).root;
+ auto& parent = (*reply).parent;
+ uint16_t children_len{};
+ auto& children = (*reply).children;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // parent
+ Read(&parent, &buf);
+
+ // children_len
+ Read(&children_len, &buf);
+
+ // pad1
+ Pad(&buf, 14);
+
+ // children
+ children.resize(children_len);
+ for (auto& children_elem : children) {
+ // children_elem
+ Read(&children_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<InternAtomReply> XProto::InternAtom(const InternAtomRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& only_if_exists = request.only_if_exists;
+ uint16_t name_len{};
+ auto& name = request.name;
+
+ // major_opcode
+ uint8_t major_opcode = 16;
+ buf.Write(&major_opcode);
+
+ // only_if_exists
+ buf.Write(&only_if_exists);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // name_len
+ name_len = name.size();
+ buf.Write(&name_len);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(name_len), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<InternAtomReply>(&buf, "InternAtom", false);
+}
+
+Future<InternAtomReply> XProto::InternAtom(const uint8_t& only_if_exists,
+ const std::string& name) {
+ return XProto::InternAtom(InternAtomRequest{only_if_exists, name});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<InternAtomReply> detail::ReadReply<InternAtomReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<InternAtomReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& atom = (*reply).atom;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // atom
+ Read(&atom, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<GetAtomNameReply> XProto::GetAtomName(
+ const GetAtomNameRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& atom = request.atom;
+
+ // major_opcode
+ uint8_t major_opcode = 17;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // atom
+ buf.Write(&atom);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetAtomNameReply>(&buf, "GetAtomName", false);
+}
+
+Future<GetAtomNameReply> XProto::GetAtomName(const Atom& atom) {
+ return XProto::GetAtomName(GetAtomNameRequest{atom});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetAtomNameReply> detail::ReadReply<GetAtomNameReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetAtomNameReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t name_len{};
+ auto& name = (*reply).name;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // name
+ name.resize(name_len);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::ChangeProperty(const ChangePropertyRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& mode = request.mode;
+ auto& window = request.window;
+ auto& property = request.property;
+ auto& type = request.type;
+ auto& format = request.format;
+ auto& data_len = request.data_len;
+ auto& data = request.data;
+
+ // major_opcode
+ uint8_t major_opcode = 18;
+ buf.Write(&major_opcode);
+
+ // mode
+ uint8_t tmp51;
+ tmp51 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp51);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // property
+ buf.Write(&property);
+
+ // type
+ buf.Write(&type);
+
+ // format
+ buf.Write(&format);
+
+ // pad0
+ Pad(&buf, 3);
+
+ // data_len
+ buf.Write(&data_len);
+
+ // data
+ buf.AppendBuffer(data, ((data_len) * (format)) / (8));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ChangeProperty", false);
+}
+
+Future<void> XProto::ChangeProperty(
+ const PropMode& mode,
+ const Window& window,
+ const Atom& property,
+ const Atom& type,
+ const uint8_t& format,
+ const uint32_t& data_len,
+ const scoped_refptr<base::RefCountedMemory>& data) {
+ return XProto::ChangeProperty(ChangePropertyRequest{
+ mode, window, property, type, format, data_len, data});
+}
+
+Future<void> XProto::DeleteProperty(const DeletePropertyRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& property = request.property;
+
+ // major_opcode
+ uint8_t major_opcode = 19;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // property
+ buf.Write(&property);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "DeleteProperty", false);
+}
+
+Future<void> XProto::DeleteProperty(const Window& window,
+ const Atom& property) {
+ return XProto::DeleteProperty(DeletePropertyRequest{window, property});
+}
+
+Future<GetPropertyReply> XProto::GetProperty(
+ const GetPropertyRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& c_delete = request.c_delete;
+ auto& window = request.window;
+ auto& property = request.property;
+ auto& type = request.type;
+ auto& long_offset = request.long_offset;
+ auto& long_length = request.long_length;
+
+ // major_opcode
+ uint8_t major_opcode = 20;
+ buf.Write(&major_opcode);
+
+ // c_delete
+ buf.Write(&c_delete);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // property
+ buf.Write(&property);
+
+ // type
+ buf.Write(&type);
+
+ // long_offset
+ buf.Write(&long_offset);
+
+ // long_length
+ buf.Write(&long_length);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetPropertyReply>(&buf, "GetProperty", false);
+}
+
+Future<GetPropertyReply> XProto::GetProperty(const uint8_t& c_delete,
+ const Window& window,
+ const Atom& property,
+ const Atom& type,
+ const uint32_t& long_offset,
+ const uint32_t& long_length) {
+ return XProto::GetProperty(GetPropertyRequest{
+ c_delete, window, property, type, long_offset, long_length});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetPropertyReply> detail::ReadReply<GetPropertyReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetPropertyReply>();
+
+ auto& format = (*reply).format;
+ auto& sequence = (*reply).sequence;
+ auto& type = (*reply).type;
+ auto& bytes_after = (*reply).bytes_after;
+ auto& value_len = (*reply).value_len;
+ auto& value = (*reply).value;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // format
+ Read(&format, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // type
+ Read(&type, &buf);
+
+ // bytes_after
+ Read(&bytes_after, &buf);
+
+ // value_len
+ Read(&value_len, &buf);
+
+ // pad0
+ Pad(&buf, 12);
+
+ // value
+ value = buffer->ReadAndAdvance((value_len) * ((format) / (8)));
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<ListPropertiesReply> XProto::ListProperties(
+ const ListPropertiesRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 21;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<ListPropertiesReply>(&buf, "ListProperties",
+ false);
+}
+
+Future<ListPropertiesReply> XProto::ListProperties(const Window& window) {
+ return XProto::ListProperties(ListPropertiesRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<ListPropertiesReply> detail::ReadReply<ListPropertiesReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<ListPropertiesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t atoms_len{};
+ auto& atoms = (*reply).atoms;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // atoms_len
+ Read(&atoms_len, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // atoms
+ atoms.resize(atoms_len);
+ for (auto& atoms_elem : atoms) {
+ // atoms_elem
+ Read(&atoms_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::SetSelectionOwner(
+ const SetSelectionOwnerRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& owner = request.owner;
+ auto& selection = request.selection;
+ auto& time = request.time;
+
+ // major_opcode
+ uint8_t major_opcode = 22;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // owner
+ buf.Write(&owner);
+
+ // selection
+ buf.Write(&selection);
+
+ // time
+ buf.Write(&time);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SetSelectionOwner", false);
+}
+
+Future<void> XProto::SetSelectionOwner(const Window& owner,
+ const Atom& selection,
+ const Time& time) {
+ return XProto::SetSelectionOwner(
+ SetSelectionOwnerRequest{owner, selection, time});
+}
+
+Future<GetSelectionOwnerReply> XProto::GetSelectionOwner(
+ const GetSelectionOwnerRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& selection = request.selection;
+
+ // major_opcode
+ uint8_t major_opcode = 23;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // selection
+ buf.Write(&selection);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetSelectionOwnerReply>(
+ &buf, "GetSelectionOwner", false);
+}
+
+Future<GetSelectionOwnerReply> XProto::GetSelectionOwner(
+ const Atom& selection) {
+ return XProto::GetSelectionOwner(GetSelectionOwnerRequest{selection});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetSelectionOwnerReply> detail::ReadReply<
+ GetSelectionOwnerReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetSelectionOwnerReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& owner = (*reply).owner;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // owner
+ Read(&owner, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::ConvertSelection(const ConvertSelectionRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& requestor = request.requestor;
+ auto& selection = request.selection;
+ auto& target = request.target;
+ auto& property = request.property;
+ auto& time = request.time;
+
+ // major_opcode
+ uint8_t major_opcode = 24;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // requestor
+ buf.Write(&requestor);
+
+ // selection
+ buf.Write(&selection);
+
+ // target
+ buf.Write(&target);
+
+ // property
+ buf.Write(&property);
+
+ // time
+ buf.Write(&time);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ConvertSelection", false);
+}
+
+Future<void> XProto::ConvertSelection(const Window& requestor,
+ const Atom& selection,
+ const Atom& target,
+ const Atom& property,
+ const Time& time) {
+ return XProto::ConvertSelection(
+ ConvertSelectionRequest{requestor, selection, target, property, time});
+}
+
+Future<void> XProto::SendEvent(const SendEventRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& propagate = request.propagate;
+ auto& destination = request.destination;
+ auto& event_mask = request.event_mask;
+ auto& event = request.event;
+ size_t event_len = event.size();
+
+ // major_opcode
+ uint8_t major_opcode = 25;
+ buf.Write(&major_opcode);
+
+ // propagate
+ buf.Write(&propagate);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // destination
+ buf.Write(&destination);
+
+ // event_mask
+ uint32_t tmp52;
+ tmp52 = static_cast<uint32_t>(event_mask);
+ buf.Write(&tmp52);
+
+ // event
+ for (auto& event_elem : event) {
+ // event_elem
+ buf.Write(&event_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SendEvent", false);
+}
+
+Future<void> XProto::SendEvent(const uint8_t& propagate,
+ const Window& destination,
+ const EventMask& event_mask,
+ const std::array<char, 32>& event) {
+ return XProto::SendEvent(
+ SendEventRequest{propagate, destination, event_mask, event});
+}
+
+Future<GrabPointerReply> XProto::GrabPointer(
+ const GrabPointerRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& owner_events = request.owner_events;
+ auto& grab_window = request.grab_window;
+ auto& event_mask = request.event_mask;
+ auto& pointer_mode = request.pointer_mode;
+ auto& keyboard_mode = request.keyboard_mode;
+ auto& confine_to = request.confine_to;
+ auto& cursor = request.cursor;
+ auto& time = request.time;
+
+ // major_opcode
+ uint8_t major_opcode = 26;
+ buf.Write(&major_opcode);
+
+ // owner_events
+ buf.Write(&owner_events);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // event_mask
+ uint16_t tmp53;
+ tmp53 = static_cast<uint16_t>(event_mask);
+ buf.Write(&tmp53);
+
+ // pointer_mode
+ uint8_t tmp54;
+ tmp54 = static_cast<uint8_t>(pointer_mode);
+ buf.Write(&tmp54);
+
+ // keyboard_mode
+ uint8_t tmp55;
+ tmp55 = static_cast<uint8_t>(keyboard_mode);
+ buf.Write(&tmp55);
+
+ // confine_to
+ buf.Write(&confine_to);
+
+ // cursor
+ buf.Write(&cursor);
+
+ // time
+ buf.Write(&time);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GrabPointerReply>(&buf, "GrabPointer", false);
+}
+
+Future<GrabPointerReply> XProto::GrabPointer(const uint8_t& owner_events,
+ const Window& grab_window,
+ const EventMask& event_mask,
+ const GrabMode& pointer_mode,
+ const GrabMode& keyboard_mode,
+ const Window& confine_to,
+ const Cursor& cursor,
+ const Time& time) {
+ return XProto::GrabPointer(
+ GrabPointerRequest{owner_events, grab_window, event_mask, pointer_mode,
+ keyboard_mode, confine_to, cursor, time});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GrabPointerReply> detail::ReadReply<GrabPointerReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GrabPointerReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ uint8_t tmp56;
+ Read(&tmp56, &buf);
+ status = static_cast<GrabStatus>(tmp56);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::UngrabPointer(const UngrabPointerRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& time = request.time;
+
+ // major_opcode
+ uint8_t major_opcode = 27;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // time
+ buf.Write(&time);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "UngrabPointer", false);
+}
+
+Future<void> XProto::UngrabPointer(const Time& time) {
+ return XProto::UngrabPointer(UngrabPointerRequest{time});
+}
+
+Future<void> XProto::GrabButton(const GrabButtonRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& owner_events = request.owner_events;
+ auto& grab_window = request.grab_window;
+ auto& event_mask = request.event_mask;
+ auto& pointer_mode = request.pointer_mode;
+ auto& keyboard_mode = request.keyboard_mode;
+ auto& confine_to = request.confine_to;
+ auto& cursor = request.cursor;
+ auto& button = request.button;
+ auto& modifiers = request.modifiers;
+
+ // major_opcode
+ uint8_t major_opcode = 28;
+ buf.Write(&major_opcode);
+
+ // owner_events
+ buf.Write(&owner_events);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // event_mask
+ uint16_t tmp57;
+ tmp57 = static_cast<uint16_t>(event_mask);
+ buf.Write(&tmp57);
+
+ // pointer_mode
+ uint8_t tmp58;
+ tmp58 = static_cast<uint8_t>(pointer_mode);
+ buf.Write(&tmp58);
+
+ // keyboard_mode
+ uint8_t tmp59;
+ tmp59 = static_cast<uint8_t>(keyboard_mode);
+ buf.Write(&tmp59);
+
+ // confine_to
+ buf.Write(&confine_to);
+
+ // cursor
+ buf.Write(&cursor);
+
+ // button
+ uint8_t tmp60;
+ tmp60 = static_cast<uint8_t>(button);
+ buf.Write(&tmp60);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // modifiers
+ uint16_t tmp61;
+ tmp61 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp61);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "GrabButton", false);
+}
+
+Future<void> XProto::GrabButton(const uint8_t& owner_events,
+ const Window& grab_window,
+ const EventMask& event_mask,
+ const GrabMode& pointer_mode,
+ const GrabMode& keyboard_mode,
+ const Window& confine_to,
+ const Cursor& cursor,
+ const ButtonIndex& button,
+ const ModMask& modifiers) {
+ return XProto::GrabButton(
+ GrabButtonRequest{owner_events, grab_window, event_mask, pointer_mode,
+ keyboard_mode, confine_to, cursor, button, modifiers});
+}
+
+Future<void> XProto::UngrabButton(const UngrabButtonRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& button = request.button;
+ auto& grab_window = request.grab_window;
+ auto& modifiers = request.modifiers;
+
+ // major_opcode
+ uint8_t major_opcode = 29;
+ buf.Write(&major_opcode);
+
+ // button
+ uint8_t tmp62;
+ tmp62 = static_cast<uint8_t>(button);
+ buf.Write(&tmp62);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // modifiers
+ uint16_t tmp63;
+ tmp63 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp63);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "UngrabButton", false);
+}
+
+Future<void> XProto::UngrabButton(const ButtonIndex& button,
+ const Window& grab_window,
+ const ModMask& modifiers) {
+ return XProto::UngrabButton(
+ UngrabButtonRequest{button, grab_window, modifiers});
+}
+
+Future<void> XProto::ChangeActivePointerGrab(
+ const ChangeActivePointerGrabRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cursor = request.cursor;
+ auto& time = request.time;
+ auto& event_mask = request.event_mask;
+
+ // major_opcode
+ uint8_t major_opcode = 30;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cursor
+ buf.Write(&cursor);
+
+ // time
+ buf.Write(&time);
+
+ // event_mask
+ uint16_t tmp64;
+ tmp64 = static_cast<uint16_t>(event_mask);
+ buf.Write(&tmp64);
+
+ // pad1
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ChangeActivePointerGrab", false);
+}
+
+Future<void> XProto::ChangeActivePointerGrab(const Cursor& cursor,
+ const Time& time,
+ const EventMask& event_mask) {
+ return XProto::ChangeActivePointerGrab(
+ ChangeActivePointerGrabRequest{cursor, time, event_mask});
+}
+
+Future<GrabKeyboardReply> XProto::GrabKeyboard(
+ const GrabKeyboardRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& owner_events = request.owner_events;
+ auto& grab_window = request.grab_window;
+ auto& time = request.time;
+ auto& pointer_mode = request.pointer_mode;
+ auto& keyboard_mode = request.keyboard_mode;
+
+ // major_opcode
+ uint8_t major_opcode = 31;
+ buf.Write(&major_opcode);
+
+ // owner_events
+ buf.Write(&owner_events);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // time
+ buf.Write(&time);
+
+ // pointer_mode
+ uint8_t tmp65;
+ tmp65 = static_cast<uint8_t>(pointer_mode);
+ buf.Write(&tmp65);
+
+ // keyboard_mode
+ uint8_t tmp66;
+ tmp66 = static_cast<uint8_t>(keyboard_mode);
+ buf.Write(&tmp66);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GrabKeyboardReply>(&buf, "GrabKeyboard",
+ false);
+}
+
+Future<GrabKeyboardReply> XProto::GrabKeyboard(const uint8_t& owner_events,
+ const Window& grab_window,
+ const Time& time,
+ const GrabMode& pointer_mode,
+ const GrabMode& keyboard_mode) {
+ return XProto::GrabKeyboard(GrabKeyboardRequest{
+ owner_events, grab_window, time, pointer_mode, keyboard_mode});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GrabKeyboardReply> detail::ReadReply<GrabKeyboardReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GrabKeyboardReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ uint8_t tmp67;
+ Read(&tmp67, &buf);
+ status = static_cast<GrabStatus>(tmp67);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::UngrabKeyboard(const UngrabKeyboardRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& time = request.time;
+
+ // major_opcode
+ uint8_t major_opcode = 32;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // time
+ buf.Write(&time);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "UngrabKeyboard", false);
+}
+
+Future<void> XProto::UngrabKeyboard(const Time& time) {
+ return XProto::UngrabKeyboard(UngrabKeyboardRequest{time});
+}
+
+Future<void> XProto::GrabKey(const GrabKeyRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& owner_events = request.owner_events;
+ auto& grab_window = request.grab_window;
+ auto& modifiers = request.modifiers;
+ auto& key = request.key;
+ auto& pointer_mode = request.pointer_mode;
+ auto& keyboard_mode = request.keyboard_mode;
+
+ // major_opcode
+ uint8_t major_opcode = 33;
+ buf.Write(&major_opcode);
+
+ // owner_events
+ buf.Write(&owner_events);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // modifiers
+ uint16_t tmp68;
+ tmp68 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp68);
+
+ // key
+ buf.Write(&key);
+
+ // pointer_mode
+ uint8_t tmp69;
+ tmp69 = static_cast<uint8_t>(pointer_mode);
+ buf.Write(&tmp69);
+
+ // keyboard_mode
+ uint8_t tmp70;
+ tmp70 = static_cast<uint8_t>(keyboard_mode);
+ buf.Write(&tmp70);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "GrabKey", false);
+}
+
+Future<void> XProto::GrabKey(const uint8_t& owner_events,
+ const Window& grab_window,
+ const ModMask& modifiers,
+ const KeyCode& key,
+ const GrabMode& pointer_mode,
+ const GrabMode& keyboard_mode) {
+ return XProto::GrabKey(GrabKeyRequest{owner_events, grab_window, modifiers,
+ key, pointer_mode, keyboard_mode});
+}
+
+Future<void> XProto::UngrabKey(const UngrabKeyRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& key = request.key;
+ auto& grab_window = request.grab_window;
+ auto& modifiers = request.modifiers;
+
+ // major_opcode
+ uint8_t major_opcode = 34;
+ buf.Write(&major_opcode);
+
+ // key
+ buf.Write(&key);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // grab_window
+ buf.Write(&grab_window);
+
+ // modifiers
+ uint16_t tmp71;
+ tmp71 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp71);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "UngrabKey", false);
+}
+
+Future<void> XProto::UngrabKey(const KeyCode& key,
+ const Window& grab_window,
+ const ModMask& modifiers) {
+ return XProto::UngrabKey(UngrabKeyRequest{key, grab_window, modifiers});
+}
+
+Future<void> XProto::AllowEvents(const AllowEventsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& mode = request.mode;
+ auto& time = request.time;
+
+ // major_opcode
+ uint8_t major_opcode = 35;
+ buf.Write(&major_opcode);
+
+ // mode
+ uint8_t tmp72;
+ tmp72 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp72);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // time
+ buf.Write(&time);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "AllowEvents", false);
+}
+
+Future<void> XProto::AllowEvents(const Allow& mode, const Time& time) {
+ return XProto::AllowEvents(AllowEventsRequest{mode, time});
+}
+
+Future<void> XProto::GrabServer(const GrabServerRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 36;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "GrabServer", false);
+}
+
+Future<void> XProto::GrabServer() {
+ return XProto::GrabServer(GrabServerRequest{});
+}
+
+Future<void> XProto::UngrabServer(const UngrabServerRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 37;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "UngrabServer", false);
+}
+
+Future<void> XProto::UngrabServer() {
+ return XProto::UngrabServer(UngrabServerRequest{});
+}
+
+Future<QueryPointerReply> XProto::QueryPointer(
+ const QueryPointerRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 38;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<QueryPointerReply>(&buf, "QueryPointer",
+ false);
+}
+
+Future<QueryPointerReply> XProto::QueryPointer(const Window& window) {
+ return XProto::QueryPointer(QueryPointerRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<QueryPointerReply> detail::ReadReply<QueryPointerReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<QueryPointerReply>();
+
+ auto& same_screen = (*reply).same_screen;
+ auto& sequence = (*reply).sequence;
+ auto& root = (*reply).root;
+ auto& child = (*reply).child;
+ auto& root_x = (*reply).root_x;
+ auto& root_y = (*reply).root_y;
+ auto& win_x = (*reply).win_x;
+ auto& win_y = (*reply).win_y;
+ auto& mask = (*reply).mask;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // same_screen
+ Read(&same_screen, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // win_x
+ Read(&win_x, &buf);
+
+ // win_y
+ Read(&win_y, &buf);
+
+ // mask
+ uint16_t tmp73;
+ Read(&tmp73, &buf);
+ mask = static_cast<KeyButMask>(tmp73);
+
+ // pad0
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<GetMotionEventsReply> XProto::GetMotionEvents(
+ const GetMotionEventsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& start = request.start;
+ auto& stop = request.stop;
+
+ // major_opcode
+ uint8_t major_opcode = 39;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // start
+ buf.Write(&start);
+
+ // stop
+ buf.Write(&stop);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetMotionEventsReply>(&buf, "GetMotionEvents",
+ false);
+}
+
+Future<GetMotionEventsReply> XProto::GetMotionEvents(const Window& window,
+ const Time& start,
+ const Time& stop) {
+ return XProto::GetMotionEvents(GetMotionEventsRequest{window, start, stop});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetMotionEventsReply> detail::ReadReply<GetMotionEventsReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetMotionEventsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t events_len{};
+ auto& events = (*reply).events;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // events_len
+ Read(&events_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // events
+ events.resize(events_len);
+ for (auto& events_elem : events) {
+ // events_elem
+ {
+ auto& time = events_elem.time;
+ auto& x = events_elem.x;
+ auto& y = events_elem.y;
+
+ // time
+ Read(&time, &buf);
+
+ // x
+ Read(&x, &buf);
+
+ // y
+ Read(&y, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<TranslateCoordinatesReply> XProto::TranslateCoordinates(
+ const TranslateCoordinatesRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& src_window = request.src_window;
+ auto& dst_window = request.dst_window;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+
+ // major_opcode
+ uint8_t major_opcode = 40;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // src_window
+ buf.Write(&src_window);
+
+ // dst_window
+ buf.Write(&dst_window);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<TranslateCoordinatesReply>(
+ &buf, "TranslateCoordinates", false);
+}
+
+Future<TranslateCoordinatesReply> XProto::TranslateCoordinates(
+ const Window& src_window,
+ const Window& dst_window,
+ const int16_t& src_x,
+ const int16_t& src_y) {
+ return XProto::TranslateCoordinates(
+ TranslateCoordinatesRequest{src_window, dst_window, src_x, src_y});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<TranslateCoordinatesReply> detail::ReadReply<
+ TranslateCoordinatesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<TranslateCoordinatesReply>();
+
+ auto& same_screen = (*reply).same_screen;
+ auto& sequence = (*reply).sequence;
+ auto& child = (*reply).child;
+ auto& dst_x = (*reply).dst_x;
+ auto& dst_y = (*reply).dst_y;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // same_screen
+ Read(&same_screen, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // dst_x
+ Read(&dst_x, &buf);
+
+ // dst_y
+ Read(&dst_y, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::WarpPointer(const WarpPointerRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& src_window = request.src_window;
+ auto& dst_window = request.dst_window;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& src_width = request.src_width;
+ auto& src_height = request.src_height;
+ auto& dst_x = request.dst_x;
+ auto& dst_y = request.dst_y;
+
+ // major_opcode
+ uint8_t major_opcode = 41;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // src_window
+ buf.Write(&src_window);
+
+ // dst_window
+ buf.Write(&dst_window);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // src_width
+ buf.Write(&src_width);
+
+ // src_height
+ buf.Write(&src_height);
+
+ // dst_x
+ buf.Write(&dst_x);
+
+ // dst_y
+ buf.Write(&dst_y);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "WarpPointer", false);
+}
+
+Future<void> XProto::WarpPointer(const Window& src_window,
+ const Window& dst_window,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const uint16_t& src_width,
+ const uint16_t& src_height,
+ const int16_t& dst_x,
+ const int16_t& dst_y) {
+ return XProto::WarpPointer(WarpPointerRequest{src_window, dst_window, src_x,
+ src_y, src_width, src_height,
+ dst_x, dst_y});
+}
+
+Future<void> XProto::SetInputFocus(const SetInputFocusRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& revert_to = request.revert_to;
+ auto& focus = request.focus;
+ auto& time = request.time;
+
+ // major_opcode
+ uint8_t major_opcode = 42;
+ buf.Write(&major_opcode);
+
+ // revert_to
+ uint8_t tmp74;
+ tmp74 = static_cast<uint8_t>(revert_to);
+ buf.Write(&tmp74);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // focus
+ buf.Write(&focus);
+
+ // time
+ buf.Write(&time);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SetInputFocus", false);
+}
+
+Future<void> XProto::SetInputFocus(const InputFocus& revert_to,
+ const Window& focus,
+ const Time& time) {
+ return XProto::SetInputFocus(SetInputFocusRequest{revert_to, focus, time});
+}
+
+Future<GetInputFocusReply> XProto::GetInputFocus(
+ const GetInputFocusRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 43;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetInputFocusReply>(&buf, "GetInputFocus",
+ false);
+}
+
+Future<GetInputFocusReply> XProto::GetInputFocus() {
+ return XProto::GetInputFocus(GetInputFocusRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetInputFocusReply> detail::ReadReply<GetInputFocusReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetInputFocusReply>();
+
+ auto& revert_to = (*reply).revert_to;
+ auto& sequence = (*reply).sequence;
+ auto& focus = (*reply).focus;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // revert_to
+ uint8_t tmp75;
+ Read(&tmp75, &buf);
+ revert_to = static_cast<InputFocus>(tmp75);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // focus
+ Read(&focus, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<QueryKeymapReply> XProto::QueryKeymap(
+ const QueryKeymapRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 44;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<QueryKeymapReply>(&buf, "QueryKeymap", false);
+}
+
+Future<QueryKeymapReply> XProto::QueryKeymap() {
+ return XProto::QueryKeymap(QueryKeymapRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<QueryKeymapReply> detail::ReadReply<QueryKeymapReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<QueryKeymapReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& keys = (*reply).keys;
+ size_t keys_len = keys.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // keys
+ for (auto& keys_elem : keys) {
+ // keys_elem
+ Read(&keys_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::OpenFont(const OpenFontRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& fid = request.fid;
+ uint16_t name_len{};
+ auto& name = request.name;
+
+ // major_opcode
+ uint8_t major_opcode = 45;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // fid
+ buf.Write(&fid);
+
+ // name_len
+ name_len = name.size();
+ buf.Write(&name_len);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(name_len), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "OpenFont", false);
+}
+
+Future<void> XProto::OpenFont(const Font& fid, const std::string& name) {
+ return XProto::OpenFont(OpenFontRequest{fid, name});
+}
+
+Future<void> XProto::CloseFont(const CloseFontRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& font = request.font;
+
+ // major_opcode
+ uint8_t major_opcode = 46;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // font
+ buf.Write(&font);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CloseFont", false);
+}
+
+Future<void> XProto::CloseFont(const Font& font) {
+ return XProto::CloseFont(CloseFontRequest{font});
+}
+
+Future<QueryFontReply> XProto::QueryFont(const QueryFontRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& font = request.font;
+
+ // major_opcode
+ uint8_t major_opcode = 47;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // font
+ buf.Write(&font);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<QueryFontReply>(&buf, "QueryFont", false);
+}
+
+Future<QueryFontReply> XProto::QueryFont(const Fontable& font) {
+ return XProto::QueryFont(QueryFontRequest{font});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<QueryFontReply> detail::ReadReply<QueryFontReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<QueryFontReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& min_bounds = (*reply).min_bounds;
+ auto& max_bounds = (*reply).max_bounds;
+ auto& min_char_or_byte2 = (*reply).min_char_or_byte2;
+ auto& max_char_or_byte2 = (*reply).max_char_or_byte2;
+ auto& default_char = (*reply).default_char;
+ uint16_t properties_len{};
+ auto& draw_direction = (*reply).draw_direction;
+ auto& min_byte1 = (*reply).min_byte1;
+ auto& max_byte1 = (*reply).max_byte1;
+ auto& all_chars_exist = (*reply).all_chars_exist;
+ auto& font_ascent = (*reply).font_ascent;
+ auto& font_descent = (*reply).font_descent;
+ uint32_t char_infos_len{};
+ auto& properties = (*reply).properties;
+ auto& char_infos = (*reply).char_infos;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // min_bounds
+ {
+ auto& left_side_bearing = min_bounds.left_side_bearing;
+ auto& right_side_bearing = min_bounds.right_side_bearing;
+ auto& character_width = min_bounds.character_width;
+ auto& ascent = min_bounds.ascent;
+ auto& descent = min_bounds.descent;
+ auto& attributes = min_bounds.attributes;
+
+ // left_side_bearing
+ Read(&left_side_bearing, &buf);
+
+ // right_side_bearing
+ Read(&right_side_bearing, &buf);
+
+ // character_width
+ Read(&character_width, &buf);
+
+ // ascent
+ Read(&ascent, &buf);
+
+ // descent
+ Read(&descent, &buf);
+
+ // attributes
+ Read(&attributes, &buf);
+ }
+
+ // pad1
+ Pad(&buf, 4);
+
+ // max_bounds
+ {
+ auto& left_side_bearing = max_bounds.left_side_bearing;
+ auto& right_side_bearing = max_bounds.right_side_bearing;
+ auto& character_width = max_bounds.character_width;
+ auto& ascent = max_bounds.ascent;
+ auto& descent = max_bounds.descent;
+ auto& attributes = max_bounds.attributes;
+
+ // left_side_bearing
+ Read(&left_side_bearing, &buf);
+
+ // right_side_bearing
+ Read(&right_side_bearing, &buf);
+
+ // character_width
+ Read(&character_width, &buf);
+
+ // ascent
+ Read(&ascent, &buf);
+
+ // descent
+ Read(&descent, &buf);
+
+ // attributes
+ Read(&attributes, &buf);
+ }
+
+ // pad2
+ Pad(&buf, 4);
+
+ // min_char_or_byte2
+ Read(&min_char_or_byte2, &buf);
+
+ // max_char_or_byte2
+ Read(&max_char_or_byte2, &buf);
+
+ // default_char
+ Read(&default_char, &buf);
+
+ // properties_len
+ Read(&properties_len, &buf);
+
+ // draw_direction
+ uint8_t tmp76;
+ Read(&tmp76, &buf);
+ draw_direction = static_cast<FontDraw>(tmp76);
+
+ // min_byte1
+ Read(&min_byte1, &buf);
+
+ // max_byte1
+ Read(&max_byte1, &buf);
+
+ // all_chars_exist
+ Read(&all_chars_exist, &buf);
+
+ // font_ascent
+ Read(&font_ascent, &buf);
+
+ // font_descent
+ Read(&font_descent, &buf);
+
+ // char_infos_len
+ Read(&char_infos_len, &buf);
+
+ // properties
+ properties.resize(properties_len);
+ for (auto& properties_elem : properties) {
+ // properties_elem
+ {
+ auto& name = properties_elem.name;
+ auto& value = properties_elem.value;
+
+ // name
+ Read(&name, &buf);
+
+ // value
+ Read(&value, &buf);
+ }
+ }
+
+ // char_infos
+ char_infos.resize(char_infos_len);
+ for (auto& char_infos_elem : char_infos) {
+ // char_infos_elem
+ {
+ auto& left_side_bearing = char_infos_elem.left_side_bearing;
+ auto& right_side_bearing = char_infos_elem.right_side_bearing;
+ auto& character_width = char_infos_elem.character_width;
+ auto& ascent = char_infos_elem.ascent;
+ auto& descent = char_infos_elem.descent;
+ auto& attributes = char_infos_elem.attributes;
+
+ // left_side_bearing
+ Read(&left_side_bearing, &buf);
+
+ // right_side_bearing
+ Read(&right_side_bearing, &buf);
+
+ // character_width
+ Read(&character_width, &buf);
+
+ // ascent
+ Read(&ascent, &buf);
+
+ // descent
+ Read(&descent, &buf);
+
+ // attributes
+ Read(&attributes, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<QueryTextExtentsReply> XProto::QueryTextExtents(
+ const QueryTextExtentsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& font = request.font;
+ auto& string = request.string;
+ size_t string_len = string.size();
+
+ // major_opcode
+ uint8_t major_opcode = 48;
+ buf.Write(&major_opcode);
+
+ // odd_length
+ uint8_t odd_length = BitAnd(string_len, 1);
+ buf.Write(&odd_length);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // font
+ buf.Write(&font);
+
+ // string
+ DCHECK_EQ(static_cast<size_t>(string_len), string.size());
+ for (auto& string_elem : string) {
+ // string_elem
+ {
+ auto& byte1 = string_elem.byte1;
+ auto& byte2 = string_elem.byte2;
+
+ // byte1
+ buf.Write(&byte1);
+
+ // byte2
+ buf.Write(&byte2);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<QueryTextExtentsReply>(
+ &buf, "QueryTextExtents", false);
+}
+
+Future<QueryTextExtentsReply> XProto::QueryTextExtents(
+ const Fontable& font,
+ const std::vector<Char16>& string) {
+ return XProto::QueryTextExtents(QueryTextExtentsRequest{font, string});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<QueryTextExtentsReply> detail::ReadReply<QueryTextExtentsReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<QueryTextExtentsReply>();
+
+ auto& draw_direction = (*reply).draw_direction;
+ auto& sequence = (*reply).sequence;
+ auto& font_ascent = (*reply).font_ascent;
+ auto& font_descent = (*reply).font_descent;
+ auto& overall_ascent = (*reply).overall_ascent;
+ auto& overall_descent = (*reply).overall_descent;
+ auto& overall_width = (*reply).overall_width;
+ auto& overall_left = (*reply).overall_left;
+ auto& overall_right = (*reply).overall_right;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // draw_direction
+ uint8_t tmp77;
+ Read(&tmp77, &buf);
+ draw_direction = static_cast<FontDraw>(tmp77);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // font_ascent
+ Read(&font_ascent, &buf);
+
+ // font_descent
+ Read(&font_descent, &buf);
+
+ // overall_ascent
+ Read(&overall_ascent, &buf);
+
+ // overall_descent
+ Read(&overall_descent, &buf);
+
+ // overall_width
+ Read(&overall_width, &buf);
+
+ // overall_left
+ Read(&overall_left, &buf);
+
+ // overall_right
+ Read(&overall_right, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<ListFontsReply> XProto::ListFonts(const ListFontsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& max_names = request.max_names;
+ uint16_t pattern_len{};
+ auto& pattern = request.pattern;
+
+ // major_opcode
+ uint8_t major_opcode = 49;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // max_names
+ buf.Write(&max_names);
+
+ // pattern_len
+ pattern_len = pattern.size();
+ buf.Write(&pattern_len);
+
+ // pattern
+ DCHECK_EQ(static_cast<size_t>(pattern_len), pattern.size());
+ for (auto& pattern_elem : pattern) {
+ // pattern_elem
+ buf.Write(&pattern_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<ListFontsReply>(&buf, "ListFonts", false);
+}
+
+Future<ListFontsReply> XProto::ListFonts(const uint16_t& max_names,
+ const std::string& pattern) {
+ return XProto::ListFonts(ListFontsRequest{max_names, pattern});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<ListFontsReply> detail::ReadReply<ListFontsReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<ListFontsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t names_len{};
+ auto& names = (*reply).names;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // names_len
+ Read(&names_len, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // names
+ names.resize(names_len);
+ for (auto& names_elem : names) {
+ // names_elem
+ {
+ uint8_t name_len{};
+ auto& name = names_elem.name;
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // name
+ name.resize(name_len);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<ListFontsWithInfoReply> XProto::ListFontsWithInfo(
+ const ListFontsWithInfoRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& max_names = request.max_names;
+ uint16_t pattern_len{};
+ auto& pattern = request.pattern;
+
+ // major_opcode
+ uint8_t major_opcode = 50;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // max_names
+ buf.Write(&max_names);
+
+ // pattern_len
+ pattern_len = pattern.size();
+ buf.Write(&pattern_len);
+
+ // pattern
+ DCHECK_EQ(static_cast<size_t>(pattern_len), pattern.size());
+ for (auto& pattern_elem : pattern) {
+ // pattern_elem
+ buf.Write(&pattern_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<ListFontsWithInfoReply>(
+ &buf, "ListFontsWithInfo", false);
+}
+
+Future<ListFontsWithInfoReply> XProto::ListFontsWithInfo(
+ const uint16_t& max_names,
+ const std::string& pattern) {
+ return XProto::ListFontsWithInfo(
+ ListFontsWithInfoRequest{max_names, pattern});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<ListFontsWithInfoReply> detail::ReadReply<
+ ListFontsWithInfoReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<ListFontsWithInfoReply>();
+
+ uint8_t name_len{};
+ auto& sequence = (*reply).sequence;
+ auto& min_bounds = (*reply).min_bounds;
+ auto& max_bounds = (*reply).max_bounds;
+ auto& min_char_or_byte2 = (*reply).min_char_or_byte2;
+ auto& max_char_or_byte2 = (*reply).max_char_or_byte2;
+ auto& default_char = (*reply).default_char;
+ uint16_t properties_len{};
+ auto& draw_direction = (*reply).draw_direction;
+ auto& min_byte1 = (*reply).min_byte1;
+ auto& max_byte1 = (*reply).max_byte1;
+ auto& all_chars_exist = (*reply).all_chars_exist;
+ auto& font_ascent = (*reply).font_ascent;
+ auto& font_descent = (*reply).font_descent;
+ auto& replies_hint = (*reply).replies_hint;
+ auto& properties = (*reply).properties;
+ auto& name = (*reply).name;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // min_bounds
+ {
+ auto& left_side_bearing = min_bounds.left_side_bearing;
+ auto& right_side_bearing = min_bounds.right_side_bearing;
+ auto& character_width = min_bounds.character_width;
+ auto& ascent = min_bounds.ascent;
+ auto& descent = min_bounds.descent;
+ auto& attributes = min_bounds.attributes;
+
+ // left_side_bearing
+ Read(&left_side_bearing, &buf);
+
+ // right_side_bearing
+ Read(&right_side_bearing, &buf);
+
+ // character_width
+ Read(&character_width, &buf);
+
+ // ascent
+ Read(&ascent, &buf);
+
+ // descent
+ Read(&descent, &buf);
+
+ // attributes
+ Read(&attributes, &buf);
+ }
+
+ // pad0
+ Pad(&buf, 4);
+
+ // max_bounds
+ {
+ auto& left_side_bearing = max_bounds.left_side_bearing;
+ auto& right_side_bearing = max_bounds.right_side_bearing;
+ auto& character_width = max_bounds.character_width;
+ auto& ascent = max_bounds.ascent;
+ auto& descent = max_bounds.descent;
+ auto& attributes = max_bounds.attributes;
+
+ // left_side_bearing
+ Read(&left_side_bearing, &buf);
+
+ // right_side_bearing
+ Read(&right_side_bearing, &buf);
+
+ // character_width
+ Read(&character_width, &buf);
+
+ // ascent
+ Read(&ascent, &buf);
+
+ // descent
+ Read(&descent, &buf);
+
+ // attributes
+ Read(&attributes, &buf);
+ }
+
+ // pad1
+ Pad(&buf, 4);
+
+ // min_char_or_byte2
+ Read(&min_char_or_byte2, &buf);
+
+ // max_char_or_byte2
+ Read(&max_char_or_byte2, &buf);
+
+ // default_char
+ Read(&default_char, &buf);
+
+ // properties_len
+ Read(&properties_len, &buf);
+
+ // draw_direction
+ uint8_t tmp78;
+ Read(&tmp78, &buf);
+ draw_direction = static_cast<FontDraw>(tmp78);
+
+ // min_byte1
+ Read(&min_byte1, &buf);
+
+ // max_byte1
+ Read(&max_byte1, &buf);
+
+ // all_chars_exist
+ Read(&all_chars_exist, &buf);
+
+ // font_ascent
+ Read(&font_ascent, &buf);
+
+ // font_descent
+ Read(&font_descent, &buf);
+
+ // replies_hint
+ Read(&replies_hint, &buf);
+
+ // properties
+ properties.resize(properties_len);
+ for (auto& properties_elem : properties) {
+ // properties_elem
+ {
+ auto& name = properties_elem.name;
+ auto& value = properties_elem.value;
+
+ // name
+ Read(&name, &buf);
+
+ // value
+ Read(&value, &buf);
+ }
+ }
+
+ // name
+ name.resize(name_len);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::SetFontPath(const SetFontPathRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ uint16_t font_qty{};
+ auto& font = request.font;
+ size_t font_len = font.size();
+
+ // major_opcode
+ uint8_t major_opcode = 51;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // font_qty
+ font_qty = font.size();
+ buf.Write(&font_qty);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // font
+ DCHECK_EQ(static_cast<size_t>(font_qty), font.size());
+ for (auto& font_elem : font) {
+ // font_elem
+ {
+ uint8_t name_len{};
+ auto& name = font_elem.name;
+
+ // name_len
+ name_len = name.size();
+ buf.Write(&name_len);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(name_len), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SetFontPath", false);
+}
+
+Future<void> XProto::SetFontPath(const std::vector<Str>& font) {
+ return XProto::SetFontPath(SetFontPathRequest{font});
+}
+
+Future<GetFontPathReply> XProto::GetFontPath(
+ const GetFontPathRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 52;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetFontPathReply>(&buf, "GetFontPath", false);
+}
+
+Future<GetFontPathReply> XProto::GetFontPath() {
+ return XProto::GetFontPath(GetFontPathRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetFontPathReply> detail::ReadReply<GetFontPathReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetFontPathReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t path_len{};
+ auto& path = (*reply).path;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // path_len
+ Read(&path_len, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // path
+ path.resize(path_len);
+ for (auto& path_elem : path) {
+ // path_elem
+ {
+ uint8_t name_len{};
+ auto& name = path_elem.name;
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // name
+ name.resize(name_len);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::CreatePixmap(const CreatePixmapRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& depth = request.depth;
+ auto& pid = request.pid;
+ auto& drawable = request.drawable;
+ auto& width = request.width;
+ auto& height = request.height;
+
+ // major_opcode
+ uint8_t major_opcode = 53;
+ buf.Write(&major_opcode);
+
+ // depth
+ buf.Write(&depth);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // pid
+ buf.Write(&pid);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CreatePixmap", false);
+}
+
+Future<void> XProto::CreatePixmap(const uint8_t& depth,
+ const Pixmap& pid,
+ const Drawable& drawable,
+ const uint16_t& width,
+ const uint16_t& height) {
+ return XProto::CreatePixmap(
+ CreatePixmapRequest{depth, pid, drawable, width, height});
+}
+
+Future<void> XProto::FreePixmap(const FreePixmapRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& pixmap = request.pixmap;
+
+ // major_opcode
+ uint8_t major_opcode = 54;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // pixmap
+ buf.Write(&pixmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "FreePixmap", false);
+}
+
+Future<void> XProto::FreePixmap(const Pixmap& pixmap) {
+ return XProto::FreePixmap(FreePixmapRequest{pixmap});
+}
+
+Future<void> XProto::CreateGC(const CreateGCRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cid = request.cid;
+ auto& drawable = request.drawable;
+ GraphicsContextAttribute value_mask{};
+ auto& value_list = request;
+
+ // major_opcode
+ uint8_t major_opcode = 55;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cid
+ buf.Write(&cid);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // value_mask
+ SwitchVar(GraphicsContextAttribute::Function, value_list.function.has_value(),
+ true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::PlaneMask,
+ value_list.plane_mask.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::Foreground,
+ value_list.foreground.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::Background,
+ value_list.background.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::LineWidth,
+ value_list.line_width.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::LineStyle,
+ value_list.line_style.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::CapStyle,
+ value_list.cap_style.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::JoinStyle,
+ value_list.join_style.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::FillStyle,
+ value_list.fill_style.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::FillRule,
+ value_list.fill_rule.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::Tile, value_list.tile.has_value(), true,
+ &value_mask);
+ SwitchVar(GraphicsContextAttribute::Stipple, value_list.stipple.has_value(),
+ true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::TileStippleOriginX,
+ value_list.tile_stipple_x_origin.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::TileStippleOriginY,
+ value_list.tile_stipple_y_origin.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::Font, value_list.font.has_value(), true,
+ &value_mask);
+ SwitchVar(GraphicsContextAttribute::SubwindowMode,
+ value_list.subwindow_mode.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::GraphicsExposures,
+ value_list.graphics_exposures.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::ClipOriginX,
+ value_list.clip_x_origin.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::ClipOriginY,
+ value_list.clip_y_origin.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::ClipMask,
+ value_list.clip_mask.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::DashOffset,
+ value_list.dash_offset.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::DashList, value_list.dashes.has_value(),
+ true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::ArcMode, value_list.arc_mode.has_value(),
+ true, &value_mask);
+ uint32_t tmp79;
+ tmp79 = static_cast<uint32_t>(value_mask);
+ buf.Write(&tmp79);
+
+ // value_list
+ auto value_list_expr = value_mask;
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Function)) {
+ auto& function = *value_list.function;
+
+ // function
+ uint32_t tmp80;
+ tmp80 = static_cast<uint32_t>(function);
+ buf.Write(&tmp80);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::PlaneMask)) {
+ auto& plane_mask = *value_list.plane_mask;
+
+ // plane_mask
+ buf.Write(&plane_mask);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Foreground)) {
+ auto& foreground = *value_list.foreground;
+
+ // foreground
+ buf.Write(&foreground);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Background)) {
+ auto& background = *value_list.background;
+
+ // background
+ buf.Write(&background);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::LineWidth)) {
+ auto& line_width = *value_list.line_width;
+
+ // line_width
+ buf.Write(&line_width);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::LineStyle)) {
+ auto& line_style = *value_list.line_style;
+
+ // line_style
+ uint32_t tmp81;
+ tmp81 = static_cast<uint32_t>(line_style);
+ buf.Write(&tmp81);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::CapStyle)) {
+ auto& cap_style = *value_list.cap_style;
+
+ // cap_style
+ uint32_t tmp82;
+ tmp82 = static_cast<uint32_t>(cap_style);
+ buf.Write(&tmp82);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::JoinStyle)) {
+ auto& join_style = *value_list.join_style;
+
+ // join_style
+ uint32_t tmp83;
+ tmp83 = static_cast<uint32_t>(join_style);
+ buf.Write(&tmp83);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::FillStyle)) {
+ auto& fill_style = *value_list.fill_style;
+
+ // fill_style
+ uint32_t tmp84;
+ tmp84 = static_cast<uint32_t>(fill_style);
+ buf.Write(&tmp84);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::FillRule)) {
+ auto& fill_rule = *value_list.fill_rule;
+
+ // fill_rule
+ uint32_t tmp85;
+ tmp85 = static_cast<uint32_t>(fill_rule);
+ buf.Write(&tmp85);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Tile)) {
+ auto& tile = *value_list.tile;
+
+ // tile
+ buf.Write(&tile);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Stipple)) {
+ auto& stipple = *value_list.stipple;
+
+ // stipple
+ buf.Write(&stipple);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::TileStippleOriginX)) {
+ auto& tile_stipple_x_origin = *value_list.tile_stipple_x_origin;
+
+ // tile_stipple_x_origin
+ buf.Write(&tile_stipple_x_origin);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::TileStippleOriginY)) {
+ auto& tile_stipple_y_origin = *value_list.tile_stipple_y_origin;
+
+ // tile_stipple_y_origin
+ buf.Write(&tile_stipple_y_origin);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Font)) {
+ auto& font = *value_list.font;
+
+ // font
+ buf.Write(&font);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::SubwindowMode)) {
+ auto& subwindow_mode = *value_list.subwindow_mode;
+
+ // subwindow_mode
+ uint32_t tmp86;
+ tmp86 = static_cast<uint32_t>(subwindow_mode);
+ buf.Write(&tmp86);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::GraphicsExposures)) {
+ auto& graphics_exposures = *value_list.graphics_exposures;
+
+ // graphics_exposures
+ buf.Write(&graphics_exposures);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::ClipOriginX)) {
+ auto& clip_x_origin = *value_list.clip_x_origin;
+
+ // clip_x_origin
+ buf.Write(&clip_x_origin);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::ClipOriginY)) {
+ auto& clip_y_origin = *value_list.clip_y_origin;
+
+ // clip_y_origin
+ buf.Write(&clip_y_origin);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::ClipMask)) {
+ auto& clip_mask = *value_list.clip_mask;
+
+ // clip_mask
+ buf.Write(&clip_mask);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::DashOffset)) {
+ auto& dash_offset = *value_list.dash_offset;
+
+ // dash_offset
+ buf.Write(&dash_offset);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::DashList)) {
+ auto& dashes = *value_list.dashes;
+
+ // dashes
+ buf.Write(&dashes);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::ArcMode)) {
+ auto& arc_mode = *value_list.arc_mode;
+
+ // arc_mode
+ uint32_t tmp87;
+ tmp87 = static_cast<uint32_t>(arc_mode);
+ buf.Write(&tmp87);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CreateGC", false);
+}
+
+Future<void> XProto::CreateGC(
+ const GraphicsContext& cid,
+ const Drawable& drawable,
+ const base::Optional<Gx>& function,
+ const base::Optional<uint32_t>& plane_mask,
+ const base::Optional<uint32_t>& foreground,
+ const base::Optional<uint32_t>& background,
+ const base::Optional<uint32_t>& line_width,
+ const base::Optional<LineStyle>& line_style,
+ const base::Optional<CapStyle>& cap_style,
+ const base::Optional<JoinStyle>& join_style,
+ const base::Optional<FillStyle>& fill_style,
+ const base::Optional<FillRule>& fill_rule,
+ const base::Optional<Pixmap>& tile,
+ const base::Optional<Pixmap>& stipple,
+ const base::Optional<int32_t>& tile_stipple_x_origin,
+ const base::Optional<int32_t>& tile_stipple_y_origin,
+ const base::Optional<Font>& font,
+ const base::Optional<SubwindowMode>& subwindow_mode,
+ const base::Optional<Bool32>& graphics_exposures,
+ const base::Optional<int32_t>& clip_x_origin,
+ const base::Optional<int32_t>& clip_y_origin,
+ const base::Optional<Pixmap>& clip_mask,
+ const base::Optional<uint32_t>& dash_offset,
+ const base::Optional<uint32_t>& dashes,
+ const base::Optional<ArcMode>& arc_mode) {
+ return XProto::CreateGC(CreateGCRequest{cid,
+ drawable,
+ function,
+ plane_mask,
+ foreground,
+ background,
+ line_width,
+ line_style,
+ cap_style,
+ join_style,
+ fill_style,
+ fill_rule,
+ tile,
+ stipple,
+ tile_stipple_x_origin,
+ tile_stipple_y_origin,
+ font,
+ subwindow_mode,
+ graphics_exposures,
+ clip_x_origin,
+ clip_y_origin,
+ clip_mask,
+ dash_offset,
+ dashes,
+ arc_mode});
+}
+
+Future<void> XProto::ChangeGC(const ChangeGCRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& gc = request.gc;
+ GraphicsContextAttribute value_mask{};
+ auto& value_list = request;
+
+ // major_opcode
+ uint8_t major_opcode = 56;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // gc
+ buf.Write(&gc);
+
+ // value_mask
+ SwitchVar(GraphicsContextAttribute::Function, value_list.function.has_value(),
+ true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::PlaneMask,
+ value_list.plane_mask.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::Foreground,
+ value_list.foreground.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::Background,
+ value_list.background.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::LineWidth,
+ value_list.line_width.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::LineStyle,
+ value_list.line_style.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::CapStyle,
+ value_list.cap_style.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::JoinStyle,
+ value_list.join_style.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::FillStyle,
+ value_list.fill_style.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::FillRule,
+ value_list.fill_rule.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::Tile, value_list.tile.has_value(), true,
+ &value_mask);
+ SwitchVar(GraphicsContextAttribute::Stipple, value_list.stipple.has_value(),
+ true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::TileStippleOriginX,
+ value_list.tile_stipple_x_origin.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::TileStippleOriginY,
+ value_list.tile_stipple_y_origin.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::Font, value_list.font.has_value(), true,
+ &value_mask);
+ SwitchVar(GraphicsContextAttribute::SubwindowMode,
+ value_list.subwindow_mode.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::GraphicsExposures,
+ value_list.graphics_exposures.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::ClipOriginX,
+ value_list.clip_x_origin.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::ClipOriginY,
+ value_list.clip_y_origin.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::ClipMask,
+ value_list.clip_mask.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::DashOffset,
+ value_list.dash_offset.has_value(), true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::DashList, value_list.dashes.has_value(),
+ true, &value_mask);
+ SwitchVar(GraphicsContextAttribute::ArcMode, value_list.arc_mode.has_value(),
+ true, &value_mask);
+ uint32_t tmp88;
+ tmp88 = static_cast<uint32_t>(value_mask);
+ buf.Write(&tmp88);
+
+ // value_list
+ auto value_list_expr = value_mask;
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Function)) {
+ auto& function = *value_list.function;
+
+ // function
+ uint32_t tmp89;
+ tmp89 = static_cast<uint32_t>(function);
+ buf.Write(&tmp89);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::PlaneMask)) {
+ auto& plane_mask = *value_list.plane_mask;
+
+ // plane_mask
+ buf.Write(&plane_mask);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Foreground)) {
+ auto& foreground = *value_list.foreground;
+
+ // foreground
+ buf.Write(&foreground);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Background)) {
+ auto& background = *value_list.background;
+
+ // background
+ buf.Write(&background);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::LineWidth)) {
+ auto& line_width = *value_list.line_width;
+
+ // line_width
+ buf.Write(&line_width);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::LineStyle)) {
+ auto& line_style = *value_list.line_style;
+
+ // line_style
+ uint32_t tmp90;
+ tmp90 = static_cast<uint32_t>(line_style);
+ buf.Write(&tmp90);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::CapStyle)) {
+ auto& cap_style = *value_list.cap_style;
+
+ // cap_style
+ uint32_t tmp91;
+ tmp91 = static_cast<uint32_t>(cap_style);
+ buf.Write(&tmp91);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::JoinStyle)) {
+ auto& join_style = *value_list.join_style;
+
+ // join_style
+ uint32_t tmp92;
+ tmp92 = static_cast<uint32_t>(join_style);
+ buf.Write(&tmp92);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::FillStyle)) {
+ auto& fill_style = *value_list.fill_style;
+
+ // fill_style
+ uint32_t tmp93;
+ tmp93 = static_cast<uint32_t>(fill_style);
+ buf.Write(&tmp93);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::FillRule)) {
+ auto& fill_rule = *value_list.fill_rule;
+
+ // fill_rule
+ uint32_t tmp94;
+ tmp94 = static_cast<uint32_t>(fill_rule);
+ buf.Write(&tmp94);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Tile)) {
+ auto& tile = *value_list.tile;
+
+ // tile
+ buf.Write(&tile);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Stipple)) {
+ auto& stipple = *value_list.stipple;
+
+ // stipple
+ buf.Write(&stipple);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::TileStippleOriginX)) {
+ auto& tile_stipple_x_origin = *value_list.tile_stipple_x_origin;
+
+ // tile_stipple_x_origin
+ buf.Write(&tile_stipple_x_origin);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::TileStippleOriginY)) {
+ auto& tile_stipple_y_origin = *value_list.tile_stipple_y_origin;
+
+ // tile_stipple_y_origin
+ buf.Write(&tile_stipple_y_origin);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::Font)) {
+ auto& font = *value_list.font;
+
+ // font
+ buf.Write(&font);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::SubwindowMode)) {
+ auto& subwindow_mode = *value_list.subwindow_mode;
+
+ // subwindow_mode
+ uint32_t tmp95;
+ tmp95 = static_cast<uint32_t>(subwindow_mode);
+ buf.Write(&tmp95);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::GraphicsExposures)) {
+ auto& graphics_exposures = *value_list.graphics_exposures;
+
+ // graphics_exposures
+ buf.Write(&graphics_exposures);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::ClipOriginX)) {
+ auto& clip_x_origin = *value_list.clip_x_origin;
+
+ // clip_x_origin
+ buf.Write(&clip_x_origin);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::ClipOriginY)) {
+ auto& clip_y_origin = *value_list.clip_y_origin;
+
+ // clip_y_origin
+ buf.Write(&clip_y_origin);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::ClipMask)) {
+ auto& clip_mask = *value_list.clip_mask;
+
+ // clip_mask
+ buf.Write(&clip_mask);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::DashOffset)) {
+ auto& dash_offset = *value_list.dash_offset;
+
+ // dash_offset
+ buf.Write(&dash_offset);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::DashList)) {
+ auto& dashes = *value_list.dashes;
+
+ // dashes
+ buf.Write(&dashes);
+ }
+ if (CaseAnd(value_list_expr, GraphicsContextAttribute::ArcMode)) {
+ auto& arc_mode = *value_list.arc_mode;
+
+ // arc_mode
+ uint32_t tmp96;
+ tmp96 = static_cast<uint32_t>(arc_mode);
+ buf.Write(&tmp96);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ChangeGC", false);
+}
+
+Future<void> XProto::ChangeGC(
+ const GraphicsContext& gc,
+ const base::Optional<Gx>& function,
+ const base::Optional<uint32_t>& plane_mask,
+ const base::Optional<uint32_t>& foreground,
+ const base::Optional<uint32_t>& background,
+ const base::Optional<uint32_t>& line_width,
+ const base::Optional<LineStyle>& line_style,
+ const base::Optional<CapStyle>& cap_style,
+ const base::Optional<JoinStyle>& join_style,
+ const base::Optional<FillStyle>& fill_style,
+ const base::Optional<FillRule>& fill_rule,
+ const base::Optional<Pixmap>& tile,
+ const base::Optional<Pixmap>& stipple,
+ const base::Optional<int32_t>& tile_stipple_x_origin,
+ const base::Optional<int32_t>& tile_stipple_y_origin,
+ const base::Optional<Font>& font,
+ const base::Optional<SubwindowMode>& subwindow_mode,
+ const base::Optional<Bool32>& graphics_exposures,
+ const base::Optional<int32_t>& clip_x_origin,
+ const base::Optional<int32_t>& clip_y_origin,
+ const base::Optional<Pixmap>& clip_mask,
+ const base::Optional<uint32_t>& dash_offset,
+ const base::Optional<uint32_t>& dashes,
+ const base::Optional<ArcMode>& arc_mode) {
+ return XProto::ChangeGC(ChangeGCRequest{gc,
+ function,
+ plane_mask,
+ foreground,
+ background,
+ line_width,
+ line_style,
+ cap_style,
+ join_style,
+ fill_style,
+ fill_rule,
+ tile,
+ stipple,
+ tile_stipple_x_origin,
+ tile_stipple_y_origin,
+ font,
+ subwindow_mode,
+ graphics_exposures,
+ clip_x_origin,
+ clip_y_origin,
+ clip_mask,
+ dash_offset,
+ dashes,
+ arc_mode});
+}
+
+Future<void> XProto::CopyGC(const CopyGCRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& src_gc = request.src_gc;
+ auto& dst_gc = request.dst_gc;
+ auto& value_mask = request.value_mask;
+
+ // major_opcode
+ uint8_t major_opcode = 57;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // src_gc
+ buf.Write(&src_gc);
+
+ // dst_gc
+ buf.Write(&dst_gc);
+
+ // value_mask
+ uint32_t tmp97;
+ tmp97 = static_cast<uint32_t>(value_mask);
+ buf.Write(&tmp97);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CopyGC", false);
+}
+
+Future<void> XProto::CopyGC(const GraphicsContext& src_gc,
+ const GraphicsContext& dst_gc,
+ const GraphicsContextAttribute& value_mask) {
+ return XProto::CopyGC(CopyGCRequest{src_gc, dst_gc, value_mask});
+}
+
+Future<void> XProto::SetDashes(const SetDashesRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& gc = request.gc;
+ auto& dash_offset = request.dash_offset;
+ uint16_t dashes_len{};
+ auto& dashes = request.dashes;
+
+ // major_opcode
+ uint8_t major_opcode = 58;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // gc
+ buf.Write(&gc);
+
+ // dash_offset
+ buf.Write(&dash_offset);
+
+ // dashes_len
+ dashes_len = dashes.size();
+ buf.Write(&dashes_len);
+
+ // dashes
+ DCHECK_EQ(static_cast<size_t>(dashes_len), dashes.size());
+ for (auto& dashes_elem : dashes) {
+ // dashes_elem
+ buf.Write(&dashes_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SetDashes", false);
+}
+
+Future<void> XProto::SetDashes(const GraphicsContext& gc,
+ const uint16_t& dash_offset,
+ const std::vector<uint8_t>& dashes) {
+ return XProto::SetDashes(SetDashesRequest{gc, dash_offset, dashes});
+}
+
+Future<void> XProto::SetClipRectangles(
+ const SetClipRectanglesRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& ordering = request.ordering;
+ auto& gc = request.gc;
+ auto& clip_x_origin = request.clip_x_origin;
+ auto& clip_y_origin = request.clip_y_origin;
+ auto& rectangles = request.rectangles;
+ size_t rectangles_len = rectangles.size();
+
+ // major_opcode
+ uint8_t major_opcode = 59;
+ buf.Write(&major_opcode);
+
+ // ordering
+ uint8_t tmp98;
+ tmp98 = static_cast<uint8_t>(ordering);
+ buf.Write(&tmp98);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // gc
+ buf.Write(&gc);
+
+ // clip_x_origin
+ buf.Write(&clip_x_origin);
+
+ // clip_y_origin
+ buf.Write(&clip_y_origin);
+
+ // rectangles
+ DCHECK_EQ(static_cast<size_t>(rectangles_len), rectangles.size());
+ for (auto& rectangles_elem : rectangles) {
+ // rectangles_elem
+ {
+ auto& x = rectangles_elem.x;
+ auto& y = rectangles_elem.y;
+ auto& width = rectangles_elem.width;
+ auto& height = rectangles_elem.height;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SetClipRectangles", false);
+}
+
+Future<void> XProto::SetClipRectangles(
+ const ClipOrdering& ordering,
+ const GraphicsContext& gc,
+ const int16_t& clip_x_origin,
+ const int16_t& clip_y_origin,
+ const std::vector<Rectangle>& rectangles) {
+ return XProto::SetClipRectangles(SetClipRectanglesRequest{
+ ordering, gc, clip_x_origin, clip_y_origin, rectangles});
+}
+
+Future<void> XProto::FreeGC(const FreeGCRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& gc = request.gc;
+
+ // major_opcode
+ uint8_t major_opcode = 60;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // gc
+ buf.Write(&gc);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "FreeGC", false);
+}
+
+Future<void> XProto::FreeGC(const GraphicsContext& gc) {
+ return XProto::FreeGC(FreeGCRequest{gc});
+}
+
+Future<void> XProto::ClearArea(const ClearAreaRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& exposures = request.exposures;
+ auto& window = request.window;
+ auto& x = request.x;
+ auto& y = request.y;
+ auto& width = request.width;
+ auto& height = request.height;
+
+ // major_opcode
+ uint8_t major_opcode = 61;
+ buf.Write(&major_opcode);
+
+ // exposures
+ buf.Write(&exposures);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ClearArea", false);
+}
+
+Future<void> XProto::ClearArea(const uint8_t& exposures,
+ const Window& window,
+ const int16_t& x,
+ const int16_t& y,
+ const uint16_t& width,
+ const uint16_t& height) {
+ return XProto::ClearArea(
+ ClearAreaRequest{exposures, window, x, y, width, height});
+}
+
+Future<void> XProto::CopyArea(const CopyAreaRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& src_drawable = request.src_drawable;
+ auto& dst_drawable = request.dst_drawable;
+ auto& gc = request.gc;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& dst_x = request.dst_x;
+ auto& dst_y = request.dst_y;
+ auto& width = request.width;
+ auto& height = request.height;
+
+ // major_opcode
+ uint8_t major_opcode = 62;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // src_drawable
+ buf.Write(&src_drawable);
+
+ // dst_drawable
+ buf.Write(&dst_drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // dst_x
+ buf.Write(&dst_x);
+
+ // dst_y
+ buf.Write(&dst_y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CopyArea", false);
+}
+
+Future<void> XProto::CopyArea(const Drawable& src_drawable,
+ const Drawable& dst_drawable,
+ const GraphicsContext& gc,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const int16_t& dst_x,
+ const int16_t& dst_y,
+ const uint16_t& width,
+ const uint16_t& height) {
+ return XProto::CopyArea(CopyAreaRequest{src_drawable, dst_drawable, gc, src_x,
+ src_y, dst_x, dst_y, width, height});
+}
+
+Future<void> XProto::CopyPlane(const CopyPlaneRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& src_drawable = request.src_drawable;
+ auto& dst_drawable = request.dst_drawable;
+ auto& gc = request.gc;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& dst_x = request.dst_x;
+ auto& dst_y = request.dst_y;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& bit_plane = request.bit_plane;
+
+ // major_opcode
+ uint8_t major_opcode = 63;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // src_drawable
+ buf.Write(&src_drawable);
+
+ // dst_drawable
+ buf.Write(&dst_drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // dst_x
+ buf.Write(&dst_x);
+
+ // dst_y
+ buf.Write(&dst_y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // bit_plane
+ buf.Write(&bit_plane);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CopyPlane", false);
+}
+
+Future<void> XProto::CopyPlane(const Drawable& src_drawable,
+ const Drawable& dst_drawable,
+ const GraphicsContext& gc,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const int16_t& dst_x,
+ const int16_t& dst_y,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint32_t& bit_plane) {
+ return XProto::CopyPlane(CopyPlaneRequest{src_drawable, dst_drawable, gc,
+ src_x, src_y, dst_x, dst_y, width,
+ height, bit_plane});
+}
+
+Future<void> XProto::PolyPoint(const PolyPointRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& coordinate_mode = request.coordinate_mode;
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& points = request.points;
+ size_t points_len = points.size();
+
+ // major_opcode
+ uint8_t major_opcode = 64;
+ buf.Write(&major_opcode);
+
+ // coordinate_mode
+ uint8_t tmp99;
+ tmp99 = static_cast<uint8_t>(coordinate_mode);
+ buf.Write(&tmp99);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // points
+ DCHECK_EQ(static_cast<size_t>(points_len), points.size());
+ for (auto& points_elem : points) {
+ // points_elem
+ {
+ auto& x = points_elem.x;
+ auto& y = points_elem.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "PolyPoint", false);
+}
+
+Future<void> XProto::PolyPoint(const CoordMode& coordinate_mode,
+ const Drawable& drawable,
+ const GraphicsContext& gc,
+ const std::vector<Point>& points) {
+ return XProto::PolyPoint(
+ PolyPointRequest{coordinate_mode, drawable, gc, points});
+}
+
+Future<void> XProto::PolyLine(const PolyLineRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& coordinate_mode = request.coordinate_mode;
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& points = request.points;
+ size_t points_len = points.size();
+
+ // major_opcode
+ uint8_t major_opcode = 65;
+ buf.Write(&major_opcode);
+
+ // coordinate_mode
+ uint8_t tmp100;
+ tmp100 = static_cast<uint8_t>(coordinate_mode);
+ buf.Write(&tmp100);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // points
+ DCHECK_EQ(static_cast<size_t>(points_len), points.size());
+ for (auto& points_elem : points) {
+ // points_elem
+ {
+ auto& x = points_elem.x;
+ auto& y = points_elem.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "PolyLine", false);
+}
+
+Future<void> XProto::PolyLine(const CoordMode& coordinate_mode,
+ const Drawable& drawable,
+ const GraphicsContext& gc,
+ const std::vector<Point>& points) {
+ return XProto::PolyLine(
+ PolyLineRequest{coordinate_mode, drawable, gc, points});
+}
+
+Future<void> XProto::PolySegment(const PolySegmentRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& segments = request.segments;
+ size_t segments_len = segments.size();
+
+ // major_opcode
+ uint8_t major_opcode = 66;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // segments
+ DCHECK_EQ(static_cast<size_t>(segments_len), segments.size());
+ for (auto& segments_elem : segments) {
+ // segments_elem
+ {
+ auto& x1 = segments_elem.x1;
+ auto& y1 = segments_elem.y1;
+ auto& x2 = segments_elem.x2;
+ auto& y2 = segments_elem.y2;
+
+ // x1
+ buf.Write(&x1);
+
+ // y1
+ buf.Write(&y1);
+
+ // x2
+ buf.Write(&x2);
+
+ // y2
+ buf.Write(&y2);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "PolySegment", false);
+}
+
+Future<void> XProto::PolySegment(const Drawable& drawable,
+ const GraphicsContext& gc,
+ const std::vector<Segment>& segments) {
+ return XProto::PolySegment(PolySegmentRequest{drawable, gc, segments});
+}
+
+Future<void> XProto::PolyRectangle(const PolyRectangleRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& rectangles = request.rectangles;
+ size_t rectangles_len = rectangles.size();
+
+ // major_opcode
+ uint8_t major_opcode = 67;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // rectangles
+ DCHECK_EQ(static_cast<size_t>(rectangles_len), rectangles.size());
+ for (auto& rectangles_elem : rectangles) {
+ // rectangles_elem
+ {
+ auto& x = rectangles_elem.x;
+ auto& y = rectangles_elem.y;
+ auto& width = rectangles_elem.width;
+ auto& height = rectangles_elem.height;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "PolyRectangle", false);
+}
+
+Future<void> XProto::PolyRectangle(const Drawable& drawable,
+ const GraphicsContext& gc,
+ const std::vector<Rectangle>& rectangles) {
+ return XProto::PolyRectangle(PolyRectangleRequest{drawable, gc, rectangles});
+}
+
+Future<void> XProto::PolyArc(const PolyArcRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& arcs = request.arcs;
+ size_t arcs_len = arcs.size();
+
+ // major_opcode
+ uint8_t major_opcode = 68;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // arcs
+ DCHECK_EQ(static_cast<size_t>(arcs_len), arcs.size());
+ for (auto& arcs_elem : arcs) {
+ // arcs_elem
+ {
+ auto& x = arcs_elem.x;
+ auto& y = arcs_elem.y;
+ auto& width = arcs_elem.width;
+ auto& height = arcs_elem.height;
+ auto& angle1 = arcs_elem.angle1;
+ auto& angle2 = arcs_elem.angle2;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // angle1
+ buf.Write(&angle1);
+
+ // angle2
+ buf.Write(&angle2);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "PolyArc", false);
+}
+
+Future<void> XProto::PolyArc(const Drawable& drawable,
+ const GraphicsContext& gc,
+ const std::vector<Arc>& arcs) {
+ return XProto::PolyArc(PolyArcRequest{drawable, gc, arcs});
+}
+
+Future<void> XProto::FillPoly(const FillPolyRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& shape = request.shape;
+ auto& coordinate_mode = request.coordinate_mode;
+ auto& points = request.points;
+ size_t points_len = points.size();
+
+ // major_opcode
+ uint8_t major_opcode = 69;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // shape
+ uint8_t tmp101;
+ tmp101 = static_cast<uint8_t>(shape);
+ buf.Write(&tmp101);
+
+ // coordinate_mode
+ uint8_t tmp102;
+ tmp102 = static_cast<uint8_t>(coordinate_mode);
+ buf.Write(&tmp102);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // points
+ DCHECK_EQ(static_cast<size_t>(points_len), points.size());
+ for (auto& points_elem : points) {
+ // points_elem
+ {
+ auto& x = points_elem.x;
+ auto& y = points_elem.y;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "FillPoly", false);
+}
+
+Future<void> XProto::FillPoly(const Drawable& drawable,
+ const GraphicsContext& gc,
+ const PolyShape& shape,
+ const CoordMode& coordinate_mode,
+ const std::vector<Point>& points) {
+ return XProto::FillPoly(
+ FillPolyRequest{drawable, gc, shape, coordinate_mode, points});
+}
+
+Future<void> XProto::PolyFillRectangle(
+ const PolyFillRectangleRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& rectangles = request.rectangles;
+ size_t rectangles_len = rectangles.size();
+
+ // major_opcode
+ uint8_t major_opcode = 70;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // rectangles
+ DCHECK_EQ(static_cast<size_t>(rectangles_len), rectangles.size());
+ for (auto& rectangles_elem : rectangles) {
+ // rectangles_elem
+ {
+ auto& x = rectangles_elem.x;
+ auto& y = rectangles_elem.y;
+ auto& width = rectangles_elem.width;
+ auto& height = rectangles_elem.height;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "PolyFillRectangle", false);
+}
+
+Future<void> XProto::PolyFillRectangle(
+ const Drawable& drawable,
+ const GraphicsContext& gc,
+ const std::vector<Rectangle>& rectangles) {
+ return XProto::PolyFillRectangle(
+ PolyFillRectangleRequest{drawable, gc, rectangles});
+}
+
+Future<void> XProto::PolyFillArc(const PolyFillArcRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& arcs = request.arcs;
+ size_t arcs_len = arcs.size();
+
+ // major_opcode
+ uint8_t major_opcode = 71;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // arcs
+ DCHECK_EQ(static_cast<size_t>(arcs_len), arcs.size());
+ for (auto& arcs_elem : arcs) {
+ // arcs_elem
+ {
+ auto& x = arcs_elem.x;
+ auto& y = arcs_elem.y;
+ auto& width = arcs_elem.width;
+ auto& height = arcs_elem.height;
+ auto& angle1 = arcs_elem.angle1;
+ auto& angle2 = arcs_elem.angle2;
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // angle1
+ buf.Write(&angle1);
+
+ // angle2
+ buf.Write(&angle2);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "PolyFillArc", false);
+}
+
+Future<void> XProto::PolyFillArc(const Drawable& drawable,
+ const GraphicsContext& gc,
+ const std::vector<Arc>& arcs) {
+ return XProto::PolyFillArc(PolyFillArcRequest{drawable, gc, arcs});
+}
+
+Future<void> XProto::PutImage(const PutImageRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& format = request.format;
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& dst_x = request.dst_x;
+ auto& dst_y = request.dst_y;
+ auto& left_pad = request.left_pad;
+ auto& depth = request.depth;
+ auto& data = request.data;
+ size_t data_len = data ? data->size() : 0;
+
+ // major_opcode
+ uint8_t major_opcode = 72;
+ buf.Write(&major_opcode);
+
+ // format
+ uint8_t tmp103;
+ tmp103 = static_cast<uint8_t>(format);
+ buf.Write(&tmp103);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // dst_x
+ buf.Write(&dst_x);
+
+ // dst_y
+ buf.Write(&dst_y);
+
+ // left_pad
+ buf.Write(&left_pad);
+
+ // depth
+ buf.Write(&depth);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // data
+ buf.AppendBuffer(data, data_len);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "PutImage", false);
+}
+
+Future<void> XProto::PutImage(
+ const ImageFormat& format,
+ const Drawable& drawable,
+ const GraphicsContext& gc,
+ const uint16_t& width,
+ const uint16_t& height,
+ const int16_t& dst_x,
+ const int16_t& dst_y,
+ const uint8_t& left_pad,
+ const uint8_t& depth,
+ const scoped_refptr<base::RefCountedMemory>& data) {
+ return XProto::PutImage(PutImageRequest{format, drawable, gc, width, height,
+ dst_x, dst_y, left_pad, depth, data});
+}
+
+Future<GetImageReply> XProto::GetImage(const GetImageRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& format = request.format;
+ auto& drawable = request.drawable;
+ auto& x = request.x;
+ auto& y = request.y;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& plane_mask = request.plane_mask;
+
+ // major_opcode
+ uint8_t major_opcode = 73;
+ buf.Write(&major_opcode);
+
+ // format
+ uint8_t tmp104;
+ tmp104 = static_cast<uint8_t>(format);
+ buf.Write(&tmp104);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // plane_mask
+ buf.Write(&plane_mask);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetImageReply>(&buf, "GetImage", false);
+}
+
+Future<GetImageReply> XProto::GetImage(const ImageFormat& format,
+ const Drawable& drawable,
+ const int16_t& x,
+ const int16_t& y,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint32_t& plane_mask) {
+ return XProto::GetImage(
+ GetImageRequest{format, drawable, x, y, width, height, plane_mask});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetImageReply> detail::ReadReply<GetImageReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetImageReply>();
+
+ auto& depth = (*reply).depth;
+ auto& sequence = (*reply).sequence;
+ auto& visual = (*reply).visual;
+ auto& data = (*reply).data;
+ size_t data_len = data ? data->size() : 0;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // depth
+ Read(&depth, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // visual
+ Read(&visual, &buf);
+
+ // pad0
+ Pad(&buf, 20);
+
+ // data
+ data = buffer->ReadAndAdvance((length) * (4));
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::PolyText8(const PolyText8Request& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& x = request.x;
+ auto& y = request.y;
+ auto& items = request.items;
+ size_t items_len = items.size();
+
+ // major_opcode
+ uint8_t major_opcode = 74;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // items
+ DCHECK_EQ(static_cast<size_t>(items_len), items.size());
+ for (auto& items_elem : items) {
+ // items_elem
+ buf.Write(&items_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "PolyText8", false);
+}
+
+Future<void> XProto::PolyText8(const Drawable& drawable,
+ const GraphicsContext& gc,
+ const int16_t& x,
+ const int16_t& y,
+ const std::vector<uint8_t>& items) {
+ return XProto::PolyText8(PolyText8Request{drawable, gc, x, y, items});
+}
+
+Future<void> XProto::PolyText16(const PolyText16Request& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& x = request.x;
+ auto& y = request.y;
+ auto& items = request.items;
+ size_t items_len = items.size();
+
+ // major_opcode
+ uint8_t major_opcode = 75;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // items
+ DCHECK_EQ(static_cast<size_t>(items_len), items.size());
+ for (auto& items_elem : items) {
+ // items_elem
+ buf.Write(&items_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "PolyText16", false);
+}
+
+Future<void> XProto::PolyText16(const Drawable& drawable,
+ const GraphicsContext& gc,
+ const int16_t& x,
+ const int16_t& y,
+ const std::vector<uint8_t>& items) {
+ return XProto::PolyText16(PolyText16Request{drawable, gc, x, y, items});
+}
+
+Future<void> XProto::ImageText8(const ImageText8Request& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ uint8_t string_len{};
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& x = request.x;
+ auto& y = request.y;
+ auto& string = request.string;
+
+ // major_opcode
+ uint8_t major_opcode = 76;
+ buf.Write(&major_opcode);
+
+ // string_len
+ string_len = string.size();
+ buf.Write(&string_len);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // string
+ DCHECK_EQ(static_cast<size_t>(string_len), string.size());
+ for (auto& string_elem : string) {
+ // string_elem
+ buf.Write(&string_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ImageText8", false);
+}
+
+Future<void> XProto::ImageText8(const Drawable& drawable,
+ const GraphicsContext& gc,
+ const int16_t& x,
+ const int16_t& y,
+ const std::string& string) {
+ return XProto::ImageText8(ImageText8Request{drawable, gc, x, y, string});
+}
+
+Future<void> XProto::ImageText16(const ImageText16Request& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ uint8_t string_len{};
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& x = request.x;
+ auto& y = request.y;
+ auto& string = request.string;
+
+ // major_opcode
+ uint8_t major_opcode = 77;
+ buf.Write(&major_opcode);
+
+ // string_len
+ string_len = string.size();
+ buf.Write(&string_len);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ // string
+ DCHECK_EQ(static_cast<size_t>(string_len), string.size());
+ for (auto& string_elem : string) {
+ // string_elem
+ {
+ auto& byte1 = string_elem.byte1;
+ auto& byte2 = string_elem.byte2;
+
+ // byte1
+ buf.Write(&byte1);
+
+ // byte2
+ buf.Write(&byte2);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ImageText16", false);
+}
+
+Future<void> XProto::ImageText16(const Drawable& drawable,
+ const GraphicsContext& gc,
+ const int16_t& x,
+ const int16_t& y,
+ const std::vector<Char16>& string) {
+ return XProto::ImageText16(ImageText16Request{drawable, gc, x, y, string});
+}
+
+Future<void> XProto::CreateColormap(const CreateColormapRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& alloc = request.alloc;
+ auto& mid = request.mid;
+ auto& window = request.window;
+ auto& visual = request.visual;
+
+ // major_opcode
+ uint8_t major_opcode = 78;
+ buf.Write(&major_opcode);
+
+ // alloc
+ uint8_t tmp105;
+ tmp105 = static_cast<uint8_t>(alloc);
+ buf.Write(&tmp105);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // mid
+ buf.Write(&mid);
+
+ // window
+ buf.Write(&window);
+
+ // visual
+ buf.Write(&visual);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CreateColormap", false);
+}
+
+Future<void> XProto::CreateColormap(const ColormapAlloc& alloc,
+ const ColorMap& mid,
+ const Window& window,
+ const VisualId& visual) {
+ return XProto::CreateColormap(
+ CreateColormapRequest{alloc, mid, window, visual});
+}
+
+Future<void> XProto::FreeColormap(const FreeColormapRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cmap = request.cmap;
+
+ // major_opcode
+ uint8_t major_opcode = 79;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "FreeColormap", false);
+}
+
+Future<void> XProto::FreeColormap(const ColorMap& cmap) {
+ return XProto::FreeColormap(FreeColormapRequest{cmap});
+}
+
+Future<void> XProto::CopyColormapAndFree(
+ const CopyColormapAndFreeRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& mid = request.mid;
+ auto& src_cmap = request.src_cmap;
+
+ // major_opcode
+ uint8_t major_opcode = 80;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // mid
+ buf.Write(&mid);
+
+ // src_cmap
+ buf.Write(&src_cmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CopyColormapAndFree", false);
+}
+
+Future<void> XProto::CopyColormapAndFree(const ColorMap& mid,
+ const ColorMap& src_cmap) {
+ return XProto::CopyColormapAndFree(CopyColormapAndFreeRequest{mid, src_cmap});
+}
+
+Future<void> XProto::InstallColormap(const InstallColormapRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cmap = request.cmap;
+
+ // major_opcode
+ uint8_t major_opcode = 81;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "InstallColormap", false);
+}
+
+Future<void> XProto::InstallColormap(const ColorMap& cmap) {
+ return XProto::InstallColormap(InstallColormapRequest{cmap});
+}
+
+Future<void> XProto::UninstallColormap(
+ const UninstallColormapRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cmap = request.cmap;
+
+ // major_opcode
+ uint8_t major_opcode = 82;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "UninstallColormap", false);
+}
+
+Future<void> XProto::UninstallColormap(const ColorMap& cmap) {
+ return XProto::UninstallColormap(UninstallColormapRequest{cmap});
+}
+
+Future<ListInstalledColormapsReply> XProto::ListInstalledColormaps(
+ const ListInstalledColormapsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = 83;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<ListInstalledColormapsReply>(
+ &buf, "ListInstalledColormaps", false);
+}
+
+Future<ListInstalledColormapsReply> XProto::ListInstalledColormaps(
+ const Window& window) {
+ return XProto::ListInstalledColormaps(ListInstalledColormapsRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<ListInstalledColormapsReply> detail::ReadReply<
+ ListInstalledColormapsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<ListInstalledColormapsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t cmaps_len{};
+ auto& cmaps = (*reply).cmaps;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // cmaps_len
+ Read(&cmaps_len, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // cmaps
+ cmaps.resize(cmaps_len);
+ for (auto& cmaps_elem : cmaps) {
+ // cmaps_elem
+ Read(&cmaps_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<AllocColorReply> XProto::AllocColor(const AllocColorRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cmap = request.cmap;
+ auto& red = request.red;
+ auto& green = request.green;
+ auto& blue = request.blue;
+
+ // major_opcode
+ uint8_t major_opcode = 84;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ // red
+ buf.Write(&red);
+
+ // green
+ buf.Write(&green);
+
+ // blue
+ buf.Write(&blue);
+
+ // pad1
+ Pad(&buf, 2);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<AllocColorReply>(&buf, "AllocColor", false);
+}
+
+Future<AllocColorReply> XProto::AllocColor(const ColorMap& cmap,
+ const uint16_t& red,
+ const uint16_t& green,
+ const uint16_t& blue) {
+ return XProto::AllocColor(AllocColorRequest{cmap, red, green, blue});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<AllocColorReply> detail::ReadReply<AllocColorReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<AllocColorReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& red = (*reply).red;
+ auto& green = (*reply).green;
+ auto& blue = (*reply).blue;
+ auto& pixel = (*reply).pixel;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // red
+ Read(&red, &buf);
+
+ // green
+ Read(&green, &buf);
+
+ // blue
+ Read(&blue, &buf);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // pixel
+ Read(&pixel, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<AllocNamedColorReply> XProto::AllocNamedColor(
+ const AllocNamedColorRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cmap = request.cmap;
+ uint16_t name_len{};
+ auto& name = request.name;
+
+ // major_opcode
+ uint8_t major_opcode = 85;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ // name_len
+ name_len = name.size();
+ buf.Write(&name_len);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(name_len), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<AllocNamedColorReply>(&buf, "AllocNamedColor",
+ false);
+}
+
+Future<AllocNamedColorReply> XProto::AllocNamedColor(const ColorMap& cmap,
+ const std::string& name) {
+ return XProto::AllocNamedColor(AllocNamedColorRequest{cmap, name});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<AllocNamedColorReply> detail::ReadReply<AllocNamedColorReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<AllocNamedColorReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& pixel = (*reply).pixel;
+ auto& exact_red = (*reply).exact_red;
+ auto& exact_green = (*reply).exact_green;
+ auto& exact_blue = (*reply).exact_blue;
+ auto& visual_red = (*reply).visual_red;
+ auto& visual_green = (*reply).visual_green;
+ auto& visual_blue = (*reply).visual_blue;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pixel
+ Read(&pixel, &buf);
+
+ // exact_red
+ Read(&exact_red, &buf);
+
+ // exact_green
+ Read(&exact_green, &buf);
+
+ // exact_blue
+ Read(&exact_blue, &buf);
+
+ // visual_red
+ Read(&visual_red, &buf);
+
+ // visual_green
+ Read(&visual_green, &buf);
+
+ // visual_blue
+ Read(&visual_blue, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<AllocColorCellsReply> XProto::AllocColorCells(
+ const AllocColorCellsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& contiguous = request.contiguous;
+ auto& cmap = request.cmap;
+ auto& colors = request.colors;
+ auto& planes = request.planes;
+
+ // major_opcode
+ uint8_t major_opcode = 86;
+ buf.Write(&major_opcode);
+
+ // contiguous
+ buf.Write(&contiguous);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ // colors
+ buf.Write(&colors);
+
+ // planes
+ buf.Write(&planes);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<AllocColorCellsReply>(&buf, "AllocColorCells",
+ false);
+}
+
+Future<AllocColorCellsReply> XProto::AllocColorCells(const uint8_t& contiguous,
+ const ColorMap& cmap,
+ const uint16_t& colors,
+ const uint16_t& planes) {
+ return XProto::AllocColorCells(
+ AllocColorCellsRequest{contiguous, cmap, colors, planes});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<AllocColorCellsReply> detail::ReadReply<AllocColorCellsReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<AllocColorCellsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t pixels_len{};
+ uint16_t masks_len{};
+ auto& pixels = (*reply).pixels;
+ auto& masks = (*reply).masks;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pixels_len
+ Read(&pixels_len, &buf);
+
+ // masks_len
+ Read(&masks_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // pixels
+ pixels.resize(pixels_len);
+ for (auto& pixels_elem : pixels) {
+ // pixels_elem
+ Read(&pixels_elem, &buf);
+ }
+
+ // masks
+ masks.resize(masks_len);
+ for (auto& masks_elem : masks) {
+ // masks_elem
+ Read(&masks_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<AllocColorPlanesReply> XProto::AllocColorPlanes(
+ const AllocColorPlanesRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& contiguous = request.contiguous;
+ auto& cmap = request.cmap;
+ auto& colors = request.colors;
+ auto& reds = request.reds;
+ auto& greens = request.greens;
+ auto& blues = request.blues;
+
+ // major_opcode
+ uint8_t major_opcode = 87;
+ buf.Write(&major_opcode);
+
+ // contiguous
+ buf.Write(&contiguous);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ // colors
+ buf.Write(&colors);
+
+ // reds
+ buf.Write(&reds);
+
+ // greens
+ buf.Write(&greens);
+
+ // blues
+ buf.Write(&blues);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<AllocColorPlanesReply>(
+ &buf, "AllocColorPlanes", false);
+}
+
+Future<AllocColorPlanesReply> XProto::AllocColorPlanes(
+ const uint8_t& contiguous,
+ const ColorMap& cmap,
+ const uint16_t& colors,
+ const uint16_t& reds,
+ const uint16_t& greens,
+ const uint16_t& blues) {
+ return XProto::AllocColorPlanes(
+ AllocColorPlanesRequest{contiguous, cmap, colors, reds, greens, blues});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<AllocColorPlanesReply> detail::ReadReply<AllocColorPlanesReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<AllocColorPlanesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t pixels_len{};
+ auto& red_mask = (*reply).red_mask;
+ auto& green_mask = (*reply).green_mask;
+ auto& blue_mask = (*reply).blue_mask;
+ auto& pixels = (*reply).pixels;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pixels_len
+ Read(&pixels_len, &buf);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // red_mask
+ Read(&red_mask, &buf);
+
+ // green_mask
+ Read(&green_mask, &buf);
+
+ // blue_mask
+ Read(&blue_mask, &buf);
+
+ // pad2
+ Pad(&buf, 8);
+
+ // pixels
+ pixels.resize(pixels_len);
+ for (auto& pixels_elem : pixels) {
+ // pixels_elem
+ Read(&pixels_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::FreeColors(const FreeColorsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cmap = request.cmap;
+ auto& plane_mask = request.plane_mask;
+ auto& pixels = request.pixels;
+ size_t pixels_len = pixels.size();
+
+ // major_opcode
+ uint8_t major_opcode = 88;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ // plane_mask
+ buf.Write(&plane_mask);
+
+ // pixels
+ DCHECK_EQ(static_cast<size_t>(pixels_len), pixels.size());
+ for (auto& pixels_elem : pixels) {
+ // pixels_elem
+ buf.Write(&pixels_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "FreeColors", false);
+}
+
+Future<void> XProto::FreeColors(const ColorMap& cmap,
+ const uint32_t& plane_mask,
+ const std::vector<uint32_t>& pixels) {
+ return XProto::FreeColors(FreeColorsRequest{cmap, plane_mask, pixels});
+}
+
+Future<void> XProto::StoreColors(const StoreColorsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cmap = request.cmap;
+ auto& items = request.items;
+ size_t items_len = items.size();
+
+ // major_opcode
+ uint8_t major_opcode = 89;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ // items
+ DCHECK_EQ(static_cast<size_t>(items_len), items.size());
+ for (auto& items_elem : items) {
+ // items_elem
+ {
+ auto& pixel = items_elem.pixel;
+ auto& red = items_elem.red;
+ auto& green = items_elem.green;
+ auto& blue = items_elem.blue;
+ auto& flags = items_elem.flags;
+
+ // pixel
+ buf.Write(&pixel);
+
+ // red
+ buf.Write(&red);
+
+ // green
+ buf.Write(&green);
+
+ // blue
+ buf.Write(&blue);
+
+ // flags
+ uint8_t tmp106;
+ tmp106 = static_cast<uint8_t>(flags);
+ buf.Write(&tmp106);
+
+ // pad0
+ Pad(&buf, 1);
+ }
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "StoreColors", false);
+}
+
+Future<void> XProto::StoreColors(const ColorMap& cmap,
+ const std::vector<ColorItem>& items) {
+ return XProto::StoreColors(StoreColorsRequest{cmap, items});
+}
+
+Future<void> XProto::StoreNamedColor(const StoreNamedColorRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& flags = request.flags;
+ auto& cmap = request.cmap;
+ auto& pixel = request.pixel;
+ uint16_t name_len{};
+ auto& name = request.name;
+
+ // major_opcode
+ uint8_t major_opcode = 90;
+ buf.Write(&major_opcode);
+
+ // flags
+ uint8_t tmp107;
+ tmp107 = static_cast<uint8_t>(flags);
+ buf.Write(&tmp107);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ // pixel
+ buf.Write(&pixel);
+
+ // name_len
+ name_len = name.size();
+ buf.Write(&name_len);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(name_len), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "StoreNamedColor", false);
+}
+
+Future<void> XProto::StoreNamedColor(const ColorFlag& flags,
+ const ColorMap& cmap,
+ const uint32_t& pixel,
+ const std::string& name) {
+ return XProto::StoreNamedColor(
+ StoreNamedColorRequest{flags, cmap, pixel, name});
+}
+
+Future<QueryColorsReply> XProto::QueryColors(
+ const QueryColorsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cmap = request.cmap;
+ auto& pixels = request.pixels;
+ size_t pixels_len = pixels.size();
+
+ // major_opcode
+ uint8_t major_opcode = 91;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ // pixels
+ DCHECK_EQ(static_cast<size_t>(pixels_len), pixels.size());
+ for (auto& pixels_elem : pixels) {
+ // pixels_elem
+ buf.Write(&pixels_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<QueryColorsReply>(&buf, "QueryColors", false);
+}
+
+Future<QueryColorsReply> XProto::QueryColors(
+ const ColorMap& cmap,
+ const std::vector<uint32_t>& pixels) {
+ return XProto::QueryColors(QueryColorsRequest{cmap, pixels});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<QueryColorsReply> detail::ReadReply<QueryColorsReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<QueryColorsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t colors_len{};
+ auto& colors = (*reply).colors;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // colors_len
+ Read(&colors_len, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // colors
+ colors.resize(colors_len);
+ for (auto& colors_elem : colors) {
+ // colors_elem
+ {
+ auto& red = colors_elem.red;
+ auto& green = colors_elem.green;
+ auto& blue = colors_elem.blue;
+
+ // red
+ Read(&red, &buf);
+
+ // green
+ Read(&green, &buf);
+
+ // blue
+ Read(&blue, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<LookupColorReply> XProto::LookupColor(
+ const LookupColorRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cmap = request.cmap;
+ uint16_t name_len{};
+ auto& name = request.name;
+
+ // major_opcode
+ uint8_t major_opcode = 92;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cmap
+ buf.Write(&cmap);
+
+ // name_len
+ name_len = name.size();
+ buf.Write(&name_len);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(name_len), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<LookupColorReply>(&buf, "LookupColor", false);
+}
+
+Future<LookupColorReply> XProto::LookupColor(const ColorMap& cmap,
+ const std::string& name) {
+ return XProto::LookupColor(LookupColorRequest{cmap, name});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<LookupColorReply> detail::ReadReply<LookupColorReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<LookupColorReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& exact_red = (*reply).exact_red;
+ auto& exact_green = (*reply).exact_green;
+ auto& exact_blue = (*reply).exact_blue;
+ auto& visual_red = (*reply).visual_red;
+ auto& visual_green = (*reply).visual_green;
+ auto& visual_blue = (*reply).visual_blue;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // exact_red
+ Read(&exact_red, &buf);
+
+ // exact_green
+ Read(&exact_green, &buf);
+
+ // exact_blue
+ Read(&exact_blue, &buf);
+
+ // visual_red
+ Read(&visual_red, &buf);
+
+ // visual_green
+ Read(&visual_green, &buf);
+
+ // visual_blue
+ Read(&visual_blue, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::CreateCursor(const CreateCursorRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cid = request.cid;
+ auto& source = request.source;
+ auto& mask = request.mask;
+ auto& fore_red = request.fore_red;
+ auto& fore_green = request.fore_green;
+ auto& fore_blue = request.fore_blue;
+ auto& back_red = request.back_red;
+ auto& back_green = request.back_green;
+ auto& back_blue = request.back_blue;
+ auto& x = request.x;
+ auto& y = request.y;
+
+ // major_opcode
+ uint8_t major_opcode = 93;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cid
+ buf.Write(&cid);
+
+ // source
+ buf.Write(&source);
+
+ // mask
+ buf.Write(&mask);
+
+ // fore_red
+ buf.Write(&fore_red);
+
+ // fore_green
+ buf.Write(&fore_green);
+
+ // fore_blue
+ buf.Write(&fore_blue);
+
+ // back_red
+ buf.Write(&back_red);
+
+ // back_green
+ buf.Write(&back_green);
+
+ // back_blue
+ buf.Write(&back_blue);
+
+ // x
+ buf.Write(&x);
+
+ // y
+ buf.Write(&y);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CreateCursor", false);
+}
+
+Future<void> XProto::CreateCursor(const Cursor& cid,
+ const Pixmap& source,
+ const Pixmap& mask,
+ const uint16_t& fore_red,
+ const uint16_t& fore_green,
+ const uint16_t& fore_blue,
+ const uint16_t& back_red,
+ const uint16_t& back_green,
+ const uint16_t& back_blue,
+ const uint16_t& x,
+ const uint16_t& y) {
+ return XProto::CreateCursor(
+ CreateCursorRequest{cid, source, mask, fore_red, fore_green, fore_blue,
+ back_red, back_green, back_blue, x, y});
+}
+
+Future<void> XProto::CreateGlyphCursor(
+ const CreateGlyphCursorRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cid = request.cid;
+ auto& source_font = request.source_font;
+ auto& mask_font = request.mask_font;
+ auto& source_char = request.source_char;
+ auto& mask_char = request.mask_char;
+ auto& fore_red = request.fore_red;
+ auto& fore_green = request.fore_green;
+ auto& fore_blue = request.fore_blue;
+ auto& back_red = request.back_red;
+ auto& back_green = request.back_green;
+ auto& back_blue = request.back_blue;
+
+ // major_opcode
+ uint8_t major_opcode = 94;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cid
+ buf.Write(&cid);
+
+ // source_font
+ buf.Write(&source_font);
+
+ // mask_font
+ buf.Write(&mask_font);
+
+ // source_char
+ buf.Write(&source_char);
+
+ // mask_char
+ buf.Write(&mask_char);
+
+ // fore_red
+ buf.Write(&fore_red);
+
+ // fore_green
+ buf.Write(&fore_green);
+
+ // fore_blue
+ buf.Write(&fore_blue);
+
+ // back_red
+ buf.Write(&back_red);
+
+ // back_green
+ buf.Write(&back_green);
+
+ // back_blue
+ buf.Write(&back_blue);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "CreateGlyphCursor", false);
+}
+
+Future<void> XProto::CreateGlyphCursor(const Cursor& cid,
+ const Font& source_font,
+ const Font& mask_font,
+ const uint16_t& source_char,
+ const uint16_t& mask_char,
+ const uint16_t& fore_red,
+ const uint16_t& fore_green,
+ const uint16_t& fore_blue,
+ const uint16_t& back_red,
+ const uint16_t& back_green,
+ const uint16_t& back_blue) {
+ return XProto::CreateGlyphCursor(CreateGlyphCursorRequest{
+ cid, source_font, mask_font, source_char, mask_char, fore_red, fore_green,
+ fore_blue, back_red, back_green, back_blue});
+}
+
+Future<void> XProto::FreeCursor(const FreeCursorRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cursor = request.cursor;
+
+ // major_opcode
+ uint8_t major_opcode = 95;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cursor
+ buf.Write(&cursor);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "FreeCursor", false);
+}
+
+Future<void> XProto::FreeCursor(const Cursor& cursor) {
+ return XProto::FreeCursor(FreeCursorRequest{cursor});
+}
+
+Future<void> XProto::RecolorCursor(const RecolorCursorRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& cursor = request.cursor;
+ auto& fore_red = request.fore_red;
+ auto& fore_green = request.fore_green;
+ auto& fore_blue = request.fore_blue;
+ auto& back_red = request.back_red;
+ auto& back_green = request.back_green;
+ auto& back_blue = request.back_blue;
+
+ // major_opcode
+ uint8_t major_opcode = 96;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // cursor
+ buf.Write(&cursor);
+
+ // fore_red
+ buf.Write(&fore_red);
+
+ // fore_green
+ buf.Write(&fore_green);
+
+ // fore_blue
+ buf.Write(&fore_blue);
+
+ // back_red
+ buf.Write(&back_red);
+
+ // back_green
+ buf.Write(&back_green);
+
+ // back_blue
+ buf.Write(&back_blue);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RecolorCursor", false);
+}
+
+Future<void> XProto::RecolorCursor(const Cursor& cursor,
+ const uint16_t& fore_red,
+ const uint16_t& fore_green,
+ const uint16_t& fore_blue,
+ const uint16_t& back_red,
+ const uint16_t& back_green,
+ const uint16_t& back_blue) {
+ return XProto::RecolorCursor(
+ RecolorCursorRequest{cursor, fore_red, fore_green, fore_blue, back_red,
+ back_green, back_blue});
+}
+
+Future<QueryBestSizeReply> XProto::QueryBestSize(
+ const QueryBestSizeRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& c_class = request.c_class;
+ auto& drawable = request.drawable;
+ auto& width = request.width;
+ auto& height = request.height;
+
+ // major_opcode
+ uint8_t major_opcode = 97;
+ buf.Write(&major_opcode);
+
+ // c_class
+ uint8_t tmp108;
+ tmp108 = static_cast<uint8_t>(c_class);
+ buf.Write(&tmp108);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<QueryBestSizeReply>(&buf, "QueryBestSize",
+ false);
+}
+
+Future<QueryBestSizeReply> XProto::QueryBestSize(const QueryShapeOf& c_class,
+ const Drawable& drawable,
+ const uint16_t& width,
+ const uint16_t& height) {
+ return XProto::QueryBestSize(
+ QueryBestSizeRequest{c_class, drawable, width, height});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<QueryBestSizeReply> detail::ReadReply<QueryBestSizeReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<QueryBestSizeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<QueryExtensionReply> XProto::QueryExtension(
+ const QueryExtensionRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ uint16_t name_len{};
+ auto& name = request.name;
+
+ // major_opcode
+ uint8_t major_opcode = 98;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // name_len
+ name_len = name.size();
+ buf.Write(&name_len);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // name
+ DCHECK_EQ(static_cast<size_t>(name_len), name.size());
+ for (auto& name_elem : name) {
+ // name_elem
+ buf.Write(&name_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<QueryExtensionReply>(&buf, "QueryExtension",
+ false);
+}
+
+Future<QueryExtensionReply> XProto::QueryExtension(const std::string& name) {
+ return XProto::QueryExtension(QueryExtensionRequest{name});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<QueryExtensionReply> detail::ReadReply<QueryExtensionReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<QueryExtensionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& present = (*reply).present;
+ auto& major_opcode = (*reply).major_opcode;
+ auto& first_event = (*reply).first_event;
+ auto& first_error = (*reply).first_error;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // present
+ Read(&present, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
+ // first_event
+ Read(&first_event, &buf);
+
+ // first_error
+ Read(&first_error, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<ListExtensionsReply> XProto::ListExtensions(
+ const ListExtensionsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 99;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<ListExtensionsReply>(&buf, "ListExtensions",
+ false);
+}
+
+Future<ListExtensionsReply> XProto::ListExtensions() {
+ return XProto::ListExtensions(ListExtensionsRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<ListExtensionsReply> detail::ReadReply<ListExtensionsReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<ListExtensionsReply>();
+
+ uint8_t names_len{};
+ auto& sequence = (*reply).sequence;
+ auto& names = (*reply).names;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // names_len
+ Read(&names_len, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad0
+ Pad(&buf, 24);
+
+ // names
+ names.resize(names_len);
+ for (auto& names_elem : names) {
+ // names_elem
+ {
+ uint8_t name_len{};
+ auto& name = names_elem.name;
+
+ // name_len
+ Read(&name_len, &buf);
+
+ // name
+ name.resize(name_len);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::ChangeKeyboardMapping(
+ const ChangeKeyboardMappingRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& keycode_count = request.keycode_count;
+ auto& first_keycode = request.first_keycode;
+ auto& keysyms_per_keycode = request.keysyms_per_keycode;
+ auto& keysyms = request.keysyms;
+ size_t keysyms_len = keysyms.size();
+
+ // major_opcode
+ uint8_t major_opcode = 100;
+ buf.Write(&major_opcode);
+
+ // keycode_count
+ buf.Write(&keycode_count);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // first_keycode
+ buf.Write(&first_keycode);
+
+ // keysyms_per_keycode
+ buf.Write(&keysyms_per_keycode);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // keysyms
+ DCHECK_EQ(static_cast<size_t>((keycode_count) * (keysyms_per_keycode)),
+ keysyms.size());
+ for (auto& keysyms_elem : keysyms) {
+ // keysyms_elem
+ buf.Write(&keysyms_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ChangeKeyboardMapping", false);
+}
+
+Future<void> XProto::ChangeKeyboardMapping(const uint8_t& keycode_count,
+ const KeyCode& first_keycode,
+ const uint8_t& keysyms_per_keycode,
+ const std::vector<KeySym>& keysyms) {
+ return XProto::ChangeKeyboardMapping(ChangeKeyboardMappingRequest{
+ keycode_count, first_keycode, keysyms_per_keycode, keysyms});
+}
+
+Future<GetKeyboardMappingReply> XProto::GetKeyboardMapping(
+ const GetKeyboardMappingRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& first_keycode = request.first_keycode;
+ auto& count = request.count;
+
+ // major_opcode
+ uint8_t major_opcode = 101;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // first_keycode
+ buf.Write(&first_keycode);
+
+ // count
+ buf.Write(&count);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetKeyboardMappingReply>(
+ &buf, "GetKeyboardMapping", false);
+}
+
+Future<GetKeyboardMappingReply> XProto::GetKeyboardMapping(
+ const KeyCode& first_keycode,
+ const uint8_t& count) {
+ return XProto::GetKeyboardMapping(
+ GetKeyboardMappingRequest{first_keycode, count});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetKeyboardMappingReply> detail::ReadReply<
+ GetKeyboardMappingReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetKeyboardMappingReply>();
+
+ auto& keysyms_per_keycode = (*reply).keysyms_per_keycode;
+ auto& sequence = (*reply).sequence;
+ auto& keysyms = (*reply).keysyms;
+ size_t keysyms_len = keysyms.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // keysyms_per_keycode
+ Read(&keysyms_per_keycode, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad0
+ Pad(&buf, 24);
+
+ // keysyms
+ keysyms.resize(length);
+ for (auto& keysyms_elem : keysyms) {
+ // keysyms_elem
+ Read(&keysyms_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::ChangeKeyboardControl(
+ const ChangeKeyboardControlRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ Keyboard value_mask{};
+ auto& value_list = request;
+
+ // major_opcode
+ uint8_t major_opcode = 102;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // value_mask
+ SwitchVar(Keyboard::KeyClickPercent, value_list.key_click_percent.has_value(),
+ true, &value_mask);
+ SwitchVar(Keyboard::BellPercent, value_list.bell_percent.has_value(), true,
+ &value_mask);
+ SwitchVar(Keyboard::BellPitch, value_list.bell_pitch.has_value(), true,
+ &value_mask);
+ SwitchVar(Keyboard::BellDuration, value_list.bell_duration.has_value(), true,
+ &value_mask);
+ SwitchVar(Keyboard::Led, value_list.led.has_value(), true, &value_mask);
+ SwitchVar(Keyboard::LedMode, value_list.led_mode.has_value(), true,
+ &value_mask);
+ SwitchVar(Keyboard::Key, value_list.key.has_value(), true, &value_mask);
+ SwitchVar(Keyboard::AutoRepeatMode, value_list.auto_repeat_mode.has_value(),
+ true, &value_mask);
+ uint32_t tmp109;
+ tmp109 = static_cast<uint32_t>(value_mask);
+ buf.Write(&tmp109);
+
+ // value_list
+ auto value_list_expr = value_mask;
+ if (CaseAnd(value_list_expr, Keyboard::KeyClickPercent)) {
+ auto& key_click_percent = *value_list.key_click_percent;
+
+ // key_click_percent
+ buf.Write(&key_click_percent);
+ }
+ if (CaseAnd(value_list_expr, Keyboard::BellPercent)) {
+ auto& bell_percent = *value_list.bell_percent;
+
+ // bell_percent
+ buf.Write(&bell_percent);
+ }
+ if (CaseAnd(value_list_expr, Keyboard::BellPitch)) {
+ auto& bell_pitch = *value_list.bell_pitch;
+
+ // bell_pitch
+ buf.Write(&bell_pitch);
+ }
+ if (CaseAnd(value_list_expr, Keyboard::BellDuration)) {
+ auto& bell_duration = *value_list.bell_duration;
+
+ // bell_duration
+ buf.Write(&bell_duration);
+ }
+ if (CaseAnd(value_list_expr, Keyboard::Led)) {
+ auto& led = *value_list.led;
+
+ // led
+ buf.Write(&led);
+ }
+ if (CaseAnd(value_list_expr, Keyboard::LedMode)) {
+ auto& led_mode = *value_list.led_mode;
+
+ // led_mode
+ uint32_t tmp110;
+ tmp110 = static_cast<uint32_t>(led_mode);
+ buf.Write(&tmp110);
+ }
+ if (CaseAnd(value_list_expr, Keyboard::Key)) {
+ auto& key = *value_list.key;
+
+ // key
+ buf.Write(&key);
+ }
+ if (CaseAnd(value_list_expr, Keyboard::AutoRepeatMode)) {
+ auto& auto_repeat_mode = *value_list.auto_repeat_mode;
+
+ // auto_repeat_mode
+ uint32_t tmp111;
+ tmp111 = static_cast<uint32_t>(auto_repeat_mode);
+ buf.Write(&tmp111);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ChangeKeyboardControl", false);
+}
+
+Future<void> XProto::ChangeKeyboardControl(
+ const base::Optional<int32_t>& key_click_percent,
+ const base::Optional<int32_t>& bell_percent,
+ const base::Optional<int32_t>& bell_pitch,
+ const base::Optional<int32_t>& bell_duration,
+ const base::Optional<uint32_t>& led,
+ const base::Optional<LedMode>& led_mode,
+ const base::Optional<KeyCode32>& key,
+ const base::Optional<AutoRepeatMode>& auto_repeat_mode) {
+ return XProto::ChangeKeyboardControl(ChangeKeyboardControlRequest{
+ key_click_percent, bell_percent, bell_pitch, bell_duration, led, led_mode,
+ key, auto_repeat_mode});
+}
+
+Future<GetKeyboardControlReply> XProto::GetKeyboardControl(
+ const GetKeyboardControlRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 103;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetKeyboardControlReply>(
+ &buf, "GetKeyboardControl", false);
+}
+
+Future<GetKeyboardControlReply> XProto::GetKeyboardControl() {
+ return XProto::GetKeyboardControl(GetKeyboardControlRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetKeyboardControlReply> detail::ReadReply<
+ GetKeyboardControlReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetKeyboardControlReply>();
+
+ auto& global_auto_repeat = (*reply).global_auto_repeat;
+ auto& sequence = (*reply).sequence;
+ auto& led_mask = (*reply).led_mask;
+ auto& key_click_percent = (*reply).key_click_percent;
+ auto& bell_percent = (*reply).bell_percent;
+ auto& bell_pitch = (*reply).bell_pitch;
+ auto& bell_duration = (*reply).bell_duration;
+ auto& auto_repeats = (*reply).auto_repeats;
+ size_t auto_repeats_len = auto_repeats.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // global_auto_repeat
+ uint8_t tmp112;
+ Read(&tmp112, &buf);
+ global_auto_repeat = static_cast<AutoRepeatMode>(tmp112);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // led_mask
+ Read(&led_mask, &buf);
+
+ // key_click_percent
+ Read(&key_click_percent, &buf);
+
+ // bell_percent
+ Read(&bell_percent, &buf);
+
+ // bell_pitch
+ Read(&bell_pitch, &buf);
+
+ // bell_duration
+ Read(&bell_duration, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // auto_repeats
+ for (auto& auto_repeats_elem : auto_repeats) {
+ // auto_repeats_elem
+ Read(&auto_repeats_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::Bell(const BellRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& percent = request.percent;
+
+ // major_opcode
+ uint8_t major_opcode = 104;
+ buf.Write(&major_opcode);
+
+ // percent
+ buf.Write(&percent);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Bell", false);
+}
+
+Future<void> XProto::Bell(const int8_t& percent) {
+ return XProto::Bell(BellRequest{percent});
+}
+
+Future<void> XProto::ChangePointerControl(
+ const ChangePointerControlRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& acceleration_numerator = request.acceleration_numerator;
+ auto& acceleration_denominator = request.acceleration_denominator;
+ auto& threshold = request.threshold;
+ auto& do_acceleration = request.do_acceleration;
+ auto& do_threshold = request.do_threshold;
+
+ // major_opcode
+ uint8_t major_opcode = 105;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // acceleration_numerator
+ buf.Write(&acceleration_numerator);
+
+ // acceleration_denominator
+ buf.Write(&acceleration_denominator);
+
+ // threshold
+ buf.Write(&threshold);
+
+ // do_acceleration
+ buf.Write(&do_acceleration);
+
+ // do_threshold
+ buf.Write(&do_threshold);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ChangePointerControl", false);
+}
+
+Future<void> XProto::ChangePointerControl(
+ const int16_t& acceleration_numerator,
+ const int16_t& acceleration_denominator,
+ const int16_t& threshold,
+ const uint8_t& do_acceleration,
+ const uint8_t& do_threshold) {
+ return XProto::ChangePointerControl(ChangePointerControlRequest{
+ acceleration_numerator, acceleration_denominator, threshold,
+ do_acceleration, do_threshold});
+}
+
+Future<GetPointerControlReply> XProto::GetPointerControl(
+ const GetPointerControlRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 106;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetPointerControlReply>(
+ &buf, "GetPointerControl", false);
+}
+
+Future<GetPointerControlReply> XProto::GetPointerControl() {
+ return XProto::GetPointerControl(GetPointerControlRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetPointerControlReply> detail::ReadReply<
+ GetPointerControlReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetPointerControlReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& acceleration_numerator = (*reply).acceleration_numerator;
+ auto& acceleration_denominator = (*reply).acceleration_denominator;
+ auto& threshold = (*reply).threshold;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // acceleration_numerator
+ Read(&acceleration_numerator, &buf);
+
+ // acceleration_denominator
+ Read(&acceleration_denominator, &buf);
+
+ // threshold
+ Read(&threshold, &buf);
+
+ // pad1
+ Pad(&buf, 18);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::SetScreenSaver(const SetScreenSaverRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& timeout = request.timeout;
+ auto& interval = request.interval;
+ auto& prefer_blanking = request.prefer_blanking;
+ auto& allow_exposures = request.allow_exposures;
+
+ // major_opcode
+ uint8_t major_opcode = 107;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // timeout
+ buf.Write(&timeout);
+
+ // interval
+ buf.Write(&interval);
+
+ // prefer_blanking
+ uint8_t tmp113;
+ tmp113 = static_cast<uint8_t>(prefer_blanking);
+ buf.Write(&tmp113);
+
+ // allow_exposures
+ uint8_t tmp114;
+ tmp114 = static_cast<uint8_t>(allow_exposures);
+ buf.Write(&tmp114);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SetScreenSaver", false);
+}
+
+Future<void> XProto::SetScreenSaver(const int16_t& timeout,
+ const int16_t& interval,
+ const Blanking& prefer_blanking,
+ const Exposures& allow_exposures) {
+ return XProto::SetScreenSaver(SetScreenSaverRequest{
+ timeout, interval, prefer_blanking, allow_exposures});
+}
+
+Future<GetScreenSaverReply> XProto::GetScreenSaver(
+ const GetScreenSaverRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 108;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetScreenSaverReply>(&buf, "GetScreenSaver",
+ false);
+}
+
+Future<GetScreenSaverReply> XProto::GetScreenSaver() {
+ return XProto::GetScreenSaver(GetScreenSaverRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetScreenSaverReply> detail::ReadReply<GetScreenSaverReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetScreenSaverReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& timeout = (*reply).timeout;
+ auto& interval = (*reply).interval;
+ auto& prefer_blanking = (*reply).prefer_blanking;
+ auto& allow_exposures = (*reply).allow_exposures;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // timeout
+ Read(&timeout, &buf);
+
+ // interval
+ Read(&interval, &buf);
+
+ // prefer_blanking
+ uint8_t tmp115;
+ Read(&tmp115, &buf);
+ prefer_blanking = static_cast<Blanking>(tmp115);
+
+ // allow_exposures
+ uint8_t tmp116;
+ Read(&tmp116, &buf);
+ allow_exposures = static_cast<Exposures>(tmp116);
+
+ // pad1
+ Pad(&buf, 18);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::ChangeHosts(const ChangeHostsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& mode = request.mode;
+ auto& family = request.family;
+ uint16_t address_len{};
+ auto& address = request.address;
+
+ // major_opcode
+ uint8_t major_opcode = 109;
+ buf.Write(&major_opcode);
+
+ // mode
+ uint8_t tmp117;
+ tmp117 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp117);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // family
+ uint8_t tmp118;
+ tmp118 = static_cast<uint8_t>(family);
+ buf.Write(&tmp118);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // address_len
+ address_len = address.size();
+ buf.Write(&address_len);
+
+ // address
+ DCHECK_EQ(static_cast<size_t>(address_len), address.size());
+ for (auto& address_elem : address) {
+ // address_elem
+ buf.Write(&address_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ChangeHosts", false);
+}
+
+Future<void> XProto::ChangeHosts(const HostMode& mode,
+ const Family& family,
+ const std::vector<uint8_t>& address) {
+ return XProto::ChangeHosts(ChangeHostsRequest{mode, family, address});
+}
+
+Future<ListHostsReply> XProto::ListHosts(const ListHostsRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 110;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<ListHostsReply>(&buf, "ListHosts", false);
+}
+
+Future<ListHostsReply> XProto::ListHosts() {
+ return XProto::ListHosts(ListHostsRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<ListHostsReply> detail::ReadReply<ListHostsReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<ListHostsReply>();
+
+ auto& mode = (*reply).mode;
+ auto& sequence = (*reply).sequence;
+ uint16_t hosts_len{};
+ auto& hosts = (*reply).hosts;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // mode
+ uint8_t tmp119;
+ Read(&tmp119, &buf);
+ mode = static_cast<AccessControl>(tmp119);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // hosts_len
+ Read(&hosts_len, &buf);
+
+ // pad0
+ Pad(&buf, 22);
+
+ // hosts
+ hosts.resize(hosts_len);
+ for (auto& hosts_elem : hosts) {
+ // hosts_elem
+ {
+ auto& family = hosts_elem.family;
+ uint16_t address_len{};
+ auto& address = hosts_elem.address;
+
+ // family
+ uint8_t tmp120;
+ Read(&tmp120, &buf);
+ family = static_cast<Family>(tmp120);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // address_len
+ Read(&address_len, &buf);
+
+ // address
+ address.resize(address_len);
+ for (auto& address_elem : address) {
+ // address_elem
+ Read(&address_elem, &buf);
+ }
+
+ // pad1
+ Align(&buf, 4);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::SetAccessControl(const SetAccessControlRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& mode = request.mode;
+
+ // major_opcode
+ uint8_t major_opcode = 111;
+ buf.Write(&major_opcode);
+
+ // mode
+ uint8_t tmp121;
+ tmp121 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp121);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SetAccessControl", false);
+}
+
+Future<void> XProto::SetAccessControl(const AccessControl& mode) {
+ return XProto::SetAccessControl(SetAccessControlRequest{mode});
+}
+
+Future<void> XProto::SetCloseDownMode(const SetCloseDownModeRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& mode = request.mode;
+
+ // major_opcode
+ uint8_t major_opcode = 112;
+ buf.Write(&major_opcode);
+
+ // mode
+ uint8_t tmp122;
+ tmp122 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp122);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SetCloseDownMode", false);
+}
+
+Future<void> XProto::SetCloseDownMode(const CloseDown& mode) {
+ return XProto::SetCloseDownMode(SetCloseDownModeRequest{mode});
+}
+
+Future<void> XProto::KillClient(const KillClientRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& resource = request.resource;
+
+ // major_opcode
+ uint8_t major_opcode = 113;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // resource
+ buf.Write(&resource);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "KillClient", false);
+}
+
+Future<void> XProto::KillClient(const uint32_t& resource) {
+ return XProto::KillClient(KillClientRequest{resource});
+}
+
+Future<void> XProto::RotateProperties(const RotatePropertiesRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ uint16_t atoms_len{};
+ auto& delta = request.delta;
+ auto& atoms = request.atoms;
+
+ // major_opcode
+ uint8_t major_opcode = 114;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // atoms_len
+ atoms_len = atoms.size();
+ buf.Write(&atoms_len);
+
+ // delta
+ buf.Write(&delta);
+
+ // atoms
+ DCHECK_EQ(static_cast<size_t>(atoms_len), atoms.size());
+ for (auto& atoms_elem : atoms) {
+ // atoms_elem
+ buf.Write(&atoms_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "RotateProperties", false);
+}
+
+Future<void> XProto::RotateProperties(const Window& window,
+ const int16_t& delta,
+ const std::vector<Atom>& atoms) {
+ return XProto::RotateProperties(
+ RotatePropertiesRequest{window, delta, atoms});
+}
+
+Future<void> XProto::ForceScreenSaver(const ForceScreenSaverRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& mode = request.mode;
+
+ // major_opcode
+ uint8_t major_opcode = 115;
+ buf.Write(&major_opcode);
+
+ // mode
+ uint8_t tmp123;
+ tmp123 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp123);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "ForceScreenSaver", false);
+}
+
+Future<void> XProto::ForceScreenSaver(const ScreenSaverMode& mode) {
+ return XProto::ForceScreenSaver(ForceScreenSaverRequest{mode});
+}
+
+Future<SetPointerMappingReply> XProto::SetPointerMapping(
+ const SetPointerMappingRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ uint8_t map_len{};
+ auto& map = request.map;
+
+ // major_opcode
+ uint8_t major_opcode = 116;
+ buf.Write(&major_opcode);
+
+ // map_len
+ map_len = map.size();
+ buf.Write(&map_len);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // map
+ DCHECK_EQ(static_cast<size_t>(map_len), map.size());
+ for (auto& map_elem : map) {
+ // map_elem
+ buf.Write(&map_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SetPointerMappingReply>(
+ &buf, "SetPointerMapping", false);
+}
+
+Future<SetPointerMappingReply> XProto::SetPointerMapping(
+ const std::vector<uint8_t>& map) {
+ return XProto::SetPointerMapping(SetPointerMappingRequest{map});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SetPointerMappingReply> detail::ReadReply<
+ SetPointerMappingReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SetPointerMappingReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ uint8_t tmp124;
+ Read(&tmp124, &buf);
+ status = static_cast<MappingStatus>(tmp124);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<GetPointerMappingReply> XProto::GetPointerMapping(
+ const GetPointerMappingRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 117;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetPointerMappingReply>(
+ &buf, "GetPointerMapping", false);
+}
+
+Future<GetPointerMappingReply> XProto::GetPointerMapping() {
+ return XProto::GetPointerMapping(GetPointerMappingRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetPointerMappingReply> detail::ReadReply<
+ GetPointerMappingReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetPointerMappingReply>();
+
+ uint8_t map_len{};
+ auto& sequence = (*reply).sequence;
+ auto& map = (*reply).map;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // map_len
+ Read(&map_len, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad0
+ Pad(&buf, 24);
+
+ // map
+ map.resize(map_len);
+ for (auto& map_elem : map) {
+ // map_elem
+ Read(&map_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<SetModifierMappingReply> XProto::SetModifierMapping(
+ const SetModifierMappingRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& keycodes_per_modifier = request.keycodes_per_modifier;
+ auto& keycodes = request.keycodes;
+ size_t keycodes_len = keycodes.size();
+
+ // major_opcode
+ uint8_t major_opcode = 118;
+ buf.Write(&major_opcode);
+
+ // keycodes_per_modifier
+ buf.Write(&keycodes_per_modifier);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // keycodes
+ DCHECK_EQ(static_cast<size_t>((keycodes_per_modifier) * (8)),
+ keycodes.size());
+ for (auto& keycodes_elem : keycodes) {
+ // keycodes_elem
+ buf.Write(&keycodes_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SetModifierMappingReply>(
+ &buf, "SetModifierMapping", false);
+}
+
+Future<SetModifierMappingReply> XProto::SetModifierMapping(
+ const uint8_t& keycodes_per_modifier,
+ const std::vector<KeyCode>& keycodes) {
+ return XProto::SetModifierMapping(
+ SetModifierMappingRequest{keycodes_per_modifier, keycodes});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SetModifierMappingReply> detail::ReadReply<
+ SetModifierMappingReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SetModifierMappingReply>();
+
+ auto& status = (*reply).status;
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // status
+ uint8_t tmp125;
+ Read(&tmp125, &buf);
+ status = static_cast<MappingStatus>(tmp125);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<GetModifierMappingReply> XProto::GetModifierMapping(
+ const GetModifierMappingRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 119;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<GetModifierMappingReply>(
+ &buf, "GetModifierMapping", false);
+}
+
+Future<GetModifierMappingReply> XProto::GetModifierMapping() {
+ return XProto::GetModifierMapping(GetModifierMappingRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<GetModifierMappingReply> detail::ReadReply<
+ GetModifierMappingReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<GetModifierMappingReply>();
+
+ auto& keycodes_per_modifier = (*reply).keycodes_per_modifier;
+ auto& sequence = (*reply).sequence;
+ auto& keycodes = (*reply).keycodes;
+ size_t keycodes_len = keycodes.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // keycodes_per_modifier
+ Read(&keycodes_per_modifier, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad0
+ Pad(&buf, 24);
+
+ // keycodes
+ keycodes.resize((keycodes_per_modifier) * (8));
+ for (auto& keycodes_elem : keycodes) {
+ // keycodes_elem
+ Read(&keycodes_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XProto::NoOperation(const NoOperationRequest& request) {
+ if (!connection_->Ready())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = 127;
+ buf.Write(&major_opcode);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "NoOperation", false);
+}
+
+Future<void> XProto::NoOperation() {
+ return XProto::NoOperation(NoOperationRequest{});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xproto.h b/chromium/ui/gfx/x/generated_protos/xproto.h
new file mode 100644
index 00000000000..3dfa0bc6fbe
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xproto.h
@@ -0,0 +1,4408 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XPROTO_H_
+#define UI_GFX_X_GENERATED_PROTOS_XPROTO_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+enum class GraphicsContext : uint32_t {};
+
+enum class ColorMap : uint32_t {};
+
+enum class Bool32 : uint32_t {};
+
+enum class VisualId : uint32_t {};
+
+enum class KeySym : uint32_t {};
+
+enum class KeyCode : uint8_t {};
+
+enum class KeyCode32 : uint32_t {};
+
+enum class Button : uint8_t {};
+
+enum class VisualClass : int {
+ StaticGray = 0,
+ GrayScale = 1,
+ StaticColor = 2,
+ PseudoColor = 3,
+ TrueColor = 4,
+ DirectColor = 5,
+};
+
+enum class EventMask : int {
+ NoEvent = 0,
+ KeyPress = 1 << 0,
+ KeyRelease = 1 << 1,
+ ButtonPress = 1 << 2,
+ ButtonRelease = 1 << 3,
+ EnterWindow = 1 << 4,
+ LeaveWindow = 1 << 5,
+ PointerMotion = 1 << 6,
+ PointerMotionHint = 1 << 7,
+ Button1Motion = 1 << 8,
+ Button2Motion = 1 << 9,
+ Button3Motion = 1 << 10,
+ Button4Motion = 1 << 11,
+ Button5Motion = 1 << 12,
+ ButtonMotion = 1 << 13,
+ KeymapState = 1 << 14,
+ Exposure = 1 << 15,
+ VisibilityChange = 1 << 16,
+ StructureNotify = 1 << 17,
+ ResizeRedirect = 1 << 18,
+ SubstructureNotify = 1 << 19,
+ SubstructureRedirect = 1 << 20,
+ FocusChange = 1 << 21,
+ PropertyChange = 1 << 22,
+ ColorMapChange = 1 << 23,
+ OwnerGrabButton = 1 << 24,
+};
+
+enum class BackingStore : int {
+ NotUseful = 0,
+ WhenMapped = 1,
+ Always = 2,
+};
+
+enum class ImageOrder : int {
+ LSBFirst = 0,
+ MSBFirst = 1,
+};
+
+enum class ModMask : int {
+ Shift = 1 << 0,
+ Lock = 1 << 1,
+ Control = 1 << 2,
+ c_1 = 1 << 3,
+ c_2 = 1 << 4,
+ c_3 = 1 << 5,
+ c_4 = 1 << 6,
+ c_5 = 1 << 7,
+ Any = 1 << 15,
+};
+
+enum class KeyButMask : int {
+ Shift = 1 << 0,
+ Lock = 1 << 1,
+ Control = 1 << 2,
+ Mod1 = 1 << 3,
+ Mod2 = 1 << 4,
+ Mod3 = 1 << 5,
+ Mod4 = 1 << 6,
+ Mod5 = 1 << 7,
+ Button1 = 1 << 8,
+ Button2 = 1 << 9,
+ Button3 = 1 << 10,
+ Button4 = 1 << 11,
+ Button5 = 1 << 12,
+};
+
+enum class Window : uint32_t {
+ None = 0,
+};
+
+enum class ButtonMask : int {
+ c_1 = 1 << 8,
+ c_2 = 1 << 9,
+ c_3 = 1 << 10,
+ c_4 = 1 << 11,
+ c_5 = 1 << 12,
+ Any = 1 << 15,
+};
+
+enum class Motion : int {
+ Normal = 0,
+ Hint = 1,
+};
+
+enum class NotifyDetail : int {
+ Ancestor = 0,
+ Virtual = 1,
+ Inferior = 2,
+ Nonlinear = 3,
+ NonlinearVirtual = 4,
+ Pointer = 5,
+ PointerRoot = 6,
+ None = 7,
+};
+
+enum class NotifyMode : int {
+ Normal = 0,
+ Grab = 1,
+ Ungrab = 2,
+ WhileGrabbed = 3,
+};
+
+enum class Visibility : int {
+ Unobscured = 0,
+ PartiallyObscured = 1,
+ FullyObscured = 2,
+};
+
+enum class Place : int {
+ OnTop = 0,
+ OnBottom = 1,
+};
+
+enum class Property : int {
+ NewValue = 0,
+ Delete = 1,
+};
+
+enum class Time : uint32_t {
+ CurrentTime = 0,
+};
+
+enum class Atom : uint32_t {
+ None = 0,
+ Any = 0,
+ PRIMARY = 1,
+ SECONDARY = 2,
+ ARC = 3,
+ ATOM = 4,
+ BITMAP = 5,
+ CARDINAL = 6,
+ COLORMAP = 7,
+ CURSOR = 8,
+ CUT_BUFFER0 = 9,
+ CUT_BUFFER1 = 10,
+ CUT_BUFFER2 = 11,
+ CUT_BUFFER3 = 12,
+ CUT_BUFFER4 = 13,
+ CUT_BUFFER5 = 14,
+ CUT_BUFFER6 = 15,
+ CUT_BUFFER7 = 16,
+ DRAWABLE = 17,
+ FONT = 18,
+ INTEGER = 19,
+ PIXMAP = 20,
+ POINT = 21,
+ RECTANGLE = 22,
+ RESOURCE_MANAGER = 23,
+ RGB_COLOR_MAP = 24,
+ RGB_BEST_MAP = 25,
+ RGB_BLUE_MAP = 26,
+ RGB_DEFAULT_MAP = 27,
+ RGB_GRAY_MAP = 28,
+ RGB_GREEN_MAP = 29,
+ RGB_RED_MAP = 30,
+ STRING = 31,
+ VISUALID = 32,
+ WINDOW = 33,
+ WM_COMMAND = 34,
+ WM_HINTS = 35,
+ WM_CLIENT_MACHINE = 36,
+ WM_ICON_NAME = 37,
+ WM_ICON_SIZE = 38,
+ WM_NAME = 39,
+ WM_NORMAL_HINTS = 40,
+ WM_SIZE_HINTS = 41,
+ WM_ZOOM_HINTS = 42,
+ MIN_SPACE = 43,
+ NORM_SPACE = 44,
+ MAX_SPACE = 45,
+ END_SPACE = 46,
+ SUPERSCRIPT_X = 47,
+ SUPERSCRIPT_Y = 48,
+ SUBSCRIPT_X = 49,
+ SUBSCRIPT_Y = 50,
+ UNDERLINE_POSITION = 51,
+ UNDERLINE_THICKNESS = 52,
+ STRIKEOUT_ASCENT = 53,
+ STRIKEOUT_DESCENT = 54,
+ ITALIC_ANGLE = 55,
+ X_HEIGHT = 56,
+ QUAD_WIDTH = 57,
+ WEIGHT = 58,
+ POINT_SIZE = 59,
+ RESOLUTION = 60,
+ COPYRIGHT = 61,
+ NOTICE = 62,
+ FONT_NAME = 63,
+ FAMILY_NAME = 64,
+ FULL_NAME = 65,
+ CAP_HEIGHT = 66,
+ WM_CLASS = 67,
+ WM_TRANSIENT_FOR = 68,
+ kLastPredefinedAtom = 68,
+};
+
+enum class ColormapState : int {
+ Uninstalled = 0,
+ Installed = 1,
+};
+
+enum class Colormap : int {
+ None = 0,
+};
+
+enum class Mapping : int {
+ Modifier = 0,
+ Keyboard = 1,
+ Pointer = 2,
+};
+
+enum class WindowClass : int {
+ CopyFromParent = 0,
+ InputOutput = 1,
+ InputOnly = 2,
+};
+
+enum class CreateWindowAttribute : int {
+ BackPixmap = 1 << 0,
+ BackPixel = 1 << 1,
+ BorderPixmap = 1 << 2,
+ BorderPixel = 1 << 3,
+ BitGravity = 1 << 4,
+ WinGravity = 1 << 5,
+ BackingStore = 1 << 6,
+ BackingPlanes = 1 << 7,
+ BackingPixel = 1 << 8,
+ OverrideRedirect = 1 << 9,
+ SaveUnder = 1 << 10,
+ EventMask = 1 << 11,
+ DontPropagate = 1 << 12,
+ Colormap = 1 << 13,
+ Cursor = 1 << 14,
+};
+
+enum class BackPixmap : int {
+ None = 0,
+ ParentRelative = 1,
+};
+
+enum class Gravity : int {
+ BitForget = 0,
+ WinUnmap = 0,
+ NorthWest = 1,
+ North = 2,
+ NorthEast = 3,
+ West = 4,
+ Center = 5,
+ East = 6,
+ SouthWest = 7,
+ South = 8,
+ SouthEast = 9,
+ Static = 10,
+};
+
+enum class MapState : int {
+ Unmapped = 0,
+ Unviewable = 1,
+ Viewable = 2,
+};
+
+enum class SetMode : int {
+ Insert = 0,
+ Delete = 1,
+};
+
+enum class ConfigWindow : int {
+ X = 1 << 0,
+ Y = 1 << 1,
+ Width = 1 << 2,
+ Height = 1 << 3,
+ BorderWidth = 1 << 4,
+ Sibling = 1 << 5,
+ StackMode = 1 << 6,
+};
+
+enum class StackMode : int {
+ Above = 0,
+ Below = 1,
+ TopIf = 2,
+ BottomIf = 3,
+ Opposite = 4,
+};
+
+enum class Circulate : int {
+ RaiseLowest = 0,
+ LowerHighest = 1,
+};
+
+enum class PropMode : int {
+ Replace = 0,
+ Prepend = 1,
+ Append = 2,
+};
+
+enum class GetPropertyType : int {
+ Any = 0,
+};
+
+enum class SendEventDest : int {
+ PointerWindow = 0,
+ ItemFocus = 1,
+};
+
+enum class GrabMode : int {
+ Sync = 0,
+ Async = 1,
+};
+
+enum class GrabStatus : int {
+ Success = 0,
+ AlreadyGrabbed = 1,
+ InvalidTime = 2,
+ NotViewable = 3,
+ Frozen = 4,
+};
+
+enum class Cursor : uint32_t {
+ None = 0,
+};
+
+enum class ButtonIndex : int {
+ Any = 0,
+ c_1 = 1,
+ c_2 = 2,
+ c_3 = 3,
+ c_4 = 4,
+ c_5 = 5,
+};
+
+enum class Grab : int {
+ Any = 0,
+};
+
+enum class Allow : int {
+ AsyncPointer = 0,
+ SyncPointer = 1,
+ ReplayPointer = 2,
+ AsyncKeyboard = 3,
+ SyncKeyboard = 4,
+ ReplayKeyboard = 5,
+ AsyncBoth = 6,
+ SyncBoth = 7,
+};
+
+enum class InputFocus : int {
+ None = 0,
+ PointerRoot = 1,
+ Parent = 2,
+ FollowKeyboard = 3,
+};
+
+enum class FontDraw : int {
+ LeftToRight = 0,
+ RightToLeft = 1,
+};
+
+enum class GraphicsContextAttribute : int {
+ Function = 1 << 0,
+ PlaneMask = 1 << 1,
+ Foreground = 1 << 2,
+ Background = 1 << 3,
+ LineWidth = 1 << 4,
+ LineStyle = 1 << 5,
+ CapStyle = 1 << 6,
+ JoinStyle = 1 << 7,
+ FillStyle = 1 << 8,
+ FillRule = 1 << 9,
+ Tile = 1 << 10,
+ Stipple = 1 << 11,
+ TileStippleOriginX = 1 << 12,
+ TileStippleOriginY = 1 << 13,
+ Font = 1 << 14,
+ SubwindowMode = 1 << 15,
+ GraphicsExposures = 1 << 16,
+ ClipOriginX = 1 << 17,
+ ClipOriginY = 1 << 18,
+ ClipMask = 1 << 19,
+ DashOffset = 1 << 20,
+ DashList = 1 << 21,
+ ArcMode = 1 << 22,
+};
+
+enum class Gx : int {
+ clear = 0,
+ c_and = 1,
+ andReverse = 2,
+ copy = 3,
+ andInverted = 4,
+ noop = 5,
+ c_xor = 6,
+ c_or = 7,
+ nor = 8,
+ equiv = 9,
+ invert = 10,
+ orReverse = 11,
+ copyInverted = 12,
+ orInverted = 13,
+ nand = 14,
+ set = 15,
+};
+
+enum class LineStyle : int {
+ Solid = 0,
+ OnOffDash = 1,
+ DoubleDash = 2,
+};
+
+enum class CapStyle : int {
+ NotLast = 0,
+ Butt = 1,
+ Round = 2,
+ Projecting = 3,
+};
+
+enum class JoinStyle : int {
+ Miter = 0,
+ Round = 1,
+ Bevel = 2,
+};
+
+enum class FillStyle : int {
+ Solid = 0,
+ Tiled = 1,
+ Stippled = 2,
+ OpaqueStippled = 3,
+};
+
+enum class FillRule : int {
+ EvenOdd = 0,
+ Winding = 1,
+};
+
+enum class SubwindowMode : int {
+ ClipByChildren = 0,
+ IncludeInferiors = 1,
+};
+
+enum class ArcMode : int {
+ Chord = 0,
+ PieSlice = 1,
+};
+
+enum class ClipOrdering : int {
+ Unsorted = 0,
+ YSorted = 1,
+ YXSorted = 2,
+ YXBanded = 3,
+};
+
+enum class CoordMode : int {
+ Origin = 0,
+ Previous = 1,
+};
+
+enum class PolyShape : int {
+ Complex = 0,
+ Nonconvex = 1,
+ Convex = 2,
+};
+
+enum class ImageFormat : int {
+ XYBitmap = 0,
+ XYPixmap = 1,
+ ZPixmap = 2,
+};
+
+enum class ColormapAlloc : int {
+ None = 0,
+ All = 1,
+};
+
+enum class ColorFlag : int {
+ Red = 1 << 0,
+ Green = 1 << 1,
+ Blue = 1 << 2,
+};
+
+enum class Pixmap : uint32_t {
+ None = 0,
+};
+
+enum class Font : uint32_t {
+ None = 0,
+};
+
+enum class QueryShapeOf : int {
+ LargestCursor = 0,
+ FastestTile = 1,
+ FastestStipple = 2,
+};
+
+enum class Keyboard : int {
+ KeyClickPercent = 1 << 0,
+ BellPercent = 1 << 1,
+ BellPitch = 1 << 2,
+ BellDuration = 1 << 3,
+ Led = 1 << 4,
+ LedMode = 1 << 5,
+ Key = 1 << 6,
+ AutoRepeatMode = 1 << 7,
+};
+
+enum class LedMode : int {
+ Off = 0,
+ On = 1,
+};
+
+enum class AutoRepeatMode : int {
+ Off = 0,
+ On = 1,
+ Default = 2,
+};
+
+enum class Blanking : int {
+ NotPreferred = 0,
+ Preferred = 1,
+ Default = 2,
+};
+
+enum class Exposures : int {
+ NotAllowed = 0,
+ Allowed = 1,
+ Default = 2,
+};
+
+enum class HostMode : int {
+ Insert = 0,
+ Delete = 1,
+};
+
+enum class Family : int {
+ Internet = 0,
+ DECnet = 1,
+ Chaos = 2,
+ ServerInterpreted = 5,
+ Internet6 = 6,
+};
+
+enum class AccessControl : int {
+ Disable = 0,
+ Enable = 1,
+};
+
+enum class CloseDown : int {
+ DestroyAll = 0,
+ RetainPermanent = 1,
+ RetainTemporary = 2,
+};
+
+enum class Kill : int {
+ AllTemporary = 0,
+};
+
+enum class ScreenSaverMode : int {
+ Reset = 0,
+ Active = 1,
+};
+
+enum class MappingStatus : int {
+ Success = 0,
+ Busy = 1,
+ Failure = 2,
+};
+
+enum class MapIndex : int {
+ Shift = 0,
+ Lock = 1,
+ Control = 2,
+ c_1 = 3,
+ c_2 = 4,
+ c_3 = 5,
+ c_4 = 6,
+ c_5 = 7,
+};
+
+struct Drawable {
+ Drawable() : value{} {}
+
+ Drawable(Window value) : value{static_cast<uint32_t>(value)} {}
+ operator Window() const { return static_cast<Window>(value); }
+
+ Drawable(Pixmap value) : value{static_cast<uint32_t>(value)} {}
+ operator Pixmap() const { return static_cast<Pixmap>(value); }
+
+ uint32_t value{};
+};
+
+struct Fontable {
+ Fontable() : value{} {}
+
+ Fontable(Font value) : value{static_cast<uint32_t>(value)} {}
+ operator Font() const { return static_cast<Font>(value); }
+
+ Fontable(GraphicsContext value) : value{static_cast<uint32_t>(value)} {}
+ operator GraphicsContext() const {
+ return static_cast<GraphicsContext>(value);
+ }
+
+ uint32_t value{};
+};
+
+struct Char16 {
+ uint8_t byte1{};
+ uint8_t byte2{};
+};
+
+struct Point {
+ int16_t x{};
+ int16_t y{};
+};
+
+struct Rectangle {
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+};
+
+struct Arc {
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ int16_t angle1{};
+ int16_t angle2{};
+};
+
+struct Format {
+ uint8_t depth{};
+ uint8_t bits_per_pixel{};
+ uint8_t scanline_pad{};
+};
+
+struct VisualType {
+ VisualId visual_id{};
+ VisualClass c_class{};
+ uint8_t bits_per_rgb_value{};
+ uint16_t colormap_entries{};
+ uint32_t red_mask{};
+ uint32_t green_mask{};
+ uint32_t blue_mask{};
+};
+
+struct Depth {
+ uint8_t depth{};
+ std::vector<VisualType> visuals{};
+};
+
+struct Screen {
+ Window root{};
+ ColorMap default_colormap{};
+ uint32_t white_pixel{};
+ uint32_t black_pixel{};
+ EventMask current_input_masks{};
+ uint16_t width_in_pixels{};
+ uint16_t height_in_pixels{};
+ uint16_t width_in_millimeters{};
+ uint16_t height_in_millimeters{};
+ uint16_t min_installed_maps{};
+ uint16_t max_installed_maps{};
+ VisualId root_visual{};
+ BackingStore backing_stores{};
+ uint8_t save_unders{};
+ uint8_t root_depth{};
+ std::vector<Depth> allowed_depths{};
+};
+
+struct SetupRequest {
+ uint8_t byte_order{};
+ uint16_t protocol_major_version{};
+ uint16_t protocol_minor_version{};
+ std::string authorization_protocol_name{};
+ std::string authorization_protocol_data{};
+};
+
+struct SetupFailed {
+ uint8_t status{};
+ uint16_t protocol_major_version{};
+ uint16_t protocol_minor_version{};
+ uint16_t length{};
+ std::string reason{};
+};
+
+struct SetupAuthenticate {
+ uint8_t status{};
+ uint16_t length{};
+ std::string reason{};
+};
+
+struct Setup {
+ uint8_t status{};
+ uint16_t protocol_major_version{};
+ uint16_t protocol_minor_version{};
+ uint16_t length{};
+ uint32_t release_number{};
+ uint32_t resource_id_base{};
+ uint32_t resource_id_mask{};
+ uint32_t motion_buffer_size{};
+ uint16_t maximum_request_length{};
+ ImageOrder image_byte_order{};
+ ImageOrder bitmap_format_bit_order{};
+ uint8_t bitmap_format_scanline_unit{};
+ uint8_t bitmap_format_scanline_pad{};
+ KeyCode min_keycode{};
+ KeyCode max_keycode{};
+ std::string vendor{};
+ std::vector<Format> pixmap_formats{};
+ std::vector<Screen> roots{};
+};
+
+struct KeyEvent {
+ static constexpr int type_id = 52;
+ enum Opcode {
+ Press = 2,
+ Release = 3,
+ } opcode{};
+ bool send_event{};
+ KeyCode detail{};
+ uint16_t sequence{};
+ Time time{};
+ Window root{};
+ Window event{};
+ Window child{};
+ int16_t root_x{};
+ int16_t root_y{};
+ int16_t event_x{};
+ int16_t event_y{};
+ KeyButMask state{};
+ uint8_t same_screen{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct ButtonEvent {
+ static constexpr int type_id = 53;
+ enum Opcode {
+ Press = 4,
+ Release = 5,
+ } opcode{};
+ bool send_event{};
+ Button detail{};
+ uint16_t sequence{};
+ Time time{};
+ Window root{};
+ Window event{};
+ Window child{};
+ int16_t root_x{};
+ int16_t root_y{};
+ int16_t event_x{};
+ int16_t event_y{};
+ KeyButMask state{};
+ uint8_t same_screen{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct MotionNotifyEvent {
+ static constexpr int type_id = 54;
+ static constexpr uint8_t opcode = 6;
+ bool send_event{};
+ Motion detail{};
+ uint16_t sequence{};
+ Time time{};
+ Window root{};
+ Window event{};
+ Window child{};
+ int16_t root_x{};
+ int16_t root_y{};
+ int16_t event_x{};
+ int16_t event_y{};
+ KeyButMask state{};
+ uint8_t same_screen{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct CrossingEvent {
+ static constexpr int type_id = 55;
+ enum Opcode {
+ EnterNotify = 7,
+ LeaveNotify = 8,
+ } opcode{};
+ bool send_event{};
+ NotifyDetail detail{};
+ uint16_t sequence{};
+ Time time{};
+ Window root{};
+ Window event{};
+ Window child{};
+ int16_t root_x{};
+ int16_t root_y{};
+ int16_t event_x{};
+ int16_t event_y{};
+ KeyButMask state{};
+ NotifyMode mode{};
+ uint8_t same_screen_focus{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct FocusEvent {
+ static constexpr int type_id = 56;
+ enum Opcode {
+ In = 9,
+ Out = 10,
+ } opcode{};
+ bool send_event{};
+ NotifyDetail detail{};
+ uint16_t sequence{};
+ Window event{};
+ NotifyMode mode{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct KeymapNotifyEvent {
+ static constexpr int type_id = 57;
+ static constexpr uint8_t opcode = 11;
+ bool send_event{};
+ std::array<uint8_t, 31> keys{};
+
+ x11::Window* GetWindow() { return nullptr; }
+};
+
+struct ExposeEvent {
+ static constexpr int type_id = 58;
+ static constexpr uint8_t opcode = 12;
+ bool send_event{};
+ uint16_t sequence{};
+ Window window{};
+ uint16_t x{};
+ uint16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t count{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+};
+
+struct GraphicsExposureEvent {
+ static constexpr int type_id = 59;
+ static constexpr uint8_t opcode = 13;
+ bool send_event{};
+ uint16_t sequence{};
+ Drawable drawable{};
+ uint16_t x{};
+ uint16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t minor_opcode{};
+ uint16_t count{};
+ uint8_t major_opcode{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&drawable); }
+};
+
+struct NoExposureEvent {
+ static constexpr int type_id = 60;
+ static constexpr uint8_t opcode = 14;
+ bool send_event{};
+ uint16_t sequence{};
+ Drawable drawable{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&drawable); }
+};
+
+struct VisibilityNotifyEvent {
+ static constexpr int type_id = 61;
+ static constexpr uint8_t opcode = 15;
+ bool send_event{};
+ uint16_t sequence{};
+ Window window{};
+ Visibility state{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+};
+
+struct CreateNotifyEvent {
+ static constexpr int type_id = 62;
+ static constexpr uint8_t opcode = 16;
+ bool send_event{};
+ uint16_t sequence{};
+ Window parent{};
+ Window window{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t border_width{};
+ uint8_t override_redirect{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+};
+
+struct DestroyNotifyEvent {
+ static constexpr int type_id = 63;
+ static constexpr uint8_t opcode = 17;
+ bool send_event{};
+ uint16_t sequence{};
+ Window event{};
+ Window window{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct UnmapNotifyEvent {
+ static constexpr int type_id = 64;
+ static constexpr uint8_t opcode = 18;
+ bool send_event{};
+ uint16_t sequence{};
+ Window event{};
+ Window window{};
+ uint8_t from_configure{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct MapNotifyEvent {
+ static constexpr int type_id = 65;
+ static constexpr uint8_t opcode = 19;
+ bool send_event{};
+ uint16_t sequence{};
+ Window event{};
+ Window window{};
+ uint8_t override_redirect{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct MapRequestEvent {
+ static constexpr int type_id = 66;
+ static constexpr uint8_t opcode = 20;
+ bool send_event{};
+ uint16_t sequence{};
+ Window parent{};
+ Window window{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+};
+
+struct ReparentNotifyEvent {
+ static constexpr int type_id = 67;
+ static constexpr uint8_t opcode = 21;
+ bool send_event{};
+ uint16_t sequence{};
+ Window event{};
+ Window window{};
+ Window parent{};
+ int16_t x{};
+ int16_t y{};
+ uint8_t override_redirect{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct ConfigureNotifyEvent {
+ static constexpr int type_id = 68;
+ static constexpr uint8_t opcode = 22;
+ bool send_event{};
+ uint16_t sequence{};
+ Window event{};
+ Window window{};
+ Window above_sibling{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t border_width{};
+ uint8_t override_redirect{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct ConfigureRequestEvent {
+ static constexpr int type_id = 69;
+ static constexpr uint8_t opcode = 23;
+ bool send_event{};
+ StackMode stack_mode{};
+ uint16_t sequence{};
+ Window parent{};
+ Window window{};
+ Window sibling{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t border_width{};
+ ConfigWindow value_mask{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+};
+
+struct GravityNotifyEvent {
+ static constexpr int type_id = 70;
+ static constexpr uint8_t opcode = 24;
+ bool send_event{};
+ uint16_t sequence{};
+ Window event{};
+ Window window{};
+ int16_t x{};
+ int16_t y{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct ResizeRequestEvent {
+ static constexpr int type_id = 71;
+ static constexpr uint8_t opcode = 25;
+ bool send_event{};
+ uint16_t sequence{};
+ Window window{};
+ uint16_t width{};
+ uint16_t height{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+};
+
+struct CirculateEvent {
+ static constexpr int type_id = 72;
+ enum Opcode {
+ Notify = 26,
+ Request = 27,
+ } opcode{};
+ bool send_event{};
+ uint16_t sequence{};
+ Window event{};
+ Window window{};
+ Place place{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+};
+
+struct PropertyNotifyEvent {
+ static constexpr int type_id = 73;
+ static constexpr uint8_t opcode = 28;
+ bool send_event{};
+ uint16_t sequence{};
+ Window window{};
+ Atom atom{};
+ Time time{};
+ Property state{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+};
+
+struct SelectionClearEvent {
+ static constexpr int type_id = 74;
+ static constexpr uint8_t opcode = 29;
+ bool send_event{};
+ uint16_t sequence{};
+ Time time{};
+ Window owner{};
+ Atom selection{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&owner); }
+};
+
+struct SelectionRequestEvent {
+ static constexpr int type_id = 75;
+ static constexpr uint8_t opcode = 30;
+ bool send_event{};
+ uint16_t sequence{};
+ Time time{};
+ Window owner{};
+ Window requestor{};
+ Atom selection{};
+ Atom target{};
+ Atom property{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&owner); }
+};
+
+struct SelectionNotifyEvent {
+ static constexpr int type_id = 76;
+ static constexpr uint8_t opcode = 31;
+ bool send_event{};
+ uint16_t sequence{};
+ Time time{};
+ Window requestor{};
+ Atom selection{};
+ Atom target{};
+ Atom property{};
+
+ x11::Window* GetWindow() {
+ return reinterpret_cast<x11::Window*>(&requestor);
+ }
+};
+
+struct ColormapNotifyEvent {
+ static constexpr int type_id = 77;
+ static constexpr uint8_t opcode = 32;
+ bool send_event{};
+ uint16_t sequence{};
+ Window window{};
+ ColorMap colormap{};
+ uint8_t c_new{};
+ ColormapState state{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+};
+
+union ClientMessageData {
+ ClientMessageData() { memset(this, 0, sizeof(*this)); }
+
+ std::array<uint8_t, 20> data8;
+ std::array<uint16_t, 10> data16;
+ std::array<uint32_t, 5> data32;
+};
+static_assert(std::is_trivially_copyable<ClientMessageData>::value, "");
+
+struct ClientMessageEvent {
+ static constexpr int type_id = 78;
+ static constexpr uint8_t opcode = 33;
+ bool send_event{};
+ uint8_t format{};
+ uint16_t sequence{};
+ Window window{};
+ Atom type{};
+ ClientMessageData data{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
+};
+
+struct MappingNotifyEvent {
+ static constexpr int type_id = 79;
+ static constexpr uint8_t opcode = 34;
+ bool send_event{};
+ uint16_t sequence{};
+ Mapping request{};
+ KeyCode first_keycode{};
+ uint8_t count{};
+
+ x11::Window* GetWindow() { return nullptr; }
+};
+
+struct GeGenericEvent {
+ static constexpr int type_id = 80;
+ static constexpr uint8_t opcode = 35;
+ bool send_event{};
+ uint16_t sequence{};
+
+ x11::Window* GetWindow() { return nullptr; }
+};
+
+struct RequestError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct ValueError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct WindowError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct PixmapError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct AtomError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct CursorError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct FontError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct MatchError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct DrawableError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct AccessError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct AllocError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct ColormapError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct GContextError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct IDChoiceError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct NameError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct LengthError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct ImplementationError : public x11::Error {
+ uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
+
+ std::string ToString() const override;
+};
+
+struct TimeCoord {
+ Time time{};
+ int16_t x{};
+ int16_t y{};
+};
+
+struct FontProperty {
+ Atom name{};
+ uint32_t value{};
+};
+
+struct CharInfo {
+ int16_t left_side_bearing{};
+ int16_t right_side_bearing{};
+ int16_t character_width{};
+ int16_t ascent{};
+ int16_t descent{};
+ uint16_t attributes{};
+};
+
+struct Str {
+ std::string name{};
+};
+
+struct Segment {
+ int16_t x1{};
+ int16_t y1{};
+ int16_t x2{};
+ int16_t y2{};
+};
+
+struct ColorItem {
+ uint32_t pixel{};
+ uint16_t red{};
+ uint16_t green{};
+ uint16_t blue{};
+ ColorFlag flags{};
+};
+
+struct Rgb {
+ uint16_t red{};
+ uint16_t green{};
+ uint16_t blue{};
+};
+
+struct Host {
+ Family family{};
+ std::vector<uint8_t> address{};
+};
+
+struct CreateWindowRequest {
+ uint8_t depth{};
+ Window wid{};
+ Window parent{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t border_width{};
+ WindowClass c_class{};
+ VisualId visual{};
+ base::Optional<Pixmap> background_pixmap{};
+ base::Optional<uint32_t> background_pixel{};
+ base::Optional<Pixmap> border_pixmap{};
+ base::Optional<uint32_t> border_pixel{};
+ base::Optional<Gravity> bit_gravity{};
+ base::Optional<Gravity> win_gravity{};
+ base::Optional<BackingStore> backing_store{};
+ base::Optional<uint32_t> backing_planes{};
+ base::Optional<uint32_t> backing_pixel{};
+ base::Optional<Bool32> override_redirect{};
+ base::Optional<Bool32> save_under{};
+ base::Optional<EventMask> event_mask{};
+ base::Optional<EventMask> do_not_propogate_mask{};
+ base::Optional<ColorMap> colormap{};
+ base::Optional<Cursor> cursor{};
+};
+
+using CreateWindowResponse = Response<void>;
+
+struct ChangeWindowAttributesRequest {
+ Window window{};
+ base::Optional<Pixmap> background_pixmap{};
+ base::Optional<uint32_t> background_pixel{};
+ base::Optional<Pixmap> border_pixmap{};
+ base::Optional<uint32_t> border_pixel{};
+ base::Optional<Gravity> bit_gravity{};
+ base::Optional<Gravity> win_gravity{};
+ base::Optional<BackingStore> backing_store{};
+ base::Optional<uint32_t> backing_planes{};
+ base::Optional<uint32_t> backing_pixel{};
+ base::Optional<Bool32> override_redirect{};
+ base::Optional<Bool32> save_under{};
+ base::Optional<EventMask> event_mask{};
+ base::Optional<EventMask> do_not_propogate_mask{};
+ base::Optional<ColorMap> colormap{};
+ base::Optional<Cursor> cursor{};
+};
+
+using ChangeWindowAttributesResponse = Response<void>;
+
+struct GetWindowAttributesRequest {
+ Window window{};
+};
+
+struct GetWindowAttributesReply {
+ BackingStore backing_store{};
+ uint16_t sequence{};
+ VisualId visual{};
+ WindowClass c_class{};
+ Gravity bit_gravity{};
+ Gravity win_gravity{};
+ uint32_t backing_planes{};
+ uint32_t backing_pixel{};
+ uint8_t save_under{};
+ uint8_t map_is_installed{};
+ MapState map_state{};
+ uint8_t override_redirect{};
+ ColorMap colormap{};
+ EventMask all_event_masks{};
+ EventMask your_event_mask{};
+ EventMask do_not_propagate_mask{};
+};
+
+using GetWindowAttributesResponse = Response<GetWindowAttributesReply>;
+
+struct DestroyWindowRequest {
+ Window window{};
+};
+
+using DestroyWindowResponse = Response<void>;
+
+struct DestroySubwindowsRequest {
+ Window window{};
+};
+
+using DestroySubwindowsResponse = Response<void>;
+
+struct ChangeSaveSetRequest {
+ SetMode mode{};
+ Window window{};
+};
+
+using ChangeSaveSetResponse = Response<void>;
+
+struct ReparentWindowRequest {
+ Window window{};
+ Window parent{};
+ int16_t x{};
+ int16_t y{};
+};
+
+using ReparentWindowResponse = Response<void>;
+
+struct MapWindowRequest {
+ Window window{};
+};
+
+using MapWindowResponse = Response<void>;
+
+struct MapSubwindowsRequest {
+ Window window{};
+};
+
+using MapSubwindowsResponse = Response<void>;
+
+struct UnmapWindowRequest {
+ Window window{};
+};
+
+using UnmapWindowResponse = Response<void>;
+
+struct UnmapSubwindowsRequest {
+ Window window{};
+};
+
+using UnmapSubwindowsResponse = Response<void>;
+
+struct ConfigureWindowRequest {
+ Window window{};
+ base::Optional<int32_t> x{};
+ base::Optional<int32_t> y{};
+ base::Optional<uint32_t> width{};
+ base::Optional<uint32_t> height{};
+ base::Optional<uint32_t> border_width{};
+ base::Optional<Window> sibling{};
+ base::Optional<StackMode> stack_mode{};
+};
+
+using ConfigureWindowResponse = Response<void>;
+
+struct CirculateWindowRequest {
+ Circulate direction{};
+ Window window{};
+};
+
+using CirculateWindowResponse = Response<void>;
+
+struct GetGeometryRequest {
+ Drawable drawable{};
+};
+
+struct GetGeometryReply {
+ uint8_t depth{};
+ uint16_t sequence{};
+ Window root{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint16_t border_width{};
+};
+
+using GetGeometryResponse = Response<GetGeometryReply>;
+
+struct QueryTreeRequest {
+ Window window{};
+};
+
+struct QueryTreeReply {
+ uint16_t sequence{};
+ Window root{};
+ Window parent{};
+ std::vector<Window> children{};
+};
+
+using QueryTreeResponse = Response<QueryTreeReply>;
+
+struct InternAtomRequest {
+ uint8_t only_if_exists{};
+ std::string name{};
+};
+
+struct InternAtomReply {
+ uint16_t sequence{};
+ Atom atom{};
+};
+
+using InternAtomResponse = Response<InternAtomReply>;
+
+struct GetAtomNameRequest {
+ Atom atom{};
+};
+
+struct GetAtomNameReply {
+ uint16_t sequence{};
+ std::string name{};
+};
+
+using GetAtomNameResponse = Response<GetAtomNameReply>;
+
+struct ChangePropertyRequest {
+ PropMode mode{};
+ Window window{};
+ Atom property{};
+ Atom type{};
+ uint8_t format{};
+ uint32_t data_len{};
+ scoped_refptr<base::RefCountedMemory> data{};
+};
+
+using ChangePropertyResponse = Response<void>;
+
+struct DeletePropertyRequest {
+ Window window{};
+ Atom property{};
+};
+
+using DeletePropertyResponse = Response<void>;
+
+struct GetPropertyRequest {
+ uint8_t c_delete{};
+ Window window{};
+ Atom property{};
+ Atom type{};
+ uint32_t long_offset{};
+ uint32_t long_length{};
+};
+
+struct GetPropertyReply {
+ uint8_t format{};
+ uint16_t sequence{};
+ Atom type{};
+ uint32_t bytes_after{};
+ uint32_t value_len{};
+ scoped_refptr<base::RefCountedMemory> value{};
+};
+
+using GetPropertyResponse = Response<GetPropertyReply>;
+
+struct ListPropertiesRequest {
+ Window window{};
+};
+
+struct ListPropertiesReply {
+ uint16_t sequence{};
+ std::vector<Atom> atoms{};
+};
+
+using ListPropertiesResponse = Response<ListPropertiesReply>;
+
+struct SetSelectionOwnerRequest {
+ Window owner{};
+ Atom selection{};
+ Time time{};
+};
+
+using SetSelectionOwnerResponse = Response<void>;
+
+struct GetSelectionOwnerRequest {
+ Atom selection{};
+};
+
+struct GetSelectionOwnerReply {
+ uint16_t sequence{};
+ Window owner{};
+};
+
+using GetSelectionOwnerResponse = Response<GetSelectionOwnerReply>;
+
+struct ConvertSelectionRequest {
+ Window requestor{};
+ Atom selection{};
+ Atom target{};
+ Atom property{};
+ Time time{};
+};
+
+using ConvertSelectionResponse = Response<void>;
+
+struct SendEventRequest {
+ uint8_t propagate{};
+ Window destination{};
+ EventMask event_mask{};
+ std::array<char, 32> event{};
+};
+
+using SendEventResponse = Response<void>;
+
+struct GrabPointerRequest {
+ uint8_t owner_events{};
+ Window grab_window{};
+ EventMask event_mask{};
+ GrabMode pointer_mode{};
+ GrabMode keyboard_mode{};
+ Window confine_to{};
+ Cursor cursor{};
+ Time time{};
+};
+
+struct GrabPointerReply {
+ GrabStatus status{};
+ uint16_t sequence{};
+};
+
+using GrabPointerResponse = Response<GrabPointerReply>;
+
+struct UngrabPointerRequest {
+ Time time{};
+};
+
+using UngrabPointerResponse = Response<void>;
+
+struct GrabButtonRequest {
+ uint8_t owner_events{};
+ Window grab_window{};
+ EventMask event_mask{};
+ GrabMode pointer_mode{};
+ GrabMode keyboard_mode{};
+ Window confine_to{};
+ Cursor cursor{};
+ ButtonIndex button{};
+ ModMask modifiers{};
+};
+
+using GrabButtonResponse = Response<void>;
+
+struct UngrabButtonRequest {
+ ButtonIndex button{};
+ Window grab_window{};
+ ModMask modifiers{};
+};
+
+using UngrabButtonResponse = Response<void>;
+
+struct ChangeActivePointerGrabRequest {
+ Cursor cursor{};
+ Time time{};
+ EventMask event_mask{};
+};
+
+using ChangeActivePointerGrabResponse = Response<void>;
+
+struct GrabKeyboardRequest {
+ uint8_t owner_events{};
+ Window grab_window{};
+ Time time{};
+ GrabMode pointer_mode{};
+ GrabMode keyboard_mode{};
+};
+
+struct GrabKeyboardReply {
+ GrabStatus status{};
+ uint16_t sequence{};
+};
+
+using GrabKeyboardResponse = Response<GrabKeyboardReply>;
+
+struct UngrabKeyboardRequest {
+ Time time{};
+};
+
+using UngrabKeyboardResponse = Response<void>;
+
+struct GrabKeyRequest {
+ uint8_t owner_events{};
+ Window grab_window{};
+ ModMask modifiers{};
+ KeyCode key{};
+ GrabMode pointer_mode{};
+ GrabMode keyboard_mode{};
+};
+
+using GrabKeyResponse = Response<void>;
+
+struct UngrabKeyRequest {
+ KeyCode key{};
+ Window grab_window{};
+ ModMask modifiers{};
+};
+
+using UngrabKeyResponse = Response<void>;
+
+struct AllowEventsRequest {
+ Allow mode{};
+ Time time{};
+};
+
+using AllowEventsResponse = Response<void>;
+
+struct GrabServerRequest {};
+
+using GrabServerResponse = Response<void>;
+
+struct UngrabServerRequest {};
+
+using UngrabServerResponse = Response<void>;
+
+struct QueryPointerRequest {
+ Window window{};
+};
+
+struct QueryPointerReply {
+ uint8_t same_screen{};
+ uint16_t sequence{};
+ Window root{};
+ Window child{};
+ int16_t root_x{};
+ int16_t root_y{};
+ int16_t win_x{};
+ int16_t win_y{};
+ KeyButMask mask{};
+};
+
+using QueryPointerResponse = Response<QueryPointerReply>;
+
+struct GetMotionEventsRequest {
+ Window window{};
+ Time start{};
+ Time stop{};
+};
+
+struct GetMotionEventsReply {
+ uint16_t sequence{};
+ std::vector<TimeCoord> events{};
+};
+
+using GetMotionEventsResponse = Response<GetMotionEventsReply>;
+
+struct TranslateCoordinatesRequest {
+ Window src_window{};
+ Window dst_window{};
+ int16_t src_x{};
+ int16_t src_y{};
+};
+
+struct TranslateCoordinatesReply {
+ uint8_t same_screen{};
+ uint16_t sequence{};
+ Window child{};
+ int16_t dst_x{};
+ int16_t dst_y{};
+};
+
+using TranslateCoordinatesResponse = Response<TranslateCoordinatesReply>;
+
+struct WarpPointerRequest {
+ Window src_window{};
+ Window dst_window{};
+ int16_t src_x{};
+ int16_t src_y{};
+ uint16_t src_width{};
+ uint16_t src_height{};
+ int16_t dst_x{};
+ int16_t dst_y{};
+};
+
+using WarpPointerResponse = Response<void>;
+
+struct SetInputFocusRequest {
+ InputFocus revert_to{};
+ Window focus{};
+ Time time{};
+};
+
+using SetInputFocusResponse = Response<void>;
+
+struct GetInputFocusRequest {};
+
+struct GetInputFocusReply {
+ InputFocus revert_to{};
+ uint16_t sequence{};
+ Window focus{};
+};
+
+using GetInputFocusResponse = Response<GetInputFocusReply>;
+
+struct QueryKeymapRequest {};
+
+struct QueryKeymapReply {
+ uint16_t sequence{};
+ std::array<uint8_t, 32> keys{};
+};
+
+using QueryKeymapResponse = Response<QueryKeymapReply>;
+
+struct OpenFontRequest {
+ Font fid{};
+ std::string name{};
+};
+
+using OpenFontResponse = Response<void>;
+
+struct CloseFontRequest {
+ Font font{};
+};
+
+using CloseFontResponse = Response<void>;
+
+struct QueryFontRequest {
+ Fontable font{};
+};
+
+struct QueryFontReply {
+ uint16_t sequence{};
+ CharInfo min_bounds{};
+ CharInfo max_bounds{};
+ uint16_t min_char_or_byte2{};
+ uint16_t max_char_or_byte2{};
+ uint16_t default_char{};
+ FontDraw draw_direction{};
+ uint8_t min_byte1{};
+ uint8_t max_byte1{};
+ uint8_t all_chars_exist{};
+ int16_t font_ascent{};
+ int16_t font_descent{};
+ std::vector<FontProperty> properties{};
+ std::vector<CharInfo> char_infos{};
+};
+
+using QueryFontResponse = Response<QueryFontReply>;
+
+struct QueryTextExtentsRequest {
+ Fontable font{};
+ std::vector<Char16> string{};
+};
+
+struct QueryTextExtentsReply {
+ FontDraw draw_direction{};
+ uint16_t sequence{};
+ int16_t font_ascent{};
+ int16_t font_descent{};
+ int16_t overall_ascent{};
+ int16_t overall_descent{};
+ int32_t overall_width{};
+ int32_t overall_left{};
+ int32_t overall_right{};
+};
+
+using QueryTextExtentsResponse = Response<QueryTextExtentsReply>;
+
+struct ListFontsRequest {
+ uint16_t max_names{};
+ std::string pattern{};
+};
+
+struct ListFontsReply {
+ uint16_t sequence{};
+ std::vector<Str> names{};
+};
+
+using ListFontsResponse = Response<ListFontsReply>;
+
+struct ListFontsWithInfoRequest {
+ uint16_t max_names{};
+ std::string pattern{};
+};
+
+struct ListFontsWithInfoReply {
+ uint16_t sequence{};
+ CharInfo min_bounds{};
+ CharInfo max_bounds{};
+ uint16_t min_char_or_byte2{};
+ uint16_t max_char_or_byte2{};
+ uint16_t default_char{};
+ FontDraw draw_direction{};
+ uint8_t min_byte1{};
+ uint8_t max_byte1{};
+ uint8_t all_chars_exist{};
+ int16_t font_ascent{};
+ int16_t font_descent{};
+ uint32_t replies_hint{};
+ std::vector<FontProperty> properties{};
+ std::string name{};
+};
+
+using ListFontsWithInfoResponse = Response<ListFontsWithInfoReply>;
+
+struct SetFontPathRequest {
+ std::vector<Str> font{};
+};
+
+using SetFontPathResponse = Response<void>;
+
+struct GetFontPathRequest {};
+
+struct GetFontPathReply {
+ uint16_t sequence{};
+ std::vector<Str> path{};
+};
+
+using GetFontPathResponse = Response<GetFontPathReply>;
+
+struct CreatePixmapRequest {
+ uint8_t depth{};
+ Pixmap pid{};
+ Drawable drawable{};
+ uint16_t width{};
+ uint16_t height{};
+};
+
+using CreatePixmapResponse = Response<void>;
+
+struct FreePixmapRequest {
+ Pixmap pixmap{};
+};
+
+using FreePixmapResponse = Response<void>;
+
+struct CreateGCRequest {
+ GraphicsContext cid{};
+ Drawable drawable{};
+ base::Optional<Gx> function{};
+ base::Optional<uint32_t> plane_mask{};
+ base::Optional<uint32_t> foreground{};
+ base::Optional<uint32_t> background{};
+ base::Optional<uint32_t> line_width{};
+ base::Optional<LineStyle> line_style{};
+ base::Optional<CapStyle> cap_style{};
+ base::Optional<JoinStyle> join_style{};
+ base::Optional<FillStyle> fill_style{};
+ base::Optional<FillRule> fill_rule{};
+ base::Optional<Pixmap> tile{};
+ base::Optional<Pixmap> stipple{};
+ base::Optional<int32_t> tile_stipple_x_origin{};
+ base::Optional<int32_t> tile_stipple_y_origin{};
+ base::Optional<Font> font{};
+ base::Optional<SubwindowMode> subwindow_mode{};
+ base::Optional<Bool32> graphics_exposures{};
+ base::Optional<int32_t> clip_x_origin{};
+ base::Optional<int32_t> clip_y_origin{};
+ base::Optional<Pixmap> clip_mask{};
+ base::Optional<uint32_t> dash_offset{};
+ base::Optional<uint32_t> dashes{};
+ base::Optional<ArcMode> arc_mode{};
+};
+
+using CreateGCResponse = Response<void>;
+
+struct ChangeGCRequest {
+ GraphicsContext gc{};
+ base::Optional<Gx> function{};
+ base::Optional<uint32_t> plane_mask{};
+ base::Optional<uint32_t> foreground{};
+ base::Optional<uint32_t> background{};
+ base::Optional<uint32_t> line_width{};
+ base::Optional<LineStyle> line_style{};
+ base::Optional<CapStyle> cap_style{};
+ base::Optional<JoinStyle> join_style{};
+ base::Optional<FillStyle> fill_style{};
+ base::Optional<FillRule> fill_rule{};
+ base::Optional<Pixmap> tile{};
+ base::Optional<Pixmap> stipple{};
+ base::Optional<int32_t> tile_stipple_x_origin{};
+ base::Optional<int32_t> tile_stipple_y_origin{};
+ base::Optional<Font> font{};
+ base::Optional<SubwindowMode> subwindow_mode{};
+ base::Optional<Bool32> graphics_exposures{};
+ base::Optional<int32_t> clip_x_origin{};
+ base::Optional<int32_t> clip_y_origin{};
+ base::Optional<Pixmap> clip_mask{};
+ base::Optional<uint32_t> dash_offset{};
+ base::Optional<uint32_t> dashes{};
+ base::Optional<ArcMode> arc_mode{};
+};
+
+using ChangeGCResponse = Response<void>;
+
+struct CopyGCRequest {
+ GraphicsContext src_gc{};
+ GraphicsContext dst_gc{};
+ GraphicsContextAttribute value_mask{};
+};
+
+using CopyGCResponse = Response<void>;
+
+struct SetDashesRequest {
+ GraphicsContext gc{};
+ uint16_t dash_offset{};
+ std::vector<uint8_t> dashes{};
+};
+
+using SetDashesResponse = Response<void>;
+
+struct SetClipRectanglesRequest {
+ ClipOrdering ordering{};
+ GraphicsContext gc{};
+ int16_t clip_x_origin{};
+ int16_t clip_y_origin{};
+ std::vector<Rectangle> rectangles{};
+};
+
+using SetClipRectanglesResponse = Response<void>;
+
+struct FreeGCRequest {
+ GraphicsContext gc{};
+};
+
+using FreeGCResponse = Response<void>;
+
+struct ClearAreaRequest {
+ uint8_t exposures{};
+ Window window{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+};
+
+using ClearAreaResponse = Response<void>;
+
+struct CopyAreaRequest {
+ Drawable src_drawable{};
+ Drawable dst_drawable{};
+ GraphicsContext gc{};
+ int16_t src_x{};
+ int16_t src_y{};
+ int16_t dst_x{};
+ int16_t dst_y{};
+ uint16_t width{};
+ uint16_t height{};
+};
+
+using CopyAreaResponse = Response<void>;
+
+struct CopyPlaneRequest {
+ Drawable src_drawable{};
+ Drawable dst_drawable{};
+ GraphicsContext gc{};
+ int16_t src_x{};
+ int16_t src_y{};
+ int16_t dst_x{};
+ int16_t dst_y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint32_t bit_plane{};
+};
+
+using CopyPlaneResponse = Response<void>;
+
+struct PolyPointRequest {
+ CoordMode coordinate_mode{};
+ Drawable drawable{};
+ GraphicsContext gc{};
+ std::vector<Point> points{};
+};
+
+using PolyPointResponse = Response<void>;
+
+struct PolyLineRequest {
+ CoordMode coordinate_mode{};
+ Drawable drawable{};
+ GraphicsContext gc{};
+ std::vector<Point> points{};
+};
+
+using PolyLineResponse = Response<void>;
+
+struct PolySegmentRequest {
+ Drawable drawable{};
+ GraphicsContext gc{};
+ std::vector<Segment> segments{};
+};
+
+using PolySegmentResponse = Response<void>;
+
+struct PolyRectangleRequest {
+ Drawable drawable{};
+ GraphicsContext gc{};
+ std::vector<Rectangle> rectangles{};
+};
+
+using PolyRectangleResponse = Response<void>;
+
+struct PolyArcRequest {
+ Drawable drawable{};
+ GraphicsContext gc{};
+ std::vector<Arc> arcs{};
+};
+
+using PolyArcResponse = Response<void>;
+
+struct FillPolyRequest {
+ Drawable drawable{};
+ GraphicsContext gc{};
+ PolyShape shape{};
+ CoordMode coordinate_mode{};
+ std::vector<Point> points{};
+};
+
+using FillPolyResponse = Response<void>;
+
+struct PolyFillRectangleRequest {
+ Drawable drawable{};
+ GraphicsContext gc{};
+ std::vector<Rectangle> rectangles{};
+};
+
+using PolyFillRectangleResponse = Response<void>;
+
+struct PolyFillArcRequest {
+ Drawable drawable{};
+ GraphicsContext gc{};
+ std::vector<Arc> arcs{};
+};
+
+using PolyFillArcResponse = Response<void>;
+
+struct PutImageRequest {
+ ImageFormat format{};
+ Drawable drawable{};
+ GraphicsContext gc{};
+ uint16_t width{};
+ uint16_t height{};
+ int16_t dst_x{};
+ int16_t dst_y{};
+ uint8_t left_pad{};
+ uint8_t depth{};
+ scoped_refptr<base::RefCountedMemory> data{};
+};
+
+using PutImageResponse = Response<void>;
+
+struct GetImageRequest {
+ ImageFormat format{};
+ Drawable drawable{};
+ int16_t x{};
+ int16_t y{};
+ uint16_t width{};
+ uint16_t height{};
+ uint32_t plane_mask{};
+};
+
+struct GetImageReply {
+ uint8_t depth{};
+ uint16_t sequence{};
+ VisualId visual{};
+ scoped_refptr<base::RefCountedMemory> data{};
+};
+
+using GetImageResponse = Response<GetImageReply>;
+
+struct PolyText8Request {
+ Drawable drawable{};
+ GraphicsContext gc{};
+ int16_t x{};
+ int16_t y{};
+ std::vector<uint8_t> items{};
+};
+
+using PolyText8Response = Response<void>;
+
+struct PolyText16Request {
+ Drawable drawable{};
+ GraphicsContext gc{};
+ int16_t x{};
+ int16_t y{};
+ std::vector<uint8_t> items{};
+};
+
+using PolyText16Response = Response<void>;
+
+struct ImageText8Request {
+ Drawable drawable{};
+ GraphicsContext gc{};
+ int16_t x{};
+ int16_t y{};
+ std::string string{};
+};
+
+using ImageText8Response = Response<void>;
+
+struct ImageText16Request {
+ Drawable drawable{};
+ GraphicsContext gc{};
+ int16_t x{};
+ int16_t y{};
+ std::vector<Char16> string{};
+};
+
+using ImageText16Response = Response<void>;
+
+struct CreateColormapRequest {
+ ColormapAlloc alloc{};
+ ColorMap mid{};
+ Window window{};
+ VisualId visual{};
+};
+
+using CreateColormapResponse = Response<void>;
+
+struct FreeColormapRequest {
+ ColorMap cmap{};
+};
+
+using FreeColormapResponse = Response<void>;
+
+struct CopyColormapAndFreeRequest {
+ ColorMap mid{};
+ ColorMap src_cmap{};
+};
+
+using CopyColormapAndFreeResponse = Response<void>;
+
+struct InstallColormapRequest {
+ ColorMap cmap{};
+};
+
+using InstallColormapResponse = Response<void>;
+
+struct UninstallColormapRequest {
+ ColorMap cmap{};
+};
+
+using UninstallColormapResponse = Response<void>;
+
+struct ListInstalledColormapsRequest {
+ Window window{};
+};
+
+struct ListInstalledColormapsReply {
+ uint16_t sequence{};
+ std::vector<ColorMap> cmaps{};
+};
+
+using ListInstalledColormapsResponse = Response<ListInstalledColormapsReply>;
+
+struct AllocColorRequest {
+ ColorMap cmap{};
+ uint16_t red{};
+ uint16_t green{};
+ uint16_t blue{};
+};
+
+struct AllocColorReply {
+ uint16_t sequence{};
+ uint16_t red{};
+ uint16_t green{};
+ uint16_t blue{};
+ uint32_t pixel{};
+};
+
+using AllocColorResponse = Response<AllocColorReply>;
+
+struct AllocNamedColorRequest {
+ ColorMap cmap{};
+ std::string name{};
+};
+
+struct AllocNamedColorReply {
+ uint16_t sequence{};
+ uint32_t pixel{};
+ uint16_t exact_red{};
+ uint16_t exact_green{};
+ uint16_t exact_blue{};
+ uint16_t visual_red{};
+ uint16_t visual_green{};
+ uint16_t visual_blue{};
+};
+
+using AllocNamedColorResponse = Response<AllocNamedColorReply>;
+
+struct AllocColorCellsRequest {
+ uint8_t contiguous{};
+ ColorMap cmap{};
+ uint16_t colors{};
+ uint16_t planes{};
+};
+
+struct AllocColorCellsReply {
+ uint16_t sequence{};
+ std::vector<uint32_t> pixels{};
+ std::vector<uint32_t> masks{};
+};
+
+using AllocColorCellsResponse = Response<AllocColorCellsReply>;
+
+struct AllocColorPlanesRequest {
+ uint8_t contiguous{};
+ ColorMap cmap{};
+ uint16_t colors{};
+ uint16_t reds{};
+ uint16_t greens{};
+ uint16_t blues{};
+};
+
+struct AllocColorPlanesReply {
+ uint16_t sequence{};
+ uint32_t red_mask{};
+ uint32_t green_mask{};
+ uint32_t blue_mask{};
+ std::vector<uint32_t> pixels{};
+};
+
+using AllocColorPlanesResponse = Response<AllocColorPlanesReply>;
+
+struct FreeColorsRequest {
+ ColorMap cmap{};
+ uint32_t plane_mask{};
+ std::vector<uint32_t> pixels{};
+};
+
+using FreeColorsResponse = Response<void>;
+
+struct StoreColorsRequest {
+ ColorMap cmap{};
+ std::vector<ColorItem> items{};
+};
+
+using StoreColorsResponse = Response<void>;
+
+struct StoreNamedColorRequest {
+ ColorFlag flags{};
+ ColorMap cmap{};
+ uint32_t pixel{};
+ std::string name{};
+};
+
+using StoreNamedColorResponse = Response<void>;
+
+struct QueryColorsRequest {
+ ColorMap cmap{};
+ std::vector<uint32_t> pixels{};
+};
+
+struct QueryColorsReply {
+ uint16_t sequence{};
+ std::vector<Rgb> colors{};
+};
+
+using QueryColorsResponse = Response<QueryColorsReply>;
+
+struct LookupColorRequest {
+ ColorMap cmap{};
+ std::string name{};
+};
+
+struct LookupColorReply {
+ uint16_t sequence{};
+ uint16_t exact_red{};
+ uint16_t exact_green{};
+ uint16_t exact_blue{};
+ uint16_t visual_red{};
+ uint16_t visual_green{};
+ uint16_t visual_blue{};
+};
+
+using LookupColorResponse = Response<LookupColorReply>;
+
+struct CreateCursorRequest {
+ Cursor cid{};
+ Pixmap source{};
+ Pixmap mask{};
+ uint16_t fore_red{};
+ uint16_t fore_green{};
+ uint16_t fore_blue{};
+ uint16_t back_red{};
+ uint16_t back_green{};
+ uint16_t back_blue{};
+ uint16_t x{};
+ uint16_t y{};
+};
+
+using CreateCursorResponse = Response<void>;
+
+struct CreateGlyphCursorRequest {
+ Cursor cid{};
+ Font source_font{};
+ Font mask_font{};
+ uint16_t source_char{};
+ uint16_t mask_char{};
+ uint16_t fore_red{};
+ uint16_t fore_green{};
+ uint16_t fore_blue{};
+ uint16_t back_red{};
+ uint16_t back_green{};
+ uint16_t back_blue{};
+};
+
+using CreateGlyphCursorResponse = Response<void>;
+
+struct FreeCursorRequest {
+ Cursor cursor{};
+};
+
+using FreeCursorResponse = Response<void>;
+
+struct RecolorCursorRequest {
+ Cursor cursor{};
+ uint16_t fore_red{};
+ uint16_t fore_green{};
+ uint16_t fore_blue{};
+ uint16_t back_red{};
+ uint16_t back_green{};
+ uint16_t back_blue{};
+};
+
+using RecolorCursorResponse = Response<void>;
+
+struct QueryBestSizeRequest {
+ QueryShapeOf c_class{};
+ Drawable drawable{};
+ uint16_t width{};
+ uint16_t height{};
+};
+
+struct QueryBestSizeReply {
+ uint16_t sequence{};
+ uint16_t width{};
+ uint16_t height{};
+};
+
+using QueryBestSizeResponse = Response<QueryBestSizeReply>;
+
+struct QueryExtensionRequest {
+ std::string name{};
+};
+
+struct QueryExtensionReply {
+ uint16_t sequence{};
+ uint8_t present{};
+ uint8_t major_opcode{};
+ uint8_t first_event{};
+ uint8_t first_error{};
+};
+
+using QueryExtensionResponse = Response<QueryExtensionReply>;
+
+struct ListExtensionsRequest {};
+
+struct ListExtensionsReply {
+ uint16_t sequence{};
+ std::vector<Str> names{};
+};
+
+using ListExtensionsResponse = Response<ListExtensionsReply>;
+
+struct ChangeKeyboardMappingRequest {
+ uint8_t keycode_count{};
+ KeyCode first_keycode{};
+ uint8_t keysyms_per_keycode{};
+ std::vector<KeySym> keysyms{};
+};
+
+using ChangeKeyboardMappingResponse = Response<void>;
+
+struct GetKeyboardMappingRequest {
+ KeyCode first_keycode{};
+ uint8_t count{};
+};
+
+struct GetKeyboardMappingReply {
+ uint8_t keysyms_per_keycode{};
+ uint16_t sequence{};
+ std::vector<KeySym> keysyms{};
+};
+
+using GetKeyboardMappingResponse = Response<GetKeyboardMappingReply>;
+
+struct ChangeKeyboardControlRequest {
+ base::Optional<int32_t> key_click_percent{};
+ base::Optional<int32_t> bell_percent{};
+ base::Optional<int32_t> bell_pitch{};
+ base::Optional<int32_t> bell_duration{};
+ base::Optional<uint32_t> led{};
+ base::Optional<LedMode> led_mode{};
+ base::Optional<KeyCode32> key{};
+ base::Optional<AutoRepeatMode> auto_repeat_mode{};
+};
+
+using ChangeKeyboardControlResponse = Response<void>;
+
+struct GetKeyboardControlRequest {};
+
+struct GetKeyboardControlReply {
+ AutoRepeatMode global_auto_repeat{};
+ uint16_t sequence{};
+ uint32_t led_mask{};
+ uint8_t key_click_percent{};
+ uint8_t bell_percent{};
+ uint16_t bell_pitch{};
+ uint16_t bell_duration{};
+ std::array<uint8_t, 32> auto_repeats{};
+};
+
+using GetKeyboardControlResponse = Response<GetKeyboardControlReply>;
+
+struct BellRequest {
+ int8_t percent{};
+};
+
+using BellResponse = Response<void>;
+
+struct ChangePointerControlRequest {
+ int16_t acceleration_numerator{};
+ int16_t acceleration_denominator{};
+ int16_t threshold{};
+ uint8_t do_acceleration{};
+ uint8_t do_threshold{};
+};
+
+using ChangePointerControlResponse = Response<void>;
+
+struct GetPointerControlRequest {};
+
+struct GetPointerControlReply {
+ uint16_t sequence{};
+ uint16_t acceleration_numerator{};
+ uint16_t acceleration_denominator{};
+ uint16_t threshold{};
+};
+
+using GetPointerControlResponse = Response<GetPointerControlReply>;
+
+struct SetScreenSaverRequest {
+ int16_t timeout{};
+ int16_t interval{};
+ Blanking prefer_blanking{};
+ Exposures allow_exposures{};
+};
+
+using SetScreenSaverResponse = Response<void>;
+
+struct GetScreenSaverRequest {};
+
+struct GetScreenSaverReply {
+ uint16_t sequence{};
+ uint16_t timeout{};
+ uint16_t interval{};
+ Blanking prefer_blanking{};
+ Exposures allow_exposures{};
+};
+
+using GetScreenSaverResponse = Response<GetScreenSaverReply>;
+
+struct ChangeHostsRequest {
+ HostMode mode{};
+ Family family{};
+ std::vector<uint8_t> address{};
+};
+
+using ChangeHostsResponse = Response<void>;
+
+struct ListHostsRequest {};
+
+struct ListHostsReply {
+ AccessControl mode{};
+ uint16_t sequence{};
+ std::vector<Host> hosts{};
+};
+
+using ListHostsResponse = Response<ListHostsReply>;
+
+struct SetAccessControlRequest {
+ AccessControl mode{};
+};
+
+using SetAccessControlResponse = Response<void>;
+
+struct SetCloseDownModeRequest {
+ CloseDown mode{};
+};
+
+using SetCloseDownModeResponse = Response<void>;
+
+struct KillClientRequest {
+ uint32_t resource{};
+};
+
+using KillClientResponse = Response<void>;
+
+struct RotatePropertiesRequest {
+ Window window{};
+ int16_t delta{};
+ std::vector<Atom> atoms{};
+};
+
+using RotatePropertiesResponse = Response<void>;
+
+struct ForceScreenSaverRequest {
+ ScreenSaverMode mode{};
+};
+
+using ForceScreenSaverResponse = Response<void>;
+
+struct SetPointerMappingRequest {
+ std::vector<uint8_t> map{};
+};
+
+struct SetPointerMappingReply {
+ MappingStatus status{};
+ uint16_t sequence{};
+};
+
+using SetPointerMappingResponse = Response<SetPointerMappingReply>;
+
+struct GetPointerMappingRequest {};
+
+struct GetPointerMappingReply {
+ uint16_t sequence{};
+ std::vector<uint8_t> map{};
+};
+
+using GetPointerMappingResponse = Response<GetPointerMappingReply>;
+
+struct SetModifierMappingRequest {
+ uint8_t keycodes_per_modifier{};
+ std::vector<KeyCode> keycodes{};
+};
+
+struct SetModifierMappingReply {
+ MappingStatus status{};
+ uint16_t sequence{};
+};
+
+using SetModifierMappingResponse = Response<SetModifierMappingReply>;
+
+struct GetModifierMappingRequest {};
+
+struct GetModifierMappingReply {
+ uint8_t keycodes_per_modifier{};
+ uint16_t sequence{};
+ std::vector<KeyCode> keycodes{};
+};
+
+using GetModifierMappingResponse = Response<GetModifierMappingReply>;
+
+struct NoOperationRequest {};
+
+using NoOperationResponse = Response<void>;
+
+class COMPONENT_EXPORT(X11) XProto {
+ public:
+ explicit XProto(Connection* connection);
+
+ Connection* connection() const { return connection_; }
+
+ Future<void> CreateWindow(const CreateWindowRequest& request);
+
+ Future<void> CreateWindow(
+ const uint8_t& depth = {},
+ const Window& wid = {},
+ const Window& parent = {},
+ const int16_t& x = {},
+ const int16_t& y = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint16_t& border_width = {},
+ const WindowClass& c_class = {},
+ const VisualId& visual = {},
+ const base::Optional<Pixmap>& background_pixmap = base::nullopt,
+ const base::Optional<uint32_t>& background_pixel = base::nullopt,
+ const base::Optional<Pixmap>& border_pixmap = base::nullopt,
+ const base::Optional<uint32_t>& border_pixel = base::nullopt,
+ const base::Optional<Gravity>& bit_gravity = base::nullopt,
+ const base::Optional<Gravity>& win_gravity = base::nullopt,
+ const base::Optional<BackingStore>& backing_store = base::nullopt,
+ const base::Optional<uint32_t>& backing_planes = base::nullopt,
+ const base::Optional<uint32_t>& backing_pixel = base::nullopt,
+ const base::Optional<Bool32>& override_redirect = base::nullopt,
+ const base::Optional<Bool32>& save_under = base::nullopt,
+ const base::Optional<EventMask>& event_mask = base::nullopt,
+ const base::Optional<EventMask>& do_not_propogate_mask = base::nullopt,
+ const base::Optional<ColorMap>& colormap = base::nullopt,
+ const base::Optional<Cursor>& cursor = base::nullopt);
+
+ Future<void> ChangeWindowAttributes(
+ const ChangeWindowAttributesRequest& request);
+
+ Future<void> ChangeWindowAttributes(
+ const Window& window = {},
+ const base::Optional<Pixmap>& background_pixmap = base::nullopt,
+ const base::Optional<uint32_t>& background_pixel = base::nullopt,
+ const base::Optional<Pixmap>& border_pixmap = base::nullopt,
+ const base::Optional<uint32_t>& border_pixel = base::nullopt,
+ const base::Optional<Gravity>& bit_gravity = base::nullopt,
+ const base::Optional<Gravity>& win_gravity = base::nullopt,
+ const base::Optional<BackingStore>& backing_store = base::nullopt,
+ const base::Optional<uint32_t>& backing_planes = base::nullopt,
+ const base::Optional<uint32_t>& backing_pixel = base::nullopt,
+ const base::Optional<Bool32>& override_redirect = base::nullopt,
+ const base::Optional<Bool32>& save_under = base::nullopt,
+ const base::Optional<EventMask>& event_mask = base::nullopt,
+ const base::Optional<EventMask>& do_not_propogate_mask = base::nullopt,
+ const base::Optional<ColorMap>& colormap = base::nullopt,
+ const base::Optional<Cursor>& cursor = base::nullopt);
+
+ Future<GetWindowAttributesReply> GetWindowAttributes(
+ const GetWindowAttributesRequest& request);
+
+ Future<GetWindowAttributesReply> GetWindowAttributes(
+ const Window& window = {});
+
+ Future<void> DestroyWindow(const DestroyWindowRequest& request);
+
+ Future<void> DestroyWindow(const Window& window = {});
+
+ Future<void> DestroySubwindows(const DestroySubwindowsRequest& request);
+
+ Future<void> DestroySubwindows(const Window& window = {});
+
+ Future<void> ChangeSaveSet(const ChangeSaveSetRequest& request);
+
+ Future<void> ChangeSaveSet(const SetMode& mode = {},
+ const Window& window = {});
+
+ Future<void> ReparentWindow(const ReparentWindowRequest& request);
+
+ Future<void> ReparentWindow(const Window& window = {},
+ const Window& parent = {},
+ const int16_t& x = {},
+ const int16_t& y = {});
+
+ Future<void> MapWindow(const MapWindowRequest& request);
+
+ Future<void> MapWindow(const Window& window = {});
+
+ Future<void> MapSubwindows(const MapSubwindowsRequest& request);
+
+ Future<void> MapSubwindows(const Window& window = {});
+
+ Future<void> UnmapWindow(const UnmapWindowRequest& request);
+
+ Future<void> UnmapWindow(const Window& window = {});
+
+ Future<void> UnmapSubwindows(const UnmapSubwindowsRequest& request);
+
+ Future<void> UnmapSubwindows(const Window& window = {});
+
+ Future<void> ConfigureWindow(const ConfigureWindowRequest& request);
+
+ Future<void> ConfigureWindow(
+ const Window& window = {},
+ const base::Optional<int32_t>& x = base::nullopt,
+ const base::Optional<int32_t>& y = base::nullopt,
+ const base::Optional<uint32_t>& width = base::nullopt,
+ const base::Optional<uint32_t>& height = base::nullopt,
+ const base::Optional<uint32_t>& border_width = base::nullopt,
+ const base::Optional<Window>& sibling = base::nullopt,
+ const base::Optional<StackMode>& stack_mode = base::nullopt);
+
+ Future<void> CirculateWindow(const CirculateWindowRequest& request);
+
+ Future<void> CirculateWindow(const Circulate& direction = {},
+ const Window& window = {});
+
+ Future<GetGeometryReply> GetGeometry(const GetGeometryRequest& request);
+
+ Future<GetGeometryReply> GetGeometry(const Drawable& drawable = {});
+
+ Future<QueryTreeReply> QueryTree(const QueryTreeRequest& request);
+
+ Future<QueryTreeReply> QueryTree(const Window& window = {});
+
+ Future<InternAtomReply> InternAtom(const InternAtomRequest& request);
+
+ Future<InternAtomReply> InternAtom(const uint8_t& only_if_exists = {},
+ const std::string& name = {});
+
+ Future<GetAtomNameReply> GetAtomName(const GetAtomNameRequest& request);
+
+ Future<GetAtomNameReply> GetAtomName(const Atom& atom = {});
+
+ Future<void> ChangeProperty(const ChangePropertyRequest& request);
+
+ Future<void> ChangeProperty(
+ const PropMode& mode = {},
+ const Window& window = {},
+ const Atom& property = {},
+ const Atom& type = {},
+ const uint8_t& format = {},
+ const uint32_t& data_len = {},
+ const scoped_refptr<base::RefCountedMemory>& data = {});
+
+ Future<void> DeleteProperty(const DeletePropertyRequest& request);
+
+ Future<void> DeleteProperty(const Window& window = {},
+ const Atom& property = {});
+
+ Future<GetPropertyReply> GetProperty(const GetPropertyRequest& request);
+
+ Future<GetPropertyReply> GetProperty(const uint8_t& c_delete = {},
+ const Window& window = {},
+ const Atom& property = {},
+ const Atom& type = {},
+ const uint32_t& long_offset = {},
+ const uint32_t& long_length = {});
+
+ Future<ListPropertiesReply> ListProperties(
+ const ListPropertiesRequest& request);
+
+ Future<ListPropertiesReply> ListProperties(const Window& window = {});
+
+ Future<void> SetSelectionOwner(const SetSelectionOwnerRequest& request);
+
+ Future<void> SetSelectionOwner(const Window& owner = {},
+ const Atom& selection = {},
+ const Time& time = {});
+
+ Future<GetSelectionOwnerReply> GetSelectionOwner(
+ const GetSelectionOwnerRequest& request);
+
+ Future<GetSelectionOwnerReply> GetSelectionOwner(const Atom& selection = {});
+
+ Future<void> ConvertSelection(const ConvertSelectionRequest& request);
+
+ Future<void> ConvertSelection(const Window& requestor = {},
+ const Atom& selection = {},
+ const Atom& target = {},
+ const Atom& property = {},
+ const Time& time = {});
+
+ Future<void> SendEvent(const SendEventRequest& request);
+
+ Future<void> SendEvent(const uint8_t& propagate = {},
+ const Window& destination = {},
+ const EventMask& event_mask = {},
+ const std::array<char, 32>& event = {});
+
+ Future<GrabPointerReply> GrabPointer(const GrabPointerRequest& request);
+
+ Future<GrabPointerReply> GrabPointer(const uint8_t& owner_events = {},
+ const Window& grab_window = {},
+ const EventMask& event_mask = {},
+ const GrabMode& pointer_mode = {},
+ const GrabMode& keyboard_mode = {},
+ const Window& confine_to = {},
+ const Cursor& cursor = {},
+ const Time& time = {});
+
+ Future<void> UngrabPointer(const UngrabPointerRequest& request);
+
+ Future<void> UngrabPointer(const Time& time = {});
+
+ Future<void> GrabButton(const GrabButtonRequest& request);
+
+ Future<void> GrabButton(const uint8_t& owner_events = {},
+ const Window& grab_window = {},
+ const EventMask& event_mask = {},
+ const GrabMode& pointer_mode = {},
+ const GrabMode& keyboard_mode = {},
+ const Window& confine_to = {},
+ const Cursor& cursor = {},
+ const ButtonIndex& button = {},
+ const ModMask& modifiers = {});
+
+ Future<void> UngrabButton(const UngrabButtonRequest& request);
+
+ Future<void> UngrabButton(const ButtonIndex& button = {},
+ const Window& grab_window = {},
+ const ModMask& modifiers = {});
+
+ Future<void> ChangeActivePointerGrab(
+ const ChangeActivePointerGrabRequest& request);
+
+ Future<void> ChangeActivePointerGrab(const Cursor& cursor = {},
+ const Time& time = {},
+ const EventMask& event_mask = {});
+
+ Future<GrabKeyboardReply> GrabKeyboard(const GrabKeyboardRequest& request);
+
+ Future<GrabKeyboardReply> GrabKeyboard(const uint8_t& owner_events = {},
+ const Window& grab_window = {},
+ const Time& time = {},
+ const GrabMode& pointer_mode = {},
+ const GrabMode& keyboard_mode = {});
+
+ Future<void> UngrabKeyboard(const UngrabKeyboardRequest& request);
+
+ Future<void> UngrabKeyboard(const Time& time = {});
+
+ Future<void> GrabKey(const GrabKeyRequest& request);
+
+ Future<void> GrabKey(const uint8_t& owner_events = {},
+ const Window& grab_window = {},
+ const ModMask& modifiers = {},
+ const KeyCode& key = {},
+ const GrabMode& pointer_mode = {},
+ const GrabMode& keyboard_mode = {});
+
+ Future<void> UngrabKey(const UngrabKeyRequest& request);
+
+ Future<void> UngrabKey(const KeyCode& key = {},
+ const Window& grab_window = {},
+ const ModMask& modifiers = {});
+
+ Future<void> AllowEvents(const AllowEventsRequest& request);
+
+ Future<void> AllowEvents(const Allow& mode = {}, const Time& time = {});
+
+ Future<void> GrabServer(const GrabServerRequest& request);
+
+ Future<void> GrabServer();
+
+ Future<void> UngrabServer(const UngrabServerRequest& request);
+
+ Future<void> UngrabServer();
+
+ Future<QueryPointerReply> QueryPointer(const QueryPointerRequest& request);
+
+ Future<QueryPointerReply> QueryPointer(const Window& window = {});
+
+ Future<GetMotionEventsReply> GetMotionEvents(
+ const GetMotionEventsRequest& request);
+
+ Future<GetMotionEventsReply> GetMotionEvents(const Window& window = {},
+ const Time& start = {},
+ const Time& stop = {});
+
+ Future<TranslateCoordinatesReply> TranslateCoordinates(
+ const TranslateCoordinatesRequest& request);
+
+ Future<TranslateCoordinatesReply> TranslateCoordinates(
+ const Window& src_window = {},
+ const Window& dst_window = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {});
+
+ Future<void> WarpPointer(const WarpPointerRequest& request);
+
+ Future<void> WarpPointer(const Window& src_window = {},
+ const Window& dst_window = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const uint16_t& src_width = {},
+ const uint16_t& src_height = {},
+ const int16_t& dst_x = {},
+ const int16_t& dst_y = {});
+
+ Future<void> SetInputFocus(const SetInputFocusRequest& request);
+
+ Future<void> SetInputFocus(const InputFocus& revert_to = {},
+ const Window& focus = {},
+ const Time& time = {});
+
+ Future<GetInputFocusReply> GetInputFocus(const GetInputFocusRequest& request);
+
+ Future<GetInputFocusReply> GetInputFocus();
+
+ Future<QueryKeymapReply> QueryKeymap(const QueryKeymapRequest& request);
+
+ Future<QueryKeymapReply> QueryKeymap();
+
+ Future<void> OpenFont(const OpenFontRequest& request);
+
+ Future<void> OpenFont(const Font& fid = {}, const std::string& name = {});
+
+ Future<void> CloseFont(const CloseFontRequest& request);
+
+ Future<void> CloseFont(const Font& font = {});
+
+ Future<QueryFontReply> QueryFont(const QueryFontRequest& request);
+
+ Future<QueryFontReply> QueryFont(const Fontable& font = {});
+
+ Future<QueryTextExtentsReply> QueryTextExtents(
+ const QueryTextExtentsRequest& request);
+
+ Future<QueryTextExtentsReply> QueryTextExtents(
+ const Fontable& font = {},
+ const std::vector<Char16>& string = {});
+
+ Future<ListFontsReply> ListFonts(const ListFontsRequest& request);
+
+ Future<ListFontsReply> ListFonts(const uint16_t& max_names = {},
+ const std::string& pattern = {});
+
+ Future<ListFontsWithInfoReply> ListFontsWithInfo(
+ const ListFontsWithInfoRequest& request);
+
+ Future<ListFontsWithInfoReply> ListFontsWithInfo(
+ const uint16_t& max_names = {},
+ const std::string& pattern = {});
+
+ Future<void> SetFontPath(const SetFontPathRequest& request);
+
+ Future<void> SetFontPath(const std::vector<Str>& font = {});
+
+ Future<GetFontPathReply> GetFontPath(const GetFontPathRequest& request);
+
+ Future<GetFontPathReply> GetFontPath();
+
+ Future<void> CreatePixmap(const CreatePixmapRequest& request);
+
+ Future<void> CreatePixmap(const uint8_t& depth = {},
+ const Pixmap& pid = {},
+ const Drawable& drawable = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {});
+
+ Future<void> FreePixmap(const FreePixmapRequest& request);
+
+ Future<void> FreePixmap(const Pixmap& pixmap = {});
+
+ Future<void> CreateGC(const CreateGCRequest& request);
+
+ Future<void> CreateGC(
+ const GraphicsContext& cid = {},
+ const Drawable& drawable = {},
+ const base::Optional<Gx>& function = base::nullopt,
+ const base::Optional<uint32_t>& plane_mask = base::nullopt,
+ const base::Optional<uint32_t>& foreground = base::nullopt,
+ const base::Optional<uint32_t>& background = base::nullopt,
+ const base::Optional<uint32_t>& line_width = base::nullopt,
+ const base::Optional<LineStyle>& line_style = base::nullopt,
+ const base::Optional<CapStyle>& cap_style = base::nullopt,
+ const base::Optional<JoinStyle>& join_style = base::nullopt,
+ const base::Optional<FillStyle>& fill_style = base::nullopt,
+ const base::Optional<FillRule>& fill_rule = base::nullopt,
+ const base::Optional<Pixmap>& tile = base::nullopt,
+ const base::Optional<Pixmap>& stipple = base::nullopt,
+ const base::Optional<int32_t>& tile_stipple_x_origin = base::nullopt,
+ const base::Optional<int32_t>& tile_stipple_y_origin = base::nullopt,
+ const base::Optional<Font>& font = base::nullopt,
+ const base::Optional<SubwindowMode>& subwindow_mode = base::nullopt,
+ const base::Optional<Bool32>& graphics_exposures = base::nullopt,
+ const base::Optional<int32_t>& clip_x_origin = base::nullopt,
+ const base::Optional<int32_t>& clip_y_origin = base::nullopt,
+ const base::Optional<Pixmap>& clip_mask = base::nullopt,
+ const base::Optional<uint32_t>& dash_offset = base::nullopt,
+ const base::Optional<uint32_t>& dashes = base::nullopt,
+ const base::Optional<ArcMode>& arc_mode = base::nullopt);
+
+ Future<void> ChangeGC(const ChangeGCRequest& request);
+
+ Future<void> ChangeGC(
+ const GraphicsContext& gc = {},
+ const base::Optional<Gx>& function = base::nullopt,
+ const base::Optional<uint32_t>& plane_mask = base::nullopt,
+ const base::Optional<uint32_t>& foreground = base::nullopt,
+ const base::Optional<uint32_t>& background = base::nullopt,
+ const base::Optional<uint32_t>& line_width = base::nullopt,
+ const base::Optional<LineStyle>& line_style = base::nullopt,
+ const base::Optional<CapStyle>& cap_style = base::nullopt,
+ const base::Optional<JoinStyle>& join_style = base::nullopt,
+ const base::Optional<FillStyle>& fill_style = base::nullopt,
+ const base::Optional<FillRule>& fill_rule = base::nullopt,
+ const base::Optional<Pixmap>& tile = base::nullopt,
+ const base::Optional<Pixmap>& stipple = base::nullopt,
+ const base::Optional<int32_t>& tile_stipple_x_origin = base::nullopt,
+ const base::Optional<int32_t>& tile_stipple_y_origin = base::nullopt,
+ const base::Optional<Font>& font = base::nullopt,
+ const base::Optional<SubwindowMode>& subwindow_mode = base::nullopt,
+ const base::Optional<Bool32>& graphics_exposures = base::nullopt,
+ const base::Optional<int32_t>& clip_x_origin = base::nullopt,
+ const base::Optional<int32_t>& clip_y_origin = base::nullopt,
+ const base::Optional<Pixmap>& clip_mask = base::nullopt,
+ const base::Optional<uint32_t>& dash_offset = base::nullopt,
+ const base::Optional<uint32_t>& dashes = base::nullopt,
+ const base::Optional<ArcMode>& arc_mode = base::nullopt);
+
+ Future<void> CopyGC(const CopyGCRequest& request);
+
+ Future<void> CopyGC(const GraphicsContext& src_gc = {},
+ const GraphicsContext& dst_gc = {},
+ const GraphicsContextAttribute& value_mask = {});
+
+ Future<void> SetDashes(const SetDashesRequest& request);
+
+ Future<void> SetDashes(const GraphicsContext& gc = {},
+ const uint16_t& dash_offset = {},
+ const std::vector<uint8_t>& dashes = {});
+
+ Future<void> SetClipRectangles(const SetClipRectanglesRequest& request);
+
+ Future<void> SetClipRectangles(const ClipOrdering& ordering = {},
+ const GraphicsContext& gc = {},
+ const int16_t& clip_x_origin = {},
+ const int16_t& clip_y_origin = {},
+ const std::vector<Rectangle>& rectangles = {});
+
+ Future<void> FreeGC(const FreeGCRequest& request);
+
+ Future<void> FreeGC(const GraphicsContext& gc = {});
+
+ Future<void> ClearArea(const ClearAreaRequest& request);
+
+ Future<void> ClearArea(const uint8_t& exposures = {},
+ const Window& window = {},
+ const int16_t& x = {},
+ const int16_t& y = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {});
+
+ Future<void> CopyArea(const CopyAreaRequest& request);
+
+ Future<void> CopyArea(const Drawable& src_drawable = {},
+ const Drawable& dst_drawable = {},
+ const GraphicsContext& gc = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const int16_t& dst_x = {},
+ const int16_t& dst_y = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {});
+
+ Future<void> CopyPlane(const CopyPlaneRequest& request);
+
+ Future<void> CopyPlane(const Drawable& src_drawable = {},
+ const Drawable& dst_drawable = {},
+ const GraphicsContext& gc = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const int16_t& dst_x = {},
+ const int16_t& dst_y = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint32_t& bit_plane = {});
+
+ Future<void> PolyPoint(const PolyPointRequest& request);
+
+ Future<void> PolyPoint(const CoordMode& coordinate_mode = {},
+ const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const std::vector<Point>& points = {});
+
+ Future<void> PolyLine(const PolyLineRequest& request);
+
+ Future<void> PolyLine(const CoordMode& coordinate_mode = {},
+ const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const std::vector<Point>& points = {});
+
+ Future<void> PolySegment(const PolySegmentRequest& request);
+
+ Future<void> PolySegment(const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const std::vector<Segment>& segments = {});
+
+ Future<void> PolyRectangle(const PolyRectangleRequest& request);
+
+ Future<void> PolyRectangle(const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const std::vector<Rectangle>& rectangles = {});
+
+ Future<void> PolyArc(const PolyArcRequest& request);
+
+ Future<void> PolyArc(const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const std::vector<Arc>& arcs = {});
+
+ Future<void> FillPoly(const FillPolyRequest& request);
+
+ Future<void> FillPoly(const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const PolyShape& shape = {},
+ const CoordMode& coordinate_mode = {},
+ const std::vector<Point>& points = {});
+
+ Future<void> PolyFillRectangle(const PolyFillRectangleRequest& request);
+
+ Future<void> PolyFillRectangle(const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const std::vector<Rectangle>& rectangles = {});
+
+ Future<void> PolyFillArc(const PolyFillArcRequest& request);
+
+ Future<void> PolyFillArc(const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const std::vector<Arc>& arcs = {});
+
+ Future<void> PutImage(const PutImageRequest& request);
+
+ Future<void> PutImage(const ImageFormat& format = {},
+ const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const int16_t& dst_x = {},
+ const int16_t& dst_y = {},
+ const uint8_t& left_pad = {},
+ const uint8_t& depth = {},
+ const scoped_refptr<base::RefCountedMemory>& data = {});
+
+ Future<GetImageReply> GetImage(const GetImageRequest& request);
+
+ Future<GetImageReply> GetImage(const ImageFormat& format = {},
+ const Drawable& drawable = {},
+ const int16_t& x = {},
+ const int16_t& y = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint32_t& plane_mask = {});
+
+ Future<void> PolyText8(const PolyText8Request& request);
+
+ Future<void> PolyText8(const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const int16_t& x = {},
+ const int16_t& y = {},
+ const std::vector<uint8_t>& items = {});
+
+ Future<void> PolyText16(const PolyText16Request& request);
+
+ Future<void> PolyText16(const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const int16_t& x = {},
+ const int16_t& y = {},
+ const std::vector<uint8_t>& items = {});
+
+ Future<void> ImageText8(const ImageText8Request& request);
+
+ Future<void> ImageText8(const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const int16_t& x = {},
+ const int16_t& y = {},
+ const std::string& string = {});
+
+ Future<void> ImageText16(const ImageText16Request& request);
+
+ Future<void> ImageText16(const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const int16_t& x = {},
+ const int16_t& y = {},
+ const std::vector<Char16>& string = {});
+
+ Future<void> CreateColormap(const CreateColormapRequest& request);
+
+ Future<void> CreateColormap(const ColormapAlloc& alloc = {},
+ const ColorMap& mid = {},
+ const Window& window = {},
+ const VisualId& visual = {});
+
+ Future<void> FreeColormap(const FreeColormapRequest& request);
+
+ Future<void> FreeColormap(const ColorMap& cmap = {});
+
+ Future<void> CopyColormapAndFree(const CopyColormapAndFreeRequest& request);
+
+ Future<void> CopyColormapAndFree(const ColorMap& mid = {},
+ const ColorMap& src_cmap = {});
+
+ Future<void> InstallColormap(const InstallColormapRequest& request);
+
+ Future<void> InstallColormap(const ColorMap& cmap = {});
+
+ Future<void> UninstallColormap(const UninstallColormapRequest& request);
+
+ Future<void> UninstallColormap(const ColorMap& cmap = {});
+
+ Future<ListInstalledColormapsReply> ListInstalledColormaps(
+ const ListInstalledColormapsRequest& request);
+
+ Future<ListInstalledColormapsReply> ListInstalledColormaps(
+ const Window& window = {});
+
+ Future<AllocColorReply> AllocColor(const AllocColorRequest& request);
+
+ Future<AllocColorReply> AllocColor(const ColorMap& cmap = {},
+ const uint16_t& red = {},
+ const uint16_t& green = {},
+ const uint16_t& blue = {});
+
+ Future<AllocNamedColorReply> AllocNamedColor(
+ const AllocNamedColorRequest& request);
+
+ Future<AllocNamedColorReply> AllocNamedColor(const ColorMap& cmap = {},
+ const std::string& name = {});
+
+ Future<AllocColorCellsReply> AllocColorCells(
+ const AllocColorCellsRequest& request);
+
+ Future<AllocColorCellsReply> AllocColorCells(const uint8_t& contiguous = {},
+ const ColorMap& cmap = {},
+ const uint16_t& colors = {},
+ const uint16_t& planes = {});
+
+ Future<AllocColorPlanesReply> AllocColorPlanes(
+ const AllocColorPlanesRequest& request);
+
+ Future<AllocColorPlanesReply> AllocColorPlanes(const uint8_t& contiguous = {},
+ const ColorMap& cmap = {},
+ const uint16_t& colors = {},
+ const uint16_t& reds = {},
+ const uint16_t& greens = {},
+ const uint16_t& blues = {});
+
+ Future<void> FreeColors(const FreeColorsRequest& request);
+
+ Future<void> FreeColors(const ColorMap& cmap = {},
+ const uint32_t& plane_mask = {},
+ const std::vector<uint32_t>& pixels = {});
+
+ Future<void> StoreColors(const StoreColorsRequest& request);
+
+ Future<void> StoreColors(const ColorMap& cmap = {},
+ const std::vector<ColorItem>& items = {});
+
+ Future<void> StoreNamedColor(const StoreNamedColorRequest& request);
+
+ Future<void> StoreNamedColor(const ColorFlag& flags = {},
+ const ColorMap& cmap = {},
+ const uint32_t& pixel = {},
+ const std::string& name = {});
+
+ Future<QueryColorsReply> QueryColors(const QueryColorsRequest& request);
+
+ Future<QueryColorsReply> QueryColors(
+ const ColorMap& cmap = {},
+ const std::vector<uint32_t>& pixels = {});
+
+ Future<LookupColorReply> LookupColor(const LookupColorRequest& request);
+
+ Future<LookupColorReply> LookupColor(const ColorMap& cmap = {},
+ const std::string& name = {});
+
+ Future<void> CreateCursor(const CreateCursorRequest& request);
+
+ Future<void> CreateCursor(const Cursor& cid = {},
+ const Pixmap& source = {},
+ const Pixmap& mask = {},
+ const uint16_t& fore_red = {},
+ const uint16_t& fore_green = {},
+ const uint16_t& fore_blue = {},
+ const uint16_t& back_red = {},
+ const uint16_t& back_green = {},
+ const uint16_t& back_blue = {},
+ const uint16_t& x = {},
+ const uint16_t& y = {});
+
+ Future<void> CreateGlyphCursor(const CreateGlyphCursorRequest& request);
+
+ Future<void> CreateGlyphCursor(const Cursor& cid = {},
+ const Font& source_font = {},
+ const Font& mask_font = {},
+ const uint16_t& source_char = {},
+ const uint16_t& mask_char = {},
+ const uint16_t& fore_red = {},
+ const uint16_t& fore_green = {},
+ const uint16_t& fore_blue = {},
+ const uint16_t& back_red = {},
+ const uint16_t& back_green = {},
+ const uint16_t& back_blue = {});
+
+ Future<void> FreeCursor(const FreeCursorRequest& request);
+
+ Future<void> FreeCursor(const Cursor& cursor = {});
+
+ Future<void> RecolorCursor(const RecolorCursorRequest& request);
+
+ Future<void> RecolorCursor(const Cursor& cursor = {},
+ const uint16_t& fore_red = {},
+ const uint16_t& fore_green = {},
+ const uint16_t& fore_blue = {},
+ const uint16_t& back_red = {},
+ const uint16_t& back_green = {},
+ const uint16_t& back_blue = {});
+
+ Future<QueryBestSizeReply> QueryBestSize(const QueryBestSizeRequest& request);
+
+ Future<QueryBestSizeReply> QueryBestSize(const QueryShapeOf& c_class = {},
+ const Drawable& drawable = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {});
+
+ Future<QueryExtensionReply> QueryExtension(
+ const QueryExtensionRequest& request);
+
+ Future<QueryExtensionReply> QueryExtension(const std::string& name = {});
+
+ Future<ListExtensionsReply> ListExtensions(
+ const ListExtensionsRequest& request);
+
+ Future<ListExtensionsReply> ListExtensions();
+
+ Future<void> ChangeKeyboardMapping(
+ const ChangeKeyboardMappingRequest& request);
+
+ Future<void> ChangeKeyboardMapping(const uint8_t& keycode_count = {},
+ const KeyCode& first_keycode = {},
+ const uint8_t& keysyms_per_keycode = {},
+ const std::vector<KeySym>& keysyms = {});
+
+ Future<GetKeyboardMappingReply> GetKeyboardMapping(
+ const GetKeyboardMappingRequest& request);
+
+ Future<GetKeyboardMappingReply> GetKeyboardMapping(
+ const KeyCode& first_keycode = {},
+ const uint8_t& count = {});
+
+ Future<void> ChangeKeyboardControl(
+ const ChangeKeyboardControlRequest& request);
+
+ Future<void> ChangeKeyboardControl(
+ const base::Optional<int32_t>& key_click_percent = base::nullopt,
+ const base::Optional<int32_t>& bell_percent = base::nullopt,
+ const base::Optional<int32_t>& bell_pitch = base::nullopt,
+ const base::Optional<int32_t>& bell_duration = base::nullopt,
+ const base::Optional<uint32_t>& led = base::nullopt,
+ const base::Optional<LedMode>& led_mode = base::nullopt,
+ const base::Optional<KeyCode32>& key = base::nullopt,
+ const base::Optional<AutoRepeatMode>& auto_repeat_mode = base::nullopt);
+
+ Future<GetKeyboardControlReply> GetKeyboardControl(
+ const GetKeyboardControlRequest& request);
+
+ Future<GetKeyboardControlReply> GetKeyboardControl();
+
+ Future<void> Bell(const BellRequest& request);
+
+ Future<void> Bell(const int8_t& percent = {});
+
+ Future<void> ChangePointerControl(const ChangePointerControlRequest& request);
+
+ Future<void> ChangePointerControl(
+ const int16_t& acceleration_numerator = {},
+ const int16_t& acceleration_denominator = {},
+ const int16_t& threshold = {},
+ const uint8_t& do_acceleration = {},
+ const uint8_t& do_threshold = {});
+
+ Future<GetPointerControlReply> GetPointerControl(
+ const GetPointerControlRequest& request);
+
+ Future<GetPointerControlReply> GetPointerControl();
+
+ Future<void> SetScreenSaver(const SetScreenSaverRequest& request);
+
+ Future<void> SetScreenSaver(const int16_t& timeout = {},
+ const int16_t& interval = {},
+ const Blanking& prefer_blanking = {},
+ const Exposures& allow_exposures = {});
+
+ Future<GetScreenSaverReply> GetScreenSaver(
+ const GetScreenSaverRequest& request);
+
+ Future<GetScreenSaverReply> GetScreenSaver();
+
+ Future<void> ChangeHosts(const ChangeHostsRequest& request);
+
+ Future<void> ChangeHosts(const HostMode& mode = {},
+ const Family& family = {},
+ const std::vector<uint8_t>& address = {});
+
+ Future<ListHostsReply> ListHosts(const ListHostsRequest& request);
+
+ Future<ListHostsReply> ListHosts();
+
+ Future<void> SetAccessControl(const SetAccessControlRequest& request);
+
+ Future<void> SetAccessControl(const AccessControl& mode = {});
+
+ Future<void> SetCloseDownMode(const SetCloseDownModeRequest& request);
+
+ Future<void> SetCloseDownMode(const CloseDown& mode = {});
+
+ Future<void> KillClient(const KillClientRequest& request);
+
+ Future<void> KillClient(const uint32_t& resource = {});
+
+ Future<void> RotateProperties(const RotatePropertiesRequest& request);
+
+ Future<void> RotateProperties(const Window& window = {},
+ const int16_t& delta = {},
+ const std::vector<Atom>& atoms = {});
+
+ Future<void> ForceScreenSaver(const ForceScreenSaverRequest& request);
+
+ Future<void> ForceScreenSaver(const ScreenSaverMode& mode = {});
+
+ Future<SetPointerMappingReply> SetPointerMapping(
+ const SetPointerMappingRequest& request);
+
+ Future<SetPointerMappingReply> SetPointerMapping(
+ const std::vector<uint8_t>& map = {});
+
+ Future<GetPointerMappingReply> GetPointerMapping(
+ const GetPointerMappingRequest& request);
+
+ Future<GetPointerMappingReply> GetPointerMapping();
+
+ Future<SetModifierMappingReply> SetModifierMapping(
+ const SetModifierMappingRequest& request);
+
+ Future<SetModifierMappingReply> SetModifierMapping(
+ const uint8_t& keycodes_per_modifier = {},
+ const std::vector<KeyCode>& keycodes = {});
+
+ Future<GetModifierMappingReply> GetModifierMapping(
+ const GetModifierMappingRequest& request);
+
+ Future<GetModifierMappingReply> GetModifierMapping();
+
+ Future<void> NoOperation(const NoOperationRequest& request);
+
+ Future<void> NoOperation();
+
+ private:
+ Connection* const connection_;
+};
+
+} // namespace x11
+
+inline constexpr x11::VisualClass operator|(x11::VisualClass l,
+ x11::VisualClass r) {
+ using T = std::underlying_type_t<x11::VisualClass>;
+ return static_cast<x11::VisualClass>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::VisualClass operator&(x11::VisualClass l,
+ x11::VisualClass r) {
+ using T = std::underlying_type_t<x11::VisualClass>;
+ return static_cast<x11::VisualClass>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::EventMask operator|(x11::EventMask l, x11::EventMask r) {
+ using T = std::underlying_type_t<x11::EventMask>;
+ return static_cast<x11::EventMask>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::EventMask operator&(x11::EventMask l, x11::EventMask r) {
+ using T = std::underlying_type_t<x11::EventMask>;
+ return static_cast<x11::EventMask>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::BackingStore operator|(x11::BackingStore l,
+ x11::BackingStore r) {
+ using T = std::underlying_type_t<x11::BackingStore>;
+ return static_cast<x11::BackingStore>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::BackingStore operator&(x11::BackingStore l,
+ x11::BackingStore r) {
+ using T = std::underlying_type_t<x11::BackingStore>;
+ return static_cast<x11::BackingStore>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ImageOrder operator|(x11::ImageOrder l,
+ x11::ImageOrder r) {
+ using T = std::underlying_type_t<x11::ImageOrder>;
+ return static_cast<x11::ImageOrder>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::ImageOrder operator&(x11::ImageOrder l,
+ x11::ImageOrder r) {
+ using T = std::underlying_type_t<x11::ImageOrder>;
+ return static_cast<x11::ImageOrder>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ModMask operator|(x11::ModMask l, x11::ModMask r) {
+ using T = std::underlying_type_t<x11::ModMask>;
+ return static_cast<x11::ModMask>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::ModMask operator&(x11::ModMask l, x11::ModMask r) {
+ using T = std::underlying_type_t<x11::ModMask>;
+ return static_cast<x11::ModMask>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::KeyButMask operator|(x11::KeyButMask l,
+ x11::KeyButMask r) {
+ using T = std::underlying_type_t<x11::KeyButMask>;
+ return static_cast<x11::KeyButMask>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::KeyButMask operator&(x11::KeyButMask l,
+ x11::KeyButMask r) {
+ using T = std::underlying_type_t<x11::KeyButMask>;
+ return static_cast<x11::KeyButMask>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Window operator|(x11::Window l, x11::Window r) {
+ using T = std::underlying_type_t<x11::Window>;
+ return static_cast<x11::Window>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Window operator&(x11::Window l, x11::Window r) {
+ using T = std::underlying_type_t<x11::Window>;
+ return static_cast<x11::Window>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ButtonMask operator|(x11::ButtonMask l,
+ x11::ButtonMask r) {
+ using T = std::underlying_type_t<x11::ButtonMask>;
+ return static_cast<x11::ButtonMask>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::ButtonMask operator&(x11::ButtonMask l,
+ x11::ButtonMask r) {
+ using T = std::underlying_type_t<x11::ButtonMask>;
+ return static_cast<x11::ButtonMask>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Motion operator|(x11::Motion l, x11::Motion r) {
+ using T = std::underlying_type_t<x11::Motion>;
+ return static_cast<x11::Motion>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Motion operator&(x11::Motion l, x11::Motion r) {
+ using T = std::underlying_type_t<x11::Motion>;
+ return static_cast<x11::Motion>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::NotifyDetail operator|(x11::NotifyDetail l,
+ x11::NotifyDetail r) {
+ using T = std::underlying_type_t<x11::NotifyDetail>;
+ return static_cast<x11::NotifyDetail>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::NotifyDetail operator&(x11::NotifyDetail l,
+ x11::NotifyDetail r) {
+ using T = std::underlying_type_t<x11::NotifyDetail>;
+ return static_cast<x11::NotifyDetail>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::NotifyMode operator|(x11::NotifyMode l,
+ x11::NotifyMode r) {
+ using T = std::underlying_type_t<x11::NotifyMode>;
+ return static_cast<x11::NotifyMode>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::NotifyMode operator&(x11::NotifyMode l,
+ x11::NotifyMode r) {
+ using T = std::underlying_type_t<x11::NotifyMode>;
+ return static_cast<x11::NotifyMode>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Visibility operator|(x11::Visibility l,
+ x11::Visibility r) {
+ using T = std::underlying_type_t<x11::Visibility>;
+ return static_cast<x11::Visibility>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Visibility operator&(x11::Visibility l,
+ x11::Visibility r) {
+ using T = std::underlying_type_t<x11::Visibility>;
+ return static_cast<x11::Visibility>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Place operator|(x11::Place l, x11::Place r) {
+ using T = std::underlying_type_t<x11::Place>;
+ return static_cast<x11::Place>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Place operator&(x11::Place l, x11::Place r) {
+ using T = std::underlying_type_t<x11::Place>;
+ return static_cast<x11::Place>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Property operator|(x11::Property l, x11::Property r) {
+ using T = std::underlying_type_t<x11::Property>;
+ return static_cast<x11::Property>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Property operator&(x11::Property l, x11::Property r) {
+ using T = std::underlying_type_t<x11::Property>;
+ return static_cast<x11::Property>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Time operator|(x11::Time l, x11::Time r) {
+ using T = std::underlying_type_t<x11::Time>;
+ return static_cast<x11::Time>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Time operator&(x11::Time l, x11::Time r) {
+ using T = std::underlying_type_t<x11::Time>;
+ return static_cast<x11::Time>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Atom operator|(x11::Atom l, x11::Atom r) {
+ using T = std::underlying_type_t<x11::Atom>;
+ return static_cast<x11::Atom>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Atom operator&(x11::Atom l, x11::Atom r) {
+ using T = std::underlying_type_t<x11::Atom>;
+ return static_cast<x11::Atom>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ColormapState operator|(x11::ColormapState l,
+ x11::ColormapState r) {
+ using T = std::underlying_type_t<x11::ColormapState>;
+ return static_cast<x11::ColormapState>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::ColormapState operator&(x11::ColormapState l,
+ x11::ColormapState r) {
+ using T = std::underlying_type_t<x11::ColormapState>;
+ return static_cast<x11::ColormapState>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Colormap operator|(x11::Colormap l, x11::Colormap r) {
+ using T = std::underlying_type_t<x11::Colormap>;
+ return static_cast<x11::Colormap>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Colormap operator&(x11::Colormap l, x11::Colormap r) {
+ using T = std::underlying_type_t<x11::Colormap>;
+ return static_cast<x11::Colormap>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Mapping operator|(x11::Mapping l, x11::Mapping r) {
+ using T = std::underlying_type_t<x11::Mapping>;
+ return static_cast<x11::Mapping>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Mapping operator&(x11::Mapping l, x11::Mapping r) {
+ using T = std::underlying_type_t<x11::Mapping>;
+ return static_cast<x11::Mapping>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::WindowClass operator|(x11::WindowClass l,
+ x11::WindowClass r) {
+ using T = std::underlying_type_t<x11::WindowClass>;
+ return static_cast<x11::WindowClass>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::WindowClass operator&(x11::WindowClass l,
+ x11::WindowClass r) {
+ using T = std::underlying_type_t<x11::WindowClass>;
+ return static_cast<x11::WindowClass>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::CreateWindowAttribute operator|(
+ x11::CreateWindowAttribute l,
+ x11::CreateWindowAttribute r) {
+ using T = std::underlying_type_t<x11::CreateWindowAttribute>;
+ return static_cast<x11::CreateWindowAttribute>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::CreateWindowAttribute operator&(
+ x11::CreateWindowAttribute l,
+ x11::CreateWindowAttribute r) {
+ using T = std::underlying_type_t<x11::CreateWindowAttribute>;
+ return static_cast<x11::CreateWindowAttribute>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::BackPixmap operator|(x11::BackPixmap l,
+ x11::BackPixmap r) {
+ using T = std::underlying_type_t<x11::BackPixmap>;
+ return static_cast<x11::BackPixmap>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::BackPixmap operator&(x11::BackPixmap l,
+ x11::BackPixmap r) {
+ using T = std::underlying_type_t<x11::BackPixmap>;
+ return static_cast<x11::BackPixmap>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Gravity operator|(x11::Gravity l, x11::Gravity r) {
+ using T = std::underlying_type_t<x11::Gravity>;
+ return static_cast<x11::Gravity>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Gravity operator&(x11::Gravity l, x11::Gravity r) {
+ using T = std::underlying_type_t<x11::Gravity>;
+ return static_cast<x11::Gravity>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::MapState operator|(x11::MapState l, x11::MapState r) {
+ using T = std::underlying_type_t<x11::MapState>;
+ return static_cast<x11::MapState>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::MapState operator&(x11::MapState l, x11::MapState r) {
+ using T = std::underlying_type_t<x11::MapState>;
+ return static_cast<x11::MapState>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::SetMode operator|(x11::SetMode l, x11::SetMode r) {
+ using T = std::underlying_type_t<x11::SetMode>;
+ return static_cast<x11::SetMode>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::SetMode operator&(x11::SetMode l, x11::SetMode r) {
+ using T = std::underlying_type_t<x11::SetMode>;
+ return static_cast<x11::SetMode>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ConfigWindow operator|(x11::ConfigWindow l,
+ x11::ConfigWindow r) {
+ using T = std::underlying_type_t<x11::ConfigWindow>;
+ return static_cast<x11::ConfigWindow>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::ConfigWindow operator&(x11::ConfigWindow l,
+ x11::ConfigWindow r) {
+ using T = std::underlying_type_t<x11::ConfigWindow>;
+ return static_cast<x11::ConfigWindow>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::StackMode operator|(x11::StackMode l, x11::StackMode r) {
+ using T = std::underlying_type_t<x11::StackMode>;
+ return static_cast<x11::StackMode>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::StackMode operator&(x11::StackMode l, x11::StackMode r) {
+ using T = std::underlying_type_t<x11::StackMode>;
+ return static_cast<x11::StackMode>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Circulate operator|(x11::Circulate l, x11::Circulate r) {
+ using T = std::underlying_type_t<x11::Circulate>;
+ return static_cast<x11::Circulate>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Circulate operator&(x11::Circulate l, x11::Circulate r) {
+ using T = std::underlying_type_t<x11::Circulate>;
+ return static_cast<x11::Circulate>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::PropMode operator|(x11::PropMode l, x11::PropMode r) {
+ using T = std::underlying_type_t<x11::PropMode>;
+ return static_cast<x11::PropMode>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::PropMode operator&(x11::PropMode l, x11::PropMode r) {
+ using T = std::underlying_type_t<x11::PropMode>;
+ return static_cast<x11::PropMode>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::GetPropertyType operator|(x11::GetPropertyType l,
+ x11::GetPropertyType r) {
+ using T = std::underlying_type_t<x11::GetPropertyType>;
+ return static_cast<x11::GetPropertyType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::GetPropertyType operator&(x11::GetPropertyType l,
+ x11::GetPropertyType r) {
+ using T = std::underlying_type_t<x11::GetPropertyType>;
+ return static_cast<x11::GetPropertyType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::SendEventDest operator|(x11::SendEventDest l,
+ x11::SendEventDest r) {
+ using T = std::underlying_type_t<x11::SendEventDest>;
+ return static_cast<x11::SendEventDest>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::SendEventDest operator&(x11::SendEventDest l,
+ x11::SendEventDest r) {
+ using T = std::underlying_type_t<x11::SendEventDest>;
+ return static_cast<x11::SendEventDest>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::GrabMode operator|(x11::GrabMode l, x11::GrabMode r) {
+ using T = std::underlying_type_t<x11::GrabMode>;
+ return static_cast<x11::GrabMode>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::GrabMode operator&(x11::GrabMode l, x11::GrabMode r) {
+ using T = std::underlying_type_t<x11::GrabMode>;
+ return static_cast<x11::GrabMode>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::GrabStatus operator|(x11::GrabStatus l,
+ x11::GrabStatus r) {
+ using T = std::underlying_type_t<x11::GrabStatus>;
+ return static_cast<x11::GrabStatus>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::GrabStatus operator&(x11::GrabStatus l,
+ x11::GrabStatus r) {
+ using T = std::underlying_type_t<x11::GrabStatus>;
+ return static_cast<x11::GrabStatus>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Cursor operator|(x11::Cursor l, x11::Cursor r) {
+ using T = std::underlying_type_t<x11::Cursor>;
+ return static_cast<x11::Cursor>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Cursor operator&(x11::Cursor l, x11::Cursor r) {
+ using T = std::underlying_type_t<x11::Cursor>;
+ return static_cast<x11::Cursor>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ButtonIndex operator|(x11::ButtonIndex l,
+ x11::ButtonIndex r) {
+ using T = std::underlying_type_t<x11::ButtonIndex>;
+ return static_cast<x11::ButtonIndex>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::ButtonIndex operator&(x11::ButtonIndex l,
+ x11::ButtonIndex r) {
+ using T = std::underlying_type_t<x11::ButtonIndex>;
+ return static_cast<x11::ButtonIndex>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Grab operator|(x11::Grab l, x11::Grab r) {
+ using T = std::underlying_type_t<x11::Grab>;
+ return static_cast<x11::Grab>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Grab operator&(x11::Grab l, x11::Grab r) {
+ using T = std::underlying_type_t<x11::Grab>;
+ return static_cast<x11::Grab>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Allow operator|(x11::Allow l, x11::Allow r) {
+ using T = std::underlying_type_t<x11::Allow>;
+ return static_cast<x11::Allow>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Allow operator&(x11::Allow l, x11::Allow r) {
+ using T = std::underlying_type_t<x11::Allow>;
+ return static_cast<x11::Allow>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::InputFocus operator|(x11::InputFocus l,
+ x11::InputFocus r) {
+ using T = std::underlying_type_t<x11::InputFocus>;
+ return static_cast<x11::InputFocus>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::InputFocus operator&(x11::InputFocus l,
+ x11::InputFocus r) {
+ using T = std::underlying_type_t<x11::InputFocus>;
+ return static_cast<x11::InputFocus>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::FontDraw operator|(x11::FontDraw l, x11::FontDraw r) {
+ using T = std::underlying_type_t<x11::FontDraw>;
+ return static_cast<x11::FontDraw>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::FontDraw operator&(x11::FontDraw l, x11::FontDraw r) {
+ using T = std::underlying_type_t<x11::FontDraw>;
+ return static_cast<x11::FontDraw>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::GraphicsContextAttribute operator|(
+ x11::GraphicsContextAttribute l,
+ x11::GraphicsContextAttribute r) {
+ using T = std::underlying_type_t<x11::GraphicsContextAttribute>;
+ return static_cast<x11::GraphicsContextAttribute>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::GraphicsContextAttribute operator&(
+ x11::GraphicsContextAttribute l,
+ x11::GraphicsContextAttribute r) {
+ using T = std::underlying_type_t<x11::GraphicsContextAttribute>;
+ return static_cast<x11::GraphicsContextAttribute>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Gx operator|(x11::Gx l, x11::Gx r) {
+ using T = std::underlying_type_t<x11::Gx>;
+ return static_cast<x11::Gx>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Gx operator&(x11::Gx l, x11::Gx r) {
+ using T = std::underlying_type_t<x11::Gx>;
+ return static_cast<x11::Gx>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::LineStyle operator|(x11::LineStyle l, x11::LineStyle r) {
+ using T = std::underlying_type_t<x11::LineStyle>;
+ return static_cast<x11::LineStyle>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::LineStyle operator&(x11::LineStyle l, x11::LineStyle r) {
+ using T = std::underlying_type_t<x11::LineStyle>;
+ return static_cast<x11::LineStyle>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::CapStyle operator|(x11::CapStyle l, x11::CapStyle r) {
+ using T = std::underlying_type_t<x11::CapStyle>;
+ return static_cast<x11::CapStyle>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::CapStyle operator&(x11::CapStyle l, x11::CapStyle r) {
+ using T = std::underlying_type_t<x11::CapStyle>;
+ return static_cast<x11::CapStyle>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::JoinStyle operator|(x11::JoinStyle l, x11::JoinStyle r) {
+ using T = std::underlying_type_t<x11::JoinStyle>;
+ return static_cast<x11::JoinStyle>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::JoinStyle operator&(x11::JoinStyle l, x11::JoinStyle r) {
+ using T = std::underlying_type_t<x11::JoinStyle>;
+ return static_cast<x11::JoinStyle>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::FillStyle operator|(x11::FillStyle l, x11::FillStyle r) {
+ using T = std::underlying_type_t<x11::FillStyle>;
+ return static_cast<x11::FillStyle>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::FillStyle operator&(x11::FillStyle l, x11::FillStyle r) {
+ using T = std::underlying_type_t<x11::FillStyle>;
+ return static_cast<x11::FillStyle>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::FillRule operator|(x11::FillRule l, x11::FillRule r) {
+ using T = std::underlying_type_t<x11::FillRule>;
+ return static_cast<x11::FillRule>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::FillRule operator&(x11::FillRule l, x11::FillRule r) {
+ using T = std::underlying_type_t<x11::FillRule>;
+ return static_cast<x11::FillRule>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::SubwindowMode operator|(x11::SubwindowMode l,
+ x11::SubwindowMode r) {
+ using T = std::underlying_type_t<x11::SubwindowMode>;
+ return static_cast<x11::SubwindowMode>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::SubwindowMode operator&(x11::SubwindowMode l,
+ x11::SubwindowMode r) {
+ using T = std::underlying_type_t<x11::SubwindowMode>;
+ return static_cast<x11::SubwindowMode>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ArcMode operator|(x11::ArcMode l, x11::ArcMode r) {
+ using T = std::underlying_type_t<x11::ArcMode>;
+ return static_cast<x11::ArcMode>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::ArcMode operator&(x11::ArcMode l, x11::ArcMode r) {
+ using T = std::underlying_type_t<x11::ArcMode>;
+ return static_cast<x11::ArcMode>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ClipOrdering operator|(x11::ClipOrdering l,
+ x11::ClipOrdering r) {
+ using T = std::underlying_type_t<x11::ClipOrdering>;
+ return static_cast<x11::ClipOrdering>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::ClipOrdering operator&(x11::ClipOrdering l,
+ x11::ClipOrdering r) {
+ using T = std::underlying_type_t<x11::ClipOrdering>;
+ return static_cast<x11::ClipOrdering>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::CoordMode operator|(x11::CoordMode l, x11::CoordMode r) {
+ using T = std::underlying_type_t<x11::CoordMode>;
+ return static_cast<x11::CoordMode>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::CoordMode operator&(x11::CoordMode l, x11::CoordMode r) {
+ using T = std::underlying_type_t<x11::CoordMode>;
+ return static_cast<x11::CoordMode>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::PolyShape operator|(x11::PolyShape l, x11::PolyShape r) {
+ using T = std::underlying_type_t<x11::PolyShape>;
+ return static_cast<x11::PolyShape>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::PolyShape operator&(x11::PolyShape l, x11::PolyShape r) {
+ using T = std::underlying_type_t<x11::PolyShape>;
+ return static_cast<x11::PolyShape>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ImageFormat operator|(x11::ImageFormat l,
+ x11::ImageFormat r) {
+ using T = std::underlying_type_t<x11::ImageFormat>;
+ return static_cast<x11::ImageFormat>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::ImageFormat operator&(x11::ImageFormat l,
+ x11::ImageFormat r) {
+ using T = std::underlying_type_t<x11::ImageFormat>;
+ return static_cast<x11::ImageFormat>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ColormapAlloc operator|(x11::ColormapAlloc l,
+ x11::ColormapAlloc r) {
+ using T = std::underlying_type_t<x11::ColormapAlloc>;
+ return static_cast<x11::ColormapAlloc>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::ColormapAlloc operator&(x11::ColormapAlloc l,
+ x11::ColormapAlloc r) {
+ using T = std::underlying_type_t<x11::ColormapAlloc>;
+ return static_cast<x11::ColormapAlloc>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ColorFlag operator|(x11::ColorFlag l, x11::ColorFlag r) {
+ using T = std::underlying_type_t<x11::ColorFlag>;
+ return static_cast<x11::ColorFlag>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::ColorFlag operator&(x11::ColorFlag l, x11::ColorFlag r) {
+ using T = std::underlying_type_t<x11::ColorFlag>;
+ return static_cast<x11::ColorFlag>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Pixmap operator|(x11::Pixmap l, x11::Pixmap r) {
+ using T = std::underlying_type_t<x11::Pixmap>;
+ return static_cast<x11::Pixmap>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Pixmap operator&(x11::Pixmap l, x11::Pixmap r) {
+ using T = std::underlying_type_t<x11::Pixmap>;
+ return static_cast<x11::Pixmap>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Font operator|(x11::Font l, x11::Font r) {
+ using T = std::underlying_type_t<x11::Font>;
+ return static_cast<x11::Font>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Font operator&(x11::Font l, x11::Font r) {
+ using T = std::underlying_type_t<x11::Font>;
+ return static_cast<x11::Font>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::QueryShapeOf operator|(x11::QueryShapeOf l,
+ x11::QueryShapeOf r) {
+ using T = std::underlying_type_t<x11::QueryShapeOf>;
+ return static_cast<x11::QueryShapeOf>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::QueryShapeOf operator&(x11::QueryShapeOf l,
+ x11::QueryShapeOf r) {
+ using T = std::underlying_type_t<x11::QueryShapeOf>;
+ return static_cast<x11::QueryShapeOf>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Keyboard operator|(x11::Keyboard l, x11::Keyboard r) {
+ using T = std::underlying_type_t<x11::Keyboard>;
+ return static_cast<x11::Keyboard>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Keyboard operator&(x11::Keyboard l, x11::Keyboard r) {
+ using T = std::underlying_type_t<x11::Keyboard>;
+ return static_cast<x11::Keyboard>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::LedMode operator|(x11::LedMode l, x11::LedMode r) {
+ using T = std::underlying_type_t<x11::LedMode>;
+ return static_cast<x11::LedMode>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::LedMode operator&(x11::LedMode l, x11::LedMode r) {
+ using T = std::underlying_type_t<x11::LedMode>;
+ return static_cast<x11::LedMode>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::AutoRepeatMode operator|(x11::AutoRepeatMode l,
+ x11::AutoRepeatMode r) {
+ using T = std::underlying_type_t<x11::AutoRepeatMode>;
+ return static_cast<x11::AutoRepeatMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::AutoRepeatMode operator&(x11::AutoRepeatMode l,
+ x11::AutoRepeatMode r) {
+ using T = std::underlying_type_t<x11::AutoRepeatMode>;
+ return static_cast<x11::AutoRepeatMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Blanking operator|(x11::Blanking l, x11::Blanking r) {
+ using T = std::underlying_type_t<x11::Blanking>;
+ return static_cast<x11::Blanking>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Blanking operator&(x11::Blanking l, x11::Blanking r) {
+ using T = std::underlying_type_t<x11::Blanking>;
+ return static_cast<x11::Blanking>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Exposures operator|(x11::Exposures l, x11::Exposures r) {
+ using T = std::underlying_type_t<x11::Exposures>;
+ return static_cast<x11::Exposures>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Exposures operator&(x11::Exposures l, x11::Exposures r) {
+ using T = std::underlying_type_t<x11::Exposures>;
+ return static_cast<x11::Exposures>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::HostMode operator|(x11::HostMode l, x11::HostMode r) {
+ using T = std::underlying_type_t<x11::HostMode>;
+ return static_cast<x11::HostMode>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::HostMode operator&(x11::HostMode l, x11::HostMode r) {
+ using T = std::underlying_type_t<x11::HostMode>;
+ return static_cast<x11::HostMode>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Family operator|(x11::Family l, x11::Family r) {
+ using T = std::underlying_type_t<x11::Family>;
+ return static_cast<x11::Family>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Family operator&(x11::Family l, x11::Family r) {
+ using T = std::underlying_type_t<x11::Family>;
+ return static_cast<x11::Family>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::AccessControl operator|(x11::AccessControl l,
+ x11::AccessControl r) {
+ using T = std::underlying_type_t<x11::AccessControl>;
+ return static_cast<x11::AccessControl>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::AccessControl operator&(x11::AccessControl l,
+ x11::AccessControl r) {
+ using T = std::underlying_type_t<x11::AccessControl>;
+ return static_cast<x11::AccessControl>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::CloseDown operator|(x11::CloseDown l, x11::CloseDown r) {
+ using T = std::underlying_type_t<x11::CloseDown>;
+ return static_cast<x11::CloseDown>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::CloseDown operator&(x11::CloseDown l, x11::CloseDown r) {
+ using T = std::underlying_type_t<x11::CloseDown>;
+ return static_cast<x11::CloseDown>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Kill operator|(x11::Kill l, x11::Kill r) {
+ using T = std::underlying_type_t<x11::Kill>;
+ return static_cast<x11::Kill>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Kill operator&(x11::Kill l, x11::Kill r) {
+ using T = std::underlying_type_t<x11::Kill>;
+ return static_cast<x11::Kill>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::ScreenSaverMode operator|(x11::ScreenSaverMode l,
+ x11::ScreenSaverMode r) {
+ using T = std::underlying_type_t<x11::ScreenSaverMode>;
+ return static_cast<x11::ScreenSaverMode>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::ScreenSaverMode operator&(x11::ScreenSaverMode l,
+ x11::ScreenSaverMode r) {
+ using T = std::underlying_type_t<x11::ScreenSaverMode>;
+ return static_cast<x11::ScreenSaverMode>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::MappingStatus operator|(x11::MappingStatus l,
+ x11::MappingStatus r) {
+ using T = std::underlying_type_t<x11::MappingStatus>;
+ return static_cast<x11::MappingStatus>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::MappingStatus operator&(x11::MappingStatus l,
+ x11::MappingStatus r) {
+ using T = std::underlying_type_t<x11::MappingStatus>;
+ return static_cast<x11::MappingStatus>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::MapIndex operator|(x11::MapIndex l, x11::MapIndex r) {
+ using T = std::underlying_type_t<x11::MapIndex>;
+ return static_cast<x11::MapIndex>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::MapIndex operator&(x11::MapIndex l, x11::MapIndex r) {
+ using T = std::underlying_type_t<x11::MapIndex>;
+ return static_cast<x11::MapIndex>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XPROTO_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xselinux.cc b/chromium/ui/gfx/x/generated_protos/xselinux.cc
new file mode 100644
index 00000000000..453b3deab92
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xselinux.cc
@@ -0,0 +1,1683 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xselinux.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+SELinux::SELinux(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<SELinux::QueryVersionReply> SELinux::QueryVersion(
+ const SELinux::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& client_major = request.client_major;
+ auto& client_minor = request.client_minor;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // client_major
+ buf.Write(&client_major);
+
+ // client_minor
+ buf.Write(&client_minor);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::QueryVersionReply>(
+ &buf, "SELinux::QueryVersion", false);
+}
+
+Future<SELinux::QueryVersionReply> SELinux::QueryVersion(
+ const uint8_t& client_major,
+ const uint8_t& client_minor) {
+ return SELinux::QueryVersion(
+ SELinux::QueryVersionRequest{client_major, client_minor});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::QueryVersionReply> detail::ReadReply<
+ SELinux::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& server_major = (*reply).server_major;
+ auto& server_minor = (*reply).server_minor;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // server_major
+ Read(&server_major, &buf);
+
+ // server_minor
+ Read(&server_minor, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> SELinux::SetDeviceCreateContext(
+ const SELinux::SetDeviceCreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint32_t context_len{};
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_len
+ context_len = context.size();
+ buf.Write(&context_len);
+
+ // context
+ DCHECK_EQ(static_cast<size_t>(context_len), context.size());
+ for (auto& context_elem : context) {
+ // context_elem
+ buf.Write(&context_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SELinux::SetDeviceCreateContext",
+ false);
+}
+
+Future<void> SELinux::SetDeviceCreateContext(const std::string& context) {
+ return SELinux::SetDeviceCreateContext(
+ SELinux::SetDeviceCreateContextRequest{context});
+}
+
+Future<SELinux::GetDeviceCreateContextReply> SELinux::GetDeviceCreateContext(
+ const SELinux::GetDeviceCreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetDeviceCreateContextReply>(
+ &buf, "SELinux::GetDeviceCreateContext", false);
+}
+
+Future<SELinux::GetDeviceCreateContextReply> SELinux::GetDeviceCreateContext() {
+ return SELinux::GetDeviceCreateContext(
+ SELinux::GetDeviceCreateContextRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetDeviceCreateContextReply> detail::ReadReply<
+ SELinux::GetDeviceCreateContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetDeviceCreateContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> SELinux::SetDeviceContext(
+ const SELinux::SetDeviceContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device = request.device;
+ uint32_t context_len{};
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device
+ buf.Write(&device);
+
+ // context_len
+ context_len = context.size();
+ buf.Write(&context_len);
+
+ // context
+ DCHECK_EQ(static_cast<size_t>(context_len), context.size());
+ for (auto& context_elem : context) {
+ // context_elem
+ buf.Write(&context_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SELinux::SetDeviceContext",
+ false);
+}
+
+Future<void> SELinux::SetDeviceContext(const uint32_t& device,
+ const std::string& context) {
+ return SELinux::SetDeviceContext(
+ SELinux::SetDeviceContextRequest{device, context});
+}
+
+Future<SELinux::GetDeviceContextReply> SELinux::GetDeviceContext(
+ const SELinux::GetDeviceContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& device = request.device;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // device
+ buf.Write(&device);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetDeviceContextReply>(
+ &buf, "SELinux::GetDeviceContext", false);
+}
+
+Future<SELinux::GetDeviceContextReply> SELinux::GetDeviceContext(
+ const uint32_t& device) {
+ return SELinux::GetDeviceContext(SELinux::GetDeviceContextRequest{device});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetDeviceContextReply> detail::ReadReply<
+ SELinux::GetDeviceContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetDeviceContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> SELinux::SetWindowCreateContext(
+ const SELinux::SetWindowCreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint32_t context_len{};
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_len
+ context_len = context.size();
+ buf.Write(&context_len);
+
+ // context
+ DCHECK_EQ(static_cast<size_t>(context_len), context.size());
+ for (auto& context_elem : context) {
+ // context_elem
+ buf.Write(&context_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SELinux::SetWindowCreateContext",
+ false);
+}
+
+Future<void> SELinux::SetWindowCreateContext(const std::string& context) {
+ return SELinux::SetWindowCreateContext(
+ SELinux::SetWindowCreateContextRequest{context});
+}
+
+Future<SELinux::GetWindowCreateContextReply> SELinux::GetWindowCreateContext(
+ const SELinux::GetWindowCreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetWindowCreateContextReply>(
+ &buf, "SELinux::GetWindowCreateContext", false);
+}
+
+Future<SELinux::GetWindowCreateContextReply> SELinux::GetWindowCreateContext() {
+ return SELinux::GetWindowCreateContext(
+ SELinux::GetWindowCreateContextRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetWindowCreateContextReply> detail::ReadReply<
+ SELinux::GetWindowCreateContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetWindowCreateContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<SELinux::GetWindowContextReply> SELinux::GetWindowContext(
+ const SELinux::GetWindowContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetWindowContextReply>(
+ &buf, "SELinux::GetWindowContext", false);
+}
+
+Future<SELinux::GetWindowContextReply> SELinux::GetWindowContext(
+ const Window& window) {
+ return SELinux::GetWindowContext(SELinux::GetWindowContextRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetWindowContextReply> detail::ReadReply<
+ SELinux::GetWindowContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetWindowContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> SELinux::SetPropertyCreateContext(
+ const SELinux::SetPropertyCreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint32_t context_len{};
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_len
+ context_len = context.size();
+ buf.Write(&context_len);
+
+ // context
+ DCHECK_EQ(static_cast<size_t>(context_len), context.size());
+ for (auto& context_elem : context) {
+ // context_elem
+ buf.Write(&context_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(
+ &buf, "SELinux::SetPropertyCreateContext", false);
+}
+
+Future<void> SELinux::SetPropertyCreateContext(const std::string& context) {
+ return SELinux::SetPropertyCreateContext(
+ SELinux::SetPropertyCreateContextRequest{context});
+}
+
+Future<SELinux::GetPropertyCreateContextReply>
+SELinux::GetPropertyCreateContext(
+ const SELinux::GetPropertyCreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetPropertyCreateContextReply>(
+ &buf, "SELinux::GetPropertyCreateContext", false);
+}
+
+Future<SELinux::GetPropertyCreateContextReply>
+SELinux::GetPropertyCreateContext() {
+ return SELinux::GetPropertyCreateContext(
+ SELinux::GetPropertyCreateContextRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetPropertyCreateContextReply> detail::ReadReply<
+ SELinux::GetPropertyCreateContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetPropertyCreateContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> SELinux::SetPropertyUseContext(
+ const SELinux::SetPropertyUseContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint32_t context_len{};
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_len
+ context_len = context.size();
+ buf.Write(&context_len);
+
+ // context
+ DCHECK_EQ(static_cast<size_t>(context_len), context.size());
+ for (auto& context_elem : context) {
+ // context_elem
+ buf.Write(&context_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SELinux::SetPropertyUseContext",
+ false);
+}
+
+Future<void> SELinux::SetPropertyUseContext(const std::string& context) {
+ return SELinux::SetPropertyUseContext(
+ SELinux::SetPropertyUseContextRequest{context});
+}
+
+Future<SELinux::GetPropertyUseContextReply> SELinux::GetPropertyUseContext(
+ const SELinux::GetPropertyUseContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetPropertyUseContextReply>(
+ &buf, "SELinux::GetPropertyUseContext", false);
+}
+
+Future<SELinux::GetPropertyUseContextReply> SELinux::GetPropertyUseContext() {
+ return SELinux::GetPropertyUseContext(
+ SELinux::GetPropertyUseContextRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetPropertyUseContextReply> detail::ReadReply<
+ SELinux::GetPropertyUseContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetPropertyUseContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<SELinux::GetPropertyContextReply> SELinux::GetPropertyContext(
+ const SELinux::GetPropertyContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& property = request.property;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // property
+ buf.Write(&property);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetPropertyContextReply>(
+ &buf, "SELinux::GetPropertyContext", false);
+}
+
+Future<SELinux::GetPropertyContextReply> SELinux::GetPropertyContext(
+ const Window& window,
+ const Atom& property) {
+ return SELinux::GetPropertyContext(
+ SELinux::GetPropertyContextRequest{window, property});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetPropertyContextReply> detail::ReadReply<
+ SELinux::GetPropertyContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetPropertyContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<SELinux::GetPropertyDataContextReply> SELinux::GetPropertyDataContext(
+ const SELinux::GetPropertyDataContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& property = request.property;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // property
+ buf.Write(&property);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetPropertyDataContextReply>(
+ &buf, "SELinux::GetPropertyDataContext", false);
+}
+
+Future<SELinux::GetPropertyDataContextReply> SELinux::GetPropertyDataContext(
+ const Window& window,
+ const Atom& property) {
+ return SELinux::GetPropertyDataContext(
+ SELinux::GetPropertyDataContextRequest{window, property});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetPropertyDataContextReply> detail::ReadReply<
+ SELinux::GetPropertyDataContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetPropertyDataContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<SELinux::ListPropertiesReply> SELinux::ListProperties(
+ const SELinux::ListPropertiesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 14;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::ListPropertiesReply>(
+ &buf, "SELinux::ListProperties", false);
+}
+
+Future<SELinux::ListPropertiesReply> SELinux::ListProperties(
+ const Window& window) {
+ return SELinux::ListProperties(SELinux::ListPropertiesRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::ListPropertiesReply> detail::ReadReply<
+ SELinux::ListPropertiesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::ListPropertiesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t properties_len{};
+ auto& properties = (*reply).properties;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // properties_len
+ Read(&properties_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // properties
+ properties.resize(properties_len);
+ for (auto& properties_elem : properties) {
+ // properties_elem
+ {
+ auto& name = properties_elem.name;
+ uint32_t object_context_len{};
+ uint32_t data_context_len{};
+ auto& object_context = properties_elem.object_context;
+ auto& data_context = properties_elem.data_context;
+
+ // name
+ Read(&name, &buf);
+
+ // object_context_len
+ Read(&object_context_len, &buf);
+
+ // data_context_len
+ Read(&data_context_len, &buf);
+
+ // object_context
+ object_context.resize(object_context_len);
+ for (auto& object_context_elem : object_context) {
+ // object_context_elem
+ Read(&object_context_elem, &buf);
+ }
+
+ // pad0
+ Align(&buf, 4);
+
+ // data_context
+ data_context.resize(data_context_len);
+ for (auto& data_context_elem : data_context) {
+ // data_context_elem
+ Read(&data_context_elem, &buf);
+ }
+
+ // pad1
+ Align(&buf, 4);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> SELinux::SetSelectionCreateContext(
+ const SELinux::SetSelectionCreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint32_t context_len{};
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 15;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_len
+ context_len = context.size();
+ buf.Write(&context_len);
+
+ // context
+ DCHECK_EQ(static_cast<size_t>(context_len), context.size());
+ for (auto& context_elem : context) {
+ // context_elem
+ buf.Write(&context_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(
+ &buf, "SELinux::SetSelectionCreateContext", false);
+}
+
+Future<void> SELinux::SetSelectionCreateContext(const std::string& context) {
+ return SELinux::SetSelectionCreateContext(
+ SELinux::SetSelectionCreateContextRequest{context});
+}
+
+Future<SELinux::GetSelectionCreateContextReply>
+SELinux::GetSelectionCreateContext(
+ const SELinux::GetSelectionCreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 16;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetSelectionCreateContextReply>(
+ &buf, "SELinux::GetSelectionCreateContext", false);
+}
+
+Future<SELinux::GetSelectionCreateContextReply>
+SELinux::GetSelectionCreateContext() {
+ return SELinux::GetSelectionCreateContext(
+ SELinux::GetSelectionCreateContextRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetSelectionCreateContextReply> detail::ReadReply<
+ SELinux::GetSelectionCreateContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetSelectionCreateContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> SELinux::SetSelectionUseContext(
+ const SELinux::SetSelectionUseContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ uint32_t context_len{};
+ auto& context = request.context;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 17;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_len
+ context_len = context.size();
+ buf.Write(&context_len);
+
+ // context
+ DCHECK_EQ(static_cast<size_t>(context_len), context.size());
+ for (auto& context_elem : context) {
+ // context_elem
+ buf.Write(&context_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "SELinux::SetSelectionUseContext",
+ false);
+}
+
+Future<void> SELinux::SetSelectionUseContext(const std::string& context) {
+ return SELinux::SetSelectionUseContext(
+ SELinux::SetSelectionUseContextRequest{context});
+}
+
+Future<SELinux::GetSelectionUseContextReply> SELinux::GetSelectionUseContext(
+ const SELinux::GetSelectionUseContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 18;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetSelectionUseContextReply>(
+ &buf, "SELinux::GetSelectionUseContext", false);
+}
+
+Future<SELinux::GetSelectionUseContextReply> SELinux::GetSelectionUseContext() {
+ return SELinux::GetSelectionUseContext(
+ SELinux::GetSelectionUseContextRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetSelectionUseContextReply> detail::ReadReply<
+ SELinux::GetSelectionUseContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetSelectionUseContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<SELinux::GetSelectionContextReply> SELinux::GetSelectionContext(
+ const SELinux::GetSelectionContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& selection = request.selection;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 19;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // selection
+ buf.Write(&selection);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetSelectionContextReply>(
+ &buf, "SELinux::GetSelectionContext", false);
+}
+
+Future<SELinux::GetSelectionContextReply> SELinux::GetSelectionContext(
+ const Atom& selection) {
+ return SELinux::GetSelectionContext(
+ SELinux::GetSelectionContextRequest{selection});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetSelectionContextReply> detail::ReadReply<
+ SELinux::GetSelectionContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetSelectionContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<SELinux::GetSelectionDataContextReply> SELinux::GetSelectionDataContext(
+ const SELinux::GetSelectionDataContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& selection = request.selection;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 20;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // selection
+ buf.Write(&selection);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetSelectionDataContextReply>(
+ &buf, "SELinux::GetSelectionDataContext", false);
+}
+
+Future<SELinux::GetSelectionDataContextReply> SELinux::GetSelectionDataContext(
+ const Atom& selection) {
+ return SELinux::GetSelectionDataContext(
+ SELinux::GetSelectionDataContextRequest{selection});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetSelectionDataContextReply> detail::ReadReply<
+ SELinux::GetSelectionDataContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetSelectionDataContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<SELinux::ListSelectionsReply> SELinux::ListSelections(
+ const SELinux::ListSelectionsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 21;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::ListSelectionsReply>(
+ &buf, "SELinux::ListSelections", false);
+}
+
+Future<SELinux::ListSelectionsReply> SELinux::ListSelections() {
+ return SELinux::ListSelections(SELinux::ListSelectionsRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::ListSelectionsReply> detail::ReadReply<
+ SELinux::ListSelectionsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::ListSelectionsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t selections_len{};
+ auto& selections = (*reply).selections;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // selections_len
+ Read(&selections_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // selections
+ selections.resize(selections_len);
+ for (auto& selections_elem : selections) {
+ // selections_elem
+ {
+ auto& name = selections_elem.name;
+ uint32_t object_context_len{};
+ uint32_t data_context_len{};
+ auto& object_context = selections_elem.object_context;
+ auto& data_context = selections_elem.data_context;
+
+ // name
+ Read(&name, &buf);
+
+ // object_context_len
+ Read(&object_context_len, &buf);
+
+ // data_context_len
+ Read(&data_context_len, &buf);
+
+ // object_context
+ object_context.resize(object_context_len);
+ for (auto& object_context_elem : object_context) {
+ // object_context_elem
+ Read(&object_context_elem, &buf);
+ }
+
+ // pad0
+ Align(&buf, 4);
+
+ // data_context
+ data_context.resize(data_context_len);
+ for (auto& data_context_elem : data_context) {
+ // data_context_elem
+ Read(&data_context_elem, &buf);
+ }
+
+ // pad1
+ Align(&buf, 4);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<SELinux::GetClientContextReply> SELinux::GetClientContext(
+ const SELinux::GetClientContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& resource = request.resource;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 22;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // resource
+ buf.Write(&resource);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<SELinux::GetClientContextReply>(
+ &buf, "SELinux::GetClientContext", false);
+}
+
+Future<SELinux::GetClientContextReply> SELinux::GetClientContext(
+ const uint32_t& resource) {
+ return SELinux::GetClientContext(SELinux::GetClientContextRequest{resource});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<SELinux::GetClientContextReply> detail::ReadReply<
+ SELinux::GetClientContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<SELinux::GetClientContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t context_len{};
+ auto& context = (*reply).context;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // context_len
+ Read(&context_len, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // context
+ context.resize(context_len);
+ for (auto& context_elem : context) {
+ // context_elem
+ Read(&context_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xselinux.h b/chromium/ui/gfx/x/generated_protos/xselinux.h
new file mode 100644
index 00000000000..bd5e30ffc0b
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xselinux.h
@@ -0,0 +1,428 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XSELINUX_H_
+#define UI_GFX_X_GENERATED_PROTOS_XSELINUX_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) SELinux {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 0;
+
+ SELinux(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ struct ListItem {
+ Atom name{};
+ std::string object_context{};
+ std::string data_context{};
+ };
+
+ struct QueryVersionRequest {
+ uint8_t client_major{};
+ uint8_t client_minor{};
+ };
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint16_t server_major{};
+ uint16_t server_minor{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion(const uint8_t& client_major = {},
+ const uint8_t& client_minor = {});
+
+ struct SetDeviceCreateContextRequest {
+ std::string context{};
+ };
+
+ using SetDeviceCreateContextResponse = Response<void>;
+
+ Future<void> SetDeviceCreateContext(
+ const SetDeviceCreateContextRequest& request);
+
+ Future<void> SetDeviceCreateContext(const std::string& context = {});
+
+ struct GetDeviceCreateContextRequest {};
+
+ struct GetDeviceCreateContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetDeviceCreateContextResponse = Response<GetDeviceCreateContextReply>;
+
+ Future<GetDeviceCreateContextReply> GetDeviceCreateContext(
+ const GetDeviceCreateContextRequest& request);
+
+ Future<GetDeviceCreateContextReply> GetDeviceCreateContext();
+
+ struct SetDeviceContextRequest {
+ uint32_t device{};
+ std::string context{};
+ };
+
+ using SetDeviceContextResponse = Response<void>;
+
+ Future<void> SetDeviceContext(const SetDeviceContextRequest& request);
+
+ Future<void> SetDeviceContext(const uint32_t& device = {},
+ const std::string& context = {});
+
+ struct GetDeviceContextRequest {
+ uint32_t device{};
+ };
+
+ struct GetDeviceContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetDeviceContextResponse = Response<GetDeviceContextReply>;
+
+ Future<GetDeviceContextReply> GetDeviceContext(
+ const GetDeviceContextRequest& request);
+
+ Future<GetDeviceContextReply> GetDeviceContext(const uint32_t& device = {});
+
+ struct SetWindowCreateContextRequest {
+ std::string context{};
+ };
+
+ using SetWindowCreateContextResponse = Response<void>;
+
+ Future<void> SetWindowCreateContext(
+ const SetWindowCreateContextRequest& request);
+
+ Future<void> SetWindowCreateContext(const std::string& context = {});
+
+ struct GetWindowCreateContextRequest {};
+
+ struct GetWindowCreateContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetWindowCreateContextResponse = Response<GetWindowCreateContextReply>;
+
+ Future<GetWindowCreateContextReply> GetWindowCreateContext(
+ const GetWindowCreateContextRequest& request);
+
+ Future<GetWindowCreateContextReply> GetWindowCreateContext();
+
+ struct GetWindowContextRequest {
+ Window window{};
+ };
+
+ struct GetWindowContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetWindowContextResponse = Response<GetWindowContextReply>;
+
+ Future<GetWindowContextReply> GetWindowContext(
+ const GetWindowContextRequest& request);
+
+ Future<GetWindowContextReply> GetWindowContext(const Window& window = {});
+
+ struct SetPropertyCreateContextRequest {
+ std::string context{};
+ };
+
+ using SetPropertyCreateContextResponse = Response<void>;
+
+ Future<void> SetPropertyCreateContext(
+ const SetPropertyCreateContextRequest& request);
+
+ Future<void> SetPropertyCreateContext(const std::string& context = {});
+
+ struct GetPropertyCreateContextRequest {};
+
+ struct GetPropertyCreateContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetPropertyCreateContextResponse =
+ Response<GetPropertyCreateContextReply>;
+
+ Future<GetPropertyCreateContextReply> GetPropertyCreateContext(
+ const GetPropertyCreateContextRequest& request);
+
+ Future<GetPropertyCreateContextReply> GetPropertyCreateContext();
+
+ struct SetPropertyUseContextRequest {
+ std::string context{};
+ };
+
+ using SetPropertyUseContextResponse = Response<void>;
+
+ Future<void> SetPropertyUseContext(
+ const SetPropertyUseContextRequest& request);
+
+ Future<void> SetPropertyUseContext(const std::string& context = {});
+
+ struct GetPropertyUseContextRequest {};
+
+ struct GetPropertyUseContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetPropertyUseContextResponse = Response<GetPropertyUseContextReply>;
+
+ Future<GetPropertyUseContextReply> GetPropertyUseContext(
+ const GetPropertyUseContextRequest& request);
+
+ Future<GetPropertyUseContextReply> GetPropertyUseContext();
+
+ struct GetPropertyContextRequest {
+ Window window{};
+ Atom property{};
+ };
+
+ struct GetPropertyContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetPropertyContextResponse = Response<GetPropertyContextReply>;
+
+ Future<GetPropertyContextReply> GetPropertyContext(
+ const GetPropertyContextRequest& request);
+
+ Future<GetPropertyContextReply> GetPropertyContext(const Window& window = {},
+ const Atom& property = {});
+
+ struct GetPropertyDataContextRequest {
+ Window window{};
+ Atom property{};
+ };
+
+ struct GetPropertyDataContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetPropertyDataContextResponse = Response<GetPropertyDataContextReply>;
+
+ Future<GetPropertyDataContextReply> GetPropertyDataContext(
+ const GetPropertyDataContextRequest& request);
+
+ Future<GetPropertyDataContextReply> GetPropertyDataContext(
+ const Window& window = {},
+ const Atom& property = {});
+
+ struct ListPropertiesRequest {
+ Window window{};
+ };
+
+ struct ListPropertiesReply {
+ uint16_t sequence{};
+ std::vector<ListItem> properties{};
+ };
+
+ using ListPropertiesResponse = Response<ListPropertiesReply>;
+
+ Future<ListPropertiesReply> ListProperties(
+ const ListPropertiesRequest& request);
+
+ Future<ListPropertiesReply> ListProperties(const Window& window = {});
+
+ struct SetSelectionCreateContextRequest {
+ std::string context{};
+ };
+
+ using SetSelectionCreateContextResponse = Response<void>;
+
+ Future<void> SetSelectionCreateContext(
+ const SetSelectionCreateContextRequest& request);
+
+ Future<void> SetSelectionCreateContext(const std::string& context = {});
+
+ struct GetSelectionCreateContextRequest {};
+
+ struct GetSelectionCreateContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetSelectionCreateContextResponse =
+ Response<GetSelectionCreateContextReply>;
+
+ Future<GetSelectionCreateContextReply> GetSelectionCreateContext(
+ const GetSelectionCreateContextRequest& request);
+
+ Future<GetSelectionCreateContextReply> GetSelectionCreateContext();
+
+ struct SetSelectionUseContextRequest {
+ std::string context{};
+ };
+
+ using SetSelectionUseContextResponse = Response<void>;
+
+ Future<void> SetSelectionUseContext(
+ const SetSelectionUseContextRequest& request);
+
+ Future<void> SetSelectionUseContext(const std::string& context = {});
+
+ struct GetSelectionUseContextRequest {};
+
+ struct GetSelectionUseContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetSelectionUseContextResponse = Response<GetSelectionUseContextReply>;
+
+ Future<GetSelectionUseContextReply> GetSelectionUseContext(
+ const GetSelectionUseContextRequest& request);
+
+ Future<GetSelectionUseContextReply> GetSelectionUseContext();
+
+ struct GetSelectionContextRequest {
+ Atom selection{};
+ };
+
+ struct GetSelectionContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetSelectionContextResponse = Response<GetSelectionContextReply>;
+
+ Future<GetSelectionContextReply> GetSelectionContext(
+ const GetSelectionContextRequest& request);
+
+ Future<GetSelectionContextReply> GetSelectionContext(
+ const Atom& selection = {});
+
+ struct GetSelectionDataContextRequest {
+ Atom selection{};
+ };
+
+ struct GetSelectionDataContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetSelectionDataContextResponse =
+ Response<GetSelectionDataContextReply>;
+
+ Future<GetSelectionDataContextReply> GetSelectionDataContext(
+ const GetSelectionDataContextRequest& request);
+
+ Future<GetSelectionDataContextReply> GetSelectionDataContext(
+ const Atom& selection = {});
+
+ struct ListSelectionsRequest {};
+
+ struct ListSelectionsReply {
+ uint16_t sequence{};
+ std::vector<ListItem> selections{};
+ };
+
+ using ListSelectionsResponse = Response<ListSelectionsReply>;
+
+ Future<ListSelectionsReply> ListSelections(
+ const ListSelectionsRequest& request);
+
+ Future<ListSelectionsReply> ListSelections();
+
+ struct GetClientContextRequest {
+ uint32_t resource{};
+ };
+
+ struct GetClientContextReply {
+ uint16_t sequence{};
+ std::string context{};
+ };
+
+ using GetClientContextResponse = Response<GetClientContextReply>;
+
+ Future<GetClientContextReply> GetClientContext(
+ const GetClientContextRequest& request);
+
+ Future<GetClientContextReply> GetClientContext(const uint32_t& resource = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XSELINUX_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xtest.cc b/chromium/ui/gfx/x/generated_protos/xtest.cc
new file mode 100644
index 00000000000..709caef798a
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xtest.cc
@@ -0,0 +1,309 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xtest.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Test::Test(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<Test::GetVersionReply> Test::GetVersion(
+ const Test::GetVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& major_version = request.major_version;
+ auto& minor_version = request.minor_version;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // major_version
+ buf.Write(&major_version);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // minor_version
+ buf.Write(&minor_version);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Test::GetVersionReply>(
+ &buf, "Test::GetVersion", false);
+}
+
+Future<Test::GetVersionReply> Test::GetVersion(const uint8_t& major_version,
+ const uint16_t& minor_version) {
+ return Test::GetVersion(
+ Test::GetVersionRequest{major_version, minor_version});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Test::GetVersionReply> detail::ReadReply<Test::GetVersionReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Test::GetVersionReply>();
+
+ auto& major_version = (*reply).major_version;
+ auto& sequence = (*reply).sequence;
+ auto& minor_version = (*reply).minor_version;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // major_version
+ Read(&major_version, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // minor_version
+ Read(&minor_version, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Test::CompareCursorReply> Test::CompareCursor(
+ const Test::CompareCursorRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& cursor = request.cursor;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // cursor
+ buf.Write(&cursor);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Test::CompareCursorReply>(
+ &buf, "Test::CompareCursor", false);
+}
+
+Future<Test::CompareCursorReply> Test::CompareCursor(
+ const Window& window,
+ const x11::Cursor& cursor) {
+ return Test::CompareCursor(Test::CompareCursorRequest{window, cursor});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Test::CompareCursorReply> detail::ReadReply<
+ Test::CompareCursorReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Test::CompareCursorReply>();
+
+ auto& same = (*reply).same;
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // same
+ Read(&same, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Test::FakeInput(const Test::FakeInputRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& type = request.type;
+ auto& detail = request.detail;
+ auto& time = request.time;
+ auto& root = request.root;
+ auto& rootX = request.rootX;
+ auto& rootY = request.rootY;
+ auto& deviceid = request.deviceid;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // type
+ buf.Write(&type);
+
+ // detail
+ buf.Write(&detail);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // time
+ buf.Write(&time);
+
+ // root
+ buf.Write(&root);
+
+ // pad1
+ Pad(&buf, 8);
+
+ // rootX
+ buf.Write(&rootX);
+
+ // rootY
+ buf.Write(&rootY);
+
+ // pad2
+ Pad(&buf, 7);
+
+ // deviceid
+ buf.Write(&deviceid);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Test::FakeInput", false);
+}
+
+Future<void> Test::FakeInput(const uint8_t& type,
+ const uint8_t& detail,
+ const uint32_t& time,
+ const Window& root,
+ const int16_t& rootX,
+ const int16_t& rootY,
+ const uint8_t& deviceid) {
+ return Test::FakeInput(
+ Test::FakeInputRequest{type, detail, time, root, rootX, rootY, deviceid});
+}
+
+Future<void> Test::GrabControl(const Test::GrabControlRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& impervious = request.impervious;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // impervious
+ buf.Write(&impervious);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Test::GrabControl", false);
+}
+
+Future<void> Test::GrabControl(const uint8_t& impervious) {
+ return Test::GrabControl(Test::GrabControlRequest{impervious});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xtest.h b/chromium/ui/gfx/x/generated_protos/xtest.h
new file mode 100644
index 00000000000..492c9e9ba50
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xtest.h
@@ -0,0 +1,174 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XTEST_H_
+#define UI_GFX_X_GENERATED_PROTOS_XTEST_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Test {
+ public:
+ static constexpr unsigned major_version = 2;
+ static constexpr unsigned minor_version = 2;
+
+ Test(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Cursor : int {
+ None = 0,
+ Current = 1,
+ };
+
+ struct GetVersionRequest {
+ uint8_t major_version{};
+ uint16_t minor_version{};
+ };
+
+ struct GetVersionReply {
+ uint8_t major_version{};
+ uint16_t sequence{};
+ uint16_t minor_version{};
+ };
+
+ using GetVersionResponse = Response<GetVersionReply>;
+
+ Future<GetVersionReply> GetVersion(const GetVersionRequest& request);
+
+ Future<GetVersionReply> GetVersion(const uint8_t& major_version = {},
+ const uint16_t& minor_version = {});
+
+ struct CompareCursorRequest {
+ Window window{};
+ x11::Cursor cursor{};
+ };
+
+ struct CompareCursorReply {
+ uint8_t same{};
+ uint16_t sequence{};
+ };
+
+ using CompareCursorResponse = Response<CompareCursorReply>;
+
+ Future<CompareCursorReply> CompareCursor(const CompareCursorRequest& request);
+
+ Future<CompareCursorReply> CompareCursor(const Window& window = {},
+ const x11::Cursor& cursor = {});
+
+ struct FakeInputRequest {
+ uint8_t type{};
+ uint8_t detail{};
+ uint32_t time{};
+ Window root{};
+ int16_t rootX{};
+ int16_t rootY{};
+ uint8_t deviceid{};
+ };
+
+ using FakeInputResponse = Response<void>;
+
+ Future<void> FakeInput(const FakeInputRequest& request);
+
+ Future<void> FakeInput(const uint8_t& type = {},
+ const uint8_t& detail = {},
+ const uint32_t& time = {},
+ const Window& root = {},
+ const int16_t& rootX = {},
+ const int16_t& rootY = {},
+ const uint8_t& deviceid = {});
+
+ struct GrabControlRequest {
+ uint8_t impervious{};
+ };
+
+ using GrabControlResponse = Response<void>;
+
+ Future<void> GrabControl(const GrabControlRequest& request);
+
+ Future<void> GrabControl(const uint8_t& impervious = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Test::Cursor operator|(x11::Test::Cursor l,
+ x11::Test::Cursor r) {
+ using T = std::underlying_type_t<x11::Test::Cursor>;
+ return static_cast<x11::Test::Cursor>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Test::Cursor operator&(x11::Test::Cursor l,
+ x11::Test::Cursor r) {
+ using T = std::underlying_type_t<x11::Test::Cursor>;
+ return static_cast<x11::Test::Cursor>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XTEST_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xv.cc b/chromium/ui/gfx/x/generated_protos/xv.cc
new file mode 100644
index 00000000000..0171ced3ca1
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xv.cc
@@ -0,0 +1,1967 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xv.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+Xv::Xv(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+std::string Xv::BadPortError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Xv::BadPortError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Xv::BadPortError>(Xv::BadPortError* error_, ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Xv::BadEncodingError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Xv::BadEncodingError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Xv::BadEncodingError>(Xv::BadEncodingError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+std::string Xv::BadControlError::ToString() const {
+ std::stringstream ss_;
+ ss_ << "Xv::BadControlError{";
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << "}";
+ return ss_.str();
+}
+
+template <>
+void ReadError<Xv::BadControlError>(Xv::BadControlError* error_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*error_).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // error_code
+ uint8_t error_code;
+ Read(&error_code, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xv::VideoNotifyEvent>(Xv::VideoNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& reason = (*event_).reason;
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& drawable = (*event_).drawable;
+ auto& port = (*event_).port;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // reason
+ uint8_t tmp0;
+ Read(&tmp0, &buf);
+ reason = static_cast<Xv::VideoNotifyReason>(tmp0);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // drawable
+ Read(&drawable, &buf);
+
+ // port
+ Read(&port, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Xv::PortNotifyEvent>(Xv::PortNotifyEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& time = (*event_).time;
+ auto& port = (*event_).port;
+ auto& attribute = (*event_).attribute;
+ auto& value = (*event_).value;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // port
+ Read(&port, &buf);
+
+ // attribute
+ Read(&attribute, &buf);
+
+ // value
+ Read(&value, &buf);
+
+ DCHECK_LE(buf.offset, 32ul);
+}
+
+Future<Xv::QueryExtensionReply> Xv::QueryExtension(
+ const Xv::QueryExtensionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xv::QueryExtensionReply>(
+ &buf, "Xv::QueryExtension", false);
+}
+
+Future<Xv::QueryExtensionReply> Xv::QueryExtension() {
+ return Xv::QueryExtension(Xv::QueryExtensionRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xv::QueryExtensionReply> detail::ReadReply<
+ Xv::QueryExtensionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xv::QueryExtensionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major = (*reply).major;
+ auto& minor = (*reply).minor;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major
+ Read(&major, &buf);
+
+ // minor
+ Read(&minor, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xv::QueryAdaptorsReply> Xv::QueryAdaptors(
+ const Xv::QueryAdaptorsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xv::QueryAdaptorsReply>(
+ &buf, "Xv::QueryAdaptors", false);
+}
+
+Future<Xv::QueryAdaptorsReply> Xv::QueryAdaptors(const Window& window) {
+ return Xv::QueryAdaptors(Xv::QueryAdaptorsRequest{window});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xv::QueryAdaptorsReply> detail::ReadReply<
+ Xv::QueryAdaptorsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xv::QueryAdaptorsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t num_adaptors{};
+ auto& info = (*reply).info;
+ size_t info_len = info.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_adaptors
+ Read(&num_adaptors, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // info
+ info.resize(num_adaptors);
+ for (auto& info_elem : info) {
+ // info_elem
+ {
+ auto& base_id = info_elem.base_id;
+ uint16_t name_size{};
+ auto& num_ports = info_elem.num_ports;
+ uint16_t num_formats{};
+ auto& type = info_elem.type;
+ auto& name = info_elem.name;
+ size_t name_len = name.size();
+ auto& formats = info_elem.formats;
+ size_t formats_len = formats.size();
+
+ // base_id
+ Read(&base_id, &buf);
+
+ // name_size
+ Read(&name_size, &buf);
+
+ // num_ports
+ Read(&num_ports, &buf);
+
+ // num_formats
+ Read(&num_formats, &buf);
+
+ // type
+ uint8_t tmp1;
+ Read(&tmp1, &buf);
+ type = static_cast<Xv::Type>(tmp1);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // name
+ name.resize(name_size);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ // pad1
+ Align(&buf, 4);
+
+ // formats
+ formats.resize(num_formats);
+ for (auto& formats_elem : formats) {
+ // formats_elem
+ {
+ auto& visual = formats_elem.visual;
+ auto& depth = formats_elem.depth;
+
+ // visual
+ Read(&visual, &buf);
+
+ // depth
+ Read(&depth, &buf);
+
+ // pad0
+ Pad(&buf, 3);
+ }
+ }
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xv::QueryEncodingsReply> Xv::QueryEncodings(
+ const Xv::QueryEncodingsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xv::QueryEncodingsReply>(
+ &buf, "Xv::QueryEncodings", false);
+}
+
+Future<Xv::QueryEncodingsReply> Xv::QueryEncodings(const Port& port) {
+ return Xv::QueryEncodings(Xv::QueryEncodingsRequest{port});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xv::QueryEncodingsReply> detail::ReadReply<
+ Xv::QueryEncodingsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xv::QueryEncodingsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint16_t num_encodings{};
+ auto& info = (*reply).info;
+ size_t info_len = info.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_encodings
+ Read(&num_encodings, &buf);
+
+ // pad1
+ Pad(&buf, 22);
+
+ // info
+ info.resize(num_encodings);
+ for (auto& info_elem : info) {
+ // info_elem
+ {
+ auto& encoding = info_elem.encoding;
+ uint16_t name_size{};
+ auto& width = info_elem.width;
+ auto& height = info_elem.height;
+ auto& rate = info_elem.rate;
+ auto& name = info_elem.name;
+ size_t name_len = name.size();
+
+ // encoding
+ Read(&encoding, &buf);
+
+ // name_size
+ Read(&name_size, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // rate
+ {
+ auto& numerator = rate.numerator;
+ auto& denominator = rate.denominator;
+
+ // numerator
+ Read(&numerator, &buf);
+
+ // denominator
+ Read(&denominator, &buf);
+ }
+
+ // name
+ name.resize(name_size);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ // pad1
+ Align(&buf, 4);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xv::GrabPortReply> Xv::GrabPort(const Xv::GrabPortRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& time = request.time;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // time
+ buf.Write(&time);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xv::GrabPortReply>(&buf, "Xv::GrabPort",
+ false);
+}
+
+Future<Xv::GrabPortReply> Xv::GrabPort(const Port& port, const Time& time) {
+ return Xv::GrabPort(Xv::GrabPortRequest{port, time});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xv::GrabPortReply> detail::ReadReply<Xv::GrabPortReply>(
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xv::GrabPortReply>();
+
+ auto& result = (*reply).result;
+ auto& sequence = (*reply).sequence;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // result
+ uint8_t tmp2;
+ Read(&tmp2, &buf);
+ result = static_cast<Xv::GrabPortStatus>(tmp2);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xv::UngrabPort(const Xv::UngrabPortRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& time = request.time;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // time
+ buf.Write(&time);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xv::UngrabPort", false);
+}
+
+Future<void> Xv::UngrabPort(const Port& port, const Time& time) {
+ return Xv::UngrabPort(Xv::UngrabPortRequest{port, time});
+}
+
+Future<void> Xv::PutVideo(const Xv::PutVideoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& vid_x = request.vid_x;
+ auto& vid_y = request.vid_y;
+ auto& vid_w = request.vid_w;
+ auto& vid_h = request.vid_h;
+ auto& drw_x = request.drw_x;
+ auto& drw_y = request.drw_y;
+ auto& drw_w = request.drw_w;
+ auto& drw_h = request.drw_h;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // vid_x
+ buf.Write(&vid_x);
+
+ // vid_y
+ buf.Write(&vid_y);
+
+ // vid_w
+ buf.Write(&vid_w);
+
+ // vid_h
+ buf.Write(&vid_h);
+
+ // drw_x
+ buf.Write(&drw_x);
+
+ // drw_y
+ buf.Write(&drw_y);
+
+ // drw_w
+ buf.Write(&drw_w);
+
+ // drw_h
+ buf.Write(&drw_h);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xv::PutVideo", false);
+}
+
+Future<void> Xv::PutVideo(const Port& port,
+ const Drawable& drawable,
+ const GraphicsContext& gc,
+ const int16_t& vid_x,
+ const int16_t& vid_y,
+ const uint16_t& vid_w,
+ const uint16_t& vid_h,
+ const int16_t& drw_x,
+ const int16_t& drw_y,
+ const uint16_t& drw_w,
+ const uint16_t& drw_h) {
+ return Xv::PutVideo(Xv::PutVideoRequest{port, drawable, gc, vid_x, vid_y,
+ vid_w, vid_h, drw_x, drw_y, drw_w,
+ drw_h});
+}
+
+Future<void> Xv::PutStill(const Xv::PutStillRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& vid_x = request.vid_x;
+ auto& vid_y = request.vid_y;
+ auto& vid_w = request.vid_w;
+ auto& vid_h = request.vid_h;
+ auto& drw_x = request.drw_x;
+ auto& drw_y = request.drw_y;
+ auto& drw_w = request.drw_w;
+ auto& drw_h = request.drw_h;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // vid_x
+ buf.Write(&vid_x);
+
+ // vid_y
+ buf.Write(&vid_y);
+
+ // vid_w
+ buf.Write(&vid_w);
+
+ // vid_h
+ buf.Write(&vid_h);
+
+ // drw_x
+ buf.Write(&drw_x);
+
+ // drw_y
+ buf.Write(&drw_y);
+
+ // drw_w
+ buf.Write(&drw_w);
+
+ // drw_h
+ buf.Write(&drw_h);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xv::PutStill", false);
+}
+
+Future<void> Xv::PutStill(const Port& port,
+ const Drawable& drawable,
+ const GraphicsContext& gc,
+ const int16_t& vid_x,
+ const int16_t& vid_y,
+ const uint16_t& vid_w,
+ const uint16_t& vid_h,
+ const int16_t& drw_x,
+ const int16_t& drw_y,
+ const uint16_t& drw_w,
+ const uint16_t& drw_h) {
+ return Xv::PutStill(Xv::PutStillRequest{port, drawable, gc, vid_x, vid_y,
+ vid_w, vid_h, drw_x, drw_y, drw_w,
+ drw_h});
+}
+
+Future<void> Xv::GetVideo(const Xv::GetVideoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& vid_x = request.vid_x;
+ auto& vid_y = request.vid_y;
+ auto& vid_w = request.vid_w;
+ auto& vid_h = request.vid_h;
+ auto& drw_x = request.drw_x;
+ auto& drw_y = request.drw_y;
+ auto& drw_w = request.drw_w;
+ auto& drw_h = request.drw_h;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // vid_x
+ buf.Write(&vid_x);
+
+ // vid_y
+ buf.Write(&vid_y);
+
+ // vid_w
+ buf.Write(&vid_w);
+
+ // vid_h
+ buf.Write(&vid_h);
+
+ // drw_x
+ buf.Write(&drw_x);
+
+ // drw_y
+ buf.Write(&drw_y);
+
+ // drw_w
+ buf.Write(&drw_w);
+
+ // drw_h
+ buf.Write(&drw_h);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xv::GetVideo", false);
+}
+
+Future<void> Xv::GetVideo(const Port& port,
+ const Drawable& drawable,
+ const GraphicsContext& gc,
+ const int16_t& vid_x,
+ const int16_t& vid_y,
+ const uint16_t& vid_w,
+ const uint16_t& vid_h,
+ const int16_t& drw_x,
+ const int16_t& drw_y,
+ const uint16_t& drw_w,
+ const uint16_t& drw_h) {
+ return Xv::GetVideo(Xv::GetVideoRequest{port, drawable, gc, vid_x, vid_y,
+ vid_w, vid_h, drw_x, drw_y, drw_w,
+ drw_h});
+}
+
+Future<void> Xv::GetStill(const Xv::GetStillRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& vid_x = request.vid_x;
+ auto& vid_y = request.vid_y;
+ auto& vid_w = request.vid_w;
+ auto& vid_h = request.vid_h;
+ auto& drw_x = request.drw_x;
+ auto& drw_y = request.drw_y;
+ auto& drw_w = request.drw_w;
+ auto& drw_h = request.drw_h;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // vid_x
+ buf.Write(&vid_x);
+
+ // vid_y
+ buf.Write(&vid_y);
+
+ // vid_w
+ buf.Write(&vid_w);
+
+ // vid_h
+ buf.Write(&vid_h);
+
+ // drw_x
+ buf.Write(&drw_x);
+
+ // drw_y
+ buf.Write(&drw_y);
+
+ // drw_w
+ buf.Write(&drw_w);
+
+ // drw_h
+ buf.Write(&drw_h);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xv::GetStill", false);
+}
+
+Future<void> Xv::GetStill(const Port& port,
+ const Drawable& drawable,
+ const GraphicsContext& gc,
+ const int16_t& vid_x,
+ const int16_t& vid_y,
+ const uint16_t& vid_w,
+ const uint16_t& vid_h,
+ const int16_t& drw_x,
+ const int16_t& drw_y,
+ const uint16_t& drw_w,
+ const uint16_t& drw_h) {
+ return Xv::GetStill(Xv::GetStillRequest{port, drawable, gc, vid_x, vid_y,
+ vid_w, vid_h, drw_x, drw_y, drw_w,
+ drw_h});
+}
+
+Future<void> Xv::StopVideo(const Xv::StopVideoRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& drawable = request.drawable;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // drawable
+ buf.Write(&drawable);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xv::StopVideo", false);
+}
+
+Future<void> Xv::StopVideo(const Port& port, const Drawable& drawable) {
+ return Xv::StopVideo(Xv::StopVideoRequest{port, drawable});
+}
+
+Future<void> Xv::SelectVideoNotify(
+ const Xv::SelectVideoNotifyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& drawable = request.drawable;
+ auto& onoff = request.onoff;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 10;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // drawable
+ buf.Write(&drawable);
+
+ // onoff
+ buf.Write(&onoff);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xv::SelectVideoNotify", false);
+}
+
+Future<void> Xv::SelectVideoNotify(const Drawable& drawable,
+ const uint8_t& onoff) {
+ return Xv::SelectVideoNotify(Xv::SelectVideoNotifyRequest{drawable, onoff});
+}
+
+Future<void> Xv::SelectPortNotify(const Xv::SelectPortNotifyRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& onoff = request.onoff;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 11;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // onoff
+ buf.Write(&onoff);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xv::SelectPortNotify", false);
+}
+
+Future<void> Xv::SelectPortNotify(const Port& port, const uint8_t& onoff) {
+ return Xv::SelectPortNotify(Xv::SelectPortNotifyRequest{port, onoff});
+}
+
+Future<Xv::QueryBestSizeReply> Xv::QueryBestSize(
+ const Xv::QueryBestSizeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& vid_w = request.vid_w;
+ auto& vid_h = request.vid_h;
+ auto& drw_w = request.drw_w;
+ auto& drw_h = request.drw_h;
+ auto& motion = request.motion;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 12;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // vid_w
+ buf.Write(&vid_w);
+
+ // vid_h
+ buf.Write(&vid_h);
+
+ // drw_w
+ buf.Write(&drw_w);
+
+ // drw_h
+ buf.Write(&drw_h);
+
+ // motion
+ buf.Write(&motion);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xv::QueryBestSizeReply>(
+ &buf, "Xv::QueryBestSize", false);
+}
+
+Future<Xv::QueryBestSizeReply> Xv::QueryBestSize(const Port& port,
+ const uint16_t& vid_w,
+ const uint16_t& vid_h,
+ const uint16_t& drw_w,
+ const uint16_t& drw_h,
+ const uint8_t& motion) {
+ return Xv::QueryBestSize(
+ Xv::QueryBestSizeRequest{port, vid_w, vid_h, drw_w, drw_h, motion});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xv::QueryBestSizeReply> detail::ReadReply<
+ Xv::QueryBestSizeReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xv::QueryBestSizeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& actual_width = (*reply).actual_width;
+ auto& actual_height = (*reply).actual_height;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // actual_width
+ Read(&actual_width, &buf);
+
+ // actual_height
+ Read(&actual_height, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xv::SetPortAttribute(const Xv::SetPortAttributeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& attribute = request.attribute;
+ auto& value = request.value;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 13;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // attribute
+ buf.Write(&attribute);
+
+ // value
+ buf.Write(&value);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xv::SetPortAttribute", false);
+}
+
+Future<void> Xv::SetPortAttribute(const Port& port,
+ const Atom& attribute,
+ const int32_t& value) {
+ return Xv::SetPortAttribute(
+ Xv::SetPortAttributeRequest{port, attribute, value});
+}
+
+Future<Xv::GetPortAttributeReply> Xv::GetPortAttribute(
+ const Xv::GetPortAttributeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& attribute = request.attribute;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 14;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // attribute
+ buf.Write(&attribute);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xv::GetPortAttributeReply>(
+ &buf, "Xv::GetPortAttribute", false);
+}
+
+Future<Xv::GetPortAttributeReply> Xv::GetPortAttribute(const Port& port,
+ const Atom& attribute) {
+ return Xv::GetPortAttribute(Xv::GetPortAttributeRequest{port, attribute});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xv::GetPortAttributeReply> detail::ReadReply<
+ Xv::GetPortAttributeReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xv::GetPortAttributeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& value = (*reply).value;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // value
+ Read(&value, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xv::QueryPortAttributesReply> Xv::QueryPortAttributes(
+ const Xv::QueryPortAttributesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 15;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xv::QueryPortAttributesReply>(
+ &buf, "Xv::QueryPortAttributes", false);
+}
+
+Future<Xv::QueryPortAttributesReply> Xv::QueryPortAttributes(const Port& port) {
+ return Xv::QueryPortAttributes(Xv::QueryPortAttributesRequest{port});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xv::QueryPortAttributesReply> detail::ReadReply<
+ Xv::QueryPortAttributesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xv::QueryPortAttributesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num_attributes{};
+ auto& text_size = (*reply).text_size;
+ auto& attributes = (*reply).attributes;
+ size_t attributes_len = attributes.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_attributes
+ Read(&num_attributes, &buf);
+
+ // text_size
+ Read(&text_size, &buf);
+
+ // pad1
+ Pad(&buf, 16);
+
+ // attributes
+ attributes.resize(num_attributes);
+ for (auto& attributes_elem : attributes) {
+ // attributes_elem
+ {
+ auto& flags = attributes_elem.flags;
+ auto& min = attributes_elem.min;
+ auto& max = attributes_elem.max;
+ uint32_t size{};
+ auto& name = attributes_elem.name;
+ size_t name_len = name.size();
+
+ // flags
+ uint32_t tmp3;
+ Read(&tmp3, &buf);
+ flags = static_cast<Xv::AttributeFlag>(tmp3);
+
+ // min
+ Read(&min, &buf);
+
+ // max
+ Read(&max, &buf);
+
+ // size
+ Read(&size, &buf);
+
+ // name
+ name.resize(size);
+ for (auto& name_elem : name) {
+ // name_elem
+ Read(&name_elem, &buf);
+ }
+
+ // pad0
+ Align(&buf, 4);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xv::ListImageFormatsReply> Xv::ListImageFormats(
+ const Xv::ListImageFormatsRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 16;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xv::ListImageFormatsReply>(
+ &buf, "Xv::ListImageFormats", false);
+}
+
+Future<Xv::ListImageFormatsReply> Xv::ListImageFormats(const Port& port) {
+ return Xv::ListImageFormats(Xv::ListImageFormatsRequest{port});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xv::ListImageFormatsReply> detail::ReadReply<
+ Xv::ListImageFormatsReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xv::ListImageFormatsReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num_formats{};
+ auto& format = (*reply).format;
+ size_t format_len = format.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_formats
+ Read(&num_formats, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // format
+ format.resize(num_formats);
+ for (auto& format_elem : format) {
+ // format_elem
+ {
+ auto& id = format_elem.id;
+ auto& type = format_elem.type;
+ auto& byte_order = format_elem.byte_order;
+ auto& guid = format_elem.guid;
+ size_t guid_len = guid.size();
+ auto& bpp = format_elem.bpp;
+ auto& num_planes = format_elem.num_planes;
+ auto& depth = format_elem.depth;
+ auto& red_mask = format_elem.red_mask;
+ auto& green_mask = format_elem.green_mask;
+ auto& blue_mask = format_elem.blue_mask;
+ auto& format = format_elem.format;
+ auto& y_sample_bits = format_elem.y_sample_bits;
+ auto& u_sample_bits = format_elem.u_sample_bits;
+ auto& v_sample_bits = format_elem.v_sample_bits;
+ auto& vhorz_y_period = format_elem.vhorz_y_period;
+ auto& vhorz_u_period = format_elem.vhorz_u_period;
+ auto& vhorz_v_period = format_elem.vhorz_v_period;
+ auto& vvert_y_period = format_elem.vvert_y_period;
+ auto& vvert_u_period = format_elem.vvert_u_period;
+ auto& vvert_v_period = format_elem.vvert_v_period;
+ auto& vcomp_order = format_elem.vcomp_order;
+ size_t vcomp_order_len = vcomp_order.size();
+ auto& vscanline_order = format_elem.vscanline_order;
+
+ // id
+ Read(&id, &buf);
+
+ // type
+ uint8_t tmp4;
+ Read(&tmp4, &buf);
+ type = static_cast<Xv::ImageFormatInfoType>(tmp4);
+
+ // byte_order
+ uint8_t tmp5;
+ Read(&tmp5, &buf);
+ byte_order = static_cast<ImageOrder>(tmp5);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // guid
+ for (auto& guid_elem : guid) {
+ // guid_elem
+ Read(&guid_elem, &buf);
+ }
+
+ // bpp
+ Read(&bpp, &buf);
+
+ // num_planes
+ Read(&num_planes, &buf);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // depth
+ Read(&depth, &buf);
+
+ // pad2
+ Pad(&buf, 3);
+
+ // red_mask
+ Read(&red_mask, &buf);
+
+ // green_mask
+ Read(&green_mask, &buf);
+
+ // blue_mask
+ Read(&blue_mask, &buf);
+
+ // format
+ uint8_t tmp6;
+ Read(&tmp6, &buf);
+ format = static_cast<Xv::ImageFormatInfoFormat>(tmp6);
+
+ // pad3
+ Pad(&buf, 3);
+
+ // y_sample_bits
+ Read(&y_sample_bits, &buf);
+
+ // u_sample_bits
+ Read(&u_sample_bits, &buf);
+
+ // v_sample_bits
+ Read(&v_sample_bits, &buf);
+
+ // vhorz_y_period
+ Read(&vhorz_y_period, &buf);
+
+ // vhorz_u_period
+ Read(&vhorz_u_period, &buf);
+
+ // vhorz_v_period
+ Read(&vhorz_v_period, &buf);
+
+ // vvert_y_period
+ Read(&vvert_y_period, &buf);
+
+ // vvert_u_period
+ Read(&vvert_u_period, &buf);
+
+ // vvert_v_period
+ Read(&vvert_v_period, &buf);
+
+ // vcomp_order
+ for (auto& vcomp_order_elem : vcomp_order) {
+ // vcomp_order_elem
+ Read(&vcomp_order_elem, &buf);
+ }
+
+ // vscanline_order
+ uint8_t tmp7;
+ Read(&tmp7, &buf);
+ vscanline_order = static_cast<Xv::ScanlineOrder>(tmp7);
+
+ // pad4
+ Pad(&buf, 11);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<Xv::QueryImageAttributesReply> Xv::QueryImageAttributes(
+ const Xv::QueryImageAttributesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& id = request.id;
+ auto& width = request.width;
+ auto& height = request.height;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 17;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // id
+ buf.Write(&id);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<Xv::QueryImageAttributesReply>(
+ &buf, "Xv::QueryImageAttributes", false);
+}
+
+Future<Xv::QueryImageAttributesReply> Xv::QueryImageAttributes(
+ const Port& port,
+ const uint32_t& id,
+ const uint16_t& width,
+ const uint16_t& height) {
+ return Xv::QueryImageAttributes(
+ Xv::QueryImageAttributesRequest{port, id, width, height});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<Xv::QueryImageAttributesReply> detail::ReadReply<
+ Xv::QueryImageAttributesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<Xv::QueryImageAttributesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num_planes{};
+ auto& data_size = (*reply).data_size;
+ auto& width = (*reply).width;
+ auto& height = (*reply).height;
+ auto& pitches = (*reply).pitches;
+ size_t pitches_len = pitches.size();
+ auto& offsets = (*reply).offsets;
+ size_t offsets_len = offsets.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num_planes
+ Read(&num_planes, &buf);
+
+ // data_size
+ Read(&data_size, &buf);
+
+ // width
+ Read(&width, &buf);
+
+ // height
+ Read(&height, &buf);
+
+ // pad1
+ Pad(&buf, 12);
+
+ // pitches
+ pitches.resize(num_planes);
+ for (auto& pitches_elem : pitches) {
+ // pitches_elem
+ Read(&pitches_elem, &buf);
+ }
+
+ // offsets
+ offsets.resize(num_planes);
+ for (auto& offsets_elem : offsets) {
+ // offsets_elem
+ Read(&offsets_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> Xv::PutImage(const Xv::PutImageRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& id = request.id;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& src_w = request.src_w;
+ auto& src_h = request.src_h;
+ auto& drw_x = request.drw_x;
+ auto& drw_y = request.drw_y;
+ auto& drw_w = request.drw_w;
+ auto& drw_h = request.drw_h;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& data = request.data;
+ size_t data_len = data.size();
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 18;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // id
+ buf.Write(&id);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // src_w
+ buf.Write(&src_w);
+
+ // src_h
+ buf.Write(&src_h);
+
+ // drw_x
+ buf.Write(&drw_x);
+
+ // drw_y
+ buf.Write(&drw_y);
+
+ // drw_w
+ buf.Write(&drw_w);
+
+ // drw_h
+ buf.Write(&drw_h);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // data
+ DCHECK_EQ(static_cast<size_t>(data_len), data.size());
+ for (auto& data_elem : data) {
+ // data_elem
+ buf.Write(&data_elem);
+ }
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xv::PutImage", false);
+}
+
+Future<void> Xv::PutImage(const Port& port,
+ const Drawable& drawable,
+ const GraphicsContext& gc,
+ const uint32_t& id,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const uint16_t& src_w,
+ const uint16_t& src_h,
+ const int16_t& drw_x,
+ const int16_t& drw_y,
+ const uint16_t& drw_w,
+ const uint16_t& drw_h,
+ const uint16_t& width,
+ const uint16_t& height,
+ const std::vector<uint8_t>& data) {
+ return Xv::PutImage(Xv::PutImageRequest{port, drawable, gc, id, src_x, src_y,
+ src_w, src_h, drw_x, drw_y, drw_w,
+ drw_h, width, height, data});
+}
+
+Future<void> Xv::ShmPutImage(const Xv::ShmPutImageRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port = request.port;
+ auto& drawable = request.drawable;
+ auto& gc = request.gc;
+ auto& shmseg = request.shmseg;
+ auto& id = request.id;
+ auto& offset = request.offset;
+ auto& src_x = request.src_x;
+ auto& src_y = request.src_y;
+ auto& src_w = request.src_w;
+ auto& src_h = request.src_h;
+ auto& drw_x = request.drw_x;
+ auto& drw_y = request.drw_y;
+ auto& drw_w = request.drw_w;
+ auto& drw_h = request.drw_h;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& send_event = request.send_event;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 19;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port
+ buf.Write(&port);
+
+ // drawable
+ buf.Write(&drawable);
+
+ // gc
+ buf.Write(&gc);
+
+ // shmseg
+ buf.Write(&shmseg);
+
+ // id
+ buf.Write(&id);
+
+ // offset
+ buf.Write(&offset);
+
+ // src_x
+ buf.Write(&src_x);
+
+ // src_y
+ buf.Write(&src_y);
+
+ // src_w
+ buf.Write(&src_w);
+
+ // src_h
+ buf.Write(&src_h);
+
+ // drw_x
+ buf.Write(&drw_x);
+
+ // drw_y
+ buf.Write(&drw_y);
+
+ // drw_w
+ buf.Write(&drw_w);
+
+ // drw_h
+ buf.Write(&drw_h);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // send_event
+ buf.Write(&send_event);
+
+ // pad0
+ Pad(&buf, 3);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Xv::ShmPutImage", false);
+}
+
+Future<void> Xv::ShmPutImage(const Port& port,
+ const Drawable& drawable,
+ const GraphicsContext& gc,
+ const Shm::Seg& shmseg,
+ const uint32_t& id,
+ const uint32_t& offset,
+ const int16_t& src_x,
+ const int16_t& src_y,
+ const uint16_t& src_w,
+ const uint16_t& src_h,
+ const int16_t& drw_x,
+ const int16_t& drw_y,
+ const uint16_t& drw_w,
+ const uint16_t& drw_h,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint8_t& send_event) {
+ return Xv::ShmPutImage(Xv::ShmPutImageRequest{
+ port, drawable, gc, shmseg, id, offset, src_x, src_y, src_w, src_h, drw_x,
+ drw_y, drw_w, drw_h, width, height, send_event});
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xv.h b/chromium/ui/gfx/x/generated_protos/xv.h
new file mode 100644
index 00000000000..268d3779caf
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xv.h
@@ -0,0 +1,779 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XV_H_
+#define UI_GFX_X_GENERATED_PROTOS_XV_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "shm.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) Xv {
+ public:
+ static constexpr unsigned major_version = 2;
+ static constexpr unsigned minor_version = 2;
+
+ Xv(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Port : uint32_t {};
+
+ enum class Encoding : uint32_t {};
+
+ enum class Type : int {
+ InputMask = 1 << 0,
+ OutputMask = 1 << 1,
+ VideoMask = 1 << 2,
+ StillMask = 1 << 3,
+ ImageMask = 1 << 4,
+ };
+
+ enum class ImageFormatInfoType : int {
+ RGB = 0,
+ YUV = 1,
+ };
+
+ enum class ImageFormatInfoFormat : int {
+ Packed = 0,
+ Planar = 1,
+ };
+
+ enum class AttributeFlag : int {
+ Gettable = 1 << 0,
+ Settable = 1 << 1,
+ };
+
+ enum class VideoNotifyReason : int {
+ Started = 0,
+ Stopped = 1,
+ Busy = 2,
+ Preempted = 3,
+ HardError = 4,
+ };
+
+ enum class ScanlineOrder : int {
+ TopToBottom = 0,
+ BottomToTop = 1,
+ };
+
+ enum class GrabPortStatus : int {
+ Success = 0,
+ BadExtension = 1,
+ AlreadyGrabbed = 2,
+ InvalidTime = 3,
+ BadReply = 4,
+ BadAlloc = 5,
+ };
+
+ struct Rational {
+ int32_t numerator{};
+ int32_t denominator{};
+ };
+
+ struct Format {
+ VisualId visual{};
+ uint8_t depth{};
+ };
+
+ struct AdaptorInfo {
+ Port base_id{};
+ uint16_t num_ports{};
+ Type type{};
+ std::string name{};
+ std::vector<Format> formats{};
+ };
+
+ struct EncodingInfo {
+ Encoding encoding{};
+ uint16_t width{};
+ uint16_t height{};
+ Rational rate{};
+ std::string name{};
+ };
+
+ struct Image {
+ uint32_t id{};
+ uint16_t width{};
+ uint16_t height{};
+ std::vector<uint32_t> pitches{};
+ std::vector<uint32_t> offsets{};
+ std::vector<uint8_t> data{};
+ };
+
+ struct AttributeInfo {
+ AttributeFlag flags{};
+ int32_t min{};
+ int32_t max{};
+ std::string name{};
+ };
+
+ struct ImageFormatInfo {
+ uint32_t id{};
+ ImageFormatInfoType type{};
+ ImageOrder byte_order{};
+ std::array<uint8_t, 16> guid{};
+ uint8_t bpp{};
+ uint8_t num_planes{};
+ uint8_t depth{};
+ uint32_t red_mask{};
+ uint32_t green_mask{};
+ uint32_t blue_mask{};
+ ImageFormatInfoFormat format{};
+ uint32_t y_sample_bits{};
+ uint32_t u_sample_bits{};
+ uint32_t v_sample_bits{};
+ uint32_t vhorz_y_period{};
+ uint32_t vhorz_u_period{};
+ uint32_t vhorz_v_period{};
+ uint32_t vvert_y_period{};
+ uint32_t vvert_u_period{};
+ uint32_t vvert_v_period{};
+ std::array<uint8_t, 32> vcomp_order{};
+ ScanlineOrder vscanline_order{};
+ };
+
+ struct BadPortError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadEncodingError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct BadControlError : public x11::Error {
+ uint16_t sequence{};
+
+ std::string ToString() const override;
+ };
+
+ struct VideoNotifyEvent {
+ static constexpr int type_id = 81;
+ static constexpr uint8_t opcode = 0;
+ bool send_event{};
+ VideoNotifyReason reason{};
+ uint16_t sequence{};
+ Time time{};
+ Drawable drawable{};
+ Port port{};
+
+ x11::Window* GetWindow() {
+ return reinterpret_cast<x11::Window*>(&drawable);
+ }
+ };
+
+ struct PortNotifyEvent {
+ static constexpr int type_id = 82;
+ static constexpr uint8_t opcode = 1;
+ bool send_event{};
+ uint16_t sequence{};
+ Time time{};
+ Port port{};
+ Atom attribute{};
+ int32_t value{};
+
+ x11::Window* GetWindow() { return nullptr; }
+ };
+
+ struct QueryExtensionRequest {};
+
+ struct QueryExtensionReply {
+ uint16_t sequence{};
+ uint16_t major{};
+ uint16_t minor{};
+ };
+
+ using QueryExtensionResponse = Response<QueryExtensionReply>;
+
+ Future<QueryExtensionReply> QueryExtension(
+ const QueryExtensionRequest& request);
+
+ Future<QueryExtensionReply> QueryExtension();
+
+ struct QueryAdaptorsRequest {
+ Window window{};
+ };
+
+ struct QueryAdaptorsReply {
+ uint16_t sequence{};
+ std::vector<AdaptorInfo> info{};
+ };
+
+ using QueryAdaptorsResponse = Response<QueryAdaptorsReply>;
+
+ Future<QueryAdaptorsReply> QueryAdaptors(const QueryAdaptorsRequest& request);
+
+ Future<QueryAdaptorsReply> QueryAdaptors(const Window& window = {});
+
+ struct QueryEncodingsRequest {
+ Port port{};
+ };
+
+ struct QueryEncodingsReply {
+ uint16_t sequence{};
+ std::vector<EncodingInfo> info{};
+ };
+
+ using QueryEncodingsResponse = Response<QueryEncodingsReply>;
+
+ Future<QueryEncodingsReply> QueryEncodings(
+ const QueryEncodingsRequest& request);
+
+ Future<QueryEncodingsReply> QueryEncodings(const Port& port = {});
+
+ struct GrabPortRequest {
+ Port port{};
+ Time time{};
+ };
+
+ struct GrabPortReply {
+ GrabPortStatus result{};
+ uint16_t sequence{};
+ };
+
+ using GrabPortResponse = Response<GrabPortReply>;
+
+ Future<GrabPortReply> GrabPort(const GrabPortRequest& request);
+
+ Future<GrabPortReply> GrabPort(const Port& port = {}, const Time& time = {});
+
+ struct UngrabPortRequest {
+ Port port{};
+ Time time{};
+ };
+
+ using UngrabPortResponse = Response<void>;
+
+ Future<void> UngrabPort(const UngrabPortRequest& request);
+
+ Future<void> UngrabPort(const Port& port = {}, const Time& time = {});
+
+ struct PutVideoRequest {
+ Port port{};
+ Drawable drawable{};
+ GraphicsContext gc{};
+ int16_t vid_x{};
+ int16_t vid_y{};
+ uint16_t vid_w{};
+ uint16_t vid_h{};
+ int16_t drw_x{};
+ int16_t drw_y{};
+ uint16_t drw_w{};
+ uint16_t drw_h{};
+ };
+
+ using PutVideoResponse = Response<void>;
+
+ Future<void> PutVideo(const PutVideoRequest& request);
+
+ Future<void> PutVideo(const Port& port = {},
+ const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const int16_t& vid_x = {},
+ const int16_t& vid_y = {},
+ const uint16_t& vid_w = {},
+ const uint16_t& vid_h = {},
+ const int16_t& drw_x = {},
+ const int16_t& drw_y = {},
+ const uint16_t& drw_w = {},
+ const uint16_t& drw_h = {});
+
+ struct PutStillRequest {
+ Port port{};
+ Drawable drawable{};
+ GraphicsContext gc{};
+ int16_t vid_x{};
+ int16_t vid_y{};
+ uint16_t vid_w{};
+ uint16_t vid_h{};
+ int16_t drw_x{};
+ int16_t drw_y{};
+ uint16_t drw_w{};
+ uint16_t drw_h{};
+ };
+
+ using PutStillResponse = Response<void>;
+
+ Future<void> PutStill(const PutStillRequest& request);
+
+ Future<void> PutStill(const Port& port = {},
+ const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const int16_t& vid_x = {},
+ const int16_t& vid_y = {},
+ const uint16_t& vid_w = {},
+ const uint16_t& vid_h = {},
+ const int16_t& drw_x = {},
+ const int16_t& drw_y = {},
+ const uint16_t& drw_w = {},
+ const uint16_t& drw_h = {});
+
+ struct GetVideoRequest {
+ Port port{};
+ Drawable drawable{};
+ GraphicsContext gc{};
+ int16_t vid_x{};
+ int16_t vid_y{};
+ uint16_t vid_w{};
+ uint16_t vid_h{};
+ int16_t drw_x{};
+ int16_t drw_y{};
+ uint16_t drw_w{};
+ uint16_t drw_h{};
+ };
+
+ using GetVideoResponse = Response<void>;
+
+ Future<void> GetVideo(const GetVideoRequest& request);
+
+ Future<void> GetVideo(const Port& port = {},
+ const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const int16_t& vid_x = {},
+ const int16_t& vid_y = {},
+ const uint16_t& vid_w = {},
+ const uint16_t& vid_h = {},
+ const int16_t& drw_x = {},
+ const int16_t& drw_y = {},
+ const uint16_t& drw_w = {},
+ const uint16_t& drw_h = {});
+
+ struct GetStillRequest {
+ Port port{};
+ Drawable drawable{};
+ GraphicsContext gc{};
+ int16_t vid_x{};
+ int16_t vid_y{};
+ uint16_t vid_w{};
+ uint16_t vid_h{};
+ int16_t drw_x{};
+ int16_t drw_y{};
+ uint16_t drw_w{};
+ uint16_t drw_h{};
+ };
+
+ using GetStillResponse = Response<void>;
+
+ Future<void> GetStill(const GetStillRequest& request);
+
+ Future<void> GetStill(const Port& port = {},
+ const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const int16_t& vid_x = {},
+ const int16_t& vid_y = {},
+ const uint16_t& vid_w = {},
+ const uint16_t& vid_h = {},
+ const int16_t& drw_x = {},
+ const int16_t& drw_y = {},
+ const uint16_t& drw_w = {},
+ const uint16_t& drw_h = {});
+
+ struct StopVideoRequest {
+ Port port{};
+ Drawable drawable{};
+ };
+
+ using StopVideoResponse = Response<void>;
+
+ Future<void> StopVideo(const StopVideoRequest& request);
+
+ Future<void> StopVideo(const Port& port = {}, const Drawable& drawable = {});
+
+ struct SelectVideoNotifyRequest {
+ Drawable drawable{};
+ uint8_t onoff{};
+ };
+
+ using SelectVideoNotifyResponse = Response<void>;
+
+ Future<void> SelectVideoNotify(const SelectVideoNotifyRequest& request);
+
+ Future<void> SelectVideoNotify(const Drawable& drawable = {},
+ const uint8_t& onoff = {});
+
+ struct SelectPortNotifyRequest {
+ Port port{};
+ uint8_t onoff{};
+ };
+
+ using SelectPortNotifyResponse = Response<void>;
+
+ Future<void> SelectPortNotify(const SelectPortNotifyRequest& request);
+
+ Future<void> SelectPortNotify(const Port& port = {},
+ const uint8_t& onoff = {});
+
+ struct QueryBestSizeRequest {
+ Port port{};
+ uint16_t vid_w{};
+ uint16_t vid_h{};
+ uint16_t drw_w{};
+ uint16_t drw_h{};
+ uint8_t motion{};
+ };
+
+ struct QueryBestSizeReply {
+ uint16_t sequence{};
+ uint16_t actual_width{};
+ uint16_t actual_height{};
+ };
+
+ using QueryBestSizeResponse = Response<QueryBestSizeReply>;
+
+ Future<QueryBestSizeReply> QueryBestSize(const QueryBestSizeRequest& request);
+
+ Future<QueryBestSizeReply> QueryBestSize(const Port& port = {},
+ const uint16_t& vid_w = {},
+ const uint16_t& vid_h = {},
+ const uint16_t& drw_w = {},
+ const uint16_t& drw_h = {},
+ const uint8_t& motion = {});
+
+ struct SetPortAttributeRequest {
+ Port port{};
+ Atom attribute{};
+ int32_t value{};
+ };
+
+ using SetPortAttributeResponse = Response<void>;
+
+ Future<void> SetPortAttribute(const SetPortAttributeRequest& request);
+
+ Future<void> SetPortAttribute(const Port& port = {},
+ const Atom& attribute = {},
+ const int32_t& value = {});
+
+ struct GetPortAttributeRequest {
+ Port port{};
+ Atom attribute{};
+ };
+
+ struct GetPortAttributeReply {
+ uint16_t sequence{};
+ int32_t value{};
+ };
+
+ using GetPortAttributeResponse = Response<GetPortAttributeReply>;
+
+ Future<GetPortAttributeReply> GetPortAttribute(
+ const GetPortAttributeRequest& request);
+
+ Future<GetPortAttributeReply> GetPortAttribute(const Port& port = {},
+ const Atom& attribute = {});
+
+ struct QueryPortAttributesRequest {
+ Port port{};
+ };
+
+ struct QueryPortAttributesReply {
+ uint16_t sequence{};
+ uint32_t text_size{};
+ std::vector<AttributeInfo> attributes{};
+ };
+
+ using QueryPortAttributesResponse = Response<QueryPortAttributesReply>;
+
+ Future<QueryPortAttributesReply> QueryPortAttributes(
+ const QueryPortAttributesRequest& request);
+
+ Future<QueryPortAttributesReply> QueryPortAttributes(const Port& port = {});
+
+ struct ListImageFormatsRequest {
+ Port port{};
+ };
+
+ struct ListImageFormatsReply {
+ uint16_t sequence{};
+ std::vector<ImageFormatInfo> format{};
+ };
+
+ using ListImageFormatsResponse = Response<ListImageFormatsReply>;
+
+ Future<ListImageFormatsReply> ListImageFormats(
+ const ListImageFormatsRequest& request);
+
+ Future<ListImageFormatsReply> ListImageFormats(const Port& port = {});
+
+ struct QueryImageAttributesRequest {
+ Port port{};
+ uint32_t id{};
+ uint16_t width{};
+ uint16_t height{};
+ };
+
+ struct QueryImageAttributesReply {
+ uint16_t sequence{};
+ uint32_t data_size{};
+ uint16_t width{};
+ uint16_t height{};
+ std::vector<uint32_t> pitches{};
+ std::vector<uint32_t> offsets{};
+ };
+
+ using QueryImageAttributesResponse = Response<QueryImageAttributesReply>;
+
+ Future<QueryImageAttributesReply> QueryImageAttributes(
+ const QueryImageAttributesRequest& request);
+
+ Future<QueryImageAttributesReply> QueryImageAttributes(
+ const Port& port = {},
+ const uint32_t& id = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {});
+
+ struct PutImageRequest {
+ Port port{};
+ Drawable drawable{};
+ GraphicsContext gc{};
+ uint32_t id{};
+ int16_t src_x{};
+ int16_t src_y{};
+ uint16_t src_w{};
+ uint16_t src_h{};
+ int16_t drw_x{};
+ int16_t drw_y{};
+ uint16_t drw_w{};
+ uint16_t drw_h{};
+ uint16_t width{};
+ uint16_t height{};
+ std::vector<uint8_t> data{};
+ };
+
+ using PutImageResponse = Response<void>;
+
+ Future<void> PutImage(const PutImageRequest& request);
+
+ Future<void> PutImage(const Port& port = {},
+ const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const uint32_t& id = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const uint16_t& src_w = {},
+ const uint16_t& src_h = {},
+ const int16_t& drw_x = {},
+ const int16_t& drw_y = {},
+ const uint16_t& drw_w = {},
+ const uint16_t& drw_h = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const std::vector<uint8_t>& data = {});
+
+ struct ShmPutImageRequest {
+ Port port{};
+ Drawable drawable{};
+ GraphicsContext gc{};
+ Shm::Seg shmseg{};
+ uint32_t id{};
+ uint32_t offset{};
+ int16_t src_x{};
+ int16_t src_y{};
+ uint16_t src_w{};
+ uint16_t src_h{};
+ int16_t drw_x{};
+ int16_t drw_y{};
+ uint16_t drw_w{};
+ uint16_t drw_h{};
+ uint16_t width{};
+ uint16_t height{};
+ uint8_t send_event{};
+ };
+
+ using ShmPutImageResponse = Response<void>;
+
+ Future<void> ShmPutImage(const ShmPutImageRequest& request);
+
+ Future<void> ShmPutImage(const Port& port = {},
+ const Drawable& drawable = {},
+ const GraphicsContext& gc = {},
+ const Shm::Seg& shmseg = {},
+ const uint32_t& id = {},
+ const uint32_t& offset = {},
+ const int16_t& src_x = {},
+ const int16_t& src_y = {},
+ const uint16_t& src_w = {},
+ const uint16_t& src_h = {},
+ const int16_t& drw_x = {},
+ const int16_t& drw_y = {},
+ const uint16_t& drw_w = {},
+ const uint16_t& drw_h = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint8_t& send_event = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+inline constexpr x11::Xv::Type operator|(x11::Xv::Type l, x11::Xv::Type r) {
+ using T = std::underlying_type_t<x11::Xv::Type>;
+ return static_cast<x11::Xv::Type>(static_cast<T>(l) | static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::Type operator&(x11::Xv::Type l, x11::Xv::Type r) {
+ using T = std::underlying_type_t<x11::Xv::Type>;
+ return static_cast<x11::Xv::Type>(static_cast<T>(l) & static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::ImageFormatInfoType operator|(
+ x11::Xv::ImageFormatInfoType l,
+ x11::Xv::ImageFormatInfoType r) {
+ using T = std::underlying_type_t<x11::Xv::ImageFormatInfoType>;
+ return static_cast<x11::Xv::ImageFormatInfoType>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::ImageFormatInfoType operator&(
+ x11::Xv::ImageFormatInfoType l,
+ x11::Xv::ImageFormatInfoType r) {
+ using T = std::underlying_type_t<x11::Xv::ImageFormatInfoType>;
+ return static_cast<x11::Xv::ImageFormatInfoType>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::ImageFormatInfoFormat operator|(
+ x11::Xv::ImageFormatInfoFormat l,
+ x11::Xv::ImageFormatInfoFormat r) {
+ using T = std::underlying_type_t<x11::Xv::ImageFormatInfoFormat>;
+ return static_cast<x11::Xv::ImageFormatInfoFormat>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::ImageFormatInfoFormat operator&(
+ x11::Xv::ImageFormatInfoFormat l,
+ x11::Xv::ImageFormatInfoFormat r) {
+ using T = std::underlying_type_t<x11::Xv::ImageFormatInfoFormat>;
+ return static_cast<x11::Xv::ImageFormatInfoFormat>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::AttributeFlag operator|(x11::Xv::AttributeFlag l,
+ x11::Xv::AttributeFlag r) {
+ using T = std::underlying_type_t<x11::Xv::AttributeFlag>;
+ return static_cast<x11::Xv::AttributeFlag>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::AttributeFlag operator&(x11::Xv::AttributeFlag l,
+ x11::Xv::AttributeFlag r) {
+ using T = std::underlying_type_t<x11::Xv::AttributeFlag>;
+ return static_cast<x11::Xv::AttributeFlag>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::VideoNotifyReason operator|(
+ x11::Xv::VideoNotifyReason l,
+ x11::Xv::VideoNotifyReason r) {
+ using T = std::underlying_type_t<x11::Xv::VideoNotifyReason>;
+ return static_cast<x11::Xv::VideoNotifyReason>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::VideoNotifyReason operator&(
+ x11::Xv::VideoNotifyReason l,
+ x11::Xv::VideoNotifyReason r) {
+ using T = std::underlying_type_t<x11::Xv::VideoNotifyReason>;
+ return static_cast<x11::Xv::VideoNotifyReason>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::ScanlineOrder operator|(x11::Xv::ScanlineOrder l,
+ x11::Xv::ScanlineOrder r) {
+ using T = std::underlying_type_t<x11::Xv::ScanlineOrder>;
+ return static_cast<x11::Xv::ScanlineOrder>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::ScanlineOrder operator&(x11::Xv::ScanlineOrder l,
+ x11::Xv::ScanlineOrder r) {
+ using T = std::underlying_type_t<x11::Xv::ScanlineOrder>;
+ return static_cast<x11::Xv::ScanlineOrder>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::GrabPortStatus operator|(x11::Xv::GrabPortStatus l,
+ x11::Xv::GrabPortStatus r) {
+ using T = std::underlying_type_t<x11::Xv::GrabPortStatus>;
+ return static_cast<x11::Xv::GrabPortStatus>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Xv::GrabPortStatus operator&(x11::Xv::GrabPortStatus l,
+ x11::Xv::GrabPortStatus r) {
+ using T = std::underlying_type_t<x11::Xv::GrabPortStatus>;
+ return static_cast<x11::Xv::GrabPortStatus>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XV_H_
diff --git a/chromium/ui/gfx/x/generated_protos/xvmc.cc b/chromium/ui/gfx/x/generated_protos/xvmc.cc
new file mode 100644
index 00000000000..98fbbb5e350
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xvmc.cc
@@ -0,0 +1,857 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#include "xvmc.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ui/gfx/x/xproto_internal.h"
+
+namespace x11 {
+
+XvMC::XvMC(Connection* connection, const x11::QueryExtensionReply& info)
+ : connection_(connection), info_(info) {}
+
+Future<XvMC::QueryVersionReply> XvMC::QueryVersion(
+ const XvMC::QueryVersionRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 0;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XvMC::QueryVersionReply>(
+ &buf, "XvMC::QueryVersion", false);
+}
+
+Future<XvMC::QueryVersionReply> XvMC::QueryVersion() {
+ return XvMC::QueryVersion(XvMC::QueryVersionRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XvMC::QueryVersionReply> detail::ReadReply<
+ XvMC::QueryVersionReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XvMC::QueryVersionReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& major = (*reply).major;
+ auto& minor = (*reply).minor;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // major
+ Read(&major, &buf);
+
+ // minor
+ Read(&minor, &buf);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XvMC::ListSurfaceTypesReply> XvMC::ListSurfaceTypes(
+ const XvMC::ListSurfaceTypesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port_id = request.port_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 1;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port_id
+ buf.Write(&port_id);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XvMC::ListSurfaceTypesReply>(
+ &buf, "XvMC::ListSurfaceTypes", false);
+}
+
+Future<XvMC::ListSurfaceTypesReply> XvMC::ListSurfaceTypes(
+ const Xv::Port& port_id) {
+ return XvMC::ListSurfaceTypes(XvMC::ListSurfaceTypesRequest{port_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XvMC::ListSurfaceTypesReply> detail::ReadReply<
+ XvMC::ListSurfaceTypesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XvMC::ListSurfaceTypesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num{};
+ auto& surfaces = (*reply).surfaces;
+ size_t surfaces_len = surfaces.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num
+ Read(&num, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // surfaces
+ surfaces.resize(num);
+ for (auto& surfaces_elem : surfaces) {
+ // surfaces_elem
+ {
+ auto& id = surfaces_elem.id;
+ auto& chroma_format = surfaces_elem.chroma_format;
+ auto& pad0 = surfaces_elem.pad0;
+ auto& max_width = surfaces_elem.max_width;
+ auto& max_height = surfaces_elem.max_height;
+ auto& subpicture_max_width = surfaces_elem.subpicture_max_width;
+ auto& subpicture_max_height = surfaces_elem.subpicture_max_height;
+ auto& mc_type = surfaces_elem.mc_type;
+ auto& flags = surfaces_elem.flags;
+
+ // id
+ Read(&id, &buf);
+
+ // chroma_format
+ Read(&chroma_format, &buf);
+
+ // pad0
+ Read(&pad0, &buf);
+
+ // max_width
+ Read(&max_width, &buf);
+
+ // max_height
+ Read(&max_height, &buf);
+
+ // subpicture_max_width
+ Read(&subpicture_max_width, &buf);
+
+ // subpicture_max_height
+ Read(&subpicture_max_height, &buf);
+
+ // mc_type
+ Read(&mc_type, &buf);
+
+ // flags
+ Read(&flags, &buf);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<XvMC::CreateContextReply> XvMC::CreateContext(
+ const XvMC::CreateContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_id = request.context_id;
+ auto& port_id = request.port_id;
+ auto& surface_id = request.surface_id;
+ auto& width = request.width;
+ auto& height = request.height;
+ auto& flags = request.flags;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 2;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_id
+ buf.Write(&context_id);
+
+ // port_id
+ buf.Write(&port_id);
+
+ // surface_id
+ buf.Write(&surface_id);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ // flags
+ buf.Write(&flags);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XvMC::CreateContextReply>(
+ &buf, "XvMC::CreateContext", false);
+}
+
+Future<XvMC::CreateContextReply> XvMC::CreateContext(const Context& context_id,
+ const Xv::Port& port_id,
+ const Surface& surface_id,
+ const uint16_t& width,
+ const uint16_t& height,
+ const uint32_t& flags) {
+ return XvMC::CreateContext(XvMC::CreateContextRequest{
+ context_id, port_id, surface_id, width, height, flags});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XvMC::CreateContextReply> detail::ReadReply<
+ XvMC::CreateContextReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XvMC::CreateContextReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& width_actual = (*reply).width_actual;
+ auto& height_actual = (*reply).height_actual;
+ auto& flags_return = (*reply).flags_return;
+ auto& priv_data = (*reply).priv_data;
+ size_t priv_data_len = priv_data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // width_actual
+ Read(&width_actual, &buf);
+
+ // height_actual
+ Read(&height_actual, &buf);
+
+ // flags_return
+ Read(&flags_return, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // priv_data
+ priv_data.resize(length);
+ for (auto& priv_data_elem : priv_data) {
+ // priv_data_elem
+ Read(&priv_data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XvMC::DestroyContext(const XvMC::DestroyContextRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& context_id = request.context_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 3;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // context_id
+ buf.Write(&context_id);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XvMC::DestroyContext", false);
+}
+
+Future<void> XvMC::DestroyContext(const Context& context_id) {
+ return XvMC::DestroyContext(XvMC::DestroyContextRequest{context_id});
+}
+
+Future<XvMC::CreateSurfaceReply> XvMC::CreateSurface(
+ const XvMC::CreateSurfaceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& surface_id = request.surface_id;
+ auto& context_id = request.context_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 4;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // surface_id
+ buf.Write(&surface_id);
+
+ // context_id
+ buf.Write(&context_id);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XvMC::CreateSurfaceReply>(
+ &buf, "XvMC::CreateSurface", false);
+}
+
+Future<XvMC::CreateSurfaceReply> XvMC::CreateSurface(
+ const Surface& surface_id,
+ const Context& context_id) {
+ return XvMC::CreateSurface(
+ XvMC::CreateSurfaceRequest{surface_id, context_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XvMC::CreateSurfaceReply> detail::ReadReply<
+ XvMC::CreateSurfaceReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XvMC::CreateSurfaceReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& priv_data = (*reply).priv_data;
+ size_t priv_data_len = priv_data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // pad1
+ Pad(&buf, 24);
+
+ // priv_data
+ priv_data.resize(length);
+ for (auto& priv_data_elem : priv_data) {
+ // priv_data_elem
+ Read(&priv_data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XvMC::DestroySurface(const XvMC::DestroySurfaceRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& surface_id = request.surface_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 5;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // surface_id
+ buf.Write(&surface_id);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XvMC::DestroySurface", false);
+}
+
+Future<void> XvMC::DestroySurface(const Surface& surface_id) {
+ return XvMC::DestroySurface(XvMC::DestroySurfaceRequest{surface_id});
+}
+
+Future<XvMC::CreateSubpictureReply> XvMC::CreateSubpicture(
+ const XvMC::CreateSubpictureRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& subpicture_id = request.subpicture_id;
+ auto& context = request.context;
+ auto& xvimage_id = request.xvimage_id;
+ auto& width = request.width;
+ auto& height = request.height;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 6;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // subpicture_id
+ buf.Write(&subpicture_id);
+
+ // context
+ buf.Write(&context);
+
+ // xvimage_id
+ buf.Write(&xvimage_id);
+
+ // width
+ buf.Write(&width);
+
+ // height
+ buf.Write(&height);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XvMC::CreateSubpictureReply>(
+ &buf, "XvMC::CreateSubpicture", false);
+}
+
+Future<XvMC::CreateSubpictureReply> XvMC::CreateSubpicture(
+ const SubPicture& subpicture_id,
+ const Context& context,
+ const uint32_t& xvimage_id,
+ const uint16_t& width,
+ const uint16_t& height) {
+ return XvMC::CreateSubpicture(XvMC::CreateSubpictureRequest{
+ subpicture_id, context, xvimage_id, width, height});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XvMC::CreateSubpictureReply> detail::ReadReply<
+ XvMC::CreateSubpictureReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XvMC::CreateSubpictureReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& width_actual = (*reply).width_actual;
+ auto& height_actual = (*reply).height_actual;
+ auto& num_palette_entries = (*reply).num_palette_entries;
+ auto& entry_bytes = (*reply).entry_bytes;
+ auto& component_order = (*reply).component_order;
+ size_t component_order_len = component_order.size();
+ auto& priv_data = (*reply).priv_data;
+ size_t priv_data_len = priv_data.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // width_actual
+ Read(&width_actual, &buf);
+
+ // height_actual
+ Read(&height_actual, &buf);
+
+ // num_palette_entries
+ Read(&num_palette_entries, &buf);
+
+ // entry_bytes
+ Read(&entry_bytes, &buf);
+
+ // component_order
+ for (auto& component_order_elem : component_order) {
+ // component_order_elem
+ Read(&component_order_elem, &buf);
+ }
+
+ // pad1
+ Pad(&buf, 12);
+
+ // priv_data
+ priv_data.resize(length);
+ for (auto& priv_data_elem : priv_data) {
+ // priv_data_elem
+ Read(&priv_data_elem, &buf);
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+Future<void> XvMC::DestroySubpicture(
+ const XvMC::DestroySubpictureRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& subpicture_id = request.subpicture_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 7;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // subpicture_id
+ buf.Write(&subpicture_id);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XvMC::DestroySubpicture", false);
+}
+
+Future<void> XvMC::DestroySubpicture(const SubPicture& subpicture_id) {
+ return XvMC::DestroySubpicture(XvMC::DestroySubpictureRequest{subpicture_id});
+}
+
+Future<XvMC::ListSubpictureTypesReply> XvMC::ListSubpictureTypes(
+ const XvMC::ListSubpictureTypesRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& port_id = request.port_id;
+ auto& surface_id = request.surface_id;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 8;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // port_id
+ buf.Write(&port_id);
+
+ // surface_id
+ buf.Write(&surface_id);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XvMC::ListSubpictureTypesReply>(
+ &buf, "XvMC::ListSubpictureTypes", false);
+}
+
+Future<XvMC::ListSubpictureTypesReply> XvMC::ListSubpictureTypes(
+ const Xv::Port& port_id,
+ const Surface& surface_id) {
+ return XvMC::ListSubpictureTypes(
+ XvMC::ListSubpictureTypesRequest{port_id, surface_id});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XvMC::ListSubpictureTypesReply> detail::ReadReply<
+ XvMC::ListSubpictureTypesReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XvMC::ListSubpictureTypesReply>();
+
+ auto& sequence = (*reply).sequence;
+ uint32_t num{};
+ auto& types = (*reply).types;
+ size_t types_len = types.size();
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // num
+ Read(&num, &buf);
+
+ // pad1
+ Pad(&buf, 20);
+
+ // types
+ types.resize(num);
+ for (auto& types_elem : types) {
+ // types_elem
+ {
+ auto& id = types_elem.id;
+ auto& type = types_elem.type;
+ auto& byte_order = types_elem.byte_order;
+ auto& guid = types_elem.guid;
+ size_t guid_len = guid.size();
+ auto& bpp = types_elem.bpp;
+ auto& num_planes = types_elem.num_planes;
+ auto& depth = types_elem.depth;
+ auto& red_mask = types_elem.red_mask;
+ auto& green_mask = types_elem.green_mask;
+ auto& blue_mask = types_elem.blue_mask;
+ auto& format = types_elem.format;
+ auto& y_sample_bits = types_elem.y_sample_bits;
+ auto& u_sample_bits = types_elem.u_sample_bits;
+ auto& v_sample_bits = types_elem.v_sample_bits;
+ auto& vhorz_y_period = types_elem.vhorz_y_period;
+ auto& vhorz_u_period = types_elem.vhorz_u_period;
+ auto& vhorz_v_period = types_elem.vhorz_v_period;
+ auto& vvert_y_period = types_elem.vvert_y_period;
+ auto& vvert_u_period = types_elem.vvert_u_period;
+ auto& vvert_v_period = types_elem.vvert_v_period;
+ auto& vcomp_order = types_elem.vcomp_order;
+ size_t vcomp_order_len = vcomp_order.size();
+ auto& vscanline_order = types_elem.vscanline_order;
+
+ // id
+ Read(&id, &buf);
+
+ // type
+ uint8_t tmp0;
+ Read(&tmp0, &buf);
+ type = static_cast<Xv::ImageFormatInfoType>(tmp0);
+
+ // byte_order
+ uint8_t tmp1;
+ Read(&tmp1, &buf);
+ byte_order = static_cast<ImageOrder>(tmp1);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // guid
+ for (auto& guid_elem : guid) {
+ // guid_elem
+ Read(&guid_elem, &buf);
+ }
+
+ // bpp
+ Read(&bpp, &buf);
+
+ // num_planes
+ Read(&num_planes, &buf);
+
+ // pad1
+ Pad(&buf, 2);
+
+ // depth
+ Read(&depth, &buf);
+
+ // pad2
+ Pad(&buf, 3);
+
+ // red_mask
+ Read(&red_mask, &buf);
+
+ // green_mask
+ Read(&green_mask, &buf);
+
+ // blue_mask
+ Read(&blue_mask, &buf);
+
+ // format
+ uint8_t tmp2;
+ Read(&tmp2, &buf);
+ format = static_cast<Xv::ImageFormatInfoFormat>(tmp2);
+
+ // pad3
+ Pad(&buf, 3);
+
+ // y_sample_bits
+ Read(&y_sample_bits, &buf);
+
+ // u_sample_bits
+ Read(&u_sample_bits, &buf);
+
+ // v_sample_bits
+ Read(&v_sample_bits, &buf);
+
+ // vhorz_y_period
+ Read(&vhorz_y_period, &buf);
+
+ // vhorz_u_period
+ Read(&vhorz_u_period, &buf);
+
+ // vhorz_v_period
+ Read(&vhorz_v_period, &buf);
+
+ // vvert_y_period
+ Read(&vvert_y_period, &buf);
+
+ // vvert_u_period
+ Read(&vvert_u_period, &buf);
+
+ // vvert_v_period
+ Read(&vvert_v_period, &buf);
+
+ // vcomp_order
+ for (auto& vcomp_order_elem : vcomp_order) {
+ // vcomp_order_elem
+ Read(&vcomp_order_elem, &buf);
+ }
+
+ // vscanline_order
+ uint8_t tmp3;
+ Read(&tmp3, &buf);
+ vscanline_order = static_cast<Xv::ScanlineOrder>(tmp3);
+
+ // pad4
+ Pad(&buf, 11);
+ }
+ }
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/generated_protos/xvmc.h b/chromium/ui/gfx/x/generated_protos/xvmc.h
new file mode 100644
index 00000000000..cd95f9d6edd
--- /dev/null
+++ b/chromium/ui/gfx/x/generated_protos/xvmc.h
@@ -0,0 +1,263 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was automatically generated with:
+// ../../ui/gfx/x/gen_xproto.py \
+// ../../third_party/xcbproto/src \
+// gen/ui/gfx/x \
+// bigreq \
+// composite \
+// damage \
+// dpms \
+// dri2 \
+// dri3 \
+// ge \
+// glx \
+// present \
+// randr \
+// record \
+// render \
+// res \
+// screensaver \
+// shape \
+// shm \
+// sync \
+// xc_misc \
+// xevie \
+// xf86dri \
+// xf86vidmode \
+// xfixes \
+// xinerama \
+// xinput \
+// xkb \
+// xprint \
+// xproto \
+// xselinux \
+// xtest \
+// xv \
+// xvmc
+
+#ifndef UI_GFX_X_GENERATED_PROTOS_XVMC_H_
+#define UI_GFX_X_GENERATED_PROTOS_XVMC_H_
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/error.h"
+#include "ui/gfx/x/ref_counted_fd.h"
+#include "xproto.h"
+#include "xv.h"
+
+namespace x11 {
+
+class Connection;
+
+template <typename Reply>
+struct Response;
+
+template <typename Reply>
+class Future;
+
+class COMPONENT_EXPORT(X11) XvMC {
+ public:
+ static constexpr unsigned major_version = 1;
+ static constexpr unsigned minor_version = 1;
+
+ XvMC(Connection* connection, const x11::QueryExtensionReply& info);
+
+ uint8_t present() const { return info_.present; }
+ uint8_t major_opcode() const { return info_.major_opcode; }
+ uint8_t first_event() const { return info_.first_event; }
+ uint8_t first_error() const { return info_.first_error; }
+
+ Connection* connection() const { return connection_; }
+
+ enum class Context : uint32_t {};
+
+ enum class Surface : uint32_t {};
+
+ enum class SubPicture : uint32_t {};
+
+ struct SurfaceInfo {
+ Surface id{};
+ uint16_t chroma_format{};
+ uint16_t pad0{};
+ uint16_t max_width{};
+ uint16_t max_height{};
+ uint16_t subpicture_max_width{};
+ uint16_t subpicture_max_height{};
+ uint32_t mc_type{};
+ uint32_t flags{};
+ };
+
+ struct QueryVersionRequest {};
+
+ struct QueryVersionReply {
+ uint16_t sequence{};
+ uint32_t major{};
+ uint32_t minor{};
+ };
+
+ using QueryVersionResponse = Response<QueryVersionReply>;
+
+ Future<QueryVersionReply> QueryVersion(const QueryVersionRequest& request);
+
+ Future<QueryVersionReply> QueryVersion();
+
+ struct ListSurfaceTypesRequest {
+ Xv::Port port_id{};
+ };
+
+ struct ListSurfaceTypesReply {
+ uint16_t sequence{};
+ std::vector<SurfaceInfo> surfaces{};
+ };
+
+ using ListSurfaceTypesResponse = Response<ListSurfaceTypesReply>;
+
+ Future<ListSurfaceTypesReply> ListSurfaceTypes(
+ const ListSurfaceTypesRequest& request);
+
+ Future<ListSurfaceTypesReply> ListSurfaceTypes(const Xv::Port& port_id = {});
+
+ struct CreateContextRequest {
+ Context context_id{};
+ Xv::Port port_id{};
+ Surface surface_id{};
+ uint16_t width{};
+ uint16_t height{};
+ uint32_t flags{};
+ };
+
+ struct CreateContextReply {
+ uint16_t sequence{};
+ uint16_t width_actual{};
+ uint16_t height_actual{};
+ uint32_t flags_return{};
+ std::vector<uint32_t> priv_data{};
+ };
+
+ using CreateContextResponse = Response<CreateContextReply>;
+
+ Future<CreateContextReply> CreateContext(const CreateContextRequest& request);
+
+ Future<CreateContextReply> CreateContext(const Context& context_id = {},
+ const Xv::Port& port_id = {},
+ const Surface& surface_id = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {},
+ const uint32_t& flags = {});
+
+ struct DestroyContextRequest {
+ Context context_id{};
+ };
+
+ using DestroyContextResponse = Response<void>;
+
+ Future<void> DestroyContext(const DestroyContextRequest& request);
+
+ Future<void> DestroyContext(const Context& context_id = {});
+
+ struct CreateSurfaceRequest {
+ Surface surface_id{};
+ Context context_id{};
+ };
+
+ struct CreateSurfaceReply {
+ uint16_t sequence{};
+ std::vector<uint32_t> priv_data{};
+ };
+
+ using CreateSurfaceResponse = Response<CreateSurfaceReply>;
+
+ Future<CreateSurfaceReply> CreateSurface(const CreateSurfaceRequest& request);
+
+ Future<CreateSurfaceReply> CreateSurface(const Surface& surface_id = {},
+ const Context& context_id = {});
+
+ struct DestroySurfaceRequest {
+ Surface surface_id{};
+ };
+
+ using DestroySurfaceResponse = Response<void>;
+
+ Future<void> DestroySurface(const DestroySurfaceRequest& request);
+
+ Future<void> DestroySurface(const Surface& surface_id = {});
+
+ struct CreateSubpictureRequest {
+ SubPicture subpicture_id{};
+ Context context{};
+ uint32_t xvimage_id{};
+ uint16_t width{};
+ uint16_t height{};
+ };
+
+ struct CreateSubpictureReply {
+ uint16_t sequence{};
+ uint16_t width_actual{};
+ uint16_t height_actual{};
+ uint16_t num_palette_entries{};
+ uint16_t entry_bytes{};
+ std::array<uint8_t, 4> component_order{};
+ std::vector<uint32_t> priv_data{};
+ };
+
+ using CreateSubpictureResponse = Response<CreateSubpictureReply>;
+
+ Future<CreateSubpictureReply> CreateSubpicture(
+ const CreateSubpictureRequest& request);
+
+ Future<CreateSubpictureReply> CreateSubpicture(
+ const SubPicture& subpicture_id = {},
+ const Context& context = {},
+ const uint32_t& xvimage_id = {},
+ const uint16_t& width = {},
+ const uint16_t& height = {});
+
+ struct DestroySubpictureRequest {
+ SubPicture subpicture_id{};
+ };
+
+ using DestroySubpictureResponse = Response<void>;
+
+ Future<void> DestroySubpicture(const DestroySubpictureRequest& request);
+
+ Future<void> DestroySubpicture(const SubPicture& subpicture_id = {});
+
+ struct ListSubpictureTypesRequest {
+ Xv::Port port_id{};
+ Surface surface_id{};
+ };
+
+ struct ListSubpictureTypesReply {
+ uint16_t sequence{};
+ std::vector<Xv::ImageFormatInfo> types{};
+ };
+
+ using ListSubpictureTypesResponse = Response<ListSubpictureTypesReply>;
+
+ Future<ListSubpictureTypesReply> ListSubpictureTypes(
+ const ListSubpictureTypesRequest& request);
+
+ Future<ListSubpictureTypesReply> ListSubpictureTypes(
+ const Xv::Port& port_id = {},
+ const Surface& surface_id = {});
+
+ private:
+ Connection* const connection_;
+ x11::QueryExtensionReply info_{};
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_GENERATED_PROTOS_XVMC_H_
diff --git a/chromium/ui/gfx/x/keyboard_state.cc b/chromium/ui/gfx/x/keyboard_state.cc
index 3ca1e8084bc..147b6c0668e 100644
--- a/chromium/ui/gfx/x/keyboard_state.cc
+++ b/chromium/ui/gfx/x/keyboard_state.cc
@@ -6,6 +6,7 @@
#include "base/i18n/case_conversion.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/keysyms/keysyms.h"
#include "ui/gfx/x/xkb.h"
#include "ui/gfx/x/xproto.h"
@@ -64,7 +65,7 @@ class CoreKeyboardState : public KeyboardState {
static_cast<int>(keyboard_mapping_.keysyms.size()));
for (size_t i = 0; i < keyboard_mapping_.keysyms.size(); i++) {
auto keycode = min_keycode + i / keyboard_mapping_.keysyms_per_keycode;
- if (keyboard_mapping_.keysyms[i] == static_cast<x11::KeySym>(keysym))
+ if (keyboard_mapping_.keysyms[i] == static_cast<KeySym>(keysym))
return static_cast<KeyCode>(keycode);
}
return {};
@@ -83,7 +84,7 @@ class CoreKeyboardState : public KeyboardState {
&mode_switch_, &num_lock_);
}
- x11::Connection* const connection_;
+ Connection* const connection_;
GetKeyboardMappingReply keyboard_mapping_;
uint16_t lock_meaning_ = 0;
uint8_t mode_switch_ = 0;
@@ -123,7 +124,7 @@ class XkbKeyboardState : public KeyboardState {
map_ = std::move(*response.reply);
}
- x11::Connection* const connection_;
+ Connection* const connection_;
Xkb::GetMapReply map_;
};
diff --git a/chromium/ui/gfx/x/property_cache.cc b/chromium/ui/gfx/x/property_cache.cc
new file mode 100644
index 00000000000..2f318a25093
--- /dev/null
+++ b/chromium/ui/gfx/x/property_cache.cc
@@ -0,0 +1,90 @@
+// Copyright 2020 The Chromium 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/x/property_cache.h"
+
+#include <limits>
+
+#include "base/check_op.h"
+#include "ui/gfx/x/event.h"
+#include "ui/gfx/x/xproto.h"
+
+namespace x11 {
+
+PropertyCache::PropertyCache(Connection* connection,
+ Window window,
+ const std::vector<Atom>& properties)
+ : connection_(connection),
+ window_(window),
+ event_selector_(window_, EventMask::PropertyChange) {
+ connection_->AddEventObserver(this);
+
+ std::vector<std::pair<Atom, PropertyValue>> mem(properties.size());
+ for (size_t i = 0; i < properties.size(); i++) {
+ mem[i].first = properties[i];
+ FetchProperty(properties[i], &mem[i].second);
+ }
+ properties_ = base::flat_map<Atom, PropertyValue>(std::move(mem));
+}
+
+PropertyCache::~PropertyCache() {
+ connection_->RemoveEventObserver(this);
+}
+
+const GetPropertyResponse& PropertyCache::Get(Atom atom) {
+ auto it = properties_.find(atom);
+ DCHECK(it != properties_.end());
+
+ if (!it->second.response.has_value())
+ it->second.future.Wait();
+ DCHECK(it->second.response.has_value());
+
+ return it->second.response.value();
+}
+
+void PropertyCache::OnEvent(const Event& xev) {
+ auto* prop = xev.As<PropertyNotifyEvent>();
+ if (!prop)
+ return;
+ if (prop->window != window_)
+ return;
+ auto it = properties_.find(prop->atom);
+ if (it == properties_.end())
+ return;
+ if (prop->state == Property::NewValue) {
+ FetchProperty(it->first, &it->second);
+ } else {
+ DCHECK_EQ(prop->state, Property::Delete);
+ // When the property is deleted, a GetPropertyRequest will result in a
+ // zeroed GetPropertyReply, so set the reply state now to avoid making an
+ // unnecessary request.
+ it->second.response =
+ GetPropertyResponse{std::make_unique<GetPropertyReply>(), nullptr};
+ }
+}
+
+void PropertyCache::FetchProperty(Atom property, PropertyValue* value) {
+ value->future = connection_->GetProperty({
+ .window = window_,
+ .property = property,
+ .long_length = std::numeric_limits<uint32_t>::max(),
+ });
+ value->future.OnResponse(base::BindOnce(&PropertyCache::OnGetPropertyResponse,
+ weak_factory_.GetWeakPtr(), value));
+}
+
+void PropertyCache::OnGetPropertyResponse(PropertyValue* value,
+ GetPropertyResponse response) {
+ value->response = std::move(response);
+}
+
+PropertyCache::PropertyValue::PropertyValue() = default;
+
+PropertyCache::PropertyValue::PropertyValue(PropertyValue&&) = default;
+PropertyCache::PropertyValue& PropertyCache::PropertyValue::operator=(
+ PropertyValue&&) = default;
+
+PropertyCache::PropertyValue::~PropertyValue() = default;
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/property_cache.h b/chromium/ui/gfx/x/property_cache.h
new file mode 100644
index 00000000000..2ab765a9016
--- /dev/null
+++ b/chromium/ui/gfx/x/property_cache.h
@@ -0,0 +1,85 @@
+// Copyright 2020 The Chromium 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_X_PROPERTY_CACHE_H_
+#define UI_GFX_X_PROPERTY_CACHE_H_
+
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/containers/flat_map.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
+#include "ui/gfx/x/xproto.h"
+
+namespace x11 {
+
+// Watches properties on an X11 window. Property values are obtained once upon
+// creation and are refreshed after each property change.
+class COMPONENT_EXPORT(X11) PropertyCache : public EventObserver {
+ public:
+ PropertyCache(Connection* connection,
+ Window window,
+ const std::vector<Atom>& properties);
+
+ PropertyCache(const PropertyCache&) = delete;
+ PropertyCache& operator=(const PropertyCache&) = delete;
+
+ ~PropertyCache() override;
+
+ const GetPropertyResponse& Get(Atom atom);
+
+ template <typename T>
+ const T* GetAs(Atom atom, size_t* size = nullptr) {
+ auto& response = Get(atom);
+ if (size)
+ *size = 0;
+ if (!response || response->format != CHAR_BIT * sizeof(T) ||
+ !response->value_len) {
+ return nullptr;
+ }
+ if (size)
+ *size = response->value_len;
+ return response->value->front_as<T>();
+ }
+
+ private:
+ friend class PropertyCacheTest;
+
+ struct PropertyValue {
+ PropertyValue();
+
+ PropertyValue(PropertyValue&&);
+ PropertyValue& operator=(PropertyValue&&);
+
+ ~PropertyValue();
+
+ Future<GetPropertyReply> future;
+ // |response| is nullopt if the request hasn't yet finished.
+ base::Optional<GetPropertyResponse> response = base::nullopt;
+ };
+
+ // EventObserver:
+ void OnEvent(const Event& xev) override;
+
+ void FetchProperty(Atom property, PropertyValue* value);
+
+ void OnGetPropertyResponse(PropertyValue* value,
+ GetPropertyResponse response);
+
+ Connection* connection_;
+ Window window_;
+ XScopedEventSelector event_selector_;
+ base::flat_map<Atom, PropertyValue> properties_;
+
+ base::WeakPtrFactory<PropertyCache> weak_factory_{this};
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_PROPERTY_CACHE_H_
diff --git a/chromium/ui/gfx/x/property_cache_unittest.cc b/chromium/ui/gfx/x/property_cache_unittest.cc
new file mode 100644
index 00000000000..ffc39d6d5e4
--- /dev/null
+++ b/chromium/ui/gfx/x/property_cache_unittest.cc
@@ -0,0 +1,173 @@
+// Copyright 2020 The Chromium 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/x/property_cache.h"
+
+#include <memory>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_util.h"
+
+namespace x11 {
+
+class PropertyCacheTest : public testing::Test {
+ public:
+ ~PropertyCacheTest() override = default;
+
+ protected:
+ base::flat_map<Atom, PropertyCache::PropertyValue>& GetProperties(
+ PropertyCache* property_cache) {
+ return property_cache->properties_;
+ }
+
+ Connection* connection() { return connection_; }
+
+ Window window() { return window_; }
+
+ private:
+ void SetUp() override {
+ connection_ = Connection::Get();
+ window_ = CreateDummyWindow("");
+ }
+
+ void TearDown() override {
+ connection_->DestroyWindow({window_}).Sync();
+ window_ = Window::None;
+ connection_ = nullptr;
+ }
+
+ Connection* connection_ = nullptr;
+ Window window_ = Window::None;
+};
+
+TEST_F(PropertyCacheTest, GetSync) {
+ auto atom = x11::GetAtom("DUMMY ATOM");
+ SetProperty(window(), atom, Atom::CARDINAL, 1234);
+
+ PropertyCache cache(connection(), window(), {atom});
+
+ // The cache should Sync() on getting the value.
+ EXPECT_FALSE(GetProperties(&cache)[atom].response.has_value());
+ auto* value = cache.GetAs<uint32_t>(atom);
+ EXPECT_TRUE(GetProperties(&cache)[atom].response.has_value());
+
+ ASSERT_TRUE(value);
+ EXPECT_EQ(*value, 1234u);
+}
+
+TEST_F(PropertyCacheTest, GetAsync) {
+ auto atom = x11::GetAtom("DUMMY ATOM");
+ SetProperty(window(), atom, Atom::CARDINAL, 1234);
+
+ PropertyCache cache(connection(), window(), {atom});
+
+ // The cache should not Sync() unnecessarily.
+ EXPECT_FALSE(GetProperties(&cache)[atom].response.has_value());
+ connection()->Sync();
+ connection()->DispatchAll();
+ EXPECT_TRUE(GetProperties(&cache)[atom].response.has_value());
+
+ auto* value = cache.GetAs<uint32_t>(atom);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(*value, 1234u);
+}
+
+TEST_F(PropertyCacheTest, Event) {
+ auto atom = x11::GetAtom("DUMMY ATOM");
+ SetProperty(window(), atom, Atom::CARDINAL, 1234);
+
+ PropertyCache cache(connection(), window(), {atom});
+
+ auto* value = cache.GetAs<uint32_t>(atom);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(*value, 1234u);
+
+ // Change the property and sync to ensure the PropertyNotify event is ready to
+ // be dispatched.
+ SetProperty(window(), atom, Atom::CARDINAL, 5678);
+ connection()->Sync();
+ connection()->ReadResponses();
+
+ // Dispatch the PropertyNotify event, which will cause the PropertyCache to
+ // send another GetPropertyRequest. Calling DispatchAll() would introduce a
+ // race condition where we could get the GetPropertyResponse early if the 2
+ // round trips are completed fast enough. To avoid this, we use Dispatch(),
+ // which doesn't read or write on the socket.
+ while (connection()->Dispatch()) {
+ }
+
+ // We don't have the new GetPropertyResponse yet, so the old value should
+ // still be there.
+ value = cache.GetAs<uint32_t>(atom);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(*value, 1234u);
+
+ // Complete the second round trip to acquire the new property value.
+ connection()->Sync();
+ connection()->DispatchAll();
+
+ // Now the cache should have the new value.
+ value = cache.GetAs<uint32_t>(atom);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(*value, 5678u);
+}
+
+TEST_F(PropertyCacheTest, GetAs) {
+ auto atom = x11::GetAtom("DUMMY ATOM");
+ SetProperty(window(), atom, Atom::CARDINAL, 1234);
+
+ PropertyCache cache(connection(), window(), {atom});
+
+ // Get() should return the correct property value.
+ auto& response = cache.Get(atom);
+ ASSERT_TRUE(response);
+ EXPECT_EQ(response->bytes_after, 0u);
+ EXPECT_EQ(response->format, 32);
+ EXPECT_EQ(response->type, Atom::CARDINAL);
+ EXPECT_EQ(*response->value->front_as<uint32_t>(), 1234u);
+ EXPECT_EQ(response->value_len, 1u);
+
+ // GetAs() should do the same thing as Get().
+ size_t size = 0;
+ auto* value = cache.GetAs<uint32_t>(atom, &size);
+ EXPECT_EQ(size, 1u);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(*value, 1234u);
+
+ // GetAs() should allow a nullptr size.
+ value = cache.GetAs<uint32_t>(atom /* size is defaulted to nullptr */);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(*value, 1234u);
+
+ // The below checks make requests and requires event dispatching, so
+ // synchronize all requests to avoid verbosity from Sync()ing everywhere.
+ connection()->SynchronizeForTest(true);
+
+ // GetAs() should return nullptr if the type's size is mismatched.
+ SetProperty(window(), atom, Atom::CARDINAL, static_cast<uint8_t>(123));
+ connection()->DispatchAll();
+ value = cache.GetAs<uint32_t>(atom, &size);
+ EXPECT_EQ(size, 0u);
+ EXPECT_FALSE(value);
+
+ // GetAs() should return nullptr if the property has no elements.
+ SetArrayProperty(window(), atom, Atom::CARDINAL, std::vector<uint32_t>());
+ connection()->DispatchAll();
+ value = cache.GetAs<uint32_t>(atom, &size);
+ EXPECT_EQ(size, 0u);
+ EXPECT_FALSE(value);
+
+ // GetAs() should return nullptr if the property is deleted.
+ DeleteProperty(window(), atom);
+ connection()->DispatchAll();
+ value = cache.GetAs<uint32_t>(atom, &size);
+ EXPECT_EQ(size, 0u);
+ EXPECT_FALSE(value);
+
+ connection()->SynchronizeForTest(true);
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/ref_counted_fd.cc b/chromium/ui/gfx/x/ref_counted_fd.cc
new file mode 100644
index 00000000000..64ed2a8026c
--- /dev/null
+++ b/chromium/ui/gfx/x/ref_counted_fd.cc
@@ -0,0 +1,37 @@
+// Copyright 2021 The Chromium 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/x/ref_counted_fd.h"
+
+#include "base/check_op.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/posix/eintr_wrapper.h"
+
+namespace x11 {
+
+RefCountedFD::RefCountedFD() = default;
+
+RefCountedFD::RefCountedFD(int fd) : impl_(base::MakeRefCounted<Impl>(fd)) {}
+
+RefCountedFD::RefCountedFD(base::ScopedFD fd)
+ : impl_(base::MakeRefCounted<Impl>(std::move(fd))) {}
+
+RefCountedFD::RefCountedFD(const RefCountedFD& other) = default;
+RefCountedFD::RefCountedFD(RefCountedFD&&) = default;
+RefCountedFD& RefCountedFD::operator=(const RefCountedFD& other) = default;
+RefCountedFD& RefCountedFD::operator=(RefCountedFD&&) = default;
+RefCountedFD::~RefCountedFD() = default;
+
+int RefCountedFD::get() const {
+ return impl_ ? impl_->fd().get() : -1;
+}
+
+RefCountedFD::Impl::Impl(int fd) : fd_(fd) {}
+
+RefCountedFD::Impl::Impl(base::ScopedFD fd) : fd_(std::move(fd)) {}
+
+RefCountedFD::Impl::~Impl() = default;
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/ref_counted_fd.h b/chromium/ui/gfx/x/ref_counted_fd.h
new file mode 100644
index 00000000000..991c9e74948
--- /dev/null
+++ b/chromium/ui/gfx/x/ref_counted_fd.h
@@ -0,0 +1,54 @@
+// Copyright 2021 The Chromium 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_X_REF_COUNTED_FD_H_
+#define UI_GFX_X_REF_COUNTED_FD_H_
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
+
+namespace x11 {
+
+// Wraps a native file descriptor and close()s it when there are no more active
+// scoped_refptrs. This class is needed to implement request argument
+// forwarding and is probably not useful outside of that context.
+class COMPONENT_EXPORT(X11) RefCountedFD {
+ public:
+ RefCountedFD();
+ explicit RefCountedFD(int fd);
+ explicit RefCountedFD(base::ScopedFD);
+
+ // All special members are defaulted.
+ RefCountedFD(const RefCountedFD&);
+ RefCountedFD(RefCountedFD&&);
+ RefCountedFD& operator=(const RefCountedFD&);
+ RefCountedFD& operator=(RefCountedFD&&);
+ ~RefCountedFD();
+
+ int get() const;
+
+ private:
+ class Impl : public base::RefCounted<Impl> {
+ public:
+ explicit Impl(int fd);
+ explicit Impl(base::ScopedFD fd);
+
+ base::ScopedFD& fd() { return fd_; }
+
+ private:
+ friend class base::RefCounted<Impl>;
+
+ ~Impl();
+
+ base::ScopedFD fd_;
+ };
+
+ scoped_refptr<Impl> impl_;
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_REF_COUNTED_FD_H_
diff --git a/chromium/ui/gfx/x/scoped_ignore_errors.cc b/chromium/ui/gfx/x/scoped_ignore_errors.cc
index 0d9e6dff0af..9364dbd9812 100644
--- a/chromium/ui/gfx/x/scoped_ignore_errors.cc
+++ b/chromium/ui/gfx/x/scoped_ignore_errors.cc
@@ -8,7 +8,7 @@ namespace x11 {
namespace {
-void IgnoreErrors(const x11::Error* error, const char* request_name) {}
+void IgnoreErrors(const Error* error, const char* request_name) {}
} // namespace
diff --git a/chromium/ui/gfx/x/x11_atom_cache.cc b/chromium/ui/gfx/x/x11_atom_cache.cc
index 767bf21124b..db030cc9bd3 100644
--- a/chromium/ui/gfx/x/x11_atom_cache.cc
+++ b/chromium/ui/gfx/x/x11_atom_cache.cc
@@ -12,82 +12,11 @@
#include "base/metrics/histogram_functions.h"
#include "base/stl_util.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
-namespace {
+namespace x11 {
-struct {
- const char* atom_name;
- x11::Atom atom_value;
-} const kPredefinedAtoms[] = {
- // {"PRIMARY", x11::Atom::PRIMARY},
- // {"SECONDARY", x11::Atom::SECONDARY},
- // {"ARC", x11::Atom::ARC},
- {"ATOM", x11::Atom::ATOM},
- // {"BITMAP", x11::Atom::BITMAP},
- {"CARDINAL", x11::Atom::CARDINAL},
- // {"COLORMAP", x11::Atom::COLORMAP},
- // {"CURSOR", x11::Atom::CURSOR},
- // {"CUT_BUFFER0", x11::Atom::CUT_BUFFER0},
- // {"CUT_BUFFER1", x11::Atom::CUT_BUFFER1},
- // {"CUT_BUFFER2", x11::Atom::CUT_BUFFER2},
- // {"CUT_BUFFER3", x11::Atom::CUT_BUFFER3},
- // {"CUT_BUFFER4", x11::Atom::CUT_BUFFER4},
- // {"CUT_BUFFER5", x11::Atom::CUT_BUFFER5},
- // {"CUT_BUFFER6", x11::Atom::CUT_BUFFER6},
- // {"CUT_BUFFER7", x11::Atom::CUT_BUFFER7},
- // {"DRAWABLE", x11::Atom::DRAWABLE},
- // {"FONT", x11::Atom::FONT},
- // {"INTEGER", x11::Atom::INTEGER},
- // {"PIXMAP", x11::Atom::PIXMAP},
- // {"POINT", x11::Atom::POINT},
- // {"RECTANGLE", x11::Atom::RECTANGLE},
- // {"RESOURCE_MANAGER", x11::Atom::RESOURCE_MANAGER},
- // {"RGB_COLOR_MAP", x11::Atom::RGB_COLOR_MAP},
- // {"RGB_BEST_MAP", x11::Atom::RGB_BEST_MAP},
- // {"RGB_BLUE_MAP", x11::Atom::RGB_BLUE_MAP},
- // {"RGB_DEFAULT_MAP", x11::Atom::RGB_DEFAULT_MAP},
- // {"RGB_GRAY_MAP", x11::Atom::RGB_GRAY_MAP},
- // {"RGB_GREEN_MAP", x11::Atom::RGB_GREEN_MAP},
- // {"RGB_RED_MAP", x11::Atom::RGB_RED_MAP},
- {"STRING", x11::Atom::STRING},
- // {"VISUALID", x11::Atom::VISUALID},
- // {"WINDOW", x11::Atom::WINDOW},
- // {"WM_COMMAND", x11::Atom::WM_COMMAND},
- // {"WM_HINTS", x11::Atom::WM_HINTS},
- // {"WM_CLIENT_MACHINE", x11::Atom::WM_CLIENT_MACHINE},
- // {"WM_ICON_NAME", x11::Atom::WM_ICON_NAME},
- // {"WM_ICON_SIZE", x11::Atom::WM_ICON_SIZE},
- // {"WM_NAME", x11::Atom::WM_NAME},
- // {"WM_NORMAL_HINTS", x11::Atom::WM_NORMAL_HINTS},
- // {"WM_SIZE_HINTS", x11::Atom::WM_SIZE_HINTS},
- // {"WM_ZOOM_HINTS", x11::Atom::WM_ZOOM_HINTS},
- // {"MIN_SPACE", x11::Atom::MIN_SPACE},
- // {"NORM_SPACE", x11::Atom::NORM_SPACE},
- // {"MAX_SPACE", x11::Atom::MAX_SPACE},
- // {"END_SPACE", x11::Atom::END_SPACE},
- // {"SUPERSCRIPT_X", x11::Atom::SUPERSCRIPT_X},
- // {"SUPERSCRIPT_Y", x11::Atom::SUPERSCRIPT_Y},
- // {"SUBSCRIPT_X", x11::Atom::SUBSCRIPT_X},
- // {"SUBSCRIPT_Y", x11::Atom::SUBSCRIPT_Y},
- // {"UNDERLINE_POSITION", x11::Atom::UNDERLINE_POSITION},
- // {"UNDERLINE_THICKNESS", x11::Atom::UNDERLINE_THICKNESS},
- // {"STRIKEOUT_ASCENT", x11::Atom::STRIKEOUT_ASCENT},
- // {"STRIKEOUT_DESCENT", x11::Atom::STRIKEOUT_DESCENT},
- // {"ITALIC_ANGLE", x11::Atom::ITALIC_ANGLE},
- // {"X_HEIGHT", x11::Atom::X_HEIGHT},
- // {"QUAD_WIDTH", x11::Atom::QUAD_WIDTH},
- // {"WEIGHT", x11::Atom::WEIGHT},
- // {"POINT_SIZE", x11::Atom::POINT_SIZE},
- // {"RESOLUTION", x11::Atom::RESOLUTION},
- // {"COPYRIGHT", x11::Atom::COPYRIGHT},
- // {"NOTICE", x11::Atom::NOTICE},
- // {"FONT_NAME", x11::Atom::FONT_NAME},
- // {"FAMILY_NAME", x11::Atom::FAMILY_NAME},
- // {"FULL_NAME", x11::Atom::FULL_NAME},
- // {"CAP_HEIGHT", x11::Atom::CAP_HEIGHT},
- {"WM_CLASS", x11::Atom::WM_CLASS},
- // {"WM_TRANSIENT_FOR", x11::Atom::WM_TRANSIENT_FOR},
-};
+namespace {
constexpr const char* kAtomsToCache[] = {
"ATOM_PAIR",
@@ -240,9 +169,7 @@ constexpr int kCacheCount = base::size(kAtomsToCache);
} // namespace
-namespace gfx {
-
-x11::Atom GetAtom(const std::string& name) {
+Atom GetAtom(const std::string& name) {
return X11AtomCache::GetInstance()->GetAtom(name);
}
@@ -250,35 +177,40 @@ X11AtomCache* X11AtomCache::GetInstance() {
return base::Singleton<X11AtomCache>::get();
}
-X11AtomCache::X11AtomCache() : connection_(x11::Connection::Get()) {
- for (const auto& predefined_atom : kPredefinedAtoms)
- cached_atoms_[predefined_atom.atom_name] = predefined_atom.atom_value;
+X11AtomCache::X11AtomCache() : connection_(Connection::Get()) {
+ // Clipboard formats are keyed on their format string (eg. "STRING",
+ // "UTF8_STRING", "image/png"). Plumbing through x11::Atoms instead would be
+ // tricky, so set "STRING" here to prevent hitting the DCHECK_GT() in
+ // GetAtom().
+ cached_atoms_["STRING"] = x11::Atom::STRING;
- std::vector<x11::Future<x11::InternAtomReply>> requests;
+ std::vector<Future<InternAtomReply>> requests;
requests.reserve(kCacheCount);
for (const char* name : kAtomsToCache)
requests.push_back(
- connection_->InternAtom(x11::InternAtomRequest{.name = name}));
+ connection_->InternAtom(InternAtomRequest{.name = name}));
// Flush so all requests are sent before waiting on any replies.
connection_->Flush();
for (size_t i = 0; i < kCacheCount; ++i) {
if (auto response = requests[i].Sync())
- cached_atoms_[kAtomsToCache[i]] = static_cast<x11::Atom>(response->atom);
+ cached_atoms_[kAtomsToCache[i]] = static_cast<Atom>(response->atom);
}
}
X11AtomCache::~X11AtomCache() = default;
-x11::Atom X11AtomCache::GetAtom(const std::string& name) const {
+Atom X11AtomCache::GetAtom(const std::string& name) const {
const auto it = cached_atoms_.find(name);
if (it != cached_atoms_.end())
return it->second;
- x11::Atom atom = x11::Atom::None;
+ Atom atom = Atom::None;
if (auto response =
- connection_->InternAtom(x11::InternAtomRequest{.name = name})
- .Sync()) {
- atom = static_cast<x11::Atom>(response->atom);
+ connection_->InternAtom(InternAtomRequest{.name = name}).Sync()) {
+ atom = response->atom;
+ DCHECK_GT(atom, x11::Atom::kLastPredefinedAtom)
+ << " Use x11::Atom::" << name << " instead of x11::GetAtom(\"" << name
+ << "\")";
cached_atoms_.emplace(name, atom);
} else {
static int error_count = 0;
@@ -290,4 +222,4 @@ x11::Atom X11AtomCache::GetAtom(const std::string& name) const {
return atom;
}
-} // namespace gfx
+} // namespace x11
diff --git a/chromium/ui/gfx/x/x11_atom_cache.h b/chromium/ui/gfx/x/x11_atom_cache.h
index 03b8f4a50df..851fe884cc2 100644
--- a/chromium/ui/gfx/x/x11_atom_cache.h
+++ b/chromium/ui/gfx/x/x11_atom_cache.h
@@ -8,8 +8,8 @@
#include <map>
#include <string>
+#include "base/component_export.h"
#include "base/macros.h"
-#include "ui/gfx/gfx_export.h"
#include "ui/gfx/x/xproto.h"
namespace base {
@@ -21,38 +21,38 @@ namespace x11 {
class Connection;
}
-namespace gfx {
+namespace x11 {
// Gets the X atom for default display corresponding to atom_name.
-GFX_EXPORT x11::Atom GetAtom(const std::string& atom_name);
+COMPONENT_EXPORT(X11) Atom GetAtom(const std::string& atom_name);
// Pre-caches all Atoms on first use to minimize roundtrips to the X11
// server. By default, GetAtom() will CHECK() that atoms accessed through
// GetAtom() were passed to the constructor, but this behaviour can be changed
// with allow_uncached_atoms().
-class GFX_EXPORT X11AtomCache {
+class COMPONENT_EXPORT(X11) X11AtomCache {
public:
static X11AtomCache* GetInstance();
private:
- friend x11::Atom GetAtom(const std::string& atom_name);
+ friend Atom GetAtom(const std::string& atom_name);
friend struct base::DefaultSingletonTraits<X11AtomCache>;
X11AtomCache();
~X11AtomCache();
// Returns the pre-interned Atom without having to go to the x server.
- // On failure, x11::None is returned.
- x11::Atom GetAtom(const std::string&) const;
+ // On failure, None is returned.
+ Atom GetAtom(const std::string&) const;
- x11::Connection* connection_;
+ Connection* connection_;
// Using std::map, as it is possible for thousands of atoms to be registered.
- mutable std::map<std::string, x11::Atom> cached_atoms_;
+ mutable std::map<std::string, Atom> cached_atoms_;
DISALLOW_COPY_AND_ASSIGN(X11AtomCache);
};
-} // namespace gfx
+} // namespace x11
#endif // UI_GFX_X_X11_ATOM_CACHE_H_
diff --git a/chromium/ui/gfx/x/x11_path.cc b/chromium/ui/gfx/x/x11_path.cc
index 823b8b617aa..5f101e8c28a 100644
--- a/chromium/ui/gfx/x/x11_path.cc
+++ b/chromium/ui/gfx/x/x11_path.cc
@@ -9,11 +9,11 @@
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRegion.h"
-namespace gfx {
+namespace x11 {
-std::unique_ptr<std::vector<x11::Rectangle>> CreateRegionFromSkRegion(
+std::unique_ptr<std::vector<Rectangle>> CreateRegionFromSkRegion(
const SkRegion& region) {
- auto result = std::make_unique<std::vector<x11::Rectangle>>();
+ auto result = std::make_unique<std::vector<Rectangle>>();
for (SkRegion::Iterator i(region); !i.done(); i.next()) {
result->push_back({
@@ -27,7 +27,7 @@ std::unique_ptr<std::vector<x11::Rectangle>> CreateRegionFromSkRegion(
return result;
}
-std::unique_ptr<std::vector<x11::Rectangle>> CreateRegionFromSkPath(
+std::unique_ptr<std::vector<Rectangle>> CreateRegionFromSkPath(
const SkPath& path) {
SkRegion clip{path.getBounds().roundOut()};
SkRegion region;
@@ -35,4 +35,4 @@ std::unique_ptr<std::vector<x11::Rectangle>> CreateRegionFromSkPath(
return CreateRegionFromSkRegion(region);
}
-} // namespace gfx
+} // namespace x11
diff --git a/chromium/ui/gfx/x/x11_path.h b/chromium/ui/gfx/x/x11_path.h
index 9e5d4be9bae..6a44b2f9438 100644
--- a/chromium/ui/gfx/x/x11_path.h
+++ b/chromium/ui/gfx/x/x11_path.h
@@ -5,24 +5,26 @@
#ifndef UI_GFX_X_X11_PATH_H_
#define UI_GFX_X_X11_PATH_H_
-#include "ui/gfx/gfx_export.h"
+#include "base/component_export.h"
#include "ui/gfx/x/xproto.h"
class SkPath;
class SkRegion;
-namespace gfx {
+namespace x11 {
// Creates a new XRegion given |region|. The caller is responsible for
// destroying the returned region.
-GFX_EXPORT std::unique_ptr<std::vector<x11::Rectangle>>
-CreateRegionFromSkRegion(const SkRegion& region);
+COMPONENT_EXPORT(X11)
+std::unique_ptr<std::vector<Rectangle>> CreateRegionFromSkRegion(
+ const SkRegion& region);
// Creates a new XRegion given |path|. The caller is responsible for destroying
// the returned region.
-GFX_EXPORT std::unique_ptr<std::vector<x11::Rectangle>> CreateRegionFromSkPath(
+COMPONENT_EXPORT(X11)
+std::unique_ptr<std::vector<Rectangle>> CreateRegionFromSkPath(
const SkPath& path);
-} // namespace gfx
+} // namespace x11
#endif // UI_GFX_X_X11_PATH_H_
diff --git a/chromium/ui/events/x/x11_window_event_manager.cc b/chromium/ui/gfx/x/x11_window_event_manager.cc
index c4ee322a963..84adab63431 100644
--- a/chromium/ui/events/x/x11_window_event_manager.cc
+++ b/chromium/ui/gfx/x/x11_window_event_manager.cc
@@ -2,33 +2,32 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/events/x/x11_window_event_manager.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
#include <stddef.h>
#include "base/memory/singleton.h"
+#include "ui/gfx/x/future.h"
-namespace ui {
+namespace x11 {
namespace {
// Asks the X server to set |window|'s event mask to |new_mask|.
-void SetEventMask(x11::Window window, x11::EventMask new_mask) {
- auto* connection = x11::Connection::Get();
+void SetEventMask(Window window, EventMask new_mask) {
+ auto* connection = Connection::Get();
// Window |window| may already be destroyed at this point, so the
// change_attributes request may give a BadWindow error. In this case, just
// ignore the error.
connection
- ->ChangeWindowAttributes(x11::ChangeWindowAttributesRequest{
- .window = window,
- .event_mask = static_cast<x11::EventMask>(new_mask)})
+ ->ChangeWindowAttributes(ChangeWindowAttributesRequest{
+ .window = window, .event_mask = static_cast<EventMask>(new_mask)})
.IgnoreError();
}
} // anonymous namespace
-XScopedEventSelector::XScopedEventSelector(x11::Window window,
- x11::EventMask event_mask)
+XScopedEventSelector::XScopedEventSelector(Window window, EventMask event_mask)
: window_(window),
event_mask_(event_mask),
event_manager_(
@@ -52,14 +51,14 @@ class XWindowEventManager::MultiMask {
~MultiMask() = default;
- void AddMask(x11::EventMask mask) {
+ void AddMask(EventMask mask) {
for (int i = 0; i < kMaskSize; i++) {
if (static_cast<uint32_t>(mask) & (1 << i))
mask_bits_[i]++;
}
}
- void RemoveMask(x11::EventMask mask) {
+ void RemoveMask(EventMask mask) {
for (int i = 0; i < kMaskSize; i++) {
if (static_cast<uint32_t>(mask) & (1 << i)) {
DCHECK(mask_bits_[i]);
@@ -68,11 +67,11 @@ class XWindowEventManager::MultiMask {
}
}
- x11::EventMask ToMask() const {
- x11::EventMask mask = x11::EventMask::NoEvent;
+ EventMask ToMask() const {
+ EventMask mask = EventMask::NoEvent;
for (int i = 0; i < kMaskSize; i++) {
if (mask_bits_[i])
- mask = mask | static_cast<x11::EventMask>(1 << i);
+ mask = mask | static_cast<EventMask>(1 << i);
}
return mask;
}
@@ -90,38 +89,35 @@ XWindowEventManager::XWindowEventManager() = default;
XWindowEventManager::~XWindowEventManager() {
// Clear events still requested by not-yet-deleted XScopedEventSelectors.
for (const auto& mask_pair : mask_map_)
- SetEventMask(mask_pair.first, x11::EventMask::NoEvent);
+ SetEventMask(mask_pair.first, EventMask::NoEvent);
}
-void XWindowEventManager::SelectEvents(x11::Window window,
- x11::EventMask event_mask) {
+void XWindowEventManager::SelectEvents(Window window, EventMask event_mask) {
std::unique_ptr<MultiMask>& mask = mask_map_[window];
if (!mask)
mask = std::make_unique<MultiMask>();
- x11::EventMask old_mask = mask_map_[window]->ToMask();
+ EventMask old_mask = mask_map_[window]->ToMask();
mask->AddMask(event_mask);
AfterMaskChanged(window, old_mask);
}
-void XWindowEventManager::DeselectEvents(x11::Window window,
- x11::EventMask event_mask) {
+void XWindowEventManager::DeselectEvents(Window window, EventMask event_mask) {
DCHECK(mask_map_.find(window) != mask_map_.end());
std::unique_ptr<MultiMask>& mask = mask_map_[window];
- x11::EventMask old_mask = mask->ToMask();
+ EventMask old_mask = mask->ToMask();
mask->RemoveMask(event_mask);
AfterMaskChanged(window, old_mask);
}
-void XWindowEventManager::AfterMaskChanged(x11::Window window,
- x11::EventMask old_mask) {
- x11::EventMask new_mask = mask_map_[window]->ToMask();
+void XWindowEventManager::AfterMaskChanged(Window window, EventMask old_mask) {
+ EventMask new_mask = mask_map_[window]->ToMask();
if (new_mask == old_mask)
return;
SetEventMask(window, new_mask);
- if (new_mask == x11::EventMask::NoEvent)
+ if (new_mask == EventMask::NoEvent)
mask_map_.erase(window);
}
-} // namespace ui
+} // namespace x11
diff --git a/chromium/ui/events/x/x11_window_event_manager.h b/chromium/ui/gfx/x/x11_window_event_manager.h
index 62cf8882b87..7d8db298bd1 100644
--- a/chromium/ui/events/x/x11_window_event_manager.h
+++ b/chromium/ui/gfx/x/x11_window_event_manager.h
@@ -2,15 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_EVENTS_X_X11_WINDOW_EVENT_MANAGER_H_
-#define UI_EVENTS_X_X11_WINDOW_EVENT_MANAGER_H_
+#ifndef UI_GFX_X_X11_WINDOW_EVENT_MANAGER_H_
+#define UI_GFX_X_X11_WINDOW_EVENT_MANAGER_H_
#include <map>
#include "base/component_export.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "ui/events/x/events_x_export.h"
#include "ui/gfx/x/connection.h"
namespace base {
@@ -18,20 +17,20 @@ template <typename T>
struct DefaultSingletonTraits;
}
-namespace ui {
+namespace x11 {
class XWindowEventManager;
// Ensures events in |event_mask| are selected on |window| for the duration of
// this object's lifetime.
-class EVENTS_X_EXPORT XScopedEventSelector {
+class COMPONENT_EXPORT(X11) XScopedEventSelector {
public:
- XScopedEventSelector(x11::Window window, x11::EventMask event_mask);
+ XScopedEventSelector(Window window, EventMask event_mask);
~XScopedEventSelector();
private:
- x11::Window window_;
- x11::EventMask event_mask_;
+ Window window_;
+ EventMask event_mask_;
base::WeakPtr<XWindowEventManager> event_manager_;
DISALLOW_COPY_AND_ASSIGN(XScopedEventSelector);
@@ -52,18 +51,18 @@ class XWindowEventManager {
~XWindowEventManager();
// Guarantees that events in |event_mask| will be reported to Chrome.
- void SelectEvents(x11::Window window, x11::EventMask event_mask);
+ void SelectEvents(Window window, EventMask event_mask);
// Deselects events on |event_mask|. Chrome will stop receiving events for
// any set bit in |event_mask| only if no other client has selected that bit.
- void DeselectEvents(x11::Window window, x11::EventMask event_mask);
+ void DeselectEvents(Window window, EventMask event_mask);
// Helper method called by SelectEvents and DeselectEvents whenever the mask
// corresponding to |window| might have changed. Calls SetEventMask if
// necessary.
- void AfterMaskChanged(x11::Window window, x11::EventMask old_mask);
+ void AfterMaskChanged(Window window, EventMask old_mask);
- std::map<x11::Window, std::unique_ptr<MultiMask>> mask_map_;
+ std::map<Window, std::unique_ptr<MultiMask>> mask_map_;
// This is used to set XScopedEventSelector::event_manager_. If |this| is
// destroyed before any XScopedEventSelector, the |event_manager_| will become
@@ -73,6 +72,6 @@ class XWindowEventManager {
DISALLOW_COPY_AND_ASSIGN(XWindowEventManager);
};
-} // namespace ui
+} // namespace x11
-#endif // UI_EVENTS_X_X11_WINDOW_EVENT_MANAGER_H_
+#endif // UI_GFX_X_X11_WINDOW_EVENT_MANAGER_H_
diff --git a/chromium/ui/gfx/x/xlib.h b/chromium/ui/gfx/x/xlib.h
index 68f4d3ec00e..1c26ffd44da 100644
--- a/chromium/ui/gfx/x/xlib.h
+++ b/chromium/ui/gfx/x/xlib.h
@@ -12,6 +12,8 @@ int XCloseDisplay(struct _XDisplay*);
int XFlush(struct _XDisplay*);
int XSynchronize(struct _XDisplay*, int);
int XSetErrorHandler(int (*)(void*, void*));
+void XFree(void*);
+int XPending(struct _XDisplay*);
}
#endif // UI_GFX_X_XLIB_H_
diff --git a/chromium/ui/gfx/x/xlib_support.cc b/chromium/ui/gfx/x/xlib_support.cc
index fe7846d0e9f..281c318287b 100644
--- a/chromium/ui/gfx/x/xlib_support.cc
+++ b/chromium/ui/gfx/x/xlib_support.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/no_destructor.h"
#include "library_loaders/xlib_loader.h"
+#include "library_loaders/xlib_xcb_loader.h"
namespace x11 {
@@ -24,6 +25,11 @@ XlibLoader* GetXlibLoader() {
return xlib_loader.get();
}
+XlibXcbLoader* GetXlibXcbLoader() {
+ static base::NoDestructor<XlibXcbLoader> xlib_xcb_loader;
+ return xlib_xcb_loader.get();
+}
+
} // namespace
DISABLE_CFI_ICALL
@@ -34,6 +40,9 @@ void InitXlib() {
CHECK(xlib_loader->Load("libX11.so.6"));
+ auto* xlib_xcb_loader = GetXlibXcbLoader();
+ CHECK(xlib_xcb_loader->Load("libX11-xcb.so.1"));
+
CHECK(xlib_loader->XInitThreads());
// The default Xlib error handler calls exit(1), which we don't want. This
@@ -50,6 +59,11 @@ void SetXlibErrorHandler() {
}
DISABLE_CFI_ICALL
+void XlibFree(void* data) {
+ GetXlibLoader()->XFree(data);
+}
+
+DISABLE_CFI_ICALL
XlibDisplay::XlibDisplay(const std::string& address) {
InitXlib();
@@ -59,8 +73,15 @@ XlibDisplay::XlibDisplay(const std::string& address) {
DISABLE_CFI_ICALL
XlibDisplay::~XlibDisplay() {
- if (display_)
- GetXlibLoader()->XCloseDisplay(display_);
+ if (!display_)
+ return;
+
+ auto* loader = GetXlibLoader();
+ // Events are not processed on |display_|, so if any client asks to receive
+ // events, they will just queue up and leak memory. This check makes sure
+ // |display_| never had any pending events before it is closed.
+ CHECK(!loader->XPending(display_));
+ loader->XCloseDisplay(display_);
}
DISABLE_CFI_ICALL
@@ -98,4 +119,9 @@ XlibDisplayWrapper& XlibDisplayWrapper::operator=(XlibDisplayWrapper&& other) {
return *this;
}
+DISABLE_CFI_ICALL
+struct xcb_connection_t* XlibDisplayWrapper::GetXcbConnection() {
+ return GetXlibXcbLoader()->XGetXCBConnection(display_);
+}
+
} // namespace x11
diff --git a/chromium/ui/gfx/x/xlib_support.h b/chromium/ui/gfx/x/xlib_support.h
index 37ea34afcbd..26accef2418 100644
--- a/chromium/ui/gfx/x/xlib_support.h
+++ b/chromium/ui/gfx/x/xlib_support.h
@@ -5,11 +5,13 @@
#ifndef UI_GFX_X_XLIB_SUPPORT_H_
#define UI_GFX_X_XLIB_SUPPORT_H_
+#include <memory>
#include <string>
#include "base/component_export.h"
struct _XDisplay;
+struct xcb_connection_t;
namespace x11 {
@@ -31,6 +33,9 @@ COMPONENT_EXPORT(X11) void InitXlib();
// Sets an async error handler which only logs an error message.
COMPONENT_EXPORT(X11) void SetXlibErrorHandler();
+// Wraps XFree().
+COMPONENT_EXPORT(X11) void XlibFree(void* data);
+
// A scoped Xlib display.
class COMPONENT_EXPORT(X11) XlibDisplay {
public:
@@ -56,6 +61,8 @@ class COMPONENT_EXPORT(X11) XlibDisplayWrapper {
}
operator struct _XDisplay *() { return display_; }
+ struct xcb_connection_t* GetXcbConnection();
+
XlibDisplayWrapper(XlibDisplayWrapper&& other);
XlibDisplayWrapper& operator=(XlibDisplayWrapper&& other);
diff --git a/chromium/ui/gfx/x/xlib_xcb.h b/chromium/ui/gfx/x/xlib_xcb.h
new file mode 100644
index 00000000000..73d56496abd
--- /dev/null
+++ b/chromium/ui/gfx/x/xlib_xcb.h
@@ -0,0 +1,12 @@
+// Copyright 2020 The Chromium 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_X_XLIB_XCB_H_
+#define UI_GFX_X_XLIB_XCB_H_
+
+extern "C" {
+struct xcb_connection_t* XGetXCBConnection(struct _XDisplay*);
+}
+
+#endif // UI_GFX_X_XLIB_XCB_H_
diff --git a/chromium/ui/gfx/x/xproto_internal.cc b/chromium/ui/gfx/x/xproto_internal.cc
index 8a23cfc6da7..e0ffe7ef608 100644
--- a/chromium/ui/gfx/x/xproto_internal.cc
+++ b/chromium/ui/gfx/x/xproto_internal.cc
@@ -8,7 +8,6 @@
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
-
namespace x11 {
MallocedRefCountedMemory::MallocedRefCountedMemory(void* data)
@@ -59,75 +58,4 @@ size_t UnretainedRefCountedMemory::size() const {
UnretainedRefCountedMemory::~UnretainedRefCountedMemory() = default;
-base::Optional<unsigned int> SendRequestImpl(x11::Connection* connection,
- WriteBuffer* buf,
- bool is_void,
- bool reply_has_fds) {
- xcb_protocol_request_t xpr{
- .ext = nullptr,
- .isvoid = is_void,
- };
-
- struct RequestHeader {
- uint8_t major_opcode;
- uint8_t minor_opcode;
- uint16_t length;
- };
-
- struct ExtendedRequestHeader {
- RequestHeader header;
- uint32_t long_length;
- };
- static_assert(sizeof(ExtendedRequestHeader) == 8, "");
-
- auto& first_buffer = buf->GetBuffers()[0];
- DCHECK_GE(first_buffer->size(), sizeof(RequestHeader));
- auto* old_header = reinterpret_cast<RequestHeader*>(
- const_cast<uint8_t*>(first_buffer->data()));
- ExtendedRequestHeader new_header{*old_header, 0};
-
- // Requests are always a multiple of 4 bytes on the wire. Because of this,
- // the length field represents the size in chunks of 4 bytes.
- DCHECK_EQ(buf->offset() % 4, 0UL);
- size_t size32 = buf->offset() / 4;
-
- // XCB requires 2 iovecs for its own internal usage.
- std::vector<struct iovec> io{{nullptr, 0}, {nullptr, 0}};
- if (size32 < connection->setup().maximum_request_length) {
- // Regular request
- old_header->length = size32;
- } else if (size32 < connection->extended_max_request_length()) {
- // BigRequests extension request
- DCHECK_EQ(new_header.header.length, 0U);
- new_header.long_length = size32 + 1;
-
- io.push_back({&new_header, sizeof(ExtendedRequestHeader)});
- first_buffer = base::MakeRefCounted<OffsetRefCountedMemory>(
- first_buffer, sizeof(RequestHeader),
- first_buffer->size() - sizeof(RequestHeader));
- } else {
- LOG(ERROR) << "Cannot send request of length " << buf->offset();
- return base::nullopt;
- }
-
- for (auto& buffer : buf->GetBuffers())
- io.push_back({const_cast<uint8_t*>(buffer->data()), buffer->size()});
- xpr.count = io.size() - 2;
-
- xcb_connection_t* conn = connection->XcbConnection();
- auto flags = XCB_REQUEST_CHECKED | XCB_REQUEST_RAW;
- if (reply_has_fds)
- flags |= XCB_REQUEST_REPLY_FDS;
-
- for (int fd : buf->fds())
- xcb_send_fd(conn, fd);
- unsigned int sequence = xcb_send_request(conn, flags, &io[2], &xpr);
-
- if (xcb_connection_has_error(conn))
- return base::nullopt;
- if (connection->synchronous())
- connection->Sync();
- return sequence;
-}
-
} // namespace x11
diff --git a/chromium/ui/gfx/x/xproto_internal.h b/chromium/ui/gfx/x/xproto_internal.h
index 6ba0604db48..3f9348c0c5b 100644
--- a/chromium/ui/gfx/x/xproto_internal.h
+++ b/chromium/ui/gfx/x/xproto_internal.h
@@ -16,13 +16,13 @@
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
#include "base/optional.h"
-#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
+#include "ui/gfx/x/xproto.h"
#include "ui/gfx/x/xproto_types.h"
namespace x11 {
-template <class Reply>
-class Future;
+class Connection;
template <typename T, typename Enable = void>
struct EnumBase {
@@ -132,22 +132,6 @@ inline void Align(ReadBuffer* buf, size_t align) {
Pad(buf, (align - (buf->offset % align)) % align);
}
-base::Optional<unsigned int> SendRequestImpl(x11::Connection* connection,
- WriteBuffer* buf,
- bool is_void,
- bool reply_has_fds);
-
-template <typename Reply>
-Future<Reply> SendRequest(x11::Connection* connection,
- WriteBuffer* buf,
- bool reply_has_fds,
- const char* request_name) {
- auto sequence = SendRequestImpl(connection, buf, std::is_void<Reply>::value,
- reply_has_fds);
- return {sequence ? connection : nullptr, sequence,
- sequence ? request_name : nullptr};
-}
-
// Helper function for xcbproto popcount. Given an integral type, returns the
// number of 1 bits present.
template <typename T>
diff --git a/chromium/ui/gfx/x/xproto_types.cc b/chromium/ui/gfx/x/xproto_types.cc
index af509848f09..cbc3506c608 100644
--- a/chromium/ui/gfx/x/xproto_types.cc
+++ b/chromium/ui/gfx/x/xproto_types.cc
@@ -7,7 +7,6 @@
#include <xcb/xcbext.h>
#include "base/memory/scoped_refptr.h"
-#include "base/trace_event/trace_event.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/xproto_internal.h"
@@ -79,95 +78,4 @@ void WriteBuffer::AppendCurrentBuffer() {
buffers_.push_back(base::RefCountedBytes::TakeVector(&current_buffer_));
}
-FutureBase::FutureBase(Connection* connection,
- base::Optional<unsigned int> sequence,
- const char* request_name)
- : connection_(connection),
- sequence_(sequence),
- request_name_(request_name) {}
-
-// If a user-defined response-handler is not installed before this object goes
-// out of scope, a default response handler will be installed. The default
-// handler throws away the reply and prints the error if there is one.
-FutureBase::~FutureBase() {
- if (!sequence_)
- return;
-
- OnResponseImpl(base::BindOnce(
- [](Connection* connection, const char* request_name,
- Connection::ErrorHandler error_handler, RawReply raw_reply,
- RawError raw_error) {
- if (!raw_error)
- return;
-
- auto error = connection->ParseError(raw_error);
- error_handler.Run(error.get(), request_name);
- },
- connection_, request_name_, connection_->error_handler_));
-}
-
-FutureBase::FutureBase(FutureBase&& future)
- : connection_(future.connection_),
- sequence_(future.sequence_),
- request_name_(future.request_name_) {
- future.Reset();
-}
-
-FutureBase& FutureBase::operator=(FutureBase&& future) {
- connection_ = future.connection_;
- sequence_ = future.sequence_;
- request_name_ = future.request_name_;
- future.Reset();
- return *this;
-}
-
-void FutureBase::SyncImpl(RawError* raw_error, RawReply* raw_reply) {
- if (!sequence_)
- return;
- xcb_generic_error_t* error = nullptr;
- void* reply = nullptr;
- if (!xcb_poll_for_reply(connection_->XcbConnection(), *sequence_, &reply,
- &error)) {
- TRACE_EVENT1("ui", "xcb_wait_for_reply", "request", request_name_);
- reply =
- xcb_wait_for_reply(connection_->XcbConnection(), *sequence_, &error);
- }
- if (reply)
- *raw_reply = base::MakeRefCounted<MallocedRefCountedMemory>(reply);
- if (error)
- *raw_error = base::MakeRefCounted<MallocedRefCountedMemory>(error);
- sequence_ = base::nullopt;
-}
-
-void FutureBase::SyncImpl(RawError* raw_error) {
- if (!sequence_)
- return;
- if (xcb_generic_error_t* error =
- xcb_request_check(connection_->XcbConnection(), {*sequence_})) {
- *raw_error = base::MakeRefCounted<MallocedRefCountedMemory>(error);
- }
- sequence_ = base::nullopt;
-}
-
-void FutureBase::OnResponseImpl(ResponseCallback callback) {
- if (!sequence_)
- return;
- connection_->AddRequest(*sequence_, std::move(callback));
- sequence_ = base::nullopt;
-}
-
-// static
-std::unique_ptr<Error> FutureBase::ParseErrorImpl(x11::Connection* connection,
- RawError raw_error) {
- if (!raw_error)
- return nullptr;
- return connection->ParseError(raw_error);
-}
-
-void FutureBase::Reset() {
- connection_ = nullptr;
- sequence_ = base::nullopt;
- request_name_ = nullptr;
-}
-
} // namespace x11
diff --git a/chromium/ui/gfx/x/xproto_types.h b/chromium/ui/gfx/x/xproto_types.h
index e38c83f561d..f591363f241 100644
--- a/chromium/ui/gfx/x/xproto_types.h
+++ b/chromium/ui/gfx/x/xproto_types.h
@@ -11,16 +11,14 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/component_export.h"
-#include "base/files/scoped_file.h"
#include "base/memory/free_deleter.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
-#include "ui/gfx/x/error.h"
namespace x11 {
-class Connection;
+class Error;
constexpr uint8_t kSendEventMask = 0x80;
@@ -111,18 +109,15 @@ void ReadEvent(T* event, ReadBuffer* buf);
template <typename Reply>
struct Response {
+ Response(std::unique_ptr<Reply> reply, std::unique_ptr<Error> error)
+ : reply(std::move(reply)), error(std::move(error)) {}
+
operator bool() const { return reply.get(); }
const Reply* operator->() const { return reply.get(); }
Reply* operator->() { return reply.get(); }
std::unique_ptr<Reply> reply;
std::unique_ptr<Error> error;
-
- private:
- friend class Future<Reply>;
-
- Response(std::unique_ptr<Reply> reply, std::unique_ptr<Error> error)
- : reply(std::move(reply)), error(std::move(error)) {}
};
template <>
@@ -135,131 +130,6 @@ struct Response<void> {
explicit Response(std::unique_ptr<Error> error) : error(std::move(error)) {}
};
-class COMPONENT_EXPORT(X11) FutureBase {
- public:
- using RawReply = scoped_refptr<base::RefCountedMemory>;
- using RawError = scoped_refptr<base::RefCountedMemory>;
- using ResponseCallback =
- base::OnceCallback<void(RawReply reply, RawError error)>;
-
- FutureBase(const FutureBase&) = delete;
- FutureBase& operator=(const FutureBase&) = delete;
-
- protected:
- FutureBase(Connection* connection,
- base::Optional<unsigned int> sequence,
- const char* request_name);
- ~FutureBase();
-
- FutureBase(FutureBase&& future);
- FutureBase& operator=(FutureBase&& future);
-
- void SyncImpl(RawError* raw_error, RawReply* raw_reply);
- void SyncImpl(RawError* raw_error);
-
- void OnResponseImpl(ResponseCallback callback);
-
- x11::Connection* connection() { return connection_; }
-
- static std::unique_ptr<Error> ParseErrorImpl(x11::Connection* connection,
- RawError raw_error);
-
- private:
- void Reset();
-
- Connection* connection_ = nullptr;
- base::Optional<unsigned int> sequence_;
- const char* request_name_ = nullptr;
-};
-
-// An x11::Future wraps an asynchronous response from the X11 server. The
-// response may be waited-for with Sync(), or asynchronously handled by
-// installing a response handler using OnResponse().
-template <typename Reply>
-class Future : public FutureBase {
- public:
- using Callback = base::OnceCallback<void(Response<Reply> response)>;
-
- Future() : FutureBase(nullptr, base::nullopt, nullptr) {}
-
- // Blocks until we receive the response from the server. Returns the response.
- Response<Reply> Sync() {
- RawError raw_error;
- RawReply raw_reply;
- SyncImpl(&raw_error, &raw_reply);
-
- std::unique_ptr<Reply> reply;
- if (raw_reply) {
- auto buf = ReadBuffer(raw_reply);
- reply = detail::ReadReply<Reply>(&buf);
- }
-
- std::unique_ptr<Error> error = ParseErrorImpl(connection(), raw_error);
-
- return {std::move(reply), std::move(error)};
- }
-
- // Installs |callback| to be run when the response is received.
- void OnResponse(Callback callback) {
- // This intermediate callback handles the conversion from |raw_reply| to a
- // real Reply object before feeding the result to |callback|. This means
- // |callback| must be bound as the first argument of the intermediate
- // function.
- auto wrapper = [](x11::Connection* connection, Callback callback,
- RawReply raw_reply, RawError raw_error) {
- std::unique_ptr<Reply> reply;
- if (raw_reply) {
- ReadBuffer buf(raw_reply);
- reply = detail::ReadReply<Reply>(&buf);
- }
- std::unique_ptr<Error> error = ParseErrorImpl(connection, raw_error);
- std::move(callback).Run({std::move(reply), std::move(error)});
- };
- OnResponseImpl(base::BindOnce(wrapper, connection(), std::move(callback)));
- }
-
- void IgnoreError() {
- OnResponse(base::BindOnce([](Response<Reply>) {}));
- }
-
- private:
- template <typename R>
- friend Future<R> SendRequest(Connection*, WriteBuffer*, bool, const char*);
-
- Future(Connection* connection,
- base::Optional<unsigned int> sequence,
- const char* request_name)
- : FutureBase(connection, sequence, request_name) {}
-};
-
-// Sync() specialization for requests that don't generate replies. The returned
-// response will only contain an error if there was one.
-template <>
-inline Response<void> Future<void>::Sync() {
- RawError raw_error;
- SyncImpl(&raw_error);
- return Response<void>{ParseErrorImpl(connection(), raw_error)};
-}
-
-// OnResponse() specialization for requests that don't generate replies. The
-// response argument to |callback| will only contain an error if there was one.
-template <>
-inline void Future<void>::OnResponse(Callback callback) {
- // See Future<Reply>::OnResponse() for an explanation of why
- // this wrapper is necessary.
- auto wrapper = [](x11::Connection* connection, Callback callback,
- RawReply reply, RawError error) {
- DCHECK(!reply);
- std::move(callback).Run(Response<void>{ParseErrorImpl(connection, error)});
- };
- OnResponseImpl(base::BindOnce(wrapper, connection(), std::move(callback)));
-}
-
-template <>
-inline void Future<void>::IgnoreError() {
- OnResponse(base::BindOnce([](Response<void>) {}));
-}
-
} // namespace x11
#endif // UI_GFX_X_XPROTO_TYPES_H_
diff --git a/chromium/ui/gfx/x/xproto_util.cc b/chromium/ui/gfx/x/xproto_util.cc
new file mode 100644
index 00000000000..6662b128ae6
--- /dev/null
+++ b/chromium/ui/gfx/x/xproto_util.cc
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium 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/x/xproto_util.h"
+
+namespace x11 {
+
+void DeleteProperty(x11::Window window, x11::Atom name) {
+ x11::Connection::Get()->DeleteProperty({
+ .window = static_cast<x11::Window>(window),
+ .property = name,
+ });
+}
+
+void SetStringProperty(Window window,
+ Atom property,
+ Atom type,
+ const std::string& value,
+ Connection* connection) {
+ std::vector<char> str(value.begin(), value.end());
+ SetArrayProperty(window, property, type, str, connection);
+}
+
+Window CreateDummyWindow(const std::string& name, Connection* connection) {
+ auto window = connection->GenerateId<Window>();
+ connection->CreateWindow(CreateWindowRequest{
+ .wid = window,
+ .parent = connection->default_root(),
+ .x = -100,
+ .y = -100,
+ .width = 10,
+ .height = 10,
+ .c_class = WindowClass::InputOnly,
+ .override_redirect = Bool32(true),
+ });
+ if (!name.empty())
+ SetStringProperty(window, Atom::WM_NAME, Atom::STRING, name);
+ return window;
+}
+
+} // namespace x11
diff --git a/chromium/ui/gfx/x/xproto_util.h b/chromium/ui/gfx/x/xproto_util.h
index 1b3b00578db..fc140e5fb8a 100644
--- a/chromium/ui/gfx/x/xproto_util.h
+++ b/chromium/ui/gfx/x/xproto_util.h
@@ -9,30 +9,121 @@
#include "base/component_export.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/xproto.h"
#include "ui/gfx/x/xproto_types.h"
namespace x11 {
template <typename T>
-x11::Future<void> SendEvent(
- const T& event,
- x11::Window target,
- x11::EventMask mask,
- x11::Connection* connection = x11::Connection::Get()) {
- static_assert(T::type_id > 0, "T must be an x11::*Event type");
- auto write_buffer = x11::Write(event);
+Future<void> SendEvent(const T& event,
+ Window target,
+ EventMask mask,
+ Connection* connection = Connection::Get()) {
+ static_assert(T::type_id > 0, "T must be an *Event type");
+ auto write_buffer = Write(event);
DCHECK_EQ(write_buffer.GetBuffers().size(), 1ul);
auto& first_buffer = write_buffer.GetBuffers()[0];
DCHECK_LE(first_buffer->size(), 32ul);
std::vector<uint8_t> event_bytes(32);
memcpy(event_bytes.data(), first_buffer->data(), first_buffer->size());
- x11::SendEventRequest send_event{false, target, mask};
+ SendEventRequest send_event{false, target, mask};
std::copy(event_bytes.begin(), event_bytes.end(), send_event.event.begin());
return connection->SendEvent(send_event);
}
+template <typename T>
+bool GetArrayProperty(Window window,
+ Atom name,
+ std::vector<T>* value,
+ Atom* out_type = nullptr,
+ size_t amount = 0,
+ Connection* connection = Connection::Get()) {
+ static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "");
+
+ size_t bytes = amount * sizeof(T);
+ // The length field specifies the maximum amount of data we would like the
+ // server to give us. It's specified in units of 4 bytes, so divide by 4.
+ // Add 3 before division to round up.
+ size_t length = (bytes + 3) / 4;
+ using lentype = decltype(GetPropertyRequest::long_length);
+ auto response =
+ connection
+ ->GetProperty(GetPropertyRequest{
+ .window = static_cast<Window>(window),
+ .property = name,
+ .long_length =
+ amount ? length : std::numeric_limits<lentype>::max()})
+ .Sync();
+ if (!response || response->format != CHAR_BIT * sizeof(T))
+ return false;
+
+ DCHECK_EQ(response->format / CHAR_BIT * response->value_len,
+ response->value->size());
+ value->resize(response->value_len);
+ memcpy(value->data(), response->value->data(), response->value->size());
+ if (out_type)
+ *out_type = response->type;
+ return true;
+}
+
+template <typename T>
+bool GetProperty(Window window,
+ const Atom name,
+ T* value,
+ Connection* connection = Connection::Get()) {
+ std::vector<T> values;
+ if (!GetArrayProperty(window, name, &values, nullptr, 1, connection) ||
+ values.empty()) {
+ return false;
+ }
+ *value = values[0];
+ return true;
+}
+
+template <typename T>
+Future<void> SetArrayProperty(Window window,
+ Atom name,
+ Atom type,
+ const std::vector<T>& values,
+ Connection* connection = Connection::Get()) {
+ static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "");
+ std::vector<uint8_t> data(sizeof(T) * values.size());
+ memcpy(data.data(), values.data(), sizeof(T) * values.size());
+ return connection->ChangeProperty(
+ ChangePropertyRequest{.window = static_cast<Window>(window),
+ .property = name,
+ .type = type,
+ .format = CHAR_BIT * sizeof(T),
+ .data_len = values.size(),
+ .data = base::RefCountedBytes::TakeVector(&data)});
+}
+
+template <typename T>
+Future<void> SetProperty(Window window,
+ Atom name,
+ Atom type,
+ const T& value,
+ Connection* connection = Connection::Get()) {
+ return SetArrayProperty(window, name, type, std::vector<T>{value},
+ connection);
+}
+
+COMPONENT_EXPORT(X11)
+void DeleteProperty(x11::Window window, x11::Atom name);
+
+COMPONENT_EXPORT(X11)
+void SetStringProperty(Window window,
+ Atom property,
+ Atom type,
+ const std::string& value,
+ Connection* connection = Connection::Get());
+
+COMPONENT_EXPORT(X11)
+Window CreateDummyWindow(const std::string& name = std::string(),
+ Connection* connection = Connection::Get());
+
} // namespace x11
#endif // UI_GFX_X_XPROTO_UTIL_H_
diff --git a/chromium/ui/gl/BUILD.gn b/chromium/ui/gl/BUILD.gn
index a3bc53748ce..b815fda06ed 100644
--- a/chromium/ui/gl/BUILD.gn
+++ b/chromium/ui/gl/BUILD.gn
@@ -5,6 +5,7 @@
import("//build/buildflag_header.gni")
import("//build/config/chrome_build.gni")
import("//build/config/chromecast_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/linux/pkg_config.gni")
import("//build/config/ozone.gni")
import("//build/config/ui.gni")
@@ -30,6 +31,7 @@ buildflag_header("buildflags") {
"ENABLE_SWIFTSHADER=$enable_swiftshader",
"USE_DAWN=$use_dawn",
"USE_STATIC_ANGLE=$use_static_angle",
+ "USE_OPENGL_APITRACE=$enable_opengl_apitrace",
]
}
@@ -165,6 +167,7 @@ component("gl") {
deps = [
":buildflags",
"//base/third_party/dynamic_annotations",
+ "//build:chromeos_buildflags",
# ANGLE includes are used cross-platform.
"//third_party/angle:includes",
@@ -510,6 +513,14 @@ static_library("test_support") {
if (use_ozone) {
deps += [ "//ui/ozone" ]
}
+
+ # If the run-time search path isn't set properly when we use ANGLE with its
+ # Vulkan backend, it may end up finding the system libvulkan.so rather than
+ # the one built in the output directory
+ if ((is_linux || is_chromeos) && !is_component_build) {
+ all_dependent_configs =
+ [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
+ }
}
source_set("run_all_unittests") {
@@ -579,7 +590,7 @@ test("gl_unittests") {
sources += [ "gl_image_ahardwarebuffer_unittest.cc" ]
}
- if (is_linux) {
+ if (is_linux || is_chromeos_lacros) {
sources += [ "gl_image_native_pixmap_unittest.cc" ]
}
diff --git a/chromium/ui/gl/DIR_METADATA b/chromium/ui/gl/DIR_METADATA
new file mode 100644
index 00000000000..e353adfc5e6
--- /dev/null
+++ b/chromium/ui/gl/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+ component: "Internals>GPU>Internals"
+}
+team_email: "graphics-dev@chromium.org"
diff --git a/chromium/ui/gl/OWNERS b/chromium/ui/gl/OWNERS
index cb9ad84e7fd..1f6eeb27894 100644
--- a/chromium/ui/gl/OWNERS
+++ b/chromium/ui/gl/OWNERS
@@ -6,7 +6,7 @@ per-file *gl_image*=dcastagna@chromium.org
per-file *_ozone*=alexst@chromium.org
per-file *_ozone*=dnicoara@chromium.org
per-file *_ozone*=spang@chromium.org
-per-file *surface_control*=khushalsagar@chromium.org
+per-file *surface_control*=vasilyt@chromium.org
-# COMPONENT: Internals>GPU>Internals
-# TEAM: graphics-dev@chromium.org
+# For Windows Direct Composition and Swap Chain
+magchen@chromium.org
diff --git a/chromium/ui/gl/angle_platform_impl.cc b/chromium/ui/gl/angle_platform_impl.cc
index 980a7ba99e9..5401759f349 100644
--- a/chromium/ui/gl/angle_platform_impl.cc
+++ b/chromium/ui/gl/angle_platform_impl.cc
@@ -155,9 +155,9 @@ bool InitializePlatform(EGLDisplay display) {
if (!angle_get_platform(static_cast<EGLDisplayType>(display),
g_PlatformMethodNames, g_NumPlatformMethods, nullptr,
&platformMethods))
- platformMethods->currentTime = ANGLEPlatformImpl_currentTime;
- platformMethods->addTraceEvent = ANGLEPlatformImpl_addTraceEvent;
+ return false;
platformMethods->currentTime = ANGLEPlatformImpl_currentTime;
+ platformMethods->addTraceEvent = ANGLEPlatformImpl_addTraceEvent;
platformMethods->getTraceCategoryEnabledFlag =
ANGLEPlatformImpl_getTraceCategoryEnabledFlag;
platformMethods->histogramBoolean = ANGLEPlatformImpl_histogramBoolean;
diff --git a/chromium/ui/gl/dc_layer_tree.cc b/chromium/ui/gl/dc_layer_tree.cc
index 139613b65d1..760dc2ffb55 100644
--- a/chromium/ui/gl/dc_layer_tree.cc
+++ b/chromium/ui/gl/dc_layer_tree.cc
@@ -12,19 +12,51 @@
#include "ui/gl/direct_composition_surface_win.h"
#include "ui/gl/swap_chain_presenter.h"
+// Required for SFINAE to check if these Win10 types exist.
+struct IDCompositionInkTrailDevice;
+
namespace gl {
namespace {
bool SizeContains(const gfx::Size& a, const gfx::Size& b) {
return gfx::Rect(a).Contains(gfx::Rect(b));
}
+
+// SFINAE used to enable building before Delegated Ink types are available in
+// the Win10 SDK.
+// TODO(1171374) : Remove this when the types are available in the Win10 SDK.
+template <typename InkTrailDevice, typename = void>
+struct DelegatedInk {
+ public:
+ static bool IsSupported(
+ const Microsoft::WRL::ComPtr<IDCompositionDevice2>& dcomp_device) {
+ return false;
+ }
+};
+
+template <typename InkTrailDevice>
+struct DelegatedInk<InkTrailDevice, decltype(typeid(InkTrailDevice), void())> {
+ public:
+ static bool IsSupported(
+ const Microsoft::WRL::ComPtr<IDCompositionDevice2>& dcomp_device) {
+ Microsoft::WRL::ComPtr<InkTrailDevice> ink_trail_device;
+ HRESULT hr = dcomp_device.As(&ink_trail_device);
+ return hr == S_OK;
+ }
+};
+
} // namespace
+VideoProcessorWrapper::VideoProcessorWrapper() = default;
+VideoProcessorWrapper::~VideoProcessorWrapper() = default;
+VideoProcessorWrapper::VideoProcessorWrapper(VideoProcessorWrapper&& other) =
+ default;
+VideoProcessorWrapper& VideoProcessorWrapper::operator=(
+ VideoProcessorWrapper&& other) = default;
+
DCLayerTree::DCLayerTree(bool disable_nv12_dynamic_textures,
- bool disable_vp_scaling,
- bool reset_vp_when_colorspace_changes)
+ bool disable_vp_scaling)
: disable_nv12_dynamic_textures_(disable_nv12_dynamic_textures),
- disable_vp_scaling_(disable_vp_scaling),
- reset_vp_when_colorspace_changes_(reset_vp_when_colorspace_changes) {}
+ disable_vp_scaling_(disable_vp_scaling) {}
DCLayerTree::~DCLayerTree() = default;
@@ -65,49 +97,42 @@ bool DCLayerTree::Initialize(
return true;
}
-bool DCLayerTree::InitializeVideoProcessor(
+VideoProcessorWrapper* DCLayerTree::InitializeVideoProcessor(
const gfx::Size& input_size,
const gfx::Size& output_size,
- const gfx::ColorSpace& input_color_space,
- const gfx::ColorSpace& output_color_space,
- Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain,
- bool is_yuv_swapchain) {
- if (!video_device_) {
+ bool is_hdr_output) {
+ VideoProcessorWrapper& video_processor_wrapper =
+ GetOrCreateVideoProcessor(is_hdr_output);
+
+ if (!video_processor_wrapper.video_device) {
// This can fail if the D3D device is "Microsoft Basic Display Adapter".
- if (FAILED(d3d11_device_.As(&video_device_))) {
+ if (FAILED(d3d11_device_.As(&video_processor_wrapper.video_device))) {
DLOG(ERROR) << "Failed to retrieve video device from D3D11 device";
DCHECK(false);
DirectCompositionSurfaceWin::DisableOverlays();
- return false;
+ return nullptr;
}
- DCHECK(video_device_);
+ DCHECK(video_processor_wrapper.video_device);
Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
d3d11_device_->GetImmediateContext(&context);
DCHECK(context);
- context.As(&video_context_);
- DCHECK(video_context_);
+ context.As(&video_processor_wrapper.video_context);
+ DCHECK(video_processor_wrapper.video_context);
}
- bool colorspace_changed = !(input_color_space == video_input_color_space_ &&
- output_color_space == video_output_color_space_ &&
- is_yuv_video_output_ == is_yuv_swapchain);
- if (video_processor_ && SizeContains(video_input_size_, input_size) &&
- SizeContains(video_output_size_, output_size) &&
- !(colorspace_changed && reset_vp_when_colorspace_changes_)) {
- if (colorspace_changed) {
- SetColorSpaceForVideoProcessor(input_color_space, output_color_space,
- std::move(swap_chain), is_yuv_swapchain);
- }
- return true;
- }
+ if (video_processor_wrapper.video_processor &&
+ SizeContains(video_processor_wrapper.video_input_size, input_size) &&
+ SizeContains(video_processor_wrapper.video_output_size, output_size))
+ return &video_processor_wrapper;
+
TRACE_EVENT2("gpu", "DCLayerTree::InitializeVideoProcessor", "input_size",
input_size.ToString(), "output_size", output_size.ToString());
- video_input_size_ = input_size;
- video_output_size_ = output_size;
+ video_processor_wrapper.video_input_size = input_size;
+ video_processor_wrapper.video_output_size = output_size;
- video_processor_.Reset();
- video_processor_enumerator_.Reset();
+ video_processor_wrapper.video_processor.Reset();
+ video_processor_wrapper.video_processor_enumerator.Reset();
D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc = {};
desc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
desc.InputFrameRate.Numerator = 60;
@@ -119,8 +144,9 @@ bool DCLayerTree::InitializeVideoProcessor(
desc.OutputWidth = output_size.width();
desc.OutputHeight = output_size.height();
desc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL;
- HRESULT hr = video_device_->CreateVideoProcessorEnumerator(
- &desc, &video_processor_enumerator_);
+ HRESULT hr =
+ video_processor_wrapper.video_device->CreateVideoProcessorEnumerator(
+ &desc, &video_processor_wrapper.video_processor_enumerator);
base::UmaHistogramSparse(
"GPU.DirectComposition.CreateVideoProcessorEnumerator", hr);
if (FAILED(hr)) {
@@ -129,11 +155,11 @@ bool DCLayerTree::InitializeVideoProcessor(
// It might fail again next time. Disable overlay support so
// overlay processor will stop sending down overlay frames.
DirectCompositionSurfaceWin::DisableOverlays();
- return false;
+ return nullptr;
}
-
- hr = video_device_->CreateVideoProcessor(video_processor_enumerator_.Get(), 0,
- &video_processor_);
+ hr = video_processor_wrapper.video_device->CreateVideoProcessor(
+ video_processor_wrapper.video_processor_enumerator.Get(), 0,
+ &video_processor_wrapper.video_processor);
base::UmaHistogramSparse(
"GPU.DirectComposition.VideoDeviceCreateVideoProcessor", hr);
if (FAILED(hr)) {
@@ -142,55 +168,21 @@ bool DCLayerTree::InitializeVideoProcessor(
// It might fail again next time. Disable overlay support so
// overlay processor will stop sending down overlay frames.
DirectCompositionSurfaceWin::DisableOverlays();
- return false;
+ return nullptr;
}
// Auto stream processing (the default) can hurt power consumption.
- video_context_->VideoProcessorSetStreamAutoProcessingMode(
- video_processor_.Get(), 0, FALSE);
- SetColorSpaceForVideoProcessor(input_color_space, output_color_space,
- std::move(swap_chain), is_yuv_swapchain);
- return true;
+ video_processor_wrapper.video_context
+ ->VideoProcessorSetStreamAutoProcessingMode(
+ video_processor_wrapper.video_processor.Get(), 0, FALSE);
+ return &video_processor_wrapper;
}
-void DCLayerTree::SetColorSpaceForVideoProcessor(
- const gfx::ColorSpace& input_color_space,
- const gfx::ColorSpace& output_color_space,
- Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain,
- bool is_yuv_swapchain) {
- Microsoft::WRL::ComPtr<IDXGISwapChain3> swap_chain3;
- Microsoft::WRL::ComPtr<ID3D11VideoContext1> context1;
- if (SUCCEEDED(swap_chain.As(&swap_chain3)) &&
- SUCCEEDED(video_context_.As(&context1))) {
- DCHECK(swap_chain3);
- DCHECK(context1);
- // Set input color space.
- context1->VideoProcessorSetStreamColorSpace1(
- video_processor_.Get(), 0,
- gfx::ColorSpaceWin::GetDXGIColorSpace(input_color_space));
- // Set output color space.
- DXGI_COLOR_SPACE_TYPE output_dxgi_color_space =
- gfx::ColorSpaceWin::GetDXGIColorSpace(output_color_space,
- /*force_yuv=*/is_yuv_swapchain);
-
- if (SUCCEEDED(swap_chain3->SetColorSpace1(output_dxgi_color_space))) {
- context1->VideoProcessorSetOutputColorSpace1(video_processor_.Get(),
- output_dxgi_color_space);
- }
- } else {
- // This can't handle as many different types of color spaces, so use it
- // only if ID3D11VideoContext1 isn't available.
- D3D11_VIDEO_PROCESSOR_COLOR_SPACE src_d3d11_color_space =
- gfx::ColorSpaceWin::GetD3D11ColorSpace(input_color_space);
- video_context_->VideoProcessorSetStreamColorSpace(video_processor_.Get(), 0,
- &src_d3d11_color_space);
- D3D11_VIDEO_PROCESSOR_COLOR_SPACE output_d3d11_color_space =
- gfx::ColorSpaceWin::GetD3D11ColorSpace(output_color_space);
- video_context_->VideoProcessorSetOutputColorSpace(
- video_processor_.Get(), &output_d3d11_color_space);
- }
- video_input_color_space_ = input_color_space;
- video_output_color_space_ = output_color_space;
- is_yuv_video_output_ = is_yuv_swapchain;
+VideoProcessorWrapper& DCLayerTree::GetOrCreateVideoProcessor(bool is_hdr) {
+ VideoProcessorType video_processor_type =
+ is_hdr ? VideoProcessorType::kHDR : VideoProcessorType::kSDR;
+ return video_processor_map_
+ .try_emplace(video_processor_type, VideoProcessorWrapper())
+ .first->second;
}
Microsoft::WRL::ComPtr<IDXGISwapChain1>
@@ -335,4 +327,8 @@ void DCLayerTree::SetFrameRate(float frame_rate) {
video_swap_chains_[ii]->SetFrameRate(frame_rate);
}
+bool DCLayerTree::SupportsDelegatedInk() {
+ return DelegatedInk<IDCompositionInkTrailDevice>::IsSupported(dcomp_device_);
+}
+
} // namespace gl
diff --git a/chromium/ui/gl/dc_layer_tree.h b/chromium/ui/gl/dc_layer_tree.h
index 90109a3efbb..ec7d925d928 100644
--- a/chromium/ui/gl/dc_layer_tree.h
+++ b/chromium/ui/gl/dc_layer_tree.h
@@ -12,6 +12,7 @@
#include <memory>
+#include "base/containers/flat_map.h"
#include "ui/gfx/color_space_win.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gl/dc_renderer_layer_params.h"
@@ -22,15 +23,41 @@ namespace gl {
class DirectCompositionChildSurfaceWin;
class SwapChainPresenter;
+enum class VideoProcessorType { kSDR, kHDR };
+
+// Cache video processor and its size.
+struct VideoProcessorWrapper {
+ VideoProcessorWrapper();
+ ~VideoProcessorWrapper();
+ VideoProcessorWrapper(VideoProcessorWrapper&& other);
+ VideoProcessorWrapper& operator=(VideoProcessorWrapper&& other);
+ VideoProcessorWrapper(const VideoProcessorWrapper&) = delete;
+ VideoProcessorWrapper& operator=(VideoProcessorWrapper& other) = delete;
+
+ // Input and output size of video processor .
+ gfx::Size video_input_size;
+ gfx::Size video_output_size;
+
+ // The video processor is cached so SwapChains don't have to recreate it
+ // whenever they're created.
+ Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device;
+ Microsoft::WRL::ComPtr<ID3D11VideoContext> video_context;
+ Microsoft::WRL::ComPtr<ID3D11VideoProcessor> video_processor;
+ Microsoft::WRL::ComPtr<ID3D11VideoProcessorEnumerator>
+ video_processor_enumerator;
+};
+
// DCLayerTree manages a tree of direct composition visuals, and associated
// swap chains for given overlay layers. It maintains a list of pending layers
// submitted using ScheduleDCLayer() that are presented and committed in
// CommitAndClearPendingOverlays().
class DCLayerTree {
public:
- DCLayerTree(bool disable_nv12_dynamic_textures,
- bool disable_vp_scaling,
- bool reset_vp_when_colorspace_changes);
+ using VideoProcessorMap =
+ base::flat_map<VideoProcessorType, VideoProcessorWrapper>;
+
+ DCLayerTree(bool disable_nv12_dynamic_textures, bool disable_vp_scaling);
+
~DCLayerTree();
// Returns true on success.
@@ -50,13 +77,9 @@ class DCLayerTree {
// at least given input and output size. The video processor is shared across
// layers so the same one can be reused if it's large enough. Returns true on
// success.
- bool InitializeVideoProcessor(
- const gfx::Size& input_size,
- const gfx::Size& output_size,
- const gfx::ColorSpace& input_color_space,
- const gfx::ColorSpace& output_color_space,
- Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain,
- bool is_yuv_swapchain);
+ VideoProcessorWrapper* InitializeVideoProcessor(const gfx::Size& input_size,
+ const gfx::Size& output_size,
+ bool is_hdr_output);
void SetNeedsRebuildVisualTree() { needs_rebuild_visual_tree_ = true; }
@@ -66,22 +89,7 @@ class DCLayerTree {
bool disable_vp_scaling() const { return disable_vp_scaling_; }
- const Microsoft::WRL::ComPtr<ID3D11VideoDevice>& video_device() const {
- return video_device_;
- }
-
- const Microsoft::WRL::ComPtr<ID3D11VideoContext>& video_context() const {
- return video_context_;
- }
-
- const Microsoft::WRL::ComPtr<ID3D11VideoProcessor>& video_processor() const {
- return video_processor_;
- }
-
- const Microsoft::WRL::ComPtr<ID3D11VideoProcessorEnumerator>&
- video_processor_enumerator() const {
- return video_processor_enumerator_;
- }
+ VideoProcessorWrapper& GetOrCreateVideoProcessor(bool is_hdr);
Microsoft::WRL::ComPtr<IDXGISwapChain1> GetLayerSwapChainForTesting(
size_t index) const;
@@ -99,38 +107,24 @@ class DCLayerTree {
HWND window() const { return window_; }
- private:
- void SetColorSpaceForVideoProcessor(
- const gfx::ColorSpace& input_color_space,
- const gfx::ColorSpace& output_color_space,
- Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain,
- bool is_yuv_swapchain);
+ bool SupportsDelegatedInk();
+ private:
const bool disable_nv12_dynamic_textures_;
const bool disable_vp_scaling_;
- const bool reset_vp_when_colorspace_changes_;
HWND window_;
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device_;
Microsoft::WRL::ComPtr<IDCompositionTarget> dcomp_target_;
- // The video processor is cached so SwapChains don't have to recreate it
- // whenever they're created.
- Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device_;
- Microsoft::WRL::ComPtr<ID3D11VideoContext> video_context_;
- Microsoft::WRL::ComPtr<ID3D11VideoProcessor> video_processor_;
- Microsoft::WRL::ComPtr<ID3D11VideoProcessorEnumerator>
- video_processor_enumerator_;
-
- // Current video processor input and output size.
- gfx::Size video_input_size_;
- gfx::Size video_output_size_;
+ // Store video processor for SDR/HDR mode separately, which could avoid
+ // problem in (http://crbug.com/1121061).
+ VideoProcessorMap video_processor_map_;
// Current video processor input and output colorspace.
gfx::ColorSpace video_input_color_space_;
gfx::ColorSpace video_output_color_space_;
- bool is_yuv_video_output_ = false;
// Set to true if a direct composition visual tree needs rebuild.
bool needs_rebuild_visual_tree_ = false;
diff --git a/chromium/ui/gl/direct_composition_child_surface_win.cc b/chromium/ui/gl/direct_composition_child_surface_win.cc
index e53dea9f034..d8380cd7360 100644
--- a/chromium/ui/gl/direct_composition_child_surface_win.cc
+++ b/chromium/ui/gl/direct_composition_child_surface_win.cc
@@ -23,6 +23,7 @@
#include "ui/gl/direct_composition_surface_win.h"
#include "ui/gl/egl_util.h"
#include "ui/gl/gl_angle_util_win.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/gl_switches.h"
diff --git a/chromium/ui/gl/direct_composition_surface_win.cc b/chromium/ui/gl/direct_composition_surface_win.cc
index 2d6e985dda7..cbc5c013068 100644
--- a/chromium/ui/gl/direct_composition_surface_win.cc
+++ b/chromium/ui/gl/direct_composition_surface_win.cc
@@ -20,6 +20,8 @@
#include "ui/gl/dc_layer_tree.h"
#include "ui/gl/direct_composition_child_surface_win.h"
#include "ui/gl/gl_angle_util_win.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_features.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gpu_switching_manager.h"
@@ -40,6 +42,8 @@ bool g_supports_overlays = false;
bool g_decode_swap_chain_disabled = false;
// Whether to force the nv12 overlay support.
bool g_force_nv12_overlay_support = false;
+// Whether software overlays have been disabled.
+bool g_disable_sw_overlays = false;
// The lock to guard g_overlay_caps_valid and g_supports_overlays.
base::Lock& GetOverlayLock() {
@@ -57,6 +61,12 @@ void SetSupportsOverlays(bool support) {
g_supports_overlays = support;
}
+bool SupportsSoftwareOverlays() {
+ return base::FeatureList::IsEnabled(
+ features::kDirectCompositionSoftwareOverlays) &&
+ !g_disable_sw_overlays;
+}
+
bool OverlayCapsValid() {
base::AutoLock auto_lock(GetOverlayLock());
return g_overlay_caps_valid;
@@ -251,8 +261,7 @@ void GetGpuDriverOverlayInfo(bool* supports_overlays,
base::UmaHistogramBoolean("GPU.DirectComposition.HardwareOverlaysSupported",
*supports_overlays);
- if (*supports_overlays || !base::FeatureList::IsEnabled(
- features::kDirectCompositionSoftwareOverlays)) {
+ if (*supports_overlays || !SupportsSoftwareOverlays()) {
return;
}
@@ -359,10 +368,9 @@ DirectCompositionSurfaceWin::DirectCompositionSurfaceWin(
settings.use_angle_texture_offset,
settings.max_pending_frames,
settings.force_root_surface_full_damage)),
- layer_tree_(std::make_unique<DCLayerTree>(
- settings.disable_nv12_dynamic_textures,
- settings.disable_vp_scaling,
- settings.reset_vp_when_colorspace_changes)) {
+ layer_tree_(
+ std::make_unique<DCLayerTree>(settings.disable_nv12_dynamic_textures,
+ settings.disable_vp_scaling)) {
ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
}
@@ -464,6 +472,11 @@ void DirectCompositionSurfaceWin::DisableOverlays() {
}
// static
+void DirectCompositionSurfaceWin::DisableSoftwareOverlays() {
+ g_disable_sw_overlays = true;
+}
+
+// static
void DirectCompositionSurfaceWin::InvalidateOverlayCaps() {
SetOverlayCapsValid(false);
}
@@ -473,9 +486,7 @@ bool DirectCompositionSurfaceWin::AreScaledOverlaysSupported() {
UpdateOverlaySupport();
if (g_overlay_format_used == DXGI_FORMAT_NV12) {
return (g_nv12_overlay_support_flags & DXGI_OVERLAY_SUPPORT_FLAG_SCALING) ||
- (SupportsOverlays() &&
- base::FeatureList::IsEnabled(
- features::kDirectCompositionSoftwareOverlays));
+ (SupportsOverlays() && SupportsSoftwareOverlays());
} else if (g_overlay_format_used == DXGI_FORMAT_YUY2) {
return !!(g_yuy2_overlay_support_flags & DXGI_OVERLAY_SUPPORT_FLAG_SCALING);
} else {
@@ -653,8 +664,7 @@ bool DirectCompositionSurfaceWin::IsSwapChainTearingSupported() {
// static
bool DirectCompositionSurfaceWin::AllowTearing() {
// Swap chain tearing is used only if vsync is disabled explicitly.
- return base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableGpuVsync) &&
+ return !features::UseGpuVsync() &&
DirectCompositionSurfaceWin::IsSwapChainTearingSupported();
}
@@ -860,6 +870,10 @@ void DirectCompositionSurfaceWin::OnDisplayMetricsChanged() {
UpdateMonitorInfo();
}
+bool DirectCompositionSurfaceWin::SupportsDelegatedInk() {
+ return layer_tree_->SupportsDelegatedInk();
+}
+
scoped_refptr<base::TaskRunner>
DirectCompositionSurfaceWin::GetWindowTaskRunnerForTesting() {
return child_window_.GetTaskRunnerForTesting();
diff --git a/chromium/ui/gl/direct_composition_surface_win.h b/chromium/ui/gl/direct_composition_surface_win.h
index a86764207a2..03da756a3f4 100644
--- a/chromium/ui/gl/direct_composition_surface_win.h
+++ b/chromium/ui/gl/direct_composition_surface_win.h
@@ -35,7 +35,6 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
bool disable_vp_scaling = false;
size_t max_pending_frames = 2;
bool use_angle_texture_offset = false;
- bool reset_vp_when_colorspace_changes = false;
bool force_root_surface_full_damage = false;
};
@@ -63,6 +62,9 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
// current GPU process' lifetime.
static void DisableOverlays();
+ // Similar to the above but disables software overlay support.
+ static void DisableSoftwareOverlays();
+
// Indicate the overlay caps are invalid.
static void InvalidateOverlayCaps();
@@ -150,6 +152,8 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
void OnDisplayRemoved() override;
void OnDisplayMetricsChanged() override;
+ bool SupportsDelegatedInk() override;
+
HWND window() const { return window_; }
scoped_refptr<base::TaskRunner> GetWindowTaskRunnerForTesting();
diff --git a/chromium/ui/gl/direct_composition_surface_win_unittest.cc b/chromium/ui/gl/direct_composition_surface_win_unittest.cc
index df97d0b1f5a..1f575daeda8 100644
--- a/chromium/ui/gl/direct_composition_surface_win_unittest.cc
+++ b/chromium/ui/gl/direct_composition_surface_win_unittest.cc
@@ -26,6 +26,7 @@
#include "ui/gl/dc_renderer_layer_params.h"
#include "ui/gl/direct_composition_child_surface_win.h"
#include "ui/gl/gl_angle_util_win.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_image_d3d.h"
#include "ui/gl/gl_image_dxgi.h"
@@ -949,7 +950,8 @@ TEST_F(DirectCompositionPixelTest, YUY2SwapChain) {
// CreateSwapChainForCompositionSurfaceHandle fails with YUY2 format on
// Win10/AMD bot (Radeon RX550). See https://crbug.com/967860.
if (context_ && context_->GetVersionInfo() &&
- context_->GetVersionInfo()->driver_vendor == "ANGLE (AMD)")
+ context_->GetVersionInfo()->driver_vendor.find("AMD") !=
+ std::string::npos)
return;
// Swap chain size is overridden to content rect size only if scaled overlays
@@ -1163,6 +1165,11 @@ TEST_F(DirectCompositionPixelTest, ResizeVideoLayer) {
TEST_F(DirectCompositionPixelTest, SwapChainImage) {
if (!surface_)
return;
+ // Fails on AMD RX 5500 XT. https://crbug.com/1152565.
+ if (context_ && context_->GetVersionInfo() &&
+ context_->GetVersionInfo()->driver_vendor.find("AMD") !=
+ std::string::npos)
+ return;
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
diff --git a/chromium/ui/gl/features.gni b/chromium/ui/gl/features.gni
index 6d4973d40bb..7fbcd0d8175 100644
--- a/chromium/ui/gl/features.gni
+++ b/chromium/ui/gl/features.gni
@@ -2,9 +2,13 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromecast_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
+import("//build/config/chromeos/ui_mode.gni")
+import("//build/util/version.gni")
+
declare_args() {
# Should ANGLE be linked statically?
- # False by default, enabling currently supported only on Android
use_static_angle = false
# Should EGL support be compiled?
@@ -23,7 +27,7 @@ declare_args() {
declare_args() {
enable_swiftshader = (is_win || is_linux || is_chromeos ||
- (is_mac && use_egl) || is_chromeos || is_fuchsia) &&
+ (is_mac && use_egl) || is_chromeos_ash || is_fuchsia) &&
(target_cpu == "x86" || target_cpu == "x64" ||
target_cpu == "arm" || target_cpu == "arm64" ||
target_cpu == "mipsel" || target_cpu == "mips64el")
diff --git a/chromium/ui/gl/generate_bindings.py b/chromium/ui/gl/generate_bindings.py
index a6f5b1d757b..0713478139a 100755
--- a/chromium/ui/gl/generate_bindings.py
+++ b/chromium/ui/gl/generate_bindings.py
@@ -3418,7 +3418,7 @@ void DriverEGL::InitializeExtensionBindings() {
file.write('%s Trace%sApi::%sFn(%s) {\n' %
(return_type, set_name.upper(), function_name, arguments))
argument_names = MakeArgNames(arguments)
- file.write(' TRACE_EVENT_BINARY_EFFICIENT0("gpu", "Trace%sAPI::%s")\n' %
+ file.write(' TRACE_EVENT_BINARY_EFFICIENT0("gpu", "Trace%sAPI::%s");\n' %
(set_name.upper(), function_name))
if return_type == 'void':
file.write(' %s_api_->%sFn(%s);\n' %
diff --git a/chromium/ui/gl/gl_angle_util_win.cc b/chromium/ui/gl/gl_angle_util_win.cc
index ef04c3977bd..4545ea30250 100644
--- a/chromium/ui/gl/gl_angle_util_win.cc
+++ b/chromium/ui/gl/gl_angle_util_win.cc
@@ -9,6 +9,7 @@
#include "base/trace_event/trace_event.h"
#include "third_party/angle/include/EGL/egl.h"
#include "third_party/angle/include/EGL/eglext.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_surface_egl.h"
namespace gl {
@@ -23,7 +24,7 @@ void* QueryDeviceObjectFromANGLE(int object_type) {
egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
}
- if (!gl::GLSurfaceEGL::HasEGLExtension("EGL_EXT_device_query"))
+ if (!gl::GLSurfaceEGL::HasEGLClientExtension("EGL_EXT_device_query"))
return nullptr;
PFNEGLQUERYDISPLAYATTRIBEXTPROC QueryDisplayAttribEXT = nullptr;
diff --git a/chromium/ui/gl/gl_bindings_autogen_egl.cc b/chromium/ui/gl/gl_bindings_autogen_egl.cc
index 43135771bd0..95f23832039 100644
--- a/chromium/ui/gl/gl_bindings_autogen_egl.cc
+++ b/chromium/ui/gl/gl_bindings_autogen_egl.cc
@@ -891,14 +891,14 @@ EGLint EGLApiBase::eglWaitSyncKHRFn(EGLDisplay dpy,
}
EGLBoolean TraceEGLApi::eglBindAPIFn(EGLenum api) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglBindAPI")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglBindAPI");
return egl_api_->eglBindAPIFn(api);
}
EGLBoolean TraceEGLApi::eglBindTexImageFn(EGLDisplay dpy,
EGLSurface surface,
EGLint buffer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglBindTexImage")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglBindTexImage");
return egl_api_->eglBindTexImageFn(dpy, surface, buffer);
}
@@ -907,7 +907,7 @@ EGLBoolean TraceEGLApi::eglChooseConfigFn(EGLDisplay dpy,
EGLConfig* configs,
EGLint config_size,
EGLint* num_config) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglChooseConfig")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglChooseConfig");
return egl_api_->eglChooseConfigFn(dpy, attrib_list, configs, config_size,
num_config);
}
@@ -916,14 +916,14 @@ EGLint TraceEGLApi::eglClientWaitSyncKHRFn(EGLDisplay dpy,
EGLSyncKHR sync,
EGLint flags,
EGLTimeKHR timeout) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglClientWaitSyncKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglClientWaitSyncKHR");
return egl_api_->eglClientWaitSyncKHRFn(dpy, sync, flags, timeout);
}
EGLBoolean TraceEGLApi::eglCopyBuffersFn(EGLDisplay dpy,
EGLSurface surface,
EGLNativePixmapType target) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCopyBuffers")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCopyBuffers");
return egl_api_->eglCopyBuffersFn(dpy, surface, target);
}
@@ -931,7 +931,7 @@ EGLContext TraceEGLApi::eglCreateContextFn(EGLDisplay dpy,
EGLConfig config,
EGLContext share_context,
const EGLint* attrib_list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreateContext")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreateContext");
return egl_api_->eglCreateContextFn(dpy, config, share_context, attrib_list);
}
@@ -940,7 +940,7 @@ EGLImageKHR TraceEGLApi::eglCreateImageKHRFn(EGLDisplay dpy,
EGLenum target,
EGLClientBuffer buffer,
const EGLint* attrib_list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreateImageKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreateImageKHR");
return egl_api_->eglCreateImageKHRFn(dpy, ctx, target, buffer, attrib_list);
}
@@ -950,8 +950,8 @@ EGLSurface TraceEGLApi::eglCreatePbufferFromClientBufferFn(
void* buffer,
EGLConfig config,
const EGLint* attrib_list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglCreatePbufferFromClientBuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0(
+ "gpu", "TraceEGLAPI::eglCreatePbufferFromClientBuffer");
return egl_api_->eglCreatePbufferFromClientBufferFn(dpy, buftype, buffer,
config, attrib_list);
}
@@ -959,7 +959,7 @@ EGLSurface TraceEGLApi::eglCreatePbufferFromClientBufferFn(
EGLSurface TraceEGLApi::eglCreatePbufferSurfaceFn(EGLDisplay dpy,
EGLConfig config,
const EGLint* attrib_list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreatePbufferSurface")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreatePbufferSurface");
return egl_api_->eglCreatePbufferSurfaceFn(dpy, config, attrib_list);
}
@@ -967,13 +967,13 @@ EGLSurface TraceEGLApi::eglCreatePixmapSurfaceFn(EGLDisplay dpy,
EGLConfig config,
EGLNativePixmapType pixmap,
const EGLint* attrib_list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreatePixmapSurface")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreatePixmapSurface");
return egl_api_->eglCreatePixmapSurfaceFn(dpy, config, pixmap, attrib_list);
}
EGLStreamKHR TraceEGLApi::eglCreateStreamKHRFn(EGLDisplay dpy,
const EGLint* attrib_list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreateStreamKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreateStreamKHR");
return egl_api_->eglCreateStreamKHRFn(dpy, attrib_list);
}
@@ -982,7 +982,7 @@ EGLBoolean TraceEGLApi::eglCreateStreamProducerD3DTextureANGLEFn(
EGLStreamKHR stream,
EGLAttrib* attrib_list) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceEGLAPI::eglCreateStreamProducerD3DTextureANGLE")
+ "gpu", "TraceEGLAPI::eglCreateStreamProducerD3DTextureANGLE");
return egl_api_->eglCreateStreamProducerD3DTextureANGLEFn(dpy, stream,
attrib_list);
}
@@ -990,7 +990,7 @@ EGLBoolean TraceEGLApi::eglCreateStreamProducerD3DTextureANGLEFn(
EGLSyncKHR TraceEGLApi::eglCreateSyncKHRFn(EGLDisplay dpy,
EGLenum type,
const EGLint* attrib_list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreateSyncKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreateSyncKHR");
return egl_api_->eglCreateSyncKHRFn(dpy, type, attrib_list);
}
@@ -998,48 +998,49 @@ EGLSurface TraceEGLApi::eglCreateWindowSurfaceFn(EGLDisplay dpy,
EGLConfig config,
EGLNativeWindowType win,
const EGLint* attrib_list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreateWindowSurface")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglCreateWindowSurface");
return egl_api_->eglCreateWindowSurfaceFn(dpy, config, win, attrib_list);
}
EGLint TraceEGLApi::eglDebugMessageControlKHRFn(EGLDEBUGPROCKHR callback,
const EGLAttrib* attrib_list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglDebugMessageControlKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceEGLAPI::eglDebugMessageControlKHR");
return egl_api_->eglDebugMessageControlKHRFn(callback, attrib_list);
}
EGLBoolean TraceEGLApi::eglDestroyContextFn(EGLDisplay dpy, EGLContext ctx) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglDestroyContext")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglDestroyContext");
return egl_api_->eglDestroyContextFn(dpy, ctx);
}
EGLBoolean TraceEGLApi::eglDestroyImageKHRFn(EGLDisplay dpy,
EGLImageKHR image) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglDestroyImageKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglDestroyImageKHR");
return egl_api_->eglDestroyImageKHRFn(dpy, image);
}
EGLBoolean TraceEGLApi::eglDestroyStreamKHRFn(EGLDisplay dpy,
EGLStreamKHR stream) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglDestroyStreamKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglDestroyStreamKHR");
return egl_api_->eglDestroyStreamKHRFn(dpy, stream);
}
EGLBoolean TraceEGLApi::eglDestroySurfaceFn(EGLDisplay dpy,
EGLSurface surface) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglDestroySurface")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglDestroySurface");
return egl_api_->eglDestroySurfaceFn(dpy, surface);
}
EGLBoolean TraceEGLApi::eglDestroySyncKHRFn(EGLDisplay dpy, EGLSyncKHR sync) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglDestroySyncKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglDestroySyncKHR");
return egl_api_->eglDestroySyncKHRFn(dpy, sync);
}
EGLint TraceEGLApi::eglDupNativeFenceFDANDROIDFn(EGLDisplay dpy,
EGLSyncKHR sync) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglDupNativeFenceFDANDROID")
+ "TraceEGLAPI::eglDupNativeFenceFDANDROID");
return egl_api_->eglDupNativeFenceFDANDROIDFn(dpy, sync);
}
@@ -1048,7 +1049,7 @@ EGLBoolean TraceEGLApi::eglExportDMABUFImageMESAFn(EGLDisplay dpy,
int* fds,
EGLint* strides,
EGLint* offsets) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglExportDMABUFImageMESA")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglExportDMABUFImageMESA");
return egl_api_->eglExportDMABUFImageMESAFn(dpy, image, fds, strides,
offsets);
}
@@ -1060,7 +1061,7 @@ EGLBoolean TraceEGLApi::eglExportDMABUFImageQueryMESAFn(
int* num_planes,
EGLuint64KHR* modifiers) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglExportDMABUFImageQueryMESA")
+ "TraceEGLAPI::eglExportDMABUFImageQueryMESA");
return egl_api_->eglExportDMABUFImageQueryMESAFn(dpy, image, fourcc,
num_planes, modifiers);
}
@@ -1072,7 +1073,7 @@ EGLBoolean TraceEGLApi::eglGetCompositorTimingANDROIDFn(
EGLint* names,
EGLnsecsANDROID* values) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglGetCompositorTimingANDROID")
+ "TraceEGLAPI::eglGetCompositorTimingANDROID");
return egl_api_->eglGetCompositorTimingANDROIDFn(dpy, surface, numTimestamps,
names, values);
}
@@ -1082,7 +1083,7 @@ EGLBoolean TraceEGLApi::eglGetCompositorTimingSupportedANDROIDFn(
EGLSurface surface,
EGLint timestamp) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceEGLAPI::eglGetCompositorTimingSupportedANDROID")
+ "gpu", "TraceEGLAPI::eglGetCompositorTimingSupportedANDROID");
return egl_api_->eglGetCompositorTimingSupportedANDROIDFn(dpy, surface,
timestamp);
}
@@ -1091,7 +1092,7 @@ EGLBoolean TraceEGLApi::eglGetConfigAttribFn(EGLDisplay dpy,
EGLConfig config,
EGLint attribute,
EGLint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetConfigAttrib")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetConfigAttrib");
return egl_api_->eglGetConfigAttribFn(dpy, config, attribute, value);
}
@@ -1099,32 +1100,32 @@ EGLBoolean TraceEGLApi::eglGetConfigsFn(EGLDisplay dpy,
EGLConfig* configs,
EGLint config_size,
EGLint* num_config) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetConfigs")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetConfigs");
return egl_api_->eglGetConfigsFn(dpy, configs, config_size, num_config);
}
EGLContext TraceEGLApi::eglGetCurrentContextFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetCurrentContext")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetCurrentContext");
return egl_api_->eglGetCurrentContextFn();
}
EGLDisplay TraceEGLApi::eglGetCurrentDisplayFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetCurrentDisplay")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetCurrentDisplay");
return egl_api_->eglGetCurrentDisplayFn();
}
EGLSurface TraceEGLApi::eglGetCurrentSurfaceFn(EGLint readdraw) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetCurrentSurface")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetCurrentSurface");
return egl_api_->eglGetCurrentSurfaceFn(readdraw);
}
EGLDisplay TraceEGLApi::eglGetDisplayFn(EGLNativeDisplayType display_id) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetDisplay")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetDisplay");
return egl_api_->eglGetDisplayFn(display_id);
}
EGLint TraceEGLApi::eglGetErrorFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetError")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetError");
return egl_api_->eglGetErrorFn();
}
@@ -1136,7 +1137,7 @@ EGLBoolean TraceEGLApi::eglGetFrameTimestampsANDROIDFn(
EGLint* timestamps,
EGLnsecsANDROID* values) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglGetFrameTimestampsANDROID")
+ "TraceEGLAPI::eglGetFrameTimestampsANDROID");
return egl_api_->eglGetFrameTimestampsANDROIDFn(
dpy, surface, frameId, numTimestamps, timestamps, values);
}
@@ -1146,7 +1147,7 @@ EGLBoolean TraceEGLApi::eglGetFrameTimestampSupportedANDROIDFn(
EGLSurface surface,
EGLint timestamp) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceEGLAPI::eglGetFrameTimestampSupportedANDROID")
+ "gpu", "TraceEGLAPI::eglGetFrameTimestampSupportedANDROID");
return egl_api_->eglGetFrameTimestampSupportedANDROIDFn(dpy, surface,
timestamp);
}
@@ -1155,35 +1156,35 @@ EGLBoolean TraceEGLApi::eglGetMscRateANGLEFn(EGLDisplay dpy,
EGLSurface surface,
EGLint* numerator,
EGLint* denominator) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetMscRateANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetMscRateANGLE");
return egl_api_->eglGetMscRateANGLEFn(dpy, surface, numerator, denominator);
}
EGLClientBuffer TraceEGLApi::eglGetNativeClientBufferANDROIDFn(
const struct AHardwareBuffer* ahardwarebuffer) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglGetNativeClientBufferANDROID")
+ "TraceEGLAPI::eglGetNativeClientBufferANDROID");
return egl_api_->eglGetNativeClientBufferANDROIDFn(ahardwarebuffer);
}
EGLBoolean TraceEGLApi::eglGetNextFrameIdANDROIDFn(EGLDisplay dpy,
EGLSurface surface,
EGLuint64KHR* frameId) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetNextFrameIdANDROID")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetNextFrameIdANDROID");
return egl_api_->eglGetNextFrameIdANDROIDFn(dpy, surface, frameId);
}
EGLDisplay TraceEGLApi::eglGetPlatformDisplayFn(EGLenum platform,
void* native_display,
const EGLAttrib* attrib_list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetPlatformDisplay")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetPlatformDisplay");
return egl_api_->eglGetPlatformDisplayFn(platform, native_display,
attrib_list);
}
__eglMustCastToProperFunctionPointerType TraceEGLApi::eglGetProcAddressFn(
const char* procname) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetProcAddress")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetProcAddress");
return egl_api_->eglGetProcAddressFn(procname);
}
@@ -1191,7 +1192,7 @@ EGLBoolean TraceEGLApi::eglGetSyncAttribKHRFn(EGLDisplay dpy,
EGLSyncKHR sync,
EGLint attribute,
EGLint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetSyncAttribKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetSyncAttribKHR");
return egl_api_->eglGetSyncAttribKHRFn(dpy, sync, attribute, value);
}
@@ -1200,12 +1201,12 @@ EGLBoolean TraceEGLApi::eglGetSyncValuesCHROMIUMFn(EGLDisplay dpy,
EGLuint64CHROMIUM* ust,
EGLuint64CHROMIUM* msc,
EGLuint64CHROMIUM* sbc) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetSyncValuesCHROMIUM")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglGetSyncValuesCHROMIUM");
return egl_api_->eglGetSyncValuesCHROMIUMFn(dpy, surface, ust, msc, sbc);
}
void TraceEGLApi::eglHandleGPUSwitchANGLEFn(EGLDisplay dpy) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglHandleGPUSwitchANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglHandleGPUSwitchANGLE");
egl_api_->eglHandleGPUSwitchANGLEFn(dpy);
}
@@ -1213,14 +1214,14 @@ EGLBoolean TraceEGLApi::eglImageFlushExternalEXTFn(
EGLDisplay dpy,
EGLImageKHR image,
const EGLAttrib* attrib_list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglImageFlushExternalEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglImageFlushExternalEXT");
return egl_api_->eglImageFlushExternalEXTFn(dpy, image, attrib_list);
}
EGLBoolean TraceEGLApi::eglInitializeFn(EGLDisplay dpy,
EGLint* major,
EGLint* minor) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglInitialize")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglInitialize");
return egl_api_->eglInitializeFn(dpy, major, minor);
}
@@ -1228,7 +1229,7 @@ EGLint TraceEGLApi::eglLabelObjectKHRFn(EGLDisplay display,
EGLenum objectType,
EGLObjectKHR object,
EGLLabelKHR label) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglLabelObjectKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglLabelObjectKHR");
return egl_api_->eglLabelObjectKHRFn(display, objectType, object, label);
}
@@ -1236,7 +1237,7 @@ EGLBoolean TraceEGLApi::eglMakeCurrentFn(EGLDisplay dpy,
EGLSurface draw,
EGLSurface read,
EGLContext ctx) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglMakeCurrent")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglMakeCurrent");
return egl_api_->eglMakeCurrentFn(dpy, draw, read, ctx);
}
@@ -1246,12 +1247,12 @@ EGLBoolean TraceEGLApi::eglPostSubBufferNVFn(EGLDisplay dpy,
EGLint y,
EGLint width,
EGLint height) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglPostSubBufferNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglPostSubBufferNV");
return egl_api_->eglPostSubBufferNVFn(dpy, surface, x, y, width, height);
}
EGLenum TraceEGLApi::eglQueryAPIFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryAPI")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryAPI");
return egl_api_->eglQueryAPIFn();
}
@@ -1259,25 +1260,25 @@ EGLBoolean TraceEGLApi::eglQueryContextFn(EGLDisplay dpy,
EGLContext ctx,
EGLint attribute,
EGLint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryContext")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryContext");
return egl_api_->eglQueryContextFn(dpy, ctx, attribute, value);
}
EGLBoolean TraceEGLApi::eglQueryDebugKHRFn(EGLint attribute, EGLAttrib* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryDebugKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryDebugKHR");
return egl_api_->eglQueryDebugKHRFn(attribute, value);
}
EGLBoolean TraceEGLApi::eglQueryDevicesEXTFn(EGLint max_devices,
EGLDeviceEXT* devices,
EGLint* num_devices) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryDevicesEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryDevicesEXT");
return egl_api_->eglQueryDevicesEXTFn(max_devices, devices, num_devices);
}
const char* TraceEGLApi::eglQueryDeviceStringEXTFn(EGLDeviceEXT device,
EGLint name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryDeviceStringEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryDeviceStringEXT");
return egl_api_->eglQueryDeviceStringEXTFn(device, name);
}
@@ -1285,7 +1286,7 @@ EGLBoolean TraceEGLApi::eglQueryDisplayAttribANGLEFn(EGLDisplay dpy,
EGLint attribute,
EGLAttrib* value) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglQueryDisplayAttribANGLE")
+ "TraceEGLAPI::eglQueryDisplayAttribANGLE");
return egl_api_->eglQueryDisplayAttribANGLEFn(dpy, attribute, value);
}
@@ -1293,7 +1294,7 @@ EGLBoolean TraceEGLApi::eglQueryStreamKHRFn(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryStreamKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryStreamKHR");
return egl_api_->eglQueryStreamKHRFn(dpy, stream, attribute, value);
}
@@ -1301,19 +1302,19 @@ EGLBoolean TraceEGLApi::eglQueryStreamu64KHRFn(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLuint64KHR* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryStreamu64KHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryStreamu64KHR");
return egl_api_->eglQueryStreamu64KHRFn(dpy, stream, attribute, value);
}
const char* TraceEGLApi::eglQueryStringFn(EGLDisplay dpy, EGLint name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryString")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryString");
return egl_api_->eglQueryStringFn(dpy, name);
}
const char* TraceEGLApi::eglQueryStringiANGLEFn(EGLDisplay dpy,
EGLint name,
EGLint index) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryStringiANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQueryStringiANGLE");
return egl_api_->eglQueryStringiANGLEFn(dpy, name, index);
}
@@ -1321,7 +1322,7 @@ EGLBoolean TraceEGLApi::eglQuerySurfaceFn(EGLDisplay dpy,
EGLSurface surface,
EGLint attribute,
EGLint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQuerySurface")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglQuerySurface");
return egl_api_->eglQuerySurfaceFn(dpy, surface, attribute, value);
}
@@ -1330,7 +1331,7 @@ EGLBoolean TraceEGLApi::eglQuerySurfacePointerANGLEFn(EGLDisplay dpy,
EGLint attribute,
void** value) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglQuerySurfacePointerANGLE")
+ "TraceEGLAPI::eglQuerySurfacePointerANGLE");
return egl_api_->eglQuerySurfacePointerANGLEFn(dpy, surface, attribute,
value);
}
@@ -1338,26 +1339,26 @@ EGLBoolean TraceEGLApi::eglQuerySurfacePointerANGLEFn(EGLDisplay dpy,
void TraceEGLApi::eglReacquireHighPowerGPUANGLEFn(EGLDisplay dpy,
EGLContext ctx) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglReacquireHighPowerGPUANGLE")
+ "TraceEGLAPI::eglReacquireHighPowerGPUANGLE");
egl_api_->eglReacquireHighPowerGPUANGLEFn(dpy, ctx);
}
void TraceEGLApi::eglReleaseHighPowerGPUANGLEFn(EGLDisplay dpy,
EGLContext ctx) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglReleaseHighPowerGPUANGLE")
+ "TraceEGLAPI::eglReleaseHighPowerGPUANGLE");
egl_api_->eglReleaseHighPowerGPUANGLEFn(dpy, ctx);
}
EGLBoolean TraceEGLApi::eglReleaseTexImageFn(EGLDisplay dpy,
EGLSurface surface,
EGLint buffer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglReleaseTexImage")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglReleaseTexImage");
return egl_api_->eglReleaseTexImageFn(dpy, surface, buffer);
}
EGLBoolean TraceEGLApi::eglReleaseThreadFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglReleaseThread")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglReleaseThread");
return egl_api_->eglReleaseThreadFn();
}
@@ -1365,7 +1366,7 @@ void TraceEGLApi::eglSetBlobCacheFuncsANDROIDFn(EGLDisplay dpy,
EGLSetBlobFuncANDROID set,
EGLGetBlobFuncANDROID get) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglSetBlobCacheFuncsANDROID")
+ "TraceEGLAPI::eglSetBlobCacheFuncsANDROID");
egl_api_->eglSetBlobCacheFuncsANDROIDFn(dpy, set, get);
}
@@ -1373,14 +1374,14 @@ EGLBoolean TraceEGLApi::eglStreamAttribKHRFn(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLint value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglStreamAttribKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglStreamAttribKHR");
return egl_api_->eglStreamAttribKHRFn(dpy, stream, attribute, value);
}
EGLBoolean TraceEGLApi::eglStreamConsumerAcquireKHRFn(EGLDisplay dpy,
EGLStreamKHR stream) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglStreamConsumerAcquireKHR")
+ "TraceEGLAPI::eglStreamConsumerAcquireKHR");
return egl_api_->eglStreamConsumerAcquireKHRFn(dpy, stream);
}
@@ -1389,7 +1390,7 @@ EGLBoolean TraceEGLApi::eglStreamConsumerGLTextureExternalAttribsNVFn(
EGLStreamKHR stream,
EGLAttrib* attrib_list) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceEGLAPI::eglStreamConsumerGLTextureExternalAttribsNV")
+ "gpu", "TraceEGLAPI::eglStreamConsumerGLTextureExternalAttribsNV");
return egl_api_->eglStreamConsumerGLTextureExternalAttribsNVFn(dpy, stream,
attrib_list);
}
@@ -1398,14 +1399,14 @@ EGLBoolean TraceEGLApi::eglStreamConsumerGLTextureExternalKHRFn(
EGLDisplay dpy,
EGLStreamKHR stream) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceEGLAPI::eglStreamConsumerGLTextureExternalKHR")
+ "gpu", "TraceEGLAPI::eglStreamConsumerGLTextureExternalKHR");
return egl_api_->eglStreamConsumerGLTextureExternalKHRFn(dpy, stream);
}
EGLBoolean TraceEGLApi::eglStreamConsumerReleaseKHRFn(EGLDisplay dpy,
EGLStreamKHR stream) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglStreamConsumerReleaseKHR")
+ "TraceEGLAPI::eglStreamConsumerReleaseKHR");
return egl_api_->eglStreamConsumerReleaseKHRFn(dpy, stream);
}
@@ -1415,7 +1416,7 @@ EGLBoolean TraceEGLApi::eglStreamPostD3DTextureANGLEFn(
void* texture,
const EGLAttrib* attrib_list) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglStreamPostD3DTextureANGLE")
+ "TraceEGLAPI::eglStreamPostD3DTextureANGLE");
return egl_api_->eglStreamPostD3DTextureANGLEFn(dpy, stream, texture,
attrib_list);
}
@@ -1424,12 +1425,12 @@ EGLBoolean TraceEGLApi::eglSurfaceAttribFn(EGLDisplay dpy,
EGLSurface surface,
EGLint attribute,
EGLint value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglSurfaceAttrib")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglSurfaceAttrib");
return egl_api_->eglSurfaceAttribFn(dpy, surface, attribute, value);
}
EGLBoolean TraceEGLApi::eglSwapBuffersFn(EGLDisplay dpy, EGLSurface surface) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglSwapBuffers")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglSwapBuffers");
return egl_api_->eglSwapBuffersFn(dpy, surface);
}
@@ -1438,39 +1439,39 @@ EGLBoolean TraceEGLApi::eglSwapBuffersWithDamageKHRFn(EGLDisplay dpy,
EGLint* rects,
EGLint n_rects) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceEGLAPI::eglSwapBuffersWithDamageKHR")
+ "TraceEGLAPI::eglSwapBuffersWithDamageKHR");
return egl_api_->eglSwapBuffersWithDamageKHRFn(dpy, surface, rects, n_rects);
}
EGLBoolean TraceEGLApi::eglSwapIntervalFn(EGLDisplay dpy, EGLint interval) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglSwapInterval")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglSwapInterval");
return egl_api_->eglSwapIntervalFn(dpy, interval);
}
EGLBoolean TraceEGLApi::eglTerminateFn(EGLDisplay dpy) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglTerminate")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglTerminate");
return egl_api_->eglTerminateFn(dpy);
}
EGLBoolean TraceEGLApi::eglWaitClientFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglWaitClient")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglWaitClient");
return egl_api_->eglWaitClientFn();
}
EGLBoolean TraceEGLApi::eglWaitGLFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglWaitGL")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglWaitGL");
return egl_api_->eglWaitGLFn();
}
EGLBoolean TraceEGLApi::eglWaitNativeFn(EGLint engine) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglWaitNative")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglWaitNative");
return egl_api_->eglWaitNativeFn(engine);
}
EGLint TraceEGLApi::eglWaitSyncKHRFn(EGLDisplay dpy,
EGLSyncKHR sync,
EGLint flags) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglWaitSyncKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglWaitSyncKHR");
return egl_api_->eglWaitSyncKHRFn(dpy, sync, flags);
}
diff --git a/chromium/ui/gl/gl_bindings_autogen_gl.cc b/chromium/ui/gl/gl_bindings_autogen_gl.cc
index 4fe60eec01e..fe40cf0cf32 100644
--- a/chromium/ui/gl/gl_bindings_autogen_gl.cc
+++ b/chromium/ui/gl/gl_bindings_autogen_gl.cc
@@ -6402,46 +6402,46 @@ void GLApiBase::glWindowRectanglesEXTFn(GLenum mode,
}
void TraceGLApi::glActiveShaderProgramFn(GLuint pipeline, GLuint program) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glActiveShaderProgram")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glActiveShaderProgram");
gl_api_->glActiveShaderProgramFn(pipeline, program);
}
void TraceGLApi::glActiveTextureFn(GLenum texture) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glActiveTexture")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glActiveTexture");
gl_api_->glActiveTextureFn(texture);
}
void TraceGLApi::glAttachShaderFn(GLuint program, GLuint shader) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glAttachShader")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glAttachShader");
gl_api_->glAttachShaderFn(program, shader);
}
void TraceGLApi::glBeginQueryFn(GLenum target, GLuint id) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBeginQuery")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBeginQuery");
gl_api_->glBeginQueryFn(target, id);
}
void TraceGLApi::glBeginTransformFeedbackFn(GLenum primitiveMode) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBeginTransformFeedback")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBeginTransformFeedback");
gl_api_->glBeginTransformFeedbackFn(primitiveMode);
}
void TraceGLApi::glBindAttribLocationFn(GLuint program,
GLuint index,
const char* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindAttribLocation")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindAttribLocation");
gl_api_->glBindAttribLocationFn(program, index, name);
}
void TraceGLApi::glBindBufferFn(GLenum target, GLuint buffer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindBuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindBuffer");
gl_api_->glBindBufferFn(target, buffer);
}
void TraceGLApi::glBindBufferBaseFn(GLenum target,
GLuint index,
GLuint buffer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindBufferBase")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindBufferBase");
gl_api_->glBindBufferBaseFn(target, index, buffer);
}
@@ -6450,14 +6450,14 @@ void TraceGLApi::glBindBufferRangeFn(GLenum target,
GLuint buffer,
GLintptr offset,
GLsizeiptr size) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindBufferRange")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindBufferRange");
gl_api_->glBindBufferRangeFn(target, index, buffer, offset, size);
}
void TraceGLApi::glBindFragDataLocationFn(GLuint program,
GLuint colorNumber,
const char* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindFragDataLocation")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindFragDataLocation");
gl_api_->glBindFragDataLocationFn(program, colorNumber, name);
}
@@ -6466,7 +6466,7 @@ void TraceGLApi::glBindFragDataLocationIndexedFn(GLuint program,
GLuint index,
const char* name) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glBindFragDataLocationIndexed")
+ "TraceGLAPI::glBindFragDataLocationIndexed");
gl_api_->glBindFragDataLocationIndexedFn(program, colorNumber, index, name);
}
@@ -6474,12 +6474,12 @@ void TraceGLApi::glBindFragmentInputLocationCHROMIUMFn(GLuint program,
GLint location,
const char* name) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glBindFragmentInputLocationCHROMIUM")
+ "gpu", "TraceGLAPI::glBindFragmentInputLocationCHROMIUM");
gl_api_->glBindFragmentInputLocationCHROMIUMFn(program, location, name);
}
void TraceGLApi::glBindFramebufferEXTFn(GLenum target, GLuint framebuffer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindFramebufferEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindFramebufferEXT");
gl_api_->glBindFramebufferEXTFn(target, framebuffer);
}
@@ -6490,33 +6490,33 @@ void TraceGLApi::glBindImageTextureEXTFn(GLuint index,
GLint layer,
GLenum access,
GLint format) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindImageTextureEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindImageTextureEXT");
gl_api_->glBindImageTextureEXTFn(index, texture, level, layered, layer,
access, format);
}
void TraceGLApi::glBindProgramPipelineFn(GLuint pipeline) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindProgramPipeline")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindProgramPipeline");
gl_api_->glBindProgramPipelineFn(pipeline);
}
void TraceGLApi::glBindRenderbufferEXTFn(GLenum target, GLuint renderbuffer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindRenderbufferEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindRenderbufferEXT");
gl_api_->glBindRenderbufferEXTFn(target, renderbuffer);
}
void TraceGLApi::glBindSamplerFn(GLuint unit, GLuint sampler) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindSampler")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindSampler");
gl_api_->glBindSamplerFn(unit, sampler);
}
void TraceGLApi::glBindTextureFn(GLenum target, GLuint texture) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindTexture")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindTexture");
gl_api_->glBindTextureFn(target, texture);
}
void TraceGLApi::glBindTransformFeedbackFn(GLenum target, GLuint id) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindTransformFeedback")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindTransformFeedback");
gl_api_->glBindTransformFeedbackFn(target, id);
}
@@ -6524,12 +6524,12 @@ void TraceGLApi::glBindUniformLocationCHROMIUMFn(GLuint program,
GLint location,
const char* name) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glBindUniformLocationCHROMIUM")
+ "TraceGLAPI::glBindUniformLocationCHROMIUM");
gl_api_->glBindUniformLocationCHROMIUMFn(program, location, name);
}
void TraceGLApi::glBindVertexArrayOESFn(GLuint array) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindVertexArrayOES")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindVertexArrayOES");
gl_api_->glBindVertexArrayOESFn(array);
}
@@ -6537,12 +6537,12 @@ void TraceGLApi::glBindVertexBufferFn(GLuint bindingindex,
GLuint buffer,
GLintptr offset,
GLsizei stride) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindVertexBuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindVertexBuffer");
gl_api_->glBindVertexBufferFn(bindingindex, buffer, offset, stride);
}
void TraceGLApi::glBlendBarrierKHRFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendBarrierKHR")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendBarrierKHR");
gl_api_->glBlendBarrierKHRFn();
}
@@ -6550,22 +6550,22 @@ void TraceGLApi::glBlendColorFn(GLclampf red,
GLclampf green,
GLclampf blue,
GLclampf alpha) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendColor")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendColor");
gl_api_->glBlendColorFn(red, green, blue, alpha);
}
void TraceGLApi::glBlendEquationFn(GLenum mode) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendEquation")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendEquation");
gl_api_->glBlendEquationFn(mode);
}
void TraceGLApi::glBlendEquationiOESFn(GLuint buf, GLenum mode) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendEquationiOES")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendEquationiOES");
gl_api_->glBlendEquationiOESFn(buf, mode);
}
void TraceGLApi::glBlendEquationSeparateFn(GLenum modeRGB, GLenum modeAlpha) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendEquationSeparate")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendEquationSeparate");
gl_api_->glBlendEquationSeparateFn(modeRGB, modeAlpha);
}
@@ -6573,17 +6573,17 @@ void TraceGLApi::glBlendEquationSeparateiOESFn(GLuint buf,
GLenum modeRGB,
GLenum modeAlpha) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glBlendEquationSeparateiOES")
+ "TraceGLAPI::glBlendEquationSeparateiOES");
gl_api_->glBlendEquationSeparateiOESFn(buf, modeRGB, modeAlpha);
}
void TraceGLApi::glBlendFuncFn(GLenum sfactor, GLenum dfactor) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendFunc")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendFunc");
gl_api_->glBlendFuncFn(sfactor, dfactor);
}
void TraceGLApi::glBlendFunciOESFn(GLuint buf, GLenum sfactor, GLenum dfactor) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendFunciOES")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendFunciOES");
gl_api_->glBlendFunciOESFn(buf, sfactor, dfactor);
}
@@ -6591,7 +6591,7 @@ void TraceGLApi::glBlendFuncSeparateFn(GLenum srcRGB,
GLenum dstRGB,
GLenum srcAlpha,
GLenum dstAlpha) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendFuncSeparate")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendFuncSeparate");
gl_api_->glBlendFuncSeparateFn(srcRGB, dstRGB, srcAlpha, dstAlpha);
}
@@ -6600,7 +6600,7 @@ void TraceGLApi::glBlendFuncSeparateiOESFn(GLuint buf,
GLenum dstRGB,
GLenum srcAlpha,
GLenum dstAlpha) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendFuncSeparateiOES")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlendFuncSeparateiOES");
gl_api_->glBlendFuncSeparateiOESFn(buf, srcRGB, dstRGB, srcAlpha, dstAlpha);
}
@@ -6614,7 +6614,7 @@ void TraceGLApi::glBlitFramebufferFn(GLint srcX0,
GLint dstY1,
GLbitfield mask,
GLenum filter) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlitFramebuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBlitFramebuffer");
gl_api_->glBlitFramebufferFn(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
dstY1, mask, filter);
}
@@ -6623,7 +6623,7 @@ void TraceGLApi::glBufferDataFn(GLenum target,
GLsizeiptr size,
const void* data,
GLenum usage) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBufferData")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBufferData");
gl_api_->glBufferDataFn(target, size, data, usage);
}
@@ -6631,18 +6631,18 @@ void TraceGLApi::glBufferSubDataFn(GLenum target,
GLintptr offset,
GLsizeiptr size,
const void* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBufferSubData")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBufferSubData");
gl_api_->glBufferSubDataFn(target, offset, size, data);
}
GLenum TraceGLApi::glCheckFramebufferStatusEXTFn(GLenum target) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glCheckFramebufferStatusEXT")
+ "TraceGLAPI::glCheckFramebufferStatusEXT");
return gl_api_->glCheckFramebufferStatusEXTFn(target);
}
void TraceGLApi::glClearFn(GLbitfield mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClear")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClear");
gl_api_->glClearFn(mask);
}
@@ -6650,28 +6650,28 @@ void TraceGLApi::glClearBufferfiFn(GLenum buffer,
GLint drawbuffer,
const GLfloat depth,
GLint stencil) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearBufferfi")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearBufferfi");
gl_api_->glClearBufferfiFn(buffer, drawbuffer, depth, stencil);
}
void TraceGLApi::glClearBufferfvFn(GLenum buffer,
GLint drawbuffer,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearBufferfv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearBufferfv");
gl_api_->glClearBufferfvFn(buffer, drawbuffer, value);
}
void TraceGLApi::glClearBufferivFn(GLenum buffer,
GLint drawbuffer,
const GLint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearBufferiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearBufferiv");
gl_api_->glClearBufferivFn(buffer, drawbuffer, value);
}
void TraceGLApi::glClearBufferuivFn(GLenum buffer,
GLint drawbuffer,
const GLuint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearBufferuiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearBufferuiv");
gl_api_->glClearBufferuivFn(buffer, drawbuffer, value);
}
@@ -6679,22 +6679,22 @@ void TraceGLApi::glClearColorFn(GLclampf red,
GLclampf green,
GLclampf blue,
GLclampf alpha) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearColor")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearColor");
gl_api_->glClearColorFn(red, green, blue, alpha);
}
void TraceGLApi::glClearDepthFn(GLclampd depth) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearDepth")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearDepth");
gl_api_->glClearDepthFn(depth);
}
void TraceGLApi::glClearDepthfFn(GLclampf depth) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearDepthf")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearDepthf");
gl_api_->glClearDepthfFn(depth);
}
void TraceGLApi::glClearStencilFn(GLint s) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearStencil")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearStencil");
gl_api_->glClearStencilFn(s);
}
@@ -6703,7 +6703,7 @@ void TraceGLApi::glClearTexImageFn(GLuint texture,
GLenum format,
GLenum type,
const GLvoid* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearTexImage")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearTexImage");
gl_api_->glClearTexImageFn(texture, level, format, type, data);
}
@@ -6718,7 +6718,7 @@ void TraceGLApi::glClearTexSubImageFn(GLuint texture,
GLenum format,
GLenum type,
const GLvoid* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearTexSubImage")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClearTexSubImage");
gl_api_->glClearTexSubImageFn(texture, level, xoffset, yoffset, zoffset,
width, height, depth, format, type, data);
}
@@ -6726,14 +6726,14 @@ void TraceGLApi::glClearTexSubImageFn(GLuint texture,
GLenum TraceGLApi::glClientWaitSyncFn(GLsync sync,
GLbitfield flags,
GLuint64 timeout) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClientWaitSync")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClientWaitSync");
return gl_api_->glClientWaitSyncFn(sync, flags, timeout);
}
GLenum TraceGLApi::glClientWaitSyncAPPLEFn(GLsync sync,
GLbitfield flags,
GLuint64 timeout) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClientWaitSyncAPPLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glClientWaitSyncAPPLE");
return gl_api_->glClientWaitSyncAPPLEFn(sync, flags, timeout);
}
@@ -6741,7 +6741,7 @@ void TraceGLApi::glColorMaskFn(GLboolean red,
GLboolean green,
GLboolean blue,
GLboolean alpha) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glColorMask")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glColorMask");
gl_api_->glColorMaskFn(red, green, blue, alpha);
}
@@ -6750,12 +6750,12 @@ void TraceGLApi::glColorMaskiOESFn(GLuint buf,
GLboolean green,
GLboolean blue,
GLboolean alpha) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glColorMaskiOES")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glColorMaskiOES");
gl_api_->glColorMaskiOESFn(buf, red, green, blue, alpha);
}
void TraceGLApi::glCompileShaderFn(GLuint shader) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCompileShader")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCompileShader");
gl_api_->glCompileShaderFn(shader);
}
@@ -6767,7 +6767,7 @@ void TraceGLApi::glCompressedTexImage2DFn(GLenum target,
GLint border,
GLsizei imageSize,
const void* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCompressedTexImage2D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCompressedTexImage2D");
gl_api_->glCompressedTexImage2DFn(target, level, internalformat, width,
height, border, imageSize, data);
}
@@ -6781,8 +6781,8 @@ void TraceGLApi::glCompressedTexImage2DRobustANGLEFn(GLenum target,
GLsizei imageSize,
GLsizei dataSize,
const void* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glCompressedTexImage2DRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0(
+ "gpu", "TraceGLAPI::glCompressedTexImage2DRobustANGLE");
gl_api_->glCompressedTexImage2DRobustANGLEFn(target, level, internalformat,
width, height, border, imageSize,
dataSize, data);
@@ -6797,7 +6797,7 @@ void TraceGLApi::glCompressedTexImage3DFn(GLenum target,
GLint border,
GLsizei imageSize,
const void* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCompressedTexImage3D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCompressedTexImage3D");
gl_api_->glCompressedTexImage3DFn(target, level, internalformat, width,
height, depth, border, imageSize, data);
}
@@ -6812,8 +6812,8 @@ void TraceGLApi::glCompressedTexImage3DRobustANGLEFn(GLenum target,
GLsizei imageSize,
GLsizei dataSize,
const void* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glCompressedTexImage3DRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0(
+ "gpu", "TraceGLAPI::glCompressedTexImage3DRobustANGLE");
gl_api_->glCompressedTexImage3DRobustANGLEFn(target, level, internalformat,
width, height, depth, border,
imageSize, dataSize, data);
@@ -6828,7 +6828,7 @@ void TraceGLApi::glCompressedTexSubImage2DFn(GLenum target,
GLenum format,
GLsizei imageSize,
const void* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCompressedTexSubImage2D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCompressedTexSubImage2D");
gl_api_->glCompressedTexSubImage2DFn(target, level, xoffset, yoffset, width,
height, format, imageSize, data);
}
@@ -6844,7 +6844,7 @@ void TraceGLApi::glCompressedTexSubImage2DRobustANGLEFn(GLenum target,
GLsizei dataSize,
const void* data) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glCompressedTexSubImage2DRobustANGLE")
+ "gpu", "TraceGLAPI::glCompressedTexSubImage2DRobustANGLE");
gl_api_->glCompressedTexSubImage2DRobustANGLEFn(
target, level, xoffset, yoffset, width, height, format, imageSize,
dataSize, data);
@@ -6861,7 +6861,7 @@ void TraceGLApi::glCompressedTexSubImage3DFn(GLenum target,
GLenum format,
GLsizei imageSize,
const void* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCompressedTexSubImage3D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCompressedTexSubImage3D");
gl_api_->glCompressedTexSubImage3DFn(target, level, xoffset, yoffset, zoffset,
width, height, depth, format, imageSize,
data);
@@ -6880,7 +6880,7 @@ void TraceGLApi::glCompressedTexSubImage3DRobustANGLEFn(GLenum target,
GLsizei dataSize,
const void* data) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glCompressedTexSubImage3DRobustANGLE")
+ "gpu", "TraceGLAPI::glCompressedTexSubImage3DRobustANGLE");
gl_api_->glCompressedTexSubImage3DRobustANGLEFn(
target, level, xoffset, yoffset, zoffset, width, height, depth, format,
imageSize, dataSize, data);
@@ -6891,7 +6891,7 @@ void TraceGLApi::glCopyBufferSubDataFn(GLenum readTarget,
GLintptr readOffset,
GLintptr writeOffset,
GLsizeiptr size) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopyBufferSubData")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopyBufferSubData");
gl_api_->glCopyBufferSubDataFn(readTarget, writeTarget, readOffset,
writeOffset, size);
}
@@ -6910,7 +6910,7 @@ void TraceGLApi::glCopySubTextureCHROMIUMFn(GLuint sourceId,
GLboolean unpackFlipY,
GLboolean unpackPremultiplyAlpha,
GLboolean unpackUnmultiplyAlpha) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopySubTextureCHROMIUM")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopySubTextureCHROMIUM");
gl_api_->glCopySubTextureCHROMIUMFn(
sourceId, sourceLevel, destTarget, destId, destLevel, xoffset, yoffset, x,
y, width, height, unpackFlipY, unpackPremultiplyAlpha,
@@ -6925,7 +6925,7 @@ void TraceGLApi::glCopyTexImage2DFn(GLenum target,
GLsizei width,
GLsizei height,
GLint border) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopyTexImage2D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopyTexImage2D");
gl_api_->glCopyTexImage2DFn(target, level, internalformat, x, y, width,
height, border);
}
@@ -6938,7 +6938,7 @@ void TraceGLApi::glCopyTexSubImage2DFn(GLenum target,
GLint y,
GLsizei width,
GLsizei height) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopyTexSubImage2D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopyTexSubImage2D");
gl_api_->glCopyTexSubImage2DFn(target, level, xoffset, yoffset, x, y, width,
height);
}
@@ -6952,7 +6952,7 @@ void TraceGLApi::glCopyTexSubImage3DFn(GLenum target,
GLint y,
GLsizei width,
GLsizei height) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopyTexSubImage3D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopyTexSubImage3D");
gl_api_->glCopyTexSubImage3DFn(target, level, xoffset, yoffset, zoffset, x, y,
width, height);
}
@@ -6967,14 +6967,14 @@ void TraceGLApi::glCopyTextureCHROMIUMFn(GLuint sourceId,
GLboolean unpackFlipY,
GLboolean unpackPremultiplyAlpha,
GLboolean unpackUnmultiplyAlpha) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopyTextureCHROMIUM")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopyTextureCHROMIUM");
gl_api_->glCopyTextureCHROMIUMFn(
sourceId, sourceLevel, destTarget, destId, destLevel, internalFormat,
destType, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
}
void TraceGLApi::glCoverageModulationNVFn(GLenum components) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCoverageModulationNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCoverageModulationNV");
gl_api_->glCoverageModulationNVFn(components);
}
@@ -6985,14 +6985,15 @@ void TraceGLApi::glCoverFillPathInstancedNVFn(GLsizei numPaths,
GLenum coverMode,
GLenum transformType,
const GLfloat* transformValues) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCoverFillPathInstancedNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glCoverFillPathInstancedNV");
gl_api_->glCoverFillPathInstancedNVFn(numPaths, pathNameType, paths, pathBase,
coverMode, transformType,
transformValues);
}
void TraceGLApi::glCoverFillPathNVFn(GLuint path, GLenum coverMode) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCoverFillPathNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCoverFillPathNV");
gl_api_->glCoverFillPathNVFn(path, coverMode);
}
@@ -7005,47 +7006,47 @@ void TraceGLApi::glCoverStrokePathInstancedNVFn(
GLenum transformType,
const GLfloat* transformValues) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glCoverStrokePathInstancedNV")
+ "TraceGLAPI::glCoverStrokePathInstancedNV");
gl_api_->glCoverStrokePathInstancedNVFn(numPaths, pathNameType, paths,
pathBase, coverMode, transformType,
transformValues);
}
void TraceGLApi::glCoverStrokePathNVFn(GLuint name, GLenum coverMode) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCoverStrokePathNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCoverStrokePathNV");
gl_api_->glCoverStrokePathNVFn(name, coverMode);
}
void TraceGLApi::glCreateMemoryObjectsEXTFn(GLsizei n, GLuint* memoryObjects) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCreateMemoryObjectsEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCreateMemoryObjectsEXT");
gl_api_->glCreateMemoryObjectsEXTFn(n, memoryObjects);
}
GLuint TraceGLApi::glCreateProgramFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCreateProgram")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCreateProgram");
return gl_api_->glCreateProgramFn();
}
GLuint TraceGLApi::glCreateShaderFn(GLenum type) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCreateShader")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCreateShader");
return gl_api_->glCreateShaderFn(type);
}
GLuint TraceGLApi::glCreateShaderProgramvFn(GLenum type,
GLsizei count,
const char* const* strings) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCreateShaderProgramv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCreateShaderProgramv");
return gl_api_->glCreateShaderProgramvFn(type, count, strings);
}
void TraceGLApi::glCullFaceFn(GLenum mode) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCullFace")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCullFace");
gl_api_->glCullFaceFn(mode);
}
void TraceGLApi::glDebugMessageCallbackFn(GLDEBUGPROC callback,
const void* userParam) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDebugMessageCallback")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDebugMessageCallback");
gl_api_->glDebugMessageCallbackFn(callback, userParam);
}
@@ -7055,7 +7056,7 @@ void TraceGLApi::glDebugMessageControlFn(GLenum source,
GLsizei count,
const GLuint* ids,
GLboolean enabled) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDebugMessageControl")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDebugMessageControl");
gl_api_->glDebugMessageControlFn(source, type, severity, count, ids, enabled);
}
@@ -7065,175 +7066,177 @@ void TraceGLApi::glDebugMessageInsertFn(GLenum source,
GLenum severity,
GLsizei length,
const char* buf) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDebugMessageInsert")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDebugMessageInsert");
gl_api_->glDebugMessageInsertFn(source, type, id, severity, length, buf);
}
void TraceGLApi::glDeleteBuffersARBFn(GLsizei n, const GLuint* buffers) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteBuffersARB")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteBuffersARB");
gl_api_->glDeleteBuffersARBFn(n, buffers);
}
void TraceGLApi::glDeleteFencesAPPLEFn(GLsizei n, const GLuint* fences) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteFencesAPPLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteFencesAPPLE");
gl_api_->glDeleteFencesAPPLEFn(n, fences);
}
void TraceGLApi::glDeleteFencesNVFn(GLsizei n, const GLuint* fences) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteFencesNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteFencesNV");
gl_api_->glDeleteFencesNVFn(n, fences);
}
void TraceGLApi::glDeleteFramebuffersEXTFn(GLsizei n,
const GLuint* framebuffers) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteFramebuffersEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteFramebuffersEXT");
gl_api_->glDeleteFramebuffersEXTFn(n, framebuffers);
}
void TraceGLApi::glDeleteMemoryObjectsEXTFn(GLsizei n,
const GLuint* memoryObjects) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteMemoryObjectsEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteMemoryObjectsEXT");
gl_api_->glDeleteMemoryObjectsEXTFn(n, memoryObjects);
}
void TraceGLApi::glDeletePathsNVFn(GLuint path, GLsizei range) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeletePathsNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeletePathsNV");
gl_api_->glDeletePathsNVFn(path, range);
}
void TraceGLApi::glDeleteProgramFn(GLuint program) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteProgram")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteProgram");
gl_api_->glDeleteProgramFn(program);
}
void TraceGLApi::glDeleteProgramPipelinesFn(GLsizei n,
const GLuint* pipelines) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteProgramPipelines")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteProgramPipelines");
gl_api_->glDeleteProgramPipelinesFn(n, pipelines);
}
void TraceGLApi::glDeleteQueriesFn(GLsizei n, const GLuint* ids) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteQueries")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteQueries");
gl_api_->glDeleteQueriesFn(n, ids);
}
void TraceGLApi::glDeleteRenderbuffersEXTFn(GLsizei n,
const GLuint* renderbuffers) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteRenderbuffersEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteRenderbuffersEXT");
gl_api_->glDeleteRenderbuffersEXTFn(n, renderbuffers);
}
void TraceGLApi::glDeleteSamplersFn(GLsizei n, const GLuint* samplers) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteSamplers")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteSamplers");
gl_api_->glDeleteSamplersFn(n, samplers);
}
void TraceGLApi::glDeleteSemaphoresEXTFn(GLsizei n, const GLuint* semaphores) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteSemaphoresEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteSemaphoresEXT");
gl_api_->glDeleteSemaphoresEXTFn(n, semaphores);
}
void TraceGLApi::glDeleteShaderFn(GLuint shader) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteShader")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteShader");
gl_api_->glDeleteShaderFn(shader);
}
void TraceGLApi::glDeleteSyncFn(GLsync sync) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteSync")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteSync");
gl_api_->glDeleteSyncFn(sync);
}
void TraceGLApi::glDeleteSyncAPPLEFn(GLsync sync) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteSyncAPPLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteSyncAPPLE");
gl_api_->glDeleteSyncAPPLEFn(sync);
}
void TraceGLApi::glDeleteTexturesFn(GLsizei n, const GLuint* textures) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteTextures")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteTextures");
gl_api_->glDeleteTexturesFn(n, textures);
}
void TraceGLApi::glDeleteTransformFeedbacksFn(GLsizei n, const GLuint* ids) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteTransformFeedbacks")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glDeleteTransformFeedbacks");
gl_api_->glDeleteTransformFeedbacksFn(n, ids);
}
void TraceGLApi::glDeleteVertexArraysOESFn(GLsizei n, const GLuint* arrays) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteVertexArraysOES")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDeleteVertexArraysOES");
gl_api_->glDeleteVertexArraysOESFn(n, arrays);
}
void TraceGLApi::glDepthFuncFn(GLenum func) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDepthFunc")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDepthFunc");
gl_api_->glDepthFuncFn(func);
}
void TraceGLApi::glDepthMaskFn(GLboolean flag) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDepthMask")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDepthMask");
gl_api_->glDepthMaskFn(flag);
}
void TraceGLApi::glDepthRangeFn(GLclampd zNear, GLclampd zFar) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDepthRange")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDepthRange");
gl_api_->glDepthRangeFn(zNear, zFar);
}
void TraceGLApi::glDepthRangefFn(GLclampf zNear, GLclampf zFar) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDepthRangef")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDepthRangef");
gl_api_->glDepthRangefFn(zNear, zFar);
}
void TraceGLApi::glDetachShaderFn(GLuint program, GLuint shader) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDetachShader")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDetachShader");
gl_api_->glDetachShaderFn(program, shader);
}
void TraceGLApi::glDisableFn(GLenum cap) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDisable")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDisable");
gl_api_->glDisableFn(cap);
}
void TraceGLApi::glDisableExtensionANGLEFn(const char* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDisableExtensionANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDisableExtensionANGLE");
gl_api_->glDisableExtensionANGLEFn(name);
}
void TraceGLApi::glDisableiOESFn(GLenum target, GLuint index) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDisableiOES")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDisableiOES");
gl_api_->glDisableiOESFn(target, index);
}
void TraceGLApi::glDisableVertexAttribArrayFn(GLuint index) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDisableVertexAttribArray")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glDisableVertexAttribArray");
gl_api_->glDisableVertexAttribArrayFn(index);
}
void TraceGLApi::glDiscardFramebufferEXTFn(GLenum target,
GLsizei numAttachments,
const GLenum* attachments) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDiscardFramebufferEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDiscardFramebufferEXT");
gl_api_->glDiscardFramebufferEXTFn(target, numAttachments, attachments);
}
void TraceGLApi::glDispatchComputeFn(GLuint numGroupsX,
GLuint numGroupsY,
GLuint numGroupsZ) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDispatchCompute")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDispatchCompute");
gl_api_->glDispatchComputeFn(numGroupsX, numGroupsY, numGroupsZ);
}
void TraceGLApi::glDispatchComputeIndirectFn(GLintptr indirect) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDispatchComputeIndirect")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDispatchComputeIndirect");
gl_api_->glDispatchComputeIndirectFn(indirect);
}
void TraceGLApi::glDrawArraysFn(GLenum mode, GLint first, GLsizei count) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawArrays")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawArrays");
gl_api_->glDrawArraysFn(mode, first, count);
}
void TraceGLApi::glDrawArraysIndirectFn(GLenum mode, const void* indirect) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawArraysIndirect")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawArraysIndirect");
gl_api_->glDrawArraysIndirectFn(mode, indirect);
}
@@ -7241,7 +7244,8 @@ void TraceGLApi::glDrawArraysInstancedANGLEFn(GLenum mode,
GLint first,
GLsizei count,
GLsizei primcount) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawArraysInstancedANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glDrawArraysInstancedANGLE");
gl_api_->glDrawArraysInstancedANGLEFn(mode, first, count, primcount);
}
@@ -7251,18 +7255,18 @@ void TraceGLApi::glDrawArraysInstancedBaseInstanceANGLEFn(GLenum mode,
GLsizei primcount,
GLuint baseinstance) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glDrawArraysInstancedBaseInstanceANGLE")
+ "gpu", "TraceGLAPI::glDrawArraysInstancedBaseInstanceANGLE");
gl_api_->glDrawArraysInstancedBaseInstanceANGLEFn(mode, first, count,
primcount, baseinstance);
}
void TraceGLApi::glDrawBufferFn(GLenum mode) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawBuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawBuffer");
gl_api_->glDrawBufferFn(mode);
}
void TraceGLApi::glDrawBuffersARBFn(GLsizei n, const GLenum* bufs) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawBuffersARB")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawBuffersARB");
gl_api_->glDrawBuffersARBFn(n, bufs);
}
@@ -7270,14 +7274,14 @@ void TraceGLApi::glDrawElementsFn(GLenum mode,
GLsizei count,
GLenum type,
const void* indices) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawElements")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawElements");
gl_api_->glDrawElementsFn(mode, count, type, indices);
}
void TraceGLApi::glDrawElementsIndirectFn(GLenum mode,
GLenum type,
const void* indirect) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawElementsIndirect")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawElementsIndirect");
gl_api_->glDrawElementsIndirectFn(mode, type, indirect);
}
@@ -7287,7 +7291,7 @@ void TraceGLApi::glDrawElementsInstancedANGLEFn(GLenum mode,
const void* indices,
GLsizei primcount) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glDrawElementsInstancedANGLE")
+ "TraceGLAPI::glDrawElementsInstancedANGLE");
gl_api_->glDrawElementsInstancedANGLEFn(mode, count, type, indices,
primcount);
}
@@ -7301,7 +7305,7 @@ void TraceGLApi::glDrawElementsInstancedBaseVertexBaseInstanceANGLEFn(
GLint baseVertex,
GLuint baseInstance) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glDrawElementsInstancedBaseVertexBaseInstanceANGLE")
+ "gpu", "TraceGLAPI::glDrawElementsInstancedBaseVertexBaseInstanceANGLE");
gl_api_->glDrawElementsInstancedBaseVertexBaseInstanceANGLEFn(
mode, count, type, indices, primcount, baseVertex, baseInstance);
}
@@ -7312,95 +7316,95 @@ void TraceGLApi::glDrawRangeElementsFn(GLenum mode,
GLsizei count,
GLenum type,
const void* indices) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawRangeElements")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glDrawRangeElements");
gl_api_->glDrawRangeElementsFn(mode, start, end, count, type, indices);
}
void TraceGLApi::glEGLImageTargetRenderbufferStorageOESFn(GLenum target,
GLeglImageOES image) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glEGLImageTargetRenderbufferStorageOES")
+ "gpu", "TraceGLAPI::glEGLImageTargetRenderbufferStorageOES");
gl_api_->glEGLImageTargetRenderbufferStorageOESFn(target, image);
}
void TraceGLApi::glEGLImageTargetTexture2DOESFn(GLenum target,
GLeglImageOES image) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glEGLImageTargetTexture2DOES")
+ "TraceGLAPI::glEGLImageTargetTexture2DOES");
gl_api_->glEGLImageTargetTexture2DOESFn(target, image);
}
void TraceGLApi::glEnableFn(GLenum cap) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEnable")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEnable");
gl_api_->glEnableFn(cap);
}
void TraceGLApi::glEnableiOESFn(GLenum target, GLuint index) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEnableiOES")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEnableiOES");
gl_api_->glEnableiOESFn(target, index);
}
void TraceGLApi::glEnableVertexAttribArrayFn(GLuint index) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEnableVertexAttribArray")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEnableVertexAttribArray");
gl_api_->glEnableVertexAttribArrayFn(index);
}
void TraceGLApi::glEndQueryFn(GLenum target) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEndQuery")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEndQuery");
gl_api_->glEndQueryFn(target);
}
void TraceGLApi::glEndTilingQCOMFn(GLbitfield preserveMask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEndTilingQCOM")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEndTilingQCOM");
gl_api_->glEndTilingQCOMFn(preserveMask);
}
void TraceGLApi::glEndTransformFeedbackFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEndTransformFeedback")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glEndTransformFeedback");
gl_api_->glEndTransformFeedbackFn();
}
GLsync TraceGLApi::glFenceSyncFn(GLenum condition, GLbitfield flags) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFenceSync")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFenceSync");
return gl_api_->glFenceSyncFn(condition, flags);
}
GLsync TraceGLApi::glFenceSyncAPPLEFn(GLenum condition, GLbitfield flags) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFenceSyncAPPLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFenceSyncAPPLE");
return gl_api_->glFenceSyncAPPLEFn(condition, flags);
}
void TraceGLApi::glFinishFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFinish")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFinish");
gl_api_->glFinishFn();
}
void TraceGLApi::glFinishFenceAPPLEFn(GLuint fence) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFinishFenceAPPLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFinishFenceAPPLE");
gl_api_->glFinishFenceAPPLEFn(fence);
}
void TraceGLApi::glFinishFenceNVFn(GLuint fence) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFinishFenceNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFinishFenceNV");
gl_api_->glFinishFenceNVFn(fence);
}
void TraceGLApi::glFlushFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFlush")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFlush");
gl_api_->glFlushFn();
}
void TraceGLApi::glFlushMappedBufferRangeFn(GLenum target,
GLintptr offset,
GLsizeiptr length) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFlushMappedBufferRange")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFlushMappedBufferRange");
gl_api_->glFlushMappedBufferRangeFn(target, offset, length);
}
void TraceGLApi::glFramebufferParameteriFn(GLenum target,
GLenum pname,
GLint param) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFramebufferParameteri")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFramebufferParameteri");
gl_api_->glFramebufferParameteriFn(target, pname, param);
}
@@ -7409,7 +7413,7 @@ void TraceGLApi::glFramebufferRenderbufferEXTFn(GLenum target,
GLenum renderbuffertarget,
GLuint renderbuffer) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glFramebufferRenderbufferEXT")
+ "TraceGLAPI::glFramebufferRenderbufferEXT");
gl_api_->glFramebufferRenderbufferEXTFn(target, attachment,
renderbuffertarget, renderbuffer);
}
@@ -7419,7 +7423,7 @@ void TraceGLApi::glFramebufferTexture2DEXTFn(GLenum target,
GLenum textarget,
GLuint texture,
GLint level) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFramebufferTexture2DEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFramebufferTexture2DEXT");
gl_api_->glFramebufferTexture2DEXTFn(target, attachment, textarget, texture,
level);
}
@@ -7431,7 +7435,7 @@ void TraceGLApi::glFramebufferTexture2DMultisampleEXTFn(GLenum target,
GLint level,
GLsizei samples) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glFramebufferTexture2DMultisampleEXT")
+ "gpu", "TraceGLAPI::glFramebufferTexture2DMultisampleEXT");
gl_api_->glFramebufferTexture2DMultisampleEXTFn(target, attachment, textarget,
texture, level, samples);
}
@@ -7441,7 +7445,7 @@ void TraceGLApi::glFramebufferTextureLayerFn(GLenum target,
GLuint texture,
GLint level,
GLint layer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFramebufferTextureLayer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFramebufferTextureLayer");
gl_api_->glFramebufferTextureLayerFn(target, attachment, texture, level,
layer);
}
@@ -7453,83 +7457,83 @@ void TraceGLApi::glFramebufferTextureMultiviewOVRFn(GLenum target,
GLint baseViewIndex,
GLsizei numViews) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glFramebufferTextureMultiviewOVR")
+ "TraceGLAPI::glFramebufferTextureMultiviewOVR");
gl_api_->glFramebufferTextureMultiviewOVRFn(target, attachment, texture,
level, baseViewIndex, numViews);
}
void TraceGLApi::glFrontFaceFn(GLenum mode) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFrontFace")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glFrontFace");
gl_api_->glFrontFaceFn(mode);
}
void TraceGLApi::glGenBuffersARBFn(GLsizei n, GLuint* buffers) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenBuffersARB")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenBuffersARB");
gl_api_->glGenBuffersARBFn(n, buffers);
}
void TraceGLApi::glGenerateMipmapEXTFn(GLenum target) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenerateMipmapEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenerateMipmapEXT");
gl_api_->glGenerateMipmapEXTFn(target);
}
void TraceGLApi::glGenFencesAPPLEFn(GLsizei n, GLuint* fences) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenFencesAPPLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenFencesAPPLE");
gl_api_->glGenFencesAPPLEFn(n, fences);
}
void TraceGLApi::glGenFencesNVFn(GLsizei n, GLuint* fences) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenFencesNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenFencesNV");
gl_api_->glGenFencesNVFn(n, fences);
}
void TraceGLApi::glGenFramebuffersEXTFn(GLsizei n, GLuint* framebuffers) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenFramebuffersEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenFramebuffersEXT");
gl_api_->glGenFramebuffersEXTFn(n, framebuffers);
}
GLuint TraceGLApi::glGenPathsNVFn(GLsizei range) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenPathsNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenPathsNV");
return gl_api_->glGenPathsNVFn(range);
}
GLuint TraceGLApi::glGenProgramPipelinesFn(GLsizei n, GLuint* pipelines) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenProgramPipelines")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenProgramPipelines");
return gl_api_->glGenProgramPipelinesFn(n, pipelines);
}
void TraceGLApi::glGenQueriesFn(GLsizei n, GLuint* ids) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenQueries")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenQueries");
gl_api_->glGenQueriesFn(n, ids);
}
void TraceGLApi::glGenRenderbuffersEXTFn(GLsizei n, GLuint* renderbuffers) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenRenderbuffersEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenRenderbuffersEXT");
gl_api_->glGenRenderbuffersEXTFn(n, renderbuffers);
}
void TraceGLApi::glGenSamplersFn(GLsizei n, GLuint* samplers) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenSamplers")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenSamplers");
gl_api_->glGenSamplersFn(n, samplers);
}
void TraceGLApi::glGenSemaphoresEXTFn(GLsizei n, GLuint* semaphores) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenSemaphoresEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenSemaphoresEXT");
gl_api_->glGenSemaphoresEXTFn(n, semaphores);
}
void TraceGLApi::glGenTexturesFn(GLsizei n, GLuint* textures) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenTextures")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenTextures");
gl_api_->glGenTexturesFn(n, textures);
}
void TraceGLApi::glGenTransformFeedbacksFn(GLsizei n, GLuint* ids) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenTransformFeedbacks")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenTransformFeedbacks");
gl_api_->glGenTransformFeedbacksFn(n, ids);
}
void TraceGLApi::glGenVertexArraysOESFn(GLsizei n, GLuint* arrays) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenVertexArraysOES")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGenVertexArraysOES");
gl_api_->glGenVertexArraysOESFn(n, arrays);
}
@@ -7540,7 +7544,7 @@ void TraceGLApi::glGetActiveAttribFn(GLuint program,
GLint* size,
GLenum* type,
char* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetActiveAttrib")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetActiveAttrib");
gl_api_->glGetActiveAttribFn(program, index, bufsize, length, size, type,
name);
}
@@ -7552,7 +7556,7 @@ void TraceGLApi::glGetActiveUniformFn(GLuint program,
GLint* size,
GLenum* type,
char* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetActiveUniform")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetActiveUniform");
gl_api_->glGetActiveUniformFn(program, index, bufsize, length, size, type,
name);
}
@@ -7561,7 +7565,7 @@ void TraceGLApi::glGetActiveUniformBlockivFn(GLuint program,
GLuint uniformBlockIndex,
GLenum pname,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetActiveUniformBlockiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetActiveUniformBlockiv");
gl_api_->glGetActiveUniformBlockivFn(program, uniformBlockIndex, pname,
params);
}
@@ -7574,7 +7578,7 @@ void TraceGLApi::glGetActiveUniformBlockivRobustANGLEFn(
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetActiveUniformBlockivRobustANGLE")
+ "gpu", "TraceGLAPI::glGetActiveUniformBlockivRobustANGLE");
gl_api_->glGetActiveUniformBlockivRobustANGLEFn(
program, uniformBlockIndex, pname, bufSize, length, params);
}
@@ -7585,7 +7589,7 @@ void TraceGLApi::glGetActiveUniformBlockNameFn(GLuint program,
GLsizei* length,
char* uniformBlockName) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetActiveUniformBlockName")
+ "TraceGLAPI::glGetActiveUniformBlockName");
gl_api_->glGetActiveUniformBlockNameFn(program, uniformBlockIndex, bufSize,
length, uniformBlockName);
}
@@ -7595,7 +7599,7 @@ void TraceGLApi::glGetActiveUniformsivFn(GLuint program,
const GLuint* uniformIndices,
GLenum pname,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetActiveUniformsiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetActiveUniformsiv");
gl_api_->glGetActiveUniformsivFn(program, uniformCount, uniformIndices, pname,
params);
}
@@ -7604,19 +7608,19 @@ void TraceGLApi::glGetAttachedShadersFn(GLuint program,
GLsizei maxcount,
GLsizei* count,
GLuint* shaders) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetAttachedShaders")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetAttachedShaders");
gl_api_->glGetAttachedShadersFn(program, maxcount, count, shaders);
}
GLint TraceGLApi::glGetAttribLocationFn(GLuint program, const char* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetAttribLocation")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetAttribLocation");
return gl_api_->glGetAttribLocationFn(program, name);
}
void TraceGLApi::glGetBooleani_vFn(GLenum target,
GLuint index,
GLboolean* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetBooleani_v")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetBooleani_v");
gl_api_->glGetBooleani_vFn(target, index, data);
}
@@ -7625,12 +7629,13 @@ void TraceGLApi::glGetBooleani_vRobustANGLEFn(GLenum target,
GLsizei bufSize,
GLsizei* length,
GLboolean* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetBooleani_vRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glGetBooleani_vRobustANGLE");
gl_api_->glGetBooleani_vRobustANGLEFn(target, index, bufSize, length, data);
}
void TraceGLApi::glGetBooleanvFn(GLenum pname, GLboolean* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetBooleanv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetBooleanv");
gl_api_->glGetBooleanvFn(pname, params);
}
@@ -7638,7 +7643,7 @@ void TraceGLApi::glGetBooleanvRobustANGLEFn(GLenum pname,
GLsizei bufSize,
GLsizei* length,
GLboolean* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetBooleanvRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetBooleanvRobustANGLE");
gl_api_->glGetBooleanvRobustANGLEFn(pname, bufSize, length, data);
}
@@ -7648,7 +7653,7 @@ void TraceGLApi::glGetBufferParameteri64vRobustANGLEFn(GLenum target,
GLsizei* length,
GLint64* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetBufferParameteri64vRobustANGLE")
+ "gpu", "TraceGLAPI::glGetBufferParameteri64vRobustANGLE");
gl_api_->glGetBufferParameteri64vRobustANGLEFn(target, pname, bufSize, length,
params);
}
@@ -7656,7 +7661,7 @@ void TraceGLApi::glGetBufferParameteri64vRobustANGLEFn(GLenum target,
void TraceGLApi::glGetBufferParameterivFn(GLenum target,
GLenum pname,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetBufferParameteriv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetBufferParameteriv");
gl_api_->glGetBufferParameterivFn(target, pname, params);
}
@@ -7665,8 +7670,8 @@ void TraceGLApi::glGetBufferParameterivRobustANGLEFn(GLenum target,
GLsizei bufSize,
GLsizei* length,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetBufferParameterivRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0(
+ "gpu", "TraceGLAPI::glGetBufferParameterivRobustANGLE");
gl_api_->glGetBufferParameterivRobustANGLEFn(target, pname, bufSize, length,
params);
}
@@ -7677,7 +7682,7 @@ void TraceGLApi::glGetBufferPointervRobustANGLEFn(GLenum target,
GLsizei* length,
void** params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetBufferPointervRobustANGLE")
+ "TraceGLAPI::glGetBufferPointervRobustANGLE");
gl_api_->glGetBufferPointervRobustANGLEFn(target, pname, bufSize, length,
params);
}
@@ -7690,23 +7695,23 @@ GLuint TraceGLApi::glGetDebugMessageLogFn(GLuint count,
GLenum* severities,
GLsizei* lengths,
char* messageLog) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetDebugMessageLog")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetDebugMessageLog");
return gl_api_->glGetDebugMessageLogFn(count, bufSize, sources, types, ids,
severities, lengths, messageLog);
}
GLenum TraceGLApi::glGetErrorFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetError")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetError");
return gl_api_->glGetErrorFn();
}
void TraceGLApi::glGetFenceivNVFn(GLuint fence, GLenum pname, GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFenceivNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFenceivNV");
gl_api_->glGetFenceivNVFn(fence, pname, params);
}
void TraceGLApi::glGetFloatvFn(GLenum pname, GLfloat* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFloatv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFloatv");
gl_api_->glGetFloatvFn(pname, params);
}
@@ -7714,17 +7719,17 @@ void TraceGLApi::glGetFloatvRobustANGLEFn(GLenum pname,
GLsizei bufSize,
GLsizei* length,
GLfloat* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFloatvRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFloatvRobustANGLE");
gl_api_->glGetFloatvRobustANGLEFn(pname, bufSize, length, data);
}
GLint TraceGLApi::glGetFragDataIndexFn(GLuint program, const char* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFragDataIndex")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFragDataIndex");
return gl_api_->glGetFragDataIndexFn(program, name);
}
GLint TraceGLApi::glGetFragDataLocationFn(GLuint program, const char* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFragDataLocation")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFragDataLocation");
return gl_api_->glGetFragDataLocationFn(program, name);
}
@@ -7733,7 +7738,7 @@ void TraceGLApi::glGetFramebufferAttachmentParameterivEXTFn(GLenum target,
GLenum pname,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetFramebufferAttachmentParameterivEXT")
+ "gpu", "TraceGLAPI::glGetFramebufferAttachmentParameterivEXT");
gl_api_->glGetFramebufferAttachmentParameterivEXTFn(target, attachment, pname,
params);
}
@@ -7746,7 +7751,7 @@ void TraceGLApi::glGetFramebufferAttachmentParameterivRobustANGLEFn(
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetFramebufferAttachmentParameterivRobustANGLE")
+ "gpu", "TraceGLAPI::glGetFramebufferAttachmentParameterivRobustANGLE");
gl_api_->glGetFramebufferAttachmentParameterivRobustANGLEFn(
target, attachment, pname, bufSize, length, params);
}
@@ -7755,7 +7760,7 @@ void TraceGLApi::glGetFramebufferParameterivFn(GLenum target,
GLenum pname,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetFramebufferParameteriv")
+ "TraceGLAPI::glGetFramebufferParameteriv");
gl_api_->glGetFramebufferParameterivFn(target, pname, params);
}
@@ -7765,21 +7770,21 @@ void TraceGLApi::glGetFramebufferParameterivRobustANGLEFn(GLenum target,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetFramebufferParameterivRobustANGLE")
+ "gpu", "TraceGLAPI::glGetFramebufferParameterivRobustANGLE");
gl_api_->glGetFramebufferParameterivRobustANGLEFn(target, pname, bufSize,
length, params);
}
GLenum TraceGLApi::glGetGraphicsResetStatusARBFn(void) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetGraphicsResetStatusARB")
+ "TraceGLAPI::glGetGraphicsResetStatusARB");
return gl_api_->glGetGraphicsResetStatusARBFn();
}
void TraceGLApi::glGetInteger64i_vFn(GLenum target,
GLuint index,
GLint64* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetInteger64i_v")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetInteger64i_v");
gl_api_->glGetInteger64i_vFn(target, index, data);
}
@@ -7789,12 +7794,12 @@ void TraceGLApi::glGetInteger64i_vRobustANGLEFn(GLenum target,
GLsizei* length,
GLint64* data) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetInteger64i_vRobustANGLE")
+ "TraceGLAPI::glGetInteger64i_vRobustANGLE");
gl_api_->glGetInteger64i_vRobustANGLEFn(target, index, bufSize, length, data);
}
void TraceGLApi::glGetInteger64vFn(GLenum pname, GLint64* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetInteger64v")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetInteger64v");
gl_api_->glGetInteger64vFn(pname, params);
}
@@ -7802,12 +7807,13 @@ void TraceGLApi::glGetInteger64vRobustANGLEFn(GLenum pname,
GLsizei bufSize,
GLsizei* length,
GLint64* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetInteger64vRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glGetInteger64vRobustANGLE");
gl_api_->glGetInteger64vRobustANGLEFn(pname, bufSize, length, data);
}
void TraceGLApi::glGetIntegeri_vFn(GLenum target, GLuint index, GLint* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetIntegeri_v")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetIntegeri_v");
gl_api_->glGetIntegeri_vFn(target, index, data);
}
@@ -7816,12 +7822,13 @@ void TraceGLApi::glGetIntegeri_vRobustANGLEFn(GLenum target,
GLsizei bufSize,
GLsizei* length,
GLint* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetIntegeri_vRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glGetIntegeri_vRobustANGLE");
gl_api_->glGetIntegeri_vRobustANGLEFn(target, index, bufSize, length, data);
}
void TraceGLApi::glGetIntegervFn(GLenum pname, GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetIntegerv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetIntegerv");
gl_api_->glGetIntegervFn(pname, params);
}
@@ -7829,7 +7836,7 @@ void TraceGLApi::glGetIntegervRobustANGLEFn(GLenum pname,
GLsizei bufSize,
GLsizei* length,
GLint* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetIntegervRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetIntegervRobustANGLE");
gl_api_->glGetIntegervRobustANGLEFn(pname, bufSize, length, data);
}
@@ -7838,7 +7845,7 @@ void TraceGLApi::glGetInternalformativFn(GLenum target,
GLenum pname,
GLsizei bufSize,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetInternalformativ")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetInternalformativ");
gl_api_->glGetInternalformativFn(target, internalformat, pname, bufSize,
params);
}
@@ -7850,7 +7857,7 @@ void TraceGLApi::glGetInternalformativRobustANGLEFn(GLenum target,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetInternalformativRobustANGLE")
+ "TraceGLAPI::glGetInternalformativRobustANGLE");
gl_api_->glGetInternalformativRobustANGLEFn(target, internalformat, pname,
bufSize, length, params);
}
@@ -7862,7 +7869,7 @@ void TraceGLApi::glGetInternalformatSampleivNVFn(GLenum target,
GLsizei bufSize,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetInternalformatSampleivNV")
+ "TraceGLAPI::glGetInternalformatSampleivNV");
gl_api_->glGetInternalformatSampleivNVFn(target, internalformat, samples,
pname, bufSize, params);
}
@@ -7870,7 +7877,7 @@ void TraceGLApi::glGetInternalformatSampleivNVFn(GLenum target,
void TraceGLApi::glGetMultisamplefvFn(GLenum pname,
GLuint index,
GLfloat* val) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetMultisamplefv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetMultisamplefv");
gl_api_->glGetMultisamplefvFn(pname, index, val);
}
@@ -7880,7 +7887,7 @@ void TraceGLApi::glGetMultisamplefvRobustANGLEFn(GLenum pname,
GLsizei* length,
GLfloat* val) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetMultisamplefvRobustANGLE")
+ "TraceGLAPI::glGetMultisamplefvRobustANGLE");
gl_api_->glGetMultisamplefvRobustANGLEFn(pname, index, bufSize, length, val);
}
@@ -7889,7 +7896,8 @@ void TraceGLApi::glGetnUniformfvRobustANGLEFn(GLuint program,
GLsizei bufSize,
GLsizei* length,
GLfloat* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetnUniformfvRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glGetnUniformfvRobustANGLE");
gl_api_->glGetnUniformfvRobustANGLEFn(program, location, bufSize, length,
params);
}
@@ -7899,7 +7907,8 @@ void TraceGLApi::glGetnUniformivRobustANGLEFn(GLuint program,
GLsizei bufSize,
GLsizei* length,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetnUniformivRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glGetnUniformivRobustANGLE");
gl_api_->glGetnUniformivRobustANGLEFn(program, location, bufSize, length,
params);
}
@@ -7910,7 +7919,7 @@ void TraceGLApi::glGetnUniformuivRobustANGLEFn(GLuint program,
GLsizei* length,
GLuint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetnUniformuivRobustANGLE")
+ "TraceGLAPI::glGetnUniformuivRobustANGLE");
gl_api_->glGetnUniformuivRobustANGLEFn(program, location, bufSize, length,
params);
}
@@ -7920,7 +7929,7 @@ void TraceGLApi::glGetObjectLabelFn(GLenum identifier,
GLsizei bufSize,
GLsizei* length,
char* label) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetObjectLabel")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetObjectLabel");
gl_api_->glGetObjectLabelFn(identifier, name, bufSize, length, label);
}
@@ -7928,12 +7937,12 @@ void TraceGLApi::glGetObjectPtrLabelFn(void* ptr,
GLsizei bufSize,
GLsizei* length,
char* label) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetObjectPtrLabel")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetObjectPtrLabel");
gl_api_->glGetObjectPtrLabelFn(ptr, bufSize, length, label);
}
void TraceGLApi::glGetPointervFn(GLenum pname, void** params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetPointerv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetPointerv");
gl_api_->glGetPointervFn(pname, params);
}
@@ -7942,7 +7951,7 @@ void TraceGLApi::glGetPointervRobustANGLERobustANGLEFn(GLenum pname,
GLsizei* length,
void** params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetPointervRobustANGLERobustANGLE")
+ "gpu", "TraceGLAPI::glGetPointervRobustANGLERobustANGLE");
gl_api_->glGetPointervRobustANGLERobustANGLEFn(pname, bufSize, length,
params);
}
@@ -7952,7 +7961,7 @@ void TraceGLApi::glGetProgramBinaryFn(GLuint program,
GLsizei* length,
GLenum* binaryFormat,
GLvoid* binary) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramBinary")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramBinary");
gl_api_->glGetProgramBinaryFn(program, bufSize, length, binaryFormat, binary);
}
@@ -7960,7 +7969,7 @@ void TraceGLApi::glGetProgramInfoLogFn(GLuint program,
GLsizei bufsize,
GLsizei* length,
char* infolog) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramInfoLog")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramInfoLog");
gl_api_->glGetProgramInfoLogFn(program, bufsize, length, infolog);
}
@@ -7968,7 +7977,7 @@ void TraceGLApi::glGetProgramInterfaceivFn(GLuint program,
GLenum programInterface,
GLenum pname,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramInterfaceiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramInterfaceiv");
gl_api_->glGetProgramInterfaceivFn(program, programInterface, pname, params);
}
@@ -7979,13 +7988,13 @@ void TraceGLApi::glGetProgramInterfaceivRobustANGLEFn(GLuint program,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetProgramInterfaceivRobustANGLE")
+ "gpu", "TraceGLAPI::glGetProgramInterfaceivRobustANGLE");
gl_api_->glGetProgramInterfaceivRobustANGLEFn(program, programInterface,
pname, bufSize, length, params);
}
void TraceGLApi::glGetProgramivFn(GLuint program, GLenum pname, GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramiv");
gl_api_->glGetProgramivFn(program, pname, params);
}
@@ -7994,7 +8003,7 @@ void TraceGLApi::glGetProgramivRobustANGLEFn(GLuint program,
GLsizei bufSize,
GLsizei* length,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramivRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramivRobustANGLE");
gl_api_->glGetProgramivRobustANGLEFn(program, pname, bufSize, length, params);
}
@@ -8003,21 +8012,21 @@ void TraceGLApi::glGetProgramPipelineInfoLogFn(GLuint pipeline,
GLsizei* length,
GLchar* infoLog) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetProgramPipelineInfoLog")
+ "TraceGLAPI::glGetProgramPipelineInfoLog");
gl_api_->glGetProgramPipelineInfoLogFn(pipeline, bufSize, length, infoLog);
}
void TraceGLApi::glGetProgramPipelineivFn(GLuint pipeline,
GLenum pname,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramPipelineiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramPipelineiv");
gl_api_->glGetProgramPipelineivFn(pipeline, pname, params);
}
GLuint TraceGLApi::glGetProgramResourceIndexFn(GLuint program,
GLenum programInterface,
const GLchar* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramResourceIndex")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramResourceIndex");
return gl_api_->glGetProgramResourceIndexFn(program, programInterface, name);
}
@@ -8029,7 +8038,7 @@ void TraceGLApi::glGetProgramResourceivFn(GLuint program,
GLsizei bufSize,
GLsizei* length,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramResourceiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramResourceiv");
gl_api_->glGetProgramResourceivFn(program, programInterface, index, propCount,
props, bufSize, length, params);
}
@@ -8038,7 +8047,7 @@ GLint TraceGLApi::glGetProgramResourceLocationFn(GLuint program,
GLenum programInterface,
const char* name) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetProgramResourceLocation")
+ "TraceGLAPI::glGetProgramResourceLocation");
return gl_api_->glGetProgramResourceLocationFn(program, programInterface,
name);
}
@@ -8049,13 +8058,13 @@ void TraceGLApi::glGetProgramResourceNameFn(GLuint program,
GLsizei bufSize,
GLsizei* length,
GLchar* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramResourceName")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetProgramResourceName");
gl_api_->glGetProgramResourceNameFn(program, programInterface, index, bufSize,
length, name);
}
void TraceGLApi::glGetQueryivFn(GLenum target, GLenum pname, GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryiv");
gl_api_->glGetQueryivFn(target, pname, params);
}
@@ -8064,14 +8073,14 @@ void TraceGLApi::glGetQueryivRobustANGLEFn(GLenum target,
GLsizei bufSize,
GLsizei* length,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryivRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryivRobustANGLE");
gl_api_->glGetQueryivRobustANGLEFn(target, pname, bufSize, length, params);
}
void TraceGLApi::glGetQueryObjecti64vFn(GLuint id,
GLenum pname,
GLint64* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryObjecti64v")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryObjecti64v");
gl_api_->glGetQueryObjecti64vFn(id, pname, params);
}
@@ -8081,13 +8090,13 @@ void TraceGLApi::glGetQueryObjecti64vRobustANGLEFn(GLuint id,
GLsizei* length,
GLint64* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetQueryObjecti64vRobustANGLE")
+ "TraceGLAPI::glGetQueryObjecti64vRobustANGLE");
gl_api_->glGetQueryObjecti64vRobustANGLEFn(id, pname, bufSize, length,
params);
}
void TraceGLApi::glGetQueryObjectivFn(GLuint id, GLenum pname, GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryObjectiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryObjectiv");
gl_api_->glGetQueryObjectivFn(id, pname, params);
}
@@ -8097,14 +8106,14 @@ void TraceGLApi::glGetQueryObjectivRobustANGLEFn(GLuint id,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetQueryObjectivRobustANGLE")
+ "TraceGLAPI::glGetQueryObjectivRobustANGLE");
gl_api_->glGetQueryObjectivRobustANGLEFn(id, pname, bufSize, length, params);
}
void TraceGLApi::glGetQueryObjectui64vFn(GLuint id,
GLenum pname,
GLuint64* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryObjectui64v")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryObjectui64v");
gl_api_->glGetQueryObjectui64vFn(id, pname, params);
}
@@ -8114,7 +8123,7 @@ void TraceGLApi::glGetQueryObjectui64vRobustANGLEFn(GLuint id,
GLsizei* length,
GLuint64* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetQueryObjectui64vRobustANGLE")
+ "TraceGLAPI::glGetQueryObjectui64vRobustANGLE");
gl_api_->glGetQueryObjectui64vRobustANGLEFn(id, pname, bufSize, length,
params);
}
@@ -8122,7 +8131,7 @@ void TraceGLApi::glGetQueryObjectui64vRobustANGLEFn(GLuint id,
void TraceGLApi::glGetQueryObjectuivFn(GLuint id,
GLenum pname,
GLuint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryObjectuiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryObjectuiv");
gl_api_->glGetQueryObjectuivFn(id, pname, params);
}
@@ -8132,7 +8141,7 @@ void TraceGLApi::glGetQueryObjectuivRobustANGLEFn(GLuint id,
GLsizei* length,
GLuint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetQueryObjectuivRobustANGLE")
+ "TraceGLAPI::glGetQueryObjectuivRobustANGLE");
gl_api_->glGetQueryObjectuivRobustANGLEFn(id, pname, bufSize, length, params);
}
@@ -8140,7 +8149,7 @@ void TraceGLApi::glGetRenderbufferParameterivEXTFn(GLenum target,
GLenum pname,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetRenderbufferParameterivEXT")
+ "TraceGLAPI::glGetRenderbufferParameterivEXT");
gl_api_->glGetRenderbufferParameterivEXTFn(target, pname, params);
}
@@ -8150,7 +8159,7 @@ void TraceGLApi::glGetRenderbufferParameterivRobustANGLEFn(GLenum target,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetRenderbufferParameterivRobustANGLE")
+ "gpu", "TraceGLAPI::glGetRenderbufferParameterivRobustANGLE");
gl_api_->glGetRenderbufferParameterivRobustANGLEFn(target, pname, bufSize,
length, params);
}
@@ -8158,7 +8167,7 @@ void TraceGLApi::glGetRenderbufferParameterivRobustANGLEFn(GLenum target,
void TraceGLApi::glGetSamplerParameterfvFn(GLuint sampler,
GLenum pname,
GLfloat* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetSamplerParameterfv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetSamplerParameterfv");
gl_api_->glGetSamplerParameterfvFn(sampler, pname, params);
}
@@ -8168,7 +8177,7 @@ void TraceGLApi::glGetSamplerParameterfvRobustANGLEFn(GLuint sampler,
GLsizei* length,
GLfloat* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetSamplerParameterfvRobustANGLE")
+ "gpu", "TraceGLAPI::glGetSamplerParameterfvRobustANGLE");
gl_api_->glGetSamplerParameterfvRobustANGLEFn(sampler, pname, bufSize, length,
params);
}
@@ -8179,7 +8188,7 @@ void TraceGLApi::glGetSamplerParameterIivRobustANGLEFn(GLuint sampler,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetSamplerParameterIivRobustANGLE")
+ "gpu", "TraceGLAPI::glGetSamplerParameterIivRobustANGLE");
gl_api_->glGetSamplerParameterIivRobustANGLEFn(sampler, pname, bufSize,
length, params);
}
@@ -8190,7 +8199,7 @@ void TraceGLApi::glGetSamplerParameterIuivRobustANGLEFn(GLuint sampler,
GLsizei* length,
GLuint* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetSamplerParameterIuivRobustANGLE")
+ "gpu", "TraceGLAPI::glGetSamplerParameterIuivRobustANGLE");
gl_api_->glGetSamplerParameterIuivRobustANGLEFn(sampler, pname, bufSize,
length, params);
}
@@ -8198,7 +8207,7 @@ void TraceGLApi::glGetSamplerParameterIuivRobustANGLEFn(GLuint sampler,
void TraceGLApi::glGetSamplerParameterivFn(GLuint sampler,
GLenum pname,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetSamplerParameteriv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetSamplerParameteriv");
gl_api_->glGetSamplerParameterivFn(sampler, pname, params);
}
@@ -8208,7 +8217,7 @@ void TraceGLApi::glGetSamplerParameterivRobustANGLEFn(GLuint sampler,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetSamplerParameterivRobustANGLE")
+ "gpu", "TraceGLAPI::glGetSamplerParameterivRobustANGLE");
gl_api_->glGetSamplerParameterivRobustANGLEFn(sampler, pname, bufSize, length,
params);
}
@@ -8217,12 +8226,12 @@ void TraceGLApi::glGetShaderInfoLogFn(GLuint shader,
GLsizei bufsize,
GLsizei* length,
char* infolog) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetShaderInfoLog")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetShaderInfoLog");
gl_api_->glGetShaderInfoLogFn(shader, bufsize, length, infolog);
}
void TraceGLApi::glGetShaderivFn(GLuint shader, GLenum pname, GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetShaderiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetShaderiv");
gl_api_->glGetShaderivFn(shader, pname, params);
}
@@ -8231,7 +8240,7 @@ void TraceGLApi::glGetShaderivRobustANGLEFn(GLuint shader,
GLsizei bufSize,
GLsizei* length,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetShaderivRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetShaderivRobustANGLE");
gl_api_->glGetShaderivRobustANGLEFn(shader, pname, bufSize, length, params);
}
@@ -8239,7 +8248,8 @@ void TraceGLApi::glGetShaderPrecisionFormatFn(GLenum shadertype,
GLenum precisiontype,
GLint* range,
GLint* precision) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetShaderPrecisionFormat")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glGetShaderPrecisionFormat");
gl_api_->glGetShaderPrecisionFormatFn(shadertype, precisiontype, range,
precision);
}
@@ -8248,17 +8258,17 @@ void TraceGLApi::glGetShaderSourceFn(GLuint shader,
GLsizei bufsize,
GLsizei* length,
char* source) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetShaderSource")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetShaderSource");
gl_api_->glGetShaderSourceFn(shader, bufsize, length, source);
}
const GLubyte* TraceGLApi::glGetStringFn(GLenum name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetString")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetString");
return gl_api_->glGetStringFn(name);
}
const GLubyte* TraceGLApi::glGetStringiFn(GLenum name, GLuint index) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetStringi")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetStringi");
return gl_api_->glGetStringiFn(name, index);
}
@@ -8267,7 +8277,7 @@ void TraceGLApi::glGetSyncivFn(GLsync sync,
GLsizei bufSize,
GLsizei* length,
GLint* values) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetSynciv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetSynciv");
gl_api_->glGetSyncivFn(sync, pname, bufSize, length, values);
}
@@ -8275,7 +8285,7 @@ void TraceGLApi::glGetTexLevelParameterfvFn(GLenum target,
GLint level,
GLenum pname,
GLfloat* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetTexLevelParameterfv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetTexLevelParameterfv");
gl_api_->glGetTexLevelParameterfvFn(target, level, pname, params);
}
@@ -8286,7 +8296,7 @@ void TraceGLApi::glGetTexLevelParameterfvRobustANGLEFn(GLenum target,
GLsizei* length,
GLfloat* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetTexLevelParameterfvRobustANGLE")
+ "gpu", "TraceGLAPI::glGetTexLevelParameterfvRobustANGLE");
gl_api_->glGetTexLevelParameterfvRobustANGLEFn(target, level, pname, bufSize,
length, params);
}
@@ -8295,7 +8305,7 @@ void TraceGLApi::glGetTexLevelParameterivFn(GLenum target,
GLint level,
GLenum pname,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetTexLevelParameteriv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetTexLevelParameteriv");
gl_api_->glGetTexLevelParameterivFn(target, level, pname, params);
}
@@ -8306,7 +8316,7 @@ void TraceGLApi::glGetTexLevelParameterivRobustANGLEFn(GLenum target,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetTexLevelParameterivRobustANGLE")
+ "gpu", "TraceGLAPI::glGetTexLevelParameterivRobustANGLE");
gl_api_->glGetTexLevelParameterivRobustANGLEFn(target, level, pname, bufSize,
length, params);
}
@@ -8314,7 +8324,7 @@ void TraceGLApi::glGetTexLevelParameterivRobustANGLEFn(GLenum target,
void TraceGLApi::glGetTexParameterfvFn(GLenum target,
GLenum pname,
GLfloat* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetTexParameterfv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetTexParameterfv");
gl_api_->glGetTexParameterfvFn(target, pname, params);
}
@@ -8324,7 +8334,7 @@ void TraceGLApi::glGetTexParameterfvRobustANGLEFn(GLenum target,
GLsizei* length,
GLfloat* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetTexParameterfvRobustANGLE")
+ "TraceGLAPI::glGetTexParameterfvRobustANGLE");
gl_api_->glGetTexParameterfvRobustANGLEFn(target, pname, bufSize, length,
params);
}
@@ -8335,7 +8345,7 @@ void TraceGLApi::glGetTexParameterIivRobustANGLEFn(GLenum target,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetTexParameterIivRobustANGLE")
+ "TraceGLAPI::glGetTexParameterIivRobustANGLE");
gl_api_->glGetTexParameterIivRobustANGLEFn(target, pname, bufSize, length,
params);
}
@@ -8346,7 +8356,7 @@ void TraceGLApi::glGetTexParameterIuivRobustANGLEFn(GLenum target,
GLsizei* length,
GLuint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetTexParameterIuivRobustANGLE")
+ "TraceGLAPI::glGetTexParameterIuivRobustANGLE");
gl_api_->glGetTexParameterIuivRobustANGLEFn(target, pname, bufSize, length,
params);
}
@@ -8354,7 +8364,7 @@ void TraceGLApi::glGetTexParameterIuivRobustANGLEFn(GLenum target,
void TraceGLApi::glGetTexParameterivFn(GLenum target,
GLenum pname,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetTexParameteriv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetTexParameteriv");
gl_api_->glGetTexParameterivFn(target, pname, params);
}
@@ -8364,7 +8374,7 @@ void TraceGLApi::glGetTexParameterivRobustANGLEFn(GLenum target,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetTexParameterivRobustANGLE")
+ "TraceGLAPI::glGetTexParameterivRobustANGLE");
gl_api_->glGetTexParameterivRobustANGLEFn(target, pname, bufSize, length,
params);
}
@@ -8377,7 +8387,7 @@ void TraceGLApi::glGetTransformFeedbackVaryingFn(GLuint program,
GLenum* type,
char* name) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetTransformFeedbackVarying")
+ "TraceGLAPI::glGetTransformFeedbackVarying");
gl_api_->glGetTransformFeedbackVaryingFn(program, index, bufSize, length,
size, type, name);
}
@@ -8387,20 +8397,20 @@ void TraceGLApi::glGetTranslatedShaderSourceANGLEFn(GLuint shader,
GLsizei* length,
char* source) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetTranslatedShaderSourceANGLE")
+ "TraceGLAPI::glGetTranslatedShaderSourceANGLE");
gl_api_->glGetTranslatedShaderSourceANGLEFn(shader, bufsize, length, source);
}
GLuint TraceGLApi::glGetUniformBlockIndexFn(GLuint program,
const char* uniformBlockName) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformBlockIndex")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformBlockIndex");
return gl_api_->glGetUniformBlockIndexFn(program, uniformBlockName);
}
void TraceGLApi::glGetUniformfvFn(GLuint program,
GLint location,
GLfloat* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformfv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformfv");
gl_api_->glGetUniformfvFn(program, location, params);
}
@@ -8409,7 +8419,7 @@ void TraceGLApi::glGetUniformfvRobustANGLEFn(GLuint program,
GLsizei bufSize,
GLsizei* length,
GLfloat* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformfvRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformfvRobustANGLE");
gl_api_->glGetUniformfvRobustANGLEFn(program, location, bufSize, length,
params);
}
@@ -8418,7 +8428,7 @@ void TraceGLApi::glGetUniformIndicesFn(GLuint program,
GLsizei uniformCount,
const char* const* uniformNames,
GLuint* uniformIndices) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformIndices")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformIndices");
gl_api_->glGetUniformIndicesFn(program, uniformCount, uniformNames,
uniformIndices);
}
@@ -8426,7 +8436,7 @@ void TraceGLApi::glGetUniformIndicesFn(GLuint program,
void TraceGLApi::glGetUniformivFn(GLuint program,
GLint location,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformiv");
gl_api_->glGetUniformivFn(program, location, params);
}
@@ -8435,20 +8445,20 @@ void TraceGLApi::glGetUniformivRobustANGLEFn(GLuint program,
GLsizei bufSize,
GLsizei* length,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformivRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformivRobustANGLE");
gl_api_->glGetUniformivRobustANGLEFn(program, location, bufSize, length,
params);
}
GLint TraceGLApi::glGetUniformLocationFn(GLuint program, const char* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformLocation")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformLocation");
return gl_api_->glGetUniformLocationFn(program, name);
}
void TraceGLApi::glGetUniformuivFn(GLuint program,
GLint location,
GLuint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformuiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformuiv");
gl_api_->glGetUniformuivFn(program, location, params);
}
@@ -8457,7 +8467,8 @@ void TraceGLApi::glGetUniformuivRobustANGLEFn(GLuint program,
GLsizei bufSize,
GLsizei* length,
GLuint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetUniformuivRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glGetUniformuivRobustANGLE");
gl_api_->glGetUniformuivRobustANGLEFn(program, location, bufSize, length,
params);
}
@@ -8465,7 +8476,7 @@ void TraceGLApi::glGetUniformuivRobustANGLEFn(GLuint program,
void TraceGLApi::glGetVertexAttribfvFn(GLuint index,
GLenum pname,
GLfloat* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetVertexAttribfv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetVertexAttribfv");
gl_api_->glGetVertexAttribfvFn(index, pname, params);
}
@@ -8475,7 +8486,7 @@ void TraceGLApi::glGetVertexAttribfvRobustANGLEFn(GLuint index,
GLsizei* length,
GLfloat* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetVertexAttribfvRobustANGLE")
+ "TraceGLAPI::glGetVertexAttribfvRobustANGLE");
gl_api_->glGetVertexAttribfvRobustANGLEFn(index, pname, bufSize, length,
params);
}
@@ -8486,7 +8497,7 @@ void TraceGLApi::glGetVertexAttribIivRobustANGLEFn(GLuint index,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetVertexAttribIivRobustANGLE")
+ "TraceGLAPI::glGetVertexAttribIivRobustANGLE");
gl_api_->glGetVertexAttribIivRobustANGLEFn(index, pname, bufSize, length,
params);
}
@@ -8497,7 +8508,7 @@ void TraceGLApi::glGetVertexAttribIuivRobustANGLEFn(GLuint index,
GLsizei* length,
GLuint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetVertexAttribIuivRobustANGLE")
+ "TraceGLAPI::glGetVertexAttribIuivRobustANGLE");
gl_api_->glGetVertexAttribIuivRobustANGLEFn(index, pname, bufSize, length,
params);
}
@@ -8505,7 +8516,7 @@ void TraceGLApi::glGetVertexAttribIuivRobustANGLEFn(GLuint index,
void TraceGLApi::glGetVertexAttribivFn(GLuint index,
GLenum pname,
GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetVertexAttribiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetVertexAttribiv");
gl_api_->glGetVertexAttribivFn(index, pname, params);
}
@@ -8515,7 +8526,7 @@ void TraceGLApi::glGetVertexAttribivRobustANGLEFn(GLuint index,
GLsizei* length,
GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glGetVertexAttribivRobustANGLE")
+ "TraceGLAPI::glGetVertexAttribivRobustANGLE");
gl_api_->glGetVertexAttribivRobustANGLEFn(index, pname, bufSize, length,
params);
}
@@ -8523,7 +8534,7 @@ void TraceGLApi::glGetVertexAttribivRobustANGLEFn(GLuint index,
void TraceGLApi::glGetVertexAttribPointervFn(GLuint index,
GLenum pname,
void** pointer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetVertexAttribPointerv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetVertexAttribPointerv");
gl_api_->glGetVertexAttribPointervFn(index, pname, pointer);
}
@@ -8533,13 +8544,13 @@ void TraceGLApi::glGetVertexAttribPointervRobustANGLEFn(GLuint index,
GLsizei* length,
void** pointer) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glGetVertexAttribPointervRobustANGLE")
+ "gpu", "TraceGLAPI::glGetVertexAttribPointervRobustANGLE");
gl_api_->glGetVertexAttribPointervRobustANGLEFn(index, pname, bufSize, length,
pointer);
}
void TraceGLApi::glHintFn(GLenum target, GLenum mode) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glHint")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glHint");
gl_api_->glHintFn(target, mode);
}
@@ -8547,7 +8558,7 @@ void TraceGLApi::glImportMemoryFdEXTFn(GLuint memory,
GLuint64 size,
GLenum handleType,
GLint fd) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glImportMemoryFdEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glImportMemoryFdEXT");
gl_api_->glImportMemoryFdEXTFn(memory, size, handleType, fd);
}
@@ -8556,7 +8567,7 @@ void TraceGLApi::glImportMemoryWin32HandleEXTFn(GLuint memory,
GLenum handleType,
void* handle) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glImportMemoryWin32HandleEXT")
+ "TraceGLAPI::glImportMemoryWin32HandleEXT");
gl_api_->glImportMemoryWin32HandleEXTFn(memory, size, handleType, handle);
}
@@ -8565,14 +8576,14 @@ void TraceGLApi::glImportMemoryZirconHandleANGLEFn(GLuint memory,
GLenum handleType,
GLuint handle) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glImportMemoryZirconHandleANGLE")
+ "TraceGLAPI::glImportMemoryZirconHandleANGLE");
gl_api_->glImportMemoryZirconHandleANGLEFn(memory, size, handleType, handle);
}
void TraceGLApi::glImportSemaphoreFdEXTFn(GLuint semaphore,
GLenum handleType,
GLint fd) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glImportSemaphoreFdEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glImportSemaphoreFdEXT");
gl_api_->glImportSemaphoreFdEXTFn(semaphore, handleType, fd);
}
@@ -8580,7 +8591,7 @@ void TraceGLApi::glImportSemaphoreWin32HandleEXTFn(GLuint semaphore,
GLenum handleType,
void* handle) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glImportSemaphoreWin32HandleEXT")
+ "TraceGLAPI::glImportSemaphoreWin32HandleEXT");
gl_api_->glImportSemaphoreWin32HandleEXTFn(semaphore, handleType, handle);
}
@@ -8588,19 +8599,19 @@ void TraceGLApi::glImportSemaphoreZirconHandleANGLEFn(GLuint semaphore,
GLenum handleType,
GLuint handle) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glImportSemaphoreZirconHandleANGLE")
+ "gpu", "TraceGLAPI::glImportSemaphoreZirconHandleANGLE");
gl_api_->glImportSemaphoreZirconHandleANGLEFn(semaphore, handleType, handle);
}
void TraceGLApi::glInsertEventMarkerEXTFn(GLsizei length, const char* marker) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glInsertEventMarkerEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glInsertEventMarkerEXT");
gl_api_->glInsertEventMarkerEXTFn(length, marker);
}
void TraceGLApi::glInvalidateFramebufferFn(GLenum target,
GLsizei numAttachments,
const GLenum* attachments) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glInvalidateFramebuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glInvalidateFramebuffer");
gl_api_->glInvalidateFramebufferFn(target, numAttachments, attachments);
}
@@ -8611,118 +8622,119 @@ void TraceGLApi::glInvalidateSubFramebufferFn(GLenum target,
GLint y,
GLint width,
GLint height) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glInvalidateSubFramebuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glInvalidateSubFramebuffer");
gl_api_->glInvalidateSubFramebufferFn(target, numAttachments, attachments, x,
y, width, height);
}
void TraceGLApi::glInvalidateTextureANGLEFn(GLenum target) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glInvalidateTextureANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glInvalidateTextureANGLE");
gl_api_->glInvalidateTextureANGLEFn(target);
}
GLboolean TraceGLApi::glIsBufferFn(GLuint buffer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsBuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsBuffer");
return gl_api_->glIsBufferFn(buffer);
}
GLboolean TraceGLApi::glIsEnabledFn(GLenum cap) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsEnabled")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsEnabled");
return gl_api_->glIsEnabledFn(cap);
}
GLboolean TraceGLApi::glIsEnablediOESFn(GLenum target, GLuint index) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsEnablediOES")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsEnablediOES");
return gl_api_->glIsEnablediOESFn(target, index);
}
GLboolean TraceGLApi::glIsFenceAPPLEFn(GLuint fence) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsFenceAPPLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsFenceAPPLE");
return gl_api_->glIsFenceAPPLEFn(fence);
}
GLboolean TraceGLApi::glIsFenceNVFn(GLuint fence) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsFenceNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsFenceNV");
return gl_api_->glIsFenceNVFn(fence);
}
GLboolean TraceGLApi::glIsFramebufferEXTFn(GLuint framebuffer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsFramebufferEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsFramebufferEXT");
return gl_api_->glIsFramebufferEXTFn(framebuffer);
}
GLboolean TraceGLApi::glIsPathNVFn(GLuint path) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsPathNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsPathNV");
return gl_api_->glIsPathNVFn(path);
}
GLboolean TraceGLApi::glIsProgramFn(GLuint program) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsProgram")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsProgram");
return gl_api_->glIsProgramFn(program);
}
GLboolean TraceGLApi::glIsProgramPipelineFn(GLuint pipeline) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsProgramPipeline")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsProgramPipeline");
return gl_api_->glIsProgramPipelineFn(pipeline);
}
GLboolean TraceGLApi::glIsQueryFn(GLuint query) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsQuery")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsQuery");
return gl_api_->glIsQueryFn(query);
}
GLboolean TraceGLApi::glIsRenderbufferEXTFn(GLuint renderbuffer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsRenderbufferEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsRenderbufferEXT");
return gl_api_->glIsRenderbufferEXTFn(renderbuffer);
}
GLboolean TraceGLApi::glIsSamplerFn(GLuint sampler) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsSampler")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsSampler");
return gl_api_->glIsSamplerFn(sampler);
}
GLboolean TraceGLApi::glIsShaderFn(GLuint shader) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsShader")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsShader");
return gl_api_->glIsShaderFn(shader);
}
GLboolean TraceGLApi::glIsSyncFn(GLsync sync) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsSync")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsSync");
return gl_api_->glIsSyncFn(sync);
}
GLboolean TraceGLApi::glIsSyncAPPLEFn(GLsync sync) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsSyncAPPLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsSyncAPPLE");
return gl_api_->glIsSyncAPPLEFn(sync);
}
GLboolean TraceGLApi::glIsTextureFn(GLuint texture) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsTexture")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsTexture");
return gl_api_->glIsTextureFn(texture);
}
GLboolean TraceGLApi::glIsTransformFeedbackFn(GLuint id) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsTransformFeedback")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsTransformFeedback");
return gl_api_->glIsTransformFeedbackFn(id);
}
GLboolean TraceGLApi::glIsVertexArrayOESFn(GLuint array) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsVertexArrayOES")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glIsVertexArrayOES");
return gl_api_->glIsVertexArrayOESFn(array);
}
void TraceGLApi::glLineWidthFn(GLfloat width) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glLineWidth")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glLineWidth");
gl_api_->glLineWidthFn(width);
}
void TraceGLApi::glLinkProgramFn(GLuint program) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glLinkProgram")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glLinkProgram");
gl_api_->glLinkProgramFn(program);
}
void* TraceGLApi::glMapBufferFn(GLenum target, GLenum access) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMapBuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMapBuffer");
return gl_api_->glMapBufferFn(target, access);
}
@@ -8730,33 +8742,33 @@ void* TraceGLApi::glMapBufferRangeFn(GLenum target,
GLintptr offset,
GLsizeiptr length,
GLbitfield access) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMapBufferRange")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMapBufferRange");
return gl_api_->glMapBufferRangeFn(target, offset, length, access);
}
void TraceGLApi::glMatrixLoadfEXTFn(GLenum matrixMode, const GLfloat* m) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMatrixLoadfEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMatrixLoadfEXT");
gl_api_->glMatrixLoadfEXTFn(matrixMode, m);
}
void TraceGLApi::glMatrixLoadIdentityEXTFn(GLenum matrixMode) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMatrixLoadIdentityEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMatrixLoadIdentityEXT");
gl_api_->glMatrixLoadIdentityEXTFn(matrixMode);
}
void TraceGLApi::glMaxShaderCompilerThreadsKHRFn(GLuint count) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glMaxShaderCompilerThreadsKHR")
+ "TraceGLAPI::glMaxShaderCompilerThreadsKHR");
gl_api_->glMaxShaderCompilerThreadsKHRFn(count);
}
void TraceGLApi::glMemoryBarrierByRegionFn(GLbitfield barriers) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMemoryBarrierByRegion")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMemoryBarrierByRegion");
gl_api_->glMemoryBarrierByRegionFn(barriers);
}
void TraceGLApi::glMemoryBarrierEXTFn(GLbitfield barriers) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMemoryBarrierEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMemoryBarrierEXT");
gl_api_->glMemoryBarrierEXTFn(barriers);
}
@@ -8764,12 +8776,12 @@ void TraceGLApi::glMemoryObjectParameterivEXTFn(GLuint memoryObject,
GLenum pname,
const GLint* param) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glMemoryObjectParameterivEXT")
+ "TraceGLAPI::glMemoryObjectParameterivEXT");
gl_api_->glMemoryObjectParameterivEXTFn(memoryObject, pname, param);
}
void TraceGLApi::glMinSampleShadingFn(GLfloat value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMinSampleShading")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMinSampleShading");
gl_api_->glMinSampleShadingFn(value);
}
@@ -8777,7 +8789,7 @@ void TraceGLApi::glMultiDrawArraysANGLEFn(GLenum mode,
const GLint* firsts,
const GLsizei* counts,
GLsizei drawcount) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMultiDrawArraysANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMultiDrawArraysANGLE");
gl_api_->glMultiDrawArraysANGLEFn(mode, firsts, counts, drawcount);
}
@@ -8788,7 +8800,7 @@ void TraceGLApi::glMultiDrawArraysInstancedANGLEFn(
const GLsizei* instanceCounts,
GLsizei drawcount) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glMultiDrawArraysInstancedANGLE")
+ "TraceGLAPI::glMultiDrawArraysInstancedANGLE");
gl_api_->glMultiDrawArraysInstancedANGLEFn(mode, firsts, counts,
instanceCounts, drawcount);
}
@@ -8801,7 +8813,7 @@ void TraceGLApi::glMultiDrawArraysInstancedBaseInstanceANGLEFn(
const GLuint* baseInstances,
GLsizei drawcount) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glMultiDrawArraysInstancedBaseInstanceANGLE")
+ "gpu", "TraceGLAPI::glMultiDrawArraysInstancedBaseInstanceANGLE");
gl_api_->glMultiDrawArraysInstancedBaseInstanceANGLEFn(
mode, firsts, counts, instanceCounts, baseInstances, drawcount);
}
@@ -8811,7 +8823,7 @@ void TraceGLApi::glMultiDrawElementsANGLEFn(GLenum mode,
GLenum type,
const GLvoid* const* indices,
GLsizei drawcount) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMultiDrawElementsANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMultiDrawElementsANGLE");
gl_api_->glMultiDrawElementsANGLEFn(mode, counts, type, indices, drawcount);
}
@@ -8822,8 +8834,8 @@ void TraceGLApi::glMultiDrawElementsInstancedANGLEFn(
const GLvoid* const* indices,
const GLsizei* instanceCounts,
GLsizei drawcount) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glMultiDrawElementsInstancedANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0(
+ "gpu", "TraceGLAPI::glMultiDrawElementsInstancedANGLE");
gl_api_->glMultiDrawElementsInstancedANGLEFn(mode, counts, type, indices,
instanceCounts, drawcount);
}
@@ -8839,7 +8851,7 @@ void TraceGLApi::glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLEFn(
GLsizei drawcount) {
TRACE_EVENT_BINARY_EFFICIENT0(
"gpu",
- "TraceGLAPI::glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE")
+ "TraceGLAPI::glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE");
gl_api_->glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLEFn(
mode, counts, type, indices, instanceCounts, baseVertices, baseInstances,
drawcount);
@@ -8849,19 +8861,19 @@ void TraceGLApi::glObjectLabelFn(GLenum identifier,
GLuint name,
GLsizei length,
const char* label) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glObjectLabel")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glObjectLabel");
gl_api_->glObjectLabelFn(identifier, name, length, label);
}
void TraceGLApi::glObjectPtrLabelFn(void* ptr,
GLsizei length,
const char* label) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glObjectPtrLabel")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glObjectPtrLabel");
gl_api_->glObjectPtrLabelFn(ptr, length, label);
}
void TraceGLApi::glPatchParameteriFn(GLenum pname, GLint value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPatchParameteri")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPatchParameteri");
gl_api_->glPatchParameteriFn(pname, value);
}
@@ -8871,7 +8883,7 @@ void TraceGLApi::glPathCommandsNVFn(GLuint path,
GLsizei numCoords,
GLenum coordType,
const GLvoid* coords) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPathCommandsNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPathCommandsNV");
gl_api_->glPathCommandsNVFn(path, numCommands, commands, numCoords, coordType,
coords);
}
@@ -8879,57 +8891,57 @@ void TraceGLApi::glPathCommandsNVFn(GLuint path,
void TraceGLApi::glPathParameterfNVFn(GLuint path,
GLenum pname,
GLfloat value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPathParameterfNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPathParameterfNV");
gl_api_->glPathParameterfNVFn(path, pname, value);
}
void TraceGLApi::glPathParameteriNVFn(GLuint path, GLenum pname, GLint value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPathParameteriNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPathParameteriNV");
gl_api_->glPathParameteriNVFn(path, pname, value);
}
void TraceGLApi::glPathStencilFuncNVFn(GLenum func, GLint ref, GLuint mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPathStencilFuncNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPathStencilFuncNV");
gl_api_->glPathStencilFuncNVFn(func, ref, mask);
}
void TraceGLApi::glPauseTransformFeedbackFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPauseTransformFeedback")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPauseTransformFeedback");
gl_api_->glPauseTransformFeedbackFn();
}
void TraceGLApi::glPixelStoreiFn(GLenum pname, GLint param) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPixelStorei")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPixelStorei");
gl_api_->glPixelStoreiFn(pname, param);
}
void TraceGLApi::glPointParameteriFn(GLenum pname, GLint param) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPointParameteri")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPointParameteri");
gl_api_->glPointParameteriFn(pname, param);
}
void TraceGLApi::glPolygonModeFn(GLenum face, GLenum mode) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPolygonMode")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPolygonMode");
gl_api_->glPolygonModeFn(face, mode);
}
void TraceGLApi::glPolygonOffsetFn(GLfloat factor, GLfloat units) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPolygonOffset")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPolygonOffset");
gl_api_->glPolygonOffsetFn(factor, units);
}
void TraceGLApi::glPopDebugGroupFn() {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPopDebugGroup")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPopDebugGroup");
gl_api_->glPopDebugGroupFn();
}
void TraceGLApi::glPopGroupMarkerEXTFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPopGroupMarkerEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPopGroupMarkerEXT");
gl_api_->glPopGroupMarkerEXTFn();
}
void TraceGLApi::glPrimitiveRestartIndexFn(GLuint index) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPrimitiveRestartIndex")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPrimitiveRestartIndex");
gl_api_->glPrimitiveRestartIndexFn(index);
}
@@ -8937,14 +8949,14 @@ void TraceGLApi::glProgramBinaryFn(GLuint program,
GLenum binaryFormat,
const GLvoid* binary,
GLsizei length) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramBinary")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramBinary");
gl_api_->glProgramBinaryFn(program, binaryFormat, binary, length);
}
void TraceGLApi::glProgramParameteriFn(GLuint program,
GLenum pname,
GLint value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramParameteri")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramParameteri");
gl_api_->glProgramParameteriFn(program, pname, value);
}
@@ -8954,7 +8966,7 @@ void TraceGLApi::glProgramPathFragmentInputGenNVFn(GLuint program,
GLint components,
const GLfloat* coeffs) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glProgramPathFragmentInputGenNV")
+ "TraceGLAPI::glProgramPathFragmentInputGenNV");
gl_api_->glProgramPathFragmentInputGenNVFn(program, location, genMode,
components, coeffs);
}
@@ -8962,7 +8974,7 @@ void TraceGLApi::glProgramPathFragmentInputGenNVFn(GLuint program,
void TraceGLApi::glProgramUniform1fFn(GLuint program,
GLint location,
GLfloat v0) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1f");
gl_api_->glProgramUniform1fFn(program, location, v0);
}
@@ -8970,14 +8982,14 @@ void TraceGLApi::glProgramUniform1fvFn(GLuint program,
GLint location,
GLsizei count,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1fv");
gl_api_->glProgramUniform1fvFn(program, location, count, value);
}
void TraceGLApi::glProgramUniform1iFn(GLuint program,
GLint location,
GLint v0) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1i")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1i");
gl_api_->glProgramUniform1iFn(program, location, v0);
}
@@ -8985,14 +8997,14 @@ void TraceGLApi::glProgramUniform1ivFn(GLuint program,
GLint location,
GLsizei count,
const GLint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1iv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1iv");
gl_api_->glProgramUniform1ivFn(program, location, count, value);
}
void TraceGLApi::glProgramUniform1uiFn(GLuint program,
GLint location,
GLuint v0) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1ui")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1ui");
gl_api_->glProgramUniform1uiFn(program, location, v0);
}
@@ -9000,7 +9012,7 @@ void TraceGLApi::glProgramUniform1uivFn(GLuint program,
GLint location,
GLsizei count,
const GLuint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1uiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform1uiv");
gl_api_->glProgramUniform1uivFn(program, location, count, value);
}
@@ -9008,7 +9020,7 @@ void TraceGLApi::glProgramUniform2fFn(GLuint program,
GLint location,
GLfloat v0,
GLfloat v1) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2f");
gl_api_->glProgramUniform2fFn(program, location, v0, v1);
}
@@ -9016,7 +9028,7 @@ void TraceGLApi::glProgramUniform2fvFn(GLuint program,
GLint location,
GLsizei count,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2fv");
gl_api_->glProgramUniform2fvFn(program, location, count, value);
}
@@ -9024,7 +9036,7 @@ void TraceGLApi::glProgramUniform2iFn(GLuint program,
GLint location,
GLint v0,
GLint v1) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2i")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2i");
gl_api_->glProgramUniform2iFn(program, location, v0, v1);
}
@@ -9032,7 +9044,7 @@ void TraceGLApi::glProgramUniform2ivFn(GLuint program,
GLint location,
GLsizei count,
const GLint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2iv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2iv");
gl_api_->glProgramUniform2ivFn(program, location, count, value);
}
@@ -9040,7 +9052,7 @@ void TraceGLApi::glProgramUniform2uiFn(GLuint program,
GLint location,
GLuint v0,
GLuint v1) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2ui")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2ui");
gl_api_->glProgramUniform2uiFn(program, location, v0, v1);
}
@@ -9048,7 +9060,7 @@ void TraceGLApi::glProgramUniform2uivFn(GLuint program,
GLint location,
GLsizei count,
const GLuint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2uiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform2uiv");
gl_api_->glProgramUniform2uivFn(program, location, count, value);
}
@@ -9057,7 +9069,7 @@ void TraceGLApi::glProgramUniform3fFn(GLuint program,
GLfloat v0,
GLfloat v1,
GLfloat v2) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3f");
gl_api_->glProgramUniform3fFn(program, location, v0, v1, v2);
}
@@ -9065,7 +9077,7 @@ void TraceGLApi::glProgramUniform3fvFn(GLuint program,
GLint location,
GLsizei count,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3fv");
gl_api_->glProgramUniform3fvFn(program, location, count, value);
}
@@ -9074,7 +9086,7 @@ void TraceGLApi::glProgramUniform3iFn(GLuint program,
GLint v0,
GLint v1,
GLint v2) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3i")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3i");
gl_api_->glProgramUniform3iFn(program, location, v0, v1, v2);
}
@@ -9082,7 +9094,7 @@ void TraceGLApi::glProgramUniform3ivFn(GLuint program,
GLint location,
GLsizei count,
const GLint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3iv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3iv");
gl_api_->glProgramUniform3ivFn(program, location, count, value);
}
@@ -9091,7 +9103,7 @@ void TraceGLApi::glProgramUniform3uiFn(GLuint program,
GLuint v0,
GLuint v1,
GLuint v2) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3ui")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3ui");
gl_api_->glProgramUniform3uiFn(program, location, v0, v1, v2);
}
@@ -9099,7 +9111,7 @@ void TraceGLApi::glProgramUniform3uivFn(GLuint program,
GLint location,
GLsizei count,
const GLuint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3uiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform3uiv");
gl_api_->glProgramUniform3uivFn(program, location, count, value);
}
@@ -9109,7 +9121,7 @@ void TraceGLApi::glProgramUniform4fFn(GLuint program,
GLfloat v1,
GLfloat v2,
GLfloat v3) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4f");
gl_api_->glProgramUniform4fFn(program, location, v0, v1, v2, v3);
}
@@ -9117,7 +9129,7 @@ void TraceGLApi::glProgramUniform4fvFn(GLuint program,
GLint location,
GLsizei count,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4fv");
gl_api_->glProgramUniform4fvFn(program, location, count, value);
}
@@ -9127,7 +9139,7 @@ void TraceGLApi::glProgramUniform4iFn(GLuint program,
GLint v1,
GLint v2,
GLint v3) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4i")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4i");
gl_api_->glProgramUniform4iFn(program, location, v0, v1, v2, v3);
}
@@ -9135,7 +9147,7 @@ void TraceGLApi::glProgramUniform4ivFn(GLuint program,
GLint location,
GLsizei count,
const GLint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4iv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4iv");
gl_api_->glProgramUniform4ivFn(program, location, count, value);
}
@@ -9145,7 +9157,7 @@ void TraceGLApi::glProgramUniform4uiFn(GLuint program,
GLuint v1,
GLuint v2,
GLuint v3) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4ui")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4ui");
gl_api_->glProgramUniform4uiFn(program, location, v0, v1, v2, v3);
}
@@ -9153,7 +9165,7 @@ void TraceGLApi::glProgramUniform4uivFn(GLuint program,
GLint location,
GLsizei count,
const GLuint* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4uiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniform4uiv");
gl_api_->glProgramUniform4uivFn(program, location, count, value);
}
@@ -9162,7 +9174,7 @@ void TraceGLApi::glProgramUniformMatrix2fvFn(GLuint program,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniformMatrix2fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniformMatrix2fv");
gl_api_->glProgramUniformMatrix2fvFn(program, location, count, transpose,
value);
}
@@ -9173,7 +9185,7 @@ void TraceGLApi::glProgramUniformMatrix2x3fvFn(GLuint program,
GLboolean transpose,
const GLfloat* value) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glProgramUniformMatrix2x3fv")
+ "TraceGLAPI::glProgramUniformMatrix2x3fv");
gl_api_->glProgramUniformMatrix2x3fvFn(program, location, count, transpose,
value);
}
@@ -9184,7 +9196,7 @@ void TraceGLApi::glProgramUniformMatrix2x4fvFn(GLuint program,
GLboolean transpose,
const GLfloat* value) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glProgramUniformMatrix2x4fv")
+ "TraceGLAPI::glProgramUniformMatrix2x4fv");
gl_api_->glProgramUniformMatrix2x4fvFn(program, location, count, transpose,
value);
}
@@ -9194,7 +9206,7 @@ void TraceGLApi::glProgramUniformMatrix3fvFn(GLuint program,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniformMatrix3fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniformMatrix3fv");
gl_api_->glProgramUniformMatrix3fvFn(program, location, count, transpose,
value);
}
@@ -9205,7 +9217,7 @@ void TraceGLApi::glProgramUniformMatrix3x2fvFn(GLuint program,
GLboolean transpose,
const GLfloat* value) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glProgramUniformMatrix3x2fv")
+ "TraceGLAPI::glProgramUniformMatrix3x2fv");
gl_api_->glProgramUniformMatrix3x2fvFn(program, location, count, transpose,
value);
}
@@ -9216,7 +9228,7 @@ void TraceGLApi::glProgramUniformMatrix3x4fvFn(GLuint program,
GLboolean transpose,
const GLfloat* value) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glProgramUniformMatrix3x4fv")
+ "TraceGLAPI::glProgramUniformMatrix3x4fv");
gl_api_->glProgramUniformMatrix3x4fvFn(program, location, count, transpose,
value);
}
@@ -9226,7 +9238,7 @@ void TraceGLApi::glProgramUniformMatrix4fvFn(GLuint program,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniformMatrix4fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glProgramUniformMatrix4fv");
gl_api_->glProgramUniformMatrix4fvFn(program, location, count, transpose,
value);
}
@@ -9237,7 +9249,7 @@ void TraceGLApi::glProgramUniformMatrix4x2fvFn(GLuint program,
GLboolean transpose,
const GLfloat* value) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glProgramUniformMatrix4x2fv")
+ "TraceGLAPI::glProgramUniformMatrix4x2fv");
gl_api_->glProgramUniformMatrix4x2fvFn(program, location, count, transpose,
value);
}
@@ -9248,7 +9260,7 @@ void TraceGLApi::glProgramUniformMatrix4x3fvFn(GLuint program,
GLboolean transpose,
const GLfloat* value) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glProgramUniformMatrix4x3fv")
+ "TraceGLAPI::glProgramUniformMatrix4x3fv");
gl_api_->glProgramUniformMatrix4x3fvFn(program, location, count, transpose,
value);
}
@@ -9257,22 +9269,22 @@ void TraceGLApi::glPushDebugGroupFn(GLenum source,
GLuint id,
GLsizei length,
const char* message) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPushDebugGroup")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPushDebugGroup");
gl_api_->glPushDebugGroupFn(source, id, length, message);
}
void TraceGLApi::glPushGroupMarkerEXTFn(GLsizei length, const char* marker) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPushGroupMarkerEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glPushGroupMarkerEXT");
gl_api_->glPushGroupMarkerEXTFn(length, marker);
}
void TraceGLApi::glQueryCounterFn(GLuint id, GLenum target) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glQueryCounter")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glQueryCounter");
gl_api_->glQueryCounterFn(id, target);
}
void TraceGLApi::glReadBufferFn(GLenum src) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReadBuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReadBuffer");
gl_api_->glReadBufferFn(src);
}
@@ -9287,7 +9299,7 @@ void TraceGLApi::glReadnPixelsRobustANGLEFn(GLint x,
GLsizei* columns,
GLsizei* rows,
void* data) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReadnPixelsRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReadnPixelsRobustANGLE");
gl_api_->glReadnPixelsRobustANGLEFn(x, y, width, height, format, type,
bufSize, length, columns, rows, data);
}
@@ -9299,7 +9311,7 @@ void TraceGLApi::glReadPixelsFn(GLint x,
GLenum format,
GLenum type,
void* pixels) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReadPixels")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReadPixels");
gl_api_->glReadPixelsFn(x, y, width, height, format, type, pixels);
}
@@ -9314,13 +9326,13 @@ void TraceGLApi::glReadPixelsRobustANGLEFn(GLint x,
GLsizei* columns,
GLsizei* rows,
void* pixels) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReadPixelsRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReadPixelsRobustANGLE");
gl_api_->glReadPixelsRobustANGLEFn(x, y, width, height, format, type, bufSize,
length, columns, rows, pixels);
}
void TraceGLApi::glReleaseShaderCompilerFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReleaseShaderCompiler")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReleaseShaderCompiler");
gl_api_->glReleaseShaderCompilerFn();
}
@@ -9328,7 +9340,7 @@ void TraceGLApi::glRenderbufferStorageEXTFn(GLenum target,
GLenum internalformat,
GLsizei width,
GLsizei height) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glRenderbufferStorageEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glRenderbufferStorageEXT");
gl_api_->glRenderbufferStorageEXTFn(target, internalformat, width, height);
}
@@ -9338,7 +9350,7 @@ void TraceGLApi::glRenderbufferStorageMultisampleFn(GLenum target,
GLsizei width,
GLsizei height) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glRenderbufferStorageMultisample")
+ "TraceGLAPI::glRenderbufferStorageMultisample");
gl_api_->glRenderbufferStorageMultisampleFn(target, samples, internalformat,
width, height);
}
@@ -9351,7 +9363,7 @@ void TraceGLApi::glRenderbufferStorageMultisampleAdvancedAMDFn(
GLsizei width,
GLsizei height) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glRenderbufferStorageMultisampleAdvancedAMD")
+ "gpu", "TraceGLAPI::glRenderbufferStorageMultisampleAdvancedAMD");
gl_api_->glRenderbufferStorageMultisampleAdvancedAMDFn(
target, samples, storageSamples, internalformat, width, height);
}
@@ -9362,42 +9374,42 @@ void TraceGLApi::glRenderbufferStorageMultisampleEXTFn(GLenum target,
GLsizei width,
GLsizei height) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glRenderbufferStorageMultisampleEXT")
+ "gpu", "TraceGLAPI::glRenderbufferStorageMultisampleEXT");
gl_api_->glRenderbufferStorageMultisampleEXTFn(target, samples,
internalformat, width, height);
}
void TraceGLApi::glRequestExtensionANGLEFn(const char* name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glRequestExtensionANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glRequestExtensionANGLE");
gl_api_->glRequestExtensionANGLEFn(name);
}
void TraceGLApi::glResumeTransformFeedbackFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glResumeTransformFeedback")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glResumeTransformFeedback");
gl_api_->glResumeTransformFeedbackFn();
}
void TraceGLApi::glSampleCoverageFn(GLclampf value, GLboolean invert) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSampleCoverage")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSampleCoverage");
gl_api_->glSampleCoverageFn(value, invert);
}
void TraceGLApi::glSampleMaskiFn(GLuint maskNumber, GLbitfield mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSampleMaski")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSampleMaski");
gl_api_->glSampleMaskiFn(maskNumber, mask);
}
void TraceGLApi::glSamplerParameterfFn(GLuint sampler,
GLenum pname,
GLfloat param) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSamplerParameterf")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSamplerParameterf");
gl_api_->glSamplerParameterfFn(sampler, pname, param);
}
void TraceGLApi::glSamplerParameterfvFn(GLuint sampler,
GLenum pname,
const GLfloat* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSamplerParameterfv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSamplerParameterfv");
gl_api_->glSamplerParameterfvFn(sampler, pname, params);
}
@@ -9406,14 +9418,14 @@ void TraceGLApi::glSamplerParameterfvRobustANGLEFn(GLuint sampler,
GLsizei bufSize,
const GLfloat* param) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glSamplerParameterfvRobustANGLE")
+ "TraceGLAPI::glSamplerParameterfvRobustANGLE");
gl_api_->glSamplerParameterfvRobustANGLEFn(sampler, pname, bufSize, param);
}
void TraceGLApi::glSamplerParameteriFn(GLuint sampler,
GLenum pname,
GLint param) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSamplerParameteri")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSamplerParameteri");
gl_api_->glSamplerParameteriFn(sampler, pname, param);
}
@@ -9422,7 +9434,7 @@ void TraceGLApi::glSamplerParameterIivRobustANGLEFn(GLuint sampler,
GLsizei bufSize,
const GLint* param) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glSamplerParameterIivRobustANGLE")
+ "TraceGLAPI::glSamplerParameterIivRobustANGLE");
gl_api_->glSamplerParameterIivRobustANGLEFn(sampler, pname, bufSize, param);
}
@@ -9430,15 +9442,15 @@ void TraceGLApi::glSamplerParameterIuivRobustANGLEFn(GLuint sampler,
GLenum pname,
GLsizei bufSize,
const GLuint* param) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glSamplerParameterIuivRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0(
+ "gpu", "TraceGLAPI::glSamplerParameterIuivRobustANGLE");
gl_api_->glSamplerParameterIuivRobustANGLEFn(sampler, pname, bufSize, param);
}
void TraceGLApi::glSamplerParameterivFn(GLuint sampler,
GLenum pname,
const GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSamplerParameteriv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSamplerParameteriv");
gl_api_->glSamplerParameterivFn(sampler, pname, params);
}
@@ -9447,22 +9459,22 @@ void TraceGLApi::glSamplerParameterivRobustANGLEFn(GLuint sampler,
GLsizei bufSize,
const GLint* param) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glSamplerParameterivRobustANGLE")
+ "TraceGLAPI::glSamplerParameterivRobustANGLE");
gl_api_->glSamplerParameterivRobustANGLEFn(sampler, pname, bufSize, param);
}
void TraceGLApi::glScissorFn(GLint x, GLint y, GLsizei width, GLsizei height) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glScissor")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glScissor");
gl_api_->glScissorFn(x, y, width, height);
}
void TraceGLApi::glSetFenceAPPLEFn(GLuint fence) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSetFenceAPPLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSetFenceAPPLE");
gl_api_->glSetFenceAPPLEFn(fence);
}
void TraceGLApi::glSetFenceNVFn(GLuint fence, GLenum condition) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSetFenceNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSetFenceNV");
gl_api_->glSetFenceNVFn(fence, condition);
}
@@ -9471,7 +9483,7 @@ void TraceGLApi::glShaderBinaryFn(GLsizei n,
GLenum binaryformat,
const void* binary,
GLsizei length) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glShaderBinary")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glShaderBinary");
gl_api_->glShaderBinaryFn(n, shaders, binaryformat, binary, length);
}
@@ -9479,7 +9491,7 @@ void TraceGLApi::glShaderSourceFn(GLuint shader,
GLsizei count,
const char* const* str,
const GLint* length) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glShaderSource")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glShaderSource");
gl_api_->glShaderSourceFn(shader, count, str, length);
}
@@ -9489,7 +9501,7 @@ void TraceGLApi::glSignalSemaphoreEXTFn(GLuint semaphore,
GLuint numTextureBarriers,
const GLuint* textures,
const GLenum* dstLayouts) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSignalSemaphoreEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glSignalSemaphoreEXT");
gl_api_->glSignalSemaphoreEXTFn(semaphore, numBufferBarriers, buffers,
numTextureBarriers, textures, dstLayouts);
}
@@ -9499,7 +9511,7 @@ void TraceGLApi::glStartTilingQCOMFn(GLuint x,
GLuint width,
GLuint height,
GLbitfield preserveMask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStartTilingQCOM")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStartTilingQCOM");
gl_api_->glStartTilingQCOMFn(x, y, width, height, preserveMask);
}
@@ -9513,7 +9525,7 @@ void TraceGLApi::glStencilFillPathInstancedNVFn(
GLenum transformType,
const GLfloat* transformValues) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glStencilFillPathInstancedNV")
+ "TraceGLAPI::glStencilFillPathInstancedNV");
gl_api_->glStencilFillPathInstancedNVFn(numPaths, pathNameType, paths,
pathBase, fillMode, mask,
transformType, transformValues);
@@ -9522,12 +9534,12 @@ void TraceGLApi::glStencilFillPathInstancedNVFn(
void TraceGLApi::glStencilFillPathNVFn(GLuint path,
GLenum fillMode,
GLuint mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilFillPathNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilFillPathNV");
gl_api_->glStencilFillPathNVFn(path, fillMode, mask);
}
void TraceGLApi::glStencilFuncFn(GLenum func, GLint ref, GLuint mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilFunc")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilFunc");
gl_api_->glStencilFuncFn(func, ref, mask);
}
@@ -9535,22 +9547,22 @@ void TraceGLApi::glStencilFuncSeparateFn(GLenum face,
GLenum func,
GLint ref,
GLuint mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilFuncSeparate")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilFuncSeparate");
gl_api_->glStencilFuncSeparateFn(face, func, ref, mask);
}
void TraceGLApi::glStencilMaskFn(GLuint mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilMask")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilMask");
gl_api_->glStencilMaskFn(mask);
}
void TraceGLApi::glStencilMaskSeparateFn(GLenum face, GLuint mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilMaskSeparate")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilMaskSeparate");
gl_api_->glStencilMaskSeparateFn(face, mask);
}
void TraceGLApi::glStencilOpFn(GLenum fail, GLenum zfail, GLenum zpass) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilOp")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilOp");
gl_api_->glStencilOpFn(fail, zfail, zpass);
}
@@ -9558,7 +9570,7 @@ void TraceGLApi::glStencilOpSeparateFn(GLenum face,
GLenum fail,
GLenum zfail,
GLenum zpass) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilOpSeparate")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilOpSeparate");
gl_api_->glStencilOpSeparateFn(face, fail, zfail, zpass);
}
@@ -9572,7 +9584,7 @@ void TraceGLApi::glStencilStrokePathInstancedNVFn(
GLenum transformType,
const GLfloat* transformValues) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glStencilStrokePathInstancedNV")
+ "TraceGLAPI::glStencilStrokePathInstancedNV");
gl_api_->glStencilStrokePathInstancedNVFn(numPaths, pathNameType, paths,
pathBase, ref, mask, transformType,
transformValues);
@@ -9581,7 +9593,7 @@ void TraceGLApi::glStencilStrokePathInstancedNVFn(
void TraceGLApi::glStencilStrokePathNVFn(GLuint path,
GLint reference,
GLuint mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilStrokePathNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glStencilStrokePathNV");
gl_api_->glStencilStrokePathNVFn(path, reference, mask);
}
@@ -9596,7 +9608,7 @@ void TraceGLApi::glStencilThenCoverFillPathInstancedNVFn(
GLenum transformType,
const GLfloat* transformValues) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glStencilThenCoverFillPathInstancedNV")
+ "gpu", "TraceGLAPI::glStencilThenCoverFillPathInstancedNV");
gl_api_->glStencilThenCoverFillPathInstancedNVFn(
numPaths, pathNameType, paths, pathBase, fillMode, mask, coverMode,
transformType, transformValues);
@@ -9607,7 +9619,7 @@ void TraceGLApi::glStencilThenCoverFillPathNVFn(GLuint path,
GLuint mask,
GLenum coverMode) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glStencilThenCoverFillPathNV")
+ "TraceGLAPI::glStencilThenCoverFillPathNV");
gl_api_->glStencilThenCoverFillPathNVFn(path, fillMode, mask, coverMode);
}
@@ -9622,7 +9634,7 @@ void TraceGLApi::glStencilThenCoverStrokePathInstancedNVFn(
GLenum transformType,
const GLfloat* transformValues) {
TRACE_EVENT_BINARY_EFFICIENT0(
- "gpu", "TraceGLAPI::glStencilThenCoverStrokePathInstancedNV")
+ "gpu", "TraceGLAPI::glStencilThenCoverStrokePathInstancedNV");
gl_api_->glStencilThenCoverStrokePathInstancedNVFn(
numPaths, pathNameType, paths, pathBase, ref, mask, coverMode,
transformType, transformValues);
@@ -9633,24 +9645,24 @@ void TraceGLApi::glStencilThenCoverStrokePathNVFn(GLuint path,
GLuint mask,
GLenum coverMode) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glStencilThenCoverStrokePathNV")
+ "TraceGLAPI::glStencilThenCoverStrokePathNV");
gl_api_->glStencilThenCoverStrokePathNVFn(path, reference, mask, coverMode);
}
GLboolean TraceGLApi::glTestFenceAPPLEFn(GLuint fence) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTestFenceAPPLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTestFenceAPPLE");
return gl_api_->glTestFenceAPPLEFn(fence);
}
GLboolean TraceGLApi::glTestFenceNVFn(GLuint fence) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTestFenceNV")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTestFenceNV");
return gl_api_->glTestFenceNVFn(fence);
}
void TraceGLApi::glTexBufferFn(GLenum target,
GLenum internalformat,
GLuint buffer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexBuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexBuffer");
gl_api_->glTexBufferFn(target, internalformat, buffer);
}
@@ -9659,7 +9671,7 @@ void TraceGLApi::glTexBufferRangeFn(GLenum target,
GLuint buffer,
GLintptr offset,
GLsizeiptr size) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexBufferRange")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexBufferRange");
gl_api_->glTexBufferRangeFn(target, internalformat, buffer, offset, size);
}
@@ -9672,7 +9684,7 @@ void TraceGLApi::glTexImage2DFn(GLenum target,
GLenum format,
GLenum type,
const void* pixels) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexImage2D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexImage2D");
gl_api_->glTexImage2DFn(target, level, internalformat, width, height, border,
format, type, pixels);
}
@@ -9685,7 +9697,7 @@ void TraceGLApi::glTexImage2DExternalANGLEFn(GLenum target,
GLint border,
GLenum format,
GLenum type) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexImage2DExternalANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexImage2DExternalANGLE");
gl_api_->glTexImage2DExternalANGLEFn(target, level, internalformat, width,
height, border, format, type);
}
@@ -9700,7 +9712,7 @@ void TraceGLApi::glTexImage2DRobustANGLEFn(GLenum target,
GLenum type,
GLsizei bufSize,
const void* pixels) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexImage2DRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexImage2DRobustANGLE");
gl_api_->glTexImage2DRobustANGLEFn(target, level, internalformat, width,
height, border, format, type, bufSize,
pixels);
@@ -9716,7 +9728,7 @@ void TraceGLApi::glTexImage3DFn(GLenum target,
GLenum format,
GLenum type,
const void* pixels) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexImage3D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexImage3D");
gl_api_->glTexImage3DFn(target, level, internalformat, width, height, depth,
border, format, type, pixels);
}
@@ -9732,21 +9744,21 @@ void TraceGLApi::glTexImage3DRobustANGLEFn(GLenum target,
GLenum type,
GLsizei bufSize,
const void* pixels) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexImage3DRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexImage3DRobustANGLE");
gl_api_->glTexImage3DRobustANGLEFn(target, level, internalformat, width,
height, depth, border, format, type,
bufSize, pixels);
}
void TraceGLApi::glTexParameterfFn(GLenum target, GLenum pname, GLfloat param) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexParameterf")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexParameterf");
gl_api_->glTexParameterfFn(target, pname, param);
}
void TraceGLApi::glTexParameterfvFn(GLenum target,
GLenum pname,
const GLfloat* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexParameterfv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexParameterfv");
gl_api_->glTexParameterfvFn(target, pname, params);
}
@@ -9755,12 +9767,12 @@ void TraceGLApi::glTexParameterfvRobustANGLEFn(GLenum target,
GLsizei bufSize,
const GLfloat* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glTexParameterfvRobustANGLE")
+ "TraceGLAPI::glTexParameterfvRobustANGLE");
gl_api_->glTexParameterfvRobustANGLEFn(target, pname, bufSize, params);
}
void TraceGLApi::glTexParameteriFn(GLenum target, GLenum pname, GLint param) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexParameteri")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexParameteri");
gl_api_->glTexParameteriFn(target, pname, param);
}
@@ -9769,7 +9781,7 @@ void TraceGLApi::glTexParameterIivRobustANGLEFn(GLenum target,
GLsizei bufSize,
const GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glTexParameterIivRobustANGLE")
+ "TraceGLAPI::glTexParameterIivRobustANGLE");
gl_api_->glTexParameterIivRobustANGLEFn(target, pname, bufSize, params);
}
@@ -9778,14 +9790,14 @@ void TraceGLApi::glTexParameterIuivRobustANGLEFn(GLenum target,
GLsizei bufSize,
const GLuint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glTexParameterIuivRobustANGLE")
+ "TraceGLAPI::glTexParameterIuivRobustANGLE");
gl_api_->glTexParameterIuivRobustANGLEFn(target, pname, bufSize, params);
}
void TraceGLApi::glTexParameterivFn(GLenum target,
GLenum pname,
const GLint* params) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexParameteriv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexParameteriv");
gl_api_->glTexParameterivFn(target, pname, params);
}
@@ -9794,7 +9806,7 @@ void TraceGLApi::glTexParameterivRobustANGLEFn(GLenum target,
GLsizei bufSize,
const GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glTexParameterivRobustANGLE")
+ "TraceGLAPI::glTexParameterivRobustANGLE");
gl_api_->glTexParameterivRobustANGLEFn(target, pname, bufSize, params);
}
@@ -9803,7 +9815,7 @@ void TraceGLApi::glTexStorage2DEXTFn(GLenum target,
GLenum internalformat,
GLsizei width,
GLsizei height) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexStorage2DEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexStorage2DEXT");
gl_api_->glTexStorage2DEXTFn(target, levels, internalformat, width, height);
}
@@ -9813,7 +9825,7 @@ void TraceGLApi::glTexStorage2DMultisampleFn(GLenum target,
GLsizei width,
GLsizei height,
GLboolean fixedsamplelocations) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexStorage2DMultisample")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexStorage2DMultisample");
gl_api_->glTexStorage2DMultisampleFn(target, samples, internalformat, width,
height, fixedsamplelocations);
}
@@ -9824,7 +9836,7 @@ void TraceGLApi::glTexStorage3DFn(GLenum target,
GLsizei width,
GLsizei height,
GLsizei depth) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexStorage3D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexStorage3D");
gl_api_->glTexStorage3DFn(target, levels, internalformat, width, height,
depth);
}
@@ -9836,7 +9848,7 @@ void TraceGLApi::glTexStorageMem2DEXTFn(GLenum target,
GLsizei height,
GLuint memory,
GLuint64 offset) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexStorageMem2DEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexStorageMem2DEXT");
gl_api_->glTexStorageMem2DEXTFn(target, levels, internalFormat, width, height,
memory, offset);
}
@@ -9851,7 +9863,7 @@ void TraceGLApi::glTexStorageMemFlags2DANGLEFn(GLenum target,
GLbitfield createFlags,
GLbitfield usageFlags) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glTexStorageMemFlags2DANGLE")
+ "TraceGLAPI::glTexStorageMemFlags2DANGLE");
gl_api_->glTexStorageMemFlags2DANGLEFn(target, levels, internalFormat, width,
height, memory, offset, createFlags,
usageFlags);
@@ -9866,7 +9878,7 @@ void TraceGLApi::glTexSubImage2DFn(GLenum target,
GLenum format,
GLenum type,
const void* pixels) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexSubImage2D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexSubImage2D");
gl_api_->glTexSubImage2DFn(target, level, xoffset, yoffset, width, height,
format, type, pixels);
}
@@ -9881,7 +9893,8 @@ void TraceGLApi::glTexSubImage2DRobustANGLEFn(GLenum target,
GLenum type,
GLsizei bufSize,
const void* pixels) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexSubImage2DRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glTexSubImage2DRobustANGLE");
gl_api_->glTexSubImage2DRobustANGLEFn(target, level, xoffset, yoffset, width,
height, format, type, bufSize, pixels);
}
@@ -9897,7 +9910,7 @@ void TraceGLApi::glTexSubImage3DFn(GLenum target,
GLenum format,
GLenum type,
const void* pixels) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexSubImage3D")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexSubImage3D");
gl_api_->glTexSubImage3DFn(target, level, xoffset, yoffset, zoffset, width,
height, depth, format, type, pixels);
}
@@ -9914,7 +9927,8 @@ void TraceGLApi::glTexSubImage3DRobustANGLEFn(GLenum target,
GLenum type,
GLsizei bufSize,
const void* pixels) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glTexSubImage3DRobustANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glTexSubImage3DRobustANGLE");
gl_api_->glTexSubImage3DRobustANGLEFn(target, level, xoffset, yoffset,
zoffset, width, height, depth, format,
type, bufSize, pixels);
@@ -9925,75 +9939,75 @@ void TraceGLApi::glTransformFeedbackVaryingsFn(GLuint program,
const char* const* varyings,
GLenum bufferMode) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLAPI::glTransformFeedbackVaryings")
+ "TraceGLAPI::glTransformFeedbackVaryings");
gl_api_->glTransformFeedbackVaryingsFn(program, count, varyings, bufferMode);
}
void TraceGLApi::glUniform1fFn(GLint location, GLfloat x) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1f");
gl_api_->glUniform1fFn(location, x);
}
void TraceGLApi::glUniform1fvFn(GLint location,
GLsizei count,
const GLfloat* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1fv");
gl_api_->glUniform1fvFn(location, count, v);
}
void TraceGLApi::glUniform1iFn(GLint location, GLint x) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1i")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1i");
gl_api_->glUniform1iFn(location, x);
}
void TraceGLApi::glUniform1ivFn(GLint location, GLsizei count, const GLint* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1iv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1iv");
gl_api_->glUniform1ivFn(location, count, v);
}
void TraceGLApi::glUniform1uiFn(GLint location, GLuint v0) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1ui")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1ui");
gl_api_->glUniform1uiFn(location, v0);
}
void TraceGLApi::glUniform1uivFn(GLint location,
GLsizei count,
const GLuint* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1uiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform1uiv");
gl_api_->glUniform1uivFn(location, count, v);
}
void TraceGLApi::glUniform2fFn(GLint location, GLfloat x, GLfloat y) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2f");
gl_api_->glUniform2fFn(location, x, y);
}
void TraceGLApi::glUniform2fvFn(GLint location,
GLsizei count,
const GLfloat* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2fv");
gl_api_->glUniform2fvFn(location, count, v);
}
void TraceGLApi::glUniform2iFn(GLint location, GLint x, GLint y) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2i")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2i");
gl_api_->glUniform2iFn(location, x, y);
}
void TraceGLApi::glUniform2ivFn(GLint location, GLsizei count, const GLint* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2iv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2iv");
gl_api_->glUniform2ivFn(location, count, v);
}
void TraceGLApi::glUniform2uiFn(GLint location, GLuint v0, GLuint v1) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2ui")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2ui");
gl_api_->glUniform2uiFn(location, v0, v1);
}
void TraceGLApi::glUniform2uivFn(GLint location,
GLsizei count,
const GLuint* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2uiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform2uiv");
gl_api_->glUniform2uivFn(location, count, v);
}
@@ -10001,24 +10015,24 @@ void TraceGLApi::glUniform3fFn(GLint location,
GLfloat x,
GLfloat y,
GLfloat z) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3f");
gl_api_->glUniform3fFn(location, x, y, z);
}
void TraceGLApi::glUniform3fvFn(GLint location,
GLsizei count,
const GLfloat* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3fv");
gl_api_->glUniform3fvFn(location, count, v);
}
void TraceGLApi::glUniform3iFn(GLint location, GLint x, GLint y, GLint z) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3i")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3i");
gl_api_->glUniform3iFn(location, x, y, z);
}
void TraceGLApi::glUniform3ivFn(GLint location, GLsizei count, const GLint* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3iv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3iv");
gl_api_->glUniform3ivFn(location, count, v);
}
@@ -10026,14 +10040,14 @@ void TraceGLApi::glUniform3uiFn(GLint location,
GLuint v0,
GLuint v1,
GLuint v2) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3ui")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3ui");
gl_api_->glUniform3uiFn(location, v0, v1, v2);
}
void TraceGLApi::glUniform3uivFn(GLint location,
GLsizei count,
const GLuint* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3uiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform3uiv");
gl_api_->glUniform3uivFn(location, count, v);
}
@@ -10042,14 +10056,14 @@ void TraceGLApi::glUniform4fFn(GLint location,
GLfloat y,
GLfloat z,
GLfloat w) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4f");
gl_api_->glUniform4fFn(location, x, y, z, w);
}
void TraceGLApi::glUniform4fvFn(GLint location,
GLsizei count,
const GLfloat* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4fv");
gl_api_->glUniform4fvFn(location, count, v);
}
@@ -10058,12 +10072,12 @@ void TraceGLApi::glUniform4iFn(GLint location,
GLint y,
GLint z,
GLint w) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4i")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4i");
gl_api_->glUniform4iFn(location, x, y, z, w);
}
void TraceGLApi::glUniform4ivFn(GLint location, GLsizei count, const GLint* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4iv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4iv");
gl_api_->glUniform4ivFn(location, count, v);
}
@@ -10072,21 +10086,21 @@ void TraceGLApi::glUniform4uiFn(GLint location,
GLuint v1,
GLuint v2,
GLuint v3) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4ui")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4ui");
gl_api_->glUniform4uiFn(location, v0, v1, v2, v3);
}
void TraceGLApi::glUniform4uivFn(GLint location,
GLsizei count,
const GLuint* v) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4uiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniform4uiv");
gl_api_->glUniform4uivFn(location, count, v);
}
void TraceGLApi::glUniformBlockBindingFn(GLuint program,
GLuint uniformBlockIndex,
GLuint uniformBlockBinding) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformBlockBinding")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformBlockBinding");
gl_api_->glUniformBlockBindingFn(program, uniformBlockIndex,
uniformBlockBinding);
}
@@ -10095,7 +10109,7 @@ void TraceGLApi::glUniformMatrix2fvFn(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix2fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix2fv");
gl_api_->glUniformMatrix2fvFn(location, count, transpose, value);
}
@@ -10103,7 +10117,7 @@ void TraceGLApi::glUniformMatrix2x3fvFn(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix2x3fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix2x3fv");
gl_api_->glUniformMatrix2x3fvFn(location, count, transpose, value);
}
@@ -10111,7 +10125,7 @@ void TraceGLApi::glUniformMatrix2x4fvFn(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix2x4fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix2x4fv");
gl_api_->glUniformMatrix2x4fvFn(location, count, transpose, value);
}
@@ -10119,7 +10133,7 @@ void TraceGLApi::glUniformMatrix3fvFn(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix3fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix3fv");
gl_api_->glUniformMatrix3fvFn(location, count, transpose, value);
}
@@ -10127,7 +10141,7 @@ void TraceGLApi::glUniformMatrix3x2fvFn(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix3x2fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix3x2fv");
gl_api_->glUniformMatrix3x2fvFn(location, count, transpose, value);
}
@@ -10135,7 +10149,7 @@ void TraceGLApi::glUniformMatrix3x4fvFn(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix3x4fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix3x4fv");
gl_api_->glUniformMatrix3x4fvFn(location, count, transpose, value);
}
@@ -10143,7 +10157,7 @@ void TraceGLApi::glUniformMatrix4fvFn(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix4fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix4fv");
gl_api_->glUniformMatrix4fvFn(location, count, transpose, value);
}
@@ -10151,7 +10165,7 @@ void TraceGLApi::glUniformMatrix4x2fvFn(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix4x2fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix4x2fv");
gl_api_->glUniformMatrix4x2fvFn(location, count, transpose, value);
}
@@ -10159,54 +10173,54 @@ void TraceGLApi::glUniformMatrix4x3fvFn(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix4x3fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUniformMatrix4x3fv");
gl_api_->glUniformMatrix4x3fvFn(location, count, transpose, value);
}
GLboolean TraceGLApi::glUnmapBufferFn(GLenum target) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUnmapBuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUnmapBuffer");
return gl_api_->glUnmapBufferFn(target);
}
void TraceGLApi::glUseProgramFn(GLuint program) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUseProgram")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUseProgram");
gl_api_->glUseProgramFn(program);
}
void TraceGLApi::glUseProgramStagesFn(GLuint pipeline,
GLbitfield stages,
GLuint program) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUseProgramStages")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glUseProgramStages");
gl_api_->glUseProgramStagesFn(pipeline, stages, program);
}
void TraceGLApi::glValidateProgramFn(GLuint program) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glValidateProgram")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glValidateProgram");
gl_api_->glValidateProgramFn(program);
}
void TraceGLApi::glValidateProgramPipelineFn(GLuint pipeline) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glValidateProgramPipeline")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glValidateProgramPipeline");
gl_api_->glValidateProgramPipelineFn(pipeline);
}
void TraceGLApi::glVertexAttrib1fFn(GLuint indx, GLfloat x) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib1f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib1f");
gl_api_->glVertexAttrib1fFn(indx, x);
}
void TraceGLApi::glVertexAttrib1fvFn(GLuint indx, const GLfloat* values) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib1fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib1fv");
gl_api_->glVertexAttrib1fvFn(indx, values);
}
void TraceGLApi::glVertexAttrib2fFn(GLuint indx, GLfloat x, GLfloat y) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib2f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib2f");
gl_api_->glVertexAttrib2fFn(indx, x, y);
}
void TraceGLApi::glVertexAttrib2fvFn(GLuint indx, const GLfloat* values) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib2fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib2fv");
gl_api_->glVertexAttrib2fvFn(indx, values);
}
@@ -10214,12 +10228,12 @@ void TraceGLApi::glVertexAttrib3fFn(GLuint indx,
GLfloat x,
GLfloat y,
GLfloat z) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib3f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib3f");
gl_api_->glVertexAttrib3fFn(indx, x, y, z);
}
void TraceGLApi::glVertexAttrib3fvFn(GLuint indx, const GLfloat* values) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib3fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib3fv");
gl_api_->glVertexAttrib3fvFn(indx, values);
}
@@ -10228,23 +10242,24 @@ void TraceGLApi::glVertexAttrib4fFn(GLuint indx,
GLfloat y,
GLfloat z,
GLfloat w) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib4f")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib4f");
gl_api_->glVertexAttrib4fFn(indx, x, y, z, w);
}
void TraceGLApi::glVertexAttrib4fvFn(GLuint indx, const GLfloat* values) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib4fv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttrib4fv");
gl_api_->glVertexAttrib4fvFn(indx, values);
}
void TraceGLApi::glVertexAttribBindingFn(GLuint attribindex,
GLuint bindingindex) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribBinding")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribBinding");
gl_api_->glVertexAttribBindingFn(attribindex, bindingindex);
}
void TraceGLApi::glVertexAttribDivisorANGLEFn(GLuint index, GLuint divisor) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribDivisorANGLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glVertexAttribDivisorANGLE");
gl_api_->glVertexAttribDivisorANGLEFn(index, divisor);
}
@@ -10253,7 +10268,7 @@ void TraceGLApi::glVertexAttribFormatFn(GLuint attribindex,
GLenum type,
GLboolean normalized,
GLuint relativeoffset) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribFormat")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribFormat");
gl_api_->glVertexAttribFormatFn(attribindex, size, type, normalized,
relativeoffset);
}
@@ -10263,12 +10278,12 @@ void TraceGLApi::glVertexAttribI4iFn(GLuint indx,
GLint y,
GLint z,
GLint w) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribI4i")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribI4i");
gl_api_->glVertexAttribI4iFn(indx, x, y, z, w);
}
void TraceGLApi::glVertexAttribI4ivFn(GLuint indx, const GLint* values) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribI4iv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribI4iv");
gl_api_->glVertexAttribI4ivFn(indx, values);
}
@@ -10277,12 +10292,12 @@ void TraceGLApi::glVertexAttribI4uiFn(GLuint indx,
GLuint y,
GLuint z,
GLuint w) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribI4ui")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribI4ui");
gl_api_->glVertexAttribI4uiFn(indx, x, y, z, w);
}
void TraceGLApi::glVertexAttribI4uivFn(GLuint indx, const GLuint* values) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribI4uiv")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribI4uiv");
gl_api_->glVertexAttribI4uivFn(indx, values);
}
@@ -10290,7 +10305,7 @@ void TraceGLApi::glVertexAttribIFormatFn(GLuint attribindex,
GLint size,
GLenum type,
GLuint relativeoffset) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribIFormat")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribIFormat");
gl_api_->glVertexAttribIFormatFn(attribindex, size, type, relativeoffset);
}
@@ -10299,7 +10314,7 @@ void TraceGLApi::glVertexAttribIPointerFn(GLuint indx,
GLenum type,
GLsizei stride,
const void* ptr) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribIPointer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribIPointer");
gl_api_->glVertexAttribIPointerFn(indx, size, type, stride, ptr);
}
@@ -10309,17 +10324,17 @@ void TraceGLApi::glVertexAttribPointerFn(GLuint indx,
GLboolean normalized,
GLsizei stride,
const void* ptr) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribPointer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexAttribPointer");
gl_api_->glVertexAttribPointerFn(indx, size, type, normalized, stride, ptr);
}
void TraceGLApi::glVertexBindingDivisorFn(GLuint bindingindex, GLuint divisor) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexBindingDivisor")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glVertexBindingDivisor");
gl_api_->glVertexBindingDivisorFn(bindingindex, divisor);
}
void TraceGLApi::glViewportFn(GLint x, GLint y, GLsizei width, GLsizei height) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glViewport")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glViewport");
gl_api_->glViewportFn(x, y, width, height);
}
@@ -10329,27 +10344,27 @@ void TraceGLApi::glWaitSemaphoreEXTFn(GLuint semaphore,
GLuint numTextureBarriers,
const GLuint* textures,
const GLenum* srcLayouts) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glWaitSemaphoreEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glWaitSemaphoreEXT");
gl_api_->glWaitSemaphoreEXTFn(semaphore, numBufferBarriers, buffers,
numTextureBarriers, textures, srcLayouts);
}
void TraceGLApi::glWaitSyncFn(GLsync sync, GLbitfield flags, GLuint64 timeout) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glWaitSync")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glWaitSync");
gl_api_->glWaitSyncFn(sync, flags, timeout);
}
void TraceGLApi::glWaitSyncAPPLEFn(GLsync sync,
GLbitfield flags,
GLuint64 timeout) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glWaitSyncAPPLE")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glWaitSyncAPPLE");
gl_api_->glWaitSyncAPPLEFn(sync, flags, timeout);
}
void TraceGLApi::glWindowRectanglesEXTFn(GLenum mode,
GLsizei n,
const GLint* box) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glWindowRectanglesEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glWindowRectanglesEXT");
gl_api_->glWindowRectanglesEXTFn(mode, n, box);
}
diff --git a/chromium/ui/gl/gl_bindings_autogen_glx.cc b/chromium/ui/gl/gl_bindings_autogen_glx.cc
index 6b32e953673..22dbef76570 100644
--- a/chromium/ui/gl/gl_bindings_autogen_glx.cc
+++ b/chromium/ui/gl/gl_bindings_autogen_glx.cc
@@ -462,7 +462,7 @@ void TraceGLXApi::glXBindTexImageEXTFn(Display* dpy,
GLXDrawable drawable,
int buffer,
int* attribList) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXBindTexImageEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXBindTexImageEXT");
glx_api_->glXBindTexImageEXTFn(dpy, drawable, buffer, attribList);
}
@@ -470,14 +470,14 @@ GLXFBConfig* TraceGLXApi::glXChooseFBConfigFn(Display* dpy,
int screen,
const int* attribList,
int* nitems) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXChooseFBConfig")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXChooseFBConfig");
return glx_api_->glXChooseFBConfigFn(dpy, screen, attribList, nitems);
}
XVisualInfo* TraceGLXApi::glXChooseVisualFn(Display* dpy,
int screen,
int* attribList) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXChooseVisual")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXChooseVisual");
return glx_api_->glXChooseVisualFn(dpy, screen, attribList);
}
@@ -485,7 +485,7 @@ void TraceGLXApi::glXCopyContextFn(Display* dpy,
GLXContext src,
GLXContext dst,
unsigned long mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCopyContext")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCopyContext");
glx_api_->glXCopyContextFn(dpy, src, dst, mask);
}
@@ -495,7 +495,7 @@ void TraceGLXApi::glXCopySubBufferMESAFn(Display* dpy,
int y,
int width,
int height) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCopySubBufferMESA")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCopySubBufferMESA");
glx_api_->glXCopySubBufferMESAFn(dpy, drawable, x, y, width, height);
}
@@ -503,7 +503,7 @@ GLXContext TraceGLXApi::glXCreateContextFn(Display* dpy,
XVisualInfo* vis,
GLXContext shareList,
int direct) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreateContext")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreateContext");
return glx_api_->glXCreateContextFn(dpy, vis, shareList, direct);
}
@@ -513,7 +513,7 @@ GLXContext TraceGLXApi::glXCreateContextAttribsARBFn(Display* dpy,
int direct,
const int* attrib_list) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLXAPI::glXCreateContextAttribsARB")
+ "TraceGLXAPI::glXCreateContextAttribsARB");
return glx_api_->glXCreateContextAttribsARBFn(dpy, config, share_context,
direct, attrib_list);
}
@@ -521,7 +521,7 @@ GLXContext TraceGLXApi::glXCreateContextAttribsARBFn(Display* dpy,
GLXPixmap TraceGLXApi::glXCreateGLXPixmapFn(Display* dpy,
XVisualInfo* visual,
Pixmap pixmap) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreateGLXPixmap")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreateGLXPixmap");
return glx_api_->glXCreateGLXPixmapFn(dpy, visual, pixmap);
}
@@ -530,7 +530,7 @@ GLXContext TraceGLXApi::glXCreateNewContextFn(Display* dpy,
int renderType,
GLXContext shareList,
int direct) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreateNewContext")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreateNewContext");
return glx_api_->glXCreateNewContextFn(dpy, config, renderType, shareList,
direct);
}
@@ -538,7 +538,7 @@ GLXContext TraceGLXApi::glXCreateNewContextFn(Display* dpy,
GLXPbuffer TraceGLXApi::glXCreatePbufferFn(Display* dpy,
GLXFBConfig config,
const int* attribList) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreatePbuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreatePbuffer");
return glx_api_->glXCreatePbufferFn(dpy, config, attribList);
}
@@ -546,7 +546,7 @@ GLXPixmap TraceGLXApi::glXCreatePixmapFn(Display* dpy,
GLXFBConfig config,
Pixmap pixmap,
const int* attribList) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreatePixmap")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreatePixmap");
return glx_api_->glXCreatePixmapFn(dpy, config, pixmap, attribList);
}
@@ -554,37 +554,37 @@ GLXWindow TraceGLXApi::glXCreateWindowFn(Display* dpy,
GLXFBConfig config,
Window win,
const int* attribList) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreateWindow")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXCreateWindow");
return glx_api_->glXCreateWindowFn(dpy, config, win, attribList);
}
void TraceGLXApi::glXDestroyContextFn(Display* dpy, GLXContext ctx) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXDestroyContext")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXDestroyContext");
glx_api_->glXDestroyContextFn(dpy, ctx);
}
void TraceGLXApi::glXDestroyGLXPixmapFn(Display* dpy, GLXPixmap pixmap) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXDestroyGLXPixmap")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXDestroyGLXPixmap");
glx_api_->glXDestroyGLXPixmapFn(dpy, pixmap);
}
void TraceGLXApi::glXDestroyPbufferFn(Display* dpy, GLXPbuffer pbuf) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXDestroyPbuffer")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXDestroyPbuffer");
glx_api_->glXDestroyPbufferFn(dpy, pbuf);
}
void TraceGLXApi::glXDestroyPixmapFn(Display* dpy, GLXPixmap pixmap) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXDestroyPixmap")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXDestroyPixmap");
glx_api_->glXDestroyPixmapFn(dpy, pixmap);
}
void TraceGLXApi::glXDestroyWindowFn(Display* dpy, GLXWindow window) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXDestroyWindow")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXDestroyWindow");
glx_api_->glXDestroyWindowFn(dpy, window);
}
const char* TraceGLXApi::glXGetClientStringFn(Display* dpy, int name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetClientString")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetClientString");
return glx_api_->glXGetClientStringFn(dpy, name);
}
@@ -592,27 +592,28 @@ int TraceGLXApi::glXGetConfigFn(Display* dpy,
XVisualInfo* visual,
int attrib,
int* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetConfig")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetConfig");
return glx_api_->glXGetConfigFn(dpy, visual, attrib, value);
}
GLXContext TraceGLXApi::glXGetCurrentContextFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetCurrentContext")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetCurrentContext");
return glx_api_->glXGetCurrentContextFn();
}
Display* TraceGLXApi::glXGetCurrentDisplayFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetCurrentDisplay")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetCurrentDisplay");
return glx_api_->glXGetCurrentDisplayFn();
}
GLXDrawable TraceGLXApi::glXGetCurrentDrawableFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetCurrentDrawable")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetCurrentDrawable");
return glx_api_->glXGetCurrentDrawableFn();
}
GLXDrawable TraceGLXApi::glXGetCurrentReadDrawableFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetCurrentReadDrawable")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLXAPI::glXGetCurrentReadDrawable");
return glx_api_->glXGetCurrentReadDrawableFn();
}
@@ -620,7 +621,7 @@ int TraceGLXApi::glXGetFBConfigAttribFn(Display* dpy,
GLXFBConfig config,
int attribute,
int* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetFBConfigAttrib")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetFBConfigAttrib");
return glx_api_->glXGetFBConfigAttribFn(dpy, config, attribute, value);
}
@@ -628,14 +629,14 @@ GLXFBConfig TraceGLXApi::glXGetFBConfigFromVisualSGIXFn(
Display* dpy,
XVisualInfo* visualInfo) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "TraceGLXAPI::glXGetFBConfigFromVisualSGIX")
+ "TraceGLXAPI::glXGetFBConfigFromVisualSGIX");
return glx_api_->glXGetFBConfigFromVisualSGIXFn(dpy, visualInfo);
}
GLXFBConfig* TraceGLXApi::glXGetFBConfigsFn(Display* dpy,
int screen,
int* nelements) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetFBConfigs")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetFBConfigs");
return glx_api_->glXGetFBConfigsFn(dpy, screen, nelements);
}
@@ -643,14 +644,14 @@ bool TraceGLXApi::glXGetMscRateOMLFn(Display* dpy,
GLXDrawable drawable,
int32_t* numerator,
int32_t* denominator) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetMscRateOML")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetMscRateOML");
return glx_api_->glXGetMscRateOMLFn(dpy, drawable, numerator, denominator);
}
void TraceGLXApi::glXGetSelectedEventFn(Display* dpy,
GLXDrawable drawable,
unsigned long* mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetSelectedEvent")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetSelectedEvent");
glx_api_->glXGetSelectedEventFn(dpy, drawable, mask);
}
@@ -659,18 +660,18 @@ bool TraceGLXApi::glXGetSyncValuesOMLFn(Display* dpy,
int64_t* ust,
int64_t* msc,
int64_t* sbc) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetSyncValuesOML")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetSyncValuesOML");
return glx_api_->glXGetSyncValuesOMLFn(dpy, drawable, ust, msc, sbc);
}
XVisualInfo* TraceGLXApi::glXGetVisualFromFBConfigFn(Display* dpy,
GLXFBConfig config) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetVisualFromFBConfig")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXGetVisualFromFBConfig");
return glx_api_->glXGetVisualFromFBConfigFn(dpy, config);
}
int TraceGLXApi::glXIsDirectFn(Display* dpy, GLXContext ctx) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXIsDirect")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXIsDirect");
return glx_api_->glXIsDirectFn(dpy, ctx);
}
@@ -678,14 +679,14 @@ int TraceGLXApi::glXMakeContextCurrentFn(Display* dpy,
GLXDrawable draw,
GLXDrawable read,
GLXContext ctx) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXMakeContextCurrent")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXMakeContextCurrent");
return glx_api_->glXMakeContextCurrentFn(dpy, draw, read, ctx);
}
int TraceGLXApi::glXMakeCurrentFn(Display* dpy,
GLXDrawable drawable,
GLXContext ctx) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXMakeCurrent")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXMakeCurrent");
return glx_api_->glXMakeCurrentFn(dpy, drawable, ctx);
}
@@ -693,7 +694,7 @@ int TraceGLXApi::glXQueryContextFn(Display* dpy,
GLXContext ctx,
int attribute,
int* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryContext")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryContext");
return glx_api_->glXQueryContextFn(dpy, ctx, attribute, value);
}
@@ -701,82 +702,82 @@ void TraceGLXApi::glXQueryDrawableFn(Display* dpy,
GLXDrawable draw,
int attribute,
unsigned int* value) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryDrawable")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryDrawable");
glx_api_->glXQueryDrawableFn(dpy, draw, attribute, value);
}
int TraceGLXApi::glXQueryExtensionFn(Display* dpy, int* errorb, int* event) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryExtension")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryExtension");
return glx_api_->glXQueryExtensionFn(dpy, errorb, event);
}
const char* TraceGLXApi::glXQueryExtensionsStringFn(Display* dpy, int screen) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryExtensionsString")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryExtensionsString");
return glx_api_->glXQueryExtensionsStringFn(dpy, screen);
}
const char* TraceGLXApi::glXQueryServerStringFn(Display* dpy,
int screen,
int name) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryServerString")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryServerString");
return glx_api_->glXQueryServerStringFn(dpy, screen, name);
}
int TraceGLXApi::glXQueryVersionFn(Display* dpy, int* maj, int* min) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryVersion")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXQueryVersion");
return glx_api_->glXQueryVersionFn(dpy, maj, min);
}
void TraceGLXApi::glXReleaseTexImageEXTFn(Display* dpy,
GLXDrawable drawable,
int buffer) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXReleaseTexImageEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXReleaseTexImageEXT");
glx_api_->glXReleaseTexImageEXTFn(dpy, drawable, buffer);
}
void TraceGLXApi::glXSelectEventFn(Display* dpy,
GLXDrawable drawable,
unsigned long mask) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXSelectEvent")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXSelectEvent");
glx_api_->glXSelectEventFn(dpy, drawable, mask);
}
void TraceGLXApi::glXSwapBuffersFn(Display* dpy, GLXDrawable drawable) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXSwapBuffers")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXSwapBuffers");
glx_api_->glXSwapBuffersFn(dpy, drawable);
}
void TraceGLXApi::glXSwapIntervalEXTFn(Display* dpy,
GLXDrawable drawable,
int interval) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXSwapIntervalEXT")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXSwapIntervalEXT");
glx_api_->glXSwapIntervalEXTFn(dpy, drawable, interval);
}
void TraceGLXApi::glXSwapIntervalMESAFn(unsigned int interval) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXSwapIntervalMESA")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXSwapIntervalMESA");
glx_api_->glXSwapIntervalMESAFn(interval);
}
void TraceGLXApi::glXUseXFontFn(Font font, int first, int count, int list) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXUseXFont")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXUseXFont");
glx_api_->glXUseXFontFn(font, first, count, list);
}
void TraceGLXApi::glXWaitGLFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXWaitGL")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXWaitGL");
glx_api_->glXWaitGLFn();
}
int TraceGLXApi::glXWaitVideoSyncSGIFn(int divisor,
int remainder,
unsigned int* count) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXWaitVideoSyncSGI")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXWaitVideoSyncSGI");
return glx_api_->glXWaitVideoSyncSGIFn(divisor, remainder, count);
}
void TraceGLXApi::glXWaitXFn(void) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXWaitX")
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLXAPI::glXWaitX");
glx_api_->glXWaitXFn();
}
diff --git a/chromium/ui/gl/gl_context.cc b/chromium/ui/gl/gl_context.cc
index 59091708368..cc8adf06ab2 100644
--- a/chromium/ui/gl/gl_context.cc
+++ b/chromium/ui/gl/gl_context.cc
@@ -281,17 +281,10 @@ void GLContext::DestroyBackpressureFences() {
void GLContext::FlushForDriverCrashWorkaround() {
// If running on Apple silicon, regardless of the architecture, disable this
- // workaround.
- // https://crbug.com/1131312
- switch (base::mac::GetCPUType()) {
- case base::mac::CPUType::kArm:
- case base::mac::CPUType::kTranslatedIntel:
- return;
- default:
- break;
- }
-
- if (!IsCurrent(nullptr))
+ // workaround. See https://crbug.com/1131312.
+ static const bool needs_flush =
+ base::mac::GetCPUType() == base::mac::CPUType::kIntel;
+ if (!needs_flush || !IsCurrent(nullptr))
return;
TRACE_EVENT0("gpu", "GLContext::FlushForDriverCrashWorkaround");
glFlush();
diff --git a/chromium/ui/gl/gl_context.h b/chromium/ui/gl/gl_context.h
index 47c9403aec3..09c57f3e612 100644
--- a/chromium/ui/gl/gl_context.h
+++ b/chromium/ui/gl/gl_context.h
@@ -95,6 +95,16 @@ struct GL_EXPORT GLContextAttribs {
// (True by default to match previous behavior.)
bool lose_context_on_reset = true;
+ // If true, EGL_ANGLE_external_context_and_surface extension will be used to
+ // create ANGLE context from the current native EGL context.
+ bool angle_create_from_external_context = false;
+
+ // If true, an ANGLE external context will be created with
+ // EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE is true, so when ReleaseCurrent is
+ // called, ANGLE will restore the GL state of the native EGL context to the
+ // state when MakeCurrent was previously called.
+ bool angle_restore_external_context_state = false;
+
ContextPriority context_priority = ContextPriorityMedium;
};
diff --git a/chromium/ui/gl/gl_context_egl.cc b/chromium/ui/gl/gl_context_egl.cc
index b5219ca17e0..a6870ee21c2 100644
--- a/chromium/ui/gl/gl_context_egl.cc
+++ b/chromium/ui/gl/gl_context_egl.cc
@@ -40,6 +40,13 @@
#define EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE 0x348D
#endif /* EGL_ANGLE_display_semaphore_share_group */
+#ifndef EGL_ANGLE_external_context_and_surface
+#define EGL_ANGLE_external_context_and_surface 1
+#define EGL_EXTERNAL_CONTEXT_ANGLE 0x348E
+#define EGL_EXTERNAL_SURFACE_ANGLE 0x348F
+#define EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE 0x3490
+#endif /* EGL_ANGLE_external_context_and_surface */
+
#ifndef EGL_ANGLE_create_context_client_arrays
#define EGL_ANGLE_create_context_client_arrays 1
#define EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE 0x3452
@@ -247,6 +254,17 @@ bool GLContextEGL::Initialize(GLSurface* compatible_surface,
}
}
+ if (GLSurfaceEGL::IsANGLEExternalContextAndSurfaceSupported()) {
+ if (attribs.angle_create_from_external_context) {
+ context_attributes.push_back(EGL_EXTERNAL_CONTEXT_ANGLE);
+ context_attributes.push_back(EGL_TRUE);
+ }
+ if (attribs.angle_restore_external_context_state) {
+ context_attributes.push_back(EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE);
+ context_attributes.push_back(EGL_TRUE);
+ }
+ }
+
// Append final EGL_NONE to signal the context attributes are finished
context_attributes.push_back(EGL_NONE);
context_attributes.push_back(EGL_NONE);
@@ -365,9 +383,9 @@ bool GLContextEGL::MakeCurrentImpl(GLSurface* surface) {
return true;
ScopedReleaseCurrent release_current;
- TRACE_EVENT2("gpu", "GLContextEGL::MakeCurrent",
- "context", context_,
- "surface", surface);
+ TRACE_EVENT2("gpu", "GLContextEGL::MakeCurrent", "context",
+ static_cast<void*>(context_), "surface",
+ static_cast<void*>(surface));
if (unbind_fbo_on_makecurrent_ && GetCurrent()) {
glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
diff --git a/chromium/ui/gl/gl_context_glx_unittest.cc b/chromium/ui/gl/gl_context_glx_unittest.cc
index c3bb1bb4ec9..85bcb6446f1 100644
--- a/chromium/ui/gl/gl_context_glx_unittest.cc
+++ b/chromium/ui/gl/gl_context_glx_unittest.cc
@@ -7,6 +7,7 @@
#include "base/memory/scoped_refptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/xproto.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_surface_glx_x11.h"
diff --git a/chromium/ui/gl/gl_features.cc b/chromium/ui/gl/gl_features.cc
index 56ef4a3aa74..c71e70c3d9d 100644
--- a/chromium/ui/gl/gl_features.cc
+++ b/chromium/ui/gl/gl_features.cc
@@ -4,7 +4,17 @@
#include "ui/gl/gl_features.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "build/chromeos_buildflags.h"
+#include "ui/gl/gl_switches.h"
+
namespace features {
+namespace {
+
+const base::Feature kGpuVsync{"GpuVsync", base::FEATURE_ENABLED_BY_DEFAULT};
+
+} // namespace
// Use the passthrough command decoder by default. This can be overridden with
// the --use-cmd-decoder=passthrough or --use-cmd-decoder=validating flags.
@@ -13,12 +23,19 @@ namespace features {
// Launched on Windows, still experimental on other platforms.
const base::Feature kDefaultPassthroughCommandDecoder{
"DefaultPassthroughCommandDecoder",
-#if defined(OS_WIN) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(CHROMECAST_BUILD))
+#if defined(OS_WIN) || \
+ ((defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
+ !defined(CHROMECAST_BUILD))
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
#endif
};
+bool UseGpuVsync() {
+ return !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuVsync) &&
+ base::FeatureList::IsEnabled(kGpuVsync);
+}
+
} // namespace features
diff --git a/chromium/ui/gl/gl_features.h b/chromium/ui/gl/gl_features.h
index 3513df18ca1..e84a953c2c0 100644
--- a/chromium/ui/gl/gl_features.h
+++ b/chromium/ui/gl/gl_features.h
@@ -11,6 +11,9 @@
namespace features {
+// Controls if GPU should synchronize presentation with vsync.
+GL_EXPORT bool UseGpuVsync();
+
// All features in alphabetical order. The features should be documented
// alongside the definition of their values in the .cc file.
GL_EXPORT extern const base::Feature kDefaultPassthroughCommandDecoder;
diff --git a/chromium/ui/gl/gl_gl_api_implementation.cc b/chromium/ui/gl/gl_gl_api_implementation.cc
index 2815f8e3f24..c172e834e90 100644
--- a/chromium/ui/gl/gl_gl_api_implementation.cc
+++ b/chromium/ui/gl/gl_gl_api_implementation.cc
@@ -6,7 +6,7 @@
#include <vector>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "ui/gl/gl_context.h"
diff --git a/chromium/ui/gl/gl_glx_api_implementation.cc b/chromium/ui/gl/gl_glx_api_implementation.cc
index 4881a3e2c2d..5c6ebe311d6 100644
--- a/chromium/ui/gl/gl_glx_api_implementation.cc
+++ b/chromium/ui/gl/gl_glx_api_implementation.cc
@@ -8,6 +8,7 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_implementation_wrapper.h"
@@ -127,11 +128,11 @@ bool GetGLWindowSystemBindingInfoGLX(const GLVersionInfo& gl_info,
base::StringToUint(split_version[0], &major_num);
// Mesa after version 17 will reliably use DRI3 when available.
- if (major_num >= 17 && connection->QueryExtension({"DRI3"}).Sync())
+ if (major_num >= 17 && connection->QueryExtension("DRI3").Sync())
info->direct_rendering_version = "2.3";
- else if (connection->QueryExtension({"DRI2"}).Sync())
+ else if (connection->QueryExtension("DRI2").Sync())
info->direct_rendering_version = "2.2";
- else if (connection->QueryExtension({"DRI"}).Sync())
+ else if (connection->QueryExtension("DRI").Sync())
info->direct_rendering_version = "2.1";
}
} else {
diff --git a/chromium/ui/gl/gl_image.cc b/chromium/ui/gl/gl_image.cc
index 768a48f66a6..2ff44864041 100644
--- a/chromium/ui/gl/gl_image.cc
+++ b/chromium/ui/gl/gl_image.cc
@@ -29,7 +29,9 @@ unsigned GLImage::GetDataFormat() {
unsigned internalformat = GetInternalFormat();
switch (internalformat) {
case GL_R16_EXT:
- return GL_RED;
+ return GL_RED_EXT;
+ case GL_RG16_EXT:
+ return GL_RG_EXT;
case GL_RGB10_A2_EXT:
return GL_RGBA;
case GL_RGB_YCRCB_420_CHROMIUM:
diff --git a/chromium/ui/gl/gl_image_egl.cc b/chromium/ui/gl/gl_image_egl.cc
index 1dad98992b0..930d35e7bca 100644
--- a/chromium/ui/gl/gl_image_egl.cc
+++ b/chromium/ui/gl/gl_image_egl.cc
@@ -5,6 +5,7 @@
#include "ui/gl/gl_image_egl.h"
#include "ui/gl/egl_util.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_enums.h"
#include "ui/gl/gl_surface_egl.h"
diff --git a/chromium/ui/gl/gl_image_glx_native_pixmap.cc b/chromium/ui/gl/gl_image_glx_native_pixmap.cc
index 1250ab0eee0..a8b261479f9 100644
--- a/chromium/ui/gl/gl_image_glx_native_pixmap.cc
+++ b/chromium/ui/gl/gl_image_glx_native_pixmap.cc
@@ -9,6 +9,7 @@
#include "ui/gfx/linux/native_pixmap_dmabuf.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/dri3.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/xproto_types.h"
#include "ui/gl/buffer_format_utils.h"
#include "ui/gl/gl_bindings.h"
@@ -55,16 +56,16 @@ x11::Pixmap XPixmapFromNativePixmap(
auto fd = HANDLE_EINTR(dup(native_pixmap.GetDmaBufFd(0)));
if (fd < 0)
return x11::Pixmap::None;
- base::ScopedFD scoped_fd(fd);
+ x11::RefCountedFD ref_counted_fd(fd);
auto* connection = x11::Connection::Get();
x11::Pixmap pixmap_id = connection->GenerateId<x11::Pixmap>();
- connection->dri3().PixmapFromBuffer({pixmap_id, connection->default_root(),
- native_pixmap.GetDmaBufPlaneSize(0),
- native_pixmap.GetBufferSize().width(),
- native_pixmap.GetBufferSize().height(),
- native_pixmap.GetDmaBufPitch(0), depth,
- bpp, std::move(scoped_fd)});
+ connection->dri3().PixmapFromBuffer(pixmap_id, connection->default_root(),
+ native_pixmap.GetDmaBufPlaneSize(0),
+ native_pixmap.GetBufferSize().width(),
+ native_pixmap.GetBufferSize().height(),
+ native_pixmap.GetDmaBufPitch(0), depth,
+ bpp, ref_counted_fd);
return pixmap_id;
}
diff --git a/chromium/ui/gl/gl_image_io_surface.h b/chromium/ui/gl/gl_image_io_surface.h
index e78cb1a066e..2c765ca2958 100644
--- a/chromium/ui/gl/gl_image_io_surface.h
+++ b/chromium/ui/gl/gl_image_io_surface.h
@@ -81,6 +81,10 @@ class GL_EXPORT GLImageIOSurface : public GLImage {
// RGB transformation.
void SetColorSpaceForYUVToRGBConversion(const gfx::ColorSpace& color_space);
+ // Sets the color space of the GLImage without modifying the underlying
+ // IOSurface. Callers should ensure the color spaces match.
+ void SetColorSpaceShallow(const gfx::ColorSpace& color_space);
+
static unsigned GetInternalFormatForTesting(gfx::BufferFormat format);
// Downcasts from |image|. Returns |nullptr| on failure.
diff --git a/chromium/ui/gl/gl_image_io_surface.mm b/chromium/ui/gl/gl_image_io_surface.mm
index 94b1fcdc26c..697d6e26127 100644
--- a/chromium/ui/gl/gl_image_io_surface.mm
+++ b/chromium/ui/gl/gl_image_io_surface.mm
@@ -457,6 +457,11 @@ void GLImageIOSurface::SetColorSpaceForYUVToRGBConversion(
color_space_for_yuv_to_rgb_ = color_space;
}
+void GLImageIOSurface::SetColorSpaceShallow(
+ const gfx::ColorSpace& color_space) {
+ GLImage::SetColorSpace(color_space);
+}
+
base::ScopedCFTypeRef<IOSurfaceRef> GLImageIOSurface::io_surface() {
return io_surface_;
}
diff --git a/chromium/ui/gl/gl_image_io_surface_egl.mm b/chromium/ui/gl/gl_image_io_surface_egl.mm
index 4ecaffb91c1..82222eeb9c9 100644
--- a/chromium/ui/gl/gl_image_io_surface_egl.mm
+++ b/chromium/ui/gl/gl_image_io_surface_egl.mm
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/scoped_binders.h"
diff --git a/chromium/ui/gl/gl_image_native_pixmap.cc b/chromium/ui/gl/gl_image_native_pixmap.cc
index bf785d00993..c768647099f 100644
--- a/chromium/ui/gl/gl_image_native_pixmap.cc
+++ b/chromium/ui/gl/gl_image_native_pixmap.cc
@@ -13,6 +13,7 @@
#include "ui/gfx/gpu_fence.h"
#include "ui/gl/buffer_format_utils.h"
#include "ui/gl/egl_util.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_enums.h"
#include "ui/gl/gl_surface_egl.h"
diff --git a/chromium/ui/gl/gl_implementation.cc b/chromium/ui/gl/gl_implementation.cc
index 433cbe8d9d9..763c1cc11c1 100644
--- a/chromium/ui/gl/gl_implementation.cc
+++ b/chromium/ui/gl/gl_implementation.cc
@@ -11,6 +11,7 @@
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
+#include "base/containers/contains.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
@@ -265,8 +266,10 @@ bool WillUseGLGetStringForExtensions() {
bool WillUseGLGetStringForExtensions(GLApi* api) {
const char* version_str =
reinterpret_cast<const char*>(api->glGetStringFn(GL_VERSION));
+ const char* renderer_str =
+ reinterpret_cast<const char*>(api->glGetStringFn(GL_RENDERER));
gfx::ExtensionSet extensions;
- GLVersionInfo version_info(version_str, nullptr, extensions);
+ GLVersionInfo version_info(version_str, renderer_str, extensions);
return version_info.is_es || version_info.major_version < 3;
}
@@ -286,4 +289,10 @@ base::NativeLibrary LoadLibraryAndPrintError(const base::FilePath& filename) {
return library;
}
+#if BUILDFLAG(USE_OPENGL_APITRACE)
+void TerminateFrame() {
+ GetGLProcAddress("glFrameTerminatorGREMEDY")();
+}
+#endif
+
} // namespace gl
diff --git a/chromium/ui/gl/gl_implementation.h b/chromium/ui/gl/gl_implementation.h
index ffe19f448d4..c6cefe206be 100644
--- a/chromium/ui/gl/gl_implementation.h
+++ b/chromium/ui/gl/gl_implementation.h
@@ -13,6 +13,7 @@
#include "base/native_library.h"
#include "build/build_config.h"
#include "ui/gfx/extension_set.h"
+#include "ui/gl/buildflags.h"
#include "ui/gl/gl_export.h"
#include "ui/gl/gl_switches.h"
@@ -161,6 +162,11 @@ GL_EXPORT base::NativeLibrary LoadLibraryAndPrintError(
GL_EXPORT base::NativeLibrary LoadLibraryAndPrintError(
const base::FilePath& filename);
+#if BUILDFLAG(USE_OPENGL_APITRACE)
+// Notify end of frame at buffer swap request.
+GL_EXPORT void TerminateFrame();
+#endif
+
} // namespace gl
#endif // UI_GL_GL_IMPLEMENTATION_H_
diff --git a/chromium/ui/gl/gl_surface.cc b/chromium/ui/gl/gl_surface.cc
index 8284db4f327..9d304c947d5 100644
--- a/chromium/ui/gl/gl_surface.cc
+++ b/chromium/ui/gl/gl_surface.cc
@@ -197,6 +197,10 @@ bool GLSurface::SupportsProtectedVideo() const {
return false;
}
+bool GLSurface::SupportsOverridePlatformSize() const {
+ return false;
+}
+
bool GLSurface::SetDrawRectangle(const gfx::Rect& rect) {
return false;
}
@@ -241,6 +245,10 @@ bool GLSurface::SupportsGpuVSync() const {
return false;
}
+bool GLSurface::SupportsDelegatedInk() {
+ return false;
+}
+
void GLSurface::SetGpuVSyncEnabled(bool enabled) {}
GLSurface* GLSurface::GetCurrent() {
@@ -465,6 +473,10 @@ bool GLSurfaceAdapter::SupportsProtectedVideo() const {
return surface_->SupportsProtectedVideo();
}
+bool GLSurfaceAdapter::SupportsOverridePlatformSize() const {
+ return surface_->SupportsOverridePlatformSize();
+}
+
bool GLSurfaceAdapter::SetDrawRectangle(const gfx::Rect& rect) {
return surface_->SetDrawRectangle(rect);
}
@@ -521,6 +533,10 @@ bool GLSurfaceAdapter::IsCurrent() {
return surface_->IsCurrent();
}
+bool GLSurfaceAdapter::SupportsDelegatedInk() {
+ return surface_->SupportsDelegatedInk();
+}
+
GLSurfaceAdapter::~GLSurfaceAdapter() {}
scoped_refptr<GLSurface> InitializeGLSurfaceWithFormat(
diff --git a/chromium/ui/gl/gl_surface.h b/chromium/ui/gl/gl_surface.h
index 44ad2952959..6fc339049f5 100644
--- a/chromium/ui/gl/gl_surface.h
+++ b/chromium/ui/gl/gl_surface.h
@@ -107,6 +107,10 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface>,
// Get the underlying platform specific surface "handle".
virtual void* GetHandle() = 0;
+ // Android SurfaceControl specific, notifies that we should not detach child
+ // surface controls during destruction.
+ virtual void PreserveChildSurfaceControls() {}
+
// Returns whether or not the surface supports SwapBuffersWithBounds
virtual bool SupportsSwapBuffersWithBounds();
@@ -267,6 +271,10 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface>,
virtual bool SupportsProtectedVideo() const;
+ // Returns true if we are allowed to adopt a size different from the
+ // platform's proposed surface size.
+ virtual bool SupportsOverridePlatformSize() const;
+
// Set the rectangle that will be drawn into on the surface, returning
// success. If failed, it is possible that the context is no longer current.
virtual bool SetDrawRectangle(const gfx::Rect& rect);
@@ -309,6 +317,8 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface>,
static bool ExtensionsContain(const char* extensions, const char* name);
+ virtual bool SupportsDelegatedInk();
+
protected:
virtual ~GLSurface();
@@ -387,6 +397,7 @@ class GL_EXPORT GLSurfaceAdapter : public GLSurface {
bool BuffersFlipped() const override;
bool SupportsDCLayers() const override;
bool SupportsProtectedVideo() const override;
+ bool SupportsOverridePlatformSize() const override;
bool SetDrawRectangle(const gfx::Rect& rect) override;
gfx::Vector2d GetDrawOffset() const override;
void SetRelyOnImplicitSync() override;
@@ -402,6 +413,8 @@ class GL_EXPORT GLSurfaceAdapter : public GLSurface {
void SetCurrent() override;
bool IsCurrent() override;
+ bool SupportsDelegatedInk() override;
+
GLSurface* surface() const { return surface_.get(); }
protected:
diff --git a/chromium/ui/gl/gl_surface_egl.cc b/chromium/ui/gl/gl_surface_egl.cc
index 054b4b4e9c1..d6ca1917f0d 100644
--- a/chromium/ui/gl/gl_surface_egl.cc
+++ b/chromium/ui/gl/gl_surface_egl.cc
@@ -9,14 +9,16 @@
#include <map>
#include <memory>
+#include <sstream>
#include <vector>
#include "base/command_line.h"
+#include "base/containers/contains.h"
+#include "base/debug/crash_logging.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/system/sys_info.h"
@@ -27,6 +29,7 @@
#include "ui/gfx/gpu_fence.h"
#include "ui/gl/angle_platform_impl.h"
#include "ui/gl/egl_util.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_context_egl.h"
#include "ui/gl/gl_display_egl_util.h"
@@ -181,6 +184,7 @@ class EGLGpuSwitchingObserver;
EGLDisplay g_egl_display = EGL_NO_DISPLAY;
EGLDisplayPlatform g_native_display(EGL_DEFAULT_DISPLAY);
+const char* g_egl_client_extensions = nullptr;
const char* g_egl_extensions = nullptr;
bool g_egl_create_context_robustness_supported = false;
bool g_egl_robustness_video_memory_purge_supported = false;
@@ -204,6 +208,7 @@ bool g_egl_android_native_fence_sync_supported = false;
bool g_egl_ext_pixel_format_float_supported = false;
bool g_egl_angle_feature_control_supported = false;
bool g_egl_angle_power_preference_supported = false;
+bool g_egl_angle_external_context_and_surface_supported = false;
EGLGpuSwitchingObserver* g_egl_gpu_switching_observer = nullptr;
constexpr const char kSwapEventTraceCategories[] = "gpu";
@@ -822,6 +827,11 @@ void GetEGLInitDisplays(bool supports_angle_d3d,
AddInitDisplay(init_displays, ANGLE_METAL);
}
+ if (supports_angle_vulkan && use_angle_default &&
+ features::IsDefaultANGLEVulkan()) {
+ AddInitDisplay(init_displays, ANGLE_VULKAN);
+ }
+
if (supports_angle_d3d) {
if (use_angle_default) {
// Default mode for ANGLE - try D3D11, else try D3D9
@@ -952,6 +962,7 @@ bool GLSurfaceEGL::InitializeOneOffForTesting() {
// static
bool GLSurfaceEGL::InitializeOneOffCommon() {
+ g_egl_client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
g_egl_extensions = eglQueryString(g_egl_display, EGL_EXTENSIONS);
g_egl_create_context_robustness_supported =
@@ -1059,6 +1070,9 @@ bool GLSurfaceEGL::InitializeOneOffCommon() {
g_egl_angle_power_preference_supported =
HasEGLExtension("EGL_ANGLE_power_preference");
+ g_egl_angle_external_context_and_surface_supported =
+ HasEGLExtension("EGL_ANGLE_external_context_and_surface");
+
if (g_egl_angle_power_preference_supported) {
g_egl_gpu_switching_observer = new EGLGpuSwitchingObserver();
ui::GpuSwitchingManager::GetInstance()->AddObserver(
@@ -1074,6 +1088,7 @@ bool GLSurfaceEGL::InitializeExtensionSettingsOneOff() {
if (!initialized_)
return false;
g_driver_egl.UpdateConditionalExtensionBindings();
+ g_egl_client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
g_egl_extensions = eglQueryString(g_egl_display, EGL_EXTENSIONS);
return true;
@@ -1096,6 +1111,7 @@ void GLSurfaceEGL::ShutdownOneOff() {
}
g_egl_display = EGL_NO_DISPLAY;
+ g_egl_client_extensions = nullptr;
g_egl_extensions = nullptr;
g_egl_create_context_robustness_supported = false;
g_egl_robustness_video_memory_purge_supported = false;
@@ -1125,11 +1141,21 @@ EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() {
}
// static
+const char* GLSurfaceEGL::GetEGLClientExtensions() {
+ return g_egl_client_extensions ? g_egl_client_extensions : "";
+}
+
+// static
const char* GLSurfaceEGL::GetEGLExtensions() {
return g_egl_extensions;
}
// static
+bool GLSurfaceEGL::HasEGLClientExtension(const char* name) {
+ return ExtensionsContain(GetEGLClientExtensions(), name);
+}
+
+// static
bool GLSurfaceEGL::HasEGLExtension(const char* name) {
return ExtensionsContain(GetEGLExtensions(), name);
}
@@ -1199,7 +1225,11 @@ bool GLSurfaceEGL::IsANGLEPowerPreferenceSupported() {
return g_egl_angle_power_preference_supported;
}
-GLSurfaceEGL::~GLSurfaceEGL() {}
+bool GLSurfaceEGL::IsANGLEExternalContextAndSurfaceSupported() {
+ return g_egl_angle_external_context_and_surface_supported;
+}
+
+GLSurfaceEGL::~GLSurfaceEGL() = default;
// InitializeDisplay is necessary because the static binding code
// needs a full Display init before it can query the Display extensions.
@@ -1213,12 +1243,9 @@ EGLDisplay GLSurfaceEGL::InitializeDisplay(EGLDisplayPlatform native_display) {
// If EGL_EXT_client_extensions not supported this call to eglQueryString
// will return NULL.
- const char* client_extensions =
- eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+ g_egl_client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
- bool supports_egl_debug =
- client_extensions &&
- ExtensionsContain(client_extensions, "EGL_KHR_debug");
+ bool supports_egl_debug = HasEGLClientExtension("EGL_KHR_debug");
if (supports_egl_debug) {
EGLAttrib controls[] = {
EGL_DEBUG_MSG_CRITICAL_KHR,
@@ -1244,32 +1271,28 @@ EGLDisplay GLSurfaceEGL::InitializeDisplay(EGLDisplayPlatform native_display) {
bool supports_angle_egl = false;
bool supports_angle_metal = false;
// Check for availability of ANGLE extensions.
- if (client_extensions &&
- ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle")) {
- supports_angle_d3d =
- ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle_d3d");
+ if (HasEGLClientExtension("EGL_ANGLE_platform_angle")) {
+ supports_angle_d3d = HasEGLClientExtension("EGL_ANGLE_platform_angle_d3d");
supports_angle_opengl =
- ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle_opengl");
+ HasEGLClientExtension("EGL_ANGLE_platform_angle_opengl");
supports_angle_null =
- ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle_null");
+ HasEGLClientExtension("EGL_ANGLE_platform_angle_null");
supports_angle_vulkan =
- ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle_vulkan");
- supports_angle_swiftshader = ExtensionsContain(
- client_extensions, "EGL_ANGLE_platform_angle_device_type_swiftshader");
- supports_angle_egl = ExtensionsContain(
- client_extensions, "EGL_ANGLE_platform_angle_device_type_egl_angle");
+ HasEGLClientExtension("EGL_ANGLE_platform_angle_vulkan");
+ supports_angle_swiftshader = HasEGLClientExtension(
+ "EGL_ANGLE_platform_angle_device_type_swiftshader");
+ supports_angle_egl =
+ HasEGLClientExtension("EGL_ANGLE_platform_angle_device_type_egl_angle");
supports_angle_metal =
- ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle_metal");
+ HasEGLClientExtension("EGL_ANGLE_platform_angle_metal");
}
bool supports_angle = supports_angle_d3d || supports_angle_opengl ||
supports_angle_null || supports_angle_vulkan ||
supports_angle_swiftshader || supports_angle_metal;
- if (client_extensions) {
- g_egl_angle_feature_control_supported =
- ExtensionsContain(client_extensions, "EGL_ANGLE_feature_control");
- }
+ g_egl_angle_feature_control_supported =
+ HasEGLClientExtension("EGL_ANGLE_feature_control");
std::vector<DisplayType> init_displays;
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -1322,12 +1345,25 @@ EGLDisplay GLSurfaceEGL::InitializeDisplay(EGLDisplayPlatform native_display) {
LOG(ERROR) << "eglInitialize " << DisplayTypeString(display_type)
<< " failed with error " << GetLastEGLErrorString()
<< (is_last ? "" : ", trying next display type");
- } else {
- UMA_HISTOGRAM_ENUMERATION("GPU.EGLDisplayType", display_type,
- DISPLAY_TYPE_MAX);
- g_egl_display = display;
- break;
+ continue;
}
+
+ std::ostringstream display_type_string;
+ auto gl_implementation = GetGLImplementation();
+ display_type_string << GetGLImplementationName(gl_implementation);
+ if (gl_implementation == kGLImplementationEGLANGLE) {
+ display_type_string << ":" << DisplayTypeString(display_type);
+ }
+
+ static auto* egl_display_type_key = base::debug::AllocateCrashKeyString(
+ "egl-display-type", base::debug::CrashKeySize::Size32);
+ base::debug::SetCrashKeyString(egl_display_type_key,
+ display_type_string.str());
+
+ UMA_HISTOGRAM_ENUMERATION("GPU.EGLDisplayType", display_type,
+ DISPLAY_TYPE_MAX);
+ g_egl_display = display;
+ break;
}
return g_egl_display;
diff --git a/chromium/ui/gl/gl_surface_egl.h b/chromium/ui/gl/gl_surface_egl.h
index 9bda1ab9f97..33f36aed459 100644
--- a/chromium/ui/gl/gl_surface_egl.h
+++ b/chromium/ui/gl/gl_surface_egl.h
@@ -9,6 +9,9 @@
#include <windows.h>
#endif
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
#include <memory>
#include <string>
#include <vector>
@@ -22,7 +25,6 @@
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/gl/egl_timestamps.h"
-#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_export.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_surface_overlay.h"
@@ -106,7 +108,9 @@ class GL_EXPORT GLSurfaceEGL : public GLSurface {
// These aren't particularly tied to surfaces, but since we already
// have the static InitializeOneOff here, it's easiest to reuse its
// initialization guards.
+ static const char* GetEGLClientExtensions();
static const char* GetEGLExtensions();
+ static bool HasEGLClientExtension(const char* name);
static bool HasEGLExtension(const char* name);
static bool IsCreateContextRobustnessSupported();
static bool IsRobustnessVideoMemoryPurgeSupported();
@@ -123,6 +127,7 @@ class GL_EXPORT GLSurfaceEGL : public GLSurface {
static bool IsPixelFormatFloatSupported();
static bool IsANGLEFeatureControlSupported();
static bool IsANGLEPowerPreferenceSupported();
+ static bool IsANGLEExternalContextAndSurfaceSupported();
protected:
~GLSurfaceEGL() override;
diff --git a/chromium/ui/gl/gl_surface_egl_surface_control.cc b/chromium/ui/gl/gl_surface_egl_surface_control.cc
index b0e7c0ff001..66a7c373337 100644
--- a/chromium/ui/gl/gl_surface_egl_surface_control.cc
+++ b/chromium/ui/gl/gl_surface_egl_surface_control.cc
@@ -113,7 +113,24 @@ void GLSurfaceEGLSurfaceControl::PrepareToDestroy(bool have_context) {
weak_factory_.InvalidateWeakPtrs();
}
+void GLSurfaceEGLSurfaceControl::PreserveChildSurfaceControls() {
+ TRACE_EVENT_INSTANT0(
+ "gpu", "GLSurfaceEGLSurfaceControl::PreserveChildSurfaceControls",
+ TRACE_EVENT_SCOPE_THREAD);
+ preserve_children_ = true;
+}
+
void GLSurfaceEGLSurfaceControl::Destroy() {
+ TRACE_EVENT0("gpu", "GLSurfaceEGLSurfaceControl::Destroy");
+ // Detach all child layers to prevent leaking unless browser asked us not too.
+ if (!preserve_children_) {
+ gfx::SurfaceControl::Transaction transaction;
+ for (auto& surface : surface_list_) {
+ transaction.SetParent(*surface.surface, nullptr);
+ }
+ transaction.Apply();
+ }
+
pending_transaction_.reset();
surface_list_.clear();
root_surface_.reset();
diff --git a/chromium/ui/gl/gl_surface_egl_surface_control.h b/chromium/ui/gl/gl_surface_egl_surface_control.h
index 57e634189b0..ba24b4ca19a 100644
--- a/chromium/ui/gl/gl_surface_egl_surface_control.h
+++ b/chromium/ui/gl/gl_surface_egl_surface_control.h
@@ -55,6 +55,7 @@ class GL_EXPORT GLSurfaceEGLSurfaceControl : public GLSurfaceEGL {
std::unique_ptr<gfx::GpuFence> gpu_fence) override;
bool IsSurfaceless() const override;
void* GetHandle() override;
+ void PreserveChildSurfaceControls() override;
// Sync versions of frame update, should never be used.
gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
@@ -251,6 +252,8 @@ class GL_EXPORT GLSurfaceEGLSurfaceControl : public GLSurfaceEGL {
TransactionAckTimeoutManager transaction_ack_timeout_manager_;
+ bool preserve_children_ = false;
+
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
base::WeakPtrFactory<GLSurfaceEGLSurfaceControl> weak_factory_{this};
};
diff --git a/chromium/ui/gl/gl_surface_egl_unittest.cc b/chromium/ui/gl/gl_surface_egl_unittest.cc
index 368d167412e..9f75776dd5d 100644
--- a/chromium/ui/gl/gl_surface_egl_unittest.cc
+++ b/chromium/ui/gl/gl_surface_egl_unittest.cc
@@ -7,6 +7,7 @@
#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/init/gl_factory.h"
diff --git a/chromium/ui/gl/gl_surface_egl_x11.cc b/chromium/ui/gl/gl_surface_egl_x11.cc
index ae4e6850003..980227258b2 100644
--- a/chromium/ui/gl/gl_surface_egl_x11.cc
+++ b/chromium/ui/gl/gl_surface_egl_x11.cc
@@ -4,6 +4,7 @@
#include "ui/gl/gl_surface_egl_x11.h"
+#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/base/x/x11_display_util.h"
#include "ui/base/x/x11_util.h"
@@ -54,6 +55,9 @@ bool NativeViewGLSurfaceEGLX11::Initialize(GLSurfaceFormat format) {
return false;
auto* connection = x11::Connection::Get();
+ // Synchronize the Xlib display to ensure ANGLE's CreateWindow request
+ // completes before we make our QueryTree request below.
+ connection->GetXlibDisplay(x11::XlibDisplayType::kSyncing);
// Query all child windows and store them. ANGLE creates a child window when
// eglCreateWindowSurface is called on X11 and expose events from this window
// need to be received by this class. Since ANGLE is using a separate
@@ -67,17 +71,15 @@ bool NativeViewGLSurfaceEGLX11::Initialize(GLSurfaceFormat format) {
{.window = child, .event_mask = x11::EventMask::Exposure});
}
- if (ui::X11EventSource::HasInstance()) {
- dispatcher_set_ = true;
- ui::X11EventSource::GetInstance()->AddXEventDispatcher(this);
- }
+ dispatcher_set_ = true;
+ connection->AddEventObserver(this);
return true;
}
void NativeViewGLSurfaceEGLX11::Destroy() {
NativeViewGLSurfaceEGL::Destroy();
- if (dispatcher_set_ && ui::X11EventSource::HasInstance())
- ui::X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+ if (dispatcher_set_)
+ x11::Connection::Get()->RemoveEventObserver(this);
}
gfx::SwapResult NativeViewGLSurfaceEGLX11::SwapBuffers(
@@ -114,21 +116,18 @@ NativeViewGLSurfaceEGLX11::CreateVsyncProviderInternal() {
return std::make_unique<XrandrIntervalOnlyVSyncProvider>();
}
-bool NativeViewGLSurfaceEGLX11::DispatchXEvent(x11::Event* x11_event) {
+void NativeViewGLSurfaceEGLX11::OnEvent(const x11::Event& x11_event) {
// When ANGLE is used for EGL, it creates an X11 child window. Expose events
// from this window need to be forwarded to this class.
- auto* expose = x11_event->As<x11::ExposeEvent>();
- bool can_dispatch = expose && std::find(children_.begin(), children_.end(),
- expose->window) != children_.end();
- if (!can_dispatch)
- return false;
+ auto* expose = x11_event.As<x11::ExposeEvent>();
+ if (!expose || !base::Contains(children_, expose->window))
+ return;
auto expose_copy = *expose;
auto window = static_cast<x11::Window>(window_);
expose_copy.window = window;
x11::SendEvent(expose_copy, window, x11::EventMask::Exposure);
x11::Connection::Get()->Flush();
- return true;
}
} // namespace gl
diff --git a/chromium/ui/gl/gl_surface_egl_x11.h b/chromium/ui/gl/gl_surface_egl_x11.h
index 14a2fb5d98f..e36a3a6bc32 100644
--- a/chromium/ui/gl/gl_surface_egl_x11.h
+++ b/chromium/ui/gl/gl_surface_egl_x11.h
@@ -10,7 +10,6 @@
#include <string>
#include "base/macros.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
#include "ui/gl/gl_export.h"
@@ -20,7 +19,7 @@ namespace gl {
// Encapsulates an EGL surface bound to a view using the X Window System.
class GL_EXPORT NativeViewGLSurfaceEGLX11 : public NativeViewGLSurfaceEGL,
- public ui::XEventDispatcher {
+ public x11::EventObserver {
public:
explicit NativeViewGLSurfaceEGLX11(x11::Window window);
NativeViewGLSurfaceEGLX11(const NativeViewGLSurfaceEGLX11& other) = delete;
@@ -41,8 +40,8 @@ class GL_EXPORT NativeViewGLSurfaceEGLX11 : public NativeViewGLSurfaceEGL,
// NativeViewGLSurfaceEGL overrides:
std::unique_ptr<gfx::VSyncProvider> CreateVsyncProviderInternal() override;
- // XEventDispatcher:
- bool DispatchXEvent(x11::Event* xev) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& xev) override;
std::vector<x11::Window> children_;
diff --git a/chromium/ui/gl/gl_surface_egl_x11_gles2.cc b/chromium/ui/gl/gl_surface_egl_x11_gles2.cc
index 0d02906a3fd..017595561a6 100644
--- a/chromium/ui/gl/gl_surface_egl_x11_gles2.cc
+++ b/chromium/ui/gl/gl_surface_egl_x11_gles2.cc
@@ -8,9 +8,9 @@
#include "ui/gfx/x/xproto.h"
#include "ui/gfx/x/xproto_util.h"
#include "ui/gl/egl_util.h"
+#include "ui/gl/gl_bindings.h"
using ui::GetLastEGLErrorString;
-using ui::X11EventSource;
namespace gl {
@@ -20,7 +20,7 @@ NativeViewGLSurfaceEGLX11GLES2::NativeViewGLSurfaceEGLX11GLES2(
bool NativeViewGLSurfaceEGLX11GLES2::InitializeNativeWindow() {
auto* connection = GetXNativeConnection();
- auto geometry = connection->GetGeometry({parent_window_}).Sync();
+ auto geometry = connection->GetGeometry(parent_window_).Sync();
if (!geometry) {
LOG(ERROR) << "GetGeometry failed for window "
<< static_cast<uint32_t>(parent_window_) << ".";
@@ -66,7 +66,7 @@ EGLConfig NativeViewGLSurfaceEGLX11GLES2::GetConfig() {
// Get a config compatible with the window
DCHECK(window_);
auto* connection = GetXNativeConnection();
- auto geometry = connection->GetGeometry({window()}).Sync();
+ auto geometry = connection->GetGeometry(window()).Sync();
if (!geometry)
return nullptr;
@@ -152,17 +152,16 @@ bool NativeViewGLSurfaceEGLX11GLES2::Resize(const gfx::Size& size,
return true;
}
-bool NativeViewGLSurfaceEGLX11GLES2::DispatchXEvent(x11::Event* x11_event) {
- auto* expose = x11_event->As<x11::ExposeEvent>();
+void NativeViewGLSurfaceEGLX11GLES2::OnEvent(const x11::Event& x11_event) {
+ auto* expose = x11_event.As<x11::ExposeEvent>();
auto window = static_cast<x11::Window>(window_);
if (!expose || expose->window != window)
- return false;
+ return;
auto expose_copy = *expose;
expose_copy.window = parent_window_;
x11::SendEvent(expose_copy, parent_window_, x11::EventMask::Exposure);
x11::Connection::Get()->Flush();
- return true;
}
NativeViewGLSurfaceEGLX11GLES2::~NativeViewGLSurfaceEGLX11GLES2() {
diff --git a/chromium/ui/gl/gl_surface_egl_x11_gles2.h b/chromium/ui/gl/gl_surface_egl_x11_gles2.h
index 73b9b4a007f..55ff91f670a 100644
--- a/chromium/ui/gl/gl_surface_egl_x11_gles2.h
+++ b/chromium/ui/gl/gl_surface_egl_x11_gles2.h
@@ -40,8 +40,8 @@ class GL_EXPORT NativeViewGLSurfaceEGLX11GLES2
}
private:
- // XEventDispatcher:
- bool DispatchXEvent(x11::Event* xev) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& xev) override;
x11::Window parent_window_;
diff --git a/chromium/ui/gl/gl_surface_glx.cc b/chromium/ui/gl/gl_surface_glx.cc
index db774dc237c..6ceefd62e6a 100644
--- a/chromium/ui/gl/gl_surface_glx.cc
+++ b/chromium/ui/gl/gl_surface_glx.cc
@@ -106,6 +106,7 @@ class OMLSyncControlVSyncProvider : public SyncControlVSyncProvider {
bool GetSyncValues(int64_t* system_time,
int64_t* media_stream_counter,
int64_t* swap_buffer_counter) override {
+ x11::Connection::Get()->Flush();
return glXGetSyncValuesOML(x11::Connection::Get()->GetXlibDisplay(),
glx_window_, system_time, media_stream_counter,
swap_buffer_counter);
@@ -600,7 +601,7 @@ bool NativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) {
auto parent = static_cast<x11::Window>(parent_window_);
auto attributes_req = conn->GetWindowAttributes({parent});
- auto geometry_req = conn->GetGeometry({parent});
+ auto geometry_req = conn->GetGeometry(parent);
conn->Flush();
auto attributes = attributes_req.Sync();
auto geometry = geometry_req.Sync();
@@ -808,16 +809,16 @@ NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() {
Destroy();
}
-void NativeViewGLSurfaceGLX::ForwardExposeEvent(x11::Event* event) {
- auto forwarded_event = *event->As<x11::ExposeEvent>();
+void NativeViewGLSurfaceGLX::ForwardExposeEvent(const x11::Event& event) {
+ auto forwarded_event = *event.As<x11::ExposeEvent>();
auto window = static_cast<x11::Window>(parent_window_);
forwarded_event.window = window;
x11::SendEvent(forwarded_event, window, x11::EventMask::Exposure);
x11::Connection::Get()->Flush();
}
-bool NativeViewGLSurfaceGLX::CanHandleEvent(x11::Event* x11_event) {
- auto* expose = x11_event->As<x11::ExposeEvent>();
+bool NativeViewGLSurfaceGLX::CanHandleEvent(const x11::Event& x11_event) {
+ auto* expose = x11_event.As<x11::ExposeEvent>();
return expose && expose->window == static_cast<x11::Window>(window_);
}
diff --git a/chromium/ui/gl/gl_surface_glx.h b/chromium/ui/gl/gl_surface_glx.h
index aa88c30297c..4cdb554a09d 100644
--- a/chromium/ui/gl/gl_surface_glx.h
+++ b/chromium/ui/gl/gl_surface_glx.h
@@ -104,10 +104,10 @@ class GL_EXPORT NativeViewGLSurfaceGLX : public GLSurfaceGLX {
virtual void UnregisterEvents() = 0;
// Forwards Expose event to child window.
- void ForwardExposeEvent(x11::Event* xevent);
+ void ForwardExposeEvent(const x11::Event& xevent);
// Checks if event is Expose for child window.
- bool CanHandleEvent(x11::Event* xevent);
+ bool CanHandleEvent(const x11::Event& xevent);
gfx::AcceleratedWidget window() const {
return static_cast<gfx::AcceleratedWidget>(window_);
diff --git a/chromium/ui/gl/gl_surface_glx_x11.cc b/chromium/ui/gl/gl_surface_glx_x11.cc
index 858987aa494..404f1caf7b5 100644
--- a/chromium/ui/gl/gl_surface_glx_x11.cc
+++ b/chromium/ui/gl/gl_surface_glx_x11.cc
@@ -4,8 +4,7 @@
#include "ui/gl/gl_surface_glx_x11.h"
-
-using ui::X11EventSource;
+#include "ui/gfx/x/future.h"
namespace gl {
@@ -18,26 +17,22 @@ GLSurfaceGLXX11::~GLSurfaceGLXX11() {
void GLSurfaceGLXX11::RegisterEvents() {
// Can be null in tests, when we don't care about Exposes.
- if (X11EventSource::HasInstance()) {
- x11::Connection::Get()->ChangeWindowAttributes(
- x11::ChangeWindowAttributesRequest{
- .window = static_cast<x11::Window>(window()),
- .event_mask = x11::EventMask::Exposure});
-
- X11EventSource::GetInstance()->AddXEventDispatcher(this);
- }
+ auto* connection = x11::Connection::Get();
+
+ connection->ChangeWindowAttributes(x11::ChangeWindowAttributesRequest{
+ .window = static_cast<x11::Window>(window()),
+ .event_mask = x11::EventMask::Exposure});
+
+ connection->AddEventObserver(this);
}
void GLSurfaceGLXX11::UnregisterEvents() {
- if (X11EventSource::HasInstance())
- X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+ x11::Connection::Get()->RemoveEventObserver(this);
}
-bool GLSurfaceGLXX11::DispatchXEvent(x11::Event* event) {
- if (!CanHandleEvent(event))
- return false;
- ForwardExposeEvent(event);
- return true;
+void GLSurfaceGLXX11::OnEvent(const x11::Event& event) {
+ if (CanHandleEvent(event))
+ ForwardExposeEvent(event);
}
} // namespace gl
diff --git a/chromium/ui/gl/gl_surface_glx_x11.h b/chromium/ui/gl/gl_surface_glx_x11.h
index 6b2a4ac5dc8..c4dfd8dc9ee 100644
--- a/chromium/ui/gl/gl_surface_glx_x11.h
+++ b/chromium/ui/gl/gl_surface_glx_x11.h
@@ -6,8 +6,8 @@
#define UI_GL_GL_SURFACE_GLX_X11_H_
#include "base/macros.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
#include "ui/gl/gl_export.h"
#include "ui/gl/gl_surface_glx.h"
@@ -17,7 +17,7 @@ namespace gl {
// X11 specific implementation of GLX surface. Registers as a
// PlatformEventDispatcher to handle XEvents.
class GL_EXPORT GLSurfaceGLXX11 : public NativeViewGLSurfaceGLX,
- public ui::XEventDispatcher {
+ public x11::EventObserver {
public:
explicit GLSurfaceGLXX11(gfx::AcceleratedWidget window);
@@ -28,8 +28,8 @@ class GL_EXPORT GLSurfaceGLXX11 : public NativeViewGLSurfaceGLX,
void RegisterEvents() override;
void UnregisterEvents() override;
- // XEventDispatcher:
- bool DispatchXEvent(x11::Event* event) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& event) override;
private:
DISALLOW_COPY_AND_ASSIGN(GLSurfaceGLXX11);
diff --git a/chromium/ui/gl/gl_switches.cc b/chromium/ui/gl/gl_switches.cc
index 034352f8f12..9a458e8c194 100644
--- a/chromium/ui/gl/gl_switches.cc
+++ b/chromium/ui/gl/gl_switches.cc
@@ -5,6 +5,11 @@
#include "ui/gl/gl_switches.h"
#include "base/stl_util.h"
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
namespace gl {
@@ -224,10 +229,25 @@ const base::Feature kDefaultANGLEOpenGL{"DefaultANGLEOpenGL",
const base::Feature kDefaultANGLEMetal{"DefaultANGLEMetal",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Default to using ANGLE's Vulkan backend.
+const base::Feature kDefaultANGLEVulkan{"DefaultANGLEVulkan",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Track current program's shaders at glUseProgram() call for crash report
// purpose. Only effective on Windows because the attached shaders may only
// be reliably retrieved with ANGLE backend.
const base::Feature kTrackCurrentShaders{"TrackCurrentShaders",
base::FEATURE_DISABLED_BY_DEFAULT};
+bool IsDefaultANGLEVulkan() {
+#if defined(OS_ANDROID)
+ // No support for devices before Q -- exit before checking feature flags
+ // so that devices are not counted in finch trials.
+ if (base::android::BuildInfo::GetInstance()->sdk_int() <
+ base::android::SDK_VERSION_Q)
+ return false;
+#endif // defined(OS_ANDROID)
+ return base::FeatureList::IsEnabled(kDefaultANGLEVulkan);
+}
+
} // namespace features
diff --git a/chromium/ui/gl/gl_switches.h b/chromium/ui/gl/gl_switches.h
index 1daab9da0f8..81ae0db537b 100644
--- a/chromium/ui/gl/gl_switches.h
+++ b/chromium/ui/gl/gl_switches.h
@@ -90,6 +90,7 @@ GL_EXPORT extern const int kGLSwitchesCopiedFromGpuProcessHostNumSwitches;
} // namespace switches
namespace features {
+
GL_EXPORT extern const base::Feature kDCompTripleBufferRootSwapChain;
GL_EXPORT extern const base::Feature kDCompTripleBufferVideoSwapChain;
GL_EXPORT extern const base::Feature kDirectCompositionForceFullDamage;
@@ -98,7 +99,11 @@ GL_EXPORT extern const base::Feature kDirectCompositionLowLatencyPresentation;
GL_EXPORT extern const base::Feature kDirectCompositionSoftwareOverlays;
GL_EXPORT extern const base::Feature kDefaultANGLEOpenGL;
GL_EXPORT extern const base::Feature kDefaultANGLEMetal;
+GL_EXPORT extern const base::Feature kDefaultANGLEVulkan;
GL_EXPORT extern const base::Feature kTrackCurrentShaders;
+
+GL_EXPORT bool IsDefaultANGLEVulkan();
+
} // namespace features
#endif // UI_GL_GL_SWITCHES_H_
diff --git a/chromium/ui/gl/gl_utils.cc b/chromium/ui/gl/gl_utils.cc
index 41e79b44b59..77d3d1ad124 100644
--- a/chromium/ui/gl/gl_utils.cc
+++ b/chromium/ui/gl/gl_utils.cc
@@ -167,8 +167,8 @@ void CollectX11GpuExtraInfo(bool enable_native_gpu_memory_buffers,
// singleton is busy being created on another thread.
GLVisualPickerGLX* visual_picker = GLVisualPickerGLX::GetInstance();
- info.system_visual = static_cast<uint32_t>(visual_picker->system_visual());
- info.rgba_visual = static_cast<uint32_t>(visual_picker->rgba_visual());
+ info.system_visual = visual_picker->system_visual();
+ info.rgba_visual = visual_picker->rgba_visual();
// With GLX, only BGR(A) buffer formats are supported. EGL does not have
// this restriction.
diff --git a/chromium/ui/gl/gl_version_info.cc b/chromium/ui/gl/gl_version_info.cc
index a8cf65628a3..f948e8983f0 100644
--- a/chromium/ui/gl/gl_version_info.cc
+++ b/chromium/ui/gl/gl_version_info.cc
@@ -36,8 +36,15 @@ GLVersionInfo::GLVersionInfo(const char* version_str,
void GLVersionInfo::Initialize(const char* version_str,
const char* renderer_str,
const gfx::ExtensionSet& extensions) {
- if (version_str)
+ if (version_str) {
ParseVersionString(version_str);
+ ParseDriverInfo(version_str);
+ }
+ // ANGLE's version string does not contain useful information for
+ // GLVersionInfo. If we are going to parse the version string and we're using
+ // ANGLE, we must also parse ANGLE's renderer string, which contains the
+ // driver's version string.
+ DCHECK(renderer_str || driver_vendor != "ANGLE");
if (renderer_str) {
std::string renderer_string = std::string(renderer_str);
@@ -101,7 +108,7 @@ void GLVersionInfo::ParseVersionString(const char* version_str) {
std::vector<base::StringPiece> pieces = base::SplitStringPiece(
lstr, " -()@", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (pieces.size() == 0) {
- // This should never happen, but let's just tolerant bad driver behavior.
+ // This should never happen, but let's just tolerate bad driver behavior.
return;
}
@@ -109,7 +116,7 @@ void GLVersionInfo::ParseVersionString(const char* version_str) {
// Desktop GL doesn't specify the GL_VERSION format, but ES spec requires
// the string to be in the format of "OpenGL ES major.minor other_info".
DCHECK_LE(3u, pieces[0].size());
- if (pieces[0][pieces[0].size() - 1] == 'V') {
+ if (pieces[0].size() > 0 && pieces[0].back() == 'V') {
// On Nexus 6 with Android N, GL_VERSION string is not spec compliant.
// There is no space between "3.1" and "V@104.0".
pieces[0].remove_suffix(1);
@@ -131,16 +138,48 @@ void GLVersionInfo::ParseVersionString(const char* version_str) {
is_es3 = true;
}
}
+}
+
+void GLVersionInfo::ParseDriverInfo(const char* version_str) {
+ if (!version_str)
+ return;
+ base::StringPiece lstr(version_str);
+ constexpr base::StringPiece kESPrefix = "OpenGL ES ";
+ if (base::StartsWith(lstr, kESPrefix, base::CompareCase::SENSITIVE)) {
+ lstr.remove_prefix(kESPrefix.size());
+ }
+ std::vector<base::StringPiece> pieces = base::SplitStringPiece(
+ lstr, " -()@", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ if (pieces.size() == 0) {
+ // This should never happen, but let's just tolerate bad driver behavior.
+ return;
+ }
+
+ if (is_es) {
+ // Desktop GL doesn't specify the GL_VERSION format, but ES spec requires
+ // the string to be in the format of "OpenGL ES major.minor other_info".
+ DCHECK_LE(3u, pieces[0].size());
+ if (pieces[0].size() > 0 && pieces[0].back() == 'V') {
+ // On Nexus 6 with Android N, GL_VERSION string is not spec compliant.
+ // There is no space between "3.1" and "V@104.0".
+ pieces[0].remove_suffix(1);
+ }
+ }
if (pieces.size() == 1)
return;
- constexpr base::StringPiece kVendors[] = {
- "ANGLE", "Mesa", "INTEL", "NVIDIA", "ATI", "FireGL", "Chromium", "APPLE"};
+ // Map key strings to driver vendors. We assume the key string is followed by
+ // the driver version.
+ const std::map<base::StringPiece, base::StringPiece> kVendors = {
+ {"ANGLE", "ANGLE"}, {"Mesa", "Mesa"}, {"INTEL", "INTEL"},
+ {"NVIDIA", "NVIDIA"}, {"ATI", "ATI"}, {"FireGL", "FireGL"},
+ {"Chromium", "Chromium"}, {"APPLE", "APPLE"}, {"AMD", "AMD"},
+ {"Metal", "Apple"}};
for (size_t ii = 1; ii < pieces.size(); ++ii) {
for (auto vendor : kVendors) {
- if (pieces[ii] == vendor) {
- driver_vendor.assign(vendor.data(), vendor.size());
+ if (pieces[ii] == vendor.first) {
+ driver_vendor.assign(vendor.second.data(), vendor.second.size());
if (ii + 1 < pieces.size())
driver_version.assign(pieces[ii + 1].data(), pieces[ii + 1].size());
return;
@@ -184,6 +223,26 @@ void GLVersionInfo::ExtractDriverVendorANGLE(const char* renderer_str) {
base::StringPiece rstr(renderer_str);
DCHECK(base::StartsWith(rstr, "ANGLE (", base::CompareCase::SENSITIVE));
rstr = rstr.substr(sizeof("ANGLE (") - 1, rstr.size() - sizeof("ANGLE ("));
+
+ // ANGLE's renderer string returns a format matching ANGLE (GL_VENDOR,
+ // GL_RENDERER, GL_VERSION)
+ std::vector<base::StringPiece> gl_strings = base::SplitStringPiece(
+ rstr, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+ // The 3rd part of the renderer string contains the native driver's version
+ // string. We should parse it here to override anything parsed from ANGLE's
+ // GL_VERSION string, which only contains information about the ANGLE version.
+ if (gl_strings.size() >= 3) {
+ // The first part of the renderer string contains the native driver's
+ // vendor string.
+ driver_vendor.assign(gl_strings[0].data(), gl_strings[0].size());
+
+ std::string native_version_str;
+ base::TrimString(gl_strings[2], ")", &native_version_str);
+ ParseDriverInfo(native_version_str.c_str());
+ return;
+ }
+
if (base::StartsWith(rstr, "Vulkan ", base::CompareCase::SENSITIVE)) {
size_t pos = rstr.find('(');
if (pos != std::string::npos)
diff --git a/chromium/ui/gl/gl_version_info.h b/chromium/ui/gl/gl_version_info.h
index 63ceab91436..7c822cdc54b 100644
--- a/chromium/ui/gl/gl_version_info.h
+++ b/chromium/ui/gl/gl_version_info.h
@@ -84,6 +84,7 @@ struct GL_EXPORT GLVersionInfo {
const char* renderer_str,
const gfx::ExtensionSet& extensions);
void ParseVersionString(const char* version_str);
+ void ParseDriverInfo(const char* version_str);
void ExtractDriverVendorANGLE(const char* renderer_str);
bool IsES3Capable(const gfx::ExtensionSet& extensions) const;
diff --git a/chromium/ui/gl/gl_version_info_unittest.cc b/chromium/ui/gl/gl_version_info_unittest.cc
index a7885766928..2378c34cc60 100644
--- a/chromium/ui/gl/gl_version_info_unittest.cc
+++ b/chromium/ui/gl/gl_version_info_unittest.cc
@@ -24,8 +24,6 @@ TEST(GLVersionInfoTest, ParseGLVersionStringTest) {
{"4.3 (Core Profile) Mesa 11.2.0", 4, 3, false, false, false, "Mesa",
"11.2.0"},
{"4.5.0 NVIDIA 364.19", 4, 5, false, false, false, "NVIDIA", "364.19"},
- {"OpenGL ES 2.0 (ANGLE 2.1.0.cd1b12260360)", 2, 0, true, true, false,
- "ANGLE", "2.1.0.cd1b12260360"},
{"2.1 INTEL-10.6.33", 2, 1, false, false, false, "INTEL", "10.6.33"},
{"2.1", 2, 1, false, false, false, "", ""},
{"OpenGL ES 3.0", 3, 0, true, false, true, "", ""},
@@ -47,6 +45,8 @@ TEST(GLVersionInfoTest, ParseGLVersionStringTest) {
false, false, "", "21.19.137.514"},
{"4.5.13497 Compatibility Profile/Debug Context 23.20.782.0", 4, 5, false,
false, false, "", "23.20.782.0"},
+ {"OpenGL ES 3.0 SwiftShader 4.1.0.7", 3, 0, true, false, true, "",
+ "4.1.0.7"},
// This is a non spec compliant string from Nexus6 on Android N.
{"OpenGL ES 3.1V@104.0", 3, 1, true, false, true, "", "104.0"}};
@@ -78,26 +78,53 @@ TEST(GLVersionInfoTest, DriverVendorForANGLE) {
const char* expected_driver_vendor;
const char* expected_driver_version;
} kTestData[] = {
- {"OpenGL ES 2.0 (ANGLE 2.1.0.44063c804e4f)",
- "ANGLE (NVIDIA Quadro P400 Direct3D11 vs_5_0 ps_5_0)",
- 2, 0, true, true, false, true,
- "ANGLE (NVIDIA)", "2.1.0.44063c804e4f"},
- {"OpenGL ES 2.0 (ANGLE 2.1.0.44063c804e4f)",
- "ANGLE (Intel(R) HD Graphics 630 Direct3D11 vs_5_0 ps_5_0)",
- 2, 0, true, true, false, true,
- "ANGLE (Intel)", "2.1.0.44063c804e4f"},
- {"OpenGL ES 2.0 (ANGLE 2.1.0.44063c804e4f)",
- "ANGLE (Radeon RX550/550 Series Direct3D11 vs_5_0 ps_5_0)",
- 2, 0, true, true, false, true,
- "ANGLE (AMD)", "2.1.0.44063c804e4f"},
- {"OpenGL ES 2.0 (ANGLE 2.1.0.44063c804e4f)",
- "ANGLE (Vulkan 1.1.120(Intel(R) UHD Graphics 630 (0x00003E92)))",
- 2, 0, true, true, false, false,
- "ANGLE (Intel)", "2.1.0.44063c804e4f"},
- {"OpenGL ES 2.0 (ANGLE 2.1.0.44063c804e4f)",
- "ANGLE (Intel, Intel(R) UHD Graphics 630, OpenGL 4.5 core)",
- 2, 0, true, true, false, false,
- "ANGLE (Intel)", "2.1.0.44063c804e4f"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (Intel Inc., Intel(R) UHD Graphics 630, OpenGL 4.1 "
+ "INTEL-14.7.11)",
+ 2, 0, true, true, false, false, "INTEL", "14.7.11"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (ATI Technologies Inc., AMD Radeon Pro 560X OpenGL Engine, "
+ "OpenGL 4.1 ATI-3.10.19)",
+ 2, 0, true, true, false, false, "ATI", "3.10.19"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (AMD, Metal Renderer: AMD Radeon Pro 560X, Version 10.15.7 "
+ "(Build 19H114))",
+ 2, 0, true, true, false, false, "AMD", "10.15.7"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (Mesa/X.org, llvmpipe (LLVM 11.0.0 256 bits), OpenGL 4.5 (Core "
+ "Profile) Mesa 20.2.4)",
+ 2, 0, true, true, false, false, "Mesa", "20.2.4"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (Apple, Apple A12Z, OpenGL 4.1 Metal - 70.12.7)", 2, 0, true,
+ true, false, false, "Apple", "70.12.7"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (NVIDIA Corporation, Quadro P1000/PCIe/SSE2, OpenGL 4.5.0 NVIDIA "
+ "440.100)",
+ 2, 0, true, true, false, false, "NVIDIA", "440.100"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (NVIDIA, Vulkan 1.1.119 (NVIDIA Quadro P1000 (0x00001CB1)), "
+ "NVIDIA-440.400.0)",
+ 2, 0, true, true, false, false, "NVIDIA", "440.400.0"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (NVIDIA, NVIDIA Quadro P1000 Direct3D11 vs_5_0 ps_5_0, "
+ "D3D11-23.21.13.9077)",
+ 2, 0, true, true, false, true, "NVIDIA", "23.21.13.9077"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (NVIDIA, NVIDIA Quadro P1000 Direct3D9Ex vs_3_0 ps_3_0, "
+ "nvldumdx.dll-23.21.13.9077)",
+ 2, 0, true, true, false, true, "NVIDIA", "23.21.13.9077"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (NVIDIA Corporation, Quadro P1000/PCIe/SSE2, OpenGL 4.5.0 NVIDIA "
+ "390.77)",
+ 2, 0, true, true, false, false, "NVIDIA", "390.77"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (NVIDIA, Vulkan 1.0.65 (NVIDIA Quadro P1000 (0x00001CB1)), "
+ "NVIDIA-390.308.0)",
+ 2, 0, true, true, false, false, "NVIDIA", "390.308.0"},
+ {"OpenGL ES 2.0.0 (ANGLE 2.1.4875 git hash: 32e78475b1c0)",
+ "ANGLE (Google, Vulkan 1.1.0 (SwiftShader Device (Subzero) "
+ "(0x0000C0DE)), SwiftShader driver-5.0.0)",
+ 2, 0, true, true, false, false, "Google", "5.0.0"},
};
gfx::ExtensionSet extensions;
diff --git a/chromium/ui/gl/gl_visual_picker_glx.cc b/chromium/ui/gl/gl_visual_picker_glx.cc
index f7ce65aebfa..abe58bdf274 100644
--- a/chromium/ui/gl/gl_visual_picker_glx.cc
+++ b/chromium/ui/gl/gl_visual_picker_glx.cc
@@ -12,6 +12,7 @@
#include "base/memory/singleton.h"
#include "base/stl_util.h"
+#include "ui/gfx/x/future.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface_glx.h"
diff --git a/chromium/ui/gl/glx_util.cc b/chromium/ui/gl/glx_util.cc
index 397e807a28f..a82815aab83 100644
--- a/chromium/ui/gl/glx_util.cc
+++ b/chromium/ui/gl/glx_util.cc
@@ -4,10 +4,9 @@
#include "ui/gl/glx_util.h"
-#include <dlfcn.h>
-
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "ui/gfx/x/future.h"
#include "ui/gfx/x/glx.h"
#include "ui/gl/gl_bindings.h"
@@ -62,13 +61,6 @@ x11::Glx::FbConfig GetConfigForWindow(x11::Connection* conn,
return {};
}
-NO_SANITIZE("cfi-icall")
-void XlibFree(void* data) {
- using xfree_type = void (*)(void*);
- auto* xfree = reinterpret_cast<xfree_type>(dlsym(RTLD_DEFAULT, "XFree"));
- xfree(data);
-}
-
} // namespace
GLXFBConfig GetFbConfigForWindow(x11::Connection* connection,
@@ -89,7 +81,7 @@ GLXFBConfig GetGlxFbConfigForXProtoFbConfig(x11::Connection* connection,
DCHECK_EQ(nitems, 1);
DCHECK(glx_configs);
GLXFBConfig glx_config = glx_configs[0];
- XlibFree(glx_configs);
+ x11::XlibFree(glx_configs);
return glx_config;
}
diff --git a/chromium/ui/gl/hdr_metadata_helper_win.cc b/chromium/ui/gl/hdr_metadata_helper_win.cc
index 14e16e9560f..7bae9b7af8f 100644
--- a/chromium/ui/gl/hdr_metadata_helper_win.cc
+++ b/chromium/ui/gl/hdr_metadata_helper_win.cc
@@ -9,7 +9,7 @@ namespace {
// Magic constants to convert to fixed point.
// https://docs.microsoft.com/en-us/windows/win32/api/dxgi1_5/ns-dxgi1_5-dxgi_hdr_metadata_hdr10
static constexpr int kPrimariesFixedPoint = 50000;
-static constexpr int kLuminanceFixedPoint = 10000;
+static constexpr int kMinLuminanceFixedPoint = 10000;
} // namespace
@@ -91,10 +91,9 @@ void HDRMetadataHelperWin::CacheDisplayMetadata(
auto& white_point = desc_best.WhitePoint;
metadata.WhitePoint[0] = white_point[0] * kPrimariesFixedPoint;
metadata.WhitePoint[1] = white_point[1] * kPrimariesFixedPoint;
- metadata.MaxMasteringLuminance =
- desc_best.MaxLuminance * kLuminanceFixedPoint;
+ metadata.MaxMasteringLuminance = desc_best.MaxLuminance;
metadata.MinMasteringLuminance =
- desc_best.MinLuminance * kLuminanceFixedPoint;
+ desc_best.MinLuminance * kMinLuminanceFixedPoint;
// It's unclear how to set these properly, so this is a guess.
// Also note that these are not fixed-point.
metadata.MaxContentLightLevel = desc_best.MaxFullFrameLuminance;
@@ -121,9 +120,9 @@ DXGI_HDR_METADATA_HDR10 HDRMetadataHelperWin::HDRMetadataToDXGI(
metadata.WhitePoint[0] = white_point.x() * kPrimariesFixedPoint;
metadata.WhitePoint[1] = white_point.y() * kPrimariesFixedPoint;
metadata.MaxMasteringLuminance =
- hdr_metadata.mastering_metadata.luminance_max * kLuminanceFixedPoint;
+ hdr_metadata.mastering_metadata.luminance_max;
metadata.MinMasteringLuminance =
- hdr_metadata.mastering_metadata.luminance_min * kLuminanceFixedPoint;
+ hdr_metadata.mastering_metadata.luminance_min * kMinLuminanceFixedPoint;
metadata.MaxContentLightLevel = hdr_metadata.max_content_light_level;
metadata.MaxFrameAverageLightLevel =
hdr_metadata.max_frame_average_light_level;
diff --git a/chromium/ui/gl/hdr_metadata_helper_win_unittest.cc b/chromium/ui/gl/hdr_metadata_helper_win_unittest.cc
index a7d9d6592ef..cef483843bf 100644
--- a/chromium/ui/gl/hdr_metadata_helper_win_unittest.cc
+++ b/chromium/ui/gl/hdr_metadata_helper_win_unittest.cc
@@ -115,7 +115,7 @@ TEST_F(HDRMetadataHelperWinTest, CachesMetadataIfAvailable) {
EXPECT_TRUE(result);
// From MSDN.
static constexpr int kPrimariesFixedPoint = 50000;
- static constexpr int kLuminanceFixedPoint = 10000;
+ static constexpr int kMinLuminanceFixedPoint = 10000;
EXPECT_EQ(result->RedPrimary[0],
static_cast<int>(desc.RedPrimary[0] * kPrimariesFixedPoint));
EXPECT_EQ(result->RedPrimary[1],
@@ -133,9 +133,9 @@ TEST_F(HDRMetadataHelperWinTest, CachesMetadataIfAvailable) {
EXPECT_EQ(result->WhitePoint[1],
static_cast<int>(desc.WhitePoint[1] * kPrimariesFixedPoint));
EXPECT_EQ(result->MaxMasteringLuminance,
- static_cast<unsigned>(desc.MaxLuminance * kLuminanceFixedPoint));
+ static_cast<unsigned>(desc.MaxLuminance));
EXPECT_EQ(result->MinMasteringLuminance,
- static_cast<unsigned>(desc.MinLuminance * kLuminanceFixedPoint));
+ static_cast<unsigned>(desc.MinLuminance * kMinLuminanceFixedPoint));
EXPECT_EQ(result->MaxContentLightLevel, desc.MaxFullFrameLuminance);
EXPECT_EQ(result->MaxFrameAverageLightLevel, desc.MaxFullFrameLuminance);
}
diff --git a/chromium/ui/gl/init/BUILD.gn b/chromium/ui/gl/init/BUILD.gn
index a0013554bfe..e447744aa69 100644
--- a/chromium/ui/gl/init/BUILD.gn
+++ b/chromium/ui/gl/init/BUILD.gn
@@ -31,15 +31,16 @@ component("init") {
public_deps = [ "//ui/gl" ]
+ if (use_static_angle) {
+ sources += [ "gl_initializer_angle.cc" ]
+ deps += [ "//third_party/angle:libEGL_static" ]
+ }
+
if (is_android) {
sources += [
"gl_factory_android.cc",
"gl_initializer_android.cc",
]
-
- if (use_static_angle) {
- deps += [ "//third_party/angle:libEGL_static" ]
- }
} else if (is_win && !use_ozone) {
sources += [
"gl_factory_win.cc",
diff --git a/chromium/ui/gl/init/create_gr_gl_interface.cc b/chromium/ui/gl/init/create_gr_gl_interface.cc
index f46b73dacee..b45925ea594 100644
--- a/chromium/ui/gl/init/create_gr_gl_interface.cc
+++ b/chromium/ui/gl/init/create_gr_gl_interface.cc
@@ -13,6 +13,10 @@
#include "ui/gl/gl_version_info.h"
#include "ui/gl/progress_reporter.h"
+#if defined(OS_APPLE)
+#include "base/mac/mac_util.h"
+#endif
+
namespace gl {
namespace init {
@@ -153,40 +157,49 @@ GrGLFunction<R GR_GL_FUNCTION_TYPE(Args...)> bind_slow_on_mac(
template <bool droppable_call = false, typename R, typename... Args>
GrGLFunction<R GR_GL_FUNCTION_TYPE(Args...)> bind_with_flush_on_mac(
- R(GL_BINDING_CALL* func)(Args...)) {
+ R(GL_BINDING_CALL* func)(Args...),
+ bool is_angle) {
#if defined(OS_APPLE)
- return [func](Args... args) {
- // Conditional may be optimized out because droppable_call is set at compile
- // time.
- if (!droppable_call || !HasInitializedNullDrawGLBindings()) {
- {
- TRACE_EVENT0(
- "gpu", "CreateGrGLInterface - bind_with_flush_on_mac - beforefunc")
- glFlush();
- }
- func(args...);
- {
- TRACE_EVENT0("gpu",
- "CreateGrGLInterface - bind_with_flush_on_mac - afterfunc")
- glFlush();
+ // If running on Apple silicon or ANGLE, regardless of the architecture,
+ // disable this workaround. See https://crbug.com/1131312.
+ const bool needs_flush =
+ base::mac::GetCPUType() == base::mac::CPUType::kIntel && !is_angle;
+ if (needs_flush) {
+ return [func](Args... args) {
+ // Conditional may be optimized out because droppable_call is set at
+ // compile time.
+ if (!droppable_call || !HasInitializedNullDrawGLBindings()) {
+ {
+ TRACE_EVENT0(
+ "gpu",
+ "CreateGrGLInterface - bind_with_flush_on_mac - beforefunc");
+ glFlush();
+ }
+ func(args...);
+ {
+ TRACE_EVENT0(
+ "gpu",
+ "CreateGrGLInterface - bind_with_flush_on_mac - afterfunc");
+ glFlush();
+ }
}
- }
- };
-#else
- return maybe_drop_call<droppable_call>(func);
+ };
+ }
#endif
+ return maybe_drop_call<droppable_call>(func);
}
template <bool droppable_call = false, typename R, typename... Args>
GrGLFunction<R GR_GL_FUNCTION_TYPE(Args...)> bind_slow_with_flush_on_mac(
R(GL_BINDING_CALL* func)(Args...),
- gl::ProgressReporter* progress_reporter) {
+ gl::ProgressReporter* progress_reporter,
+ bool is_angle) {
if (!progress_reporter) {
- return bind_with_flush_on_mac<droppable_call>(func);
+ return bind_with_flush_on_mac<droppable_call>(func, is_angle);
}
- return [func, progress_reporter](Args... args) {
+ return [func, progress_reporter, is_angle](Args... args) {
gl::ScopedProgressReporter scoped_reporter(progress_reporter);
- return bind_with_flush_on_mac<droppable_call>(func)(args...);
+ return bind_with_flush_on_mac<droppable_call>(func, is_angle)(args...);
};
}
@@ -297,8 +310,8 @@ sk_sp<GrGLInterface> CreateGrGLInterface(
functions->fBlendFunc = gl->glBlendFuncFn;
functions->fBufferData = gl->glBufferDataFn;
functions->fBufferSubData = gl->glBufferSubDataFn;
- functions->fClear =
- bind_slow_with_flush_on_mac<true>(gl->glClearFn, progress_reporter);
+ functions->fClear = bind_slow_with_flush_on_mac<true>(
+ gl->glClearFn, progress_reporter, version_info.is_angle);
functions->fClearColor = gl->glClearColorFn;
functions->fClearStencil = gl->glClearStencilFn;
functions->fClearTexImage = gl->glClearTexImageFn;
@@ -307,7 +320,7 @@ sk_sp<GrGLInterface> CreateGrGLInterface(
functions->fCompileShader =
bind_slow(gl->glCompileShaderFn, progress_reporter);
functions->fCompressedTexImage2D = bind_slow_with_flush_on_mac(
- gl->glCompressedTexImage2DFn, progress_reporter);
+ gl->glCompressedTexImage2DFn, progress_reporter, version_info.is_angle);
functions->fCompressedTexSubImage2D =
bind_slow(gl->glCompressedTexSubImage2DFn, progress_reporter);
functions->fCopyTexSubImage2D =
@@ -339,8 +352,8 @@ sk_sp<GrGLInterface> CreateGrGLInterface(
functions->fDeleteQueries = gl->glDeleteQueriesFn;
functions->fDeleteSamplers = gl->glDeleteSamplersFn;
functions->fDeleteShader = bind_slow(gl->glDeleteShaderFn, progress_reporter);
- functions->fDeleteTextures =
- bind_slow_with_flush_on_mac(gl->glDeleteTexturesFn, progress_reporter);
+ functions->fDeleteTextures = bind_slow_with_flush_on_mac(
+ gl->glDeleteTexturesFn, progress_reporter, version_info.is_angle);
functions->fDepthMask = gl->glDepthMaskFn;
functions->fDisable = gl->glDisableFn;
functions->fDisableVertexAttribArray = gl->glDisableVertexAttribArrayFn;
@@ -455,16 +468,16 @@ sk_sp<GrGLInterface> CreateGrGLInterface(
functions->fStencilOpSeparate = gl->glStencilOpSeparateFn;
functions->fTexBuffer = gl->glTexBufferFn;
functions->fTexBufferRange = gl->glTexBufferRangeFn;
- functions->fTexImage2D =
- bind_slow_with_flush_on_mac(gl->glTexImage2DFn, progress_reporter);
+ functions->fTexImage2D = bind_slow_with_flush_on_mac(
+ gl->glTexImage2DFn, progress_reporter, version_info.is_angle);
functions->fTexParameterf = gl->glTexParameterfFn;
functions->fTexParameterfv = gl->glTexParameterfvFn;
functions->fTexParameteri = gl->glTexParameteriFn;
functions->fTexParameteriv = gl->glTexParameterivFn;
- functions->fTexStorage2D =
- bind_slow_with_flush_on_mac(gl->glTexStorage2DEXTFn, progress_reporter);
- functions->fTexSubImage2D =
- bind_slow_with_flush_on_mac(gl->glTexSubImage2DFn, progress_reporter);
+ functions->fTexStorage2D = bind_slow_with_flush_on_mac(
+ gl->glTexStorage2DEXTFn, progress_reporter, version_info.is_angle);
+ functions->fTexSubImage2D = bind_slow_with_flush_on_mac(
+ gl->glTexSubImage2DFn, progress_reporter, version_info.is_angle);
// GL 4.5 or GL_ARB_texture_barrier or GL_NV_texture_barrier
// functions->fTextureBarrier = gl->glTextureBarrierFn;
@@ -518,25 +531,26 @@ sk_sp<GrGLInterface> CreateGrGLInterface(
functions->fGetRenderbufferParameteriv =
gl->glGetRenderbufferParameterivEXTFn;
functions->fBindFramebuffer = bind_slow_with_flush_on_mac(
- gl->glBindFramebufferEXTFn, progress_reporter);
+ gl->glBindFramebufferEXTFn, progress_reporter, version_info.is_angle);
functions->fFramebufferTexture2D = gl->glFramebufferTexture2DEXTFn;
functions->fCheckFramebufferStatus = gl->glCheckFramebufferStatusEXTFn;
functions->fDeleteFramebuffers = bind_slow_with_flush_on_mac(
- gl->glDeleteFramebuffersEXTFn, progress_reporter);
- functions->fRenderbufferStorage =
- bind_with_flush_on_mac(gl->glRenderbufferStorageEXTFn);
+ gl->glDeleteFramebuffersEXTFn, progress_reporter, version_info.is_angle);
+ functions->fRenderbufferStorage = bind_with_flush_on_mac(
+ gl->glRenderbufferStorageEXTFn, version_info.is_angle);
functions->fGenRenderbuffers = gl->glGenRenderbuffersEXTFn;
- functions->fDeleteRenderbuffers =
- bind_with_flush_on_mac(gl->glDeleteRenderbuffersEXTFn);
+ functions->fDeleteRenderbuffers = bind_with_flush_on_mac(
+ gl->glDeleteRenderbuffersEXTFn, version_info.is_angle);
functions->fFramebufferRenderbuffer = gl->glFramebufferRenderbufferEXTFn;
functions->fBindRenderbuffer = gl->glBindRenderbufferEXTFn;
- functions->fRenderbufferStorageMultisample =
- bind_with_flush_on_mac(gl->glRenderbufferStorageMultisampleFn);
+ functions->fRenderbufferStorageMultisample = bind_with_flush_on_mac(
+ gl->glRenderbufferStorageMultisampleFn, version_info.is_angle);
functions->fFramebufferTexture2DMultisample =
gl->glFramebufferTexture2DMultisampleEXTFn;
- functions->fRenderbufferStorageMultisampleES2EXT =
- bind_with_flush_on_mac(gl->glRenderbufferStorageMultisampleEXTFn);
- functions->fBlitFramebuffer = bind_with_flush_on_mac(gl->glBlitFramebufferFn);
+ functions->fRenderbufferStorageMultisampleES2EXT = bind_with_flush_on_mac(
+ gl->glRenderbufferStorageMultisampleEXTFn, version_info.is_angle);
+ functions->fBlitFramebuffer =
+ bind_with_flush_on_mac(gl->glBlitFramebufferFn, version_info.is_angle);
functions->fMatrixLoadf = gl->glMatrixLoadfEXTFn;
functions->fMatrixLoadIdentity = gl->glMatrixLoadIdentityEXTFn;
diff --git a/chromium/ui/gl/init/gl_factory.cc b/chromium/ui/gl/init/gl_factory.cc
index d6494eb6de9..facdc5a4775 100644
--- a/chromium/ui/gl/init/gl_factory.cc
+++ b/chromium/ui/gl/init/gl_factory.cc
@@ -22,6 +22,8 @@ namespace init {
namespace {
+bool g_is_angle_enabled = true;
+
bool ShouldFallbackToSoftwareGL() {
const base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
std::string requested_implementation_name =
@@ -57,7 +59,7 @@ GLImplementation GetRequestedGLImplementation(bool* fallback_to_software_gl) {
}
// If the passthrough command decoder is enabled, put ANGLE first if allowed
- if (gl::UsePassthroughCommandDecoder(cmd)) {
+ if (g_is_angle_enabled && gl::UsePassthroughCommandDecoder(cmd)) {
auto iter = std::find(allowed_impls.begin(), allowed_impls.end(),
kGLImplementationEGLANGLE);
if (iter != allowed_impls.end()) {
@@ -207,5 +209,10 @@ scoped_refptr<GLSurface> CreateOffscreenGLSurface(const gfx::Size& size) {
return CreateOffscreenGLSurfaceWithFormat(size, GLSurfaceFormat());
}
+void DisableANGLE() {
+ DCHECK_NE(GetGLImplementation(), kGLImplementationEGLANGLE);
+ g_is_angle_enabled = false;
+}
+
} // namespace init
} // namespace gl
diff --git a/chromium/ui/gl/init/gl_factory.h b/chromium/ui/gl/init/gl_factory.h
index f741c89b003..43028f7b43e 100644
--- a/chromium/ui/gl/init/gl_factory.h
+++ b/chromium/ui/gl/init/gl_factory.h
@@ -102,6 +102,9 @@ GL_INIT_EXPORT scoped_refptr<GLSurface> CreateOffscreenGLSurfaceWithFormat(
GL_INIT_EXPORT void SetDisabledExtensionsPlatform(
const std::string& disabled_extensions);
+// Disable ANGLE and force to use native or other GL implementation.
+GL_INIT_EXPORT void DisableANGLE();
+
} // namespace init
} // namespace gl
diff --git a/chromium/ui/gl/init/gl_initializer.h b/chromium/ui/gl/init/gl_initializer.h
index 4976093284e..4fa188883f9 100644
--- a/chromium/ui/gl/init/gl_initializer.h
+++ b/chromium/ui/gl/init/gl_initializer.h
@@ -5,6 +5,7 @@
#ifndef UI_GL_INIT_GL_INITIALIZER_H_
#define UI_GL_INIT_GL_INITIALIZER_H_
+#include "ui/gl/buildflags.h"
#include "ui/gl/gl_implementation.h"
namespace gl {
@@ -22,6 +23,10 @@ bool InitializeGLOneOffPlatform();
// Initializes a particular GL implementation.
bool InitializeStaticGLBindings(GLImplementation implementation);
+#if BUILDFLAG(USE_STATIC_ANGLE)
+bool InitializeStaticANGLEEGL();
+#endif // BUILDFLAG(USE_STATIC_ANGLE)
+
// Clears GL bindings for all implementations supported by platform.
void ShutdownGLPlatform();
diff --git a/chromium/ui/gl/init/gl_initializer_android.cc b/chromium/ui/gl/init/gl_initializer_android.cc
index 29af2d82da2..d1c269e9c91 100644
--- a/chromium/ui/gl/init/gl_initializer_android.cc
+++ b/chromium/ui/gl/init/gl_initializer_android.cc
@@ -9,31 +9,17 @@
#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_gl_api_implementation.h"
#include "ui/gl/gl_surface_egl.h"
-
-#if BUILDFLAG(USE_STATIC_ANGLE)
-#include <EGL/egl.h>
-#endif // BUILDFLAG(USE_STATIC_ANGLE)
+#include "ui/gl/init/gl_initializer.h"
namespace gl {
namespace init {
namespace {
-#if BUILDFLAG(USE_STATIC_ANGLE)
-bool InitializeStaticANGLEEGLInternal() {
-#pragma push_macro("eglGetProcAddress")
-#undef eglGetProcAddress
- SetGLGetProcAddressProc(&eglGetProcAddress);
-#pragma pop_macro("eglGetProcAddress")
- return true;
-}
-#endif // BUILDFLAG(USE_STATIC_ANGLE)
-
bool InitializeStaticNativeEGLInternal() {
base::NativeLibrary gles_library = LoadLibraryAndPrintError("libGLESv2.so");
if (!gles_library)
@@ -68,7 +54,7 @@ bool InitializeStaticEGLInternal(GLImplementation implementation) {
#if BUILDFLAG(USE_STATIC_ANGLE)
// Use ANGLE if it is requested and it is statically linked
if (implementation == kGLImplementationEGLANGLE) {
- initialized = InitializeStaticANGLEEGLInternal();
+ initialized = InitializeStaticANGLEEGL();
}
#endif // BUILDFLAG(USE_STATIC_ANGLE)
diff --git a/chromium/ui/gl/init/gl_initializer_angle.cc b/chromium/ui/gl/init/gl_initializer_angle.cc
new file mode 100644
index 00000000000..9e0b59b0591
--- /dev/null
+++ b/chromium/ui/gl/init/gl_initializer_angle.cc
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gl/init/gl_initializer.h"
+
+#include <EGL/egl.h>
+
+namespace gl {
+namespace init {
+
+bool InitializeStaticANGLEEGL() {
+#pragma push_macro("eglGetProcAddress")
+#undef eglGetProcAddress
+ SetGLGetProcAddressProc(&eglGetProcAddress);
+#pragma pop_macro("eglGetProcAddress")
+ return true;
+}
+
+} // namespace init
+} // namespace gl
diff --git a/chromium/ui/gl/init/gl_initializer_linux_x11.cc b/chromium/ui/gl/init/gl_initializer_linux_x11.cc
index a5c030d5f3d..b1f21c4bf0e 100644
--- a/chromium/ui/gl/init/gl_initializer_linux_x11.cc
+++ b/chromium/ui/gl/init/gl_initializer_linux_x11.cc
@@ -11,7 +11,6 @@
#include "build/build_config.h"
#include "ui/gfx/switches.h"
#include "ui/gfx/x/connection.h"
-#include "ui/gl/buildflags.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_egl_api_implementation.h"
#include "ui/gl/gl_gl_api_implementation.h"
@@ -20,6 +19,7 @@
#include "ui/gl/gl_surface_glx.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/init/gl_display_egl_util_x11.h"
+#include "ui/gl/init/gl_initializer.h"
namespace gl {
namespace init {
@@ -35,9 +35,6 @@ const char kGLLibraryName[] = "libGL.so.1";
const char kGLESv2LibraryName[] = "libGLESv2.so.2";
const char kEGLLibraryName[] = "libEGL.so.1";
-const char kGLESv2ANGLELibraryName[] = "libGLESv2.so";
-const char kEGLANGLELibraryName[] = "libEGL.so";
-
#if BUILDFLAG(ENABLE_SWIFTSHADER)
const char kGLESv2SwiftShaderLibraryName[] = "libGLESv2.so";
const char kEGLSwiftShaderLibraryName[] = "libEGL.so";
@@ -79,10 +76,9 @@ bool InitializeStaticGLXInternal() {
return true;
}
-bool InitializeStaticEGLInternal(GLImplementation implementation) {
+bool InitializeStaticEGLInternalFromLibrary(GLImplementation implementation) {
base::FilePath glesv2_path(kGLESv2LibraryName);
base::FilePath egl_path(kEGLLibraryName);
-
if (implementation == kGLImplementationSwiftShaderGL) {
#if BUILDFLAG(ENABLE_SWIFTSHADER)
base::FilePath module_path;
@@ -96,12 +92,19 @@ bool InitializeStaticEGLInternal(GLImplementation implementation) {
return false;
#endif
} else if (implementation == kGLImplementationEGLANGLE) {
+#if !BUILDFLAG(USE_STATIC_ANGLE)
base::FilePath module_path;
if (!base::PathService::Get(base::DIR_MODULE, &module_path))
return false;
+ const char kGLESv2ANGLELibraryName[] = "libGLESv2.so";
+ const char kEGLANGLELibraryName[] = "libEGL.so";
+
glesv2_path = module_path.Append(kGLESv2ANGLELibraryName);
egl_path = module_path.Append(kEGLANGLELibraryName);
+#else // BUILDFLAG(USE_STATIC_ANGLE)
+ NOTREACHED();
+#endif
}
base::NativeLibrary gles_library = LoadLibraryAndPrintError(glesv2_path);
@@ -127,6 +130,25 @@ bool InitializeStaticEGLInternal(GLImplementation implementation) {
SetGLGetProcAddressProc(get_proc_address);
AddGLNativeLibrary(egl_library);
AddGLNativeLibrary(gles_library);
+
+ return true;
+}
+
+bool InitializeStaticEGLInternal(GLImplementation implementation) {
+#if BUILDFLAG(USE_STATIC_ANGLE)
+ if (implementation == kGLImplementationEGLANGLE) {
+ // Use ANGLE if it is requested and it is statically linked
+ if (!InitializeStaticANGLEEGL())
+ return false;
+ } else if (!InitializeStaticEGLInternalFromLibrary(implementation)) {
+ return false;
+ }
+#else
+ if (!InitializeStaticEGLInternalFromLibrary(implementation)) {
+ return false;
+ }
+#endif // !BUILDFLAG(USE_STATIC_ANGLE)
+
if (implementation == kGLImplementationEGLANGLE) {
SetGLImplementation(kGLImplementationEGLANGLE);
} else {
diff --git a/chromium/ui/gl/init/gl_initializer_mac.cc b/chromium/ui/gl/init/gl_initializer_mac.cc
index d8ad42a0755..f659291023a 100644
--- a/chromium/ui/gl/init/gl_initializer_mac.cc
+++ b/chromium/ui/gl/init/gl_initializer_mac.cc
@@ -16,13 +16,13 @@
#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_gl_api_implementation.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gpu_switching_manager.h"
+#include "ui/gl/init/gl_initializer.h"
#if defined(USE_EGL)
#include "ui/gl/gl_egl_api_implementation.h"
@@ -97,7 +97,7 @@ const char kEGLANGLELibraryName[] = "libEGL.dylib";
const char kGLESv2SwiftShaderLibraryName[] = "libswiftshader_libGLESv2.dylib";
const char kEGLSwiftShaderLibraryName[] = "libswiftshader_libEGL.dylib";
-bool InitializeStaticEGLInternal(GLImplementation implementation) {
+bool InitializeStaticEGLInternalFromLibrary(GLImplementation implementation) {
// Some unit test targets depend on Angle/SwiftShader but aren't built
// as app bundles. In that case, the .dylib is next to the executable.
base::FilePath base_dir;
@@ -123,6 +123,9 @@ bool InitializeStaticEGLInternal(GLImplementation implementation) {
} else {
glesv2_path = base_dir.Append(kGLESv2ANGLELibraryName);
egl_path = base_dir.Append(kEGLANGLELibraryName);
+#if BUILDFLAG(USE_STATIC_ANGLE)
+ NOTREACHED();
+#endif
}
base::NativeLibrary gles_library = LoadLibraryAndPrintError(glesv2_path);
@@ -152,8 +155,26 @@ bool InitializeStaticEGLInternal(GLImplementation implementation) {
// currently
AddGLNativeLibrary(gles_library);
AddGLNativeLibrary(egl_library);
- SetGLImplementation(implementation);
+ return true;
+}
+
+bool InitializeStaticEGLInternal(GLImplementation implementation) {
+#if BUILDFLAG(USE_STATIC_ANGLE)
+ if (implementation == kGLImplementationEGLANGLE) {
+ // Use ANGLE if it is requested and it is statically linked
+ if (!InitializeStaticANGLEEGL())
+ return false;
+ } else if (!InitializeStaticEGLInternalFromLibrary(implementation)) {
+ return false;
+ }
+#else
+ if (!InitializeStaticEGLInternalFromLibrary(implementation)) {
+ return false;
+ }
+#endif // !BUILDFLAG(USE_STATIC_ANGLE)
+
+ SetGLImplementation(implementation);
InitializeStaticGLBindingsGL();
InitializeStaticGLBindingsEGL();
diff --git a/chromium/ui/gl/init/gl_initializer_win.cc b/chromium/ui/gl/init/gl_initializer_win.cc
index b369eb25585..8e3b73b0642 100644
--- a/chromium/ui/gl/init/gl_initializer_win.cc
+++ b/chromium/ui/gl/init/gl_initializer_win.cc
@@ -17,7 +17,6 @@
#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_gl_api_implementation.h"
@@ -45,7 +44,7 @@ bool LoadD3DXLibrary(const base::FilePath& module_path,
return true;
}
-bool InitializeStaticEGLInternal(GLImplementation implementation) {
+bool InitializeStaticEGLInternalFromLibrary(GLImplementation implementation) {
base::FilePath module_path;
if (!base::PathService::Get(base::DIR_MODULE, &module_path))
return false;
@@ -67,6 +66,9 @@ bool InitializeStaticEGLInternal(GLImplementation implementation) {
#endif
} else {
gles_path = module_path;
+#if BUILDFLAG(USE_STATIC_ANGLE)
+ NOTREACHED();
+#endif
}
// Load libglesv2.dll before libegl.dll because the latter is dependent on
@@ -103,8 +105,26 @@ bool InitializeStaticEGLInternal(GLImplementation implementation) {
SetGLGetProcAddressProc(get_proc_address);
AddGLNativeLibrary(egl_library);
AddGLNativeLibrary(gles_library);
- SetGLImplementation(implementation);
+ return true;
+}
+
+bool InitializeStaticEGLInternal(GLImplementation implementation) {
+#if BUILDFLAG(USE_STATIC_ANGLE)
+ if (implementation == kGLImplementationEGLANGLE) {
+ // Use ANGLE if it is requested and it is statically linked
+ if (!InitializeStaticANGLEEGL())
+ return false;
+ } else if (!InitializeStaticEGLInternalFromLibrary(implementation)) {
+ return false;
+ }
+#else
+ if (!InitializeStaticEGLInternalFromLibrary(implementation)) {
+ return false;
+ }
+#endif // !BUILDFLAG(USE_STATIC_ANGLE)
+
+ SetGLImplementation(implementation);
InitializeStaticGLBindingsGL();
InitializeStaticGLBindingsEGL();
diff --git a/chromium/ui/gl/swap_chain_presenter.cc b/chromium/ui/gl/swap_chain_presenter.cc
index 0b4c1156a3f..bc8f30d0198 100644
--- a/chromium/ui/gl/swap_chain_presenter.cc
+++ b/chromium/ui/gl/swap_chain_presenter.cc
@@ -796,6 +796,7 @@ bool SwapChainPresenter::PresentToDecodeSwapChain(
frames_since_color_space_change_);
frames_since_color_space_change_ = 0;
}
+ swap_chain_format_ = DXGI_FORMAT_NV12;
RecordPresentationStatistics();
return true;
}
@@ -1086,9 +1087,9 @@ bool SwapChainPresenter::VideoProcessorBlt(
// TODO(sunnyps): Ensure output color space for YUV swap chains is Rec709 or
// Rec601 so that the conversion from gfx::ColorSpace to DXGI_COLOR_SPACE
// doesn't need a |force_yuv| parameter (and the associated plumbing).
- gfx::ColorSpace output_color_space = IsYUVSwapChainFormat(swap_chain_format_)
- ? src_color_space
- : gfx::ColorSpace::CreateSRGB();
+ bool is_yuv_swapchain = IsYUVSwapChainFormat(swap_chain_format_);
+ gfx::ColorSpace output_color_space =
+ is_yuv_swapchain ? src_color_space : gfx::ColorSpace::CreateSRGB();
if (base::FeatureList::IsEnabled(kFallbackBT709VideoToBT601) &&
(output_color_space == gfx::ColorSpace::CreateREC709())) {
output_color_space = gfx::ColorSpace::CreateREC601();
@@ -1096,17 +1097,48 @@ bool SwapChainPresenter::VideoProcessorBlt(
if (content_is_hdr)
output_color_space = gfx::ColorSpace::CreateHDR10();
- if (!layer_tree_->InitializeVideoProcessor(
- content_rect.size(), swap_chain_size_, src_color_space,
- output_color_space, swap_chain_,
- IsYUVSwapChainFormat(swap_chain_format_))) {
+ VideoProcessorWrapper* video_processor_wrapper =
+ layer_tree_->InitializeVideoProcessor(
+ content_rect.size(), swap_chain_size_, output_color_space.IsHDR());
+ if (!video_processor_wrapper)
return false;
- }
Microsoft::WRL::ComPtr<ID3D11VideoContext> video_context =
- layer_tree_->video_context();
+ video_processor_wrapper->video_context;
Microsoft::WRL::ComPtr<ID3D11VideoProcessor> video_processor =
- layer_tree_->video_processor();
+ video_processor_wrapper->video_processor;
+
+ Microsoft::WRL::ComPtr<IDXGISwapChain3> swap_chain3;
+ Microsoft::WRL::ComPtr<ID3D11VideoContext1> context1;
+ if (SUCCEEDED(swap_chain_.As(&swap_chain3)) &&
+ SUCCEEDED(video_context.As(&context1))) {
+ DCHECK(swap_chain3);
+ DCHECK(context1);
+ // Set input color space.
+ context1->VideoProcessorSetStreamColorSpace1(
+ video_processor.Get(), 0,
+ gfx::ColorSpaceWin::GetDXGIColorSpace(src_color_space));
+ // Set output color space.
+ DXGI_COLOR_SPACE_TYPE output_dxgi_color_space =
+ gfx::ColorSpaceWin::GetDXGIColorSpace(output_color_space,
+ /*force_yuv=*/is_yuv_swapchain);
+
+ if (SUCCEEDED(swap_chain3->SetColorSpace1(output_dxgi_color_space))) {
+ context1->VideoProcessorSetOutputColorSpace1(video_processor.Get(),
+ output_dxgi_color_space);
+ }
+ } else {
+ // This can't handle as many different types of color spaces, so use it
+ // only if ID3D11VideoContext1 isn't available.
+ D3D11_VIDEO_PROCESSOR_COLOR_SPACE src_d3d11_color_space =
+ gfx::ColorSpaceWin::GetD3D11ColorSpace(src_color_space);
+ video_context->VideoProcessorSetStreamColorSpace(video_processor.Get(), 0,
+ &src_d3d11_color_space);
+ D3D11_VIDEO_PROCESSOR_COLOR_SPACE output_d3d11_color_space =
+ gfx::ColorSpaceWin::GetD3D11ColorSpace(output_color_space);
+ video_context->VideoProcessorSetOutputColorSpace(video_processor.Get(),
+ &output_d3d11_color_space);
+ }
Microsoft::WRL::ComPtr<ID3D11VideoContext2> context2;
base::Optional<DXGI_HDR_METADATA_HDR10> display_metadata =
layer_tree_->GetHDRMetadataHelper()->GetDisplayMetadata();
@@ -1140,9 +1172,10 @@ bool SwapChainPresenter::VideoProcessorBlt(
}
Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device =
- layer_tree_->video_device();
+ video_processor_wrapper->video_device;
Microsoft::WRL::ComPtr<ID3D11VideoProcessorEnumerator>
- video_processor_enumerator = layer_tree_->video_processor_enumerator();
+ video_processor_enumerator =
+ video_processor_wrapper->video_processor_enumerator;
D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC input_desc = {};
input_desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
diff --git a/chromium/ui/gl/yuv_to_rgb_converter.cc b/chromium/ui/gl/yuv_to_rgb_converter.cc
index 514290e282c..e6be831cfff 100644
--- a/chromium/ui/gl/yuv_to_rgb_converter.cc
+++ b/chromium/ui/gl/yuv_to_rgb_converter.cc
@@ -195,6 +195,10 @@ YUVToRGBConverter::YUVToRGBConverter(const GLVersionInfo& gl_version_info,
g_current_gl_driver->ext.b_GL_ANGLE_get_tex_level_parameter;
has_robust_resource_init_ =
g_current_gl_driver->ext.b_GL_ANGLE_robust_resource_initialization;
+
+ has_sampler_objects_ = gl_version_info.IsAtLeastGLES(3, 0) ||
+ gl_version_info.IsAtLeastGL(3, 3) ||
+ g_current_gl_driver->ext.b_GL_ARB_sampler_objects;
}
YUVToRGBConverter::~YUVToRGBConverter() {
@@ -233,9 +237,19 @@ void YUVToRGBConverter::CopyYUV420ToRGB(unsigned target,
GLint old_texture0_binding = -1;
glActiveTexture(GL_TEXTURE0);
glGetIntegerv(source_target_getter, &old_texture0_binding);
+ GLint old_sampler0_binding = -1;
+ if (has_sampler_objects_) {
+ glGetIntegerv(GL_SAMPLER_BINDING, &old_sampler0_binding);
+ glBindSampler(0, 0);
+ }
GLint old_texture1_binding = -1;
glActiveTexture(GL_TEXTURE1);
glGetIntegerv(source_target_getter, &old_texture1_binding);
+ GLint old_sampler1_binding = -1;
+ if (has_sampler_objects_) {
+ glGetIntegerv(GL_SAMPLER_BINDING, &old_sampler1_binding);
+ glBindSampler(1, 0);
+ }
// Allocate the rgb texture.
glActiveTexture(old_active_texture);
@@ -312,6 +326,10 @@ void YUVToRGBConverter::CopyYUV420ToRGB(unsigned target,
glActiveTexture(GL_TEXTURE1);
glBindTexture(source_texture_target_, old_texture1_binding);
glActiveTexture(old_active_texture);
+ if (old_sampler0_binding > 0)
+ glBindSampler(0, old_sampler0_binding);
+ if (old_sampler1_binding > 0)
+ glBindSampler(1, old_sampler1_binding);
}
} // namespace gl
diff --git a/chromium/ui/gl/yuv_to_rgb_converter.h b/chromium/ui/gl/yuv_to_rgb_converter.h
index 28d47d44407..9be78a082f9 100644
--- a/chromium/ui/gl/yuv_to_rgb_converter.h
+++ b/chromium/ui/gl/yuv_to_rgb_converter.h
@@ -44,6 +44,7 @@ class YUVToRGBConverter {
unsigned source_texture_target_ = 0;
bool has_get_tex_level_parameter_ = false;
bool has_robust_resource_init_ = false;
+ bool has_sampler_objects_ = false;
};
} // namespace gl
diff --git a/chromium/ui/gtk/BUILD.gn b/chromium/ui/gtk/BUILD.gn
index e1106392113..447f77309fb 100644
--- a/chromium/ui/gtk/BUILD.gn
+++ b/chromium/ui/gtk/BUILD.gn
@@ -2,13 +2,30 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-assert(is_linux || is_chromeos, "This file should only be referenced on Linux")
+assert(is_linux || is_chromeos_lacros || is_chromeos,
+ "This file should only be referenced on Linux")
+import("//build/buildflag_header.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/features.gni")
import("//build/config/linux/gtk/gtk.gni")
import("//build/config/ozone.gni")
import("//build/config/ui.gni")
import("//printing/buildflags/buildflags.gni")
+import("//tools/generate_stubs/rules.gni")
+
+buildflag_header("gtk_buildflags") {
+ header = "gtk_buildflags.h"
+
+ flags = [ "GTK_VERSION=$gtk_version" ]
+}
+
+generate_stubs("gdk_pixbuf") {
+ sigs = [ "gdk_pixbuf.sigs" ]
+ extra_header = "gdk_pixbuf.fragment"
+ output_name = "gdk_pixbuf"
+ deps = [ "//build/config/linux/gtk" ]
+}
component("gtk_ui_delegate") {
public = [ "gtk_ui_delegate.h" ]
@@ -17,6 +34,7 @@ component("gtk_ui_delegate") {
"//base",
"//ui/gfx",
]
+ public_deps = [ ":gtk_buildflags" ]
defines = [ "IS_GTK_IMPL" ]
}
@@ -62,6 +80,7 @@ component("gtk") {
}
deps = [
+ ":gdk_pixbuf",
"//base",
"//build/config/linux/gtk:gtkprint",
"//printing",
diff --git a/chromium/ui/gtk/DIR_METADATA b/chromium/ui/gtk/DIR_METADATA
new file mode 100644
index 00000000000..2cead19be78
--- /dev/null
+++ b/chromium/ui/gtk/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI>Browser>Themes"
+}
diff --git a/chromium/ui/gtk/OWNERS b/chromium/ui/gtk/OWNERS
index f4ab9a47634..d0aeb473de2 100644
--- a/chromium/ui/gtk/OWNERS
+++ b/chromium/ui/gtk/OWNERS
@@ -1,4 +1,2 @@
estade@chromium.org
thomasanderson@chromium.org
-
-# COMPONENT: UI>Browser>Themes
diff --git a/chromium/ui/gtk/gdk_pixbuf.fragment b/chromium/ui/gtk/gdk_pixbuf.fragment
new file mode 100644
index 00000000000..99e4ea2ecb9
--- /dev/null
+++ b/chromium/ui/gtk/gdk_pixbuf.fragment
@@ -0,0 +1 @@
+#include <gdk-pixbuf/gdk-pixbuf.h>
diff --git a/chromium/ui/gtk/gdk_pixbuf.sigs b/chromium/ui/gtk/gdk_pixbuf.sigs
new file mode 100644
index 00000000000..35caa0fa257
--- /dev/null
+++ b/chromium/ui/gtk/gdk_pixbuf.sigs
@@ -0,0 +1,3 @@
+GdkPixbuf* gdk_pixbuf_new_from_file_at_size(const char* filename, int width, int height, GError** error);
+int gdk_pixbuf_get_width(const GdkPixbuf* pixbuf);
+int gdk_pixbuf_get_height(const GdkPixbuf* pixbuf);
diff --git a/chromium/ui/gtk/gtk_ui.cc b/chromium/ui/gtk/gtk_ui.cc
index 63f4dbc4518..2c96ffb0b5b 100644
--- a/chromium/ui/gtk/gtk_ui.cc
+++ b/chromium/ui/gtk/gtk_ui.cc
@@ -4,6 +4,7 @@
#include "ui/gtk/gtk_ui.h"
+#include <cairo.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <pango/pango.h>
@@ -45,6 +46,7 @@
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/skbitmap_operations.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gtk/gdk_pixbuf.h"
#include "ui/gtk/gtk_key_bindings_handler.h"
#include "ui/gtk/gtk_ui_delegate.h"
#include "ui/gtk/gtk_util.h"
@@ -225,7 +227,6 @@ struct GtkIconInfoDeleter {
};
typedef std::unique_ptr<GIcon, GObjectDeleter> ScopedGIcon;
typedef std::unique_ptr<GtkIconInfo, GtkIconInfoDeleter> ScopedGtkIconInfo;
-typedef std::unique_ptr<GdkPixbuf, GObjectDeleter> ScopedGdkPixbuf;
// Number of app indicators used (used as part of app-indicator id).
int indicators_count;
@@ -309,61 +310,6 @@ views::LinuxUI::WindowFrameAction GetDefaultMiddleClickAction() {
}
}
-const SkBitmap GdkPixbufToSkBitmap(GdkPixbuf* pixbuf) {
- // TODO(erg): What do we do in the case where the pixbuf fails these dchecks?
- // I would prefer to use our gtk based canvas, but that would require
- // recompiling half of our skia extensions with gtk support, which we can't
- // do in this build.
- DCHECK_EQ(GDK_COLORSPACE_RGB, gdk_pixbuf_get_colorspace(pixbuf));
-
- int n_channels = gdk_pixbuf_get_n_channels(pixbuf);
- int w = gdk_pixbuf_get_width(pixbuf);
- int h = gdk_pixbuf_get_height(pixbuf);
-
- SkBitmap ret;
- ret.allocN32Pixels(w, h);
- ret.eraseColor(0);
-
- uint32_t* skia_data = static_cast<uint32_t*>(ret.getAddr(0, 0));
-
- if (n_channels == 4) {
- int total_length = w * h;
- guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
-
- // Now here's the trick: we need to convert the gdk data (which is RGBA and
- // isn't premultiplied) to skia (which can be anything and premultiplied).
- for (int i = 0; i < total_length; ++i, gdk_pixels += 4) {
- const unsigned char& red = gdk_pixels[0];
- const unsigned char& green = gdk_pixels[1];
- const unsigned char& blue = gdk_pixels[2];
- const unsigned char& alpha = gdk_pixels[3];
-
- skia_data[i] = SkPreMultiplyARGB(alpha, red, green, blue);
- }
- } else if (n_channels == 3) {
- // Because GDK makes rowstrides word aligned, we need to do something a bit
- // more complex when a pixel isn't perfectly a word of memory.
- int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
- guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
- for (int y = 0; y < h; ++y) {
- int row = y * rowstride;
-
- for (int x = 0; x < w; ++x) {
- guchar* pixel = gdk_pixels + row + (x * 3);
- const unsigned char& red = pixel[0];
- const unsigned char& green = pixel[1];
- const unsigned char& blue = pixel[2];
-
- skia_data[y * w + x] = SkPreMultiplyARGB(255, red, green, blue);
- }
- }
- } else {
- NOTREACHED();
- }
-
- return ret;
-}
-
} // namespace
GtkUi::GtkUi(ui::GtkUiDelegate* delegate) : delegate_(delegate) {
@@ -413,6 +359,9 @@ void GtkUi::Initialize() {
}
#endif
+ CHECK(ui_gtk::InitializeStubs(
+ {{ui_gtk::kModuleGdk_pixbuf, {"libgdk_pixbuf-2.0.so.0"}}}));
+
GtkSettings* settings = gtk_settings_get_default();
g_signal_connect_after(settings, "notify::gtk-theme-name",
G_CALLBACK(OnThemeChangedThunk), this);
@@ -567,7 +516,7 @@ bool GtkUi::GetDefaultUsesSystemTheme() const {
gfx::Image GtkUi::GetIconForContentType(const std::string& content_type,
int size) const {
// This call doesn't take a reference.
- GtkIconTheme* theme = gtk_icon_theme_get_default();
+ GtkIconTheme* theme = GetDefaultIconTheme();
std::string content_types[] = {content_type, kUnknownContentType};
@@ -578,13 +527,29 @@ gfx::Image GtkUi::GetIconForContentType(const std::string& content_type,
static_cast<GtkIconLookupFlags>(GTK_ICON_LOOKUP_FORCE_SIZE)));
if (!icon_info)
continue;
- ScopedGdkPixbuf pixbuf(gtk_icon_info_load_icon(icon_info.get(), nullptr));
- if (!pixbuf)
+ auto* surface =
+ gtk_icon_info_load_surface(icon_info.get(), nullptr, nullptr);
+ if (!surface)
continue;
+ DCHECK_EQ(cairo_surface_get_type(surface), CAIRO_SURFACE_TYPE_IMAGE);
+ DCHECK_EQ(cairo_image_surface_get_format(surface), CAIRO_FORMAT_ARGB32);
+
+ SkBitmap bitmap;
+ SkImageInfo image_info =
+ SkImageInfo::Make(cairo_image_surface_get_width(surface),
+ cairo_image_surface_get_height(surface),
+ kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
+ if (!bitmap.installPixels(
+ image_info, cairo_image_surface_get_data(surface),
+ image_info.minRowBytes(),
+ [](void*, void* surface) {
+ cairo_surface_destroy(
+ reinterpret_cast<cairo_surface_t*>(surface));
+ },
+ surface)) {
+ continue;
+ }
- SkBitmap bitmap = GdkPixbufToSkBitmap(pixbuf.get());
- DCHECK_EQ(size, bitmap.width());
- DCHECK_EQ(size, bitmap.height());
gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
image_skia.MakeThreadSafe();
return gfx::Image(image_skia);
@@ -932,19 +897,14 @@ void GtkUi::UpdateColors() {
const std::string header_selector_inactive = header_selector + ":backdrop";
const SkColor frame_color =
SkColorSetA(GetBgColor(header_selector), SK_AlphaOPAQUE);
- const SkColor frame_color_incognito =
- color_utils::HSLShift(frame_color, kDefaultTintFrameIncognito);
const SkColor frame_color_inactive =
SkColorSetA(GetBgColor(header_selector_inactive), SK_AlphaOPAQUE);
- const SkColor frame_color_incognito_inactive =
- color_utils::HSLShift(frame_color_inactive, kDefaultTintFrameIncognito);
color_map[ThemeProperties::COLOR_FRAME_ACTIVE] = frame_color;
color_map[ThemeProperties::COLOR_FRAME_INACTIVE] = frame_color_inactive;
- color_map[ThemeProperties::COLOR_FRAME_ACTIVE_INCOGNITO] =
- frame_color_incognito;
+ color_map[ThemeProperties::COLOR_FRAME_ACTIVE_INCOGNITO] = frame_color;
color_map[ThemeProperties::COLOR_FRAME_INACTIVE_INCOGNITO] =
- frame_color_incognito_inactive;
+ frame_color_inactive;
// Compose the window color on the frame color to ensure the resulting tab
// color is opaque.
@@ -969,20 +929,12 @@ void GtkUi::UpdateColors() {
background_tab_text_color;
color_map[ThemeProperties::
COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE_INCOGNITO] =
- color_utils::BlendForMinContrast(
- color_utils::HSLShift(background_tab_text_color,
- kDefaultTintFrameIncognito),
- frame_color_incognito)
- .color;
+ background_tab_text_color;
color_map[ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE] =
background_tab_text_color_inactive;
color_map[ThemeProperties::
COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE_INCOGNITO] =
- color_utils::BlendForMinContrast(
- color_utils::HSLShift(background_tab_text_color_inactive,
- kDefaultTintFrameIncognito),
- frame_color_incognito_inactive)
- .color;
+ background_tab_text_color_inactive;
color_map[ThemeProperties::COLOR_OMNIBOX_TEXT] =
native_theme_->GetSystemColor(
@@ -1086,14 +1038,13 @@ float GtkUi::GetRawDeviceScaleFactor() {
DCHECK_GT(scale, 0.0);
gdouble resolution = gdk_screen_get_resolution(screen);
- // TODO(https://crbug.com/1033552): Remove this hack once the Trusty bots are
- // fixed to have a resolution of 96, or when the Trusty bots are removed
- // altogether.
- if (std::abs(resolution - 95.8486) < 0.001)
- resolution = 96;
if (resolution > 0)
scale *= resolution / kDefaultDPI;
+ // Round to the nearest 64th so that UI can losslessly multiply and divide
+ // the scale factor.
+ scale = roundf(scale * 64) / 64;
+
return scale;
}
diff --git a/chromium/ui/gtk/gtk_ui_delegate.h b/chromium/ui/gtk/gtk_ui_delegate.h
index 9daed0a8f46..7e7c37b0a99 100644
--- a/chromium/ui/gtk/gtk_ui_delegate.h
+++ b/chromium/ui/gtk/gtk_ui_delegate.h
@@ -7,11 +7,17 @@
#include "base/component_export.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/gtk/gtk_buildflags.h"
using GdkKeymap = struct _GdkKeymap;
-using GdkWindow = struct _GdkWindow;
using GtkWindow = struct _GtkWindow;
+#if BUILDFLAG(GTK_VERSION) == 3
+using GdkWindow = struct _GdkWindow;
+#else
+using GdkWindow = struct _GdkSurface;
+#endif
+
namespace ui {
// GtkUiDelegate encapsulates platform-specific functionalities required by
@@ -55,6 +61,9 @@ class COMPONENT_EXPORT(GTK) GtkUiDelegate {
// Presents |window|, doing all the necessary platform-specific operations
// needed, if any.
virtual void ShowGtkWindow(GtkWindow* window) = 0;
+
+ // Get the current keyboard modifier state.
+ virtual int GetGdkKeyState() = 0;
};
} // namespace ui
diff --git a/chromium/ui/gtk/gtk_util.cc b/chromium/ui/gtk/gtk_util.cc
index 6cd7e64be6c..c3ae090b639 100644
--- a/chromium/ui/gtk/gtk_util.cc
+++ b/chromium/ui/gtk/gtk_util.cc
@@ -83,35 +83,23 @@ GdkModifierType GetIbusFlags(const ui::KeyEvent& key_event) {
<< ui::kPropertyKeyboardIBusFlagOffset);
}
-GdkModifierType ExtractGdkEventStateFromKeyEvent(
- const ui::KeyEvent& key_event) {
- auto event_flags = static_cast<ui::EventFlags>(key_event.flags());
- static const struct {
- ui::EventFlags event_flag;
- GdkModifierType gdk_modifier;
- } mapping[] = {
- {ui::EF_SHIFT_DOWN, GDK_SHIFT_MASK},
- {ui::EF_CAPS_LOCK_ON, GDK_LOCK_MASK},
- {ui::EF_CONTROL_DOWN, GDK_CONTROL_MASK},
- {ui::EF_ALT_DOWN, GDK_MOD1_MASK},
- {ui::EF_NUM_LOCK_ON, GDK_MOD2_MASK},
- {ui::EF_MOD3_DOWN, GDK_MOD3_MASK},
- {ui::EF_COMMAND_DOWN, GDK_MOD4_MASK},
- {ui::EF_ALTGR_DOWN, GDK_MOD5_MASK},
- {ui::EF_LEFT_MOUSE_BUTTON, GDK_BUTTON1_MASK},
- {ui::EF_MIDDLE_MOUSE_BUTTON, GDK_BUTTON2_MASK},
- {ui::EF_RIGHT_MOUSE_BUTTON, GDK_BUTTON3_MASK},
- {ui::EF_BACK_MOUSE_BUTTON, GDK_BUTTON4_MASK},
- {ui::EF_FORWARD_MOUSE_BUTTON, GDK_BUTTON5_MASK},
- };
- unsigned int gdk_modifier_type = 0;
- for (const auto& map : mapping) {
- if (event_flags & map.event_flag) {
- gdk_modifier_type = gdk_modifier_type | map.gdk_modifier;
- }
+GdkModifierType GetGdkKeyEventState(ui::KeyEvent key_event) {
+ // ui::KeyEvent uses a normalized modifier state which is not respected by
+ // Gtk, so we need to get the state from the display backend. Gtk instead
+ // follows the X11 spec in which the state of a key event is expected to be
+ // the mask of modifier keys _prior_ to this event. Some IMEs rely on this
+ // behavior. See https://crbug.com/1086946#c11.
+
+ GdkModifierType state = GetIbusFlags(key_event);
+ if (key_event.key_code() != ui::VKEY_PROCESSKEY) {
+ // This is an synthetized event when |key_code| is VKEY_PROCESSKEY.
+ // In such a case there is no event being dispatching in the display
+ // backend.
+ state = static_cast<GdkModifierType>(
+ state | ui::GtkUiDelegate::instance()->GetGdkKeyState());
}
- return static_cast<GdkModifierType>(gdk_modifier_type |
- GetIbusFlags(key_event));
+
+ return state;
}
int GetKeyEventProperty(const ui::KeyEvent& key_event,
@@ -128,11 +116,6 @@ int GetKeyEventProperty(const ui::KeyEvent& key_event,
namespace gtk {
-// TODO(thomasanderson): ThemeService has a whole interface just for reading
-// default constants. Figure out what to do with that more long term; for now,
-// just copy the constant itself here.
-const color_utils::HSL kDefaultTintFrameIncognito = {-1, 0.2f, 0.35f};
-
void GtkInitFromCommandLine(const base::CommandLine& command_line) {
CommonInitFromCommandLine(command_line);
}
@@ -590,7 +573,7 @@ GdkEvent* GdkEventFromKeyEvent(const ui::KeyEvent& key_event) {
GdkKeymap* keymap = GtkUi::GetDelegate()->GetGdkKeymap();
// Get keyval and state
- GdkModifierType state = ExtractGdkEventStateFromKeyEvent(key_event);
+ GdkModifierType state = GetGdkKeyEventState(key_event);
guint keyval = GDK_KEY_VoidSymbol;
GdkModifierType consumed;
gdk_keymap_translate_keyboard_state(keymap, hw_code, state, group, &keyval,
@@ -614,4 +597,12 @@ GdkEvent* GdkEventFromKeyEvent(const ui::KeyEvent& key_event) {
return gdk_event;
}
+GtkIconTheme* GetDefaultIconTheme() {
+#if GTK_CHECK_VERSION(3, 90, 0)
+ return gtk_icon_theme_get_for_display(gdk_display_get_default());
+#else
+ return gtk_icon_theme_get_default();
+#endif
+}
+
} // namespace gtk
diff --git a/chromium/ui/gtk/gtk_util.h b/chromium/ui/gtk/gtk_util.h
index 1512a55ed7b..df6cac5ba32 100644
--- a/chromium/ui/gtk/gtk_util.h
+++ b/chromium/ui/gtk/gtk_util.h
@@ -5,8 +5,11 @@
#ifndef UI_GTK_GTK_UTIL_H_
#define UI_GTK_GTK_UTIL_H_
+#include <gdk/gdk.h>
#include <gtk/gtk.h>
+
#include <string>
+#include <vector>
#include "ui/base/glib/scoped_gobject.h"
#include "ui/native_theme/native_theme.h"
@@ -16,8 +19,6 @@
// not nullptr.
#define WEAK_GTK_FN(x) extern "C" __attribute__((weak)) decltype(x) x
-typedef union _GdkEvent GdkEvent;
-
namespace aura {
class Window;
}
@@ -26,18 +27,12 @@ namespace base {
class CommandLine;
}
-namespace color_utils {
-struct HSL;
-}
-
namespace ui {
class KeyEvent;
}
namespace gtk {
-extern const color_utils::HSL kDefaultTintFrameIncognito;
-
void GtkInitFromCommandLine(const base::CommandLine& command_line);
// Sets |dialog| as transient for |parent|, which will keep it on top and center
@@ -90,6 +85,7 @@ bool GtkCheckVersion(int major, int minor = 0, int micro = 0);
using ScopedStyleContext = ScopedGObject<GtkStyleContext>;
using ScopedCssProvider = ScopedGObject<GtkCssProvider>;
+#if !GTK_CHECK_VERSION(3, 90, 0)
} // namespace gtk
// Template override cannot be in the gtk namespace.
@@ -117,6 +113,7 @@ inline void gtk::ScopedStyleContext::Unref() {
}
namespace gtk {
+#endif
// Converts ui::NativeTheme::State to GtkStateFlags.
GtkStateFlags StateToStateFlags(ui::NativeTheme::State state);
@@ -196,6 +193,8 @@ int BuildXkbStateFromGdkEvent(unsigned int state, unsigned char group);
// root aura::Window targeted by that key event.
GdkEvent* GdkEventFromKeyEvent(const ui::KeyEvent& key_event);
+GtkIconTheme* GetDefaultIconTheme();
+
} // namespace gtk
#endif // UI_GTK_GTK_UTIL_H_
diff --git a/chromium/ui/gtk/input_method_context_impl_gtk.cc b/chromium/ui/gtk/input_method_context_impl_gtk.cc
index b3b03c560ec..332d171ef3b 100644
--- a/chromium/ui/gtk/input_method_context_impl_gtk.cc
+++ b/chromium/ui/gtk/input_method_context_impl_gtk.cc
@@ -215,6 +215,7 @@ void InputMethodContextImplGtk::SetContextClientWindow(GdkWindow* window) {
if (window == gdk_last_set_client_window_)
return;
#if GTK_CHECK_VERSION(3, 90, 0)
+ asdf;
gtk_im_context_set_client_widget(gtk_context_, GTK_WIDGET(window));
#else
gtk_im_context_set_client_window(gtk_context_, window);
diff --git a/chromium/ui/gtk/input_method_context_impl_gtk.h b/chromium/ui/gtk/input_method_context_impl_gtk.h
index 3423c5a7f0b..1034b7412ff 100644
--- a/chromium/ui/gtk/input_method_context_impl_gtk.h
+++ b/chromium/ui/gtk/input_method_context_impl_gtk.h
@@ -11,10 +11,16 @@
#include "ui/base/glib/glib_signal.h"
#include "ui/base/ime/linux/linux_input_method_context.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gtk/gtk_buildflags.h"
-typedef struct _GdkWindow GdkWindow;
typedef struct _GtkIMContext GtkIMContext;
+#if BUILDFLAG(GTK_VERSION) == 3
+using GdkWindow = struct _GdkWindow;
+#else
+using GdkWindow = struct _GdkSurface;
+#endif
+
namespace gtk {
// An implementation of LinuxInputMethodContext which uses GtkIMContext
diff --git a/chromium/ui/gtk/native_theme_gtk.cc b/chromium/ui/gtk/native_theme_gtk.cc
index 977f166904f..29ad448b157 100644
--- a/chromium/ui/gtk/native_theme_gtk.cc
+++ b/chromium/ui/gtk/native_theme_gtk.cc
@@ -9,9 +9,9 @@
#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/skbitmap_operations.h"
#include "ui/gfx/skia_util.h"
#include "ui/gtk/gtk_util.h"
+#include "ui/native_theme/native_theme_aura.h"
namespace gtk {
@@ -459,6 +459,19 @@ void NativeThemeGtk::SetThemeCssOverride(ScopedCssProvider provider) {
}
}
+void NativeThemeGtk::NotifyObservers() {
+ NativeTheme::NotifyObservers();
+
+ // Update the preferred contrast settings for the NativeThemeAura instance and
+ // notify its observers about the change.
+ ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi();
+ native_theme->set_preferred_contrast(
+ UserHasContrastPreference()
+ ? ui::NativeThemeBase::PreferredContrast::kMore
+ : ui::NativeThemeBase::PreferredContrast::kNoPreference);
+ native_theme->NotifyObservers();
+}
+
void NativeThemeGtk::OnThemeChanged(GtkSettings* settings,
GtkParamSpec* param) {
SetThemeCssOverride(ScopedCssProvider());
@@ -496,8 +509,11 @@ void NativeThemeGtk::OnThemeChanged(GtkSettings* settings,
// case-insensitive.
std::transform(theme_name.begin(), theme_name.end(), theme_name.begin(),
::tolower);
- set_high_contrast(theme_name.find("high") != std::string::npos &&
- theme_name.find("contrast") != std::string::npos);
+ bool high_contrast = theme_name.find("high") != std::string::npos &&
+ theme_name.find("contrast") != std::string::npos;
+ set_preferred_contrast(
+ high_contrast ? ui::NativeThemeBase::PreferredContrast::kMore
+ : ui::NativeThemeBase::PreferredContrast::kNoPreference);
NotifyObservers();
}
@@ -708,13 +724,7 @@ void NativeThemeGtk::PaintFrameTopArea(
SkBitmap bitmap =
GetWidgetBitmap(rect.size(), context, BG_RENDER_RECURSIVE, false);
-
- if (frame_top_area.incognito) {
- bitmap = SkBitmapOperations::CreateHSLShiftedBitmap(
- bitmap, kDefaultTintFrameIncognito);
- bitmap.setImmutable();
- }
-
+ bitmap.setImmutable();
canvas->drawImage(cc::PaintImage::CreateFromBitmap(std::move(bitmap)),
rect.x(), rect.y());
}
diff --git a/chromium/ui/gtk/native_theme_gtk.h b/chromium/ui/gtk/native_theme_gtk.h
index af2d80892df..a89d1f78399 100644
--- a/chromium/ui/gtk/native_theme_gtk.h
+++ b/chromium/ui/gtk/native_theme_gtk.h
@@ -71,6 +71,7 @@ class NativeThemeGtk : public ui::NativeThemeBase {
const gfx::Rect& rect,
const FrameTopAreaExtraParams& frame_top_area,
ColorScheme color_scheme) const override;
+ void NotifyObservers() override;
void OnThemeChanged(GtkSettings* settings, GtkParamSpec* param);
diff --git a/chromium/ui/gtk/nav_button_provider_gtk.cc b/chromium/ui/gtk/nav_button_provider_gtk.cc
index 441dcd8c0de..119da0ead30 100644
--- a/chromium/ui/gtk/nav_button_provider_gtk.cc
+++ b/chromium/ui/gtk/nav_button_provider_gtk.cc
@@ -16,6 +16,12 @@ namespace gtk {
namespace {
+#if GTK_CHECK_VERSION(3, 90, 0)
+using NavButtonIcon = ScopedGObject<GdkTexture>;
+#else
+using NavButtonIcon = ScopedGObject<GdkPixbuf>;
+#endif
+
// gtkheaderbar.c uses GTK_ICON_SIZE_MENU, which is 16px.
const int kNavButtonIconSize = 16;
@@ -109,17 +115,41 @@ gfx::Insets MarginFromStyleContext(GtkStyleContext* context,
return InsetsFromGtkBorder(margin);
}
-ScopedGObject<GdkPixbuf> LoadNavButtonIcon(
+gfx::Size LoadNavButtonIcon(
views::NavButtonProvider::FrameButtonDisplayType type,
GtkStyleContext* button_context,
- int scale) {
+ int scale,
+ NavButtonIcon* icon = nullptr) {
const char* icon_name = IconNameFromButtonType(type);
+#if GTK_CHECK_VERSION(3, 90, 0)
+ ScopedGObject<GtkIconPaintable> icon_paintable(gtk_icon_theme_lookup_icon(
+ GetDefaultIconTheme(), icon_name, nullptr, kNavButtonIconSize, scale,
+ GTK_TEXT_DIR_NONE, static_cast<GtkIconLookupFlags>(0)));
+ auto* paintable = GDK_PAINTABLE(icon_paintable);
+ int width = gdk_paintable_get_intrinsic_width(paintable);
+ int height = gdk_paintable_get_intrinsic_height(paintable);
+ if (icon) {
+ auto* snapshot = gtk_snapshot_new();
+ gdk_paintable_snapshot(paintable, snapshot, width, height);
+ ScopedGObject<GskRenderNode> node(gtk_snapshot_free_to_node(snapshot));
+ auto rect = GRAPHENE_RECT_INIT(0, 0, width, height);
+ ScopedGObject<GskRenderer> renderer(gsk_cairo_renderer_new());
+ *icon = NavButtonIcon(gsk_renderer_render_texture(renderer, node, &rect));
+ }
+ return {width, height};
+#else
ScopedGObject<GtkIconInfo> icon_info(gtk_icon_theme_lookup_icon_for_scale(
- gtk_icon_theme_get_default(), icon_name, kNavButtonIconSize, scale,
+ GetDefaultIconTheme(), icon_name, kNavButtonIconSize, scale,
static_cast<GtkIconLookupFlags>(GTK_ICON_LOOKUP_USE_BUILTIN |
GTK_ICON_LOOKUP_GENERIC_FALLBACK)));
- return ScopedGObject<GdkPixbuf>(gtk_icon_info_load_symbolic_for_context(
+ NavButtonIcon icon_pixbuf(gtk_icon_info_load_symbolic_for_context(
icon_info, button_context, nullptr, nullptr));
+ gfx::Size size{gdk_pixbuf_get_width(icon_pixbuf),
+ gdk_pixbuf_get_height(icon_pixbuf)};
+ if (icon)
+ *icon = std::move(icon_pixbuf);
+ return size;
+#endif
}
gfx::Size GetMinimumWidgetSize(gfx::Size content_size,
@@ -129,18 +159,15 @@ gfx::Size GetMinimumWidgetSize(gfx::Size content_size,
gfx::Rect widget_rect = gfx::Rect(content_size);
if (content_context)
widget_rect.Inset(-MarginFromStyleContext(content_context, state));
+#if !GTK_CHECK_VERSION(3, 90, 0)
if (GtkCheckVersion(3, 20)) {
int min_width, min_height;
-#if GTK_CHECK_VERSION(3, 90, 0)
- gtk_style_context_get(widget_context, "min-width", &min_width, "min-height",
- &min_height, nullptr);
-#else
gtk_style_context_get(widget_context, state, "min-width", &min_width,
"min-height", &min_height, nullptr);
-#endif
widget_rect.set_width(std::max(widget_rect.width(), min_width));
widget_rect.set_height(std::max(widget_rect.height(), min_height));
}
+#endif
widget_rect.Inset(-PaddingFromStyleContext(widget_context, state));
widget_rect.Inset(-BorderFromStyleContext(widget_context, state));
return widget_rect.size();
@@ -169,11 +196,8 @@ void CalculateUnscaledButtonSize(
"GtkButton#button.titlebutton." +
std::string(ButtonStyleClassFromButtonType(type)));
- ScopedGObject<GdkPixbuf> icon_pixbuf =
- LoadNavButtonIcon(type, button_context, 1);
+ auto icon_size = LoadNavButtonIcon(type, button_context, 1);
- gfx::Size icon_size(gdk_pixbuf_get_width(icon_pixbuf),
- gdk_pixbuf_get_height(icon_pixbuf));
auto image_context =
AppendCssNodeToStyleContext(button_context, "GtkImage#image");
gfx::Size image_size = GetMinimumWidgetSize(icon_size, nullptr, image_context,
@@ -198,7 +222,7 @@ class NavButtonImageSource : public gfx::ImageSkiaSource {
active_(active),
button_size_(button_size) {}
- ~NavButtonImageSource() override {}
+ ~NavButtonImageSource() override = default;
gfx::ImageSkiaRep GetImageForScale(float scale) override {
// gfx::ImageSkia kindly caches the result of this function, so
@@ -261,11 +285,9 @@ class NavButtonImageSource : public gfx::ImageSkiaSource {
// transform. But the icon is loaded from a pixbuf, so we pick
// the next-highest integer scale and manually downsize.
int pixbuf_scale = scale == static_cast<int>(scale) ? scale : scale + 1;
- ScopedGObject<GdkPixbuf> icon_pixbuf =
- LoadNavButtonIcon(type_, button_context, pixbuf_scale);
-
- gfx::Size icon_size(gdk_pixbuf_get_width(icon_pixbuf),
- gdk_pixbuf_get_height(icon_pixbuf));
+ NavButtonIcon icon_pixbuf;
+ auto icon_size =
+ LoadNavButtonIcon(type_, button_context, pixbuf_scale, &icon_pixbuf);
SkBitmap bitmap;
bitmap.allocN32Pixels(scale * button_size_.width(),
@@ -309,9 +331,9 @@ class NavButtonImageSource : public gfx::ImageSkiaSource {
} // namespace
-NavButtonProviderGtk::NavButtonProviderGtk() {}
+NavButtonProviderGtk::NavButtonProviderGtk() = default;
-NavButtonProviderGtk::~NavButtonProviderGtk() {}
+NavButtonProviderGtk::~NavButtonProviderGtk() = default;
void NavButtonProviderGtk::RedrawImages(int top_area_height,
bool maximized,
diff --git a/chromium/ui/gtk/printing/DIR_METADATA b/chromium/ui/gtk/printing/DIR_METADATA
new file mode 100644
index 00000000000..ee7161a682c
--- /dev/null
+++ b/chromium/ui/gtk/printing/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals>Printing"
+}
diff --git a/chromium/ui/gtk/printing/OWNERS b/chromium/ui/gtk/printing/OWNERS
index d50bb849014..9b08c6620bd 100644
--- a/chromium/ui/gtk/printing/OWNERS
+++ b/chromium/ui/gtk/printing/OWNERS
@@ -1,3 +1 @@
file://printing/OWNERS
-
-# COMPONENT: Internals>Printing
diff --git a/chromium/ui/gtk/select_file_dialog_impl.cc b/chromium/ui/gtk/select_file_dialog_impl.cc
index 8dfc91f918e..36d53b986b8 100644
--- a/chromium/ui/gtk/select_file_dialog_impl.cc
+++ b/chromium/ui/gtk/select_file_dialog_impl.cc
@@ -79,7 +79,7 @@ SelectFileDialogImpl::SelectFileDialogImpl(
}
}
-SelectFileDialogImpl::~SelectFileDialogImpl() {}
+SelectFileDialogImpl::~SelectFileDialogImpl() = default;
void SelectFileDialogImpl::ListenerDestroyed() {
listener_ = nullptr;
diff --git a/chromium/ui/gtk/select_file_dialog_impl_gtk.cc b/chromium/ui/gtk/select_file_dialog_impl_gtk.cc
index f810e48d364..1d7b74b1644 100644
--- a/chromium/ui/gtk/select_file_dialog_impl_gtk.cc
+++ b/chromium/ui/gtk/select_file_dialog_impl_gtk.cc
@@ -23,6 +23,7 @@
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "ui/aura/window_observer.h"
+#include "ui/base/glib/scoped_gobject.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gtk/gtk_ui.h"
#include "ui/gtk/gtk_ui_delegate.h"
@@ -51,18 +52,6 @@ const char* const kSaveLabel = GTK_STOCK_SAVE;
G_GNUC_END_IGNORE_DEPRECATIONS
#endif
-// Makes sure that .jpg also shows .JPG.
-gboolean FileFilterCaseInsensitive(const GtkFileFilterInfo* file_info,
- std::string* file_extension) {
- return base::EndsWith(file_info->filename, *file_extension,
- base::CompareCase::INSENSITIVE_ASCII);
-}
-
-// Deletes |data| when gtk_file_filter_add_custom() is done with it.
-void OnFileFilterDataDestroyed(std::string* file_extension) {
- delete file_extension;
-}
-
// Runs DesktopWindowTreeHostLinux::EnableEventListening() when the file-picker
// is closed.
void OnFilePickerDestroy(base::OnceClosure* callback_raw) {
@@ -70,10 +59,101 @@ void OnFilePickerDestroy(base::OnceClosure* callback_raw) {
std::move(*callback).Run();
}
+void GtkFileChooserSetCurrentFolder(GtkFileChooser* dialog,
+ const base::FilePath& path) {
+#if GTK_CHECK_VERSION(3, 90, 0)
+ ScopedGObject<GFile> file(g_file_new_for_path(path.value().c_str()));
+ gtk_file_chooser_set_current_folder(dialog, file, nullptr);
+#else
+ gtk_file_chooser_set_current_folder(dialog, path.value().c_str());
+#endif
+}
+
+void GtkFileChooserSetFilename(GtkFileChooser* dialog,
+ const base::FilePath& path) {
+#if GTK_CHECK_VERSION(3, 90, 0)
+ ScopedGObject<GFile> file(g_file_new_for_path(path.value().c_str()));
+ gtk_file_chooser_set_file(dialog, file, nullptr);
+#else
+ gtk_file_chooser_set_filename(dialog, path.value().c_str());
+#endif
+}
+
+void GtkWindowDestroy(GtkWidget* widget) {
+#if GTK_CHECK_VERSION(3, 90, 0)
+ gtk_window_destroy(GTK_WINDOW(widget));
+#else
+ gtk_widget_destroy(widget);
+#endif
+}
+
+int GtkDialogSelectedFilterIndex(GtkWidget* dialog) {
+ GtkFileFilter* selected_filter =
+ gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog));
+#if GTK_CHECK_VERSION(3, 90, 0)
+ ScopedGObject<GListModel> filters(
+ gtk_file_chooser_get_filters(GTK_FILE_CHOOSER(dialog)));
+ int size = g_list_model_get_n_items(filters);
+ int idx = -1;
+ for (; idx < size; ++idx) {
+ if (g_list_model_get_item(filters, idx) == selected_filter)
+ break;
+ }
+#else
+ GSList* filters = gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(dialog));
+ int idx = g_slist_index(filters, selected_filter);
+ g_slist_free(filters);
+#endif
+ return idx;
+}
+
+std::string GtkFileChooserGetFilename(GtkWidget* dialog) {
+ const char* filename = nullptr;
+#if GTK_CHECK_VERSION(3, 90, 0)
+ ScopedGObject<GFile> file(
+ gtk_file_chooser_get_file(GTK_FILE_CHOOSER(dialog)));
+ if (file)
+ filename = g_file_peek_path(file);
+#else
+ struct GFreeDeleter {
+ void operator()(gchar* ptr) const { g_free(ptr); }
+ };
+ std::unique_ptr<gchar, GFreeDeleter> gchar_filename(
+ gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
+ filename = gchar_filename.get();
+#endif
+ return filename ? std::string(filename) : std::string();
+}
+
+std::vector<base::FilePath> GtkFileChooserGetFilenames(GtkWidget* dialog) {
+ std::vector<base::FilePath> filenames_fp;
+#if GTK_CHECK_VERSION(3, 90, 0)
+ ScopedGObject<GListModel> files(
+ gtk_file_chooser_get_files(GTK_FILE_CHOOSER(dialog)));
+ auto size = g_list_model_get_n_items(files);
+ for (unsigned int i = 0; i < size; ++i) {
+ ScopedGObject<GFile> file(G_FILE(g_list_model_get_object(files, i)));
+ filenames_fp.emplace_back(g_file_peek_path(file));
+ }
+#else
+ GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
+ if (!filenames)
+ return {};
+ for (GSList* iter = filenames; iter != nullptr; iter = g_slist_next(iter)) {
+ base::FilePath path(static_cast<char*>(iter->data));
+ g_free(iter->data);
+ filenames_fp.push_back(path);
+ }
+ g_slist_free(filenames);
+#endif
+ return filenames_fp;
+}
+
} // namespace
namespace gtk {
+#if !GTK_CHECK_VERSION(3, 90, 0)
// The size of the preview we display for selected image files. We set height
// larger than width because generally there is more free space vertically
// than horiztonally (setting the preview image will alway expand the width of
@@ -81,6 +161,7 @@ namespace gtk {
// be preserved.
static const int kPreviewWidth = 256;
static const int kPreviewHeight = 512;
+#endif
SelectFileDialogImpl* SelectFileDialogImpl::NewSelectFileDialogImplGTK(
Listener* listener,
@@ -91,15 +172,14 @@ SelectFileDialogImpl* SelectFileDialogImpl::NewSelectFileDialogImplGTK(
SelectFileDialogImplGTK::SelectFileDialogImplGTK(
Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy)
- : SelectFileDialogImpl(listener, std::move(policy)), preview_(nullptr) {}
+ : SelectFileDialogImpl(listener, std::move(policy)) {}
SelectFileDialogImplGTK::~SelectFileDialogImplGTK() {
- for (std::set<aura::Window*>::iterator iter = parents_.begin();
- iter != parents_.end(); ++iter) {
- (*iter)->RemoveObserver(this);
- }
- while (dialogs_.begin() != dialogs_.end()) {
- gtk_widget_destroy(*(dialogs_.begin()));
+ for (auto* window : parents_)
+ window->RemoveObserver(this);
+ while (!dialogs_.empty()) {
+ auto* widget = *(dialogs_.begin());
+ GtkWindowDestroy(widget);
}
}
@@ -113,11 +193,10 @@ bool SelectFileDialogImplGTK::HasMultipleFileTypeChoicesImpl() {
void SelectFileDialogImplGTK::OnWindowDestroying(aura::Window* window) {
// Remove the |parent| property associated with the |dialog|.
- for (std::set<GtkWidget*>::iterator it = dialogs_.begin();
- it != dialogs_.end(); ++it) {
- aura::Window* parent = GetAuraTransientParent(*it);
+ for (auto* dialog : dialogs_) {
+ aura::Window* parent = GetAuraTransientParent(dialog);
if (parent == window)
- ClearAuraTransientParent(*it, parent);
+ ClearAuraTransientParent(dialog, parent);
}
std::set<aura::Window*>::iterator iter = parents_.find(window);
@@ -171,16 +250,23 @@ void SelectFileDialogImplGTK::SelectFileImpl(
NOTREACHED();
return;
}
+#if GTK_CHECK_VERSION(3, 90, 0)
+ gtk_window_set_hide_on_close(GTK_WINDOW(dialog), true);
+#else
g_signal_connect(dialog, "delete-event",
G_CALLBACK(gtk_widget_hide_on_delete), nullptr);
+#endif
dialogs_.insert(dialog);
- preview_ = gtk_image_new();
g_signal_connect(dialog, "destroy", G_CALLBACK(OnFileChooserDestroyThunk),
this);
+
+#if !GTK_CHECK_VERSION(3, 90, 0)
+ preview_ = gtk_image_new();
g_signal_connect(dialog, "update-preview", G_CALLBACK(OnUpdatePreviewThunk),
this);
gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), preview_);
+#endif
params_map_[dialog] = params;
@@ -217,19 +303,16 @@ void SelectFileDialogImplGTK::AddFilters(GtkFileChooser* chooser) {
GtkFileFilter* filter = nullptr;
std::set<std::string> fallback_labels;
- for (size_t j = 0; j < file_types_.extensions[i].size(); ++j) {
- const std::string& current_extension = file_types_.extensions[i][j];
+ for (const auto& current_extension : file_types_.extensions[i]) {
if (!current_extension.empty()) {
if (!filter)
filter = gtk_file_filter_new();
- std::unique_ptr<std::string> file_extension(
- new std::string("." + current_extension));
- fallback_labels.insert(std::string("*").append(*file_extension));
- gtk_file_filter_add_custom(
- filter, GTK_FILE_FILTER_FILENAME,
- reinterpret_cast<GtkFileFilterFunc>(FileFilterCaseInsensitive),
- file_extension.release(),
- reinterpret_cast<GDestroyNotify>(OnFileFilterDataDestroyed));
+ for (std::string pattern :
+ {"*." + base::ToLowerASCII(current_extension),
+ "*." + base::ToUpperASCII(current_extension)}) {
+ gtk_file_filter_add_pattern(filter, pattern.c_str());
+ fallback_labels.insert(pattern);
+ }
}
}
// We didn't find any non-empty extensions to filter on.
@@ -281,14 +364,10 @@ void SelectFileDialogImplGTK::FileSelected(GtkWidget* dialog,
}
if (listener_) {
- GtkFileFilter* selected_filter =
- gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog));
- GSList* filters = gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(dialog));
- int idx = g_slist_index(filters, selected_filter);
- g_slist_free(filters);
- listener_->FileSelected(path, idx + 1, PopParamsForDialog(dialog));
+ listener_->FileSelected(path, GtkDialogSelectedFilterIndex(dialog) + 1,
+ PopParamsForDialog(dialog));
}
- gtk_widget_destroy(dialog);
+ GtkWindowDestroy(dialog);
}
void SelectFileDialogImplGTK::MultiFilesSelected(
@@ -298,14 +377,14 @@ void SelectFileDialogImplGTK::MultiFilesSelected(
if (listener_)
listener_->MultiFilesSelected(files, PopParamsForDialog(dialog));
- gtk_widget_destroy(dialog);
+ GtkWindowDestroy(dialog);
}
void SelectFileDialogImplGTK::FileNotSelected(GtkWidget* dialog) {
void* params = PopParamsForDialog(dialog);
if (listener_)
listener_->FileSelectionCanceled(params);
- gtk_widget_destroy(dialog);
+ GtkWindowDestroy(dialog);
}
GtkWidget* SelectFileDialogImplGTK::CreateFileOpenHelper(
@@ -320,17 +399,15 @@ GtkWidget* SelectFileDialogImplGTK::CreateFileOpenHelper(
if (!default_path.empty()) {
if (CallDirectoryExistsOnUIThread(default_path)) {
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
- default_path.value().c_str());
+ GtkFileChooserSetCurrentFolder(GTK_FILE_CHOOSER(dialog), default_path);
} else {
// If the file doesn't exist, this will just switch to the correct
// directory. That's good enough.
- gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
- default_path.value().c_str());
+ GtkFileChooserSetFilename(GTK_FILE_CHOOSER(dialog), default_path);
}
} else if (!last_opened_path_->empty()) {
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
- last_opened_path_->value().c_str());
+ GtkFileChooserSetCurrentFolder(GTK_FILE_CHOOSER(dialog),
+ *last_opened_path_);
}
return dialog;
}
@@ -361,12 +438,10 @@ GtkWidget* SelectFileDialogImplGTK::CreateSelectFolderDialog(
GtkFileChooser* chooser = GTK_FILE_CHOOSER(dialog);
if (type == SELECT_UPLOAD_FOLDER || type == SELECT_EXISTING_FOLDER)
gtk_file_chooser_set_create_folders(chooser, FALSE);
- if (!default_path.empty()) {
- gtk_file_chooser_set_filename(chooser, default_path.value().c_str());
- } else if (!last_opened_path_->empty()) {
- gtk_file_chooser_set_current_folder(chooser,
- last_opened_path_->value().c_str());
- }
+ if (!default_path.empty())
+ GtkFileChooserSetCurrentFolder(chooser, default_path);
+ else if (!last_opened_path_->empty())
+ GtkFileChooserSetCurrentFolder(chooser, *last_opened_path_);
GtkFileFilter* only_folders = gtk_file_filter_new();
gtk_file_filter_set_name(
only_folders,
@@ -429,24 +504,25 @@ GtkWidget* SelectFileDialogImplGTK::CreateSaveAsDialog(
if (CallDirectoryExistsOnUIThread(default_path)) {
// If this is an existing directory, navigate to that directory, with no
// filename.
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
- default_path.value().c_str());
+ GtkFileChooserSetCurrentFolder(GTK_FILE_CHOOSER(dialog), default_path);
} else {
// The default path does not exist, or is an existing file. We use
// set_current_folder() followed by set_current_name(), as per the
// recommendation of the GTK docs.
- gtk_file_chooser_set_current_folder(
- GTK_FILE_CHOOSER(dialog), default_path.DirName().value().c_str());
+ GtkFileChooserSetCurrentFolder(GTK_FILE_CHOOSER(dialog),
+ default_path.DirName());
gtk_file_chooser_set_current_name(
GTK_FILE_CHOOSER(dialog), default_path.BaseName().value().c_str());
}
} else if (!last_saved_path_->empty()) {
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
- last_saved_path_->value().c_str());
+ GtkFileChooserSetCurrentFolder(GTK_FILE_CHOOSER(dialog), *last_saved_path_);
}
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
+ // Overwrite confirmation is always enabled in GTK4.
+#if !GTK_CHECK_VERSION(3, 90, 0)
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),
TRUE);
+#endif
g_signal_connect(dialog, "response",
G_CALLBACK(OnSelectSingleFileDialogResponseThunk), this);
return dialog;
@@ -478,14 +554,12 @@ void SelectFileDialogImplGTK::SelectSingleFileHelper(GtkWidget* dialog,
return;
}
- gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
- if (!filename) {
+ auto filename = GtkFileChooserGetFilename(dialog);
+ if (filename.empty()) {
FileNotSelected(dialog);
return;
}
-
base::FilePath path(filename);
- g_free(filename);
if (allow_folder) {
FileSelected(dialog, path);
@@ -517,27 +591,17 @@ void SelectFileDialogImplGTK::OnSelectMultiFileDialogResponse(GtkWidget* dialog,
return;
}
- GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
- if (!filenames) {
- FileNotSelected(dialog);
- return;
- }
-
- std::vector<base::FilePath> filenames_fp;
- for (GSList* iter = filenames; iter != nullptr; iter = g_slist_next(iter)) {
- base::FilePath path(static_cast<char*>(iter->data));
- g_free(iter->data);
- if (CallDirectoryExistsOnUIThread(path))
- continue;
- filenames_fp.push_back(path);
- }
- g_slist_free(filenames);
-
- if (filenames_fp.empty()) {
+ auto filenames = GtkFileChooserGetFilenames(dialog);
+ filenames.erase(std::remove_if(filenames.begin(), filenames.end(),
+ [this](const base::FilePath& path) {
+ return CallDirectoryExistsOnUIThread(path);
+ }),
+ filenames.end());
+ if (filenames.empty()) {
FileNotSelected(dialog);
return;
}
- MultiFilesSelected(dialog, filenames_fp);
+ MultiFilesSelected(dialog, filenames);
}
void SelectFileDialogImplGTK::OnFileChooserDestroy(GtkWidget* dialog) {
@@ -558,6 +622,7 @@ void SelectFileDialogImplGTK::OnFileChooserDestroy(GtkWidget* dialog) {
}
}
+#if !GTK_CHECK_VERSION(3, 90, 0)
void SelectFileDialogImplGTK::OnUpdatePreview(GtkWidget* chooser) {
gchar* filename =
gtk_file_chooser_get_preview_filename(GTK_FILE_CHOOSER(chooser));
@@ -588,5 +653,6 @@ void SelectFileDialogImplGTK::OnUpdatePreview(GtkWidget* chooser) {
gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(chooser),
pixbuf ? TRUE : FALSE);
}
+#endif
} // namespace gtk
diff --git a/chromium/ui/gtk/select_file_dialog_impl_gtk.h b/chromium/ui/gtk/select_file_dialog_impl_gtk.h
index ca73d9cc04b..74966c1dd25 100644
--- a/chromium/ui/gtk/select_file_dialog_impl_gtk.h
+++ b/chromium/ui/gtk/select_file_dialog_impl_gtk.h
@@ -122,17 +122,22 @@ class SelectFileDialogImplGTK : public SelectFileDialogImpl,
OnFileChooserDestroy,
GtkWidget*);
+#if !GTK_CHECK_VERSION(3, 90, 0)
// Callback for when we update the preview for the selection.
CHROMEG_CALLBACK_0(SelectFileDialogImplGTK,
void,
OnUpdatePreview,
GtkWidget*);
+#endif
// A map from dialog windows to the |params| user data associated with them.
std::map<GtkWidget*, void*> params_map_;
+ // GTK4 provides its own preview.
+#if !GTK_CHECK_VERSION(3, 90, 0)
// The GtkImage widget for showing previews of selected images.
- GtkWidget* preview_;
+ GtkWidget* preview_ = nullptr;
+#endif
// All our dialogs.
std::set<GtkWidget*> dialogs_;
diff --git a/chromium/ui/gtk/settings_provider_gsettings.cc b/chromium/ui/gtk/settings_provider_gsettings.cc
index 980b859ead0..1430b5b66d1 100644
--- a/chromium/ui/gtk/settings_provider_gsettings.cc
+++ b/chromium/ui/gtk/settings_provider_gsettings.cc
@@ -51,7 +51,8 @@ SettingsProviderGSettings::SettingsProviderGSettings(GtkUi* delegate)
g_settings_schema_source_get_default(), settings_schema, FALSE);
if (!button_schema ||
!g_settings_schema_has_key(button_schema, kButtonLayoutKey) ||
- !(button_settings_ = g_settings_new(settings_schema))) {
+ !(button_settings_ =
+ ScopedGObject<GSettings>(g_settings_new(settings_schema)))) {
ParseAndStoreButtonValue(kDefaultButtonString);
} else {
// Get the inital value of the keys we're interested in.
@@ -66,7 +67,8 @@ SettingsProviderGSettings::SettingsProviderGSettings(GtkUi* delegate)
// If this fails, the default action has already been set in gtk_ui.cc.
if (click_schema &&
g_settings_schema_has_key(click_schema, kMiddleClickActionKey) &&
- (click_settings_ = g_settings_new(kGnomePreferencesSchema))) {
+ (click_settings_ =
+ ScopedGObject<GSettings>(g_settings_new(kGnomePreferencesSchema)))) {
OnMiddleClickActionChanged(click_settings_, kMiddleClickActionKey);
signal_middle_click_id_ =
g_signal_connect(click_settings_, kMiddleClickActionChangedSignal,
@@ -75,16 +77,10 @@ SettingsProviderGSettings::SettingsProviderGSettings(GtkUi* delegate)
}
SettingsProviderGSettings::~SettingsProviderGSettings() {
- if (button_settings_) {
- if (signal_button_id_)
- g_signal_handler_disconnect(button_settings_, signal_button_id_);
- g_free(button_settings_);
- }
- if (click_settings_) {
- if (signal_middle_click_id_)
- g_signal_handler_disconnect(click_settings_, signal_middle_click_id_);
- g_free(click_settings_);
- }
+ if (signal_button_id_)
+ g_signal_handler_disconnect(button_settings_, signal_button_id_);
+ if (signal_middle_click_id_)
+ g_signal_handler_disconnect(click_settings_, signal_middle_click_id_);
}
// Private:
diff --git a/chromium/ui/gtk/settings_provider_gsettings.h b/chromium/ui/gtk/settings_provider_gsettings.h
index 9ef220a8511..4387dc22cca 100644
--- a/chromium/ui/gtk/settings_provider_gsettings.h
+++ b/chromium/ui/gtk/settings_provider_gsettings.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "ui/base/glib/glib_signal.h"
+#include "ui/base/glib/scoped_gobject.h"
#include "ui/gtk/settings_provider.h"
namespace gtk {
@@ -44,8 +45,8 @@ class SettingsProviderGSettings : public SettingsProvider {
GtkUi* delegate_;
- GSettings* button_settings_ = nullptr;
- GSettings* click_settings_ = nullptr;
+ ScopedGObject<GSettings> button_settings_;
+ ScopedGObject<GSettings> click_settings_;
gulong signal_button_id_;
gulong signal_middle_click_id_;
diff --git a/chromium/ui/gtk/x/gtk_event_loop_x11.cc b/chromium/ui/gtk/x/gtk_event_loop_x11.cc
index 1fcd117d71b..bfef18dc6b5 100644
--- a/chromium/ui/gtk/x/gtk_event_loop_x11.cc
+++ b/chromium/ui/gtk/x/gtk_event_loop_x11.cc
@@ -4,26 +4,80 @@
#include "ui/gtk/x/gtk_event_loop_x11.h"
-#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <xcb/xcb.h>
#include <xcb/xproto.h>
#include "base/memory/singleton.h"
#include "ui/base/x/x11_util.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/event.h"
extern "C" {
+#if GTK_CHECK_VERSION(3, 90, 0)
+unsigned long gdk_x11_surface_get_xid(GdkSurface* surface);
+#else
unsigned long gdk_x11_window_get_xid(GdkWindow* window);
+#endif
}
namespace ui {
namespace {
-int BuildXkbStateFromGdkEvent(unsigned int state, unsigned char group) {
- return state | ((group & 0x3) << 13);
+x11::KeyButMask BuildXkbStateFromGdkEvent(unsigned int state,
+ unsigned char group) {
+ return static_cast<x11::KeyButMask>(state | ((group & 0x3) << 13));
+}
+
+x11::KeyEvent ConvertGdkEventToKeyEvent(GdkEvent* gdk_event) {
+#if GTK_CHECK_VERSION(3, 90, 0)
+ GdkKeymapKey* keys = nullptr;
+ guint* keyvals = nullptr;
+ gint n_entries = 0;
+ gdk_display_map_keycode(gdk_display_get_default(),
+ gdk_key_event_get_keycode(gdk_event), &keys, &keyvals,
+ &n_entries);
+ guint keyval = gdk_key_event_get_keyval(gdk_event);
+ GdkKeymapKey keymap_key{0, 0, 0};
+ if (keys) {
+ for (gint i = 0; i < n_entries; i++) {
+ if (keyvals[i] == keyval) {
+ keymap_key = keys[i];
+ break;
+ }
+ }
+ g_free(keys);
+ g_free(keyvals);
+ }
+
+ return {
+ .opcode = gdk_event_get_event_type(gdk_event) == GDK_KEY_PRESS
+ ? x11::KeyEvent::Press
+ : x11::KeyEvent::Release,
+ .detail = static_cast<x11::KeyCode>(keymap_key.keycode),
+ .time = static_cast<x11::Time>(gdk_event_get_time(gdk_event)),
+ .root = ui::GetX11RootWindow(),
+ .event = static_cast<x11::Window>(
+ gdk_x11_surface_get_xid(gdk_event_get_surface(gdk_event))),
+ .state = BuildXkbStateFromGdkEvent(
+ gdk_event_get_modifier_state(gdk_event), keymap_key.group),
+ .same_screen = true,
+ };
+#else
+ return {
+ .opcode = gdk_event->key.type == GDK_KEY_PRESS ? x11::KeyEvent::Press
+ : x11::KeyEvent::Release,
+ .send_event = gdk_event->key.send_event,
+ .detail = static_cast<x11::KeyCode>(gdk_event->key.hardware_keycode),
+ .time = static_cast<x11::Time>(gdk_event->key.time),
+ .root = ui::GetX11RootWindow(),
+ .event = static_cast<x11::Window>(
+ gdk_x11_window_get_xid(gdk_event->key.window)),
+ .state =
+ BuildXkbStateFromGdkEvent(gdk_event->key.state, gdk_event->key.group),
+ .same_screen = true,
+ };
+#endif
}
} // namespace
@@ -44,10 +98,15 @@ GtkEventLoopX11::~GtkEventLoopX11() {
// static
void GtkEventLoopX11::DispatchGdkEvent(GdkEvent* gdk_event, gpointer) {
- switch (gdk_event->type) {
+#if GTK_CHECK_VERSION(3, 90, 0)
+ auto event_type = gdk_event_get_event_type(gdk_event);
+#else
+ auto event_type = gdk_event->type;
+#endif
+ switch (event_type) {
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
- ProcessGdkEventKey(gdk_event->key);
+ ProcessGdkEventKey(gdk_event);
break;
default:
break; // Do nothing.
@@ -57,7 +116,7 @@ void GtkEventLoopX11::DispatchGdkEvent(GdkEvent* gdk_event, gpointer) {
}
// static
-void GtkEventLoopX11::ProcessGdkEventKey(const GdkEventKey& gdk_event_key) {
+void GtkEventLoopX11::ProcessGdkEventKey(GdkEvent* gdk_event) {
// This function translates GdkEventKeys into XKeyEvents and puts them to
// the X event queue.
//
@@ -72,37 +131,10 @@ void GtkEventLoopX11::ProcessGdkEventKey(const GdkEventKey& gdk_event_key) {
// corresponding key event in the X event queue. So we have to handle this
// case. ibus-gtk is used through gtk-immodule to support IMEs.
- auto* conn = x11::Connection::Get();
-
- x11::KeyEvent key{
- .opcode = gdk_event_key.type == GDK_KEY_PRESS ? x11::KeyEvent::Press
- : x11::KeyEvent::Release,
- .send_event = gdk_event_key.send_event,
- .detail = static_cast<x11::KeyCode>(gdk_event_key.hardware_keycode),
- .time = static_cast<x11::Time>(gdk_event_key.time),
- .root = ui::GetX11RootWindow(),
- .event = static_cast<x11::Window>(
- gdk_x11_window_get_xid(gdk_event_key.window)),
- .same_screen = true,
- };
- x11::Event event(key, false);
-
- // The key state is 16 bits on the wire, but ibus-gtk adds additional flags
- // that may be outside this range, so set the state after conversion from
- // the wire format.
- // TODO(https://crbug.com/1066670): Add a test to ensure this subtle logic
- // doesn't regress after all X11 event code is refactored from using Xlib to
- // XProto.
- int state =
- BuildXkbStateFromGdkEvent(gdk_event_key.state, gdk_event_key.group);
- event.As<x11::KeyEvent>()->state = static_cast<x11::KeyButMask>(state);
-
// We want to process the gtk event; mapped to an X11 event immediately
// otherwise if we put it back on the queue we may get items out of order.
- if (ui::X11EventSource* x11_source = ui::X11EventSource::GetInstance())
- x11_source->DispatchXEvent(&event);
- else
- conn->events().push_front(std::move(event));
+ x11::Connection::Get()->DispatchEvent(
+ x11::Event{ConvertGdkEventToKeyEvent(gdk_event)});
}
} // namespace ui
diff --git a/chromium/ui/gtk/x/gtk_event_loop_x11.h b/chromium/ui/gtk/x/gtk_event_loop_x11.h
index 7ea72051d36..baa53a5b823 100644
--- a/chromium/ui/gtk/x/gtk_event_loop_x11.h
+++ b/chromium/ui/gtk/x/gtk_event_loop_x11.h
@@ -5,11 +5,9 @@
#ifndef UI_GTK_X_GTK_EVENT_LOOP_X11_H_
#define UI_GTK_X_GTK_EVENT_LOOP_X11_H_
-#include "base/macros.h"
-#include "ui/base/glib/glib_integers.h"
+#include <gdk/gdk.h>
-using GdkEvent = union _GdkEvent;
-using GdkEventKey = struct _GdkEventKey;
+#include "ui/base/glib/glib_integers.h"
namespace base {
template <typename Type>
@@ -22,16 +20,17 @@ class GtkEventLoopX11 {
public:
static GtkEventLoopX11* EnsureInstance();
+ GtkEventLoopX11(const GtkEventLoopX11&) = delete;
+ GtkEventLoopX11& operator=(const GtkEventLoopX11&) = delete;
+
private:
friend struct base::DefaultSingletonTraits<GtkEventLoopX11>;
GtkEventLoopX11();
- GtkEventLoopX11(const GtkEventLoopX11&) = delete;
- GtkEventLoopX11& operator=(const GtkEventLoopX11&) = delete;
~GtkEventLoopX11();
static void DispatchGdkEvent(GdkEvent* gdk_event, gpointer);
- static void ProcessGdkEventKey(const GdkEventKey& gdk_event_key);
+ static void ProcessGdkEventKey(GdkEvent* gdk_event);
};
} // namespace ui
diff --git a/chromium/ui/gtk/x/gtk_ui_delegate_x11.cc b/chromium/ui/gtk/x/gtk_ui_delegate_x11.cc
index 7aa7e78d010..2160c8543b8 100644
--- a/chromium/ui/gtk/x/gtk_ui_delegate_x11.cc
+++ b/chromium/ui/gtk/x/gtk_ui_delegate_x11.cc
@@ -7,11 +7,13 @@
#include <gtk/gtk.h>
#include "base/check.h"
+#include "base/environment.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/x/xlib_support.h"
#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_util.h"
#include "ui/gtk/x/gtk_event_loop_x11.h"
#include "ui/platform_window/x11/x11_window.h"
#include "ui/platform_window/x11/x11_window_manager.h"
@@ -32,6 +34,9 @@ GtkUiDelegateX11::GtkUiDelegateX11(x11::Connection* connection)
: connection_(connection) {
DCHECK(connection_);
gdk_set_allowed_backends("x11");
+ // GDK_BACKEND takes precedence over gdk_set_allowed_backends(), so override
+ // it to ensure we get the x11 backend.
+ base::Environment::Create()->SetVar("GDK_BACKEND", "x11");
x11::InitXlib();
}
@@ -99,4 +104,16 @@ void GtkUiDelegateX11::ShowGtkWindow(GtkWindow* window) {
static_cast<uint32_t>(X11EventSource::GetInstance()->GetTimestamp()));
}
+int GtkUiDelegateX11::GetGdkKeyState() {
+ auto* xevent =
+ X11EventSource::GetInstance()->connection()->dispatching_event();
+
+ if (!xevent)
+ return ui::EF_NONE;
+
+ auto* key_xevent = xevent->As<x11::KeyEvent>();
+ DCHECK(key_xevent);
+ return static_cast<int>(key_xevent->state);
+}
+
} // namespace ui
diff --git a/chromium/ui/gtk/x/gtk_ui_delegate_x11.h b/chromium/ui/gtk/x/gtk_ui_delegate_x11.h
index 730af74ed73..e92f9a3c886 100644
--- a/chromium/ui/gtk/x/gtk_ui_delegate_x11.h
+++ b/chromium/ui/gtk/x/gtk_ui_delegate_x11.h
@@ -34,6 +34,7 @@ class COMPONENT_EXPORT(UI_GTK_X) GtkUiDelegateX11 : public GtkUiDelegate {
gfx::AcceleratedWidget parent) override;
void ClearTransientFor(gfx::AcceleratedWidget parent) override;
void ShowGtkWindow(GtkWindow* window) override;
+ int GetGdkKeyState() override;
private:
GdkDisplay* GetGdkDisplay();
diff --git a/chromium/ui/latency/DIR_METADATA b/chromium/ui/latency/DIR_METADATA
new file mode 100644
index 00000000000..e80036e6c93
--- /dev/null
+++ b/chromium/ui/latency/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Speed>Metrics"
+}
diff --git a/chromium/ui/latency/OWNERS b/chromium/ui/latency/OWNERS
index b72d1d8258a..554e4fe9e9e 100644
--- a/chromium/ui/latency/OWNERS
+++ b/chromium/ui/latency/OWNERS
@@ -1,6 +1,3 @@
# latency info
sadrul@chromium.org
-tdresser@chromium.org
-nzolghadr@chromium.org
-
-# COMPONENT: Speed>Metrics
+flackr@chromium.org
diff --git a/chromium/ui/latency/ipc/DIR_METADATA b/chromium/ui/latency/ipc/DIR_METADATA
new file mode 100644
index 00000000000..f31293e3139
--- /dev/null
+++ b/chromium/ui/latency/ipc/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI"
+}
diff --git a/chromium/ui/latency/ipc/OWNERS b/chromium/ui/latency/ipc/OWNERS
index 38a3112a952..1c4a39b0307 100644
--- a/chromium/ui/latency/ipc/OWNERS
+++ b/chromium/ui/latency/ipc/OWNERS
@@ -6,5 +6,3 @@ per-file BUILD.gn=*
# The following lines are redundant, they're just to silence the presubmit
per-file *_param_traits*.*=set noparent
per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS
-
-# COMPONENT: UI
diff --git a/chromium/ui/latency/latency_info.cc b/chromium/ui/latency/latency_info.cc
index f369ec6df9f..e0811de9f03 100644
--- a/chromium/ui/latency/latency_info.cc
+++ b/chromium/ui/latency/latency_info.cc
@@ -274,7 +274,8 @@ void LatencyInfo::AddLatencyNumberWithTimestampImpl(
ts = base::TimeTicks::Now();
}
- TRACE_EVENT_BEGIN(kTraceCategoriesForAsyncEvents, trace_name_str,
+ TRACE_EVENT_BEGIN(kTraceCategoriesForAsyncEvents,
+ perfetto::StaticString{trace_name_str},
perfetto::Track::Global(trace_id_), ts);
}
diff --git a/chromium/ui/latency/latency_info.dot b/chromium/ui/latency/latency_info.dot
index 887d4e9eae4..e5ee68f8b2f 100644
--- a/chromium/ui/latency/latency_info.dot
+++ b/chromium/ui/latency/latency_info.dot
@@ -17,7 +17,6 @@ Event.Latency.EndToEnd.TouchpadPinch\n"];
[label="\
Event.Latency.<scroll_name>.TimeToScrollUpdateSwapBegin2\n\
Event.Latency.<scroll_name>.<input_modality>.TimeToScrollUpdateSwapBegin4\n\
-Event.Latency.Scroll.Wheel.TimeToScrollUpdateSwapBegin2\n\
UKM: Event.<scroll_name>.<input_modality>.TimeToScrollUpdateSwapBegin\n"]
scroll_to_schedule_metrics
[label="\
diff --git a/chromium/ui/latency/latency_tracker.cc b/chromium/ui/latency/latency_tracker.cc
index 7f059ff7672..0f89e2cf3d6 100644
--- a/chromium/ui/latency/latency_tracker.cc
+++ b/chromium/ui/latency/latency_tracker.cc
@@ -50,19 +50,6 @@ bool IsInertialScroll(const LatencyInfo& latency) {
return latency.source_event_type() == ui::SourceEventType::INERTIAL;
}
-// This UMA metric tracks the time from when the original wheel event is created
-// to when the scroll gesture results in final frame swap. All scroll events are
-// included in this metric.
-void RecordUmaEventLatencyScrollWheelTimeToScrollUpdateSwapBegin2Histogram(
- base::TimeTicks start,
- base::TimeTicks end) {
- CONFIRM_EVENT_TIMES_EXIST(start, end);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Event.Latency.Scroll.Wheel.TimeToScrollUpdateSwapBegin2",
- std::max(static_cast<int64_t>(0), (end - start).InMicroseconds()), 1,
- 1000000, 100);
-}
-
bool LatencyTraceIdCompare(const LatencyInfo& i, const LatencyInfo& j) {
return i.trace_id() < j.trace_id();
}
@@ -211,11 +198,6 @@ void LatencyTracker::ComputeEndToEndLatencyHistograms(
UMA_HISTOGRAM_INPUT_LATENCY_5_SECONDS_MAX_MICROSECONDS(
metric_name, original_timestamp, gpu_swap_begin_timestamp);
- if (input_modality == "Wheel") {
- RecordUmaEventLatencyScrollWheelTimeToScrollUpdateSwapBegin2Histogram(
- original_timestamp, gpu_swap_begin_timestamp);
- }
-
} else if (latency.FindLatency(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
&original_timestamp)) {
@@ -254,10 +236,6 @@ void LatencyTracker::ComputeEndToEndLatencyHistograms(
UMA_HISTOGRAM_INPUT_LATENCY_5_SECONDS_MAX_MICROSECONDS(
metric_name, original_timestamp, gpu_swap_begin_timestamp);
- if (input_modality == "Wheel") {
- RecordUmaEventLatencyScrollWheelTimeToScrollUpdateSwapBegin2Histogram(
- original_timestamp, gpu_swap_begin_timestamp);
- }
} else if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
&original_timestamp)) {
if (latency.source_event_type() == SourceEventType::KEY_PRESS) {
diff --git a/chromium/ui/login/BUILD.gn b/chromium/ui/login/BUILD.gn
index 3d66b879464..6acddfc8f3b 100644
--- a/chromium/ui/login/BUILD.gn
+++ b/chromium/ui/login/BUILD.gn
@@ -6,3 +6,6 @@ import("//third_party/closure_compiler/compile_js.gni")
js_library("display_manager_types") {
}
+
+js_library("login_ui_tools") {
+}
diff --git a/chromium/ui/login/DIR_METADATA b/chromium/ui/login/DIR_METADATA
new file mode 100644
index 00000000000..a4805830559
--- /dev/null
+++ b/chromium/ui/login/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI>Shell>OOBE"
+}
diff --git a/chromium/ui/login/OWNERS b/chromium/ui/login/OWNERS
index 6ecf4dab402..43c2ba77ae7 100644
--- a/chromium/ui/login/OWNERS
+++ b/chromium/ui/login/OWNERS
@@ -7,4 +7,3 @@ xiyuan@chromium.org
# (in CET)
antrim@chromium.org
rsorokin@chromium.org
-# COMPONENT: UI>Shell>OOBE
diff --git a/chromium/ui/login/account_picker/chromeos_screen_account_picker.css b/chromium/ui/login/account_picker/chromeos_screen_account_picker.css
deleted file mode 100644
index 258a6cad035..00000000000
--- a/chromium/ui/login/account_picker/chromeos_screen_account_picker.css
+++ /dev/null
@@ -1,150 +0,0 @@
-/* Copyright 2014 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-.account-picker.flying-pods #account-picker {
- transition: width 180ms ease, height 180ms ease;
-}
-
-#bubble,
-#bubble-persistent {
- margin-top: 16px;
- z-index: 1;
-}
-
-#signin-banner-container1 {
- height: 64px;
- max-width: 450px;
- position: absolute;
- z-index: 3;
-}
-
-#signin-banner-container2 {
- display: inline-block;
- position: relative;
-}
-
-html[dir=rtl] #signin-banner-container2 {
- left: -50%;
- right: auto;
-}
-
-#signin-banner {
- background-color: rgba(0, 0, 0, 0.75);
- border-radius: 4px;
- color: #FFF;
- display: none;
- font-family: "Roboto";
- font-size: 13px;
- position: relative;
- text-align: center;
-}
-
-html[dir=rtl] #signin-banner {
- left: auto;
- right: -50%;
-}
-
-#signin-banner.warning {
- -webkit-padding-start: 128px;
- background-color: transparent;
- color: rgb(215, 68, 57);
- font-size: 10px;
-}
-
-#signin-banner.warning::before {
- background-image: url(../../webui/resources/images/icon_error_outline.svg);
- background-size: 20px;
- content: '';
- height: 20px;
- left: 24px;
- position: absolute;
- transform: translateY(-50%);
- top: 50%;
- width: 20px;
-}
-
-html[dir=rtl] #signin-banner.warning::before {
- left: auto;
- right: 24px;
-}
-
-html[screen=user-adding] #signin-banner {
- background-color: rgba(0, 0, 0, 0.34);
- display: inline-block;
-}
-
-html[screen=user-adding] #signin-banner,
-html[screen=login] #signin-banner {
- padding: 20px 24px;
-}
-
-html[screen=user-adding] #signin-banner.warning,
-html[screen=login] #signin-banner.warning {
- -webkit-padding-start: 52px; /* 24 + 20(icon width) + 8 (icon padding). */
-}
-
-html[screen=login] #signin-banner,
-html[screen=lock] #signin-banner {
- display: inline-block;
- opacity: 0;
- visibility: hidden;
-}
-
-html[screen=login] #signin-banner.message-set,
-html[screen=lock] #signin-banner.message-set {
- opacity: 0.8;
- transition: opacity 1s;
- visibility: visible;
-}
-
-.small-pod-container {
- overflow: scroll;
- position: absolute;
-}
-
-.small-pod-container.images-loading {
- visibility: hidden;
-}
-
-.small-pod-container.show-overflow {
- overflow: visible;
-}
-
-.small-pod-container::-webkit-scrollbar {
- width: 0;
-}
-
-.small-pod-container.scroll::-webkit-scrollbar {
- width: 6px;
-}
-
-.small-pod-container.scroll::-webkit-scrollbar-thumb {
- background-color: rgba(255, 255, 255, .17);
- border-radius: 8px;
- display: none;
-}
-
-.small-pod-container.scroll:hover::-webkit-scrollbar-thumb {
- display: block;
-}
-
-.small-pod-container::-webkit-scrollbar-corner {
- background-color: transparent; /* Hides the default white box. */
-}
-
-.small-pod-container-mask {
- height: 112px;
- position: absolute;
- width: 100%;
- z-index: 2;
-}
-
-.small-pod-container-mask.images-loading {
- visibility: hidden;
-}
-
-.small-pod-container-mask.rotate {
- transform: rotate(180deg);
-}
diff --git a/chromium/ui/login/account_picker/chromeos_screen_account_picker.html b/chromium/ui/login/account_picker/chromeos_screen_account_picker.html
deleted file mode 100644
index cd9ba7fea45..00000000000
--- a/chromium/ui/login/account_picker/chromeos_screen_account_picker.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<div id="account-picker" class="step faded hidden" hidden>
- <div id="signin-banner-container1">
- <div id="signin-banner-container2">
- <div id="signin-banner">$i18n{signinBannerText}</div>
- </div>
- </div>
- <podrow id="pod-row" class="podrow images-loading"></podrow>
- <div id="pod-container" class="small-pod-container images-loading"></div>
- <div class="small-pod-container-mask images-loading"></div>
- <div class="small-pod-container-mask rotate images-loading"></div>
-</div>
diff --git a/chromium/ui/login/account_picker/chromeos_screen_account_picker.js b/chromium/ui/login/account_picker/chromeos_screen_account_picker.js
deleted file mode 100644
index 28f0d2f178f..00000000000
--- a/chromium/ui/login/account_picker/chromeos_screen_account_picker.js
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Account picker screen implementation.
- */
-
-login.createScreen('AccountPickerScreen', 'account-picker', function() {
- /**
- * Maximum number of offline login failures before online login.
- * @type {number}
- * @const
- */
- var MAX_LOGIN_ATTEMPTS_IN_POD = 3;
-
- /**
- * Time after which the sign-in error bubble should be hidden if it is
- * overlayed over the detachable base change warning bubble (to ensure that
- * the detachable base warning is not obscured indefinitely).
- * @const {number}
- */
- var SIGNIN_ERROR_OVER_DETACHABLE_BASE_WARNING_TIMEOUT_MS = 5000;
-
- return {
- EXTERNAL_API: [
- 'loadUsers',
- 'updateUserImage',
- 'setCapsLockState',
- 'removeUser',
- 'showBannerMessage',
- 'showUserPodCustomIcon',
- 'hideUserPodCustomIcon',
- 'setUserPodFingerprintIcon',
- 'removeUserPodFingerprintIcon',
- 'selectPodForDetachableBaseWarningBubble',
- 'setPinEnabledForUser',
- 'setAuthType',
- 'setTabletModeState',
- 'setDemoModeState',
- 'setPublicSessionDisplayName',
- 'setPublicSessionLocales',
- 'setPublicSessionKeyboardLayouts',
- 'setOverlayColors',
- 'togglePodBackground',
- ],
-
- preferredWidth_: 0,
- preferredHeight_: 0,
-
- // Whether this screen is shown for the first time.
- firstShown_: true,
-
- // Whether this screen is currently being shown.
- showing_: false,
-
- /** @override */
- decorate: function() {
- login.PodRow.decorate($('pod-row'));
- },
-
- /** @override */
- getPreferredSize: function() {
- return {width: this.preferredWidth_, height: this.preferredHeight_};
- },
-
- /** @override */
- onWindowResize: function() {
- $('pod-row').onWindowResize();
- },
-
- /**
- * Sets preferred size for account picker screen.
- */
- setPreferredSize: function(width, height) {
- this.preferredWidth_ = width;
- this.preferredHeight_ = height;
- },
-
- /**
- * Sets login screen overlay colors based on colors extracted from the
- * wallpaper.
- * @param {string} maskColor Color for the gradient mask.
- * @param {string} scrollColor Color for the small pods container.
- */
- setOverlayColors: function(maskColor, scrollColor) {
- $('pod-row').setOverlayColors(maskColor, scrollColor);
- },
-
- /**
- * Toggles the background behind user pods.
- * @param {boolean} showPodBackground Whether to add background behind user
- * pods.
- */
- togglePodBackground: function(showPodBackground) {
- $('pod-row').togglePodBackground(showPodBackground);
- },
-
- /* Cancel user adding if ESC was pressed.
- */
- cancel: function() {
- if (Oobe.getInstance().displayType == DISPLAY_TYPE.USER_ADDING)
- chrome.send('cancelUserAdding');
- },
-
- /**
- * Event handler that is invoked just after the frame is shown.
- * @param {string} data Screen init payload.
- */
- onAfterShow: function(data) {
- $('pod-row').handleAfterShow();
- },
-
- /**
- * Event handler that is invoked just before the frame is shown.
- * @param {string} data Screen init payload.
- */
- onBeforeShow: function(data) {
- this.showing_ = true;
-
- chrome.send('loginUIStateChanged', ['account-picker', true]);
-
- chrome.send('hideCaptivePortal');
- var podRow = $('pod-row');
- podRow.signinUIState = OOBE_UI_STATE.ACCOUNT_PICKER;
- podRow.handleBeforeShow();
-
- // In case of the preselected pod onShow will be called once pod
- // receives focus.
- if (!podRow.preselectedPod)
- this.onShow();
- },
-
- /**
- * Event handler invoked when the page is shown and ready.
- */
- onShow: function() {
- if (!this.showing_) {
- // This method may be called asynchronously when the pod row finishes
- // initializing. However, at that point, the screen may have been hidden
- // again already. If that happens, ignore the onShow() call.
- return;
- }
- chrome.send('getTabletModeState');
- chrome.send('getDemoModeState');
- if (!this.firstShown_)
- return;
- this.firstShown_ = false;
-
- // Ensure that login is actually visible.
- window.requestAnimationFrame(function() {
- chrome.send('accountPickerReady');
- chrome.send('loginVisible', ['account-picker']);
- });
- },
-
- /**
- * Event handler that is invoked just before the frame is hidden.
- */
- onBeforeHide: function() {
- $('pod-row').clearFocusedPod();
- $('bubble-persistent').hide();
- this.showing_ = false;
- chrome.send('loginUIStateChanged', ['account-picker', false]);
- var podRow = $('pod-row');
- podRow.signinUIState = OOBE_UI_STATE.HIDDEN;
- podRow.handleHide();
- },
-
- /**
- * Shows sign-in error bubble.
- * @param {number} loginAttempts Number of login attemps tried.
- * @param {HTMLElement} error Error to show in bubble.
- */
- showErrorBubble: function(loginAttempts, error) {
- var activatedPod = $('pod-row').activatedPod;
- if (!activatedPod) {
- $('bubble').showContentForElement($('pod-row'),
- cr.ui.Bubble.Attachment.RIGHT,
- error);
- return;
- }
- // Show web authentication if this is not a supervised user.
- if (loginAttempts > MAX_LOGIN_ATTEMPTS_IN_POD &&
- !activatedPod.user.supervisedUser) {
- chrome.send('maxIncorrectPasswordAttempts',
- [activatedPod.user.emailAddress]);
- activatedPod.showSigninUI();
- } else {
- if (loginAttempts == 1) {
- chrome.send('firstIncorrectPasswordAttempt',
- [activatedPod.user.emailAddress]);
- }
- // Update the pod row display if incorrect password.
- $('pod-row').setFocusedPodErrorDisplay(true);
-
- // If a warning that the detachable base is different than the one
- // previously used by the user is shown for the pod, make sure that the
- // sign-in error gets hidden reasonably soon.
- // If the detachable base was changed maliciously while the user was
- // away, the attacker might attempt to use the sign-in error but to
- // obscure the detachable base warning hoping that the user will miss it
- // when they get back to the device.
- var timeout = activatedPod.showingDetachableBaseWarningBubble() ?
- SIGNIN_ERROR_OVER_DETACHABLE_BASE_WARNING_TIMEOUT_MS :
- undefined;
- activatedPod.showBubble(error, {timeout: timeout});
- }
- },
-
- /**
- * Ensures that a user pod is selected and focused, and thus ready to show a
- * warning bubble for detachable base change. This is needed for two
- * reasons:
- * 1. The detachable base state is associated with a user, so a user pod
- * has to be selected in order to know for which user the detachable
- * base state should be considered (e.g. there might be two large user
- * pods in the account picker).
- * 2. The warning bubble is attached to the pod's auth element, which is
- * only shown if the pod is focused. The bubble anchor should be
- * visible in order to properly calculate the bubble position.
- */
- selectPodForDetachableBaseWarningBubble: function() {
- $('pod-row').maybePreselectPod();
- },
-
- /**
- * Shows a persistent bubble warning to the user that the current detachable
- * base is different than the one they were last using, and that it might
- * not be trusted.
- *
- * @param {string} username The username of the user under whose user pod
- * the warning should be displayed.
- * @param {HTMLElement} content The warning bubble content.
- */
- showDetachableBaseWarningBubble: function(username, content) {
- var podRow = $('pod-row');
- var pod = podRow.pods.find(pod => pod.user.username == username);
- if (pod)
- pod.showDetachableBaseWarningBubble(content);
- },
-
- /**
- * Hides the detachable base warning for the user.
- *
- * @param {string} username The username that identifies the user pod from
- * under which the detachable base warning bubble should be removed.
- */
- hideDetachableBaseWarningBubble: function(username) {
- var pod = $('pod-row').pods.find(pod => pod.user.username == username);
- if (pod)
- pod.hideDetachableBaseWarningBubble();
- },
-
- /**
- * Loads given users in pod row.
- * @param {array} users Array of user.
- */
- loadUsers: function(users) {
- $('pod-row').loadPods(users);
- },
-
- /**
- * Updates current image of a user.
- * @param {string} username User for which to update the image.
- */
- updateUserImage: function(username) {
- $('pod-row').updateUserImage(username);
- },
-
- /**
- * Updates Caps Lock state (for Caps Lock hint in password input field).
- * @param {boolean} enabled Whether Caps Lock is on.
- */
- setCapsLockState: function(enabled) {
- $('pod-row').classList.toggle('capslock-on', enabled);
- },
-
- /**
- * Remove given user from pod row if it is there.
- * @param {string} user name.
- */
- removeUser: function(username) {
- $('pod-row').removeUserPod(username);
- },
-
- /**
- * Displays a banner containing |message|. If the banner is already present
- * this function updates the message in the banner. This function is used
- * by the chrome.screenlockPrivate.showMessage API.
- * @param {string} message Text to be displayed or empty to hide the banner.
- * @param {boolean} isWarning True if the given message is a warning.
- */
- showBannerMessage: function(message, isWarning) {
- $('pod-row').showBannerMessage(message, isWarning);
- },
-
- /**
- * Shows a custom icon in the user pod of |username|. This function
- * is used by the chrome.screenlockPrivate API.
- * @param {string} username Username of pod to add button
- * @param {!{id: !string,
- * hardlockOnClick: boolean,
- * isTrialRun: boolean,
- * tooltip: ({text: string, autoshow: boolean} | undefined)}} icon
- * The icon parameters.
- */
- showUserPodCustomIcon: function(username, icon) {
- $('pod-row').showUserPodCustomIcon(username, icon);
- },
-
- /**
- * Hides the custom icon in the user pod of |username| added by
- * showUserPodCustomIcon(). This function is used by the
- * chrome.screenlockPrivate API.
- * @param {string} username Username of pod to remove button
- */
- hideUserPodCustomIcon: function(username) {
- $('pod-row').hideUserPodCustomIcon(username);
- },
-
- /**
- * Set a fingerprint icon in the user pod of |username|.
- * @param {string} username Username of the selected user
- * @param {number} state Fingerprint unlock state
- */
- setUserPodFingerprintIcon: function(username, state) {
- $('pod-row').setUserPodFingerprintIcon(username, state);
- },
-
- /**
- * Removes the fingerprint icon in the user pod of |username|.
- * @param {string} username Username of the selected user.
- */
- removeUserPodFingerprintIcon: function(username) {
- $('pod-row').removeUserPodFingerprintIcon(username);
- },
-
- /**
- * Sets the authentication type used to authenticate the user.
- * @param {string} username Username of selected user
- * @param {number} authType Authentication type, must be a valid value in
- * the AUTH_TYPE enum in chromeos_user_pod_row.js.
- * @param {string} value The initial value to use for authentication.
- */
- setAuthType: function(username, authType, value) {
- $('pod-row').setAuthType(username, authType, value);
- },
-
- /**
- * Sets the state of tablet mode.
- * @param {boolean} isTabletModeEnabled true if the mode is on.
- */
- setTabletModeState: function(isTabletModeEnabled) {
- $('pod-row').setTabletModeState(isTabletModeEnabled);
- },
-
- /**
- * Sets whether the device is in demo mode.
- * @param {boolean} isDeviceInDemoMode true if the device is in demo mode.
- */
- setDemoModeState: function(isDeviceInDemoMode) {
- $('pod-row').setDemoModeState(isDeviceInDemoMode);
- },
-
- /**
- * Enables or disables the pin keyboard for the given user. This may change
- * pin keyboard visibility.
- * @param {!string} user
- * @param {boolean} enabled
- */
- setPinEnabledForUser: function(user, enabled) {
- $('pod-row').setPinEnabled(user, enabled);
- },
-
- /**
- * Updates the display name shown on a public session pod.
- * @param {string} userID The user ID of the public session
- * @param {string} displayName The new display name
- */
- setPublicSessionDisplayName: function(userID, displayName) {
- $('pod-row').setPublicSessionDisplayName(userID, displayName);
- },
-
- /**
- * Updates the list of locales available for a public session.
- * @param {string} userID The user ID of the public session
- * @param {!Object} locales The list of available locales
- * @param {string} defaultLocale The locale to select by default
- * @param {boolean} multipleRecommendedLocales Whether |locales| contains
- * two or more recommended locales
- */
- setPublicSessionLocales: function(
- userID, locales, defaultLocale, multipleRecommendedLocales) {
- $('pod-row').setPublicSessionLocales(userID,
- locales,
- defaultLocale,
- multipleRecommendedLocales);
- },
-
- /**
- * Updates the list of available keyboard layouts for a public session pod.
- * @param {string} userID The user ID of the public session
- * @param {string} locale The locale to which this list of keyboard layouts
- * applies
- * @param {!Object} list List of available keyboard layouts
- */
- setPublicSessionKeyboardLayouts: function(userID, locale, list) {
- $('pod-row').setPublicSessionKeyboardLayouts(userID, locale, list);
- },
- };
-});
diff --git a/chromium/ui/login/account_picker/chromeos_user_pod_row.css b/chromium/ui/login/account_picker/chromeos_user_pod_row.css
deleted file mode 100644
index 0fb30ac8fdd..00000000000
--- a/chromium/ui/login/account_picker/chromeos_user_pod_row.css
+++ /dev/null
@@ -1,1218 +0,0 @@
-/* Copyright 2014 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * This is the stylesheet used by user pods row of account picker UI.
- */
-
-podrow {
- overflow: visible;
-}
-
-/* Hide the pod row while images are loading. */
-podrow.images-loading {
- visibility: hidden;
-}
-
-pin-keyboard {
- display: block;
-}
-
-.pod {
- -webkit-tap-highlight-color: transparent;
- border-radius: 2px;
- cursor: pointer;
- opacity: 0.54;
- outline: none;
- position: absolute;
- z-index: 0;
-}
-
-.account-picker.flying-pods .pod {
- transition: all 180ms;
-}
-
-.pod .pin-container {
- position: absolute;
- width: 234px;
- z-index: 3;
-}
-
-.pod .pin-container.pin-enabled {
- left: 36px;
- opacity: 1;
- top: 300px;
- transition: opacity 200ms ease-in-out 180ms;
- visibility: visible;
-}
-
-.pod .pin-container.pin-disabled {
- opacity: 0; /* Opacity is set to 1 after the pin element is loaded. */
- transition: none;
- visibility: hidden; /* Needed because pin-keyboard's offsetHeight is
- checked to determine if loaded. */
- z-index: -1;
-}
-
-.pod.faded {
- opacity: .75;
-}
-
-.pod.focused {
- cursor: default;
- opacity: 1;
- z-index: 1;
-}
-
-.pod.focused[auth-type='userClick'] {
- cursor: pointer;
-}
-
-.pod.hovered {
- opacity: 1;
-}
-
-.user-image-pane {
- height: 96px;
- left: 105px;
- position: absolute;
- top: 54px;
- transition: height 180ms ease-in-out,
- left 180ms ease-in-out,
- right 180ms ease-in-out,
- top 180ms ease-in-out,
- width 180ms ease-in-out;
- width: 96px;
- z-index: 3;
-}
-
-html[dir=rtl] .user-image-pane {
- left: auto;
- right: 105px;
-}
-
-.user-image-container {
- align-items: center;
- display: flex;
- height: 100%;
- justify-content: center;
- width: 100%;
-}
-
-.pod .user-image {
- border-radius: 50%;
- flex: none;
- height: 100%;
- width: 100%;
-}
-
-.pod .user-image.switch-image-animation {
- animation: switch-image 180ms;
-}
-
-.pod.hovered .user-image {
- display: none;
-}
-
-.pod.focused .user-image {
- display: none;
-}
-
-.pod .animated-image {
- display: none;
-}
-
-.pod.hovered .animated-image {
- display: block;
-}
-
-.pod.focused .animated-image {
- display: block;
-}
-
-.pod .badge-container {
- background: #FFF;
- border-radius: 50%;
- bottom: 0;
- display: none;
- height: 27px;
- position: absolute;
- right: 0;
- width: 27px;
-}
-
-.pod .badge-container iron-icon {
- --iron-icon-height: 25px;
- --iron-icon-width: 25px;
- display: none;
- padding: 0;
-}
-
-.pod.legacy-supervised .badge-container,
-.pod.legacy-supervised .legacy-supervised-badge {
- display: block;
-}
-
-/* TODO(noms): Refactor this out into a CrOS-specific file and simplify the
- style rule once it is included on CrOS only. crbug.com/397638 */
-html:not([screen=login-add-user]) .pod .user-image {
- max-height: 160px;
- max-width: 160px;
- position: absolute;
-}
-
-html:not([screen=login-add-user]) .pod.focused .user-image {
- opacity: 1;
-}
-
-.pod.multiprofiles-policy-applied .user-image {
- -webkit-filter: grayscale(100%);
-}
-
-.main-pane {
- z-index: 2;
-}
-
-.name-container {
- display: flex;
- position: absolute;
- top: 182px;
-}
-
-.pod.focused:not(.multiprofiles-policy-applied):not(.public-account) .auth-container {
- display: flex;
- height: 40px;
- left: 51px;
- position: absolute;
- top: 236px;
-/* On chromeos we extend the width to cover the padding on the user pods. This
- is so the submit button on chromeos can extend onto the padding as shown on
- mocks. */
-<if expr="not chromeos">
- width: 160px;
-</if>
-<if expr="chromeos">
- width: 204px;
-</if>
-}
-
-html[dir=rtl] .pod.focused:not(.multiprofiles-policy-applied):not(.public-account) .auth-container {
- left: auto;
- right: 51px;
-}
-
-.auth-container .submit-button[disabled] {
- opacity: 0.34;
-}
-
-.auth-container .submit-button {
- --cr-icon-button--icon-size: 20px;
- --cr-icon-button-size: 20px;
- --cr-icon-button-fill-color: white;
- margin: 15px 0 5px 0;
- opacity: 1;
-}
-
-.auth-container .custom-icon-shown .submit-button {
- margin: 11px 0 5px 0;
-}
-
-.name-container {
- transition: transform 180ms;
-}
-
-.pod.focused .name-container {
- display: flex;
-}
-
-.pod.focused.multiprofiles-policy-applied .name-container {
- display: flex;
-}
-
-.name {
- color: #FFFFFF;
- flex: auto;
- font: 24px Roboto;
- font-weight: 300; /* roboto-light */
- outline: none;
- overflow: hidden;
- text-align: center;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.auth-container,
-.password-entry-container,
-.reauth-hint-container {
- display: none;
-}
-
-.input-line {
- display: none;
- height: 1px;
- opacity: 0.34;
- position: absolute;
- stroke: #FFFFFF;
- stroke-width: 1px;
- top: 40px;
- width: 204px;
-}
-
-.input-present .input-line {
- opacity: 1;
-}
-
-.pod[is-active-directory] .reauth-warning {
- display: none;
-}
-
-.pod[auth-type='offlinePassword'].focused .password-entry-container,
-.pod[auth-type='forceOfflinePassword'].focused .password-entry-container,
-.pod[auth-type='offlinePassword'].focused .input-line,
-.pod[auth-type='forceOfflinePassword'].focused .input-line {
- display: flex;
- flex: auto;
-}
-
-.password-container {
- height: 34px;
- margin-top: 6px;
- width: 184px; /* Input line width - Submit button width */
-}
-
-.capslock-on .password-container {
- width: 164px; /* Input line width - Caps lock icon width */
-}
-
-.custom-icon-shown .password-container {
- -webkit-padding-start: 8px;
- height: 39px;
- margin-top: 1px;
- width: 149px; /* Input line width -
- (Submit button width + Custom icon width) */
-}
-
-.capslock-on .custom-icon-shown .password-container {
- width: 129px; /* Input line width -
- (Submit button width + Caps lock icon width +
- Custom icon width) */
-}
-
-.pod input[type='password'] {
- background-color: transparent;
- border: none;
- color: rgba(255, 255, 255, .67);
- font-family: "Roboto";
- font-size: 16px;
- height: 100%;
- letter-spacing: 6px;
- padding: 0;
- width: 100%;
-}
-
-.pod input[type='password']::-webkit-input-placeholder {
- color: rgba(255, 255, 255, .67);
- font-size: 13px;
- letter-spacing: 0;
-}
-
-.capslock-hint-container {
- display: none;
-}
-
-<if expr="chromeos">
-.capslock-on .capslock-hint-container {
- display: block;
- flex: none;
- height: 40px;
- position: relative;
- width: 20px;
-}
-</if>
-
-.capslock-hint {
- --iron-icon-height: 22px;
- --iron-icon-width: 22px;
- opacity: 0.34;
- padding: 13px 0 5px;
-}
-
-.custom-icon-shown .capslock-hint {
- padding: 12px 0 6px;
-}
-
-.input-present .capslock-hint {
- opacity: 1;
-}
-
-.password-label,
-.signin-transition-container {
- display: none;
-}
-
-.pod[auth-type='userClick']:not(.signing-in) .password-label,
-.pod[auth-type='userClick'].signing-in .signin-transition-container {
- color: grey;
- display: block;
- flex: auto;
- margin-top: 11px;
- outline: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.custom-icon {
- -webkit-margin-end: 0;
- -webkit-margin-start: auto;
- background-position: center;
- background-repeat: no-repeat;
- flex: none;
- height: 27px;
- margin: 8px 0;
- width: 27px;
-}
-
-.custom-icon.faded {
- transition: opacity 200ms ease-in-out, visibility 200ms ease-in-out;
-}
-
-.custom-icon-hardlocked {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED);
-}
-
-.custom-icon-hardlocked.icon-with-tooltip:hover {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_HOVER);
-}
-
-.custom-icon-hardlocked.interactive-custom-icon:active {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_PRESSED);
-}
-
-.custom-icon-locked {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_LOCKED);
-}
-
-.custom-icon-locked.icon-with-tooltip:hover {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_HOVER);
-}
-
-.custom-icon-locked.interactive-custom-icon:active {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_PRESSED);
-}
-
-.custom-icon-locked-to-be-activated {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED);
-}
-
-.custom-icon-locked-to-be-activated.icon-with-tooltip:hover {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_HOVER);
-}
-
-.custom-icon-locked-to-be-activated.interactive-custom-icon:active {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_PRESSED);
-}
-
-.custom-icon-locked-with-proximity-hint {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT);
-}
-
-.custom-icon-locked-with-proximity-hint.icon-with-tooltip:hover {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT_HOVER);
-}
-
-.custom-icon-locked-with-proximity-hint.interactive-custom-icon:active {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT_PRESSED);
-}
-
-.custom-icon-unlocked {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED);
-}
-
-.custom-icon-unlocked.icon-with-tooltip:hover {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_HOVER);
-}
-
-.custom-icon-unlocked.interactive-custom-icon:active {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_PRESSED);
-}
-
-/**
- * Preloads resources for custom icon. Without this, the resources will be
- * loaded when CSS properties using them are first applied, which has visible
- * delay and may cause a short white flash when the icon background changes.
- */
-.custom-icon::after {
- content:
- url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED)
- url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_HOVER)
- url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_PRESSED)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_HOVER)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_PRESSED)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_HOVER)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_PRESSED)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT_HOVER)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT_PRESSED)
- url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED)
- url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_HOVER)
- url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_PRESSED);
- display: none;
-}
-
-.custom-icon-spinner {
- animation: easy-unlock-spinner-animation 2s steps(45) infinite;
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_SPINNER);
-}
-
-@keyframes easy-unlock-spinner-animation {
- from { background-position: 0 }
- to { background-position: -1215px }
-}
-
-.interactive-custom-icon {
- cursor: pointer;
-}
-
-.pod[auth-type='onlineSignIn'] .custom-icon-container {
- display: none;
-}
-
-.fingerprint-icon-container,
-.custom-icon-container {
- display: flex;
- flex: none;
- flex-direction: column;
- height: 43px;
- width: 27px;
-}
-
-.pod[auth-type='onlineSignIn'] .reauth-hint-container {
- display: flex;
- justify-content: center;
- margin-top: 8px;
- width: 100%;
-}
-
-.reauth-hint-container .reauth-warning {
- -webkit-mask-image: url(../../../ui/webui/resources/images/warning.svg);
- -webkit-mask-position: center;
- -webkit-mask-repeat: no-repeat;
- -webkit-mask-size: 20px;
- background-color: #E67C73;
- width: 24px;
-}
-
-.reauth-hint-container .reauth-name-hint {
- align-self: center;
- color: #E67C73;
- font-size: 12px;
- outline: none;
- overflow: hidden;
- padding: 0 6px;
- text-align: center;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.user-type-icon-area {
- background-color: white;
- border-radius: 2px;
- position: absolute;
- top: 0;
-}
-
-.action-box-area {
- opacity: 0;
- outline: none;
- transition: opacity 100ms;
- z-index: 4;
-}
-
-.action-box-area:focus,
-.action-box-area.hovered,
-.action-box-area.active,
-.action-box-area.forced {
- opacity: 1;
-}
-
-.action-box-button {
- --cr-icon-button-icon-size: 24px;
- --cr-icon-button-size: 28px;
- margin-inline-end: 0;
- margin-inline-start: 8px;
- margin-top: 3px;
-}
-
-.action-box-button.ripple-circle {
- background: #FFF;
- border-radius: 50%;
- opacity: .08;
- position: absolute;
- transform: scale(0);
-}
-
-.action-box-area.active .action-box-button.ripple-circle {
- animation: ripple 360ms;
- transform: scale(1);
-}
-
-@keyframes ripple {
- 0% { transform: scale(0); }
- 30% { transform: scale(1); }
- 100% { transform: scale(1); }
-}
-
-.action-box-area .action-box-icon {
- /* overriden in chrome/browser/resources/user_manager/user_manager.css */
- display: none;
-}
-
-.user-image-gradient-area {
- /* overriden in chrome/browser/resources/user_manager/user_manager.css */
- display: none;
-}
-
-.user-type-icon-area {
- left: 0;
- z-index: 5;
-}
-
-html[dir=rtl] .user-type-icon-area {
- left: auto;
- right: 0;
-}
-
-.user-type-icon-image {
- height: 16px;
- margin: 5px;
- width: 16px;
-}
-
-.user-type-icon-area.legacySupervised .user-type-icon-image {
- background-image: url(../../webui/resources/images/supervisor_account.svg);
- background-size: 18px;
-}
-
-.user-type-icon-area.child .user-type-icon-image {
- background-image: url(../../webui/resources/images/account_child_invert.svg);
- background-size: 18px;
-}
-
-.user-type-icon-area.policy .user-type-icon-image {
- background-image: url(../../webui/resources/images/business.svg);
- background-size: 18px;
-}
-
-.user-type-icon-area.app .user-type-icon-image {
- background-image: url(chrome://theme/IDR_KIOSK_APP_USER_POD_ICON);
-}
-
-.fingerprint-icon-container.hidden {
- display: none;
-}
-
-.fingerprint-icon-container.default .fingerprint-icon-image {
- background-image: url(../../webui/resources/images/fingerprint_default.svg);
-}
-
-.fingerprint-icon-container.default:hover .fingerprint-icon-image {
- background-image: url(../../webui/resources/images/fingerprint_signin.svg);
-}
-
-.fingerprint-icon-container.signin .fingerprint-icon-image {
- background-image: url(../../webui/resources/images/fingerprint_signin.svg);
-}
-
-.fingerprint-icon-container.failed .fingerprint-icon-image {
- background-image: url(../../webui/resources/images/icon_error_outline.svg);
-}
-
-.action-box-menu {
- display: none;
- position: absolute;
- z-index: 6;
-}
-
-.action-box-area.active ~ .action-box-menu {
- -webkit-margin-start: 12px;
- animation: fade-in 180ms;
- background-color: rgba(0, 0, 0, 0.8);
- border-radius: 2px;
- display: flex;
- flex-direction: column;
- font-size: 13px;
- margin-top: 3px;
- width: 220px;
-}
-
-.action-box-area.active ~ .action-box-menu.left-edge-offset {
- left: 0 !important;
-}
-
-.action-box-area.active ~ .action-box-menu.right-edge-offset {
- right: 0 !important;
-}
-
-.action-box-area.active ~ .action-box-menu:not(.menu-moved-up) {
- top: 200px;
-}
-
-.action-box-area.active ~ .action-box-menu.menu-moved-up {
- bottom: 207px;
-}
-
-.action-box-area.menu-moved-up {
- transform: rotate(180deg);
-}
-
-.action-box-menu-title {
- color: #FFFFFF;
- display: flex;
- flex-direction: column;
- padding: 13px 14px 18px;
-}
-
-.action-box-menu-title:focus {
- outline-style: none;
-}
-
-.action-box-menu-title-name,
-.action-box-menu-title-email {
- flex: none;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.action-box-menu-title-name {
- padding-bottom: 7px;
-}
-
-.action-box-menu-title-email {
- opacity: 0.54;
-}
-
-.action-box-menu-remove {
- border-top: 0.17px solid rgba(255, 255, 255, .34);
- color: #7BAAF7;
- outline: none;
- padding: 18px 14px;
-}
-
-.action-box-menu-remove:focus {
- font-weight: bold;
-}
-
-.action-box-remove-user-warning {
- border-top: 0.17px solid rgba(255, 255, 255, .34);
- color: white;
- font-size: 13px;
- line-height: 18px;
- padding: 13px 14px 18px;
-}
-
-.action-box-remove-user-warning > div,
-.action-box-remove-user-warning > table {
- padding-bottom: 19px;
-}
-
-.action-box-remove-non-owner-user-warning-text span.email {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.total-count {
- font-weight: bold;
-}
-
-.action-box-remove-user-warning-table-nonsync {
- border-spacing: 0;
- width: 100%;
-}
-
-.action-box-remove-user-warning-table td {
- padding: 0;
-}
-
-.action-box-remove-user-warning-table-numbers {
- color: #757575;
- text-align: end;
-}
-
-/* Hide dialog elements not in a correct category. Only combinations currently
- in use are included here. */
-.pod.legacy-supervised .non-sync,
-.pod.legacy-supervised .action-box-remove-user-warning-text,
-.pod.legacy-supervised .action-box-remove-non-owner-user-warning-text,
-.pod:not(.legacy-supervised)
- .action-box-remove-legacy-supervised-user-warning-text,
-.pod.synced .non-sync {
- display: none;
-}
-
-.user-type-bubble {
- background-color: rgba(0, 0, 0, 0.9);
- border-radius: 4px;
- color: #FFF;
- font-family: "Roboto";
- font-size: 13px;
- left: 36px;
- opacity: 0;
- padding: 17px;
- position: absolute;
- top: 35px;
- transition: all 100ms;
- visibility: hidden;
- width: 200px;
- z-index: 7;
-}
-
-html[dir=rtl] .user-type-bubble {
- left: auto;
- right: 36px;
-}
-
-.bubble-shown,
-.user-type-icon-area.policy:hover ~ .user-type-bubble {
- opacity: 1;
- visibility: visible;
-}
-
-.user-type-bubble-header {
- font-weight: bold;
- margin-bottom: 14px;
- text-align: center;
-}
-
-/**** Public account user pod rules *******************************************/
-
-.public-account-expanded > div,
-.public-account-expanded .pod:not(.expanded) {
- opacity: 0; /* Cannot be replaced with display: none, otherwise the tab
- indexes of other elements in the pod row will be ignored. */
-}
-
-.pod.public-account.expanded {
- animation: fade-in 180ms;
- background-color: rgba(0, 0, 0, 0.56);
- border-radius: 2px;
- height: 324px;
- transition: none;
- width: 622px;
-}
-
-.expanded-pane {
- display: none;
-}
-
-.pod.public-account.expanded .expanded-pane {
- border-left: 0.17px solid rgba(255, 255, 255, .34);
- color: rgba(255, 255, 255, .87);
- display: block;
- font-family: "Roboto";
- font-size: 13px;
- height: 324px;
- left: 322px;
- overflow: hidden;
- position: absolute;
- top: 0;
- width: 300px;
- z-index: 1;
-}
-
-html[dir=rtl] .expanded-pane {
- float: left;
-}
-
-.expanded-pane-container {
- margin-left: 28px;
- margin-right: 28px;
-}
-
-.reminder {
- margin-top: 20px;
-}
-
-.language-and-input-section {
- display: none;
-}
-
-.pod.public-account.expanded.advanced .language-and-input-section {
- display: block;
- margin-left: 28px;
- margin-right: 28px;
- margin-top: 37px;
- opacity: 1;
-}
-
-.select-with-label {
- display: flex;
- flex-direction: column;
- margin-top: 20px;
-}
-
-.language-select-label,
-.keyboard-select-label {
- opacity: .34;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- width: 170px;
-}
-
-.select-container {
- height: 16px;
- margin-top: 5px;
- width: 178px;
-}
-
-.language-select,
-.keyboard-select {
- width: 100%;
-}
-
-.enter-button {
- flex: none;
-}
-
-.pod.public-account .full-name {
- display: none;
- left: 50%;
- position: absolute;
- top: 100%;
- z-index: 3;
-}
-
-html[dir=rtl] .pod.public-account .full-name {
- left: auto;
- right: 50%;
-}
-
-.pod.public-account .name-container:hover .full-name {
- animation: fade-in 180ms;
- background-color: rgba(0, 0, 0, 0.8);
- border-radius: 2px;
- color: rgba(255, 255, 255, .87);
- display: flex;
- font-size: 13px;
- padding: 8px;
-}
-
-.pod .public-account-info-container {
- display: none;
-}
-
-.pod.public-account .public-account-info-container {
- display: block;
- position: absolute;
- top: 230px;
-}
-
-.public-account-info-container .learn-more {
- --iron-icon-height: 12px;
- --iron-icon-width: 12px;
- display: block;
- opacity: .67;
- padding: 0;
- position: absolute;
-}
-
-.public-account-info-container .info {
- -webkit-padding-start: 8px;
- color: rgba(255, 255, 255, .67);
- font-family: "Roboto";
- font-size: 13px;
- overflow: hidden;
- position: absolute;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.pod.public-account .button-container {
- background: rgba(255, 255, 255, .17);
- border-radius: 50%;
- display: none;
- height: 40px;
- left: 133px;
- position: absolute;
- top: 59px;
- width: 40px;
-}
-
-html[dir=rtl] .pod.public-account .button-container {
- left: auto;
- right: 133px;
-}
-
-.pod.public-account .button-container.forced,
-.pod.public-account.hovered .button-container,
-.pod.public-account.focused .button-container {
- display: block;
-}
-
-.pod.public-account.expanded .button-container {
- display: none;
-}
-
-.public-account-submit-button {
- --cr-icon-button-fill-color: #FFF;
- --cr-icon-button-size: 40px;
- opacity: 1;
-}
-
-.monitoring-container {
- margin-top: 106px;
-}
-
-.advanced .monitoring-container {
- margin-top: 35px;
- transition: margin-top 180ms;
-}
-
-.monitoring-learn-more {
- color: #7BAAF7;
- text-decoration: none;
-}
-
-.monitoring-learn-more:focus,
-.language-and-input:focus {
- font-weight: bold;
- outline: none;
-}
-
-.monitoring-dialog-container .cr-dialog-shield {
- background: black;
- opacity: 0.5;
-}
-
-.monitoring-dialog-container .cr-dialog-buttons {
- display: none;
-}
-
-.monitoring-dialog-container .cr-dialog-frame {
- height: 170px;
- padding: 0px;
- position: relative;
- width: 430px;
-}
-
-.monitoring-dialog-container .cr-dialog-close {
- color: grey;
- height: 34px;
- position: absolute;
- top: 0px;
- width: 34px;
-}
-
-.monitoring-dialog-container .cr-dialog-title {
- font-size: 16px;
- font-weight: bold;
- left: 20px;
- position: absolute;
- top: 15px;
-}
-
-.monitoring-dialog-container .cr-dialog-text {
- color: grey;
- font-size: 13px;
- overflow: visible;
- position: absolute;
- top: 20px;
-}
-
-.monitoring-dialog-container .cr-dialog-item {
- -webkit-margin-start: 42px;
- display: list-item;
- margin-bottom: -6px;
-}
-
-.language-and-input-container {
- margin-top: 20px;
- flex: none;
-}
-
-.language-and-input {
- color: #7BAAF7;
- text-decoration: none;
-}
-
-.enter-button-container {
- background-color: #4285F4;
- border-radius: 50%;
- bottom: 28px;
- height: 40px;
- position: absolute;
- right: 28px;
- width: 40px;
-}
-
-html[dir=rtl] .enter-button-container {
- left: 28px;
- right: auto;
-}
-
-.language-and-input-dropdown {
- -webkit-margin-start: 6px;
- height: 16px;
- padding: 0;
- width: 16px;
-}
-
-/* Animations for the animated ellipsis: */
-.animated-ellipsis-component0 {
- animation: ellipsis-component0 1.5s infinite;
-}
-
-@keyframes ellipsis-component0 {
- 0% { opacity: 0; }
- 25% { opacity: 1; }
- 50% { opacity: 1; }
- 75% { opacity: 1; }
- 100% { opacity: 0; }
-}
-
-.animated-ellipsis-component1 {
- animation: ellipsis-component1 1.5s infinite;
-}
-
-@keyframes ellipsis-component1 {
- 0% { opacity: 0; }
- 25% { opacity: 0; }
- 50% { opacity: 1; }
- 75% { opacity: 1; }
- 100% { opacity: 0; }
-}
-
-.animated-ellipsis-component2 {
- animation: ellipsis-component2 1.5s infinite;
-}
-
-@keyframes ellipsis-component2 {
- 0% { opacity: 0; }
- 25% { opacity: 0; }
- 50% { opacity: 0; }
- 75% { opacity: 1; }
- 100% { opacity: 0; }
-}
-
-.large-pod {
- height: 346px;
- width: 306px;
-}
-
-.pod.pin-enabled .large-pod {
- height: 618px;
-}
-
-.pod.public-account.expanded .large-pod {
- left: 8px;
- position: absolute;
- top: 8px;
-}
-
-.small-pod {
- height: 74px;
- width: 304px;
-}
-
-.small-pod.extra-small {
- height: 60px;
- width: 282px;
-}
-
-.small-user-image-container {
- align-items: center;
- height: 74px;
- justify-content: center;
- position: absolute;
- transition: height 180ms ease-in-out,
- left 180ms ease-in-out,
- right 180ms ease-in-out,
- top 180ms ease-in-out,
- width 180ms ease-in-out;
- width: 74px;
-}
-
-.small-pod.extra-small .small-user-image-container {
- height: 60px;
- width: 60px;
-}
-
-.small-pod-name {
- color: #FFFFFF;
- flex: auto;
- font: 20px Roboto;
- font-weight: 300; /* roboto-light */
- height: 28px;
- left: 90px;
- opacity: 1;
- outline: none;
- overflow: hidden;
- padding: 23px 0;
- position: absolute;
- text-overflow: ellipsis;
- white-space: nowrap;
- width: 214px;
-}
-
-html[dir=rtl] .small-pod-name {
- left: auto;
- right: 90px;
-}
-
-.small-pod.extra-small .small-pod-name {
- left: 76px;
- padding: 16px 0;
- width: 190px;
-}
-
-html[dir=rtl] .small-pod.extra-small .small-pod-name {
- left: auto;
- right: 76px;
-}
-
-.pod-background {
- background-color: rgba(0, 0, 0, 0.9);
- border-radius: 4px;
- display: none;
- position: absolute;
-}
-
-.large-pod .pod-background {
- height: 378px;
- left: -16px;
- top: -16px;
- width: 338px;
-}
-
-.small-pod .pod-background {
- height: 90px;
- left: -8px;
- top: -8px;
- width: 320px;
-}
-
-.pod.show-pod-background:not(.expanded) .large-pod .pod-background,
-.pod.show-pod-background .small-pod:not(.extra-small) .pod-background {
- display: block;
-}
-
-@keyframes switch-image {
- from { transform: rotate3d(0, 1, 0, 90deg); }
- to { transform: none; }
-}
-
-@keyframes fade-in {
- from { opacity: 0; }
- to { opacity: 1; }
-}
diff --git a/chromium/ui/login/account_picker/chromeos_user_pod_row.js b/chromium/ui/login/account_picker/chromeos_user_pod_row.js
deleted file mode 100644
index 37c281c2f26..00000000000
--- a/chromium/ui/login/account_picker/chromeos_user_pod_row.js
+++ /dev/null
@@ -1,4741 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview User pod row implementation.
- */
-
-cr.define('login', function() {
- /**
- * Variables used for pod placement processing. Width and height should be
- * synced with computed CSS sizes of pods.
- */
- var CROS_POD_WIDTH = 306;
- var CROS_SMALL_POD_WIDTH = 304;
- var CROS_EXTRA_SMALL_POD_WIDTH = 282;
- var DESKTOP_POD_WIDTH = 180;
- var MD_DESKTOP_POD_WIDTH = 160;
- var PUBLIC_EXPANDED_WIDTH = 622;
- var CROS_POD_HEIGHT = 346;
- var CROS_SMALL_POD_HEIGHT = 74;
- var CROS_EXTRA_SMALL_POD_HEIGHT = 60;
- var DESKTOP_POD_HEIGHT = 226;
- var MD_DESKTOP_POD_HEIGHT = 200;
- var PUBLIC_EXPANDED_HEIGHT = 324;
- var POD_ROW_PADDING = 10;
- var DESKTOP_ROW_PADDING = 32;
- var CUSTOM_ICON_CONTAINER_SIZE = 40;
- var CROS_PIN_POD_HEIGHT = 417;
- var SCROLL_MASK_HEIGHT = 112;
- var CROS_POD_HEIGHT_WITH_PIN = 618;
- var PUBLIC_SESSION_ICON_WIDTH = 12;
- var CROS_POD_WARNING_BANNER_OFFSET_Y = 270;
-
- /**
- * The maximum number of users that each pod placement method can handle.
- */
- var POD_ROW_LIMIT = 2;
- var LANDSCAPE_MODE_LIMIT = 6;
- var PORTRAIT_MODE_LIMIT = 9;
-
- /**
- * Distance between the bubble and user pod.
- * @type {number}
- * @const
- */
- var BUBBLE_POD_OFFSET = 4;
-
- /**
- * Maximum time for which the pod row remains hidden until all user images
- * have been loaded.
- * @type {number}
- * @const
- */
- var POD_ROW_IMAGES_LOAD_TIMEOUT_MS = 3000;
-
- /**
- * The duration of the animation for switching between main pod and small
- * pod. It should be synced with CSS.
- * @type {number}
- * @const
- */
- var POD_SWITCH_ANIMATION_DURATION_MS = 180;
-
- /**
- * Tab order for user pods. Update these when adding new controls.
- * @enum {number}
- * @const
- */
- var UserPodTabOrder = {
- POD_INPUT: 1, // Password input field, action box menu button and
- // the pod itself.
- PIN_KEYBOARD: 2, // Pin keyboard below the password input field.
- POD_CUSTOM_ICON: 3, // Pod custom icon next to password input field.
- HEADER_BAR: 4, // Buttons on the header bar (Shutdown, Add User).
- POD_MENU_ITEM: 5 // User pod menu items (User info, Remove user).
- };
-
- /**
- * Supported authentication types. Keep in sync with the enum in
- * components/proximity_auth/public/interfaces/auth_type.mojom
- * @enum {number}
- * @const
- */
- var AUTH_TYPE = {
- OFFLINE_PASSWORD: 0,
- ONLINE_SIGN_IN: 1,
- USER_CLICK: 2,
- EXPAND_THEN_USER_CLICK: 3,
- FORCE_OFFLINE_PASSWORD: 4
- };
-
- /**
- * Names of authentication types.
- */
- var AUTH_TYPE_NAMES = {
- 0: 'offlinePassword',
- 1: 'onlineSignIn',
- 2: 'userClick',
- 3: 'expandThenUserClick',
- 4: 'forceOfflinePassword'
- };
-
- /**
- * Supported fingerprint unlock states.
- * @enum {number}
- * @const
- */
- var FINGERPRINT_STATES = {
- HIDDEN: 0,
- DEFAULT: 1,
- SIGNIN: 2,
- FAILED: 3,
- };
-
- /**
- * The fingerprint states to classes mapping.
- * {@code state} properties indicate current fingerprint unlock state.
- * {@code class} properties are CSS classes used to set the icons' background
- * and password placeholder color.
- * @const {Array<{type: !number, class: !string}>}
- */
- var FINGERPRINT_STATES_MAPPING = [
- {state: FINGERPRINT_STATES.HIDDEN, class: 'hidden'},
- {state: FINGERPRINT_STATES.DEFAULT, class: 'default'},
- {state: FINGERPRINT_STATES.SIGNIN, class: 'signin'},
- {state: FINGERPRINT_STATES.FAILED, class: 'failed'}
- ];
-
- // Supported multi-profile user behavior values.
- // Keep in sync with the enum in login_user_info.mojom
- var MULTI_PROFILE_USER_BEHAVIOR = {
- UNRESTRICTED: 0,
- PRIMARY_ONLY: 1,
- NOT_ALLOWED: 2,
- OWNER_PRIMARY_ONLY: 3
- };
-
- // Focus and tab order are organized as follows:
- //
- // (1) all user pods have tab index 1 so they are traversed first;
- // (2) when a user pod is activated, its tab index is set to -1, then its
- // main input field and action box menu button get focus;
- // (3) if pin keyboard is present, it has tab index 2 so it follows the
- // action box menu button;
- // (4) if user pod custom icon is interactive, it has tab index 3;
- // (5) buttons on the header bar have tab index 4;
- // (6) User pod menu items (if present) have tab index 5;
- // (7) lastly, focus jumps to the Status Area and back to user pods.
- //
- // 'Focus' event is handled by a capture handler for the whole document
- // and in some cases 'mousedown' event handlers are used instead of 'click'
- // handlers where it's necessary to prevent 'focus' event from being fired.
-
- /**
- * Helper function to remove a class from given element.
- * @param {!HTMLElement} el Element whose class list to change.
- * @param {string} cl Class to remove.
- */
- function removeClass(el, cl) {
- el.classList.remove(cl);
- }
-
- /**
- * Helper function to switch directions for right-to-left languages.
- * @param {!HTMLElement} el Element whose style needs to change.
- */
- function switchDirection(el) {
- var leftStyle = el.style.left;
- el.style.left = el.style.right;
- el.style.right = leftStyle;
- }
-
- /**
- * Creates a user pod.
- * @constructor
- * @extends {HTMLDivElement}
- */
- var UserPod = cr.ui.define(function() {
- var node = $('user-pod-template').cloneNode(true);
- node.removeAttribute('id');
- return node;
- });
-
- /**
- * The display style of user pods.
- * @enum {number}
- * @const
- */
- UserPod.Style = {
- LARGE: 0,
- SMALL: 1,
- EXTRA_SMALL: 2
- };
-
- /**
- * Stops event propagation from the any user pod child element.
- * @param {Event} e Event to handle.
- */
- function stopEventPropagation(e) {
- // Prevent default so that we don't trigger a 'focus' event.
- e.preventDefault();
- e.stopPropagation();
- }
-
- /**
- * Creates an element for custom icon shown in a user pod next to the input
- * field.
- * @constructor
- * @extends {HTMLDivElement}
- */
- var UserPodCustomIcon = cr.ui.define(function() {
- var node = document.createElement('div');
- node.classList.add('custom-icon-container');
- node.hidden = true;
-
- // Create the actual icon element and add it as a child to the container.
- var iconNode = document.createElement('div');
- iconNode.classList.add('custom-icon');
- node.appendChild(iconNode);
- return node;
- });
-
- /**
- * The supported user pod custom icons.
- * {@code id} properties should be in sync with values set by C++ side.
- * {@code class} properties are CSS classes used to set the icons' background.
- * @const {Array<{id: !string, class: !string}>}
- */
- UserPodCustomIcon.ICONS = [
- {id: 'locked', class: 'custom-icon-locked'},
- {id: 'locked-to-be-activated',
- class: 'custom-icon-locked-to-be-activated'},
- {id: 'locked-with-proximity-hint',
- class: 'custom-icon-locked-with-proximity-hint'},
- {id: 'unlocked', class: 'custom-icon-unlocked'},
- {id: 'hardlocked', class: 'custom-icon-hardlocked'},
- {id: 'spinner', class: 'custom-icon-spinner'}
- ];
-
- /**
- * The hover state for the icon. When user hovers over the icon, a tooltip
- * should be shown after a short delay. This enum is used to keep track of
- * the tooltip status related to hover state.
- * @enum {string}
- */
- UserPodCustomIcon.HoverState = {
- /** The user is not hovering over the icon. */
- NO_HOVER: 'no_hover',
-
- /** The user is hovering over the icon but the tooltip is not activated. */
- HOVER: 'hover',
-
- /**
- * User is hovering over the icon and the tooltip is activated due to the
- * hover state (which happens with delay after user starts hovering).
- */
- HOVER_TOOLTIP: 'hover_tooltip'
- };
-
- /**
- * If the icon has a tooltip that should be automatically shown, the tooltip
- * is shown even when there is no user action (i.e. user is not hovering over
- * the icon), after a short delay. The tooltip should be hidden after some
- * time. Note that the icon will not be considered autoshown if it was
- * previously shown as a result of the user action.
- * This enum is used to keep track of this state.
- * @enum {string}
- */
- UserPodCustomIcon.TooltipAutoshowState = {
- /** The tooltip should not be or was not automatically shown. */
- DISABLED: 'disabled',
-
- /**
- * The tooltip should be automatically shown, but the timeout for showing
- * the tooltip has not yet passed.
- */
- ENABLED: 'enabled',
-
- /** The tooltip was automatically shown. */
- ACTIVE : 'active'
- };
-
- UserPodCustomIcon.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- /**
- * The id of the icon being shown.
- * @type {string}
- * @private
- */
- iconId_: '',
-
- /**
- * A reference to the timeout for updating icon hover state. Non-null
- * only if there is an active timeout.
- * @type {?number}
- * @private
- */
- updateHoverStateTimeout_: null,
-
- /**
- * A reference to the timeout for updating icon tooltip autoshow state.
- * Non-null only if there is an active timeout.
- * @type {?number}
- * @private
- */
- updateTooltipAutoshowStateTimeout_: null,
-
- /**
- * Callback for click and 'Enter' key events that gets set if the icon is
- * interactive.
- * @type {?function()}
- * @private
- */
- actionHandler_: null,
-
- /**
- * The current tooltip state.
- * @type {{active: function(): boolean,
- * autoshow: !UserPodCustomIcon.TooltipAutoshowState,
- * hover: !UserPodCustomIcon.HoverState,
- * text: string}}
- * @private
- */
- tooltipState_: {
- /**
- * Utility method for determining whether the tooltip is active, either as
- * a result of hover state or being autoshown.
- * @return {boolean}
- */
- active: function() {
- return this.autoshow == UserPodCustomIcon.TooltipAutoshowState.ACTIVE ||
- this.hover == UserPodCustomIcon.HoverState.HOVER_TOOLTIP;
- },
-
- /**
- * @type {!UserPodCustomIcon.TooltipAutoshowState}
- */
- autoshow: UserPodCustomIcon.TooltipAutoshowState.DISABLED,
-
- /**
- * @type {!UserPodCustomIcon.HoverState}
- */
- hover: UserPodCustomIcon.HoverState.NO_HOVER,
-
- /**
- * The tooltip text.
- * @type {string}
- */
- text: ''
- },
-
- /** @override */
- decorate: function() {
- this.iconElement.addEventListener(
- 'mouseover',
- this.updateHoverState_.bind(this,
- UserPodCustomIcon.HoverState.HOVER));
- this.iconElement.addEventListener(
- 'mouseout',
- this.updateHoverState_.bind(this,
- UserPodCustomIcon.HoverState.NO_HOVER));
- this.iconElement.addEventListener('mousedown',
- this.handleMouseDown_.bind(this));
- this.iconElement.addEventListener('click',
- this.handleClick_.bind(this));
- this.iconElement.addEventListener('keydown',
- this.handleKeyDown_.bind(this));
-
- // When the icon is focused using mouse, there should be no outline shown.
- // Preventing default mousedown event accomplishes this.
- this.iconElement.addEventListener('mousedown', function(e) {
- e.preventDefault();
- });
- },
-
- /**
- * Getter for the icon element's div.
- * @return {HTMLDivElement}
- */
- get iconElement() {
- return this.querySelector('.custom-icon');
- },
-
- /**
- * Updates the icon element class list to properly represent the provided
- * icon.
- * @param {!string} id The id of the icon that should be shown. Should be
- * one of the ids listed in {@code UserPodCustomIcon.ICONS}.
- */
- setIcon: function(id) {
- this.iconId_ = id;
- UserPodCustomIcon.ICONS.forEach(function(icon) {
- this.iconElement.classList.toggle(icon.class, id == icon.id);
- }, this);
- },
-
- /**
- * Sets the ARIA label for the icon.
- * @param {!string} ariaLabel
- */
- setAriaLabel: function(ariaLabel) {
- this.iconElement.setAttribute('aria-label', ariaLabel);
- },
-
- /**
- * Shows the icon.
- */
- show: function() {
- // Show the icon if the current iconId is valid.
- var validIcon = false;
- UserPodCustomIcon.ICONS.forEach(function(icon) {
- validIcon = validIcon || this.iconId_ == icon.id;
- }, this);
- // Update password container width based on the visibility of the
- // custom icon container.
- var parentPod = this.getParentPod_();
- if (parentPod) {
- parentPod.passwordEntryContainerElement.classList.toggle(
- 'custom-icon-shown', validIcon);
- }
- this.hidden = !validIcon;
- },
-
- /**
- * Updates the icon tooltip. If {@code autoshow} parameter is set the
- * tooltip is immediatelly shown. If tooltip text is not set, the method
- * ensures the tooltip gets hidden. If tooltip is shown prior to this call,
- * it remains shown, but the tooltip text is updated.
- * @param {!{text: string, autoshow: boolean}} tooltip The tooltip
- * parameters.
- */
- setTooltip: function(tooltip) {
- this.iconElement.classList.toggle('icon-with-tooltip', !!tooltip.text);
-
- this.updateTooltipAutoshowState_(
- tooltip.autoshow ?
- UserPodCustomIcon.TooltipAutoshowState.ENABLED :
- UserPodCustomIcon.TooltipAutoshowState.DISABLED);
- this.tooltipState_.text = tooltip.text;
- this.updateTooltip_();
- },
-
- /**
- * Sets up icon tabIndex attribute and handler for click and 'Enter' key
- * down events.
- * @param {?function()} callback If icon should be interactive, the
- * function to get called on click and 'Enter' key down events. Should
- * be null to make the icon non interactive.
- */
- setInteractive: function(callback) {
- this.iconElement.classList.toggle('interactive-custom-icon', !!callback);
-
- // Update tabIndex property if needed.
- if (!!this.actionHandler_ != !!callback) {
- if (callback) {
- this.iconElement.setAttribute('tabIndex',
- UserPodTabOrder.POD_CUSTOM_ICON);
- } else {
- this.iconElement.removeAttribute('tabIndex');
- }
- }
-
- // Set the new action handler.
- this.actionHandler_ = callback;
- },
-
- /**
- * Hides the icon and cleans its state.
- */
- hide: function() {
- this.hideTooltip_();
- this.clearUpdateHoverStateTimeout_();
- this.clearUpdateTooltipAutoshowStateTimeout_();
- this.setInteractive(null);
- this.hidden = true;
- },
-
- /**
- * Clears timeout for showing a tooltip if one is set. Used to cancel
- * showing the tooltip when the user starts typing the password.
- */
- cancelDelayedTooltipShow: function() {
- this.updateTooltipAutoshowState_(
- UserPodCustomIcon.TooltipAutoshowState.DISABLED);
- this.clearUpdateHoverStateTimeout_();
- },
-
- /**
- * Handles mouse down event in the icon element.
- * @param {Event} e The mouse down event.
- * @private
- */
- handleMouseDown_: function(e) {
- this.updateHoverState_(UserPodCustomIcon.HoverState.NO_HOVER);
- this.updateTooltipAutoshowState_(
- UserPodCustomIcon.TooltipAutoshowState.DISABLED);
-
- // Stop the event propagation so in the case the click ends up on the
- // user pod (outside the custom icon) auth is not attempted.
- stopEventPropagation(e);
- },
-
- /**
- * Handles click event on the icon element. No-op if
- * {@code this.actionHandler_} is not set.
- * @param {Event} e The click event.
- * @private
- */
- handleClick_: function(e) {
- if (!this.actionHandler_)
- return;
- this.actionHandler_();
- stopEventPropagation(e);
- },
-
- /**
- * Handles key down event on the icon element. Only 'Enter' key is handled.
- * No-op if {@code this.actionHandler_} is not set.
- * @param {Event} e The key down event.
- * @private
- */
- handleKeyDown_: function(e) {
- if (!this.actionHandler_ || e.key != 'Enter')
- return;
- this.actionHandler_(e);
- stopEventPropagation(e);
- },
-
- /**
- * Changes the tooltip hover state and updates tooltip visibility if needed.
- * @param {!UserPodCustomIcon.HoverState} state
- * @private
- */
- updateHoverState_: function(state) {
- this.clearUpdateHoverStateTimeout_();
- this.sanitizeTooltipStateIfBubbleHidden_();
-
- if (state == UserPodCustomIcon.HoverState.HOVER) {
- if (this.tooltipState_.active()) {
- this.tooltipState_.hover = UserPodCustomIcon.HoverState.HOVER_TOOLTIP;
- } else {
- this.updateHoverStateSoon_(
- UserPodCustomIcon.HoverState.HOVER_TOOLTIP);
- }
- return;
- }
-
- if (state != UserPodCustomIcon.HoverState.NO_HOVER &&
- state != UserPodCustomIcon.HoverState.HOVER_TOOLTIP) {
- console.error('Invalid hover state ' + state);
- return;
- }
-
- this.tooltipState_.hover = state;
- this.updateTooltip_();
- },
-
- /**
- * Sets up a timeout for updating icon hover state.
- * @param {!UserPodCustomIcon.HoverState} state
- * @private
- */
- updateHoverStateSoon_: function(state) {
- if (this.updateHoverStateTimeout_)
- clearTimeout(this.updateHoverStateTimeout_);
- this.updateHoverStateTimeout_ =
- setTimeout(this.updateHoverState_.bind(this, state), 1000);
- },
-
- /**
- * Clears a timeout for updating icon hover state if there is one set.
- * @private
- */
- clearUpdateHoverStateTimeout_: function() {
- if (this.updateHoverStateTimeout_) {
- clearTimeout(this.updateHoverStateTimeout_);
- this.updateHoverStateTimeout_ = null;
- }
- },
-
- /**
- * Changes the tooltip autoshow state and changes tooltip visibility if
- * needed.
- * @param {!UserPodCustomIcon.TooltipAutoshowState} state
- * @private
- */
- updateTooltipAutoshowState_: function(state) {
- this.clearUpdateTooltipAutoshowStateTimeout_();
- this.sanitizeTooltipStateIfBubbleHidden_();
-
- if (state == UserPodCustomIcon.TooltipAutoshowState.DISABLED) {
- if (this.tooltipState_.autoshow != state) {
- this.tooltipState_.autoshow = state;
- this.updateTooltip_();
- }
- return;
- }
-
- if (this.tooltipState_.active()) {
- if (this.tooltipState_.autoshow !=
- UserPodCustomIcon.TooltipAutoshowState.ACTIVE) {
- this.tooltipState_.autoshow =
- UserPodCustomIcon.TooltipAutoshowState.DISABLED;
- } else {
- // If the tooltip is already automatically shown, the timeout for
- // removing it should be reset.
- this.updateTooltipAutoshowStateSoon_(
- UserPodCustomIcon.TooltipAutoshowState.DISABLED);
- }
- return;
- }
-
- if (state == UserPodCustomIcon.TooltipAutoshowState.ENABLED) {
- this.updateTooltipAutoshowStateSoon_(
- UserPodCustomIcon.TooltipAutoshowState.ACTIVE);
- } else if (state == UserPodCustomIcon.TooltipAutoshowState.ACTIVE) {
- this.updateTooltipAutoshowStateSoon_(
- UserPodCustomIcon.TooltipAutoshowState.DISABLED);
- }
-
- this.tooltipState_.autoshow = state;
- this.updateTooltip_();
- },
-
- /**
- * Sets up a timeout for updating tooltip autoshow state.
- * @param {!UserPodCustomIcon.TooltipAutoshowState} state
- * @private
- */
- updateTooltipAutoshowStateSoon_: function(state) {
- if (this.updateTooltipAutoshowStateTimeout_)
- clearTimeout(this.updateTooltupAutoshowStateTimeout_);
- var timeout =
- state == UserPodCustomIcon.TooltipAutoshowState.DISABLED ?
- 5000 : 1000;
- this.updateTooltipAutoshowStateTimeout_ =
- setTimeout(this.updateTooltipAutoshowState_.bind(this, state),
- timeout);
- },
-
- /**
- * Clears the timeout for updating tooltip autoshow state if one is set.
- * @private
- */
- clearUpdateTooltipAutoshowStateTimeout_: function() {
- if (this.updateTooltipAutoshowStateTimeout_) {
- clearTimeout(this.updateTooltipAutoshowStateTimeout_);
- this.updateTooltipAutoshowStateTimeout_ = null;
- }
- },
-
- /**
- * If tooltip bubble is hidden, this makes sure that hover and tooltip
- * autoshow states are not the ones that imply an active tooltip.
- * Used to handle a case where the tooltip bubble is hidden by an event that
- * does not update one of the states (e.g. click outside the pod will not
- * update tooltip autoshow state). Should be called before making
- * tooltip state updates.
- * @private
- */
- sanitizeTooltipStateIfBubbleHidden_: function() {
- if (!$('bubble').hidden)
- return;
-
- if (this.tooltipState_.hover ==
- UserPodCustomIcon.HoverState.HOVER_TOOLTIP &&
- this.tooltipState_.text) {
- this.tooltipState_.hover = UserPodCustomIcon.HoverState.NO_HOVER;
- this.clearUpdateHoverStateTimeout_();
- }
-
- if (this.tooltipState_.autoshow ==
- UserPodCustomIcon.TooltipAutoshowState.ACTIVE) {
- this.tooltipState_.autoshow =
- UserPodCustomIcon.TooltipAutoshowState.DISABLED;
- this.clearUpdateTooltipAutoshowStateTimeout_();
- }
- },
-
- /**
- * Returns whether the user pod to which the custom icon belongs is focused.
- * @return {boolean}
- * @private
- */
- isParentPodFocused_: function() {
- if ($('account-picker').hidden)
- return false;
- var parentPod = this.getParentPod_();
- return parentPod && parentPod.parentNode.isFocused(parentPod);
- },
-
- /**
- * Depending on {@code this.tooltipState_}, it updates tooltip visibility
- * and text.
- * @private
- */
- updateTooltip_: function() {
- var parentPod = this.getParentPod_();
- if (this.hidden || !parentPod ||
- parentPod.getPodStyle() != UserPod.Style.LARGE ||
- !this.isParentPodFocused_()) {
- return;
- }
-
- if (!this.tooltipState_.active() || !this.tooltipState_.text) {
- this.hideTooltip_();
- return;
- }
-
- // Show the tooltip bubble.
- var bubbleContent = document.createElement('div');
- bubbleContent.textContent = this.tooltipState_.text;
-
- parentPod.showBubble(bubbleContent);
- },
-
- /**
- * Hides the tooltip.
- * @private
- */
- hideTooltip_: function() {
- $('bubble').hideForElement(this);
- },
-
- /**
- * Gets the parent pod (may be null) of this custom icon.
- * @return {?HTMLDivElement}
- */
- getParentPod_: function() {
- var parentPod = this.parentNode;
- while (parentPod && !parentPod.classList.contains('pod'))
- parentPod = parentPod.parentNode;
- return parentPod;
- }
- };
-
- /**
- * Unique salt added to user image URLs to prevent caching. Dictionary with
- * user names as keys.
- * @type {Object}
- */
- UserPod.userImageSalt_ = {};
-
- UserPod.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- /**
- * Whether click on the pod can issue a user click auth attempt. The
- * attempt can be issued iff the pod was focused when the click
- * started (i.e. on mouse down event).
- * @type {boolean}
- * @private
- */
- userClickAuthAllowed_: false,
-
- /**
- * Whether the user has recently authenticated with fingerprint.
- * @type {boolean}
- * @private
- */
- fingerprintAuthenticated_: false,
-
- /**
- * True iff the pod can display the pin keyboard. The pin keyboard may not
- * always be displayed even if this is true, ie, if the virtual keyboard is
- * also being displayed.
- */
- pinEnabled: false,
-
- /**
- * If set, a function which hides a persistent detachable base warning
- * bubble. This will be set if a detachable base warning bubble is shown for
- * this pod.
- * @type {?function()}
- * @private
- */
- detachableBaseWarningBubbleHider_: null,
-
- /** @override */
- decorate: function() {
- this.tabIndex = UserPodTabOrder.POD_INPUT;
- this.actionBoxAreaElement.tabIndex = UserPodTabOrder.POD_INPUT;
-
- this.addEventListener('keydown', this.handlePodKeyDown_.bind(this));
- this.addEventListener('click', this.handleClickOnPod_.bind(this));
- this.addEventListener('mousedown', this.handlePodMouseDown_.bind(this));
-
- if (this.pinKeyboard) {
- this.pinKeyboard.passwordElement = this.passwordElement;
- this.pinKeyboard.addEventListener('pin-change',
- this.handleInputChanged_.bind(this));
- this.pinKeyboard.tabIndex = UserPodTabOrder.PIN_KEYBOARD;
- }
-
- this.actionBoxAreaElement.addEventListener('mousedown',
- stopEventPropagation);
- this.actionBoxAreaElement.addEventListener('click',
- this.handleActionAreaButtonClick_.bind(this));
- this.actionBoxAreaElement.addEventListener('keydown',
- this.handleActionAreaButtonKeyDown_.bind(this));
-
- this.actionBoxMenuTitleElement.addEventListener('keydown',
- this.handleMenuTitleElementKeyDown_.bind(this));
- this.actionBoxMenuTitleElement.addEventListener('blur',
- this.handleMenuTitleElementBlur_.bind(this));
-
- this.actionBoxMenuRemoveElement.addEventListener('click',
- this.handleRemoveCommandClick_.bind(this));
- this.actionBoxMenuRemoveElement.addEventListener('keydown',
- this.handleRemoveCommandKeyDown_.bind(this));
- this.actionBoxMenuRemoveElement.addEventListener('blur',
- this.handleRemoveCommandBlur_.bind(this));
- this.actionBoxRemoveUserWarningButtonElement.addEventListener('click',
- this.handleRemoveUserConfirmationClick_.bind(this));
- this.actionBoxRemoveUserWarningButtonElement.addEventListener('keydown',
- this.handleRemoveUserConfirmationKeyDown_.bind(this));
-
- if (this.fingerprintIconElement) {
- this.fingerprintIconElement.addEventListener(
- 'mouseover', this.handleFingerprintIconMouseOver_.bind(this));
- this.fingerprintIconElement.addEventListener(
- 'mouseout', this.handleFingerprintIconMouseOut_.bind(this));
- this.fingerprintIconElement.addEventListener(
- 'mousedown', stopEventPropagation);
- }
-
- var customIcon = this.customIconElement;
- customIcon.parentNode.replaceChild(new UserPodCustomIcon(), customIcon);
- },
-
- /**
- * Initializes the pod after its properties set and added to a pod row.
- */
- initialize: function() {
- this.passwordElement.addEventListener('keydown',
- this.parentNode.handleKeyDown.bind(this.parentNode));
- this.passwordElement.addEventListener('keypress',
- this.handlePasswordKeyPress_.bind(this));
- this.passwordElement.addEventListener('input',
- this.handleInputChanged_.bind(this));
-
- if (this.submitButton) {
- this.submitButton.addEventListener('click',
- this.handleSubmitButtonClick_.bind(this));
- }
-
- this.imageElement.addEventListener('load',
- this.parentNode.handlePodImageLoad.bind(this.parentNode, this));
-
- this.smallPodImageElement.addEventListener(
- 'load',
- this.parentNode.handlePodImageLoad.bind(this.parentNode, this));
-
- var initialAuthType = this.user.initialAuthType ||
- AUTH_TYPE.OFFLINE_PASSWORD;
- this.setAuthType(initialAuthType, null);
-
- if (this.user.isActiveDirectory)
- this.setAttribute('is-active-directory', '');
-
- this.userClickAuthAllowed_ = false;
- },
-
- /**
- * Whether the user pod is disabled.
- * @type {boolean}
- */
- disabled_: false,
- get disabled() {
- return this.disabled_;
- },
- set disabled(value) {
- this.disabled_ = value;
- this.querySelectorAll('button,input').forEach(function(element) {
- element.disabled = value
- });
-
- this.tabIndex = value ? -1 : UserPodTabOrder.POD_INPUT;
- this.actionBoxAreaElement.tabIndex =
- value ? -1 : UserPodTabOrder.POD_INPUT;
-
- // Special handling for submit button - the submit button should be
- // enabled only if there is the password value set.
- var submitButton = this.submitButton;
- if (submitButton)
- submitButton.disabled = value || !this.passwordElement.value;
- },
-
- /**
- * Resets tab order for pod elements to its initial state.
- */
- resetTabOrder: function() {
- // Note: the |mainInput| can be the pod itself.
- this.mainInput.tabIndex = -1;
- this.tabIndex = UserPodTabOrder.POD_INPUT;
- },
-
- /**
- * Handles keypress event (i.e. any textual input) on password input.
- * @param {Event} e Keypress Event object.
- * @private
- */
- handlePasswordKeyPress_: function(e) {
- // When tabbing from the system tray a tab key press is received. Suppress
- // this so as not to type a tab character into the password field.
- if (e.keyCode == 9) {
- e.preventDefault();
- return;
- }
- this.customIconElement.cancelDelayedTooltipShow();
- },
-
- /**
- * Handles a click event on submit button.
- * @param {Event} e Click event.
- */
- handleSubmitButtonClick_: function(e) {
- this.parentNode.setActivatedPod(this, e);
- },
-
- /**
- * Top edge margin number of pixels.
- * @type {?number}
- */
- set top(top) {
- this.style.top = cr.ui.toCssPx(top);
- },
-
- /**
- * Top edge margin number of pixels.
- */
- get top() {
- return parseInt(this.style.top);
- },
-
- /**
- * Left edge margin number of pixels.
- * @type {?number}
- */
- set left(left) {
- this.style.left = cr.ui.toCssPx(left);
- },
-
- /**
- * Left edge margin number of pixels.
- */
- get left() {
- return parseInt(this.style.left);
- },
-
- /**
- * Height number of pixels.
- */
- get height() {
- return this.offsetHeight;
- },
-
- /**
- * Gets image element.
- * @type {!HTMLImageElement}
- */
- get imageElement() {
- return this.querySelector('.user-image');
- },
-
- /**
- * Gets animated image element.
- * @type {!HTMLImageElement}
- */
- get animatedImageElement() {
- return this.querySelector('.user-image.animated-image');
- },
-
- /**
- * Gets name element.
- * @type {!HTMLDivElement}
- */
- get nameElement() {
- return this.querySelector('.name');
- },
-
- /**
- * Gets image element of the small pod.
- * @type {!HTMLImageElement}
- */
- get smallPodImageElement() {
- return this.querySelector('.user-image.small-pod-image');
- },
-
- /**
- * Gets animated image element.
- * @type {!HTMLImageElement}
- */
- get smallPodAnimatedImageElement() {
- return this.querySelector('.user-image.small-pod-image.animated-image');
- },
-
- /**
- * Gets name element of the small pod.
- * @type {!HTMLDivElement}
- */
- get smallPodNameElement() {
- return this.querySelector('.small-pod-name');
- },
-
- /**
- * Gets reauth name hint element.
- * @type {!HTMLDivElement}
- */
- get reauthNameHintElement() {
- return this.querySelector('.reauth-name-hint');
- },
-
- /**
- * Gets the container holding the password field.
- * @type {!HTMLInputElement}
- */
- get passwordEntryContainerElement() {
- return this.querySelector('.password-entry-container');
- },
-
- /**
- * Gets password field.
- * @type {!HTMLInputElement}
- */
- get passwordElement() {
- return this.querySelector('.password');
- },
-
- /**
- * Gets submit button.
- * @type {!HTMLInputElement}
- */
- get submitButton() {
- return this.querySelector('.submit-button');
- },
-
- /**
- * Gets the password label, which is used to show a message where the
- * password field is normally.
- * @type {!HTMLInputElement}
- */
- get passwordLabelElement() {
- return this.querySelector('.password-label');
- },
-
- get pinContainer() {
- return this.querySelector('.pin-container');
- },
-
- /**
- * Gets the pin-keyboard of the pod.
- * @type {!HTMLElement}
- */
- get pinKeyboard() {
- return this.querySelector('pin-keyboard');
- },
-
- /**
- * Gets user online sign in hint element.
- * @type {!HTMLDivElement}
- */
- get reauthWarningElement() {
- return this.querySelector('.reauth-hint-container');
- },
-
- /**
- * Gets action box area.
- * @type {!HTMLInputElement}
- */
- get actionBoxAreaElement() {
- return this.querySelector('.action-box-area');
- },
-
- /**
- * Gets user type icon area.
- * @type {!HTMLDivElement}
- */
- get userTypeIconAreaElement() {
- return this.querySelector('.user-type-icon-area');
- },
-
- /**
- * Gets user type bubble like multi-profiles policy restriction message.
- * @type {!HTMLDivElement}
- */
- get userTypeBubbleElement() {
- return this.querySelector('.user-type-bubble');
- },
-
- /**
- * Gets action box menu.
- * @type {!HTMLDivElement}
- */
- get actionBoxMenu() {
- return this.querySelector('.action-box-menu');
- },
-
- /**
- * Gets action box menu title (user name and email).
- * @type {!HTMLDivElement}
- */
- get actionBoxMenuTitleElement() {
- return this.querySelector('.action-box-menu-title');
- },
-
- /**
- * Gets action box menu title, user name item.
- * @type {!HTMLSpanElement}
- */
- get actionBoxMenuTitleNameElement() {
- return this.querySelector('.action-box-menu-title-name');
- },
-
- /**
- * Gets action box menu title, user email item.
- * @type {!HTMLSpanElement}
- */
- get actionBoxMenuTitleEmailElement() {
- return this.querySelector('.action-box-menu-title-email');
- },
-
- /**
- * Gets action box menu, remove user command item div.
- * @type {!HTMLInputElement}
- */
- get actionBoxMenuRemoveElement() {
- return this.querySelector('.action-box-menu-remove');
- },
-
- /**
- * Gets action box menu, remove user command item div.
- * @type {!HTMLInputElement}
- */
- get actionBoxRemoveUserWarningElement() {
- return this.querySelector('.action-box-remove-user-warning');
- },
-
- /**
- * Gets action box menu, remove user command item div.
- * @type {!HTMLInputElement}
- */
- get actionBoxRemoveUserWarningButtonElement() {
- return this.querySelector('.remove-warning-button');
- },
-
- /**
- * Gets the custom icon. This icon is normally hidden, but can be shown
- * using the chrome.screenlockPrivate API.
- * @type {!HTMLDivElement}
- */
- get customIconElement() {
- return this.querySelector('.custom-icon-container');
- },
-
- /**
- * Gets the elements used for statistics display.
- * @type {Object.<string, !HTMLDivElement>}
- */
- get statsMapElements() {
- return {
- 'BrowsingHistory':
- this.querySelector('.action-box-remove-user-warning-history'),
- 'Passwords':
- this.querySelector('.action-box-remove-user-warning-passwords'),
- 'Bookmarks':
- this.querySelector('.action-box-remove-user-warning-bookmarks'),
- 'Autofill':
- this.querySelector('.action-box-remove-user-warning-autofill')
- }
- },
-
- /**
- * Gets the fingerprint icon area.
- * @type {!HTMLDivElement}
- */
- get fingerprintIconElement() {
- return this.querySelector('.fingerprint-icon-container');
- },
-
- /**
- * Returns true if it's a public session pod.
- * @type {boolean}
- */
- get isPublicSessionPod() {
- return this.classList.contains('public-account');
- },
-
- /**
- * Sets the pod style.
- * @param {UserPod.Style} style Style set to the pod.
- */
- setPodStyle: function(style) {
- switch (style) {
- case UserPod.Style.LARGE:
- this.querySelector('.large-pod').hidden = false;
- this.querySelector('.small-pod').hidden = true;
- break;
- case UserPod.Style.SMALL:
- this.querySelector('.large-pod').hidden = true;
- this.querySelector('.small-pod').hidden = false;
- this.querySelector('.small-pod').classList.remove('extra-small');
- break;
- case UserPod.Style.EXTRA_SMALL:
- this.querySelector('.large-pod').hidden = true;
- this.querySelector('.small-pod').hidden = false;
- this.querySelector('.small-pod').classList.add('extra-small');
- break;
- default:
- console.error("Attempt to set an invalid pod style.");
- break;
- }
- },
-
- /**
- * Gets the pod style.
- * @return {UserPod.Style} Pod style.
- */
- getPodStyle: function() {
- if (this.querySelector('.small-pod').hidden)
- return UserPod.Style.LARGE;
- if (this.querySelector('.small-pod').classList.contains('extra-small'))
- return UserPod.Style.EXTRA_SMALL;
- return UserPod.Style.SMALL;
- },
-
- /**
- * Updates the user pod element.
- */
- update: function() {
- var animatedImageSrc = 'chrome://userimage/' + this.user.username +
- '?id=' + UserPod.userImageSalt_[this.user.username];
- var imageSrc = animatedImageSrc + '&frame=0';
- this.imageElement.src = imageSrc;
- this.animatedImageElement.src = animatedImageSrc;
- this.smallPodImageElement.src = imageSrc;
- this.smallPodAnimatedImageElement.src = animatedImageSrc;
-
- this.nameElement.textContent = this.user_.displayName;
- this.smallPodNameElement.textContent = this.user_.displayName;
- this.reauthNameHintElement.textContent = this.user_.displayName;
- this.classList.toggle('signed-in', this.user_.signedIn);
-
- if (this.isAuthTypeUserClick)
- this.passwordLabelElement.textContent = this.authValue;
-
- this.updateActionBoxArea();
- this.customizeUserPodPerUserType();
- this.updateAriaLabels_();
- },
-
- updateActionBoxArea: function() {
- if (this.user_.publicAccount) {
- this.actionBoxAreaElement.hidden = true;
- return;
- }
-
- this.actionBoxMenuRemoveElement.hidden = !this.user_.canRemove;
-
- this.actionBoxMenuTitleNameElement.textContent = this.user_.isOwner ?
- loadTimeData.getStringF('ownerUserPattern', this.user_.displayName) :
- this.user_.displayName;
- this.actionBoxMenuTitleEmailElement.textContent = this.user_.emailAddress;
-
- this.actionBoxMenuTitleEmailElement.hidden =
- this.user_.legacySupervisedUser;
- },
-
- customizeUserPodPerUserType: function() {
- if (this.user_.childUser && !this.user_.isDesktopUser) {
- this.setUserPodIconType('child');
- } else if (this.user_.legacySupervisedUser && !this.user_.isDesktopUser) {
- this.setUserPodIconType('legacySupervised');
- this.classList.add('legacy-supervised');
- } else if (this.multiProfilesPolicyApplied) {
- // Mark user pod as not focusable which in addition to the grayed out
- // filter makes it look in disabled state.
- this.classList.add('multiprofiles-policy-applied');
- this.setUserPodIconType('policy');
-
- if (this.user.multiProfilesPolicy ==
- MULTI_PROFILE_USER_BEHAVIOR.PRIMARY_ONLY) {
- this.querySelector('.mp-policy-primary-only-msg').hidden = false;
- } else if (this.user.multiProfilesPolicy ==
- MULTI_PROFILE_USER_BEHAVIOR.OWNER_PRIMARY_ONLY) {
- this.querySelector('.mp-owner-primary-only-msg').hidden = false;
- } else {
- this.querySelector('.mp-policy-not-allowed-msg').hidden = false;
- }
- }
- },
-
- /**
- * Updates ARIA labels and sets hidden states. All updates related to ARIA
- * should go here.
- * @private
- */
- updateAriaLabels_: function() {
- this.setAttribute('aria-label', this.user_.displayName);
- this.querySelector('.password-container')
- .setAttribute(
- 'aria-label',
- loadTimeData.getStringF(
- 'passwordFieldAccessibleName', this.user_.emailAddress));
- this.actionBoxAreaElement.setAttribute(
- 'aria-label',
- loadTimeData.getStringF(
- 'podMenuButtonAccessibleName', this.user_.emailAddress));
- this.actionBoxMenuRemoveElement.setAttribute(
- 'aria-label',
- loadTimeData.getString('podMenuRemoveItemAccessibleName'));
- },
-
- isPinReady: function() {
- return this.pinKeyboard && this.pinKeyboard.offsetHeight > 0;
- },
-
- set showError(visible) {
- if (this.submitButton)
- this.submitButton.classList.toggle('error-shown', visible);
- },
-
- updatePinClass_: function(element, enable) {
- element.classList.toggle('pin-enabled', enable);
- element.classList.toggle('pin-disabled', !enable);
- },
-
- setPinVisibility: function(visible) {
- if (this.isPinShown() == visible)
- return;
-
- // Do not show pin if virtual keyboard is there.
- if (visible && Oobe.getInstance().virtualKeyboardShown)
- return;
-
- // Do not show pin keyboard if the pod does not have pin enabled.
- if (visible && !this.pinEnabled)
- return;
-
- // Do not show pin keyboard if the pod is not in large style.
- if (visible && this.getPodStyle() != UserPod.Style.LARGE)
- return;
-
- var elements = this.getElementsByClassName('pin-tag');
- for (var i = 0; i < elements.length; ++i)
- this.updatePinClass_(elements[i], visible);
- this.updatePinClass_(this, visible);
-
- // Set the focus to the input element after showing/hiding pin keyboard.
- this.mainInput.focus();
-
- // Change the password placeholder based on pin keyboard visibility.
- this.passwordElement.placeholder = loadTimeData.getString(visible ?
- 'pinKeyboardPlaceholderPinPassword' : 'passwordHint');
-
- // Adjust the vertical position based on the pin keyboard visibility.
- var podHeight = visible ? CROS_POD_HEIGHT_WITH_PIN : CROS_POD_HEIGHT;
- this.top = ($('pod-row').screenSize.height - podHeight) / 2;
- },
-
- isPinShown: function() {
- return this.classList.contains('pin-enabled');
- },
-
- setUserPodIconType: function(userTypeClass) {
- this.userTypeIconAreaElement.classList.add(userTypeClass);
- // TODO(wzang): Evaluate all icon types other than supervised user and
- // switch them to badges per the design spec.
- this.userTypeIconAreaElement.hidden = true;
- },
-
- isFingerprintIconShown: function() {
- return this.fingerprintIconElement && !this.fingerprintIconElement.hidden;
- },
-
- /**
- * The user that this pod represents.
- * @type {!Object}
- */
- user_: undefined,
- get user() {
- return this.user_;
- },
- set user(userDict) {
- this.user_ = userDict;
- this.update();
- },
-
- /**
- * Returns true if multi-profiles sign in is currently active and this
- * user pod is restricted per policy.
- * @type {boolean}
- */
- get multiProfilesPolicyApplied() {
- var isMultiProfilesUI =
- (Oobe.getInstance().displayType == DISPLAY_TYPE.USER_ADDING);
- return isMultiProfilesUI && !this.user_.isMultiProfilesAllowed;
- },
-
- /**
- * Gets main input element.
- * @type {(HTMLButtonElement|HTMLInputElement)}
- */
- get mainInput() {
- if (this.isAuthTypePassword) {
- return this.passwordElement;
- } else if (this.isAuthTypeOnlineSignIn) {
- return this;
- } else if (this.isAuthTypeUserClick) {
- return this.passwordLabelElement;
- }
- },
-
- /**
- * Whether action box button is in active state.
- * @type {boolean}
- */
- get isActionBoxMenuActive() {
- return this.actionBoxAreaElement.classList.contains('active');
- },
- set isActionBoxMenuActive(active) {
- if (active == this.isActionBoxMenuActive)
- return;
-
- if (active) {
- this.actionBoxMenuRemoveElement.hidden = !this.user_.canRemove;
- this.actionBoxRemoveUserWarningElement.hidden = true;
-
- // Clear focus first if another pod is focused.
- if (!this.parentNode.isFocused(this)) {
- this.parentNode.focusPod(undefined, true);
- this.actionBoxAreaElement.focus();
- }
-
- // Hide user-type-bubble.
- this.userTypeBubbleElement.classList.remove('bubble-shown');
-
- this.actionBoxAreaElement.classList.add('active');
-
- // Invisible focus causes ChromeVox to read user name and email.
- this.actionBoxMenuTitleElement.tabIndex = UserPodTabOrder.POD_MENU_ITEM;
- this.actionBoxMenuTitleElement.focus();
- } else {
- this.actionBoxAreaElement.classList.remove('active');
- this.actionBoxAreaElement.classList.remove('menu-moved-up');
- this.actionBoxMenu.classList.remove('menu-moved-up');
- }
- },
-
- /**
- * Whether action box button is in hovered state.
- * @type {boolean}
- */
- get isActionBoxMenuHovered() {
- return this.actionBoxAreaElement.classList.contains('hovered');
- },
- set isActionBoxMenuHovered(hovered) {
- if (hovered == this.isActionBoxMenuHovered)
- return;
-
- if (hovered) {
- this.actionBoxAreaElement.classList.add('hovered');
- this.classList.add('hovered');
- } else {
- if (this.multiProfilesPolicyApplied)
- this.userTypeBubbleElement.classList.remove('bubble-shown');
- this.actionBoxAreaElement.classList.remove('hovered');
- this.classList.remove('hovered');
- }
- },
-
- /**
- * Set the authentication type for the pod.
- * @param {number} An auth type value defined in the AUTH_TYPE enum.
- * @param {string} authValue The initial value used for the auth type.
- */
- setAuthType: function(authType, authValue) {
- this.authType_ = authType;
- this.authValue_ = authValue;
- this.setAttribute('auth-type', AUTH_TYPE_NAMES[this.authType_]);
- this.update();
- this.reset(this.parentNode.isFocused(this));
- },
-
- /**
- * The auth type of the user pod. This value is one of the enum
- * values in AUTH_TYPE.
- * @type {number}
- */
- get authType() {
- return this.authType_;
- },
-
- /**
- * The initial value used for the pod's authentication type.
- * eg. a prepopulated password input when using password authentication.
- */
- get authValue() {
- return this.authValue_;
- },
-
- /**
- * True if the the user pod uses a password to authenticate.
- * @type {bool}
- */
- get isAuthTypePassword() {
- return this.authType_ == AUTH_TYPE.OFFLINE_PASSWORD ||
- this.authType_ == AUTH_TYPE.FORCE_OFFLINE_PASSWORD;
- },
-
- /**
- * True if the the user pod uses a user click to authenticate.
- * @type {bool}
- */
- get isAuthTypeUserClick() {
- return this.authType_ == AUTH_TYPE.USER_CLICK;
- },
-
- /**
- * True if the the user pod uses a online sign in to authenticate.
- * @type {bool}
- */
- get isAuthTypeOnlineSignIn() {
- return this.authType_ == AUTH_TYPE.ONLINE_SIGN_IN;
- },
-
- /**
- * Updates the image element of the user.
- */
- updateUserImage: function() {
- UserPod.userImageSalt_[this.user.username] = new Date().getTime();
- this.update();
- },
-
- /**
- * Focuses on input element.
- * @param {boolean?} opt_ensureFocus If true, keep trying to focus until a
- * focus change event is raised.
- */
- focusInput: function(opt_ensureFocus) {
- // If |opt_ensureFocus| is set, keep setting the focus until we get a
- // global focus change event. Sometimes focus requests are ignored while
- // loading the page. See crbug.com/725622.
- if (opt_ensureFocus) {
- var INTERVAL_REPEAT_MS = 10;
- var input = this.mainInput;
- var intervalId = setInterval(function() {
- input.focus();
- }, INTERVAL_REPEAT_MS);
- window.addEventListener('focus', function refocus() {
- if (document.activeElement != input)
- return;
- window.removeEventListener('focus', refocus);
- window.clearInterval(intervalId);
- }, true);
- }
-
- // Move tabIndex from the whole pod to the main input.
- // Note: the |mainInput| can be the pod itself.
- this.tabIndex = -1;
- this.mainInput.tabIndex = UserPodTabOrder.POD_INPUT;
- this.mainInput.focus();
- },
-
- /**
- * Activates the pod.
- * @param {Event} e Event object.
- * @return {boolean} True if activated successfully.
- */
- activate: function(e) {
- if (this.isAuthTypeOnlineSignIn) {
- this.showSigninUI();
- } else if (this.isAuthTypeUserClick) {
- Oobe.disableSigninUI();
- this.classList.toggle('signing-in', true);
- chrome.send('attemptUnlock', [this.user.username]);
- } else if (this.isAuthTypePassword) {
- if (this.fingerprintAuthenticated_) {
- this.fingerprintAuthenticated_ = false;
- return true;
- }
- var pinValue = this.pinKeyboard ? this.pinKeyboard.value : '';
- var password = this.passwordElement.value || pinValue;
- if (!password)
- return false;
- Oobe.disableSigninUI();
- chrome.send('authenticateUser', [
- this.user.username, password, this.isPinShown() && !isNaN(password)
- ]);
- } else {
- console.error('Activating user pod with invalid authentication type: ' +
- this.authType);
- }
-
- return true;
- },
-
- showSupervisedUserSigninWarning: function() {
- // Legacy supervised user token has been invalidated.
- // Make sure that pod is focused i.e. "Sign in" button is seen.
- this.parentNode.focusPod(this);
-
- var error = document.createElement('div');
- var messageDiv = document.createElement('div');
- messageDiv.className = 'error-message-bubble';
- messageDiv.textContent =
- loadTimeData.getString('supervisedUserExpiredTokenWarning');
- error.appendChild(messageDiv);
-
- $('bubble').showContentForElement(
- this.reauthWarningElement,
- cr.ui.Bubble.Attachment.TOP,
- error,
- this.reauthWarningElement.offsetWidth / 2,
- 4);
- // Move warning bubble up if it overlaps the shelf.
- var maxHeight =
- cr.ui.LoginUITools.getMaxHeightBeforeShelfOverlapping($('bubble'));
- if (maxHeight < $('bubble').offsetHeight) {
- $('bubble').showContentForElement(
- this.reauthWarningElement,
- cr.ui.Bubble.Attachment.BOTTOM,
- error,
- this.reauthWarningElement.offsetWidth / 2,
- 4);
- }
- },
-
- /**
- * Shows signin UI for this user.
- */
- showSigninUI: function() {
- if (this.user.legacySupervisedUser && !this.user.isDesktopUser) {
- this.showSupervisedUserSigninWarning();
- } else {
- // Disable online sign-in flow for user-adding screen.
- if (Oobe.getInstance().displayType == DISPLAY_TYPE.USER_ADDING)
- return;
-
- this.parentNode.showSigninUI(this.user.emailAddress);
- }
- },
-
- /**
- * Returns the element that should be used as the anchor for error bubbles
- * associated with the pod.
- *
- * @return {HTMLElement} The anchor for error bubbles.
- * @private
- */
- getBubbleAnchor_: function() {
- var bubbleAnchor = this.getElementsByClassName('auth-container')[0];
- if (!bubbleAnchor) {
- console.error('auth-container not found!');
- bubbleAnchor = this.mainInput;
- }
- return bubbleAnchor;
- },
-
- /**
- * Shows a bubble under the auth-container of the user pod.
- * @param {HTMLElement} content Content to show in bubble.
- * @param {!{bubble: (HTMLElement|undefined),
- * anchor: (HTMLElement|undefined),
- * timeout: (number|undefined)}|undefined} opt_options The custom
- * options describing how the bubble should be shown:
- * <ul>
- * <li>bubble: The element that hosts the bubble content.</li>
- * <li>
- * anchor: The element to which the bubble should be anchored.
- * </li>
- * <li>
- * timeout: Amount of time in ms after which the bubble
- * should be hidden. Note: this should only be used for
- * {@code $('bubble')} bubble element. The timeout will get
- * cleared if the bubble is shown again.
- * </li>
- * </ul>
- * @return {function()} Function that, when called, hides the shown bubble.
- */
- showBubble: function(content, opt_options) {
- /** @const */ var BUBBLE_OFFSET = 25;
- // -8 = 4(BUBBLE_POD_OFFSET) - 2(bubble margin)
- // - 10(internal bubble adjustment)
- var bubblePositioningPadding = -8;
-
- var options = opt_options || {};
- var bubble = options.bubble || $('bubble');
-
- // Make sure bubble timeout is changed only for $('bubble') element.
- if (options.timeout && bubble != $('bubble')) {
- console.error('Timeout can be set only when showing #bubble element.');
- return;
- }
-
- var bubbleAnchor = options.anchor || this.getBubbleAnchor_();
- var attachment;
- if (this.pinContainer && this.pinContainer.style.visibility == 'visible')
- attachment = cr.ui.Bubble.Attachment.RIGHT;
- else
- attachment = cr.ui.Bubble.Attachment.BOTTOM;
-
- // Cannot use cr.ui.LoginUITools.get* on bubble until it is attached to
- // the element. getMaxHeight/Width rely on the correct up/left element
- // side positioning that doesn't happen until bubble is attached.
- var maxHeight =
- cr.ui.LoginUITools.getMaxHeightBeforeShelfOverlapping(bubbleAnchor) -
- bubbleAnchor.offsetHeight - BUBBLE_POD_OFFSET;
- var maxWidth = cr.ui.LoginUITools.getMaxWidthToFit(bubbleAnchor) -
- bubbleAnchor.offsetWidth - BUBBLE_POD_OFFSET;
-
- // Change bubble visibility temporary to calculate height.
- var bubbleVisibility = bubble.style.visibility;
- bubble.style.visibility = 'hidden';
- bubble.hidden = false;
- // Now we need the bubble to have the new content before calculating
- // size. Undefined |content| == reuse old content.
- if (content !== undefined)
- bubble.replaceContent(content);
-
- // Get bubble size.
- var bubbleOffsetHeight = parseInt(bubble.offsetHeight);
- var bubbleOffsetWidth = parseInt(bubble.offsetWidth);
- // Restore attributes.
- bubble.style.visibility = bubbleVisibility;
- bubble.hidden = true;
-
- if (attachment == cr.ui.Bubble.Attachment.BOTTOM) {
- // Move the bubble if it overlaps the shelf.
- if (maxHeight < bubbleOffsetHeight)
- attachment = cr.ui.Bubble.Attachment.TOP;
- } else {
- // Move the bubble if it doesn't fit screen.
- if (maxWidth < bubbleOffsetWidth) {
- bubblePositioningPadding = 2;
- attachment = cr.ui.Bubble.Attachment.LEFT;
- }
- }
-
- if (bubble == $('bubble'))
- this.clearBubbleHideTimeout_();
-
- var state = {shown: false, hidden: false};
-
- var showBubbleCallback = function() {
- this.removeEventListener('transitionend', showBubbleCallback);
- // If the bubble was requested to be hidden while the transition was in
- // progress, do not show the bubble.
- if (state.hidden)
- return;
-
- state.shown = true;
-
- bubble.showContentForElement(
- bubbleAnchor, attachment, content, BUBBLE_OFFSET,
- bubblePositioningPadding, true);
-
- if (options.timeout != undefined) {
- this.hideBubbleTimeout_ = setTimeout(() => {
- this.hideBubbleTimeout_ = undefined;
- bubble.hideForElement(bubbleAnchor);
- }, options.timeout);
- }
- }.bind(this);
- this.addEventListener('transitionend', showBubbleCallback);
- ensureTransitionEndEvent(this);
-
- return function() {
- if (state.hidden)
- return;
-
- state.hidden = true;
- if (state.shown)
- bubble.hideForElement(bubbleAnchor);
- };
- },
-
- /**
- * Clears the timeout to hide a bubble, if a bubble timeout was set.
- * @private
- */
- clearBubbleHideTimeout_: function() {
- if (this.hideBubbleTimeout_) {
- clearTimeout(this.hideBubbleTimeout_);
- this.hideBubbleTimeout_ = null;
- }
- },
-
- /**
- * Shows persistent bubble for detachable base change warning.
- * @param {HTMLElement} content The bubble contens.
- */
- showDetachableBaseWarningBubble: function(content) {
- var anchor = this.getBubbleAnchor_();
- if (!anchor)
- return;
- this.clearBubbleHideTimeout_();
- $('bubble').hideForElement(anchor);
- this.detachableBaseWarningBubbleHider_ = this.showBubble(
- content, {bubble: $('bubble-persistent'), anchor: anchor});
- },
-
- /**
- * If a peristent bubble for detachable base change warning is shown (and
- * anchored at this pod), hides the bubble.
- */
- hideDetachableBaseWarningBubble: function() {
- if (this.detachableBaseWarningBubbleHider_) {
- this.detachableBaseWarningBubbleHider_();
- this.detachableBaseWarningBubbleHider_ = null;
- }
- },
-
- /**
- * Whether a detachable base warning bubble is being shown for this pod.
- * @return {boolean}
- */
- showingDetachableBaseWarningBubble: function() {
- return this.detachableBaseWarningBubbleHider_ &&
- !$('bubble-persistent').hidden &&
- $('bubble-persistent').anchor == this.getBubbleAnchor_();
- },
-
- /**
- * Resets the input field and updates the tab order of pod controls.
- * @param {boolean} takeFocus If true, input field takes focus.
- */
- reset: function(takeFocus) {
- this.passwordElement.value = '';
- if (this.pinKeyboard)
- this.pinKeyboard.value = '';
- this.updateInput_();
- this.classList.toggle('signing-in', false);
- if (takeFocus) {
- if (!this.multiProfilesPolicyApplied) {
- this.focusInput(
- this.mainInput.tagName == 'INPUT' /*opt_ensureFocus*/);
- }
- }
- else
- this.resetTabOrder();
- },
-
- /**
- * Removes a user using the correct identifier based on user type.
- * @param {Object} user User to be removed.
- */
- removeUser: function(user) {
- chrome.send('removeUser',
- [user.isDesktopUser ? user.profilePath : user.username]);
- },
-
- /**
- * Handles a click event on action area button.
- * @param {Event} e Click event.
- */
- handleActionAreaButtonClick_: function(e) {
- if (this.parentNode.disabled)
- return;
- this.isActionBoxMenuActive = !this.isActionBoxMenuActive;
- // Action area menu and error bubbles shouldn't appear together.
- Oobe.clearErrors();
- e.stopPropagation();
- },
-
- /**
- * Handles a keydown event on action area button.
- * @param {Event} e KeyDown event.
- */
- handleActionAreaButtonKeyDown_: function(e) {
- if (this.disabled)
- return;
- switch (e.key) {
- case 'Enter':
- case ' ':
- if (this.parentNode.focusedPod_ && !this.isActionBoxMenuActive) {
- this.isActionBoxMenuActive = true;
- Oobe.clearErrors();
- }
- e.stopPropagation();
- break;
- case 'ArrowUp':
- case 'ArrowDown':
- if (this.isActionBoxMenuActive) {
- this.actionBoxMenuRemoveElement.tabIndex =
- UserPodTabOrder.POD_MENU_ITEM;
- this.actionBoxMenuRemoveElement.focus();
- }
- e.stopPropagation();
- break;
- // Ignore these two, so ChromeVox hotkeys don't close the menu before
- // they can navigate through it.
- case 'Shift':
- case 'Meta':
- break;
- case 'Escape':
- this.actionBoxAreaElement.focus();
- this.isActionBoxMenuActive = false;
- e.stopPropagation();
- break;
- case 'Tab':
- if (!this.parentNode.alwaysFocusSinglePod)
- this.parentNode.focusPod();
- default:
- this.isActionBoxMenuActive = false;
- break;
- }
- },
-
- /**
- * Handles a keydown event on menu title.
- * @param {Event} e KeyDown event.
- */
- handleMenuTitleElementKeyDown_: function(e) {
- if (this.disabled)
- return;
-
- if (e.key != 'Tab') {
- this.handleActionAreaButtonKeyDown_(e);
- return;
- }
-
- if (e.shiftKey == false) {
- if (this.actionBoxMenuRemoveElement.hidden) {
- this.isActionBoxMenuActive = false;
- } else {
- this.actionBoxMenuRemoveElement.tabIndex =
- UserPodTabOrder.POD_MENU_ITEM;
- this.actionBoxMenuRemoveElement.focus();
- e.preventDefault();
- }
- } else {
- this.isActionBoxMenuActive = false;
- this.focusInput();
- e.preventDefault();
- }
- },
-
- /**
- * Handles a blur event on menu title.
- * @param {Event} e Blur event.
- */
- handleMenuTitleElementBlur_: function(e) {
- if (this.disabled)
- return;
- this.actionBoxMenuTitleElement.tabIndex = -1;
- },
-
- /**
- * Handles a click event on remove user command.
- * @param {Event} e Click event.
- */
- handleRemoveCommandClick_: function(e) {
- this.showRemoveWarning_();
- },
-
- /**
- * Move the action box menu up if needed.
- */
- moveActionMenuUpIfNeeded_: function() {
- // Skip checking (computationally expensive) if already moved up.
- if (this.actionBoxMenu.classList.contains('menu-moved-up'))
- return;
-
- // Move up the menu if it overlaps shelf.
- var maxHeight = cr.ui.LoginUITools.getMaxHeightBeforeShelfOverlapping(
- this.actionBoxMenu, true);
- var actualHeight = parseInt(
- window.getComputedStyle(this.actionBoxMenu).height);
- if (maxHeight < actualHeight) {
- this.actionBoxMenu.classList.add('menu-moved-up');
- this.actionBoxAreaElement.classList.add('menu-moved-up');
- }
- },
-
- /**
- * Shows remove user warning. Used for legacy supervised users
- * and non-device-owner on CrOS, and for all users on desktop.
- */
- showRemoveWarning_: function() {
- this.actionBoxMenuRemoveElement.hidden = true;
- this.actionBoxRemoveUserWarningElement.hidden = false;
-
- if (!this.user.isDesktopUser) {
- this.moveActionMenuUpIfNeeded_();
- if (!this.user.legacySupervisedUser) {
- this.querySelector(
- '.action-box-remove-user-warning-text').style.display = 'none';
- this.querySelector(
- '.action-box-remove-user-warning-table-nonsync').style.display
- = 'none';
- var message = loadTimeData.getString('removeNonOwnerUserWarningText');
- this.updateRemoveNonOwnerUserWarningMessage_(this.user.profilePath,
- message);
- }
- } else {
- // Show extra statistics information for desktop users
- this.querySelector(
- '.action-box-remove-non-owner-user-warning-text').hidden = true;
- this.RemoveWarningDialogSetMessage_();
- // set a global handler for the callback
- window.updateRemoveWarningDialog =
- this.updateRemoveWarningDialog_.bind(this);
- var is_synced_user = this.user.emailAddress !== "";
- if (!is_synced_user) {
- chrome.send('removeUserWarningLoadStats', [this.user.profilePath]);
- }
- }
- chrome.send('logRemoveUserWarningShown');
- },
-
- /**
- * Refresh the statistics in the remove user warning dialog.
- * @param {string} profilePath The filepath of the URL (must be verified).
- * @param {Object} profileStats Statistics associated with profileURL.
- */
- updateRemoveWarningDialog_: function(profilePath, profileStats) {
- if (profilePath !== this.user.profilePath)
- return;
-
- var stats_elements = this.statsMapElements;
- // Update individual statistics
- for (var key in profileStats) {
- if (stats_elements.hasOwnProperty(key)) {
- stats_elements[key].textContent = profileStats[key].count;
- }
- }
- },
-
- /**
- * Set the new message in the dialog.
- */
- RemoveWarningDialogSetMessage_: function() {
- var is_synced_user = this.user.emailAddress !== "";
- message = loadTimeData.getString(
- is_synced_user ? 'removeUserWarningTextSync' :
- 'removeUserWarningTextNonSync');
- this.updateRemoveWarningDialogSetMessage_(this.user.profilePath,
- message);
- },
-
- /**
- * Refresh the message in the remove user warning dialog.
- * @param {string} profilePath The filepath of the URL (must be verified).
- * @param {string} message The message to be written.
- * @param {number|string=} count The number or string to replace $1 in
- * |message|. Can be omitted if $1 is not present in |message|.
- */
- updateRemoveWarningDialogSetMessage_: function(
- profilePath, message, count) {
- if (profilePath !== this.user.profilePath)
- return;
- // Add localized messages where $1 will be replaced with
- // <span class="total-count"></span> and $2 will be replaced with
- // <span class="email"></span>.
- var element = this.querySelector('.action-box-remove-user-warning-text');
- element.textContent = '';
-
- messageParts = message.split(/(\$[12])/);
- var numParts = messageParts.length;
- for (var j = 0; j < numParts; j++) {
- if (messageParts[j] === '$1') {
- var elementToAdd = document.createElement('span');
- elementToAdd.classList.add('total-count');
- elementToAdd.textContent = count;
- element.appendChild(elementToAdd);
- } else if (messageParts[j] === '$2') {
- var elementToAdd = document.createElement('span');
- elementToAdd.classList.add('email');
- elementToAdd.textContent = this.user.emailAddress;
- element.appendChild(elementToAdd);
- } else {
- element.appendChild(document.createTextNode(messageParts[j]));
- }
- }
- this.moveActionMenuUpIfNeeded_();
- },
-
- /**
- * Update the message in the "remove non-owner user warning" dialog on CrOS.
- * @param {string} profilePath The filepath of the URL (must be verified).
- * @param (string) message The message to be written.
- */
- updateRemoveNonOwnerUserWarningMessage_: function(profilePath, message) {
- if (profilePath !== this.user.profilePath)
- return;
- // Add localized messages where $1 will be replaced with
- // <span class="email"></span>.
- var element = this.querySelector(
- '.action-box-remove-non-owner-user-warning-text');
- element.textContent = '';
-
- messageParts = message.split(/(\$[1])/);
- var numParts = messageParts.length;
- for (var j = 0; j < numParts; j++) {
- if (messageParts[j] == '$1') {
- var elementToAdd = document.createElement('span');
- elementToAdd.classList.add('email');
- elementToAdd.textContent = this.user.emailAddress;
- element.appendChild(elementToAdd);
- } else {
- element.appendChild(document.createTextNode(messageParts[j]));
- }
- }
- this.moveActionMenuUpIfNeeded_();
- },
-
- /**
- * Handles a click event on remove user confirmation button.
- * @param {Event} e Click event.
- */
- handleRemoveUserConfirmationClick_: function(e) {
- if (this.isActionBoxMenuActive) {
- this.isActionBoxMenuActive = false;
- this.removeUser(this.user);
- e.stopPropagation();
- }
- },
-
- /**
- * Handles mouseover event on fingerprint icon.
- * @param {Event} e MouseOver event.
- */
- handleFingerprintIconMouseOver_: function(e) {
- var bubbleContent = document.createElement('div');
- bubbleContent.textContent =
- loadTimeData.getString('fingerprintIconMessage');
- this.passwordElement.placeholder =
- loadTimeData.getString('fingerprintHint');
-
- /** @const */ var BUBBLE_OFFSET = 25;
- /** @const */ var BUBBLE_PADDING = -8;
- var attachment = this.isPinShown() ? cr.ui.Bubble.Attachment.RIGHT :
- cr.ui.Bubble.Attachment.BOTTOM;
- var bubbleAnchor = this.getBubbleAnchorForFingerprintIcon_();
- $('bubble').showContentForElement(
- bubbleAnchor, attachment, bubbleContent, BUBBLE_OFFSET,
- BUBBLE_PADDING, true);
- },
-
- /**
- * Handles mouseout event on fingerprint icon.
- * @param {Event} e MouseOut event.
- */
- handleFingerprintIconMouseOut_: function(e) {
- var bubbleAnchor = this.getBubbleAnchorForFingerprintIcon_();
- $('bubble').hideForElement(bubbleAnchor);
- this.passwordElement.placeholder = loadTimeData.getString(
- this.isPinShown() ? 'pinKeyboardPlaceholderPinPassword' :
- 'passwordHint');
- },
-
- /**
- * Returns bubble anchor of the fingerprint icon.
- * @return {!HTMLElement} Anchor element of the bubble.
- */
- getBubbleAnchorForFingerprintIcon_: function() {
- var bubbleAnchor = this;
- if (this.isPinShown())
- bubbleAnchor = (this.getElementsByClassName('auth-container'))[0];
- return bubbleAnchor;
- },
-
- /**
- * Handles a keydown event on remove user confirmation button.
- * @param {Event} e KeyDown event.
- */
- handleRemoveUserConfirmationKeyDown_: function(e) {
- if (!this.isActionBoxMenuActive)
- return;
-
- // Only handle pressing 'Enter' or 'Space', and let all other events
- // bubble to the action box menu.
- if (e.key == 'Enter' || e.key == ' ') {
- this.isActionBoxMenuActive = false;
- this.removeUser(this.user);
- e.stopPropagation();
- // Prevent default so that we don't trigger a 'click' event.
- e.preventDefault();
- }
- },
-
- /**
- * Handles a keydown event on remove command.
- * @param {Event} e KeyDown event.
- */
- handleRemoveCommandKeyDown_: function(e) {
- if (this.disabled)
- return;
- switch (e.key) {
- case 'Enter':
- e.preventDefault();
- this.showRemoveWarning_();
- e.stopPropagation();
- break;
- case 'ArrowUp':
- case 'ArrowDown':
- e.stopPropagation();
- break;
- // Ignore these two, so ChromeVox hotkeys don't close the menu before
- // they can navigate through it.
- case 'Shift':
- case 'Meta':
- break;
- case 'Escape':
- this.actionBoxAreaElement.focus();
- this.isActionBoxMenuActive = false;
- e.stopPropagation();
- break;
- default:
- this.actionBoxAreaElement.focus();
- this.isActionBoxMenuActive = false;
- break;
- }
- },
-
- /**
- * Handles a blur event on remove command.
- * @param {Event} e Blur event.
- */
- handleRemoveCommandBlur_: function(e) {
- if (this.disabled)
- return;
- this.actionBoxMenuRemoveElement.tabIndex = -1;
- },
-
- /**
- * Handles mouse down event. It sets whether the user click auth will be
- * allowed on the next mouse click event. The auth is allowed iff the pod
- * was focused on the mouse down event starting the click.
- * @param {Event} e The mouse down event.
- */
- handlePodMouseDown_: function(e) {
- // Only large pods have mouse down event.
- if (this.getPodStyle() == UserPod.Style.LARGE)
- this.userClickAuthAllowed_ = this.parentNode.isFocused(this);
- },
-
- /**
- * Called when the input of the password element changes. Updates the submit
- * button color and state and hides the error popup bubble.
- */
- updateInput_: function() {
- var isEmpty = this.passwordElement.value.length == 0;
- if (this.submitButton) {
- this.submitButton.disabled = isEmpty;
- if (this.isFingerprintIconShown()) {
- this.submitButton.hidden = isEmpty;
- } else {
- this.submitButton.hidden = false;
- }
- }
- this.showError = false;
- $('bubble').hide();
- this.classList.toggle('input-present', !isEmpty);
- },
-
- /**
- * Handles input event on the password element.
- * @param {Event} e Input event.
- */
- handleInputChanged_: function(e) {
- this.updateInput_();
- },
-
- /**
- * Handles click event on a user pod.
- * @param {Event} e Click event.
- */
- handleClickOnPod_: function(e) {
- if (this.parentNode.disabled)
- return;
-
- // Click events on public session pods should only be handled by their
- // overriding handler.
- if (this.isPublicSessionPod)
- return;
-
- if (this.getPodStyle() != UserPod.Style.LARGE) {
- $('pod-row').switchMainPod(this);
- return;
- }
- Oobe.clearErrors();
-
- if (!this.isActionBoxMenuActive) {
- if (this.isAuthTypeOnlineSignIn) {
- this.showSigninUI();
- } else if (this.isAuthTypeUserClick && this.userClickAuthAllowed_) {
- // Note that this.userClickAuthAllowed_ is set in mouse down event
- // handler.
- this.parentNode.setActivatedPod(this);
- } else if (this.pinKeyboard &&
- e.target == this.pinKeyboard.submitButton) {
- // Sets the pod as activated if the submit button is clicked so that
- // it simulates what the enter button does for the password/pin.
- this.parentNode.setActivatedPod(this);
- }
-
- if (this.multiProfilesPolicyApplied)
- this.userTypeBubbleElement.classList.add('bubble-shown');
-
- // Prevent default so that we don't trigger 'focus' event and
- // stop propagation so that the 'click' event does not bubble
- // up and accidentally closes the bubble tooltip.
- stopEventPropagation(e);
- }
- },
-
- /**
- * Handles keydown event for a user pod.
- * @param {Event} e Key event.
- */
- handlePodKeyDown_: function(e) {
- if (this.getPodStyle() != UserPod.Style.LARGE) {
- this.handleNonLargePodKeyDown_(e);
- return;
- }
- if (!this.isAuthTypeUserClick || this.disabled)
- return;
- switch (e.key) {
- case 'Enter':
- case ' ':
- if (this.parentNode.isFocused(this))
- this.parentNode.setActivatedPod(this);
- break;
- }
- },
-
- /**
- * Handles keydown event for a small or extra small user pod.
- * @param {Event} e Key event.
- */
- handleNonLargePodKeyDown_: function(e) {
- switch (e.key) {
- case 'Enter':
- case ' ':
- if ($('pod-row').isFocused(this))
- $('pod-row').switchMainPod(this);
- break;
- }
- }
- };
-
- /**
- * Creates a public account user pod.
- * @constructor
- * @extends {UserPod}
- */
- var PublicAccountUserPod = cr.ui.define(function() {
- var node = UserPod();
-
- var extras = $('public-account-user-pod-extras-template').children;
- for (var i = 0; i < extras.length; ++i) {
- var el = extras[i].cloneNode(true);
- node.appendChild(el);
- }
-
- return node;
- });
-
- PublicAccountUserPod.prototype = {
- __proto__: UserPod.prototype,
-
- /**
- * Keeps track of the pod's original position before it's expanded.
- * @type {Object}
- */
- lastPosition: {left: 'unset', top: 'unset'},
-
- /**
- * If true, the public session should be launched directly without showing
- * the expanded view when the pod is activated.
- * @type {boolean}
- */
- skipExpandedView: false,
-
- /**
- * If true, further attempts of entering public session should bail out.
- * @type {boolean}
- */
- isEnteringPublicSession_: false,
-
- /**
- * The Learn more dialog.
- * @type {HTMLDivElement}
- */
- learnMoreDialog_: undefined,
-
- /**
- * "Enter" button in expanded side pane.
- * @type {!HTMLButtonElement}
- */
- get enterButtonElement() {
- return this.querySelector('.enter-button');
- },
-
- /**
- * Boolean flag of whether the pod is showing the side pane. The flag
- * controls whether 'expanded' class is added to the pod's class list and
- * resets tab order because main input element changes when the 'expanded'
- * state changes.
- * @type {boolean}
- */
- get expanded() {
- return this.classList.contains('expanded');
- },
-
- set expanded(expanded) {
- if (this.getPodStyle() != UserPod.Style.LARGE) {
- console.error(
- 'Attempt to expand a public session pod when it is not large.');
- return;
- }
- if (this.expanded == expanded)
- return;
-
- this.resetTabOrder();
- this.classList.toggle('expanded', expanded);
- if (expanded) {
- // Show the advanced expanded pod directly if there are at least two
- // recommended locales. This will be the case in multilingual
- // environments where users are likely to want to choose among locales.
- if (this.querySelector('.language-select').multipleRecommendedLocales)
- this.classList.add('advanced');
- } else {
- this.classList.remove('advanced');
- }
- this.parentNode.handlePublicPodExpansion(this, expanded);
- },
-
- get advanced() {
- return this.classList.contains('advanced');
- },
-
- /** @override */
- get mainInput() {
- if (this.expanded)
- return this.querySelector('.monitoring-learn-more');
- else
- return this.nameElement;
- },
-
- /** @override */
- decorate: function() {
- UserPod.prototype.decorate.call(this);
-
- this.classList.add('public-account');
-
- this.nameElement.addEventListener('keydown', (function(e) {
- if (e.key == 'Enter') {
- this.parentNode.setActivatedPod(this, e);
- // Stop this keydown event from bubbling up to PodRow handler.
- e.stopPropagation();
- // Prevent default so that we don't trigger a 'click' event on the
- // newly focused "Enter" button.
- e.preventDefault();
- }
- }).bind(this));
-
- var languageSelect = this.querySelector('.language-select');
- languageSelect.tabIndex = UserPodTabOrder.POD_INPUT;
- languageSelect.manuallyChanged = false;
- languageSelect.addEventListener(
- 'change',
- function() {
- languageSelect.manuallyChanged = true;
- this.getPublicSessionKeyboardLayouts_();
- }.bind(this));
-
- var keyboardSelect = this.querySelector('.keyboard-select');
- keyboardSelect.tabIndex = UserPodTabOrder.POD_INPUT;
- keyboardSelect.loadedLocale = null;
-
- var languageAndInputLink = this.querySelector('.language-and-input');
- languageAndInputLink.tabIndex = UserPodTabOrder.POD_INPUT;
- languageAndInputLink.addEventListener(
- 'click', this.transitionToAdvanced_.bind(this));
-
- var languageAndInputIcon =
- this.querySelector('.language-and-input-dropdown');
- languageAndInputIcon.addEventListener(
- 'click', this.transitionToAdvanced_.bind(this));
-
- var monitoringLearnMore = this.querySelector('.monitoring-learn-more');
- monitoringLearnMore.tabIndex = UserPodTabOrder.POD_INPUT;
- monitoringLearnMore.addEventListener(
- 'click', this.onLearnMoreClicked_.bind(this));
-
- this.enterButtonElement.tabIndex = UserPodTabOrder.POD_INPUT;
- this.enterButtonElement.addEventListener('click', (function(e) {
- this.enterButtonElement.disabled = true;
- this.enterPublicSession_();
- }).bind(this));
- },
-
- /** @override **/
- initialize: function() {
- UserPod.prototype.initialize.call(this);
-
- id = this.user.username + '-keyboard';
- this.querySelector('.keyboard-select-label').htmlFor = id;
- this.querySelector('.keyboard-select').setAttribute('id', id);
-
- var id = this.user.username + '-language';
- this.querySelector('.language-select-label').htmlFor = id;
- var languageSelect = this.querySelector('.language-select');
- languageSelect.setAttribute('id', id);
- this.populateLanguageSelect(this.user.initialLocales,
- this.user.initialLocale,
- this.user.initialMultipleRecommendedLocales);
- },
-
- /** @override **/
- update: function() {
- UserPod.prototype.update.call(this);
- this.querySelector('.info').textContent =
- loadTimeData.getStringF('publicAccountInfoFormat',
- this.user_.enterpriseDomainManager);
- if (this.querySelector('.full-name'))
- this.querySelector('.full-name').textContent = this.user_.displayName;
- },
-
- /** @override */
- focusInput: function() {
- // Move tabIndex from the whole pod to the main input.
- this.tabIndex = -1;
- this.mainInput.tabIndex = UserPodTabOrder.POD_INPUT;
- this.mainInput.focus();
- },
-
- /** @override */
- reset: function(takeFocus) {
- if (!takeFocus)
- this.expanded = false;
- this.enterButtonElement.disabled = false;
- UserPod.prototype.reset.call(this, takeFocus);
- },
-
- /** @override */
- activate: function(e) {
- if (!this.expanded) {
- if (this.skipExpandedView) {
- this.enterPublicSession_();
- } else {
- this.expanded = true;
- this.focusInput();
- }
- }
- return true;
- },
-
- /** @override */
- handleClickOnPod_: function(e) {
- if (this.parentNode.disabled)
- return;
-
- if (this.getPodStyle() != UserPod.Style.LARGE) {
- $('pod-row').switchMainPod(this);
- return;
- }
- Oobe.clearErrors();
-
- this.parentNode.focusPod(this);
- this.parentNode.setActivatedPod(this, e);
- // Prevent default so that we don't trigger 'focus' event.
- e.preventDefault();
- },
-
- /**
- * Updates the display name shown on the pod.
- * @param {string} displayName The new display name
- */
- setDisplayName: function(displayName) {
- this.user_.displayName = displayName;
- this.update();
- },
-
- /**
- * Transition the expanded pod from the basic to the advanced view.
- */
- transitionToAdvanced_: function() {
- this.classList.add('advanced');
- },
-
- /**
- * Show a dialog when user clicks on Learn more button.
- */
- onLearnMoreClicked_: function() {
- // Ignore if the Learn more dialog is already open.
- if (this.learnMoreDialog_)
- return;
-
- var topContainer = document.querySelector('#scroll-container');
- var dialogContainer =
- topContainer.querySelector('.monitoring-dialog-container');
- if (!dialogContainer) {
- // Add a dummy parent element to enable different CSS settings.
- dialogContainer = document.createElement('div');
- dialogContainer.classList.add('monitoring-dialog-container');
- topContainer.appendChild(dialogContainer);
- }
- dialogContainer.classList.toggle(
- 'advanced', this.classList.contains('advanced'));
- var html = '';
- var infoItems = ['publicAccountMonitoringInfoItem1',
- 'publicAccountMonitoringInfoItem2',
- 'publicAccountMonitoringInfoItem3',
- 'publicAccountMonitoringInfoItem4'];
- for (item of infoItems) {
- html += '<p class="cr-dialog-item">';
- html += loadTimeData.getString(item);
- html += '</p>';
- }
- var title = loadTimeData.getString('publicAccountMonitoringInfo');
- this.learnMoreDialog_ = new cr.ui.dialogs.BaseDialog(dialogContainer);
- this.learnMoreDialog_.showHtml(
- title, html, undefined, this.onLearnMoreDialogClosed_.bind(this));
- this.parentNode.disabled = true;
- },
-
- /**
- * Clean up after the Learn more dialog is closed.
- */
- onLearnMoreDialogClosed_: function() {
- this.parentNode.disabled = false;
- this.learnMoreDialog_ = undefined;
- },
-
- /**
- * Retrieves the list of keyboard layouts available for the currently
- * selected locale.
- */
- getPublicSessionKeyboardLayouts_: function() {
- var selectedLocale = this.querySelector('.language-select').value;
- if (selectedLocale ==
- this.querySelector('.keyboard-select').loadedLocale) {
- // If the list of keyboard layouts was loaded for the currently selected
- // locale, it is already up to date.
- return;
- }
- chrome.send('getPublicSessionKeyboardLayouts',
- [this.user.username, selectedLocale]);
- },
-
- /**
- * Populates the keyboard layout "select" element with a list of layouts.
- * @param {string} locale The locale to which this list of keyboard layouts
- * applies
- * @param {!Object} list List of available keyboard layouts
- */
- populateKeyboardSelect: function(locale, list) {
- if (locale != this.querySelector('.language-select').value) {
- // The selected locale has changed and the list of keyboard layouts is
- // not applicable. This method will be called again when a list of
- // keyboard layouts applicable to the selected locale is retrieved.
- return;
- }
-
- var keyboardSelect = this.querySelector('.keyboard-select');
- keyboardSelect.loadedLocale = locale;
- keyboardSelect.innerHTML = '';
- for (var i = 0; i < list.length; ++i) {
- var item = list[i];
- keyboardSelect.appendChild(
- new Option(item.title, item.value, item.selected, item.selected));
- }
- },
-
- /**
- * Populates the language "select" element with a list of locales.
- * @param {!Object} locales The list of available locales
- * @param {string} defaultLocale The locale to select by default
- * @param {boolean} multipleRecommendedLocales Whether |locales| contains
- * two or more recommended locales
- */
- populateLanguageSelect: function(
- locales, defaultLocale, multipleRecommendedLocales) {
- var languageSelect = this.querySelector('.language-select');
- // If the user manually selected a locale, do not change the selection.
- // Otherwise, select the new |defaultLocale|.
- var selected =
- languageSelect.manuallyChanged ? languageSelect.value : defaultLocale;
- languageSelect.innerHTML = '';
- var group = languageSelect;
- for (var i = 0; i < locales.length; ++i) {
- var item = locales[i];
- if (item.optionGroupName) {
- group = document.createElement('optgroup');
- group.label = item.optionGroupName;
- languageSelect.appendChild(group);
- } else {
- group.appendChild(new Option(item.title,
- item.value,
- item.value == selected,
- item.value == selected));
- }
- }
- languageSelect.multipleRecommendedLocales = multipleRecommendedLocales;
-
- // Retrieve a list of keyboard layouts applicable to the locale that is
- // now selected.
- this.getPublicSessionKeyboardLayouts_();
- },
-
- /**
- * Launches the public session with the user-selected locale and keyboard
- * layout (if available).
- * @private
- */
- enterPublicSession_: function() {
- if (this.isEnteringPublicSession_)
- return;
- this.isEnteringPublicSession_ = true;
- var locale = this.querySelector('.language-select').value;
- var keyboardSelect = this.querySelector('.keyboard-select');
- // The contents of |keyboardSelect| is updated asynchronously. If its
- // locale does not match |locale|, it has not updated yet and the
- // currently selected keyboard layout may not be applicable to |locale|.
- // Do not return any keyboard layout in this case and let the backend
- // choose a suitable layout.
- var keyboardLayout =
- keyboardSelect.loadedLocale == locale ? keyboardSelect.value : '';
- chrome.send(
- 'launchPublicSession', [this.user.username, locale, keyboardLayout]);
- }
- };
-
- /**
- * Creates a user pod to be used only in desktop chrome.
- * @constructor
- * @extends {UserPod}
- */
- var DesktopUserPod = cr.ui.define(function() {
- // Don't just instantiate a UserPod(), as this will call decorate() on the
- // parent object, and add duplicate event listeners.
- var node = $('user-pod-template').cloneNode(true);
- node.removeAttribute('id');
- return node;
- });
-
- DesktopUserPod.prototype = {
- __proto__: UserPod.prototype,
-
- /** @override */
- initialize: function() {
- if (this.user.needsSignin) {
- if (this.user.hasLocalCreds) {
- this.user.initialAuthType = AUTH_TYPE.OFFLINE_PASSWORD;
- } else {
- this.user.initialAuthType = AUTH_TYPE.ONLINE_SIGN_IN;
- }
- }
- UserPod.prototype.initialize.call(this);
- },
-
- /** @override */
- get mainInput() {
- if (this.user.needsSignin)
- return this.passwordElement;
- else
- return this.nameElement;
- },
-
- /** @override */
- update: function() {
- this.imageElement.src = this.user.userImage;
- this.smallPodImageElement.src = this.user.userImage;
- this.nameElement.textContent = this.user.displayName;
- this.smallPodNameElement.textContent = this.user.displayName;
- this.reauthNameHintElement.textContent = this.user.displayName;
-
- var isLockedUser = this.user.needsSignin;
- var isLegacySupervisedUser = this.user.legacySupervisedUser;
- var isChildUser = this.user.childUser;
- var isSyncedUser = this.user.emailAddress !== "";
- var isProfileLoaded = this.user.isProfileLoaded;
- this.classList.toggle('locked', isLockedUser);
- this.classList.toggle('legacy-supervised', isLegacySupervisedUser);
- this.classList.toggle('child', isChildUser);
- this.classList.toggle('synced', isSyncedUser);
-
- if (this.isAuthTypeUserClick)
- this.passwordLabelElement.textContent = this.authValue;
-
- this.passwordElement.setAttribute('aria-label', loadTimeData.getStringF(
- 'passwordFieldAccessibleName', this.user_.emailAddress));
-
- UserPod.prototype.updateActionBoxArea.call(this);
- },
-
- /** @override */
- activate: function(e) {
- if (!this.user.needsSignin) {
- Oobe.launchUser(this.user.profilePath);
- } else if (this.user.hasLocalCreds && !this.passwordElement.value) {
- return false;
- } else {
- chrome.send('authenticatedLaunchUser',
- [this.user.profilePath,
- this.user.emailAddress,
- this.passwordElement.value]);
- }
- this.passwordElement.value = '';
- return true;
- },
-
- /** @override */
- handleClickOnPod_: function(e) {
- if (this.parentNode.disabled)
- return;
-
- if (this.getPodStyle() != UserPod.Style.LARGE) {
- $('pod-row').switchMainPod(this);
- return;
- }
-
- Oobe.clearErrors();
- this.parentNode.lastFocusedPod_ = this;
-
- // If this is a locked pod and there are local credentials, show the
- // password field. Otherwise call activate() which will open up a browser
- // window or show the reauth dialog, as needed.
- if (!(this.user.needsSignin && this.user.hasLocalCreds) &&
- !this.isActionBoxMenuActive) {
- this.activate(e);
- }
-
- if (this.isAuthTypeUserClick)
- chrome.send('attemptUnlock', [this.user.emailAddress]);
- },
- };
-
- /**
- * Creates a new pod row element.
- * @constructor
- * @extends {HTMLDivElement}
- */
- var PodRow = cr.ui.define('podrow');
-
- PodRow.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- // Whether this user pod row is shown for the first time.
- firstShown_: true,
-
- // True if inside focusPod().
- insideFocusPod_: false,
-
- // Focused pod.
- focusedPod_: undefined,
-
- // Activated pod, i.e. the pod of current login attempt.
- activatedPod_: undefined,
-
- // Pod that was most recently focused, if any.
- lastFocusedPod_: undefined,
-
- // Pod that occupies the main spot.
- mainPod_: undefined,
-
- // Pods whose initial images haven't been loaded yet.
- podsWithPendingImages_: [],
-
- // Whether pod placement has been postponed.
- podPlacementPostponed_: false,
-
- // Standard user pod height/width.
- userPodHeight_: 0,
- userPodWidth_: 0,
-
- // Array of users that are shown (public/supervised/regular).
- users_: [],
-
- // If we're in tablet mode.
- tabletModeEnabled_: false,
-
- // If testing mode is enabled.
- testingModeEnabled_: false,
-
- // The color used by the scroll list when the user count exceeds
- // LANDSCAPE_MODE_LIMIT or PORTRAIT_MODE_LIMIT.
- overlayColors_: {maskColor: undefined, scrollColor: undefined},
-
- // Whether we should add background behind user pods.
- showPodBackground_: false,
-
- // Current UI state of the sign-in screen.
- signinUIState_: OOBE_UI_STATE.HIDDEN,
-
- /** @override */
- decorate: function() {
- // Event listeners that are installed for the time period during which
- // the element is visible.
- this.listeners_ = {
- focus: [this.handleFocus_.bind(this), true /* useCapture */],
- click: [this.handleClick_.bind(this), true],
- mousemove: [this.handleMouseMove_.bind(this), false],
- keydown: [this.handleKeyDown.bind(this), false]
- };
-
- var isDesktopUserManager = Oobe.getInstance().displayType ==
- DISPLAY_TYPE.DESKTOP_USER_MANAGER;
- var isNewDesktopUserManager = Oobe.getInstance().newDesktopUserManager;
- this.userPodHeight_ = isDesktopUserManager ?
- isNewDesktopUserManager ? MD_DESKTOP_POD_HEIGHT :
- DESKTOP_POD_HEIGHT :
- CROS_POD_HEIGHT;
- this.userPodWidth_ = isDesktopUserManager ?
- isNewDesktopUserManager ? MD_DESKTOP_POD_WIDTH :
- DESKTOP_POD_WIDTH :
- CROS_POD_WIDTH;
- },
-
- /**
- * Returns all the pods in this pod row. Some pods may not be its direct
- * children, but the caller doesn't have to know this.
- * @type {NodeList}
- */
- get pods() {
- var powRowChildren = Array.prototype.slice.call(this.children);
- var containerChildren =
- Array.prototype.slice.call(this.smallPodsContainer.children);
- return powRowChildren.concat(containerChildren);
- },
-
- /**
- * Return true if user pod row has only single user pod in it, which should
- * always be focused except desktop mode.
- * @type {boolean}
- */
- get alwaysFocusSinglePod() {
- return Oobe.getInstance().displayType !=
- DISPLAY_TYPE.DESKTOP_USER_MANAGER &&
- this.pods.length == 1;
- },
-
- /**
- * Returns pod with the given username (null if there is no such pod).
- * @param {string} username Username to be matched.
- * @return {Object} Pod with the given username. null if pod hasn't been
- * found.
- */
- getPodWithUsername_: function(username) {
- for (var i = 0, pod; pod = this.pods[i]; ++i) {
- if (pod.user.username == username)
- return pod;
- }
- return null;
- },
-
- /**
- * True if the the pod row is disabled (handles no user interaction).
- * @type {boolean}
- */
- disabled_: false,
- get disabled() {
- return this.disabled_;
- },
- set disabled(value) {
- this.disabled_ = value;
- this.pods.forEach(function(pod) {
- pod.disabled = value;
- });
- },
-
- /**
- * Creates a user pod from given email.
- * @param {!Object} user User info dictionary.
- */
- createUserPod: function(user) {
- var userPod;
- if (user.isDesktopUser)
- userPod = new DesktopUserPod({user: user});
- else if (user.publicAccount)
- userPod = new PublicAccountUserPod({user: user});
- else
- userPod = new UserPod({user: user});
-
- userPod.hidden = false;
- return userPod;
- },
-
- /**
- * Add an existing user pod to this pod row.
- * @param {!Object} user User info dictionary.
- */
- addUserPod: function(user) {
- var userPod = this.createUserPod(user);
- this.appendChild(userPod);
- userPod.initialize();
- },
-
- /**
- * Performs visual changes on the user pod if there is an error.
- * @param {boolean} visible Whether to show or hide the display.
- */
- setFocusedPodErrorDisplay: function(visible) {
- if (this.focusedPod_)
- this.focusedPod_.showError = visible;
- },
-
- /**
- * Shows or hides the pin keyboard for the current focused pod.
- * @param {boolean} visible
- */
- setFocusedPodPinVisibility: function(visible) {
- if (this.focusedPod_)
- this.focusedPod_.setPinVisibility(visible);
- },
-
- /**
- * Enables or disables the pin keyboard for the given user. A disabled pin
- * keyboard will never be displayed.
- *
- * If the user's pod is focused, then enabling the pin keyboard will display
- * it; disabling the pin keyboard will hide it.
- * @param {!string} username
- * @param {boolean} enabled
- */
- setPinEnabled: function(username, enabled) {
- var pod = this.getPodWithUsername_(username);
- if (!pod) {
- console.error('Attempt to enable/disable pin keyboard of missing pod.');
- return;
- }
-
- // Make sure to set |pinEnabled| before toggling visiblity to avoid
- // validation errors.
- pod.pinEnabled = enabled;
-
- if (this.focusedPod_ == pod) {
- if (enabled) {
- ensurePinKeyboardLoaded(
- this.setPinVisibility.bind(this, username, true));
- } else {
- this.setPinVisibility(username, false);
- }
- }
- },
-
- /**
- * Shows or hides the pin keyboard from the pod with the given |username|.
- * This is only a visibility change; the pin keyboard can be reshown.
- *
- * Use setPinEnabled if the pin keyboard should be disabled for the given
- * user.
- * @param {!user} username
- * @param {boolean} visible
- */
- setPinVisibility: function(username, visible) {
- var pod = this.getPodWithUsername_(username);
- if (!pod) {
- console.error('Attempt to show/hide pin keyboard of missing pod.');
- return;
- }
- if (visible && pod.pinEnabled === false) {
- console.error('Attempt to show disabled pin keyboard');
- return;
- }
- if (visible && this.focusedPod_ != pod) {
- console.error('Attempt to show pin keyboard on non-focused pod');
- return;
- }
-
- pod.setPinVisibility(visible);
- },
-
- /**
- * Removes user pod from pod row.
- * @param {!user} username
- */
- removeUserPod: function(username) {
- var podToRemove = this.getPodWithUsername_(username);
- if (podToRemove == null) {
- console.warn('Attempt to remove pod that does not exist');
- return;
- }
- // Its parent is not necessarily this pod row.
- podToRemove.parentNode.removeChild(podToRemove);
- this.mainPod_ = null;
- if (this.pods.length > 0) {
- // placePods_() will select a new main pod and re-append pods
- // to different parents if necessary.
- this.placePods_();
- this.maybePreselectPod();
- }
- },
-
- /**
- * Returns index of given pod or -1 if not found.
- * @param {UserPod} pod Pod to look up.
- * @private
- */
- indexOf_: function(pod) {
- for (var i = 0; i < this.pods.length; ++i) {
- if (pod == this.pods[i])
- return i;
- }
- return -1;
- },
-
- /**
- * Populates pod row with given existing users and start init animation.
- * @param {array} users Array of existing user emails.
- */
- loadPods: function(users) {
- this.users_ = users;
-
- this.rebuildPods();
- },
-
- /**
- * Current header bar UI / sign in state.
- *
- * @type {number} state Current state of the sign-in screen (see
- * OOBE_UI_STATE).
- */
- get signinUIState() {
- return this.signinUIState_;
- },
-
- set signinUIState(state) {
- this.signinUIState_ = state;
- this.rebuildPods();
- },
-
- /**
- * Rebuilds pod row using users_ that were previously set or
- * updated.
- */
- rebuildPods: function() {
- var emptyPodRow = this.pods.length == 0;
-
- // Clear existing pods.
- this.innerHTML = '';
- this.focusedPod_ = undefined;
- this.activatedPod_ = undefined;
- this.lastFocusedPod_ = undefined;
- this.mainPod_ = undefined;
- this.smallPodsContainer.innerHTML = '';
- this.topMask.innerHTML = '';
- this.bottomMask.innerHTML = '';
-
- // Switch off animation
- Oobe.getInstance().toggleClass('flying-pods', false);
-
- for (var i = 0; i < this.users_.length; ++i)
- this.addUserPod(this.users_[i]);
-
- for (var i = 0, pod; pod = this.pods[i]; ++i)
- this.podsWithPendingImages_.push(pod);
-
- // Make sure we eventually show the pod row, even if some image is stuck.
- setTimeout(function() {
- $('pod-row').classList.remove('images-loading');
- this.smallPodsContainer.classList.remove('images-loading');
- this.topMask.classList.remove('images-loading');
- this.bottomMask.classList.remove('images-loading');
- }.bind(this), POD_ROW_IMAGES_LOAD_TIMEOUT_MS);
-
- var isAccountPicker = this.signinUIState_ == OOBE_UI_STATE.ACCOUNT_PICKER;
-
- // Immediately recalculate pods layout only when current UI is account
- // picker. Otherwise postpone it.
- if (isAccountPicker) {
- this.placePods_();
- this.maybePreselectPod();
-
- // Without timeout changes in pods positions will be animated even
- // though it happened when 'flying-pods' class was disabled.
- setTimeout(function() {
- Oobe.getInstance().toggleClass('flying-pods', true);
- }, 0);
- } else {
- this.podPlacementPostponed_ = true;
- }
- },
-
- /**
- * Gets the container of small pods.
- * @type {!HTMLDivElement}
- */
- get smallPodsContainer() {
- return document.querySelector('.small-pod-container');
- },
-
- /**
- * Gets the gradient mask at the top.
- * @type {!HTMLDivElement}
- */
- get topMask() {
- return document.querySelector('.small-pod-container-mask');
- },
-
- /**
- * Gets the gradient mask at the bottom.
- * @type {!HTMLDivElement}
- */
- get bottomMask() {
- return document.querySelector('.small-pod-container-mask.rotate');
- },
-
- /**
- * Shows a custom icon on a user pod besides the input field.
- * @param {string} username Username of pod to add button
- * @param {!{id: !string,
- * hardlockOnClick: boolean,
- * isTrialRun: boolean,
- * ariaLabel: string | undefined,
- * tooltip: ({text: string, autoshow: boolean} | undefined)}} icon
- * The icon parameters.
- */
- showUserPodCustomIcon: function(username, icon) {
- var pod = this.getPodWithUsername_(username);
- if (pod == null) {
- console.error('Unable to show user pod button: user pod not found.');
- return;
- }
-
- if (!icon.id && !icon.tooltip)
- return;
-
- if (icon.id)
- pod.customIconElement.setIcon(icon.id);
-
- if (icon.isTrialRun) {
- pod.customIconElement.setInteractive(
- this.onDidClickLockIconDuringTrialRun_.bind(this, username));
- } else if (icon.hardlockOnClick) {
- pod.customIconElement.setInteractive(
- this.hardlockUserPod_.bind(this, username));
- } else {
- pod.customIconElement.setInteractive(null);
- }
-
- var ariaLabel = icon.ariaLabel || (icon.tooltip && icon.tooltip.text);
- if (ariaLabel)
- pod.customIconElement.setAriaLabel(ariaLabel);
- else
- console.warn('No ARIA label for user pod custom icon.');
-
- pod.customIconElement.show();
-
- // This has to be called after |show| in case the tooltip should be shown
- // immediatelly.
- pod.customIconElement.setTooltip(
- icon.tooltip || {text: '', autoshow: false});
-
- // Hide fingerprint icon when custom icon is shown.
- this.setUserPodFingerprintIcon(username, FINGERPRINT_STATES.HIDDEN);
- },
-
- /**
- * Hard-locks user pod for the user. If user pod is hard-locked, it can be
- * only unlocked using password, and the authentication type cannot be
- * changed.
- * @param {!string} username The user's username.
- * @private
- */
- hardlockUserPod_: function(username) {
- chrome.send('hardlockPod', [username]);
- },
-
- /**
- * Records a metric indicating that the user clicked on the lock icon during
- * the trial run for Easy Unlock.
- * @param {!string} username The user's username.
- * @private
- */
- onDidClickLockIconDuringTrialRun_: function(username) {
- chrome.send('recordClickOnLockIcon', [username]);
- },
-
- /**
- * Hides the custom icon in the user pod added by showUserPodCustomIcon().
- * @param {string} username Username of pod to remove button
- */
- hideUserPodCustomIcon: function(username) {
- var pod = this.getPodWithUsername_(username);
- if (pod == null) {
- console.error('Unable to hide user pod button: user pod not found.');
- return;
- }
-
- // TODO(tengs): Allow option for a fading transition.
- pod.customIconElement.hide();
-
- // Show fingerprint icon if applicable.
- this.setUserPodFingerprintIcon(username, FINGERPRINT_STATES.DEFAULT);
- },
-
- /**
- * Set a fingerprint icon in the user pod of |username|.
- * @param {string} username Username of the selected user
- * @param {number} state Fingerprint unlock state
- */
- setUserPodFingerprintIcon: function(username, state) {
- var pod = this.getPodWithUsername_(username);
- if (pod == null) {
- console.error(
- 'Unable to set user pod fingerprint icon: user pod not found.');
- return;
- }
- pod.fingerprintAuthenticated_ = false;
- if (!pod.fingerprintIconElement)
- return;
- if (!pod.user.allowFingerprint || state == FINGERPRINT_STATES.HIDDEN ||
- !pod.customIconElement.hidden) {
- pod.fingerprintIconElement.hidden = true;
- pod.submitButton.hidden = false;
- return;
- }
-
- FINGERPRINT_STATES_MAPPING.forEach(function(icon) {
- pod.fingerprintIconElement.classList.toggle(
- icon.class, state == icon.state);
- });
- pod.fingerprintIconElement.hidden = false;
- pod.submitButton.hidden = pod.passwordElement.value.length == 0;
- this.updatePasswordField_(pod, state);
- if (state == FINGERPRINT_STATES.DEFAULT)
- return;
-
- pod.fingerprintAuthenticated_ = true;
- this.setActivatedPod(pod);
- if (state == FINGERPRINT_STATES.FAILED) {
- /** @const */ var RESET_ICON_TIMEOUT_MS = 500;
- setTimeout(
- this.resetIconAndPasswordField_.bind(this, pod),
- RESET_ICON_TIMEOUT_MS);
- }
- },
-
- /**
- * Reset the fingerprint icon and password field.
- * @param {UserPod} pod Pod to reset.
- */
- resetIconAndPasswordField_: function(pod) {
- if (!pod.fingerprintIconElement)
- return;
- this.setUserPodFingerprintIcon(
- pod.user.username, FINGERPRINT_STATES.DEFAULT);
- },
-
- /**
- * Remove the fingerprint icon in the user pod.
- * @param {string} username Username of the selected user
- */
- removeUserPodFingerprintIcon: function(username) {
- var pod = this.getPodWithUsername_(username);
- if (pod == null) {
- console.error('No user pod found (when removing fingerprint icon).');
- return;
- }
- this.resetIconAndPasswordField_(pod);
- if (pod.fingerprintIconElement) {
- pod.fingerprintIconElement.parentNode.removeChild(
- pod.fingerprintIconElement);
- }
- pod.submitButton.hidden = false;
- },
-
- /**
- * Updates the password field in the user pod.
- * @param {UserPod} pod Pod to update.
- * @param {number} state Fingerprint unlock state
- */
- updatePasswordField_: function(pod, state) {
- FINGERPRINT_STATES_MAPPING.forEach(function(item) {
- pod.passwordElement.classList.toggle(item.class, state == item.state);
- });
- var placeholderStr = loadTimeData.getString(
- pod.isPinShown() ? 'pinKeyboardPlaceholderPinPassword' :
- 'passwordHint');
- if (state == FINGERPRINT_STATES.SIGNIN) {
- placeholderStr = loadTimeData.getString('fingerprintSigningin');
- } else if (state == FINGERPRINT_STATES.FAILED) {
- placeholderStr = loadTimeData.getString('fingerprintSigninFailed');
- }
- pod.passwordElement.placeholder = placeholderStr;
- },
-
- /**
- * Sets the authentication type used to authenticate the user.
- * @param {string} username Username of selected user
- * @param {number} authType Authentication type, must be one of the
- * values listed in AUTH_TYPE enum.
- * @param {string} value The initial value to use for authentication.
- */
- setAuthType: function(username, authType, value) {
- var pod = this.getPodWithUsername_(username);
- if (pod == null) {
- console.error('Unable to set auth type: user pod not found.');
- return;
- }
- pod.setAuthType(authType, value);
- },
-
- /**
- * Sets the state of tablet mode.
- * @param {boolean} isTabletModeEnabled
- */
- setTabletModeState: function(isTabletModeEnabled) {
- this.tabletModeEnabled_ = isTabletModeEnabled;
- this.pods.forEach(function(pod, index) {
- pod.actionBoxAreaElement.classList.toggle(
- 'forced', isTabletModeEnabled);
- if (pod.isPublicSessionPod) {
- pod.querySelector('.button-container')
- .classList.toggle('forced', isTabletModeEnabled);
- }
- });
- },
-
- /**
- * Sets whether the device is in demo mode.
- * @param {boolean} isDeviceInDemoMode
- */
- setDemoModeState: function(isDeviceInDemoMode) {
- for (let pod of this.pods) {
- if (pod.isPublicSessionPod)
- pod.skipExpandedView = isDeviceInDemoMode;
- }
- },
-
- /**
- * Updates the display name shown on a public session pod.
- * @param {string} userID The user ID of the public session
- * @param {string} displayName The new display name
- */
- setPublicSessionDisplayName: function(userID, displayName) {
- var pod = this.getPodWithUsername_(userID);
- if (pod != null)
- pod.setDisplayName(displayName);
- },
-
- /**
- * Updates the list of locales available for a public session.
- * @param {string} userID The user ID of the public session
- * @param {!Object} locales The list of available locales
- * @param {string} defaultLocale The locale to select by default
- * @param {boolean} multipleRecommendedLocales Whether |locales| contains
- * two or more recommended locales
- */
- setPublicSessionLocales: function(
- userID, locales, defaultLocale, multipleRecommendedLocales) {
- var pod = this.getPodWithUsername_(userID);
- if (pod != null) {
- pod.populateLanguageSelect(locales,
- defaultLocale,
- multipleRecommendedLocales);
- }
- },
-
- /**
- * Updates the list of available keyboard layouts for a public session pod.
- * @param {string} userID The user ID of the public session
- * @param {string} locale The locale to which this list of keyboard layouts
- * applies
- * @param {!Object} list List of available keyboard layouts
- */
- setPublicSessionKeyboardLayouts: function(userID, locale, list) {
- var pod = this.getPodWithUsername_(userID);
- if (pod != null)
- pod.populateKeyboardSelect(locale, list);
- },
-
- /**
- * Called when window was resized. The two common use cases are changing
- * screen orientation and showing the virtual keyboard.
- */
- onWindowResize: function() {
- var isAccountPicker = this.signinUIState_ == OOBE_UI_STATE.ACCOUNT_PICKER;
- if (isAccountPicker) {
- // Redo pod placement if account picker is the current screen.
- this.placePods_();
- } else {
- // Postpone pod placement. |handleBeforeShow| will check this flag.
- this.podPlacementPostponed_ = true;
- }
- },
-
- /**
- * Places pods onto their positions in pod grid matching the new design.
- * @private
- */
- placePods_: function() {
- var pods = this.pods;
- if (pods.length == 0) {
- console.error('Attempt to place pods for an empty pod list.');
- return;
- }
- // Appends all pods to their proper parents. Small pods have parent other
- // than the pod row. The pods were all initialized with the pow row as a
- // temporary parent, which is intended to ensure that all event listeners
- // work properly. If the main pod already exists, it means we are in the
- // process of resizing the window, then there is no need to change parents
- // of any pod.
- if (!this.mainPod_) {
- this.mainPod_ = this.preselectedPod;
- this.appendPodsToParents_();
- }
- this.handleBeforePodPlacement_();
-
- if (this.isScreenShrinked_()) {
- // When virtual keyboard is shown, the account picker should occupy
- // all the remaining screen. Screen size was already updated to exclude
- // the virtual keyboard.
- this.parentNode.setPreferredSize(
- this.screenSize.width, this.screenSize.height);
- } else {
- // Make sure not to block the header bar when virtual keyboard is absent.
- this.parentNode.setPreferredSize(
- Oobe.getInstance().clientAreaSize.width,
- Oobe.getInstance().clientAreaSize.height);
- }
-
- if (pods.length == 1) {
- this.placeSinglePod_();
- } else if (pods.length == POD_ROW_LIMIT) {
- this.placePodsOnPodRow_();
- } else {
- this.placePodsOnContainer_();
- }
- Oobe.getInstance().updateScreenSize(this.parentNode);
- this.handleAfterPodPlacement_();
- },
-
- /**
- * Appends pods to proper parents. Called each time before pod placement.
- * @private
- */
- appendPodsToParents_: function() {
- var pods = this.pods;
- // Pod count may have changed, so the placement method may change
- // accordingly. Therefore, always remove all pods from their current
- // parents first.
- for (var pod of pods) {
- pod.parentNode.removeChild(pod);
- }
- if (pods.length <= POD_ROW_LIMIT) {
- for (var pod of pods) {
- this.appendChild(pod);
- }
- } else {
- // When the user count exceeds the limit (currently set to 2), only the
- // main pod still has pow row as parent, all other pods should be
- // appended to the container with scroll bar.
- for (var pod of pods) {
- if (pod == this.mainPod_)
- this.appendChild(pod);
- else
- this.smallPodsContainer.appendChild(pod);
- }
- }
- },
-
- /**
- * Makes the screen unscrollable and hides the empty area underneath when
- * virtual keyboard is shown.
- * @private
- */
- hideEmptyArea_: function() {
- // When virtual keyboard is shown, although the screen size is reduced
- // properly, the size of #outer-container remains the same in order to
- // make other screens (e.g. Add person) scrollable, but this shouldn't
- // apply to account picker.
- // This is a hacky solution: we can make #scroll-container hide the
- // overflow area and manully position #inner-container.
- // NOTE: The global states set here might need to be cleared in
- // handleHide. Please update the code there when adding new stuff here.
- var isScreenShrinked = this.isScreenShrinked_();
- $('scroll-container')
- .classList.toggle('disable-scroll', isScreenShrinked);
- $('inner-container').classList.toggle('disable-scroll', isScreenShrinked);
- $('inner-container').style.top = isScreenShrinked ?
- cr.ui.toCssPx($('scroll-container').scrollTop) :
- 'unset';
- },
-
- /**
- * Called when there is one user pod.
- * @private
- */
- placeSinglePod_: function() {
- this.mainPod_.setPodStyle(UserPod.Style.LARGE);
- this.centerPod_(this.mainPod_, CROS_POD_WIDTH, CROS_POD_HEIGHT);
- },
-
- /**
- * Called when the number of pods is within the POD_ROW_LIMIT.
- * @private
- */
- placePodsOnPodRow_: function() {
- // Both pods have large size and are placed adjacently.
- var secondPod =
- this.pods[0] == this.mainPod_ ? this.pods[1] : this.pods[0];
- this.mainPod_.setPodStyle(UserPod.Style.LARGE);
- secondPod.setPodStyle(UserPod.Style.LARGE);
-
- var DOUBLE_PODS_PADDING = this.isPortraitMode_() ? 32 : 118;
- var leftPadding =
- (this.screenSize.width - (CROS_POD_WIDTH * 2 + DOUBLE_PODS_PADDING)) /
- 2;
- // Start actual positioning.
- this.mainPod_.left = leftPadding;
- this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
- secondPod.left = leftPadding + CROS_POD_WIDTH + DOUBLE_PODS_PADDING;
- secondPod.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
- },
-
- /**
- * Called when the number of pods exceeds the POD_ROW_LIMIT.
- * @private
- */
- placePodsOnContainer_: function() {
- this.smallPodsContainer.hidden = false;
- var pods = this.pods;
- if ((pods.length > LANDSCAPE_MODE_LIMIT && !this.isPortraitMode_()) ||
- (pods.length > PORTRAIT_MODE_LIMIT && this.isPortraitMode_())) {
- // If the pod count exceeds limits, they should be in extra small size
- // and the container will become scrollable.
- this.placePodsOnScrollableContainer_();
- return;
- }
- this.mainPod_.setPodStyle(UserPod.Style.LARGE);
- for (var pod of pods) {
- if (pod != this.mainPod_) {
- // All pods except the main one must be set to the small style.
- pod.setPodStyle(UserPod.Style.SMALL);
- }
- }
- // The size of the smallPodsContainer must be updated to avoid overflow.
- this.smallPodsContainer.style.height =
- cr.ui.toCssPx(this.screenSize.height);
- this.smallPodsContainer.style.width = cr.ui.toCssPx(CROS_SMALL_POD_WIDTH);
-
- var LEFT_PADDING = this.isPortraitMode_() ? 0 : 98;
- var MIDDLE_PADDING = this.isPortraitMode_() ? 84 : 220;
- var contentsWidth = LEFT_PADDING +
- CROS_POD_WIDTH + MIDDLE_PADDING + CROS_SMALL_POD_WIDTH;
- var blankWidth = this.screenSize.width - contentsWidth;
- var actualLeftPadding = LEFT_PADDING;
- actualLeftPadding +=
- this.isPortraitMode_() ? blankWidth * 2 / 3 : blankWidth / 2;
- var SMALL_POD_PADDING = 54;
- var actualSmallPodPadding = SMALL_POD_PADDING;
- var smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT +
- (pods.length - 2) * actualSmallPodPadding;
-
- // SCROLL_TOP_PADDING denotes the smallest top padding we can tolerate
- // before allowing the container to overflow and show the scroll bar.
- var SCROLL_TOP_PADDING = this.isPortraitMode_() ? 66 : 72;
- if (smallPodsTotalHeight + SCROLL_TOP_PADDING * 2 >
- this.screenSize.height) {
- // In case the contents overflow for any reason (it shouldn't if the
- // pod count is within limits), fall to the scrollable container case.
- // But before that we'll try a smaller top padding and recalculate the
- // total height if virtual keyboard is shown.
- if (this.isScreenShrinked_()) {
- actualSmallPodPadding = 32;
- smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT +
- (pods.length - 2) * actualSmallPodPadding;
- }
- // If virtual keyboard is not shown, or the updated total height still
- // exceeds screen height, fall to the scrollable container case.
- if (smallPodsTotalHeight + SCROLL_TOP_PADDING * 2 >
- this.screenSize.height) {
- this.placePodsOnScrollableContainer_();
- return;
- }
- }
-
- // Start positioning of the main pod and the smallPodsContainer.
- this.mainPod_.left = actualLeftPadding;
- this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
- this.smallPodsContainer.style.left =
- cr.ui.toCssPx(actualLeftPadding + CROS_POD_WIDTH + MIDDLE_PADDING);
- this.smallPodsContainer.style.top = cr.ui.toCssPx(0);
- // Start positioning of the small pods inside the smallPodsContainer.
- var smallPodsTopPadding =
- (this.screenSize.height - smallPodsTotalHeight) / 2;
- for (var pod of pods) {
- if (pod == this.mainPod_) {
- continue;
- }
- pod.left = 0;
- pod.top = smallPodsTopPadding;
- smallPodsTopPadding += CROS_SMALL_POD_HEIGHT + actualSmallPodPadding;
- }
- },
-
- /**
- * Called when the LANDSCAPE_MODE_LIMIT or PORTRAIT_MODE_LIMIT is exceeded
- * and the scrollable container is shown.
- * @private
- */
- placePodsOnScrollableContainer_: function() {
- this.smallPodsContainer.hidden = false;
- // Add a dark overlay.
- this.smallPodsContainer.classList.add('scroll');
- if (this.overlayColors_.scrollColor) {
- this.smallPodsContainer.style.backgroundColor =
- this.overlayColors_.scrollColor;
- }
- var pods = this.pods;
- this.mainPod_.setPodStyle(UserPod.Style.LARGE);
- for (var pod of pods) {
- if (pod != this.mainPod_) {
- // All pods except the main one must be set to the extra small style.
- pod.setPodStyle(UserPod.Style.EXTRA_SMALL);
- }
- }
-
- var SCROLL_LEFT_PADDING = this.isPortraitMode_() ? 46 : 72;
- var SCROLL_RIGHT_PADDING = this.isPortraitMode_() ? 12 : 72;
- // The offsetWidth of the smallPodsContainer.
- var scrollAreaWidth = SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH +
- SCROLL_RIGHT_PADDING;
- var mainPodPadding = (this.screenSize.width -
- scrollAreaWidth - CROS_POD_WIDTH) / 2;
- var SCROLL_TOP_PADDING = this.isPortraitMode_() ? 66 : 72;
- var EXTRA_SMALL_POD_PADDING = 32;
- // Start positioning of the main pod and the smallPodsContainer.
- this.mainPod_.left = mainPodPadding;
- this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
- this.smallPodsContainer.style.left =
- cr.ui.toCssPx(mainPodPadding * 2 + CROS_POD_WIDTH);
- this.smallPodsContainer.style.top = cr.ui.toCssPx(0);
-
- // Precalculate the total height of the scrollable container and check if
- // it indeed exceeds the screen height.
- var scrollHeight = 0;
- for (var pod of pods) {
- if (pod == this.mainPod_) {
- continue;
- }
- scrollHeight += CROS_EXTRA_SMALL_POD_HEIGHT + EXTRA_SMALL_POD_PADDING;
- }
- scrollHeight -= EXTRA_SMALL_POD_PADDING;
- // The smallPodsContainer should occupy the full screen vertically.
- this.smallPodsContainer.style.height =
- cr.ui.toCssPx(this.screenSize.height);
- this.smallPodsContainer.style.width = cr.ui.toCssPx(
- SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH +
- SCROLL_RIGHT_PADDING);
-
- // SCROLL_TOP_PADDING denotes the smallest top padding we can tolerate
- // before allowing the container to overflow and show the scroll bar.
- var actualTopPadding = SCROLL_TOP_PADDING;
- if ((this.screenSize.height - scrollHeight) / 2 > actualTopPadding) {
- // Edge case: the total height of the scrollable container does not
- // exceed the screen height (minus the neceesary padding), so the
- // scroll bar will not appear.
- // In this case, we still want to keep the extra small pod size and
- // the overlay, but the top and bottom padding should be adjusted
- // to ensure a symmetric layout.
- actualTopPadding = (this.screenSize.height - scrollHeight) / 2;
- } else if (!this.isScreenShrinked_()) {
- // The scroll bar will definitely be shown if we reach here. A gradient
- // mask is applied to avoid blocking the header bar if the virtual
- // keyboard is not shown. When the keyboard is shown, there's no need
- // to add the mask and the original top padding value should be kept.
- actualTopPadding = SCROLL_MASK_HEIGHT;
- this.showScrollMask_();
- }
-
- // Start positioning of the small pods inside the smallPodsContainer.
- var topPadding = actualTopPadding;
- var lastPod = undefined;
- for (var pod of pods) {
- if (pod == this.mainPod_) {
- continue;
- }
- pod.left = SCROLL_LEFT_PADDING;
- pod.top = topPadding;
- topPadding += CROS_EXTRA_SMALL_POD_HEIGHT + EXTRA_SMALL_POD_PADDING;
- lastPod = pod;
- }
- // Make sure the last pod has a proper bottom padding for a symmetric
- // layout.
- lastPod.style.paddingBottom = cr.ui.toCssPx(actualTopPadding);
- },
-
- /**
- * Called each time before pod placement to ensure we start with the
- * initial state, which is ready to place only one user pod. The styles
- * of elements necessary for other placement methods must be set
- * explicitly each time.
- * @private
- */
- handleBeforePodPlacement_: function() {
- this.smallPodsContainer.hidden = true;
- this.topMask.hidden = true;
- this.bottomMask.hidden = true;
- this.smallPodsContainer.classList.remove('scroll');
- if (this.overlayColors_.scrollColor)
- this.smallPodsContainer.style.backgroundColor = 'unset';
- var pods = this.pods;
- for (var pod of pods) {
- // There is a chance that one of the pods has a bottom padding, so
- // reset all of them to be safe. This is because if the pod was at
- // the last position in the scrollable container, a bottom padding
- // was added to ensure a symmetric layout.
- pod.style.paddingBottom = cr.ui.toCssPx(0);
- }
- this.hideEmptyArea_();
- // Clear error bubbles whenever pod placement is happening, i.e., after
- // orientation change, showing or hiding virtual keyboard, and user
- // removal.
- Oobe.clearErrors();
- },
-
- /**
- * Checks if the screen is in portrait mode.
- * @return {boolean} True if in portrait mode.
- */
- isPortraitMode_: function() {
- return this.screenSize.width < this.screenSize.height;
- },
-
- /**
- * Checks if the screen is shrinked, i.e., when showing virtual keyboard.
- * We used to check Oobe.getInstance().virtualKeyboardShown directly
- * but there were occasional bugs because that value may not be updated yet
- * during pod placement.
- * @return {boolean} True if the screen is shrinked.
- */
- isScreenShrinked_: function() {
- return this.screenSize.height <= Oobe.getInstance().clientAreaSize.height;
- },
-
- /**
- * Called when scroll bar is shown and we need a mask for the header bar.
- * @private
- */
- showScrollMask_: function() {
- this.topMask.hidden = false;
- this.topMask.style.left = this.smallPodsContainer.style.left;
- this.topMask.style.width = this.smallPodsContainer.style.width;
- this.bottomMask.hidden = false;
- this.bottomMask.style.left = this.smallPodsContainer.style.left;
- this.bottomMask.style.width = this.smallPodsContainer.style.width;
- // The bottom mask should overlap with the header bar, and its z-index
- // is chosen to ensure it does not block users from using the header bar.
- this.bottomMask.style.top =
- cr.ui.toCssPx(this.screenSize.height - SCROLL_MASK_HEIGHT);
- if (this.overlayColors_.maskColor) {
- var maskGradient = this.getMaskGradient_(this.overlayColors_.maskColor);
- this.topMask.style.background = maskGradient;
- this.bottomMask.style.background = maskGradient;
- }
- },
-
- /**
- * Called after pod placement and before showing the pod row. Updates
- * elements whose style may depend on the pod placement outcome.
- * @private
- */
- handleAfterPodPlacement_: function() {
- var pods = this.pods;
- for (var pod of pods) {
- if (pod.getPodStyle() != UserPod.Style.LARGE)
- continue;
- // Make sure that user name on each large pod is centered and extra
- // long names don't exceed maximum pod width.
- var nameArea = pod.querySelector('.name-container');
- var leftMargin = (CROS_POD_WIDTH - pod.nameElement.offsetWidth) / 2;
- if (leftMargin > 0) {
- nameArea.style.left = cr.ui.toCssPx(leftMargin);
- nameArea.style.right = 'auto';
- } else {
- pod.nameElement.style.width = cr.ui.toCssPx(CROS_POD_WIDTH);
- nameArea.style.left = cr.ui.toCssPx(0);
- nameArea.style.right = 'auto';
- // For public session pods whose names are cut off, add a banner
- // which shows the full name upon hovering.
- if (pod.isPublicSessionPod && !pod.querySelector('.full-name')) {
- var fullNameContainer = document.createElement('div');
- fullNameContainer.classList.add('full-name');
- fullNameContainer.textContent = pod.nameElement.textContent;
- nameArea.appendChild(fullNameContainer);
- }
- }
-
- // Update info container area for public session pods.
- if (pod.isPublicSessionPod) {
- var infoElement = pod.querySelector('.info');
- var infoIcon = pod.querySelector('.learn-more');
- var totalWidth = PUBLIC_SESSION_ICON_WIDTH + infoElement.offsetWidth;
- var infoLeftMargin = (CROS_POD_WIDTH - totalWidth) / 2;
- if (infoLeftMargin > 0) {
- infoIcon.style.left = cr.ui.toCssPx(infoLeftMargin);
- infoIcon.style.right = 'auto';
- infoElement.style.left =
- cr.ui.toCssPx(infoLeftMargin + PUBLIC_SESSION_ICON_WIDTH);
- infoElement.style.right = 'auto';
- } else {
- infoIcon.style.left = cr.ui.toCssPx(0);
- infoIcon.style.right = 'auto';
- infoElement.style.left = cr.ui.toCssPx(PUBLIC_SESSION_ICON_WIDTH);
- infoElement.style.right = 'auto';
- infoElement.style.width = cr.ui.toCssPx(
- CROS_POD_WIDTH - PUBLIC_SESSION_ICON_WIDTH -
- infoElement.style.paddingLeft);
- }
- // If the public session pod is already expanded, make sure it's
- // still centered.
- if (pod.expanded)
- this.centerPod_(pod, PUBLIC_EXPANDED_WIDTH, PUBLIC_EXPANDED_HEIGHT);
- }
-
- // Update action box menu position to ensure it doesn't overlap with
- // elements outside the pod.
- var actionBoxMenu = pod.querySelector('.action-box-menu');
- var actionBoxButton = pod.querySelector('.action-box-button');
- var MENU_TOP_PADDING = 7;
- if (this.isPortraitMode_() && pods.length > 1) {
- // Confine the menu inside the pod when it may overlap with outside
- // elements.
- actionBoxMenu.style.left = 'auto';
- actionBoxMenu.style.right = cr.ui.toCssPx(0);
- actionBoxMenu.style.top =
- cr.ui.toCssPx(actionBoxButton.offsetHeight + MENU_TOP_PADDING);
- } else if (!this.isPortraitMode_() && this.isScreenShrinked_()) {
- // Prevent the virtual keyboard from blocking the remove user button.
- actionBoxMenu.style.left = cr.ui.toCssPx(
- pod.nameElement.offsetWidth + actionBoxButton.offsetWidth);
- actionBoxMenu.style.right = 'auto';
- actionBoxMenu.style.top = cr.ui.toCssPx(0);
- } else {
- actionBoxMenu.style.left = cr.ui.toCssPx(
- pod.nameElement.offsetWidth + actionBoxButton.style.marginLeft);
- actionBoxMenu.style.right = 'auto';
- actionBoxMenu.style.top =
- cr.ui.toCssPx(actionBoxButton.offsetHeight + MENU_TOP_PADDING);
- }
-
- // Update password container width based on the visibility of the
- // custom icon container.
- pod.passwordEntryContainerElement.classList.toggle(
- 'custom-icon-shown', !pod.customIconElement.hidden);
- // Add ripple animation.
- var actionBoxRippleEffect =
- pod.querySelector('.action-box-button.ripple-circle');
- actionBoxRippleEffect.style.left = cr.ui.toCssPx(
- pod.nameElement.offsetWidth + actionBoxButton.style.marginLeft);
- actionBoxRippleEffect.style.right = 'auto';
- actionBoxRippleEffect.style.top =
- cr.ui.toCssPx(actionBoxButton.style.marginTop);
- // Adjust the vertical position of the pod if pin keyboard is shown.
- if (pod.isPinShown() && !this.isScreenShrinked_())
- pod.top = (this.screenSize.height - CROS_POD_HEIGHT_WITH_PIN) / 2;
-
- // In the end, switch direction of the above elements if right-to-left
- // language is used.
- if (isRTL()) {
- switchDirection(nameArea);
- switchDirection(actionBoxMenu);
- switchDirection(actionBoxRippleEffect);
- if (pod.isPublicSessionPod) {
- switchDirection(pod.querySelector('.info'));
- switchDirection(pod.querySelector('.learn-more'));
- }
- }
- }
- this.updateSigninBannerPosition_();
- this.togglePodBackground(this.showPodBackground_);
- },
-
- /**
- * Updates the sign-in banner position if it's shown. Called each time
- * after message update or pod placement, because the position of the
- * banner dynamically depends on the pod positions.
- * @private
- */
- updateSigninBannerPosition_: function() {
- var bannerContainer = $('signin-banner-container1');
- if (bannerContainer.hidden)
- return;
- if ($('signin-banner').classList.contains('warning')) {
- bannerContainer.style.top =
- cr.ui.toCssPx(this.mainPod_.top + CROS_POD_WARNING_BANNER_OFFSET_Y);
- } else {
- bannerContainer.style.top = cr.ui.toCssPx(this.mainPod_.top / 2);
- }
- if (this.pods.length <= POD_ROW_LIMIT) {
- bannerContainer.style.left = cr.ui.toCssPx(
- (this.screenSize.width - bannerContainer.offsetWidth) / 2);
- } else {
- var leftPadding = this.mainPod_.left -
- (bannerContainer.offsetWidth - CROS_POD_WIDTH) / 2;
- bannerContainer.style.left = cr.ui.toCssPx(Math.max(leftPadding, 0));
- }
- },
-
- /**
- * Handles required UI changes when a public session pod toggles the
- * expanded state.
- * @param {UserPod} pod Public session pod.
- * @param {boolean} expanded Whether the pod is expanded or not.
- */
- handlePublicPodExpansion: function(pod, expanded) {
- // Hide all other elements in the account picker if the pod is expanded.
- this.parentNode.classList.toggle('public-account-expanded', expanded);
- if (expanded) {
- this.centerPod_(pod, PUBLIC_EXPANDED_WIDTH, PUBLIC_EXPANDED_HEIGHT);
- } else {
- // Return the pod to its last position.
- pod.left = pod.lastPosition.left;
- pod.top = pod.lastPosition.top;
- // Pod placement has already finished by this point, but we still need
- // to make sure that the styles of all the elements in the pod row are
- // updated before being shown.
- this.handleAfterPodPlacement_();
- }
- },
-
- /**
- * Called when a pod needs to be centered.
- * @param {UserPod} pod Pod to be centered.
- * @param {number} podWidth The pod width.
- * @param {number} podHeight The pod height.
- * @private
- */
- centerPod_: function(pod, podWidth, podHeight) {
- // The original position of a public session pod is recorded in case of
- // future need.
- if (pod.isPublicSessionPod)
- pod.lastPosition = {left: pod.left, top: pod.top};
- // Avoid using offsetWidth and offsetHeight in case the pod is not fully
- // loaded yet.
- pod.left = (this.screenSize.width - podWidth) / 2;
- pod.top = (this.screenSize.height - podHeight) / 2;
- },
-
- /**
- * Toggles the animation for switching between main pod and small pod.
- * @param {UserPod} pod Pod that needs to toggle the animation.
- * @param {boolean} enabled Whether the switch animation is needed.
- * @private
- */
- toggleSwitchAnimation_: function(pod, enabled) {
- pod.imageElement.classList.toggle('switch-image-animation', enabled);
- pod.animatedImageElement.classList.toggle(
- 'switch-image-animation', enabled);
- pod.smallPodImageElement.classList.toggle(
- 'switch-image-animation', enabled);
- pod.smallPodAnimatedImageElement.classList.toggle(
- 'switch-image-animation', enabled);
- },
-
- /**
- * Called when a small or extra small pod is clicked to trigger the switch
- * with the main pod.
- * @param {UserPod} pod Pod to be switched with the main pod.
- */
- switchMainPod: function(pod) {
- if (this.disabled) {
- console.error('Cannot switch main pod while sign-in UI is disabled.');
- return;
- }
- if (!this.mainPod_) {
- console.error('Attempt to switch a non-existing main pod.');
- return;
- }
- // Find the index of the small pod.
- var insert = 0;
- var children = pod.parentNode.children;
- while (insert < children.length && children[insert] != pod)
- insert++;
- if (insert >= children.length) {
- console.error('Attempt to switch a non-existing small pod.');
- return;
- }
- // Switch style of the two pods.
- this.mainPod_.setPodStyle(pod.getPodStyle());
- pod.setPodStyle(UserPod.Style.LARGE);
- // Add switch animation.
- this.toggleSwitchAnimation_(this.mainPod_, true);
- this.toggleSwitchAnimation_(pod, true);
- setTimeout(function() {
- var pods = this.pods;
- for (var pod of pods)
- this.toggleSwitchAnimation_(pod, false);
- }.bind(this), POD_SWITCH_ANIMATION_DURATION_MS);
-
- // Switch parent and position of the two pods.
- var left = pod.left;
- var top = pod.top;
- // Edge case: paddingBottom should be switched too because there's a
- // chance that the small pod was at the end of the scrollable container
- // and had a non-zero paddingBottom.
- var paddingBottom = pod.style.paddingBottom;
- var parent = pod.parentNode;
- parent.removeChild(pod);
- this.appendChild(pod);
- pod.left = this.mainPod_.left;
- pod.top = this.mainPod_.top;
- pod.style.paddingBottom = cr.ui.toCssPx(0);
-
- this.removeChild(this.mainPod_);
- // It must have the same index with the original small pod, instead
- // of being appended as the last child, in order to maintain the tab
- // order.
- parent.insertBefore(this.mainPod_, children[insert]);
- this.mainPod_.left = left;
- this.mainPod_.top = top;
- this.mainPod_.style.paddingBottom = paddingBottom;
- this.mainPod_ = pod;
- // The new main pod should already be focused but we need a focus update
- // in order to focus on the input box.
- this.focusPod(this.mainPod_, true /* force */);
- this.handleAfterPodPlacement_();
- },
-
- /**
- * Returns dimensions of screen including the header bar.
- * @type {Object}
- */
- get screenSize() {
- var container = $('scroll-container');
- return {width: container.offsetWidth, height: container.offsetHeight};
- },
-
- /**
- * Displays a banner containing |message|. If the banner is already present
- * this function updates the message in the banner.
- * @param {string} message Text to be displayed or empty to hide the banner.
- * @param {boolean} isWarning True if the given message is a warning.
- */
- showBannerMessage: function(message, isWarning) {
- var banner = $('signin-banner');
- banner.textContent = message;
- banner.classList.toggle('message-set', !!message);
- banner.classList.toggle('warning', isWarning);
- $('signin-banner-container1').hidden = banner.textContent.length == 0;
- this.updateSigninBannerPosition_();
- },
-
- /**
- * Sets login screen overlay colors based on colors extracted from the
- * wallpaper.
- * @param {string} maskColor Color for the gradient mask.
- * @param {string} scrollColor Color for the small pods container.
- */
- setOverlayColors: function(maskColor, scrollColor) {
- if (this.smallPodsContainer.classList.contains('scroll'))
- this.smallPodsContainer.style.backgroundColor = scrollColor;
- if (!this.topMask.hidden) {
- var maskGradient = this.getMaskGradient_(maskColor);
- this.topMask.style.background = maskGradient;
- this.bottomMask.style.background = maskGradient;
- }
- // Save the colors because the scrollable container and the masks may
- // become visible later.
- this.overlayColors_.maskColor = maskColor;
- this.overlayColors_.scrollColor = scrollColor;
- },
-
- /**
- * Helper function to create a style string for the scroll masks.
- * @param {string} maskColor Color for the gradient mask.
- * @return {string} A CSS style.
- */
- getMaskGradient_: function(maskColor) {
- return 'linear-gradient(' + maskColor + ', transparent)';
- },
-
- /**
- * Toggles the background behind user pods.
- * @param {boolean} showPodBackground Whether to add background behind user
- * pods.
- */
- togglePodBackground: function(showPodBackground) {
- this.showPodBackground_ = showPodBackground;
- var pods = this.pods;
- for (var pod of pods)
- pod.classList.toggle('show-pod-background', showPodBackground);
-
- var isShowingScrollList =
- this.smallPodsContainer.classList.contains('scroll');
- if (isShowingScrollList) {
- if (showPodBackground) {
- // The scroll list should use a fixed color to make sure the pods are
- // legible.
- this.smallPodsContainer.style.backgroundColor = 'rgba(0, 0, 0, 0.9)';
- } else if (this.overlayColors_.scrollColor) {
- // Change the background back to the color extracted from wallpaper.
- this.smallPodsContainer.style.backgroundColor =
- this.overlayColors_.scrollColor;
- }
- }
- // Edge case: when we add pod background, we also need to add extra
- // padding to the pods if they are not placed on top of the scroll list.
- // The padding may result in overflow, so we allow showing overflow here.
- // An alternative is to adjust the size of the small pods container, but
- // we want to avoid changing the pod placement for this edge case.
- this.smallPodsContainer.classList.toggle(
- 'show-overflow', showPodBackground && !isShowingScrollList);
- },
-
- /**
- * Whether the pod is currently focused.
- * @param {UserPod} pod Pod to check for focus.
- * @return {boolean} Pod focus status.
- */
- isFocused: function(pod) {
- return this.focusedPod_ == pod;
- },
-
- /**
- * Focuses a given user pod or clear focus when given null.
- * @param {UserPod=} podToFocus User pod to focus (undefined clears focus).
- * @param {boolean=} opt_force If true, forces focus update even when
- * podToFocus is already focused.
- * @param {boolean=} opt_skipInputFocus If true, don't focus on the input
- * box of user pod.
- */
- focusPod: function(podToFocus, opt_force, opt_skipInputFocus) {
- if (this.isFocused(podToFocus) && !opt_force) {
- // Calling focusPod w/o podToFocus means reset.
- if (!podToFocus)
- Oobe.clearErrors();
- return;
- }
-
- // Make sure there's only one focusPod operation happening at a time.
- if (this.insideFocusPod_) {
- return;
- }
- this.insideFocusPod_ = true;
-
- for (var i = 0, pod; pod = this.pods[i]; ++i) {
- if (!this.alwaysFocusSinglePod) {
- pod.isActionBoxMenuActive = false;
- }
- if (pod != podToFocus) {
- pod.isActionBoxMenuHovered = false;
- pod.classList.remove('focused');
- pod.setPinVisibility(false);
- this.setUserPodFingerprintIcon(
- pod.user.username, FINGERPRINT_STATES.HIDDEN);
- // On Desktop, the faded style is not set correctly, so we should
- // manually fade out non-focused pods if there is a focused pod.
- if (pod.user.isDesktopUser && podToFocus)
- pod.classList.add('faded');
- else
- pod.classList.remove('faded');
- pod.reset(false);
- }
- }
-
- // Clear any error messages for previous pod.
- if (!this.isFocused(podToFocus))
- Oobe.clearErrors();
-
- this.focusedPod_ = podToFocus;
- if (podToFocus) {
- // Only show the keyboard if it is fully loaded.
- if (podToFocus.isPinReady())
- podToFocus.setPinVisibility(true);
- podToFocus.classList.remove('faded');
- podToFocus.classList.add('focused');
- if (!podToFocus.multiProfilesPolicyApplied) {
- podToFocus.classList.toggle('signing-in', false);
- if (!opt_skipInputFocus)
- podToFocus.focusInput();
- } else {
- podToFocus.userTypeBubbleElement.classList.add('bubble-shown');
- // Note it is not necessary to skip this focus request when
- // |opt_skipInputFocus| is true. When |multiProfilesPolicyApplied|
- // is false, it doesn't focus on the password input box by default.
- podToFocus.focus();
- }
-
- // Only updates wallpaper when the focused pod is in large style.
- chrome.send('focusPod', [
- podToFocus.user.username,
- podToFocus.getPodStyle() == UserPod.Style.LARGE
- ]);
- this.firstShown_ = false;
- this.lastFocusedPod_ = podToFocus;
- this.setUserPodFingerprintIcon(
- podToFocus.user.username, FINGERPRINT_STATES.DEFAULT);
- } else {
- chrome.send('noPodFocused');
- }
- this.insideFocusPod_ = false;
- },
-
- /**
- * Returns the currently activated pod.
- * @type {UserPod}
- */
- get activatedPod() {
- return this.activatedPod_;
- },
-
- /**
- * Sets currently activated pod.
- * @param {UserPod} pod Pod to check for focus.
- * @param {Event} e Event object.
- */
- setActivatedPod: function(pod, e) {
- if (this.disabled) {
- console.error('Cannot activate pod while sign-in UI is disabled.');
- return;
- }
- // If testing mode is enabled and a positive integer was entered, abort
- // the activation process and start testing mode.
- if (pod && this.testingModeEnabled_) {
- var userCount = pod.passwordElement.value;
- if (parseInt(userCount) == userCount && userCount > 0) {
- this.showDummyUsersForTesting(userCount);
- return;
- }
- }
- if (pod && pod.activate(e))
- this.activatedPod_ = pod;
- },
-
- /**
- * Used for testing only. Create the specified number of dummy users and
- * conveniently test the behaviors under different number of pods.
- * @param {number} count The number of users we want to test for.
- */
- showDummyUsersForTesting: function(count) {
- if (!this.testingModeEnabled_) {
- console.error(
- 'Attempt to create dummy users when testing mode is disabled.');
- return;
- }
- var pods = this.pods;
- for (var pod of pods)
- pod.parentNode.removeChild(pod);
- var sampleUser = this.users_[0];
- var users = [];
- for (var i = 0; i < count; i++)
- users.push(sampleUser);
-
- this.loadPods(users);
- },
-
- /**
- * The pod that is preselected on user pod row show.
- * @type {?UserPod}
- */
- get preselectedPod() {
- var isDesktopUserManager = Oobe.getInstance().displayType ==
- DISPLAY_TYPE.DESKTOP_USER_MANAGER;
- if (isDesktopUserManager) {
- // On desktop, don't pre-select a pod if it's the only one.
- if (this.pods.length == 1)
- return null;
-
- // The desktop User Manager can send an URI encoded profile path in the
- // url hash, that indicates a pod that should be initially focused.
- var focusedProfilePath =
- decodeURIComponent(window.location.hash.substr(1));
- for (var i = 0, pod; pod = this.pods[i]; ++i) {
- if (focusedProfilePath === pod.user.profilePath)
- return pod;
- }
- return null;
- }
-
- for (i = 0; pod = this.pods[i]; ++i) {
- if (!pod.multiProfilesPolicyApplied)
- return pod;
- }
- return this.pods[0];
- },
-
- /**
- * Resets input UI.
- * @param {boolean} takeFocus True to take focus.
- */
- reset: function(takeFocus) {
- this.disabled = false;
- if (this.activatedPod_)
- this.activatedPod_.reset(takeFocus);
- },
-
- /**
- * Restores input focus to current selected pod, if there is any.
- */
- refocusCurrentPod: function() {
- if (this.focusedPod_ && !this.focusedPod_.multiProfilesPolicyApplied) {
- this.focusedPod_.focusInput();
- }
- },
-
- /**
- * Clears focused pod password field.
- */
- clearFocusedPod: function() {
- if (!this.disabled && this.focusedPod_)
- this.focusedPod_.reset(true);
- },
-
- /**
- * Shows signin UI.
- * @param {string} email Email for signin UI.
- */
- showSigninUI: function(email) {
- // Clear any error messages that might still be around.
- Oobe.clearErrors();
- this.disabled = true;
- this.lastFocusedPod_ = this.getPodWithUsername_(email);
- Oobe.showSigninUI(email);
- },
-
- /**
- * Updates current image of a user.
- * @param {string} username User for which to update the image.
- */
- updateUserImage: function(username) {
- var pod = this.getPodWithUsername_(username);
- if (pod)
- pod.updateUserImage();
- },
-
- /**
- * Handler of click event.
- * @param {Event} e Click Event object.
- * @private
- */
- handleClick_: function(e) {
- if (this.disabled)
- return;
-
- // Clear all menus if the click is outside pod menu and its
- // button area.
- if (!findAncestorByClass(e.target, 'action-box-menu') &&
- !findAncestorByClass(e.target, 'action-box-area')) {
- for (var i = 0, pod; pod = this.pods[i]; ++i)
- pod.isActionBoxMenuActive = false;
- }
-
- // Clears focus if not clicked on a pod and if there's more than one pod.
- var pod = findAncestorByClass(e.target, 'pod');
- if ((!pod || pod.parentNode != this) && !this.alwaysFocusSinglePod) {
- this.focusPod();
- }
-
- if (pod && pod.getPodStyle() == UserPod.Style.LARGE)
- pod.isActionBoxMenuHovered = true;
-
- // Return focus back to single pod.
- if (this.alwaysFocusSinglePod && !pod) {
- this.focusPod(this.focusedPod_, true /* force */);
- this.focusedPod_.userTypeBubbleElement.classList.remove('bubble-shown');
- this.focusedPod_.isActionBoxMenuHovered = false;
- // If the click is outside the public session pod, still focus on it
- // but do not expand it any more.
- if (this.focusedPod_.isPublicSessionPod)
- this.focusedPod_.expanded = false;
- }
- },
-
- /**
- * Handler of mouse move event.
- * @param {Event} e Click Event object.
- * @private
- */
- handleMouseMove_: function(e) {
- if (this.disabled)
- return;
- if (e.movementX == 0 && e.movementY == 0)
- return;
-
- // Defocus (thus hide) action box, if it is focused on a user pod
- // and the pointer is not hovering over it.
- var pod = findAncestorByClass(e.target, 'pod');
- if (document.activeElement &&
- document.activeElement.parentNode != pod &&
- document.activeElement.classList.contains('action-box-area')) {
- document.activeElement.parentNode.focus();
- }
-
- if (pod)
- pod.isActionBoxMenuHovered = true;
-
- // Hide action boxes on other user pods.
- for (var i = 0, p; p = this.pods[i]; ++i)
- if (p != pod && !p.isActionBoxMenuActive)
- p.isActionBoxMenuHovered = false;
- },
-
- /**
- * Handles focus event.
- * @param {Event} e Focus Event object.
- * @private
- */
- handleFocus_: function(e) {
- if (this.disabled)
- return;
- if (e.target.parentNode == this) {
- // Handles focus event on a large pod.
- if (e.target.classList.contains('focused')) {
- // Edge case: prevent input box from receiving unncessary focus
- // (thus hiding virtual keyboard) when remove user is clicked.
- if (e.target.isActionBoxMenuActive)
- return;
- if (!e.target.multiProfilesPolicyApplied)
- e.target.focusInput();
- else
- e.target.userTypeBubbleElement.classList.add('bubble-shown');
- } else
- this.focusPod(e.target);
- return;
- }
-
- // Small pods do not have input box.
- if (e.target.parentNode == this.smallPodsContainer) {
- this.focusPod(e.target, false, true /* opt_skipInputFocus */);
- return;
- }
-
- var pod = findAncestorByClass(e.target, 'pod');
- if (pod && pod.parentNode == this) {
- // Focus on a control of a pod but not on the action area button.
- if (!pod.classList.contains('focused')) {
- if (e.target.classList.contains('action-box-area') ||
- e.target.classList.contains('remove-warning-button')) {
- // focusPod usually moves focus on the password input box which
- // triggers virtual keyboard to show up. But the focus may move to a
- // non text input element shortly by e.target.focus. Hence, a
- // virtual keyboard flicking might be observed. We need to manually
- // prevent focus on password input box to avoid virtual keyboard
- // flicking in this case. See crbug.com/396016 for details.
- this.focusPod(pod, false, true /* opt_skipInputFocus */);
- } else {
- this.focusPod(pod);
- }
- pod.userTypeBubbleElement.classList.remove('bubble-shown');
- e.target.focus();
- }
- return;
- }
-
- // Clears pod focus when we reach here. It means new focus is neither
- // on a pod nor on a button/input for a pod.
- // Do not "defocus" user pod when it is a single pod.
- // That means that 'focused' class will not be removed and
- // input field/button will always be visible.
- if (!this.alwaysFocusSinglePod)
- this.focusPod();
- else {
- // Hide user-type-bubble in case this is one pod and we lost focus of
- // it.
- this.focusedPod_.userTypeBubbleElement.classList.remove('bubble-shown');
- }
- },
-
- /**
- * Handler of keydown event.
- * @param {Event} e KeyDown Event object.
- */
- handleKeyDown: function(e) {
- if (this.disabled)
- return;
- var editing = e.target.tagName == 'INPUT' && e.target.value;
- switch (e.key) {
- case 'ArrowLeft':
- if (!editing) {
- if (this.focusedPod_ && this.focusedPod_.previousElementSibling)
- this.focusPod(this.focusedPod_.previousElementSibling);
- else
- this.focusPod(this.lastElementChild);
-
- e.stopPropagation();
- }
- break;
- case 'ArrowRight':
- if (!editing) {
- if (this.focusedPod_ && this.focusedPod_.nextElementSibling)
- this.focusPod(this.focusedPod_.nextElementSibling);
- else
- this.focusPod(this.firstElementChild);
-
- e.stopPropagation();
- }
- break;
- case 'Enter':
- // Keydown events on public session pods should only be handled by
- // their own handler.
- if (this.focusedPod_ && !this.focusedPod_.isPublicSessionPod) {
- var targetTag = e.target.tagName;
- if (e.target == this.focusedPod_.passwordElement ||
- (this.focusedPod_.pinKeyboard &&
- e.target == this.focusedPod_.pinKeyboard.inputElement) ||
- (targetTag != 'INPUT' &&
- targetTag != 'BUTTON' &&
- targetTag != 'A')) {
- this.setActivatedPod(this.focusedPod_, e);
- e.stopPropagation();
- }
- }
- break;
- case 'Escape':
- if (!this.alwaysFocusSinglePod)
- this.focusPod();
- break;
- }
- if (this.isValidInPassword(e.key)) {
- if (!this.focusedPod_ && this.mainPod_) {
- // If no pod is being focused, and a valid password key is entered,
- // move focus to the input field of the main pod. The key will be
- // treated as the first character of the password. Please note: when
- // the focus is on the header bar (excluding the status tray area),
- // this will also move focus to the main pod.
- this.focusPod(this.mainPod_);
- } else if (this.focusedPod_) {
- // If there's a focused pod but its input field is not focused (e.g.
- // when dropdown menu is shown, or crbug.com/725622), move focus to
- // the input field which will treat the key as password. This is a
- // no-op for small pods, or if the input field is already focused.
- this.focusedPod_.focusInput();
- }
- }
- },
-
- /**
- * Returns true if the key can be used in a valid password.
- * @param {string} key The character to check.
- * @return {boolean}
- */
- isValidInPassword: function(key) {
- // Passwords can consist of any ASCII characters per the guideline:
- // https://support.google.com/a/answer/33386. However we'll limit to
- // only alphanumeric and some special characters that we are sure won't
- // conflict with other keyboard events.
- // TODO(wzang): This should ideally be kept in sync with the requirements
- // set by the backend.
- if (key.length != 1)
- return false;
- return key.charCodeAt(0) > 31 && key.charCodeAt(0) < 127;
- },
-
- /**
- * Called right after the pod row is shown.
- */
- handleAfterShow: function() {
- var focusedPod = this.focusedPod_;
-
- // Without timeout changes in pods positions will be animated even though
- // it happened when 'flying-pods' class was disabled.
- setTimeout(function() {
- Oobe.getInstance().toggleClass('flying-pods', true);
- if (focusedPod)
- ensureTransitionEndEvent(focusedPod);
- }, 0);
-
- // Force input focus for user pod on show and once transition ends.
- if (focusedPod) {
- var screen = this.parentNode;
- var self = this;
- focusedPod.addEventListener('transitionend', function f(e) {
- focusedPod.removeEventListener('transitionend', f);
- focusedPod.reset(true);
- // Notify screen that it is ready.
- screen.onShow();
- });
- }
- },
-
- /**
- * Called right before the pod row is shown.
- */
- handleBeforeShow: function() {
- Oobe.getInstance().toggleClass('flying-pods', false);
- for (var event in this.listeners_) {
- this.ownerDocument.addEventListener(
- event, this.listeners_[event][0], this.listeners_[event][1]);
- }
- if (this.podPlacementPostponed_) {
- this.podPlacementPostponed_ = false;
- this.placePods_();
- this.maybePreselectPod();
- }
-
- this.handleAfterPodPlacement_();
- },
-
- /**
- * Called when the element is hidden.
- */
- handleHide: function() {
- for (var event in this.listeners_) {
- this.ownerDocument.removeEventListener(
- event, this.listeners_[event][0], this.listeners_[event][1]);
- }
-
- // Clear global states that should only applies to account picker.
- $('scroll-container').classList.remove('disable-scroll');
- $('inner-container').classList.remove('disable-scroll');
- $('inner-container').style.top = 'unset';
- },
-
- /**
- * Called when a pod's user image finishes loading.
- */
- handlePodImageLoad: function(pod) {
- var index = this.podsWithPendingImages_.indexOf(pod);
- if (index == -1) {
- return;
- }
-
- this.podsWithPendingImages_.splice(index, 1);
- if (this.podsWithPendingImages_.length == 0) {
- this.classList.remove('images-loading');
- this.smallPodsContainer.classList.remove('images-loading');
- this.topMask.classList.remove('images-loading');
- this.bottomMask.classList.remove('images-loading');
- }
- },
-
- /**
- * Preselects pod, if needed.
- */
- maybePreselectPod: function() {
- var pod = this.preselectedPod;
- // Force a focus update to ensure the correct wallpaper is loaded.
- this.focusPod(pod, true /* force */);
-
- // Hide user-type-bubble in case all user pods are disabled and we focus
- // first pod.
- if (pod && pod.multiProfilesPolicyApplied) {
- pod.userTypeBubbleElement.classList.remove('bubble-shown');
- }
- }
- };
-
- return {
- PodRow: PodRow
- };
-});
diff --git a/chromium/ui/login/account_picker/chromeos_user_pod_template.css b/chromium/ui/login/account_picker/chromeos_user_pod_template.css
deleted file mode 100644
index aa243ec6615..00000000000
--- a/chromium/ui/login/account_picker/chromeos_user_pod_template.css
+++ /dev/null
@@ -1,34 +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.
- *
- * This is the stylesheet imported into the style module in
- * chromeos_user_pod_template.html.
- */
-
-cr-icon-button {
- --cr-icon-button-fill-color: var(--google-grey-refresh-500);
- cursor: default;
- margin: 0;
-}
-
-.action-box-remove-user-warning .remove-warning-button {
- background: transparent;
- border: none;
- box-shadow: none;
- color: #e66a5e; /* Google dark red 500 */
- cursor: default;
- padding: 4px;
-}
-
-.action-box-remove-user-warning .remove-warning-button:not(:active):focus {
- font-weight: bold;
-}
-
-/* TODO(crbug.com/814922): Merge most of these with the default values. */
-pin-keyboard {
- --pin-keyboard-backspace-opacity: 1;
- --pin-keyboard-backspace-color: #FFF;
- --pin-keyboard-letter-color: rgba(255, 255, 255, .34);
- --pin-keyboard-number-color: #FFF;
-}
diff --git a/chromium/ui/login/account_picker/chromeos_user_pod_template.html b/chromium/ui/login/account_picker/chromeos_user_pod_template.html
deleted file mode 100644
index 2ca9526aa62..00000000000
--- a/chromium/ui/login/account_picker/chromeos_user_pod_template.html
+++ /dev/null
@@ -1,257 +0,0 @@
-<dom-module id="user-pod-template-shared-styles">
- <template>
- <link rel="stylesheet" href="chromeos_user_pod_template.css">
- </template>
-</dom-module>
-
-<custom-style>
- <style is="custom-style" include="user-pod-template-shared-styles"></style>
-</custom-style>
-
-<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
-<link rel="import" href="chrome://resources/cr_elements/icons.html">
-
-<iron-iconset-svg name="user-pod" size="24">
- <svg>
- <defs>
- <!--
- Inlined from Polymer's iron-icons to avoid importing everything.
- See http://goo.gl/Y1OdAq for instructions on adding additional icons.
- -->
- <g id="arrow-forward"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"></path></g>
- <g id="dropdown" stroke="none" stroke-width="1" fill-rule="evenodd">
- <polygon points="16.59 8.59 12 13.17 7.41 8.59 6 10 12 16 18 10"></polygon>
- </g>
- <g id="legacy-supervised-badge">
- <path d="M16.5,13.5 C17.42,13.5 18.16,12.7533333 18.16,11.8333333 C18.16,10.9133333 17.42,10.1666667 16.5,10.1666667 C15.58,10.1666667 14.8333333,10.9133333 14.8333333,11.8333333 C14.8333333,12.7533333 15.58,13.5 16.5,13.5 Z M11.5,12.8333333 C12.6066667,12.8333333 13.4933333,11.94 13.4933333,10.8333333 C13.4933333,9.72666667 12.6066667,8.83333333 11.5,8.83333333 C10.3933333,8.83333333 9.5,9.72666667 9.5,10.8333333 C9.5,11.94 10.3933333,12.8333333 11.5,12.8333333 Z M16.5,14.8333333 C15.28,14.8333333 12.8333333,15.4466667 12.8333333,16.6666667 L12.8333333,18.1666667 L20.1666667,18.1666667 L20.1666667,16.6666667 C20.1666667,15.4466667 17.72,14.8333333 16.5,14.8333333 Z M11.5,14.1666667 C9.94666667,14.1666667 6.83333333,14.9466667 6.83333333,16.5 L6.83333333,18.1666667 L11.5,18.1666667 L11.5,16.6666667 C11.5,16.1 11.72,15.1066667 13.08,14.3533333 C12.5,14.2333333 11.94,14.1666667 11.5,14.1666667 Z" id="Shape" fill="#000000" fill-rule="nonzero" opacity="0.34"></path>
- </g>
- <g id="caps-lock">
- <path d="M2.5,4.49188419 C2.5,3.39179693 3.39339733,2.5 4.49188419,2.5 L15.5081158,2.5 C16.6082031,2.5 17.5,3.39339733 17.5,4.49188419 L17.5,15.5081158 C17.5,16.6082031 16.6066027,17.5 15.5081158,17.5 L4.49188419,17.5 C3.39179693,17.5 2.5,16.6066027 2.5,15.5081158 L2.5,4.49188419 Z M10,7.47368421 L13.825,11.5 L15,10.2631579 L10,5 L5,10.2631579 L6.175,11.5 L10,7.47368421 Z M5,15 L15,15 L15,13.5 L5,13.5 L5,15 Z" id="Combined-Shape" fill="#FFFFFF"></path>
- </g>
- <g id="public-session-icon">
- <path d="M16,17 L18,17 L18,15 L16,15 L16,17 Z M16,13 L18,13 L18,11 L16,11 L16,13 Z M20,19 L12,19 L12,17 L14,17 L14,15 L12,15 L12,13 L14,13 L14,11 L12,11 L12,9 L20,9 L20,19 Z M8,7 L10,7 L10,5 L8,5 L8,7 Z M8,11 L10,11 L10,9 L8,9 L8,11 Z M8,15 L10,15 L10,13 L8,13 L8,15 Z M8,19 L10,19 L10,17 L8,17 L8,19 Z M4,7 L6,7 L6,5 L4,5 L4,7 Z M4,11 L6,11 L6,9 L4,9 L4,11 Z M4,15 L6,15 L6,13 L4,13 L4,15 Z M4,19 L6,19 L6,17 L4,17 L4,19 Z M12,7 L12,3 L2,3 L2,21 L22,21 L22,7 L12,7 Z" id="Page-1" fill="#FFFFFF"></path>
- </g>
- </defs>
- </svg>
-</iron-iconset-svg>
-
-<div id="user-pod-template" class="pod disabled" hidden>
- <div class="large-pod">
- <div class="pod-background"></div>
- <div class="user-image-pane">
- <div class="user-image-container">
- <img class="user-image" alt>
- <img class="user-image animated-image" alt>
- </div>
- <div class="badge-container">
- <iron-icon class="legacy-supervised-badge"
- icon="user-pod:legacy-supervised-badge">
- </iron-icon>
- </div>
- </div>
-<if expr="chromeos">
- <div class="pin-container pin-disabled pin-tag">
- <pin-keyboard enable-password hide-input enable-placeholder
- enable-letters>
- </pin-keyboard>
- </div>
-</if>
- <div class="main-pane">
- <div class="auth-container">
- <!-- Password Authentication -->
- <div class="custom-icon-container" hidden></div>
-<if expr="chromeos">
- <div class="fingerprint-icon-container" hidden
- aria-label="$i18n{fingerprintIconMessage}">
- <div class="custom-icon fingerprint-icon-image"></div>
- </div>
-</if>
- <div class="password-entry-container">
- <div class="password-container">
- <input type="password" class="password"
- placeholder="$i18n{passwordHint}">
- </div>
-<if expr="chromeos">
- <div class="capslock-hint-container">
- <iron-icon class="capslock-hint" icon="user-pod:caps-lock">
- </iron-icon>
- </div>
- <cr-icon-button class="submit-button" disabled
- aria-label="$i18n{submitButtonAccessibleName}"
- iron-icon="user-pod:arrow-forward" tabindex="-1"></cr-icon-button>
-</if>
- </div>
- <!-- User Click Authentication -->
- <div class="password-label"></div>
- <div class="signin-transition-container">
- <span class="signing-in-label">$i18n{signingIn}</span>
- <span class="animated-ellipsis-component0">.</span>
- <span class="animated-ellipsis-component1">.</span>
- <span class="animated-ellipsis-component2">.</span>
- </div>
- <div class="reauth-hint-container">
- <span class="reauth-warning"></span>
- <span class="reauth-name-hint"></span>
- </div>
- <div class="input-line">
- <svg>
- <line x1="0" y1="0" x2="204" y2="0">
- </svg>
- </div>
- </div>
- <div class="name-container">
- <div class="name"></div>
- <div class="action-box-area">
- <cr-icon-button class="action-box-button"
- iron-icon="user-pod:dropdown"></cr-icon-button>
- <div class="action-box-button ripple-circle"></div>
- <iron-icon icon="cr:more-vert" class="action-box-icon"></iron-icon>
- </div>
- <div class="action-box-menu">
- <div class="action-box-menu-title">
- <span class="action-box-menu-title-name"></span>
- <span class="action-box-menu-title-email"></span>
- </div>
- <div class="action-box-menu-remove">
- $i18n{removeUserWarningButtonTitle}
- </div>
- <div class="action-box-remove-user-warning" hidden>
- <div class="action-box-remove-user-warning-text"></div>
- <table class="action-box-remove-user-warning-table-nonsync
- non-sync has-stats">
- <tbody>
- <tr>
- <td>$i18n{removeUserWarningTextHistory}</td>
- <td class="action-box-remove-user-warning-history
- action-box-remove-user-warning-table-numbers">
- $i18n{removeUserWarningTextCalculating}
- </td>
- </tr>
- <tr>
- <td>$i18n{removeUserWarningTextPasswords}</td>
- <td class="action-box-remove-user-warning-passwords
- action-box-remove-user-warning-table-numbers">
- $i18n{removeUserWarningTextCalculating}
- </td>
- </tr>
- <tr>
- <td>$i18n{removeUserWarningTextBookmarks}</td>
- <td class="action-box-remove-user-warning-bookmarks
- action-box-remove-user-warning-table-numbers">
- $i18n{removeUserWarningTextCalculating}
- </td>
- </tr>
- <tr>
- <td>$i18n{removeUserWarningTextAutofill}</td>
- <td class="action-box-remove-user-warning-autofill
- action-box-remove-user-warning-table-numbers">
- $i18n{removeUserWarningTextCalculating}
- </td>
- </tr>
- </tbody>
- </table>
- <div class="action-box-remove-legacy-supervised-user-warning-text">
- $i18n{removeLegacySupervisedUserWarningText}
- </div>
- <div class="action-box-remove-non-owner-user-warning-text"></div>
- <!-- cr-button is imported inside user_manager.html -->
- <cr-button class="remove-warning-button action-button" noink>
- $i18n{removeUserWarningButtonTitle}
- </cr-button>
- </div>
- </div>
- </div>
- <div class="public-account-info-container">
- <iron-icon class="learn-more" icon="user-pod:public-session-icon">
- </iron-icon>
- <div class="info"></div>
- <div class="button-container">
- <cr-icon-button class="public-account-submit-button expand-button"
- aria-label="$i18n{submitButtonAccessibleName}"
- iron-icon="user-pod:arrow-forward" tabindex="-1"></cr-icon-button>
- </div>
- </div>
- </div>
- <div class="user-image-gradient-area">
- </div>
- <div class="user-type-icon-area" hidden>
- <div class="custom-appearance user-type-icon-image"></div>
- </div>
- <div class="user-type-bubble">
- <div class="user-type-bubble-header">
- <span class="mp-policy-title">
- $i18n{multiProfilesRestrictedPolicyTitle}
- </span>
- </div>
- <div class="user-type-bubble-body">
- <span class="mp-policy-not-allowed-msg" hidden>
- $i18n{multiProfilesNotAllowedPolicyMsg}
- </span>
- <span class="mp-policy-primary-only-msg" hidden>
- $i18n{multiProfilesPrimaryOnlyPolicyMsg}
- </span>
- <span class="mp-owner-primary-only-msg" hidden>
- $i18n{multiProfilesOwnerPrimaryOnlyMsg}
- </span>
- </div>
- </div>
- </div>
- <div class="small-pod" hidden>
- <div class="pod-background"></div>
- <div class="small-user-image-container">
- <img class="user-image small-pod-image" alt>
- <img class="user-image small-pod-image animated-image"
- alt>
- </div>
- <div class="small-pod-name"></div>
- </div>
-</div>
-
-<!-- Extra elements that are appended to above "user-pod-template" for public
- account user pod. Note that only the children of the template div are
- appended. -->
-<div id="public-account-user-pod-extras-template" hidden>
- <div class="expanded-pane">
- <div class="expanded-pane-container">
- <div class="monitoring-container">
- <span class="monitoring-warning">
- $i18n{publicAccountMonitoringWarning}
- </span>
- <a class="monitoring-learn-more" href="#" role="button">
- $i18n{publicAccountLearnMore}
- </a>
- </div>
- <div class="reminder">$i18n{publicAccountReminder}</div>
- <div class="language-and-input-container">
- <a class="language-and-input" href="#" role="button">
- $i18n{publicSessionLanguageAndInput}
- </a>
- <cr-icon-button class="language-and-input-dropdown"
- iron-icon="user-pod:dropdown"></cr-icon-button>
- </div>
- </div>
- <div class="language-and-input-section">
- <div class="select-with-label">
- <label class="language-select-label">
- $i18n{publicSessionSelectLanguage}
- </label>
- <div class="select-container">
- <select class="language-select"></select>
- </div>
- </div>
- <div class="select-with-label">
- <label class="keyboard-select-label">
- $i18n{publicSessionSelectKeyboard}
- </label>
- <div class="select-container">
- <select class="keyboard-select"></select>
- </div>
- </div>
- </div>
- <div class="enter-button-container">
- <cr-icon-button class="public-account-submit-button enter-button"
- aria-label="$i18n{publicAccountEnterAccessibleName}"
- iron-icon="user-pod:arrow-forward"></cr-icon-button>
- </div>
- </div>
-</div>
diff --git a/chromium/ui/login/account_picker/screen_account_picker.css b/chromium/ui/login/account_picker/screen_account_picker.css
deleted file mode 100644
index e3dd4617293..00000000000
--- a/chromium/ui/login/account_picker/screen_account_picker.css
+++ /dev/null
@@ -1,74 +0,0 @@
-/* Copyright 2014 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-.account-picker.flying-pods #account-picker {
- transition: width 180ms ease, height 180ms ease;
-}
-
-#bubble {
- z-index: 1;
-}
-
-#signin-banner-container1 {
- bottom: 100%;
- margin-bottom: 10px;
- position: absolute;
- width: 100%;
-}
-
-html[screen=login] #signin-banner-container1 {
- margin-bottom: 6px;
-}
-
-#signin-banner-container2 {
- display: inline-block;
- position: relative;
- right: -50%;
-}
-
-html[dir=rtl] #signin-banner-container2 {
- left: -50%;
- right: auto;
-}
-
-#signin-banner {
- background-color: rgba(0, 0, 0, 0.75);
- border-radius: 4px;
- color: whitesmoke;
- display: none;
- left: -50%;
- max-width: 722px;
- padding: 20px;
- position: relative;
- text-align: center;
- width: max-content;
-}
-
-html[dir=rtl] #signin-banner {
- left: auto;
- right: -50%;
-}
-
-html[screen=user-adding] #signin-banner {
- display: inline-block;
-}
-
-html[screen=login] #signin-banner {
- padding: 20px 24px;
-}
-
-html[screen=login] #signin-banner,
-html[screen=lock] #signin-banner {
- display: inline-block;
- opacity: 0;
- visibility: hidden;
-}
-
-html[screen=login] #signin-banner.message-set,
-html[screen=lock] #signin-banner.message-set {
- opacity: 1;
- transition: opacity 1s;
- visibility: visible;
-}
diff --git a/chromium/ui/login/account_picker/screen_account_picker.html b/chromium/ui/login/account_picker/screen_account_picker.html
deleted file mode 100644
index 0d0544766f7..00000000000
--- a/chromium/ui/login/account_picker/screen_account_picker.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<div id="account-picker" class="step faded hidden no-logo" hidden>
- <div id="signin-banner-container1">
- <div id="signin-banner-container2">
- <div id="signin-banner">$i18n{signinBannerText}</div>
- </div>
- </div>
- <podrow id="pod-row" class="podrow images-loading"></podrow>
-</div>
diff --git a/chromium/ui/login/account_picker/screen_account_picker.js b/chromium/ui/login/account_picker/screen_account_picker.js
deleted file mode 100644
index 5a79cfdc142..00000000000
--- a/chromium/ui/login/account_picker/screen_account_picker.js
+++ /dev/null
@@ -1,403 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Account picker screen implementation.
- */
-
-login.createScreen('AccountPickerScreen', 'account-picker', function() {
- /**
- * Maximum number of offline login failures before online login.
- * @type {number}
- * @const
- */
- var MAX_LOGIN_ATTEMPTS_IN_POD = 3;
-
- /**
- * Distance between error bubble and user POD.
- * @type {number}
- * @const
- */
- var BUBBLE_POD_OFFSET = 4;
-
- return {
- EXTERNAL_API: [
- 'loadUsers',
- 'updateUserImage',
- 'setCapsLockState',
- 'removeUser',
- 'showBannerMessage',
- 'showUserPodCustomIcon',
- 'hideUserPodCustomIcon',
- 'setUserPodFingerprintIcon',
- 'removeUserPodFingerprintIcon',
- 'setPinEnabledForUser',
- 'setAuthType',
- 'setTabletModeState',
- 'setPublicSessionDisplayName',
- 'setPublicSessionLocales',
- 'setPublicSessionKeyboardLayouts',
- ],
-
- preferredWidth_: 0,
- preferredHeight_: 0,
-
- // Whether this screen is shown for the first time.
- firstShown_: true,
-
- // Whether this screen is currently being shown.
- showing_: false,
-
- /** @override */
- decorate: function() {
- login.PodRow.decorate($('pod-row'));
- },
-
- /** @override */
- getPreferredSize: function() {
- return {width: this.preferredWidth_, height: this.preferredHeight_};
- },
-
- /** @override */
- onWindowResize: function() {
- $('pod-row').onWindowResize();
-
- // Reposition the error bubble, if it is showing. Since we are just
- // moving the bubble, the number of login attempts tried doesn't matter.
- var errorBubble = $('bubble');
- if (errorBubble && !errorBubble.hidden)
- this.showErrorBubble(0, undefined /* Reuses the existing message. */);
- },
-
- /**
- * Sets preferred size for account picker screen.
- */
- setPreferredSize: function(width, height) {
- this.preferredWidth_ = width;
- this.preferredHeight_ = height;
- },
-
- /* Cancel user adding if ESC was pressed.
- */
- cancel: function() {
- if (Oobe.getInstance().displayType == DISPLAY_TYPE.USER_ADDING)
- chrome.send('cancelUserAdding');
- },
-
- /**
- * Event handler that is invoked just after the frame is shown.
- * @param {string} data Screen init payload.
- */
- onAfterShow: function(data) {
- $('pod-row').handleAfterShow();
- },
-
- /**
- * Event handler that is invoked just before the frame is shown.
- * @param {string} data Screen init payload.
- */
- onBeforeShow: function(data) {
- this.showing_ = true;
- chrome.send('loginUIStateChanged', ['account-picker', true]);
- $('login-header-bar').signinUIState = OOBE_UI_STATE.ACCOUNT_PICKER;
- // Header bar should be always visible on Account Picker screen.
- chrome.send('hideCaptivePortal');
- var podRow = $('pod-row');
- podRow.handleBeforeShow();
-
- // In case of the preselected pod onShow will be called once pod
- // receives focus.
- if (!podRow.preselectedPod)
- this.onShow();
- },
-
- /**
- * Event handler invoked when the page is shown and ready.
- */
- onShow: function() {
- if (!this.showing_) {
- // This method may be called asynchronously when the pod row finishes
- // initializing. However, at that point, the screen may have been
- // hidden again already. If that happens, ignore the onShow() call.
- return;
- }
- chrome.send('getTabletModeState');
- if (!this.firstShown_)
- return;
- this.firstShown_ = false;
-
- // Ensure that login is actually visible.
- window.requestAnimationFrame(function() {
- chrome.send('accountPickerReady');
- chrome.send('loginVisible', ['account-picker']);
- });
- },
-
- /**
- * Event handler that is invoked just before the frame is hidden.
- */
- onBeforeHide: function() {
- $('pod-row').clearFocusedPod();
- this.showing_ = false;
- chrome.send('loginUIStateChanged', ['account-picker', false]);
- $('login-header-bar').signinUIState = OOBE_UI_STATE.HIDDEN;
- $('pod-row').handleHide();
- },
-
- /**
- * Shows sign-in error bubble.
- * @param {number} loginAttempts Number of login attemps tried.
- * @param {HTMLElement} content Content to show in bubble.
- */
- showErrorBubble: function(loginAttempts, error) {
- var activatedPod = $('pod-row').activatedPod;
- if (!activatedPod) {
- $('bubble').showContentForElement(
- $('pod-row'), cr.ui.Bubble.Attachment.RIGHT, error);
- return;
- }
- // Show web authentication if this is not a supervised user.
- if (loginAttempts > MAX_LOGIN_ATTEMPTS_IN_POD &&
- !activatedPod.user.supervisedUser) {
- chrome.send(
- 'maxIncorrectPasswordAttempts', [activatedPod.user.emailAddress]);
- activatedPod.showSigninUI();
- } else {
- if (loginAttempts == 1) {
- chrome.send(
- 'firstIncorrectPasswordAttempt',
- [activatedPod.user.emailAddress]);
- }
- // Update the pod row display if incorrect password.
- $('pod-row').setFocusedPodErrorDisplay(true);
-
- /** @const */ var BUBBLE_OFFSET = 25;
- // -8 = 4(BUBBLE_POD_OFFSET) - 2(bubble margin)
- // - 10(internal bubble adjustment)
- var bubblePositioningPadding = -8;
-
- var bubbleAnchor;
- var attachment;
- if (activatedPod.pinContainer &&
- activatedPod.pinContainer.style.visibility == 'visible') {
- // Anchor the bubble to the input field.
- bubbleAnchor =
- (activatedPod.getElementsByClassName('auth-container'))[0];
- if (!bubbleAnchor) {
- console.error('auth-container not found!');
- bubbleAnchor = activatedPod.mainInput;
- }
- attachment = cr.ui.Bubble.Attachment.RIGHT;
- } else {
- // Anchor the bubble to the pod instead of the input.
- bubbleAnchor = activatedPod;
- attachment = cr.ui.Bubble.Attachment.BOTTOM;
- }
-
- var bubble = $('bubble');
-
- // Cannot use cr.ui.LoginUITools.get* on bubble until it is attached to
- // the element. getMaxHeight/Width rely on the correct up/left element
- // side positioning that doesn't happen until bubble is attached.
- var maxHeight = cr.ui.LoginUITools.getMaxHeightBeforeShelfOverlapping(
- bubbleAnchor) -
- bubbleAnchor.offsetHeight - BUBBLE_POD_OFFSET;
- var maxWidth = cr.ui.LoginUITools.getMaxWidthToFit(bubbleAnchor) -
- bubbleAnchor.offsetWidth - BUBBLE_POD_OFFSET;
-
- // Change bubble visibility temporary to calculate height.
- var bubbleVisibility = bubble.style.visibility;
- bubble.style.visibility = 'hidden';
- bubble.hidden = false;
- // Now we need the bubble to have the new content before calculating
- // size. Undefined |error| == reuse old content.
- if (error !== undefined)
- bubble.replaceContent(error);
-
- // Get bubble size.
- var bubbleOffsetHeight = parseInt(bubble.offsetHeight);
- var bubbleOffsetWidth = parseInt(bubble.offsetWidth);
- // Restore attributes.
- bubble.style.visibility = bubbleVisibility;
- bubble.hidden = true;
-
- if (attachment == cr.ui.Bubble.Attachment.BOTTOM) {
- // Move error bubble if it overlaps the shelf.
- if (maxHeight < bubbleOffsetHeight)
- attachment = cr.ui.Bubble.Attachment.TOP;
- } else {
- // Move error bubble if it doesn't fit screen.
- if (maxWidth < bubbleOffsetWidth) {
- bubblePositioningPadding = 2;
- attachment = cr.ui.Bubble.Attachment.LEFT;
- }
- }
- var showBubbleCallback = function() {
- activatedPod.removeEventListener(
- 'transitionend', showBubbleCallback);
- $('bubble').showContentForElement(
- bubbleAnchor, attachment, error, BUBBLE_OFFSET,
- bubblePositioningPadding, true);
- };
- activatedPod.addEventListener('transitionend', showBubbleCallback);
- ensureTransitionEndEvent(activatedPod);
- }
- },
-
- /**
- * Loads given users in pod row.
- * @param {array} users Array of user.
- * @param {boolean} showGuest Whether to show guest session button.
- */
- loadUsers: function(users, showGuest) {
- $('pod-row').loadPods(users);
- $('login-header-bar').showGuestButton = showGuest;
- // On Desktop, #login-header-bar has a shadow if there are 8+ profiles.
- if (Oobe.getInstance().displayType == DISPLAY_TYPE.DESKTOP_USER_MANAGER)
- $('login-header-bar').classList.toggle('shadow', users.length > 8);
- },
-
- /**
- * Updates current image of a user.
- * @param {string} username User for which to update the image.
- */
- updateUserImage: function(username) {
- $('pod-row').updateUserImage(username);
- },
-
- /**
- * Updates Caps Lock state (for Caps Lock hint in password input field).
- * @param {boolean} enabled Whether Caps Lock is on.
- */
- setCapsLockState: function(enabled) {
- $('pod-row').classList.toggle('capslock-on', enabled);
- },
-
- /**
- * Remove given user from pod row if it is there.
- * @param {string} user name.
- */
- removeUser: function(username) {
- $('pod-row').removeUserPod(username);
- },
-
- /**
- * Displays a banner containing |message|. If the banner is already present
- * this function updates the message in the banner. This function is used
- * by the chrome.screenlockPrivate.showMessage API.
- * @param {string} message Text to be displayed or empty to hide the
- * banner.
- * @param {boolean} isWarning True if the given message is a warning.
- */
- showBannerMessage: function(message, isWarning) {
- var banner = $('signin-banner');
- banner.textContent = message;
- banner.classList.toggle('message-set', !!message);
- },
-
- /**
- * Shows a custom icon in the user pod of |username|. This function
- * is used by the chrome.screenlockPrivate API.
- * @param {string} username Username of pod to add button
- * @param {!{id: !string,
- * hardlockOnClick: boolean,
- * isTrialRun: boolean,
- * tooltip: ({text: string, autoshow: boolean} | undefined)}}
- * icon The icon parameters.
- */
- showUserPodCustomIcon: function(username, icon) {
- $('pod-row').showUserPodCustomIcon(username, icon);
- },
-
- /**
- * Hides the custom icon in the user pod of |username| added by
- * showUserPodCustomIcon(). This function is used by the
- * chrome.screenlockPrivate API.
- * @param {string} username Username of pod to remove button
- */
- hideUserPodCustomIcon: function(username) {
- $('pod-row').hideUserPodCustomIcon(username);
- },
-
- /**
- * Set a fingerprint icon in the user pod of |username|.
- * @param {string} username Username of the selected user
- * @param {number} state Fingerprint unlock state
- */
- setUserPodFingerprintIcon: function(username, state) {
- $('pod-row').setUserPodFingerprintIcon(username, state);
- },
-
- /**
- * Removes the fingerprint icon in the user pod of |username|.
- * @param {string} username Username of the selected user.
- */
- removeUserPodFingerprintIcon: function(username) {
- $('pod-row').removeUserPodFingerprintIcon(username);
- },
-
- /**
- * Sets the authentication type used to authenticate the user.
- * @param {string} username Username of selected user
- * @param {number} authType Authentication type, must be a valid value in
- * the AUTH_TYPE enum in user_pod_row.js.
- * @param {string} value The initial value to use for authentication.
- */
- setAuthType: function(username, authType, value) {
- $('pod-row').setAuthType(username, authType, value);
- },
-
- /**
- * Sets the state of tablet mode.
- * @param {boolean} isTabletModeEnabled true if the mode is on.
- */
- setTabletModeState: function(isTabletModeEnabled) {
- $('pod-row').setTabletModeState(isTabletModeEnabled);
- },
-
- /**
- * Enables or disables the pin keyboard for the given user. This may change
- * pin keyboard visibility.
- * @param {!string} user
- * @param {boolean} enabled
- */
- setPinEnabledForUser: function(user, enabled) {
- $('pod-row').setPinEnabled(user, enabled);
- },
-
- /**
- * Updates the display name shown on a public session pod.
- * @param {string} userID The user ID of the public session
- * @param {string} displayName The new display name
- */
- setPublicSessionDisplayName: function(userID, displayName) {
- $('pod-row').setPublicSessionDisplayName(userID, displayName);
- },
-
- /**
- * Updates the list of locales available for a public session.
- * @param {string} userID The user ID of the public session
- * @param {!Object} locales The list of available locales
- * @param {string} defaultLocale The locale to select by default
- * @param {boolean} multipleRecommendedLocales Whether |locales| contains
- * two or more recommended locales
- */
- setPublicSessionLocales: function(
- userID, locales, defaultLocale, multipleRecommendedLocales) {
- $('pod-row').setPublicSessionLocales(
- userID, locales, defaultLocale, multipleRecommendedLocales);
- },
-
- /**
- * Updates the list of available keyboard layouts for a public session pod.
- * @param {string} userID The user ID of the public session
- * @param {string} locale The locale to which this list of keyboard layouts
- * applies
- * @param {!Object} list List of available keyboard layouts
- */
- setPublicSessionKeyboardLayouts: function(userID, locale, list) {
- $('pod-row').setPublicSessionKeyboardLayouts(userID, locale, list);
- },
- };
-});
diff --git a/chromium/ui/login/account_picker/user_pod_row.css b/chromium/ui/login/account_picker/user_pod_row.css
deleted file mode 100644
index c58d1524910..00000000000
--- a/chromium/ui/login/account_picker/user_pod_row.css
+++ /dev/null
@@ -1,1017 +0,0 @@
-/* Copyright 2014 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * This is the stylesheet used by user pods row of account picker UI.
- */
-
-podrow {
- /* Temporarily disabled because animation interferes with updating screen's
- size. */
- height: 100%;
- overflow: visible;
- position: absolute;
- width: 100%;
-}
-
-/* Hide the pod row while images are loading. */
-podrow.images-loading {
- visibility: hidden;
-}
-
-pin-keyboard {
- display: block;
-}
-
-.pod {
- -webkit-tap-highlight-color: transparent;
- background-color: white;
- border-radius: 2px;
- box-shadow: 0 4px 23px 5px rgba(0, 0, 0, 0.2),
- 0 2px 6px rgba(0, 0, 0, 0.15),
- 0 3px 0 rgba(0, 0, 0, 0.08);
- cursor: pointer;
- height: 213px;
- outline: none;
- position: absolute;
- top: 0;
- transform: scale3d(0.9, 0.9, 0.9);
- width: 180px;
- z-index: 0;
-}
-
-.account-picker.flying-pods .pod {
- transition: all 180ms;
-}
-
-.pod.pin-enabled {
- height: 417px;
- top: -87px !important;
-}
-
-.pod .pin-container {
- height: 204px;
- position: absolute;
- top: 170px;
-}
-
-.pod.faded {
- opacity: .75;
-}
-
-podrow[ncolumns='6'] .pod {
- transform: scale3d(0.8, 0.8, 0.8);
-}
-
-.pod.focused {
- /* Focused pod has the same size no matter how many pods. */
- cursor: default;
- transform: scale3d(1, 1, 1) !important;
- z-index: 1;
-}
-
-.pod.focused[auth-type='userClick'] {
- cursor: pointer;
-}
-
-.user-image-pane {
- background-color: white;
- height: 160px;
- left: 10px;
- position: absolute;
- top: 10px;
- transition: height 180ms ease-in-out,
- left 180ms ease-in-out,
- right 180ms ease-in-out,
- top 180ms ease-in-out,
- width 180ms ease-in-out;
- width: 160px;
- z-index: 3;
-}
-
-html[dir=rtl] .user-image-pane {
- left: auto;
- right: 10px;
-}
-
-.user-image-container {
- align-items: center;
- display: flex;
- height: 100%;
- justify-content: center;
- width: 100%;
-}
-
-.pod .user-image {
- flex: none;
-}
-
-.pod.focused .user-image {
- display: none;
-}
-
-.pod .animated-image {
- display: none;
-}
-
-.pod.focused .animated-image {
- display: block;
-}
-
-/* TODO(noms): Refactor this out into a CrOS-specific file and simplify the
- style rule once it is included on CrOS only. crbug.com/397638 */
-html:not([screen=login-add-user]) .pod .user-image {
- max-height: 160px;
- max-width: 160px;
- opacity: 0.7;
- position: absolute;
-}
-
-html:not([screen=login-add-user]) .pod.focused .user-image {
- opacity: 1;
-}
-
-.pod.multiprofiles-policy-applied .user-image {
- -webkit-filter: grayscale(100%);
-}
-
-.signed-in-indicator {
- display: none;
-}
-
-.pod.signed-in .signed-in-indicator {
- background-color: rgba(0, 0, 0, 0.5);
- color: white;
- display: block;
- font-size: small;
- position: absolute;
- text-align: center;
- top: 0;
- width: 100%;
-}
-
-.main-pane {
- left: 10px;
- position: absolute;
- top: 10px;
- z-index: 2;
-}
-
-html[dir=rtl] .main-pane {
- left: auto;
- right: 10px;
-}
-
-.name-container,
-.pod.focused:not(.multiprofiles-policy-applied) .auth-container {
- background-color: white;
- display: flex;
- position: absolute;
- top: 160px;
-/* On chromeos we extend the width to cover the padding on the user pods. This
- is so the submit button on chromeos can extend onto the padding as shown on
- mocks. */
-<if expr="not chromeos">
- width: 160px;
-</if>
-<if expr="chromeos">
- width: 170px;
-</if>
-}
-
-.auth-container .submit-button[disabled] {
- --cr-icon-button-fill-color: #000;
- opacity: 0.26;
-}
-
-.auth-container .submit-button {
- --cr-icon-button-fill-color: var(--google-blue-500);
- --cr-icon-button-icon-size: 22px;
- --cr-icon-button-size: 43px;
- position: relative;
-}
-
-.auth-container .submit-button.error-shown {
- --cr-icon-button-fill-color: #CD2A00;
-}
-
-.name-container {
- transition: transform 180ms;
-}
-
-.pod.focused .name-container {
- display: none;
-}
-
-.pod.focused.multiprofiles-policy-applied .name-container {
- display: flex;
-}
-
-.name {
- color: #565656;
- /* This should be 15.6px - the equivalent of 14px at 90% scale. */
- flex: auto;
- font-size: 16px;
- margin-top: 12px;
- outline: none;
- overflow: hidden;
- padding: 0 6px;
- text-align: center;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.learn-more-container,
-.auth-container,
-.password-entry-container,
-.reauth-hint-container {
- display: none;
-}
-
-.pod[is-active-directory] .reauth-warning {
- display: none;
-}
-
-.pod[auth-type='offlinePassword'].focused .password-entry-container,
-.pod[auth-type='forceOfflinePassword'].focused .password-entry-container {
- display: flex;
- flex: auto;
-}
-
-.password-container {
- flex: auto;
-}
-
-.pod input[type='password'] {
- background-color: white;
- border: none;
- padding: 4px 6px;
- position: relative;
- top: 6px;
- width: 100%;
-}
-
-.capslock-hint-container {
- display: none;
-}
-
-<if expr="chromeos">
-.capslock-on .capslock-hint-container {
- display: block;
- flex: none;
- height: 43px;
- position: relative;
- width: 20px;
-}
-</if>
-
-.capslock-hint {
- -webkit-margin-end: 6px;
- -webkit-margin-start: -2px;
- margin: auto;
- position: relative;
- top: 15px;
-}
-
-.password-label,
-.signin-transition-container {
- display: none;
-}
-
-.pod[auth-type='userClick']:not(.signing-in) .password-label,
-.pod[auth-type='userClick'].signing-in .signin-transition-container {
- color: grey;
- display: block;
- flex: auto;
- margin-top: 11px;
- outline: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.custom-icon {
- -webkit-margin-end: 0;
- -webkit-margin-start: auto;
- background-position: center;
- background-repeat: no-repeat;
- flex: none;
- height: 27px;
- margin: 8px 0;
- width: 27px;
-}
-
-.custom-icon.faded {
- transition: opacity 200ms ease-in-out, visibility 200ms ease-in-out;
-}
-
-.custom-icon-hardlocked {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED);
-}
-
-.custom-icon-hardlocked.icon-with-tooltip:hover {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_HOVER);
-}
-
-.custom-icon-hardlocked.interactive-custom-icon:active {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_PRESSED);
-}
-
-.custom-icon-locked {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_LOCKED);
-}
-
-.custom-icon-locked.icon-with-tooltip:hover {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_HOVER);
-}
-
-.custom-icon-locked.interactive-custom-icon:active {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_PRESSED);
-}
-
-.custom-icon-locked-to-be-activated {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED);
-}
-
-.custom-icon-locked-to-be-activated.icon-with-tooltip:hover {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_HOVER);
-}
-
-.custom-icon-locked-to-be-activated.interactive-custom-icon:active {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_PRESSED);
-}
-
-.custom-icon-locked-with-proximity-hint {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT);
-}
-
-.custom-icon-locked-with-proximity-hint.icon-with-tooltip:hover {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT_HOVER);
-}
-
-.custom-icon-locked-with-proximity-hint.interactive-custom-icon:active {
- background-image:
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT_PRESSED);
-}
-
-.custom-icon-unlocked {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED);
-}
-
-.custom-icon-unlocked.icon-with-tooltip:hover {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_HOVER);
-}
-
-.custom-icon-unlocked.interactive-custom-icon:active {
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_PRESSED);
-}
-
-/**
- * Preloads resources for custom icon. Without this, the resources will be
- * loaded when CSS properties using them are first applied, which has visible
- * delay and may cause a short white flash when the icon background changes.
- */
-.custom-icon::after {
- content:
- url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED)
- url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_HOVER)
- url(chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_PRESSED)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_HOVER)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_PRESSED)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_HOVER)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_PRESSED)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT_HOVER)
- url(chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT_PRESSED)
- url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED)
- url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_HOVER)
- url(chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_PRESSED);
- display: none;
-}
-
-.custom-icon-spinner {
- animation: easy-unlock-spinner-animation 2s steps(45) infinite;
- background-image: url(chrome://theme/IDR_EASY_UNLOCK_SPINNER);
-}
-
-@keyframes easy-unlock-spinner-animation {
- from { background-position: 0 }
- to { background-position: -1215px }
-}
-
-.interactive-custom-icon {
- cursor: pointer;
-}
-
-.pod[auth-type='onlineSignIn'] .custom-icon-container {
- display: none;
-}
-
-.fingerprint-icon-container,
-.custom-icon-container {
- display: flex;
- flex: none;
- flex-direction: column;
- height: 43px;
- width: 27px;
-}
-
-.pod[auth-type='onlineSignIn'] .reauth-hint-container {
- display: flex;
- justify-content: center;
- margin-top: 8px;
- width: 100%;
-}
-
-.reauth-hint-container .reauth-warning {
- -webkit-mask-image: url(../../../ui/webui/resources/images/warning.svg);
- -webkit-mask-position: center;
- -webkit-mask-repeat: no-repeat;
- -webkit-mask-size: 20px;
- background-color: #f4b400;
- height: 24px;
- width: 24px;
-}
-
-.reauth-hint-container .reauth-name-hint {
- align-self: center;
- color: #565656;
- font-size: 16px;
- outline: none;
- overflow: hidden;
- padding: 0 6px;
- text-align: center;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.action-box-area,
-.user-type-icon-area {
- background-color: white;
- border-radius: 2px;
- position: absolute;
- top: 0;
-}
-
-.action-box-area {
- opacity: 0;
- outline: none;
- right: 0;
- transition: opacity 100ms;
- z-index: 4;
-}
-
-html[dir=rtl] .action-box-area {
- left: 0;
- right: auto;
-}
-
-.action-box-area:focus,
-.action-box-area.hovered,
-.action-box-area.active,
-.action-box-area.forced {
- opacity: 1;
-}
-
-.action-box-button {
- --cr-icon-button--icon-size: 13px;
- --cr-icon-button-size: 29px;
- background-image: url(chrome://theme/IDR_OOBE_ACTION_BOX_BUTTON_NORMAL);
- margin: 5px;
-}
-
-.action-box-button:hover {
- background-image: url(chrome://theme/IDR_OOBE_ACTION_BOX_BUTTON_HOVER);
-}
-
-.action-box-area.active .action-box-button {
- background-image: url(chrome://theme/IDR_OOBE_ACTION_BOX_BUTTON_PRESSED);
-}
-
-.action-box-area .action-box-icon {
- /* overriden in chrome/browser/resources/user_manager/user_manager.css */
- display: none;
-}
-
-.user-image-gradient-area {
- /* overriden in chrome/browser/resources/user_manager/user_manager.css */
- display: none;
-}
-
-.user-type-icon-area {
- left: 0;
- z-index: 5;
-}
-
-html[dir=rtl] .user-type-icon-area {
- left: auto;
- right: 0;
-}
-
-.user-type-icon-image {
- height: 16px;
- margin: 5px;
- width: 16px;
-}
-
-.user-type-icon-area.legacySupervised .user-type-icon-image {
- background-image: url(../../webui/resources/images/supervisor_account.svg);
- background-size: 18px;
-}
-
-.user-type-icon-area.child .user-type-icon-image {
- background-image: url(../../webui/resources/images/account_child_invert.svg);
- background-size: 18px;
-}
-
-.user-type-icon-area.policy .user-type-icon-image {
- background-image: url(../../webui/resources/images/business.svg);
- background-size: 18px;
-}
-
-.user-type-icon-area.app .user-type-icon-image {
- background-image: url(chrome://theme/IDR_KIOSK_APP_USER_POD_ICON);
-}
-
-.fingerprint-icon-container.hidden {
- display: none;
-}
-
-.fingerprint-icon-container.default .fingerprint-icon-image {
- background-image: url(../../webui/resources/images/fingerprint_default.svg);
-}
-
-.fingerprint-icon-container.default:hover .fingerprint-icon-image {
- background-image: url(../../webui/resources/images/fingerprint_signin.svg);
-}
-
-.fingerprint-icon-container.signin .fingerprint-icon-image {
- background-image: url(../../webui/resources/images/fingerprint_signin.svg);
-}
-
-.fingerprint-icon-container.failed .fingerprint-icon-image {
- background-image: url(../../webui/resources/images/icon_error_outline.svg);
-}
-
-.pod input[type='password'].hidden::-webkit-input-placeholder {
- color: grey;
-}
-
-.pod input[type='password'].default::-webkit-input-placeholder {
- color: grey;
-}
-
-.pod input[type='password'].signin::-webkit-input-placeholder {
- color: var(--google-blue-500);
-}
-
-.pod input[type='password'].failed::-webkit-input-placeholder {
- color: var(--google-red-500);
-}
-
-.action-box-menu {
- display: none;
- z-index: 6;
-}
-
-.action-box-area.active ~ .action-box-menu {
- background-color: white;
- border: 1px solid lightgray;
- border-radius: 2px;
- display: flex;
- flex-direction: column;
- font-size: 13px;
- position: absolute;
- right: 5px;
- width: 220px;
-}
-
-.action-box-area.active ~ .action-box-menu.left-edge-offset {
- left: 0 !important;
-}
-
-.action-box-area.active ~ .action-box-menu.right-edge-offset {
- right: 0 !important;
-}
-
-.action-box-area.active ~ .action-box-menu:not(.menu-moved-up) {
- top: 18px;
-}
-
-.action-box-area.active ~ .action-box-menu.menu-moved-up {
- bottom: 207px;
-}
-
-.action-box-area.menu-moved-up {
- transform: rotate(180deg);
-}
-
-html[dir=rtl] .action-box-area.active ~ .action-box-menu {
- left: 5px;
- right: auto;
-}
-
-.action-box-menu-title {
- color: #757575;
- display: flex;
- flex-direction: column;
- padding: 7px 20px;
-}
-
-.action-box-menu-title:focus {
- outline-style: none;
-}
-
-.action-box-menu-title-name,
-.action-box-menu-title-email {
- flex: none;
- height: 23px;
- line-height: 19px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.action-box-menu-remove {
- border-top: 1px solid lightgray;
- line-height: 19px;
- min-height: 24px;
- outline: none;
- padding: 12px 20px 7px;
-}
-
-.action-box-menu-remove:hover,
-.action-box-menu-remove:focus {
- background-color: #f3f3f3;
-}
-
-.action-box-remove-user-warning {
- border-top: 1px solid lightgray;
- font-size: 12px;
- line-height: 18px;
- padding: 20px;
-}
-
-.action-box-remove-user-warning > div,
-.action-box-remove-user-warning > table {
- padding-bottom: 20px;
-}
-
-.total-count {
- font-weight: bold;
-}
-
-.action-box-remove-user-warning-table-nonsync {
- border-spacing: 0;
- width: 100%;
-}
-
-.action-box-remove-user-warning-table td {
- padding: 0;
-}
-
-.action-box-remove-user-warning-table-numbers {
- color: #757575;
- text-align: end;
-}
-
-/* Hide dialog elements not in a correct category. Only combinations currently
- in use are included here. */
-.pod.legacy-supervised .non-sync,
-.pod.legacy-supervised .action-box-remove-user-warning-text,
-.pod.legacy-supervised .action-box-remove-non-owner-user-warning-text,
-.pod:not(.legacy-supervised)
- .action-box-remove-legacy-supervised-user-warning-text,
-.pod.synced .non-sync {
- display: none;
-}
-
-.user-type-bubble {
- background-color: white;
- border: 1px solid lightgray;
- border-radius: 2px;
- left: 5px;
- opacity: 0;
- padding: 17px;
- position: absolute;
- top: 20px;
- transition: all 100ms;
- visibility: hidden;
- width: 200px;
- z-index: 7;
-}
-
-html[dir=rtl] .user-type-bubble {
- left: auto;
- right: 5px;
-}
-
-.bubble-shown,
-.user-type-icon-area.policy:hover ~ .user-type-bubble {
- opacity: 1;
- visibility: visible;
-}
-
-.user-type-bubble-header {
- font-weight: bold;
- margin-bottom: 14px;
-}
-
-/**** Public account user pod rules *******************************************/
-
-.pod.public-account.expanded {
- height: 230px;
- width: 500px;
-}
-
-.pod.public-account.expanded.advanced {
- height: 280px;
- width: 610px;
-}
-
-.pod.public-account.focused .name-container {
- display: flex;
-}
-
-.pod.public-account.expanded .name-container {
- display: none;
-}
-
-.pod.public-account .learn-more-container {
- display: block;
- flex: none;
-}
-
-.pod.public-account .learn-more {
- top: 22px;
-}
-
-.expanded-pane {
- display: none;
-}
-
-.pod.public-account.animating .expanded-pane,
-.pod.public-account.expanded .expanded-pane {
- display: block;
- font-size: 12px;
- margin: 10px;
- overflow: hidden;
- z-index: 1;
-}
-
-.expanded-pane-contents {
- display: flex;
- flex-direction: column;
- float: right;
- height: 213px;
- width: 490px;
-}
-
-.pod.public-account.transitioning-to-advanced .expanded-pane-contents {
- transition: width 180ms;
-}
-
-.pod.public-account.expanded.advanced .expanded-pane-contents {
- height: 263px;
- width: 600px;
-}
-
-html[dir=rtl] .expanded-pane-contents {
- float: left;
-}
-
-.side-container {
- -webkit-margin-start: 200px;
- flex: auto;
-}
-
-.expanded-pane-name {
- font-size: 19px;
- margin-bottom: 11px;
- margin-top: -2px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.expanded-pane-container {
- color: grey;
-}
-
-.reminder {
- margin-top: 20px;
-}
-
-.language-and-input-section {
- display: none;
-}
-
-.pod.public-account.transitioning-to-advanced .language-and-input-section {
- display: block;
- opacity: 0;
- transition: opacity 180ms ease 180ms;
-}
-
-.pod.public-account.expanded.advanced .language-and-input-section {
- display: block;
- opacity: 1;
-}
-
-.select-with-label {
- display: flex;
- margin-top: 20px;
-}
-
-.language-select-label,
-.keyboard-select-label {
- flex: none;
- margin-top: 3px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- width: 170px;
-}
-
-.select-container {
- flex: auto;
-}
-
-.language-select,
-.keyboard-select {
- width: 100%;
-}
-
-.bottom-container {
- -webkit-margin-start: 20px;
- align-items: center;
- display: flex;
- flex-direction: row-reverse;
- flex: none;
- font-size: 13px;
- justify-content: space-between;
- margin-bottom: 4px;
-}
-
-.expanded-pane-learn-more-container,
-.enter-button {
- flex: none;
-}
-
-.expanded-pane-learn-more,
-.pod.public-account .learn-more {
- background-image: url(../../webui/resources/images/business.svg);
- background-size: 18px;
- height: 18px;
- margin-top: -10px;
- position: relative;
- width: 18px;
-}
-
-.expanded-pane-learn-more {
- top: 5px;
-}
-
-.info {
- flex: auto;
- margin: -10px 25px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.monitoring-container {
- margin-top: 35px;
-}
-
-.monitoring-learn-more {
- color: rgb(49, 106, 197);
- text-decoration: none;
-}
-
-.monitoring-dialog-container .cr-dialog-shield {
- background: black;
- opacity: 0.5;
-}
-
-.monitoring-dialog-container .cr-dialog-buttons {
- display: none;
-}
-
-.monitoring-dialog-container .cr-dialog-frame {
- height: 170px;
- left: -46px;
- padding: 0px;
- position: relative;
- top: -24px;
- width: 430px;
-}
-
-.monitoring-dialog-container.advanced .cr-dialog-frame {
- left: -110px;
- top: 0px;
-}
-
-.monitoring-dialog-container .cr-dialog-close {
- color: grey;
- height: 34px;
- position: absolute;
- top: 0px;
- width: 34px;
-}
-
-.monitoring-dialog-container .cr-dialog-title {
- font-size: 16px;
- font-weight: bold;
- left: 20px;
- position: absolute;
- top: 15px;
-}
-
-.monitoring-dialog-container .cr-dialog-text {
- color: grey;
- font-size: 13px;
- overflow: visible;
- position: absolute;
- top: 20px;
-}
-
-.monitoring-dialog-container .cr-dialog-item {
- -webkit-margin-start: 42px;
- display: list-item;
- margin-bottom: -6px;
-}
-
-.language-and-input-container {
- -webkit-margin-end: 25px;
- flex: none;
-}
-
-.language-and-input {
- color: rgb(49, 106, 197);
- text-decoration: none;
-}
-
-.pod.public-account.expanded.advanced .language-and-input-container {
- display: none;
-}
-
-.enter-button {
- background-color: rgb(66, 133, 244);
- color: white;
- font-size: 12px;
- text-transform: none;
-}
-
-.enter-button.keyboard-focus {
- font-weight: normal;
-}
-
-.horizontal-line {
- border-bottom: 1px double #cccccc;
- bottom: 8px;
- position: relative;
-}
-
-/* Animations for the animated ellipsis: */
-.animated-ellipsis-component0 {
- animation: ellipsis-component0 1.5s infinite;
-}
-
-@keyframes ellipsis-component0 {
- 0% { opacity: 0; }
- 25% { opacity: 1; }
- 50% { opacity: 1; }
- 75% { opacity: 1; }
- 100% { opacity: 0; }
-}
-
-.animated-ellipsis-component1 {
- animation: ellipsis-component1 1.5s infinite;
-}
-
-@keyframes ellipsis-component1 {
- 0% { opacity: 0; }
- 25% { opacity: 0; }
- 50% { opacity: 1; }
- 75% { opacity: 1; }
- 100% { opacity: 0; }
-}
-
-.animated-ellipsis-component2 {
- animation: ellipsis-component2 1.5s infinite;
-}
-
-@keyframes ellipsis-component2 {
- 0% { opacity: 0; }
- 25% { opacity: 0; }
- 50% { opacity: 0; }
- 75% { opacity: 1; }
- 100% { opacity: 0; }
-}
diff --git a/chromium/ui/login/account_picker/user_pod_row.js b/chromium/ui/login/account_picker/user_pod_row.js
deleted file mode 100644
index e79739d5dda..00000000000
--- a/chromium/ui/login/account_picker/user_pod_row.js
+++ /dev/null
@@ -1,3656 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview User pod row implementation.
- */
-
-cr.define('login', function() {
- /**
- * Number of displayed columns depending on user pod count.
- * @type {Array<number>}
- * @const
- */
- var COLUMNS = [0, 1, 2, 3, 4, 5, 4, 4, 4, 5, 5, 6, 6, 5, 5, 6, 6, 6, 6];
-
- /**
- * Mapping between number of columns in pod-row and margin between user pods
- * for such layout.
- * @type {Array<number>}
- * @const
- */
- var MARGIN_BY_COLUMNS = [undefined, 40, 40, 40, 40, 40, 12];
-
- /**
- * Mapping between number of columns in the desktop pod-row and margin
- * between user pods for such layout.
- * @type {Array<number>}
- * @const
- */
- var DESKTOP_MARGIN_BY_COLUMNS = [undefined, 32, 32, 32, 32, 32, 32];
-
- /**
- * Maximal number of columns currently supported by pod-row.
- * @type {number}
- * @const
- */
- var MAX_NUMBER_OF_COLUMNS = 6;
-
- /**
- * Maximal number of rows if sign-in banner is displayed alonside.
- * @type {number}
- * @const
- */
- var MAX_NUMBER_OF_ROWS_UNDER_SIGNIN_BANNER = 2;
-
- /**
- * Variables used for pod placement processing. Width and height should be
- * synced with computed CSS sizes of pods.
- */
- var CROS_POD_WIDTH = 180;
- var DESKTOP_POD_WIDTH = 180;
- var MD_DESKTOP_POD_WIDTH = 160;
- var PUBLIC_EXPANDED_BASIC_WIDTH = 500;
- var PUBLIC_EXPANDED_ADVANCED_WIDTH = 610;
- var CROS_POD_HEIGHT = 213;
- var DESKTOP_POD_HEIGHT = 226;
- var MD_DESKTOP_POD_HEIGHT = 200;
- var POD_ROW_PADDING = 10;
- var DESKTOP_ROW_PADDING = 32;
- var CUSTOM_ICON_CONTAINER_SIZE = 40;
- var CROS_PIN_POD_HEIGHT = 417;
-
- /**
- * Minimal padding between user pod and virtual keyboard.
- * @type {number}
- * @const
- */
- var USER_POD_KEYBOARD_MIN_PADDING = 20;
-
- /**
- * Maximum time for which the pod row remains hidden until all user images
- * have been loaded.
- * @type {number}
- * @const
- */
- var POD_ROW_IMAGES_LOAD_TIMEOUT_MS = 3000;
-
- /**
- * Tab order for user pods. Update these when adding new controls.
- * @enum {number}
- * @const
- */
- var UserPodTabOrder = {
- POD_INPUT: 1, // Password input field, Action box menu button and
- // the pod itself.
- PIN_KEYBOARD: 2, // Pin keyboard below the password input field.
- POD_CUSTOM_ICON: 3, // Pod custom icon next to password input field.
- HEADER_BAR: 4, // Buttons on the header bar (Shutdown, Add User).
- POD_MENU_ITEM: 5 // User pad menu items (User info, Remove user).
- };
-
- /**
- * Supported authentication types. Keep in sync with the enum in
- * components/proximity_auth/public/interfaces/auth_type.mojom
- * @enum {number}
- * @const
- */
- var AUTH_TYPE = {
- OFFLINE_PASSWORD: 0,
- ONLINE_SIGN_IN: 1,
- USER_CLICK: 2,
- EXPAND_THEN_USER_CLICK: 3,
- FORCE_OFFLINE_PASSWORD: 4
- };
-
- /**
- * Names of authentication types.
- */
- var AUTH_TYPE_NAMES = {
- 0: 'offlinePassword',
- 1: 'onlineSignIn',
- 2: 'userClick',
- 3: 'expandThenUserClick',
- 4: 'forceOfflinePassword'
- };
-
- /**
- * Supported fingerprint unlock states.
- * @enum {number}
- * @const
- */
- var FINGERPRINT_STATES = {
- HIDDEN: 0,
- DEFAULT: 1,
- SIGNIN: 2,
- FAILED: 3,
- };
-
- /**
- * The fingerprint states to classes mapping.
- * {@code state} properties indicate current fingerprint unlock state.
- * {@code class} properties are CSS classes used to set the icons' background
- * and password placeholder color.
- * @const {Array<{type: !number, class: !string}>}
- */
- var FINGERPRINT_STATES_MAPPING = [
- {state: FINGERPRINT_STATES.HIDDEN, class: 'hidden'},
- {state: FINGERPRINT_STATES.DEFAULT, class: 'default'},
- {state: FINGERPRINT_STATES.SIGNIN, class: 'signin'},
- {state: FINGERPRINT_STATES.FAILED, class: 'failed'}
- ];
-
- // Supported multi-profile user behavior values.
- // Keep in sync with the enum in login_user_info.mojom
- var MULTI_PROFILE_USER_BEHAVIOR = {
- UNRESTRICTED: 0,
- PRIMARY_ONLY: 1,
- NOT_ALLOWED: 2,
- OWNER_PRIMARY_ONLY: 3
- };
-
- // Focus and tab order are organized as follows:
- //
- // (1) all user pods have tab index 1 so they are traversed first;
- // (2) when a user pod is activated, its tab index is set to -1 and its
- // main input field gets focus and tab index 1;
- // (3) if user pod custom icon is interactive, it has tab index 2 so it
- // follows the input.
- // (4) buttons on the header bar have tab index 3 so they follow the custom
- // icon, or user pod if custom icon is not interactive;
- // (5) Action box buttons have tab index 4 and follow header bar buttons;
- // (6) lastly, focus jumps to the Status Area and back to user pods.
- //
- // 'Focus' event is handled by a capture handler for the whole document
- // and in some cases 'mousedown' event handlers are used instead of 'click'
- // handlers where it's necessary to prevent 'focus' event from being fired.
-
- /**
- * Helper function to remove a class from given element.
- * @param {!HTMLElement} el Element whose class list to change.
- * @param {string} cl Class to remove.
- */
- function removeClass(el, cl) {
- el.classList.remove(cl);
- }
-
- /**
- * Creates a user pod.
- * @constructor
- * @extends {HTMLDivElement}
- */
- var UserPod = cr.ui.define(function() {
- var node = $('user-pod-template').cloneNode(true);
- node.removeAttribute('id');
- return node;
- });
-
- /**
- * Stops event propagation from the any user pod child element.
- * @param {Event} e Event to handle.
- */
- function stopEventPropagation(e) {
- // Prevent default so that we don't trigger a 'focus' event.
- e.preventDefault();
- e.stopPropagation();
- }
-
- /**
- * Creates an element for custom icon shown in a user pod next to the input
- * field.
- * @constructor
- * @extends {HTMLDivElement}
- */
- var UserPodCustomIcon = cr.ui.define(function() {
- var node = document.createElement('div');
- node.classList.add('custom-icon-container');
- node.hidden = true;
-
- // Create the actual icon element and add it as a child to the container.
- var iconNode = document.createElement('div');
- iconNode.classList.add('custom-icon');
- node.appendChild(iconNode);
- return node;
- });
-
- /**
- * The supported user pod custom icons.
- * {@code id} properties should be in sync with values set by C++ side.
- * {@code class} properties are CSS classes used to set the icons' background.
- * @const {Array<{id: !string, class: !string}>}
- */
- UserPodCustomIcon.ICONS = [
- {id: 'locked', class: 'custom-icon-locked'},
- {id: 'locked-to-be-activated',
- class: 'custom-icon-locked-to-be-activated'},
- {id: 'locked-with-proximity-hint',
- class: 'custom-icon-locked-with-proximity-hint'},
- {id: 'unlocked', class: 'custom-icon-unlocked'},
- {id: 'hardlocked', class: 'custom-icon-hardlocked'},
- {id: 'spinner', class: 'custom-icon-spinner'}
- ];
-
- /**
- * The hover state for the icon. When user hovers over the icon, a tooltip
- * should be shown after a short delay. This enum is used to keep track of
- * the tooltip status related to hover state.
- * @enum {string}
- */
- UserPodCustomIcon.HoverState = {
- /** The user is not hovering over the icon. */
- NO_HOVER: 'no_hover',
-
- /** The user is hovering over the icon but the tooltip is not activated. */
- HOVER: 'hover',
-
- /**
- * User is hovering over the icon and the tooltip is activated due to the
- * hover state (which happens with delay after user starts hovering).
- */
- HOVER_TOOLTIP: 'hover_tooltip'
- };
-
- /**
- * If the icon has a tooltip that should be automatically shown, the tooltip
- * is shown even when there is no user action (i.e. user is not hovering over
- * the icon), after a short delay. The tooltip should be hidden after some
- * time. Note that the icon will not be considered autoshown if it was
- * previously shown as a result of the user action.
- * This enum is used to keep track of this state.
- * @enum {string}
- */
- UserPodCustomIcon.TooltipAutoshowState = {
- /** The tooltip should not be or was not automatically shown. */
- DISABLED: 'disabled',
-
- /**
- * The tooltip should be automatically shown, but the timeout for showing
- * the tooltip has not yet passed.
- */
- ENABLED: 'enabled',
-
- /** The tooltip was automatically shown. */
- ACTIVE : 'active'
- };
-
- UserPodCustomIcon.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- /**
- * The id of the icon being shown.
- * @type {string}
- * @private
- */
- iconId_: '',
-
- /**
- * A reference to the timeout for updating icon hover state. Non-null
- * only if there is an active timeout.
- * @type {?number}
- * @private
- */
- updateHoverStateTimeout_: null,
-
- /**
- * A reference to the timeout for updating icon tooltip autoshow state.
- * Non-null only if there is an active timeout.
- * @type {?number}
- * @private
- */
- updateTooltipAutoshowStateTimeout_: null,
-
- /**
- * Callback for click and 'Enter' key events that gets set if the icon is
- * interactive.
- * @type {?function()}
- * @private
- */
- actionHandler_: null,
-
- /**
- * The current tooltip state.
- * @type {{active: function(): boolean,
- * autoshow: !UserPodCustomIcon.TooltipAutoshowState,
- * hover: !UserPodCustomIcon.HoverState,
- * text: string}}
- * @private
- */
- tooltipState_: {
- /**
- * Utility method for determining whether the tooltip is active, either as
- * a result of hover state or being autoshown.
- * @return {boolean}
- */
- active: function() {
- return this.autoshow == UserPodCustomIcon.TooltipAutoshowState.ACTIVE ||
- this.hover == UserPodCustomIcon.HoverState.HOVER_TOOLTIP;
- },
-
- /**
- * @type {!UserPodCustomIcon.TooltipAutoshowState}
- */
- autoshow: UserPodCustomIcon.TooltipAutoshowState.DISABLED,
-
- /**
- * @type {!UserPodCustomIcon.HoverState}
- */
- hover: UserPodCustomIcon.HoverState.NO_HOVER,
-
- /**
- * The tooltip text.
- * @type {string}
- */
- text: ''
- },
-
- /** @override */
- decorate: function() {
- this.iconElement.addEventListener(
- 'mouseover',
- this.updateHoverState_.bind(this,
- UserPodCustomIcon.HoverState.HOVER));
- this.iconElement.addEventListener(
- 'mouseout',
- this.updateHoverState_.bind(this,
- UserPodCustomIcon.HoverState.NO_HOVER));
- this.iconElement.addEventListener('mousedown',
- this.handleMouseDown_.bind(this));
- this.iconElement.addEventListener('click',
- this.handleClick_.bind(this));
- this.iconElement.addEventListener('keydown',
- this.handleKeyDown_.bind(this));
-
- // When the icon is focused using mouse, there should be no outline shown.
- // Preventing default mousedown event accomplishes this.
- this.iconElement.addEventListener('mousedown', function(e) {
- e.preventDefault();
- });
- },
-
- /**
- * Getter for the icon element's div.
- * @return {HTMLDivElement}
- */
- get iconElement() {
- return this.querySelector('.custom-icon');
- },
-
- /**
- * Updates the icon element class list to properly represent the provided
- * icon.
- * @param {!string} id The id of the icon that should be shown. Should be
- * one of the ids listed in {@code UserPodCustomIcon.ICONS}.
- */
- setIcon: function(id) {
- this.iconId_ = id;
- UserPodCustomIcon.ICONS.forEach(function(icon) {
- this.iconElement.classList.toggle(icon.class, id == icon.id);
- }, this);
- },
-
- /**
- * Sets the ARIA label for the icon.
- * @param {!string} ariaLabel
- */
- setAriaLabel: function(ariaLabel) {
- this.iconElement.setAttribute('aria-label', ariaLabel);
- },
-
- /**
- * Shows the icon.
- */
- show: function() {
- // Show the icon if the current iconId is valid.
- var validIcon = false;
- UserPodCustomIcon.ICONS.forEach(function(icon) {
- validIcon = validIcon || this.iconId_ == icon.id;
- }, this);
- this.hidden = validIcon ? false : true;
- },
-
- /**
- * Updates the icon tooltip. If {@code autoshow} parameter is set the
- * tooltip is immediatelly shown. If tooltip text is not set, the method
- * ensures the tooltip gets hidden. If tooltip is shown prior to this call,
- * it remains shown, but the tooltip text is updated.
- * @param {!{text: string, autoshow: boolean}} tooltip The tooltip
- * parameters.
- */
- setTooltip: function(tooltip) {
- this.iconElement.classList.toggle('icon-with-tooltip', !!tooltip.text);
-
- this.updateTooltipAutoshowState_(
- tooltip.autoshow ?
- UserPodCustomIcon.TooltipAutoshowState.ENABLED :
- UserPodCustomIcon.TooltipAutoshowState.DISABLED);
- this.tooltipState_.text = tooltip.text;
- this.updateTooltip_();
- },
-
- /**
- * Sets up icon tabIndex attribute and handler for click and 'Enter' key
- * down events.
- * @param {?function()} callback If icon should be interactive, the
- * function to get called on click and 'Enter' key down events. Should
- * be null to make the icon non interactive.
- */
- setInteractive: function(callback) {
- this.iconElement.classList.toggle('interactive-custom-icon', !!callback);
-
- // Update tabIndex property if needed.
- if (!!this.actionHandler_ != !!callback) {
- if (callback) {
- this.iconElement.setAttribute('tabIndex',
- UserPodTabOrder.POD_CUSTOM_ICON);
- } else {
- this.iconElement.removeAttribute('tabIndex');
- }
- }
-
- // Set the new action handler.
- this.actionHandler_ = callback;
- },
-
- /**
- * Hides the icon and cleans its state.
- */
- hide: function() {
- this.hideTooltip_();
- this.clearUpdateHoverStateTimeout_();
- this.clearUpdateTooltipAutoshowStateTimeout_();
- this.setInteractive(null);
- this.hidden = true;
- },
-
- /**
- * Clears timeout for showing a tooltip if one is set. Used to cancel
- * showing the tooltip when the user starts typing the password.
- */
- cancelDelayedTooltipShow: function() {
- this.updateTooltipAutoshowState_(
- UserPodCustomIcon.TooltipAutoshowState.DISABLED);
- this.clearUpdateHoverStateTimeout_();
- },
-
- /**
- * Handles mouse down event in the icon element.
- * @param {Event} e The mouse down event.
- * @private
- */
- handleMouseDown_: function(e) {
- this.updateHoverState_(UserPodCustomIcon.HoverState.NO_HOVER);
- this.updateTooltipAutoshowState_(
- UserPodCustomIcon.TooltipAutoshowState.DISABLED);
-
- // Stop the event propagation so in the case the click ends up on the
- // user pod (outside the custom icon) auth is not attempted.
- stopEventPropagation(e);
- },
-
- /**
- * Handles click event on the icon element. No-op if
- * {@code this.actionHandler_} is not set.
- * @param {Event} e The click event.
- * @private
- */
- handleClick_: function(e) {
- if (!this.actionHandler_)
- return;
- this.actionHandler_();
- stopEventPropagation(e);
- },
-
- /**
- * Handles key down event on the icon element. Only 'Enter' key is handled.
- * No-op if {@code this.actionHandler_} is not set.
- * @param {Event} e The key down event.
- * @private
- */
- handleKeyDown_: function(e) {
- if (!this.actionHandler_ || e.key != 'Enter')
- return;
- this.actionHandler_(e);
- stopEventPropagation(e);
- },
-
- /**
- * Changes the tooltip hover state and updates tooltip visibility if needed.
- * @param {!UserPodCustomIcon.HoverState} state
- * @private
- */
- updateHoverState_: function(state) {
- this.clearUpdateHoverStateTimeout_();
- this.sanitizeTooltipStateIfBubbleHidden_();
-
- if (state == UserPodCustomIcon.HoverState.HOVER) {
- if (this.tooltipState_.active()) {
- this.tooltipState_.hover = UserPodCustomIcon.HoverState.HOVER_TOOLTIP;
- } else {
- this.updateHoverStateSoon_(
- UserPodCustomIcon.HoverState.HOVER_TOOLTIP);
- }
- return;
- }
-
- if (state != UserPodCustomIcon.HoverState.NO_HOVER &&
- state != UserPodCustomIcon.HoverState.HOVER_TOOLTIP) {
- console.error('Invalid hover state ' + state);
- return;
- }
-
- this.tooltipState_.hover = state;
- this.updateTooltip_();
- },
-
- /**
- * Sets up a timeout for updating icon hover state.
- * @param {!UserPodCustomIcon.HoverState} state
- * @private
- */
- updateHoverStateSoon_: function(state) {
- if (this.updateHoverStateTimeout_)
- clearTimeout(this.updateHoverStateTimeout_);
- this.updateHoverStateTimeout_ =
- setTimeout(this.updateHoverState_.bind(this, state), 1000);
- },
-
- /**
- * Clears a timeout for updating icon hover state if there is one set.
- * @private
- */
- clearUpdateHoverStateTimeout_: function() {
- if (this.updateHoverStateTimeout_) {
- clearTimeout(this.updateHoverStateTimeout_);
- this.updateHoverStateTimeout_ = null;
- }
- },
-
- /**
- * Changes the tooltip autoshow state and changes tooltip visibility if
- * needed.
- * @param {!UserPodCustomIcon.TooltipAutoshowState} state
- * @private
- */
- updateTooltipAutoshowState_: function(state) {
- this.clearUpdateTooltipAutoshowStateTimeout_();
- this.sanitizeTooltipStateIfBubbleHidden_();
-
- if (state == UserPodCustomIcon.TooltipAutoshowState.DISABLED) {
- if (this.tooltipState_.autoshow != state) {
- this.tooltipState_.autoshow = state;
- this.updateTooltip_();
- }
- return;
- }
-
- if (this.tooltipState_.active()) {
- if (this.tooltipState_.autoshow !=
- UserPodCustomIcon.TooltipAutoshowState.ACTIVE) {
- this.tooltipState_.autoshow =
- UserPodCustomIcon.TooltipAutoshowState.DISABLED;
- } else {
- // If the tooltip is already automatically shown, the timeout for
- // removing it should be reset.
- this.updateTooltipAutoshowStateSoon_(
- UserPodCustomIcon.TooltipAutoshowState.DISABLED);
- }
- return;
- }
-
- if (state == UserPodCustomIcon.TooltipAutoshowState.ENABLED) {
- this.updateTooltipAutoshowStateSoon_(
- UserPodCustomIcon.TooltipAutoshowState.ACTIVE);
- } else if (state == UserPodCustomIcon.TooltipAutoshowState.ACTIVE) {
- this.updateTooltipAutoshowStateSoon_(
- UserPodCustomIcon.TooltipAutoshowState.DISABLED);
- }
-
- this.tooltipState_.autoshow = state;
- this.updateTooltip_();
- },
-
- /**
- * Sets up a timeout for updating tooltip autoshow state.
- * @param {!UserPodCustomIcon.TooltipAutoshowState} state
- * @private
- */
- updateTooltipAutoshowStateSoon_: function(state) {
- if (this.updateTooltipAutoshowStateTimeout_)
- clearTimeout(this.updateTooltupAutoshowStateTimeout_);
- var timeout =
- state == UserPodCustomIcon.TooltipAutoshowState.DISABLED ?
- 5000 : 1000;
- this.updateTooltipAutoshowStateTimeout_ =
- setTimeout(this.updateTooltipAutoshowState_.bind(this, state),
- timeout);
- },
-
- /**
- * Clears the timeout for updating tooltip autoshow state if one is set.
- * @private
- */
- clearUpdateTooltipAutoshowStateTimeout_: function() {
- if (this.updateTooltipAutoshowStateTimeout_) {
- clearTimeout(this.updateTooltipAutoshowStateTimeout_);
- this.updateTooltipAutoshowStateTimeout_ = null;
- }
- },
-
- /**
- * If tooltip bubble is hidden, this makes sure that hover and tooltip
- * autoshow states are not the ones that imply an active tooltip.
- * Used to handle a case where the tooltip bubble is hidden by an event that
- * does not update one of the states (e.g. click outside the pod will not
- * update tooltip autoshow state). Should be called before making
- * tooltip state updates.
- * @private
- */
- sanitizeTooltipStateIfBubbleHidden_: function() {
- if (!$('bubble').hidden)
- return;
-
- if (this.tooltipState_.hover ==
- UserPodCustomIcon.HoverState.HOVER_TOOLTIP &&
- this.tooltipState_.text) {
- this.tooltipState_.hover = UserPodCustomIcon.HoverState.NO_HOVER;
- this.clearUpdateHoverStateTimeout_();
- }
-
- if (this.tooltipState_.autoshow ==
- UserPodCustomIcon.TooltipAutoshowState.ACTIVE) {
- this.tooltipState_.autoshow =
- UserPodCustomIcon.TooltipAutoshowState.DISABLED;
- this.clearUpdateTooltipAutoshowStateTimeout_();
- }
- },
-
- /**
- * Returns whether the user pod to which the custom icon belongs is focused.
- * @return {boolean}
- * @private
- */
- isParentPodFocused_: function() {
- if ($('account-picker').hidden)
- return false;
- var parentPod = this.parentNode;
- while (parentPod && !parentPod.classList.contains('pod'))
- parentPod = parentPod.parentNode;
- return parentPod && parentPod.parentNode.isFocused(parentPod);
- },
-
- /**
- * Depending on {@code this.tooltipState_}, it updates tooltip visibility
- * and text.
- * @private
- */
- updateTooltip_: function() {
- if (this.hidden || !this.isParentPodFocused_())
- return;
-
- if (!this.tooltipState_.active() || !this.tooltipState_.text) {
- this.hideTooltip_();
- return;
- }
-
- // Show the tooltip bubble.
- var bubbleContent = document.createElement('div');
- bubbleContent.textContent = this.tooltipState_.text;
-
- /** @const */ var BUBBLE_OFFSET = CUSTOM_ICON_CONTAINER_SIZE / 2;
- // TODO(tengs): Introduce a special reauth state for the account picker,
- // instead of showing the tooltip bubble here (crbug.com/409427).
- /** @const */ var BUBBLE_PADDING = 8 + (this.iconId_ ? 0 : 23);
- $('bubble').showContentForElement(this,
- cr.ui.Bubble.Attachment.LEFT,
- bubbleContent,
- BUBBLE_OFFSET,
- BUBBLE_PADDING);
- },
-
- /**
- * Hides the tooltip.
- * @private
- */
- hideTooltip_: function() {
- $('bubble').hideForElement(this);
- }
- };
-
- /**
- * Unique salt added to user image URLs to prevent caching. Dictionary with
- * user names as keys.
- * @type {Object}
- */
- UserPod.userImageSalt_ = {};
-
- UserPod.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- /**
- * Whether click on the pod can issue a user click auth attempt. The
- * attempt can be issued iff the pod was focused when the click
- * started (i.e. on mouse down event).
- * @type {boolean}
- * @private
- */
- userClickAuthAllowed_: false,
-
- /**
- * Whether the user has recently authenticated with fingerprint.
- * @type {boolean}
- * @private
- */
- fingerprintAuthenticated_: false,
-
- /**
- * True iff the pod can display the pin keyboard. The pin keyboard may not
- * always be displayed even if this is true, ie, if the virtual keyboard is
- * also being displayed.
- */
- pinEnabled: false,
-
- /** @override */
- decorate: function() {
- this.tabIndex = UserPodTabOrder.POD_INPUT;
- this.actionBoxAreaElement.tabIndex = UserPodTabOrder.POD_INPUT;
-
- this.addEventListener('keydown', this.handlePodKeyDown_.bind(this));
- this.addEventListener('click', this.handleClickOnPod_.bind(this));
- this.addEventListener('mousedown', this.handlePodMouseDown_.bind(this));
-
- if (this.pinKeyboard) {
- this.pinKeyboard.passwordElement = this.passwordElement;
- this.pinKeyboard.addEventListener('pin-change',
- this.handleInputChanged_.bind(this));
- this.pinKeyboard.tabIndex = UserPodTabOrder.PIN_KEYBOARD;
- }
-
- this.actionBoxAreaElement.addEventListener('mousedown',
- stopEventPropagation);
- this.actionBoxAreaElement.addEventListener('click',
- this.handleActionAreaButtonClick_.bind(this));
- this.actionBoxAreaElement.addEventListener('keydown',
- this.handleActionAreaButtonKeyDown_.bind(this));
- this.actionBoxAreaElement.addEventListener('focus', () => {
- this.isActionBoxMenuActive = false;
- });
-
- this.actionBoxMenuTitleElement.addEventListener('keydown',
- this.handleMenuTitleElementKeyDown_.bind(this));
- this.actionBoxMenuTitleElement.addEventListener('blur',
- this.handleMenuTitleElementBlur_.bind(this));
-
- this.actionBoxMenuRemoveElement.addEventListener('click',
- this.handleRemoveCommandClick_.bind(this));
- this.actionBoxMenuRemoveElement.addEventListener('keydown',
- this.handleRemoveCommandKeyDown_.bind(this));
- this.actionBoxMenuRemoveElement.addEventListener('blur',
- this.handleRemoveCommandBlur_.bind(this));
- this.actionBoxRemoveUserWarningButtonElement.addEventListener('click',
- this.handleRemoveUserConfirmationClick_.bind(this));
- this.actionBoxRemoveUserWarningButtonElement.addEventListener('keydown',
- this.handleRemoveUserConfirmationKeyDown_.bind(this));
-
- if (this.fingerprintIconElement) {
- this.fingerprintIconElement.addEventListener(
- 'mouseover', this.handleFingerprintIconMouseOver_.bind(this));
- this.fingerprintIconElement.addEventListener(
- 'mouseout', this.handleFingerprintIconMouseOut_.bind(this));
- this.fingerprintIconElement.addEventListener(
- 'mousedown', stopEventPropagation);
- }
-
- var customIcon = this.customIconElement;
- customIcon.parentNode.replaceChild(new UserPodCustomIcon(), customIcon);
- },
-
- /**
- * Initializes the pod after its properties set and added to a pod row.
- */
- initialize: function() {
- this.passwordElement.addEventListener('keydown',
- this.parentNode.handleKeyDown.bind(this.parentNode));
- this.passwordElement.addEventListener('keypress',
- this.handlePasswordKeyPress_.bind(this));
- this.passwordElement.addEventListener('input',
- this.handleInputChanged_.bind(this));
-
- if (this.submitButton) {
- this.submitButton.addEventListener('click',
- this.handleSubmitButtonClick_.bind(this));
- }
-
- this.imageElement.addEventListener('load',
- this.parentNode.handlePodImageLoad.bind(this.parentNode, this));
-
- var initialAuthType = this.user.initialAuthType ||
- AUTH_TYPE.OFFLINE_PASSWORD;
- this.setAuthType(initialAuthType, null);
-
- if (this.user.isActiveDirectory)
- this.setAttribute('is-active-directory', '');
-
- this.userClickAuthAllowed_ = false;
- },
-
- /**
- * Whether the user pod is disabled.
- * @type {boolean}
- */
- disabled_: false,
- get disabled() {
- return this.disabled_;
- },
- set disabled(value) {
- this.disabled_ = value;
- this.querySelectorAll('button,input').forEach(function(element) {
- element.disabled = value
- });
-
- // Special handling for submit button - the submit button should be
- // enabled only if there is the password value set.
- var submitButton = this.submitButton;
- if (submitButton)
- submitButton.disabled = value || !this.passwordElement.value;
- },
-
- /**
- * Resets tab order for pod elements to its initial state.
- */
- resetTabOrder: function() {
- // Note: the |mainInput| can be the pod itself.
- this.mainInput.tabIndex = -1;
- this.tabIndex = UserPodTabOrder.POD_INPUT;
- },
-
- /**
- * Handles keypress event (i.e. any textual input) on password input.
- * @param {Event} e Keypress Event object.
- * @private
- */
- handlePasswordKeyPress_: function(e) {
- // When tabbing from the system tray a tab key press is received. Suppress
- // this so as not to type a tab character into the password field.
- if (e.keyCode == 9) {
- e.preventDefault();
- return;
- }
- this.customIconElement.cancelDelayedTooltipShow();
- },
-
- /**
- * Handles a click event on submit button.
- * @param {Event} e Click event.
- */
- handleSubmitButtonClick_: function(e) {
- this.parentNode.setActivatedPod(this, e);
- },
-
- /**
- * Top edge margin number of pixels.
- * @type {?number}
- */
- set top(top) {
- this.style.top = cr.ui.toCssPx(top);
- },
-
- /**
- * Top edge margin number of pixels.
- */
- get top() {
- return parseInt(this.style.top);
- },
-
- /**
- * Left edge margin number of pixels.
- * @type {?number}
- */
- set left(left) {
- this.style.left = cr.ui.toCssPx(left);
- },
-
- /**
- * Left edge margin number of pixels.
- */
- get left() {
- return parseInt(this.style.left);
- },
-
- /**
- * Height number of pixels.
- */
- get height() {
- return this.offsetHeight;
- },
-
- /**
- * Gets image element.
- * @type {!HTMLImageElement}
- */
- get imageElement() {
- return this.querySelector('.user-image');
- },
-
- /**
- * Gets animated image element.
- * @type {!HTMLImageElement}
- */
- get animatedImageElement() {
- return this.querySelector('.user-image.animated-image');
- },
-
- /**
- * Gets name element.
- * @type {!HTMLDivElement}
- */
- get nameElement() {
- return this.querySelector('.name');
- },
-
- /**
- * Gets reauth name hint element.
- * @type {!HTMLDivElement}
- */
- get reauthNameHintElement() {
- return this.querySelector('.reauth-name-hint');
- },
-
- /**
- * Gets the container holding the password field.
- * @type {!HTMLInputElement}
- */
- get passwordEntryContainerElement() {
- return this.querySelector('.password-entry-container');
- },
-
- /**
- * Gets password field.
- * @type {!HTMLInputElement}
- */
- get passwordElement() {
- return this.querySelector('.password');
- },
-
- /**
- * Gets submit button.
- * @type {!HTMLInputElement}
- */
- get submitButton() {
- return this.querySelector('.submit-button');
- },
-
- /**
- * Gets the password label, which is used to show a message where the
- * password field is normally.
- * @type {!HTMLInputElement}
- */
- get passwordLabelElement() {
- return this.querySelector('.password-label');
- },
-
- get pinContainer() {
- return this.querySelector('.pin-container');
- },
-
- /**
- * Gets the pin-keyboard of the pod.
- * @type {!HTMLElement}
- */
- get pinKeyboard() {
- return this.querySelector('pin-keyboard');
- },
-
- /**
- * Gets user online sign in hint element.
- * @type {!HTMLDivElement}
- */
- get reauthWarningElement() {
- return this.querySelector('.reauth-hint-container');
- },
-
- /**
- * Gets action box area.
- * @type {!HTMLInputElement}
- */
- get actionBoxAreaElement() {
- return this.querySelector('.action-box-area');
- },
-
- /**
- * Gets user type icon area.
- * @type {!HTMLDivElement}
- */
- get userTypeIconAreaElement() {
- return this.querySelector('.user-type-icon-area');
- },
-
- /**
- * Gets user type bubble like multi-profiles policy restriction message.
- * @type {!HTMLDivElement}
- */
- get userTypeBubbleElement() {
- return this.querySelector('.user-type-bubble');
- },
-
- /**
- * Gets action box menu.
- * @type {!HTMLDivElement}
- */
- get actionBoxMenu() {
- return this.querySelector('.action-box-menu');
- },
-
- /**
- * Gets action box menu title (user name and email).
- * @type {!HTMLDivElement}
- */
- get actionBoxMenuTitleElement() {
- return this.querySelector('.action-box-menu-title');
- },
-
- /**
- * Gets action box menu title, user name item.
- * @type {!HTMLSpanElement}
- */
- get actionBoxMenuTitleNameElement() {
- return this.querySelector('.action-box-menu-title-name');
- },
-
- /**
- * Gets action box menu title, user email item.
- * @type {!HTMLSpanElement}
- */
- get actionBoxMenuTitleEmailElement() {
- return this.querySelector('.action-box-menu-title-email');
- },
-
- /**
- * Gets action box menu, remove user command item.
- * @type {!HTMLInputElement}
- */
- get actionBoxMenuCommandElement() {
- return this.querySelector('.action-box-menu-remove-command');
- },
-
- /**
- * Gets action box menu, remove user command item div.
- * @type {!HTMLInputElement}
- */
- get actionBoxMenuRemoveElement() {
- return this.querySelector('.action-box-menu-remove');
- },
-
- /**
- * Gets action box menu, remove user command item div.
- * @type {!HTMLInputElement}
- */
- get actionBoxRemoveUserWarningElement() {
- return this.querySelector('.action-box-remove-user-warning');
- },
-
- /**
- * Gets action box menu, remove user command item div.
- * @type {!HTMLInputElement}
- */
- get actionBoxRemoveUserWarningButtonElement() {
- return this.querySelector('.remove-warning-button');
- },
-
- /**
- * Gets the custom icon. This icon is normally hidden, but can be shown
- * using the chrome.screenlockPrivate API.
- * @type {!HTMLDivElement}
- */
- get customIconElement() {
- return this.querySelector('.custom-icon-container');
- },
-
- /**
- * Gets the elements used for statistics display.
- * @type {Object.<string, !HTMLDivElement>}
- */
- get statsMapElements() {
- return {
- 'BrowsingHistory':
- this.querySelector('.action-box-remove-user-warning-history'),
- 'Passwords':
- this.querySelector('.action-box-remove-user-warning-passwords'),
- 'Bookmarks':
- this.querySelector('.action-box-remove-user-warning-bookmarks'),
- 'Autofill':
- this.querySelector('.action-box-remove-user-warning-autofill')
- }
- },
-
- /**
- * Gets the fingerprint icon area.
- * @type {!HTMLDivElement}
- */
- get fingerprintIconElement() {
- return this.querySelector('.fingerprint-icon-container');
- },
-
- /**
- * Updates the user pod element.
- */
- update: function() {
- var animatedImageSrc = 'chrome://userimage/' + this.user.username +
- '?id=' + UserPod.userImageSalt_[this.user.username];
- this.imageElement.src = animatedImageSrc + '&frame=0';
- this.animatedImageElement.src = animatedImageSrc;
-
- this.nameElement.textContent = this.user_.displayName;
- this.reauthNameHintElement.textContent = this.user_.displayName;
- this.classList.toggle('signed-in', this.user_.signedIn);
-
- if (this.isAuthTypeUserClick)
- this.passwordLabelElement.textContent = this.authValue;
-
- this.updateActionBoxArea();
-
- this.passwordElement.setAttribute('aria-label', loadTimeData.getStringF(
- 'passwordFieldAccessibleName', this.user_.emailAddress));
-
- this.customizeUserPodPerUserType();
- },
-
- updateActionBoxArea: function() {
- if (this.user_.publicAccount) {
- this.actionBoxAreaElement.hidden = true;
- return;
- }
-
- this.actionBoxMenuRemoveElement.hidden = !this.user_.canRemove;
-
- this.actionBoxAreaElement.setAttribute(
- 'aria-label', loadTimeData.getStringF(
- 'podMenuButtonAccessibleName', this.user_.emailAddress));
- this.actionBoxMenuRemoveElement.setAttribute(
- 'aria-label', loadTimeData.getString(
- 'podMenuRemoveItemAccessibleName'));
- this.actionBoxMenuTitleNameElement.textContent = this.user_.isOwner ?
- loadTimeData.getStringF('ownerUserPattern', this.user_.displayName) :
- this.user_.displayName;
- this.actionBoxMenuTitleEmailElement.textContent = this.user_.emailAddress;
-
- this.actionBoxMenuTitleEmailElement.hidden =
- this.user_.legacySupervisedUser;
-
- this.actionBoxMenuCommandElement.textContent =
- loadTimeData.getString('removeUser');
- },
-
- customizeUserPodPerUserType: function() {
- if (this.user_.childUser && !this.user_.isDesktopUser) {
- this.setUserPodIconType('child');
- } else if (this.user_.legacySupervisedUser && !this.user_.isDesktopUser) {
- this.setUserPodIconType('legacySupervised');
- this.classList.add('legacy-supervised');
- } else if (this.multiProfilesPolicyApplied) {
- // Mark user pod as not focusable which in addition to the grayed out
- // filter makes it look in disabled state.
- this.classList.add('multiprofiles-policy-applied');
- this.setUserPodIconType('policy');
-
- if (this.user.multiProfilesPolicy ==
- MULTI_PROFILE_USER_BEHAVIOR.PRIMARY_ONLY) {
- this.querySelector('.mp-policy-primary-only-msg').hidden = false;
- } else if (this.user.multiProfilesPolicy ==
- MULTI_PROFILE_USER_BEHAVIOR.OWNER_PRIMARY_ONLY) {
- this.querySelector('.mp-owner-primary-only-msg').hidden = false;
- } else {
- this.querySelector('.mp-policy-not-allowed-msg').hidden = false;
- }
- }
- },
-
- isPinReady: function() {
- return this.pinKeyboard && this.pinKeyboard.offsetHeight > 0;
- },
-
- set showError(visible) {
- if (this.submitButton)
- this.submitButton.classList.toggle('error-shown', visible);
- },
-
- updatePinClass_: function(element, enable) {
- element.classList.toggle('pin-enabled', enable);
- element.classList.toggle('pin-disabled', !enable);
- },
-
- setPinVisibility: function(visible) {
- if (this.isPinShown() == visible)
- return;
-
- // Do not show pin if virtual keyboard is there.
- if (visible && Oobe.getInstance().virtualKeyboardShown)
- return;
-
- // Do not show pin keyboard if the pod does not have pin enabled.
- if (visible && !this.pinEnabled)
- return;
-
- var elements = this.getElementsByClassName('pin-tag');
- for (var i = 0; i < elements.length; ++i)
- this.updatePinClass_(elements[i], visible);
- this.updatePinClass_(this, visible);
-
- // Set the focus to the input element after showing/hiding pin keyboard.
- this.mainInput.focus();
-
- // Change the password placeholder based on pin keyboard visibility.
- this.passwordElement.placeholder = loadTimeData.getString(visible ?
- 'pinKeyboardPlaceholderPinPassword' : 'passwordHint');
- },
-
- isPinShown: function() {
- return this.classList.contains('pin-enabled');
- },
-
- setUserPodIconType: function(userTypeClass) {
- this.userTypeIconAreaElement.classList.add(userTypeClass);
- this.userTypeIconAreaElement.hidden = false;
- },
-
- isFingerprintIconShown: function() {
- return this.fingerprintIconElement && !this.fingerprintIconElement.hidden;
- },
-
- /**
- * The user that this pod represents.
- * @type {!Object}
- */
- user_: undefined,
- get user() {
- return this.user_;
- },
- set user(userDict) {
- this.user_ = userDict;
- this.update();
- },
-
- /**
- * Returns true if multi-profiles sign in is currently active and this
- * user pod is restricted per policy.
- * @type {boolean}
- */
- get multiProfilesPolicyApplied() {
- var isMultiProfilesUI =
- (Oobe.getInstance().displayType == DISPLAY_TYPE.USER_ADDING);
- return isMultiProfilesUI && !this.user_.isMultiProfilesAllowed;
- },
-
- /**
- * Gets main input element.
- * @type {(HTMLButtonElement|HTMLInputElement)}
- */
- get mainInput() {
- if (this.isAuthTypePassword) {
- return this.passwordElement;
- } else if (this.isAuthTypeOnlineSignIn) {
- return this;
- } else if (this.isAuthTypeUserClick) {
- return this.passwordLabelElement;
- }
- },
-
- /**
- * Whether action box button is in active state.
- * @type {boolean}
- */
- get isActionBoxMenuActive() {
- return this.actionBoxAreaElement.classList.contains('active');
- },
- set isActionBoxMenuActive(active) {
- if (active == this.isActionBoxMenuActive)
- return;
-
- if (active) {
- this.actionBoxMenuRemoveElement.hidden = !this.user_.canRemove;
- this.actionBoxRemoveUserWarningElement.hidden = true;
-
- // Clear focus first if another pod is focused.
- if (!this.parentNode.isFocused(this)) {
- this.parentNode.focusPod(undefined, true);
- this.actionBoxAreaElement.focus();
- }
-
- // Hide user-type-bubble.
- this.userTypeBubbleElement.classList.remove('bubble-shown');
-
- this.actionBoxAreaElement.classList.add('active');
-
- // Invisible focus causes ChromeVox to read user name and email.
- this.actionBoxMenuTitleElement.tabIndex = UserPodTabOrder.POD_MENU_ITEM;
- this.actionBoxMenuTitleElement.focus();
-
- // If the user pod is on either edge of the screen, then the menu
- // could be displayed partially ofscreen.
- this.actionBoxMenu.classList.remove('left-edge-offset');
- this.actionBoxMenu.classList.remove('right-edge-offset');
-
- var offsetLeft =
- cr.ui.login.DisplayManager.getOffset(this.actionBoxMenu).left;
- var menuWidth = this.actionBoxMenu.offsetWidth;
- if (offsetLeft < 0)
- this.actionBoxMenu.classList.add('left-edge-offset');
- else if (offsetLeft + menuWidth > window.innerWidth)
- this.actionBoxMenu.classList.add('right-edge-offset');
- } else {
- this.actionBoxAreaElement.classList.remove('active');
- this.actionBoxAreaElement.classList.remove('menu-moved-up');
- this.actionBoxMenu.classList.remove('menu-moved-up');
- }
- },
-
- /**
- * Whether action box button is in hovered state.
- * @type {boolean}
- */
- get isActionBoxMenuHovered() {
- return this.actionBoxAreaElement.classList.contains('hovered');
- },
- set isActionBoxMenuHovered(hovered) {
- if (hovered == this.isActionBoxMenuHovered)
- return;
-
- if (hovered) {
- this.actionBoxAreaElement.classList.add('hovered');
- this.classList.add('hovered');
- } else {
- if (this.multiProfilesPolicyApplied)
- this.userTypeBubbleElement.classList.remove('bubble-shown');
- this.actionBoxAreaElement.classList.remove('hovered');
- this.classList.remove('hovered');
- }
- },
-
- /**
- * Set the authentication type for the pod.
- * @param {number} An auth type value defined in the AUTH_TYPE enum.
- * @param {string} authValue The initial value used for the auth type.
- */
- setAuthType: function(authType, authValue) {
- this.authType_ = authType;
- this.authValue_ = authValue;
- this.setAttribute('auth-type', AUTH_TYPE_NAMES[this.authType_]);
- this.update();
- this.reset(this.parentNode.isFocused(this));
- },
-
- /**
- * The auth type of the user pod. This value is one of the enum
- * values in AUTH_TYPE.
- * @type {number}
- */
- get authType() {
- return this.authType_;
- },
-
- /**
- * The initial value used for the pod's authentication type.
- * eg. a prepopulated password input when using password authentication.
- */
- get authValue() {
- return this.authValue_;
- },
-
- /**
- * True if the the user pod uses a password to authenticate.
- * @type {bool}
- */
- get isAuthTypePassword() {
- return this.authType_ == AUTH_TYPE.OFFLINE_PASSWORD ||
- this.authType_ == AUTH_TYPE.FORCE_OFFLINE_PASSWORD;
- },
-
- /**
- * True if the the user pod uses a user click to authenticate.
- * @type {bool}
- */
- get isAuthTypeUserClick() {
- return this.authType_ == AUTH_TYPE.USER_CLICK;
- },
-
- /**
- * True if the the user pod uses a online sign in to authenticate.
- * @type {bool}
- */
- get isAuthTypeOnlineSignIn() {
- return this.authType_ == AUTH_TYPE.ONLINE_SIGN_IN;
- },
-
- /**
- * Updates the image element of the user.
- */
- updateUserImage: function() {
- UserPod.userImageSalt_[this.user.username] = new Date().getTime();
- this.update();
- },
-
- /**
- * Focuses on input element.
- */
- focusInput: function() {
- // Move tabIndex from the whole pod to the main input.
- // Note: the |mainInput| can be the pod itself.
- this.tabIndex = -1;
- this.mainInput.tabIndex = UserPodTabOrder.POD_INPUT;
- this.mainInput.focus();
- },
-
- /**
- * Activates the pod.
- * @param {Event} e Event object.
- * @return {boolean} True if activated successfully.
- */
- activate: function(e) {
- if (this.isAuthTypeOnlineSignIn) {
- this.showSigninUI();
- } else if (this.isAuthTypeUserClick) {
- Oobe.disableSigninUI();
- this.classList.toggle('signing-in', true);
- chrome.send('attemptUnlock', [this.user.username]);
- } else if (this.isAuthTypePassword) {
- if (this.fingerprintAuthenticated_) {
- this.fingerprintAuthenticated_ = false;
- return true;
- }
- var pinValue = this.pinKeyboard ? this.pinKeyboard.value : '';
- var password = this.passwordElement.value || pinValue;
- if (!password)
- return false;
- Oobe.disableSigninUI();
- chrome.send('authenticateUser', [
- this.user.username, password, this.isPinShown() && !isNaN(password)
- ]);
- } else {
- console.error('Activating user pod with invalid authentication type: ' +
- this.authType);
- }
-
- return true;
- },
-
- showSupervisedUserSigninWarning: function() {
- // Legacy supervised user token has been invalidated.
- // Make sure that pod is focused i.e. "Sign in" button is seen.
- this.parentNode.focusPod(this);
-
- var error = document.createElement('div');
- var messageDiv = document.createElement('div');
- messageDiv.className = 'error-message-bubble';
- messageDiv.textContent =
- loadTimeData.getString('supervisedUserExpiredTokenWarning');
- error.appendChild(messageDiv);
-
- $('bubble').showContentForElement(
- this.reauthWarningElement,
- cr.ui.Bubble.Attachment.TOP,
- error,
- this.reauthWarningElement.offsetWidth / 2,
- 4);
- // Move warning bubble up if it overlaps the shelf.
- var maxHeight =
- cr.ui.LoginUITools.getMaxHeightBeforeShelfOverlapping($('bubble'));
- if (maxHeight < $('bubble').offsetHeight) {
- $('bubble').showContentForElement(
- this.reauthWarningElement,
- cr.ui.Bubble.Attachment.BOTTOM,
- error,
- this.reauthWarningElement.offsetWidth / 2,
- 4);
- }
- },
-
- /**
- * Shows signin UI for this user.
- */
- showSigninUI: function() {
- if (this.user.legacySupervisedUser && !this.user.isDesktopUser) {
- this.showSupervisedUserSigninWarning();
- } else {
- // Special case for multi-profiles sign in. We show users even if they
- // are not allowed per policy. Restrict those users from starting GAIA.
- if (this.multiProfilesPolicyApplied)
- return;
-
- this.parentNode.showSigninUI(this.user.emailAddress);
- }
- },
-
- /**
- * Resets the input field and updates the tab order of pod controls.
- * @param {boolean} takeFocus If true, input field takes focus.
- */
- reset: function(takeFocus) {
- this.passwordElement.value = '';
- if (this.pinKeyboard)
- this.pinKeyboard.value = '';
- this.updateInput_();
- this.classList.toggle('signing-in', false);
- if (takeFocus) {
- if (!this.multiProfilesPolicyApplied)
- this.focusInput(); // This will set a custom tab order.
- }
- else
- this.resetTabOrder();
- },
-
- /**
- * Removes a user using the correct identifier based on user type.
- * @param {Object} user User to be removed.
- */
- removeUser: function(user) {
- chrome.send('removeUser',
- [user.isDesktopUser ? user.profilePath : user.username]);
- },
-
- /**
- * Handles a click event on action area button.
- * @param {Event} e Click event.
- */
- handleActionAreaButtonClick_: function(e) {
- if (this.parentNode.disabled)
- return;
- this.isActionBoxMenuActive = !this.isActionBoxMenuActive;
- e.stopPropagation();
- },
-
- /**
- * Handles a keydown event on action area button.
- * @param {Event} e KeyDown event.
- */
- handleActionAreaButtonKeyDown_: function(e) {
- if (this.disabled)
- return;
- switch (e.key) {
- case 'Enter':
- case ' ':
- if (this.parentNode.focusedPod_ && !this.isActionBoxMenuActive)
- this.isActionBoxMenuActive = true;
- e.stopPropagation();
- break;
- case 'ArrowUp':
- case 'ArrowDown':
- if (this.isActionBoxMenuActive) {
- this.actionBoxMenuRemoveElement.tabIndex =
- UserPodTabOrder.POD_MENU_ITEM;
- this.actionBoxMenuRemoveElement.focus();
- }
- e.stopPropagation();
- break;
- // Ignore these two, so ChromeVox hotkeys don't close the menu before
- // they can navigate through it.
- case 'Shift':
- case 'Meta':
- break;
- case 'Escape':
- this.actionBoxAreaElement.focus();
- this.isActionBoxMenuActive = false;
- e.stopPropagation();
- break;
- case 'Tab':
- if (!this.parentNode.alwaysFocusSinglePod)
- this.parentNode.focusPod();
- default:
- this.isActionBoxMenuActive = false;
- break;
- }
- },
-
- /**
- * Handles a keydown event on menu title.
- * @param {Event} e KeyDown event.
- */
- handleMenuTitleElementKeyDown_: function(e) {
- if (this.disabled)
- return;
-
- if (e.key != 'Tab') {
- this.handleActionAreaButtonKeyDown_(e);
- return;
- }
-
- if (e.shiftKey == false) {
- if (this.actionBoxMenuRemoveElement.hidden) {
- this.isActionBoxMenuActive = false;
- } else {
- this.actionBoxMenuRemoveElement.tabIndex =
- UserPodTabOrder.POD_MENU_ITEM;
- this.actionBoxMenuRemoveElement.focus();
- e.preventDefault();
- }
- } else {
- this.isActionBoxMenuActive = false;
- this.focusInput();
- e.preventDefault();
- }
- },
-
- /**
- * Handles a blur event on menu title.
- * @param {Event} e Blur event.
- */
- handleMenuTitleElementBlur_: function(e) {
- if (this.disabled)
- return;
- this.actionBoxMenuTitleElement.tabIndex = -1;
- },
-
- /**
- * Handles a click event on remove user command.
- * @param {Event} e Click event.
- */
- handleRemoveCommandClick_: function(e) {
- this.showRemoveWarning_();
- },
-
- /**
- * Move the action box menu up if needed.
- */
- moveActionMenuUpIfNeeded_: function() {
- // Skip checking (computationally expensive) if already moved up.
- if (this.actionBoxMenu.classList.contains('menu-moved-up'))
- return;
-
- // Move up the menu if it overlaps shelf.
- var maxHeight = cr.ui.LoginUITools.getMaxHeightBeforeShelfOverlapping(
- this.actionBoxMenu, true);
- var actualHeight = parseInt(
- window.getComputedStyle(this.actionBoxMenu).height);
- if (maxHeight < actualHeight) {
- this.actionBoxMenu.classList.add('menu-moved-up');
- this.actionBoxAreaElement.classList.add('menu-moved-up');
- }
- },
-
- /**
- * Shows remove user warning. Used for legacy supervised users
- * and non-device-owner on CrOS, and for all users on desktop.
- */
- showRemoveWarning_: function() {
- this.actionBoxMenuRemoveElement.hidden = true;
- this.actionBoxRemoveUserWarningElement.hidden = false;
-
- if (!this.user.isDesktopUser) {
- this.moveActionMenuUpIfNeeded_();
- if (!this.user.legacySupervisedUser) {
- this.querySelector(
- '.action-box-remove-user-warning-text').style.display = 'none';
- this.querySelector(
- '.action-box-remove-user-warning-table-nonsync').style.display
- = 'none';
- var message = loadTimeData.getString('removeNonOwnerUserWarningText');
- this.updateRemoveNonOwnerUserWarningMessage_(this.user.profilePath,
- message);
- }
- } else {
- // Show extra statistics information for desktop users
- this.querySelector(
- '.action-box-remove-non-owner-user-warning-text').hidden = true;
- this.RemoveWarningDialogSetMessage_();
- // set a global handler for the callback
- window.updateRemoveWarningDialog =
- this.updateRemoveWarningDialog_.bind(this);
- var is_synced_user = this.user.emailAddress !== "";
- if (!is_synced_user) {
- chrome.send('removeUserWarningLoadStats', [this.user.profilePath]);
- }
- }
- chrome.send('logRemoveUserWarningShown');
- },
-
- /**
- * Refresh the statistics in the remove user warning dialog.
- * @param {string} profilePath The filepath of the URL (must be verified).
- * @param {Object} profileStats Statistics associated with profileURL.
- */
- updateRemoveWarningDialog_: function(profilePath, profileStats) {
- if (profilePath !== this.user.profilePath)
- return;
-
- var stats_elements = this.statsMapElements;
- // Update individual statistics
- for (var key in profileStats) {
- if (stats_elements.hasOwnProperty(key)) {
- stats_elements[key].textContent = profileStats[key].count;
- }
- }
- },
-
- /**
- * Set the new message in the dialog.
- */
- RemoveWarningDialogSetMessage_: function() {
- var is_synced_user = this.user.emailAddress !== "";
- message = loadTimeData.getString(
- is_synced_user ? 'removeUserWarningTextSync' :
- 'removeUserWarningTextNonSync');
- this.updateRemoveWarningDialogSetMessage_(this.user.profilePath,
- message);
- },
-
- /**
- * Refresh the message in the remove user warning dialog.
- * @param {string} profilePath The filepath of the URL (must be verified).
- * @param {string} message The message to be written.
- * @param {number|string=} count The number or string to replace $1 in
- * |message|. Can be omitted if $1 is not present in |message|.
- */
- updateRemoveWarningDialogSetMessage_: function(profilePath, message,
- count) {
- if (profilePath !== this.user.profilePath)
- return;
- // Add localized messages where $1 will be replaced with
- // <span class="total-count"></span> and $2 will be replaced with
- // <span class="email"></span>.
- var element = this.querySelector('.action-box-remove-user-warning-text');
- element.textContent = '';
-
- messageParts = message.split(/(\$[12])/);
- var numParts = messageParts.length;
- for (var j = 0; j < numParts; j++) {
- if (messageParts[j] === '$1') {
- var elementToAdd = document.createElement('span');
- elementToAdd.classList.add('total-count');
- elementToAdd.textContent = count;
- element.appendChild(elementToAdd);
- } else if (messageParts[j] === '$2') {
- var elementToAdd = document.createElement('span');
- elementToAdd.classList.add('email');
- elementToAdd.textContent = this.user.emailAddress;
- element.appendChild(elementToAdd);
- } else {
- element.appendChild(document.createTextNode(messageParts[j]));
- }
- }
- this.moveActionMenuUpIfNeeded_();
- },
-
- /**
- * Update the message in the "remove non-owner user warning" dialog on CrOS.
- * @param {string} profilePath The filepath of the URL (must be verified).
- * @param (string) message The message to be written.
- */
- updateRemoveNonOwnerUserWarningMessage_: function(profilePath, message) {
- if (profilePath !== this.user.profilePath)
- return;
- // Add localized messages where $1 will be replaced with
- // <span class="email"></span>.
- var element = this.querySelector(
- '.action-box-remove-non-owner-user-warning-text');
- element.textContent = '';
-
- messageParts = message.split(/(\$[1])/);
- var numParts = messageParts.length;
- for (var j = 0; j < numParts; j++) {
- if (messageParts[j] == '$1') {
- var elementToAdd = document.createElement('span');
- elementToAdd.classList.add('email');
- elementToAdd.textContent = this.user.emailAddress;
- element.appendChild(elementToAdd);
- } else {
- element.appendChild(document.createTextNode(messageParts[j]));
- }
- }
- this.moveActionMenuUpIfNeeded_();
- },
-
- /**
- * Handles a click event on remove user confirmation button.
- * @param {Event} e Click event.
- */
- handleRemoveUserConfirmationClick_: function(e) {
- if (this.isActionBoxMenuActive) {
- this.isActionBoxMenuActive = false;
- this.removeUser(this.user);
- e.stopPropagation();
- }
- },
-
- /**
- * Handles mouseover event on fingerprint icon.
- * @param {Event} e MouseOver event.
- */
- handleFingerprintIconMouseOver_: function(e) {
- var bubbleContent = document.createElement('div');
- bubbleContent.textContent =
- loadTimeData.getString('fingerprintIconMessage');
- this.passwordElement.placeholder =
- loadTimeData.getString('fingerprintHint');
-
- /** @const */ var BUBBLE_OFFSET = 25;
- /** @const */ var BUBBLE_PADDING = -8;
- var attachment = this.isPinShown() ? cr.ui.Bubble.Attachment.RIGHT :
- cr.ui.Bubble.Attachment.BOTTOM;
- var bubbleAnchor = this.getBubbleAnchorForFingerprintIcon_();
- $('bubble').showContentForElement(
- bubbleAnchor, attachment, bubbleContent, BUBBLE_OFFSET,
- BUBBLE_PADDING, true);
- },
-
- /**
- * Handles mouseout event on fingerprint icon.
- * @param {Event} e MouseOut event.
- */
- handleFingerprintIconMouseOut_: function(e) {
- var bubbleAnchor = this.getBubbleAnchorForFingerprintIcon_();
- $('bubble').hideForElement(bubbleAnchor);
- this.passwordElement.placeholder = loadTimeData.getString(
- this.isPinShown() ? 'pinKeyboardPlaceholderPinPassword' :
- 'passwordHint');
- },
-
- /**
- * Returns bubble anchor of the fingerprint icon.
- * @return {!HTMLElement} Anchor element of the bubble.
- */
- getBubbleAnchorForFingerprintIcon_: function() {
- var bubbleAnchor = this;
- if (this.isPinShown())
- bubbleAnchor = (this.getElementsByClassName('auth-container'))[0];
- return bubbleAnchor;
- },
-
- /**
- * Handles a keydown event on remove user confirmation button.
- * @param {Event} e KeyDown event.
- */
- handleRemoveUserConfirmationKeyDown_: function(e) {
- if (!this.isActionBoxMenuActive)
- return;
-
- // Only handle pressing 'Enter' or 'Space', and let all other events
- // bubble to the action box menu.
- if (e.key == 'Enter' || e.key == ' ') {
- this.isActionBoxMenuActive = false;
- this.removeUser(this.user);
- e.stopPropagation();
- // Prevent default so that we don't trigger a 'click' event.
- e.preventDefault();
- }
- },
-
- /**
- * Handles a keydown event on remove command.
- * @param {Event} e KeyDown event.
- */
- handleRemoveCommandKeyDown_: function(e) {
- if (this.disabled)
- return;
- switch (e.key) {
- case 'Enter':
- e.preventDefault();
- this.showRemoveWarning_();
- e.stopPropagation();
- break;
- case 'ArrowUp':
- case 'ArrowDown':
- e.stopPropagation();
- break;
- // Ignore these two, so ChromeVox hotkeys don't close the menu before
- // they can navigate through it.
- case 'Shift':
- case 'Meta':
- break;
- case 'Escape':
- this.actionBoxAreaElement.focus();
- this.isActionBoxMenuActive = false;
- e.stopPropagation();
- break;
- default:
- this.actionBoxAreaElement.focus();
- this.isActionBoxMenuActive = false;
- break;
- }
- },
-
- /**
- * Handles a blur event on remove command.
- * @param {Event} e Blur event.
- */
- handleRemoveCommandBlur_: function(e) {
- if (this.disabled)
- return;
- this.actionBoxMenuRemoveElement.tabIndex = -1;
- },
-
- /**
- * Handles mouse down event. It sets whether the user click auth will be
- * allowed on the next mouse click event. The auth is allowed iff the pod
- * was focused on the mouse down event starting the click.
- * @param {Event} e The mouse down event.
- */
- handlePodMouseDown_: function(e) {
- this.userClickAuthAllowed_ = this.parentNode.isFocused(this);
- },
-
- /**
- * Called when the input of the password element changes. Updates the submit
- * button color and state and hides the error popup bubble.
- */
- updateInput_: function() {
- if (this.submitButton) {
- this.submitButton.disabled = this.passwordElement.value.length == 0;
- if (this.isFingerprintIconShown()) {
- this.submitButton.hidden = this.passwordElement.value.length == 0;
- } else {
- this.submitButton.hidden = false;
- }
- }
- this.showError = false;
- $('bubble').hide();
- },
-
- /**
- * Handles input event on the password element.
- * @param {Event} e Input event.
- */
- handleInputChanged_: function(e) {
- this.updateInput_();
- },
-
- /**
- * Handles click event on a user pod.
- * @param {Event} e Click event.
- */
- handleClickOnPod_: function(e) {
- if (this.parentNode.disabled)
- return;
-
- if (!this.isActionBoxMenuActive) {
- if (this.isAuthTypeOnlineSignIn) {
- this.showSigninUI();
- } else if (this.isAuthTypeUserClick && this.userClickAuthAllowed_) {
- // Note that this.userClickAuthAllowed_ is set in mouse down event
- // handler.
- this.parentNode.setActivatedPod(this);
- } else if (this.pinKeyboard &&
- e.target == this.pinKeyboard.submitButton) {
- // Sets the pod as activated if the submit button is clicked so that
- // it simulates what the enter button does for the password/pin.
- this.parentNode.setActivatedPod(this);
- }
-
- if (this.multiProfilesPolicyApplied)
- this.userTypeBubbleElement.classList.add('bubble-shown');
-
- // Prevent default so that we don't trigger 'focus' event and
- // stop propagation so that the 'click' event does not bubble
- // up and accidentally closes the bubble tooltip.
- stopEventPropagation(e);
- }
- },
-
- /**
- * Handles keydown event for a user pod.
- * @param {Event} e Key event.
- */
- handlePodKeyDown_: function(e) {
- if (!this.isAuthTypeUserClick || this.disabled)
- return;
- switch (e.key) {
- case 'Enter':
- case ' ':
- if (this.parentNode.isFocused(this))
- this.parentNode.setActivatedPod(this);
- break;
- }
- }
- };
-
- /**
- * Creates a public account user pod.
- * @constructor
- * @extends {UserPod}
- */
- var PublicAccountUserPod = cr.ui.define(function() {
- var node = UserPod();
-
- var extras = $('public-account-user-pod-extras-template').children;
- for (var i = 0; i < extras.length; ++i) {
- var el = extras[i].cloneNode(true);
- node.appendChild(el);
- }
-
- return node;
- });
-
- PublicAccountUserPod.prototype = {
- __proto__: UserPod.prototype,
-
- /**
- * "Enter" button in expanded side pane.
- * @type {!HTMLButtonElement}
- */
- get enterButtonElement() {
- return this.querySelector('.enter-button');
- },
-
- /**
- * Boolean flag of whether the pod is showing the side pane. The flag
- * controls whether 'expanded' class is added to the pod's class list and
- * resets tab order because main input element changes when the 'expanded'
- * state changes.
- * @type {boolean}
- */
- get expanded() {
- return this.classList.contains('expanded');
- },
-
- set expanded(expanded) {
- if (this.expanded == expanded)
- return;
-
- this.resetTabOrder();
- this.classList.toggle('expanded', expanded);
- if (expanded) {
- // Show the advanced expanded pod directly if there are at least two
- // recommended locales. This will be the case in multilingual
- // environments where users are likely to want to choose among locales.
- if (this.querySelector('.language-select').multipleRecommendedLocales)
- this.classList.add('advanced');
- this.usualLeft = this.left;
- this.makeSpaceForExpandedPod_();
- } else if (typeof(this.usualLeft) != 'undefined') {
- this.left = this.usualLeft;
- }
-
- var self = this;
- this.classList.add('animating');
- this.addEventListener('transitionend', function f(e) {
- self.removeEventListener('transitionend', f);
- self.classList.remove('animating');
-
- // Accessibility focus indicator does not move with the focused
- // element. Sends a 'focus' event on the currently focused element
- // so that accessibility focus indicator updates its location.
- if (document.activeElement)
- document.activeElement.dispatchEvent(new Event('focus'));
- });
- // Guard timer set to animation duration + 20ms.
- ensureTransitionEndEvent(this, 200);
- },
-
- get advanced() {
- return this.classList.contains('advanced');
- },
-
- /** @override */
- get mainInput() {
- if (this.expanded)
- return this.enterButtonElement;
- else
- return this.nameElement;
- },
-
- /** @override */
- decorate: function() {
- UserPod.prototype.decorate.call(this);
-
- this.classList.add('public-account');
-
- this.nameElement.addEventListener('keydown', (function(e) {
- if (e.key == 'Enter') {
- this.parentNode.setActivatedPod(this, e);
- // Stop this keydown event from bubbling up to PodRow handler.
- e.stopPropagation();
- // Prevent default so that we don't trigger a 'click' event on the
- // newly focused "Enter" button.
- e.preventDefault();
- }
- }).bind(this));
-
- var languageSelect = this.querySelector('.language-select');
- languageSelect.tabIndex = UserPodTabOrder.POD_INPUT;
- languageSelect.manuallyChanged = false;
- languageSelect.addEventListener(
- 'change',
- function() {
- languageSelect.manuallyChanged = true;
- this.getPublicSessionKeyboardLayouts_();
- }.bind(this));
-
- var keyboardSelect = this.querySelector('.keyboard-select');
- keyboardSelect.tabIndex = UserPodTabOrder.POD_INPUT;
- keyboardSelect.loadedLocale = null;
-
- var languageAndInput = this.querySelector('.language-and-input');
- languageAndInput.tabIndex = UserPodTabOrder.POD_INPUT;
- languageAndInput.addEventListener('click',
- this.transitionToAdvanced_.bind(this));
-
- var monitoringLearnMore = this.querySelector('.monitoring-learn-more');
- monitoringLearnMore.tabIndex = UserPodTabOrder.POD_INPUT;
- monitoringLearnMore.addEventListener(
- 'click', this.onMonitoringLearnMoreClicked_.bind(this));
-
- this.enterButtonElement.addEventListener('click', (function(e) {
- this.enterButtonElement.disabled = true;
- var locale = this.querySelector('.language-select').value;
- var keyboardSelect = this.querySelector('.keyboard-select');
- // The contents of |keyboardSelect| is updated asynchronously. If its
- // locale does not match |locale|, it has not updated yet and the
- // currently selected keyboard layout may not be applicable to |locale|.
- // Do not return any keyboard layout in this case and let the backend
- // choose a suitable layout.
- var keyboardLayout =
- keyboardSelect.loadedLocale == locale ? keyboardSelect.value : '';
- chrome.send('launchPublicSession',
- [this.user.username, locale, keyboardLayout]);
- }).bind(this));
- },
-
- /** @override **/
- initialize: function() {
- UserPod.prototype.initialize.call(this);
-
- id = this.user.username + '-keyboard';
- this.querySelector('.keyboard-select-label').htmlFor = id;
- this.querySelector('.keyboard-select').setAttribute('id', id);
-
- var id = this.user.username + '-language';
- this.querySelector('.language-select-label').htmlFor = id;
- var languageSelect = this.querySelector('.language-select');
- languageSelect.setAttribute('id', id);
- this.populateLanguageSelect(this.user.initialLocales,
- this.user.initialLocale,
- this.user.initialMultipleRecommendedLocales);
- },
-
- /** @override **/
- update: function() {
- UserPod.prototype.update.call(this);
- this.querySelector('.expanded-pane-name').textContent =
- this.user_.displayName;
- this.querySelector('.info').textContent =
- loadTimeData.getStringF('publicAccountInfoFormat',
- this.user_.enterpriseDomainManager);
- },
-
- /** @override */
- focusInput: function() {
- // Move tabIndex from the whole pod to the main input.
- this.tabIndex = -1;
- this.mainInput.tabIndex = UserPodTabOrder.POD_INPUT;
- this.mainInput.focus();
- },
-
- /** @override */
- reset: function(takeFocus) {
- if (!takeFocus)
- this.expanded = false;
- this.enterButtonElement.disabled = false;
- UserPod.prototype.reset.call(this, takeFocus);
- },
-
- /** @override */
- activate: function(e) {
- if (!this.expanded) {
- this.expanded = true;
- this.focusInput();
- }
- return true;
- },
-
- /** @override */
- handleClickOnPod_: function(e) {
- if (this.parentNode.disabled)
- return;
-
- this.parentNode.focusPod(this);
- this.parentNode.setActivatedPod(this, e);
- // Prevent default so that we don't trigger 'focus' event.
- e.preventDefault();
- },
-
- /**
- * Updates the display name shown on the pod.
- * @param {string} displayName The new display name
- */
- setDisplayName: function(displayName) {
- this.user_.displayName = displayName;
- this.update();
- },
-
- makeSpaceForExpandedPod_: function() {
- var width = this.classList.contains('advanced') ?
- PUBLIC_EXPANDED_ADVANCED_WIDTH : PUBLIC_EXPANDED_BASIC_WIDTH;
- var isDesktopUserManager = Oobe.getInstance().displayType ==
- DISPLAY_TYPE.DESKTOP_USER_MANAGER;
- var rowPadding = isDesktopUserManager ? DESKTOP_ROW_PADDING :
- POD_ROW_PADDING;
- if (this.left + width > $('pod-row').offsetWidth - rowPadding)
- this.left = $('pod-row').offsetWidth - rowPadding - width;
- },
-
- /**
- * Transition the expanded pod from the basic to the advanced view.
- */
- transitionToAdvanced_: function() {
- var pod = this;
- var languageAndInputSection =
- this.querySelector('.language-and-input-section');
- this.classList.add('transitioning-to-advanced');
- setTimeout(function() {
- pod.classList.add('advanced');
- pod.makeSpaceForExpandedPod_();
- languageAndInputSection.addEventListener('transitionend',
- function observer() {
- languageAndInputSection.removeEventListener('transitionend',
- observer);
- pod.classList.remove('transitioning-to-advanced');
- pod.querySelector('.language-select').focus();
- });
- // Guard timer set to animation duration + 20ms.
- ensureTransitionEndEvent(languageAndInputSection, 380);
- }, 0);
- },
-
- /**
- * Show a dialog when user clicks on learn more (monitoring) button.
- */
- onMonitoringLearnMoreClicked_: function() {
- if (!this.dialogContainer_) {
- this.dialogContainer_ = document.createElement('div');
- this.dialogContainer_.classList.add('monitoring-dialog-container');
- var topContainer = document.querySelector('#scroll-container');
- topContainer.appendChild(this.dialogContainer_);
- }
- // Public Session POD in advanced view has a different size so add a dummy
- // parent element to enable different CSS settings.
- this.dialogContainer_.classList.toggle(
- 'advanced', this.classList.contains('advanced'))
- var html = '';
- var infoItems = ['publicAccountMonitoringInfoItem1',
- 'publicAccountMonitoringInfoItem2',
- 'publicAccountMonitoringInfoItem3',
- 'publicAccountMonitoringInfoItem4'];
- for (item of infoItems) {
- html += '<p class="cr-dialog-item">';
- html += loadTimeData.getString(item);
- html += '</p>';
- }
- var title = loadTimeData.getString('publicAccountMonitoringInfo');
- this.dialog_ = new cr.ui.dialogs.BaseDialog(this.dialogContainer_);
- this.dialog_.showHtml(title, html, undefined,
- this.onMonitoringDialogClosed_.bind(this));
- this.parentNode.disabled = true;
- },
-
- /**
- * Cleanup after the monitoring warning dialog is closed.
- */
- onMonitoringDialogClosed_: function() {
- this.parentNode.disabled = false;
- this.dialog_ = undefined;
- },
-
- /**
- * Retrieves the list of keyboard layouts available for the currently
- * selected locale.
- */
- getPublicSessionKeyboardLayouts_: function() {
- var selectedLocale = this.querySelector('.language-select').value;
- if (selectedLocale ==
- this.querySelector('.keyboard-select').loadedLocale) {
- // If the list of keyboard layouts was loaded for the currently selected
- // locale, it is already up to date.
- return;
- }
- chrome.send('getPublicSessionKeyboardLayouts',
- [this.user.username, selectedLocale]);
- },
-
- /**
- * Populates the keyboard layout "select" element with a list of layouts.
- * @param {string} locale The locale to which this list of keyboard layouts
- * applies
- * @param {!Object} list List of available keyboard layouts
- */
- populateKeyboardSelect: function(locale, list) {
- if (locale != this.querySelector('.language-select').value) {
- // The selected locale has changed and the list of keyboard layouts is
- // not applicable. This method will be called again when a list of
- // keyboard layouts applicable to the selected locale is retrieved.
- return;
- }
-
- var keyboardSelect = this.querySelector('.keyboard-select');
- keyboardSelect.loadedLocale = locale;
- keyboardSelect.innerHTML = '';
- for (var i = 0; i < list.length; ++i) {
- var item = list[i];
- keyboardSelect.appendChild(
- new Option(item.title, item.value, item.selected, item.selected));
- }
- },
-
- /**
- * Populates the language "select" element with a list of locales.
- * @param {!Object} locales The list of available locales
- * @param {string} defaultLocale The locale to select by default
- * @param {boolean} multipleRecommendedLocales Whether |locales| contains
- * two or more recommended locales
- */
- populateLanguageSelect: function(locales,
- defaultLocale,
- multipleRecommendedLocales) {
- var languageSelect = this.querySelector('.language-select');
- // If the user manually selected a locale, do not change the selection.
- // Otherwise, select the new |defaultLocale|.
- var selected =
- languageSelect.manuallyChanged ? languageSelect.value : defaultLocale;
- languageSelect.innerHTML = '';
- var group = languageSelect;
- for (var i = 0; i < locales.length; ++i) {
- var item = locales[i];
- if (item.optionGroupName) {
- group = document.createElement('optgroup');
- group.label = item.optionGroupName;
- languageSelect.appendChild(group);
- } else {
- group.appendChild(new Option(item.title,
- item.value,
- item.value == selected,
- item.value == selected));
- }
- }
- languageSelect.multipleRecommendedLocales = multipleRecommendedLocales;
-
- // Retrieve a list of keyboard layouts applicable to the locale that is
- // now selected.
- this.getPublicSessionKeyboardLayouts_();
- }
- };
-
- /**
- * Creates a user pod to be used only in desktop chrome.
- * @constructor
- * @extends {UserPod}
- */
- var DesktopUserPod = cr.ui.define(function() {
- // Don't just instantiate a UserPod(), as this will call decorate() on the
- // parent object, and add duplicate event listeners.
- var node = $('user-pod-template').cloneNode(true);
- node.removeAttribute('id');
- return node;
- });
-
- DesktopUserPod.prototype = {
- __proto__: UserPod.prototype,
-
- /** @override */
- initialize: function() {
- if (this.user.needsSignin) {
- if (this.user.hasLocalCreds) {
- this.user.initialAuthType = AUTH_TYPE.OFFLINE_PASSWORD;
- } else {
- this.user.initialAuthType = AUTH_TYPE.ONLINE_SIGN_IN;
- }
- }
- UserPod.prototype.initialize.call(this);
- },
-
- /** @override */
- get mainInput() {
- if (this.user.needsSignin && this.user.hasLocalCreds)
- return this.passwordElement;
- else
- return this.nameElement;
- },
-
- /** @override */
- update: function() {
- this.imageElement.src = this.user.userImage;
- this.animatedImageElement.src = this.user.userImage;
- this.nameElement.textContent = this.user.displayName;
- this.reauthNameHintElement.textContent = this.user.displayName;
-
- var isLockedUser = this.user.needsSignin;
- var isLegacySupervisedUser = this.user.legacySupervisedUser;
- var isChildUser = this.user.childUser;
- var isSyncedUser = this.user.emailAddress !== "";
- var isProfileLoaded = this.user.isProfileLoaded;
- this.classList.toggle('locked', isLockedUser);
- this.classList.toggle('legacy-supervised', isLegacySupervisedUser);
- this.classList.toggle('child', isChildUser);
- this.classList.toggle('synced', isSyncedUser);
-
- if (this.isAuthTypeUserClick)
- this.passwordLabelElement.textContent = this.authValue;
-
- this.passwordElement.setAttribute('aria-label', loadTimeData.getStringF(
- 'passwordFieldAccessibleName', this.user_.emailAddress));
-
- UserPod.prototype.updateActionBoxArea.call(this);
- },
-
- /** @override */
- activate: function(e) {
- if (!this.user.needsSignin) {
- Oobe.launchUser(this.user.profilePath);
- } else if (this.user.hasLocalCreds && !this.passwordElement.value) {
- return false;
- } else {
- chrome.send('authenticatedLaunchUser',
- [this.user.profilePath,
- this.user.emailAddress,
- this.passwordElement.value]);
- }
- this.passwordElement.value = '';
- return true;
- },
-
- /** @override */
- handleClickOnPod_: function(e) {
- if (this.parentNode.disabled)
- return;
-
- Oobe.clearErrors();
- this.parentNode.lastFocusedPod_ = this;
-
- // If this is a locked pod and there are local credentials, show the
- // password field. Otherwise call activate() which will open up a browser
- // window or show the reauth dialog, as needed.
- if (!(this.user.needsSignin && this.user.hasLocalCreds) &&
- !this.isActionBoxMenuActive) {
- this.activate(e);
- }
-
- if (this.isAuthTypeUserClick)
- chrome.send('attemptUnlock', [this.user.emailAddress]);
- },
- };
-
- /**
- * Creates a new pod row element.
- * @constructor
- * @extends {HTMLDivElement}
- */
- var PodRow = cr.ui.define('podrow');
-
- PodRow.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- // Whether this user pod row is shown for the first time.
- firstShown_: true,
-
- // True if inside focusPod().
- insideFocusPod_: false,
-
- // Focused pod.
- focusedPod_: undefined,
-
- // Activated pod, i.e. the pod of current login attempt.
- activatedPod_: undefined,
-
- // Pod that was most recently focused, if any.
- lastFocusedPod_: undefined,
-
- // Pods whose initial images haven't been loaded yet.
- podsWithPendingImages_: [],
-
- // Whether pod placement has been postponed.
- podPlacementPostponed_: false,
-
- // Standard user pod height/width.
- userPodHeight_: 0,
- userPodWidth_: 0,
-
- // Array of users that are shown (public/supervised/regular).
- users_: [],
-
- // If we're in tablet mode.
- tabletModeEnabled_: false,
-
- /** @override */
- decorate: function() {
- // Event listeners that are installed for the time period during which
- // the element is visible.
- this.listeners_ = {
- focus: [this.handleFocus_.bind(this), true /* useCapture */],
- click: [this.handleClick_.bind(this), true],
- mousemove: [this.handleMouseMove_.bind(this), false],
- keydown: [this.handleKeyDown.bind(this), false]
- };
-
- var isDesktopUserManager = Oobe.getInstance().displayType ==
- DISPLAY_TYPE.DESKTOP_USER_MANAGER;
- var isNewDesktopUserManager = Oobe.getInstance().newDesktopUserManager;
- this.userPodHeight_ = isDesktopUserManager ?
- isNewDesktopUserManager ? MD_DESKTOP_POD_HEIGHT :
- DESKTOP_POD_HEIGHT :
- CROS_POD_HEIGHT;
- this.userPodWidth_ = isDesktopUserManager ?
- isNewDesktopUserManager ? MD_DESKTOP_POD_WIDTH :
- DESKTOP_POD_WIDTH :
- CROS_POD_WIDTH;
- },
-
- /**
- * Returns all the pods in this pod row.
- * @type {NodeList}
- */
- get pods() {
- return Array.prototype.slice.call(this.children);
- },
-
- /**
- * Return true if user pod row has only single user pod in it, which should
- * always be focused except desktop and tablet modes.
- * @type {boolean}
- */
- get alwaysFocusSinglePod() {
- var isDesktopUserManager = Oobe.getInstance().displayType ==
- DISPLAY_TYPE.DESKTOP_USER_MANAGER;
-
- return (isDesktopUserManager || this.tabletModeEnabled_) ?
- false :
- this.children.length == 1;
- },
-
- /**
- * Returns pod with the given username (null if there is no such pod).
- * @param {string} username Username to be matched.
- * @return {Object} Pod with the given username. null if pod hasn't been
- * found.
- */
- getPodWithUsername_: function(username) {
- for (var i = 0, pod; pod = this.pods[i]; ++i) {
- if (pod.user.username == username)
- return pod;
- }
- return null;
- },
-
- /**
- * True if the the pod row is disabled (handles no user interaction).
- * @type {boolean}
- */
- disabled_: false,
- get disabled() {
- return this.disabled_;
- },
- set disabled(value) {
- this.disabled_ = value;
- this.pods.forEach(function(pod) {
- pod.disabled = value;
- });
- },
-
- /**
- * Creates a user pod from given email.
- * @param {!Object} user User info dictionary.
- */
- createUserPod: function(user) {
- var userPod;
- if (user.isDesktopUser)
- userPod = new DesktopUserPod({user: user});
- else if (user.publicAccount)
- userPod = new PublicAccountUserPod({user: user});
- else
- userPod = new UserPod({user: user});
-
- userPod.hidden = false;
- return userPod;
- },
-
- /**
- * Add an existing user pod to this pod row.
- * @param {!Object} user User info dictionary.
- */
- addUserPod: function(user) {
- var userPod = this.createUserPod(user);
- this.appendChild(userPod);
- userPod.initialize();
- },
-
- /**
- * Performs visual changes on the user pod if there is an error.
- * @param {boolean} visible Whether to show or hide the display.
- */
- setFocusedPodErrorDisplay: function(visible) {
- if (this.focusedPod_)
- this.focusedPod_.showError = visible;
- },
-
- /**
- * Shows or hides the pin keyboard for the current focused pod.
- * @param {boolean} visible
- */
- setFocusedPodPinVisibility: function(visible) {
- if (this.focusedPod_)
- this.focusedPod_.setPinVisibility(visible);
- },
-
- /**
- * Enables or disables the pin keyboard for the given user. A disabled pin
- * keyboard will never be displayed.
- *
- * If the user's pod is focused, then enabling the pin keyboard will display
- * it; disabling the pin keyboard will hide it.
- * @param {!string} username
- * @param {boolean} enabled
- */
- setPinEnabled: function(username, enabled) {
- var pod = this.getPodWithUsername_(username);
- if (!pod) {
- console.error('Attempt to enable/disable pin keyboard of missing pod.');
- return;
- }
-
- // Make sure to set |pinEnabled| before toggling visiblity to avoid
- // validation errors.
- pod.pinEnabled = enabled;
-
- if (this.focusedPod_ == pod) {
- if (enabled) {
- ensurePinKeyboardLoaded(
- this.setPinVisibility.bind(this, username, true));
- } else {
- this.setPinVisibility(username, false);
- }
- }
- },
-
- /**
- * Shows or hides the pin keyboard from the pod with the given |username|.
- * This is only a visibility change; the pin keyboard can be reshown.
- *
- * Use setPinEnabled if the pin keyboard should be disabled for the given
- * user.
- * @param {!user} username
- * @param {boolean} visible
- */
- setPinVisibility: function(username, visible) {
- var pod = this.getPodWithUsername_(username);
- if (!pod) {
- console.error('Attempt to show/hide pin keyboard of missing pod.');
- return;
- }
- if (visible && pod.pinEnabled === false) {
- console.error('Attempt to show disabled pin keyboard');
- return;
- }
- if (visible && this.focusedPod_ != pod) {
- console.error('Attempt to show pin keyboard on non-focused pod');
- return;
- }
-
- pod.setPinVisibility(visible);
- },
-
- /**
- * Removes user pod from pod row.
- * @param {!user} username
- */
- removeUserPod: function(username) {
- var podToRemove = this.getPodWithUsername_(username);
- if (podToRemove == null) {
- console.warn('Attempt to remove pod that does not exist');
- return;
- }
- this.removeChild(podToRemove);
- if (this.pods.length > 0)
- this.placePods_();
- },
-
- /**
- * Returns index of given pod or -1 if not found.
- * @param {UserPod} pod Pod to look up.
- * @private
- */
- indexOf_: function(pod) {
- for (var i = 0; i < this.pods.length; ++i) {
- if (pod == this.pods[i])
- return i;
- }
- return -1;
- },
-
- /**
- * Populates pod row with given existing users and start init animation.
- * @param {array} users Array of existing user emails.
- */
- loadPods: function(users) {
- this.users_ = users;
-
- this.rebuildPods();
- },
-
- /**
- * Scrolls focused user pod into view.
- */
- scrollFocusedPodIntoView: function() {
- var pod = this.focusedPod_;
- if (!pod)
- return;
-
- // First check whether focused pod is already fully visible.
- var visibleArea = $('scroll-container');
- // Visible area may not defined at user manager screen on all platforms.
- // Windows, Mac and Linux do not have visible area.
- if (!visibleArea)
- return;
- var scrollTop = visibleArea.scrollTop;
- var clientHeight = visibleArea.clientHeight;
- var podTop = $('oobe').offsetTop + pod.offsetTop;
- var padding = USER_POD_KEYBOARD_MIN_PADDING;
- if (podTop + pod.height + padding <= scrollTop + clientHeight &&
- podTop - padding >= scrollTop) {
- return;
- }
-
- // Scroll so that user pod is as centered as possible.
- visibleArea.scrollTop = podTop - (clientHeight - pod.offsetHeight) / 2;
- },
-
- /**
- * Rebuilds pod row using users_ that were previously set or updated.
- */
- rebuildPods: function() {
- var emptyPodRow = this.pods.length == 0;
-
- // Clear existing pods.
- this.innerHTML = '';
- this.focusedPod_ = undefined;
- this.activatedPod_ = undefined;
- this.lastFocusedPod_ = undefined;
-
- // Switch off animation
- Oobe.getInstance().toggleClass('flying-pods', false);
-
- // Populate the pod row.
- for (var i = 0; i < this.users_.length; ++i)
- this.addUserPod(this.users_[i]);
-
- for (var i = 0, pod; pod = this.pods[i]; ++i)
- this.podsWithPendingImages_.push(pod);
-
- // Make sure we eventually show the pod row, even if some image is stuck.
- setTimeout(function() {
- $('pod-row').classList.remove('images-loading');
- }, POD_ROW_IMAGES_LOAD_TIMEOUT_MS);
-
- var isAccountPicker =
- $('login-header-bar').signinUIState == OOBE_UI_STATE.ACCOUNT_PICKER;
-
- // Immediately recalculate pods layout only when current UI is account
- // picker. Otherwise postpone it.
- if (isAccountPicker) {
- this.placePods_();
- this.maybePreselectPod();
-
- // Without timeout changes in pods positions will be animated even
- // though it happened when 'flying-pods' class was disabled.
- setTimeout(function() {
- Oobe.getInstance().toggleClass('flying-pods', true);
- }, 0);
- } else {
- this.podPlacementPostponed_ = true;
- }
- },
-
- /**
- * Shows a custom icon on a user pod besides the input field.
- * @param {string} username Username of pod to add button
- * @param {!{id: !string,
- * hardlockOnClick: boolean,
- * isTrialRun: boolean,
- * ariaLabel: string | undefined,
- * tooltip: ({text: string, autoshow: boolean} | undefined)}} icon
- * The icon parameters.
- */
- showUserPodCustomIcon: function(username, icon) {
- var pod = this.getPodWithUsername_(username);
- if (pod == null) {
- console.error('Unable to show user pod button: user pod not found.');
- return;
- }
-
- if (!icon.id && !icon.tooltip)
- return;
-
- if (icon.id)
- pod.customIconElement.setIcon(icon.id);
-
- if (icon.isTrialRun) {
- pod.customIconElement.setInteractive(
- this.onDidClickLockIconDuringTrialRun_.bind(this, username));
- } else if (icon.hardlockOnClick) {
- pod.customIconElement.setInteractive(
- this.hardlockUserPod_.bind(this, username));
- } else {
- pod.customIconElement.setInteractive(null);
- }
-
- var ariaLabel = icon.ariaLabel || (icon.tooltip && icon.tooltip.text);
- if (ariaLabel)
- pod.customIconElement.setAriaLabel(ariaLabel);
- else
- console.warn('No ARIA label for user pod custom icon.');
-
- pod.customIconElement.show();
-
- // This has to be called after |show| in case the tooltip should be shown
- // immediatelly.
- pod.customIconElement.setTooltip(
- icon.tooltip || {text: '', autoshow: false});
-
- // Hide fingerprint icon when custom icon is shown.
- this.setUserPodFingerprintIcon(username, FINGERPRINT_STATES.HIDDEN);
- },
-
- /**
- * Hard-locks user pod for the user. If user pod is hard-locked, it can be
- * only unlocked using password, and the authentication type cannot be
- * changed.
- * @param {!string} username The user's username.
- * @private
- */
- hardlockUserPod_: function(username) {
- chrome.send('hardlockPod', [username]);
- },
-
- /**
- * Records a metric indicating that the user clicked on the lock icon during
- * the trial run for Easy Unlock.
- * @param {!string} username The user's username.
- * @private
- */
- onDidClickLockIconDuringTrialRun_: function(username) {
- chrome.send('recordClickOnLockIcon', [username]);
- },
-
- /**
- * Hides the custom icon in the user pod added by showUserPodCustomIcon().
- * @param {string} username Username of pod to remove button
- */
- hideUserPodCustomIcon: function(username) {
- var pod = this.getPodWithUsername_(username);
- if (pod == null) {
- console.error('Unable to hide user pod button: user pod not found.');
- return;
- }
-
- // TODO(tengs): Allow option for a fading transition.
- pod.customIconElement.hide();
-
- // Show fingerprint icon if applicable.
- this.setUserPodFingerprintIcon(username, FINGERPRINT_STATES.DEFAULT);
- },
-
- /**
- * Set a fingerprint icon in the user pod of |username|.
- * @param {string} username Username of the selected user
- * @param {number} state Fingerprint unlock state
- */
- setUserPodFingerprintIcon: function(username, state) {
- var pod = this.getPodWithUsername_(username);
- if (pod == null) {
- console.error(
- 'Unable to set user pod fingerprint icon: user pod not found.');
- return;
- }
- pod.fingerprintAuthenticated_ = false;
- if (!pod.fingerprintIconElement)
- return;
- if (!pod.user.allowFingerprint || state == FINGERPRINT_STATES.HIDDEN ||
- !pod.customIconElement.hidden) {
- pod.fingerprintIconElement.hidden = true;
- pod.submitButton.hidden = false;
- return;
- }
-
- FINGERPRINT_STATES_MAPPING.forEach(function(icon) {
- pod.fingerprintIconElement.classList.toggle(
- icon.class, state == icon.state);
- });
- pod.fingerprintIconElement.hidden = false;
- pod.submitButton.hidden = pod.passwordElement.value.length == 0;
- this.updatePasswordField_(pod, state);
- if (state == FINGERPRINT_STATES.DEFAULT)
- return;
-
- pod.fingerprintAuthenticated_ = true;
- this.setActivatedPod(pod);
- if (state == FINGERPRINT_STATES.FAILED) {
- /** @const */ var RESET_ICON_TIMEOUT_MS = 500;
- setTimeout(
- this.resetIconAndPasswordField_.bind(this, pod),
- RESET_ICON_TIMEOUT_MS);
- }
- },
-
- /**
- * Reset the fingerprint icon and password field.
- * @param {UserPod} pod Pod to reset.
- */
- resetIconAndPasswordField_: function(pod) {
- if (!pod.fingerprintIconElement)
- return;
- this.setUserPodFingerprintIcon(
- pod.user.username, FINGERPRINT_STATES.DEFAULT);
- },
-
- /**
- * Remove the fingerprint icon in the user pod.
- * @param {string} username Username of the selected user
- */
- removeUserPodFingerprintIcon: function(username) {
- var pod = this.getPodWithUsername_(username);
- if (pod == null) {
- console.error('No user pod found (when removing fingerprint icon).');
- return;
- }
- this.resetIconAndPasswordField_(pod);
- if (pod.fingerprintIconElement) {
- pod.fingerprintIconElement.parentNode.removeChild(
- pod.fingerprintIconElement);
- }
- pod.submitButton.hidden = false;
- },
-
- /**
- * Updates the password field in the user pod.
- * @param {UserPod} pod Pod to update.
- * @param {number} state Fingerprint unlock state
- */
- updatePasswordField_: function(pod, state) {
- FINGERPRINT_STATES_MAPPING.forEach(function(item) {
- pod.passwordElement.classList.toggle(item.class, state == item.state);
- });
- var placeholderStr = loadTimeData.getString(
- pod.isPinShown() ? 'pinKeyboardPlaceholderPinPassword' :
- 'passwordHint');
- if (state == FINGERPRINT_STATES.SIGNIN) {
- placeholderStr = loadTimeData.getString('fingerprintSigningin');
- } else if (state == FINGERPRINT_STATES.FAILED) {
- placeholderStr = loadTimeData.getString('fingerprintSigninFailed');
- }
- pod.passwordElement.placeholder = placeholderStr;
- },
-
- /**
- * Sets the authentication type used to authenticate the user.
- * @param {string} username Username of selected user
- * @param {number} authType Authentication type, must be one of the
- * values listed in AUTH_TYPE enum.
- * @param {string} value The initial value to use for authentication.
- */
- setAuthType: function(username, authType, value) {
- var pod = this.getPodWithUsername_(username);
- if (pod == null) {
- console.error('Unable to set auth type: user pod not found.');
- return;
- }
- pod.setAuthType(authType, value);
- },
-
- /**
- * Sets the state of tablet mode.
- * @param {boolean} isTabletModeEnabled true if the mode is on.
- */
- setTabletModeState: function(isTabletModeEnabled) {
- this.tabletModeEnabled_ = isTabletModeEnabled;
- this.pods.forEach(function(pod, index) {
- pod.actionBoxAreaElement.classList.toggle(
- 'forced', isTabletModeEnabled);
- });
- },
-
- /**
- * Updates the display name shown on a public session pod.
- * @param {string} userID The user ID of the public session
- * @param {string} displayName The new display name
- */
- setPublicSessionDisplayName: function(userID, displayName) {
- var pod = this.getPodWithUsername_(userID);
- if (pod != null)
- pod.setDisplayName(displayName);
- },
-
- /**
- * Updates the list of locales available for a public session.
- * @param {string} userID The user ID of the public session
- * @param {!Object} locales The list of available locales
- * @param {string} defaultLocale The locale to select by default
- * @param {boolean} multipleRecommendedLocales Whether |locales| contains
- * two or more recommended locales
- */
- setPublicSessionLocales: function(userID,
- locales,
- defaultLocale,
- multipleRecommendedLocales) {
- var pod = this.getPodWithUsername_(userID);
- if (pod != null) {
- pod.populateLanguageSelect(locales,
- defaultLocale,
- multipleRecommendedLocales);
- }
- },
-
- /**
- * Updates the list of available keyboard layouts for a public session pod.
- * @param {string} userID The user ID of the public session
- * @param {string} locale The locale to which this list of keyboard layouts
- * applies
- * @param {!Object} list List of available keyboard layouts
- */
- setPublicSessionKeyboardLayouts: function(userID, locale, list) {
- var pod = this.getPodWithUsername_(userID);
- if (pod != null)
- pod.populateKeyboardSelect(locale, list);
- },
-
- /**
- * Called when window was resized.
- */
- onWindowResize: function() {
- var layout = this.calculateLayout_();
- if (layout.columns != this.columns || layout.rows != this.rows)
- this.placePods_();
-
- // Wrap this in a set timeout so the function is called after the pod is
- // finished transitioning so that we work with the final pod dimensions.
- // If there is no focused pod that may be transitioning when this function
- // is called, we can call scrollFocusedPodIntoView() right away.
- var timeOut = 0;
- if (this.focusedPod_) {
- var style = getComputedStyle(this.focusedPod_);
- timeOut = parseFloat(style.transitionDuration) * 1000;
- }
-
- setTimeout(function() {
- this.scrollFocusedPodIntoView();
- }.bind(this), timeOut);
- },
-
- /**
- * Returns width of podrow having |columns| number of columns.
- * @private
- */
- columnsToWidth_: function(columns) {
- var isDesktopUserManager = Oobe.getInstance().displayType ==
- DISPLAY_TYPE.DESKTOP_USER_MANAGER;
- var margin = isDesktopUserManager ? DESKTOP_MARGIN_BY_COLUMNS[columns] :
- MARGIN_BY_COLUMNS[columns];
- var rowPadding = isDesktopUserManager ? DESKTOP_ROW_PADDING :
- POD_ROW_PADDING;
- return 2 * rowPadding + columns * this.userPodWidth_ +
- (columns - 1) * margin;
- },
-
- /**
- * Returns height of podrow having |rows| number of rows.
- * @private
- */
- rowsToHeight_: function(rows) {
- var isDesktopUserManager = Oobe.getInstance().displayType ==
- DISPLAY_TYPE.DESKTOP_USER_MANAGER;
- var rowPadding = isDesktopUserManager ? DESKTOP_ROW_PADDING :
- POD_ROW_PADDING;
- return 2 * rowPadding + rows * this.userPodHeight_;
- },
-
- /**
- * Calculates number of columns and rows that podrow should have in order to
- * hold as much its pods as possible for current screen size. Also it tries
- * to choose layout that looks good.
- * @return {{columns: number, rows: number}}
- */
- calculateLayout_: function() {
- var preferredColumns = this.pods.length < COLUMNS.length ?
- COLUMNS[this.pods.length] : COLUMNS[COLUMNS.length - 1];
- var maxWidth = Oobe.getInstance().clientAreaSize.width;
- var columns = preferredColumns;
- while (maxWidth < this.columnsToWidth_(columns) && columns > 1)
- --columns;
- var rows = Math.floor((this.pods.length - 1) / columns) + 1;
- if (getComputedStyle(
- $('signin-banner'), null).getPropertyValue('display') != 'none') {
- rows = Math.min(rows, MAX_NUMBER_OF_ROWS_UNDER_SIGNIN_BANNER);
- }
- if (!Oobe.getInstance().newDesktopUserManager) {
- var maxHeigth = Oobe.getInstance().clientAreaSize.height;
- while (maxHeigth < this.rowsToHeight_(rows) && rows > 1)
- --rows;
- }
- // One more iteration if it's not enough cells to place all pods.
- while (maxWidth >= this.columnsToWidth_(columns + 1) &&
- columns * rows < this.pods.length &&
- columns < MAX_NUMBER_OF_COLUMNS) {
- ++columns;
- }
- return {columns: columns, rows: rows};
- },
-
- /**
- * Places pods onto their positions onto pod grid.
- * @private
- */
- placePods_: function() {
- var isDesktopUserManager = Oobe.getInstance().displayType ==
- DISPLAY_TYPE.DESKTOP_USER_MANAGER;
- if (isDesktopUserManager && !Oobe.getInstance().userPodsPageVisible)
- return;
-
- var layout = this.calculateLayout_();
- var columns = this.columns = layout.columns;
- var rows = this.rows = layout.rows;
- var maxPodsNumber = columns * rows;
- var margin = isDesktopUserManager ? DESKTOP_MARGIN_BY_COLUMNS[columns] :
- MARGIN_BY_COLUMNS[columns];
- this.parentNode.setPreferredSize(
- this.columnsToWidth_(columns), this.rowsToHeight_(rows));
- var height = this.userPodHeight_;
- var width = this.userPodWidth_;
- var pinPodLocation = { column: columns + 1, row: rows + 1 };
- if (this.focusedPod_ && this.focusedPod_.isPinShown())
- pinPodLocation = this.findPodLocation_(this.focusedPod_, columns, rows);
-
- this.pods.forEach(function(pod, index) {
- if (index >= maxPodsNumber) {
- pod.hidden = true;
- return;
- }
- pod.hidden = false;
- if (pod.offsetHeight != height &&
- pod.offsetHeight != CROS_PIN_POD_HEIGHT) {
- console.error('Pod offsetHeight (' + pod.offsetHeight +
- ') and POD_HEIGHT (' + height + ') are not equal.');
- }
- if (pod.offsetWidth != width) {
- console.error('Pod offsetWidth (' + pod.offsetWidth +
- ') and POD_WIDTH (' + width + ') are not equal.');
- }
- var column = index % columns;
- var row = Math.floor(index / columns);
-
- var rowPadding = isDesktopUserManager ? DESKTOP_ROW_PADDING :
- POD_ROW_PADDING;
- pod.left = rowPadding + column * (width + margin);
-
- // On desktop, we want the rows to always be equally spaced.
- pod.top = isDesktopUserManager ? row * (height + rowPadding) :
- row * height + rowPadding;
- });
- Oobe.getInstance().updateScreenSize(this.parentNode);
- },
-
- /**
- * Number of columns.
- * @type {?number}
- */
- set columns(columns) {
- // Cannot use 'columns' here.
- this.setAttribute('ncolumns', columns);
- },
- get columns() {
- return parseInt(this.getAttribute('ncolumns'));
- },
-
- /**
- * Number of rows.
- * @type {?number}
- */
- set rows(rows) {
- // Cannot use 'rows' here.
- this.setAttribute('nrows', rows);
- },
- get rows() {
- return parseInt(this.getAttribute('nrows'));
- },
-
- /**
- * Whether the pod is currently focused.
- * @param {UserPod} pod Pod to check for focus.
- * @return {boolean} Pod focus status.
- */
- isFocused: function(pod) {
- return this.focusedPod_ == pod;
- },
-
- /**
- * Focuses a given user pod or clear focus when given null.
- * @param {UserPod=} podToFocus User pod to focus (undefined clears focus).
- * @param {boolean=} opt_force If true, forces focus update even when
- * podToFocus is already focused.
- * @param {boolean=} opt_skipInputFocus If true, don't focus on the input
- * box of user pod.
- */
- focusPod: function(podToFocus, opt_force, opt_skipInputFocus) {
- if (this.isFocused(podToFocus) && !opt_force) {
- // Calling focusPod w/o podToFocus means reset.
- if (!podToFocus)
- Oobe.clearErrors();
- return;
- }
-
- // Make sure there's only one focusPod operation happening at a time.
- if (this.insideFocusPod_) {
- return;
- }
- this.insideFocusPod_ = true;
-
- for (var i = 0, pod; pod = this.pods[i]; ++i) {
- if (!this.alwaysFocusSinglePod) {
- pod.isActionBoxMenuActive = false;
- }
- if (pod != podToFocus) {
- pod.isActionBoxMenuHovered = false;
- pod.classList.remove('focused');
- pod.setPinVisibility(false);
- this.setUserPodFingerprintIcon(
- pod.user.username, FINGERPRINT_STATES.HIDDEN);
- // On Desktop, the faded style is not set correctly, so we should
- // manually fade out non-focused pods if there is a focused pod.
- if (pod.user.isDesktopUser && podToFocus)
- pod.classList.add('faded');
- else
- pod.classList.remove('faded');
- pod.reset(false);
- }
- }
-
- // Clear any error messages for previous pod.
- if (!this.isFocused(podToFocus))
- Oobe.clearErrors();
-
- this.focusedPod_ = podToFocus;
- if (podToFocus) {
- // Only show the keyboard if it is fully loaded.
- if (podToFocus.isPinReady())
- podToFocus.setPinVisibility(true);
- podToFocus.classList.remove('faded');
- podToFocus.classList.add('focused');
- if (!podToFocus.multiProfilesPolicyApplied) {
- podToFocus.classList.toggle('signing-in', false);
- if (!opt_skipInputFocus)
- podToFocus.focusInput();
- } else {
- podToFocus.userTypeBubbleElement.classList.add('bubble-shown');
- // Note it is not necessary to skip this focus request when
- // |opt_skipInputFocus| is true. When |multiProfilesPolicyApplied|
- // is false, it doesn't focus on the password input box by default.
- podToFocus.focus();
- }
-
- chrome.send(
- 'focusPod', [podToFocus.user.username, true /* loads wallpaper */]);
- this.firstShown_ = false;
- this.lastFocusedPod_ = podToFocus;
- this.scrollFocusedPodIntoView();
- this.setUserPodFingerprintIcon(
- podToFocus.user.username, FINGERPRINT_STATES.DEFAULT);
- } else {
- chrome.send('noPodFocused');
- }
- this.insideFocusPod_ = false;
- },
-
- /**
- * Returns the currently activated pod.
- * @type {UserPod}
- */
- get activatedPod() {
- return this.activatedPod_;
- },
-
- /**
- * Sets currently activated pod.
- * @param {UserPod} pod Pod to check for focus.
- * @param {Event} e Event object.
- */
- setActivatedPod: function(pod, e) {
- if (this.disabled) {
- console.error('Cannot activate pod while sign-in UI is disabled.');
- return;
- }
- if (pod && pod.activate(e))
- this.activatedPod_ = pod;
- },
-
- /**
- * The pod that is preselected on user pod row show.
- * @type {?UserPod}
- */
- get preselectedPod() {
- var isDesktopUserManager = Oobe.getInstance().displayType ==
- DISPLAY_TYPE.DESKTOP_USER_MANAGER;
- if (isDesktopUserManager) {
- // On desktop, don't pre-select a pod if it's the only one.
- if (this.pods.length == 1)
- return null;
-
- // The desktop User Manager can send an URI encoded profile path in the
- // url hash, that indicates a pod that should be initially focused.
- var focusedProfilePath =
- decodeURIComponent(window.location.hash.substr(1));
- for (var i = 0, pod; pod = this.pods[i]; ++i) {
- if (focusedProfilePath === pod.user.profilePath)
- return pod;
- }
- return null;
- }
-
- for (i = 0; pod = this.pods[i]; ++i) {
- if (!pod.multiProfilesPolicyApplied)
- return pod;
- }
- return this.pods[0];
- },
-
- /**
- * Resets input UI.
- * @param {boolean} takeFocus True to take focus.
- */
- reset: function(takeFocus) {
- this.disabled = false;
- if (this.activatedPod_)
- this.activatedPod_.reset(takeFocus);
- },
-
- /**
- * Restores input focus to current selected pod, if there is any.
- */
- refocusCurrentPod: function() {
- if (this.focusedPod_ && !this.focusedPod_.multiProfilesPolicyApplied) {
- this.focusedPod_.focusInput();
- }
- },
-
- /**
- * Clears focused pod password field.
- */
- clearFocusedPod: function() {
- if (!this.disabled && this.focusedPod_)
- this.focusedPod_.reset(true);
- },
-
- /**
- * Shows signin UI.
- * @param {string} email Email for signin UI.
- */
- showSigninUI: function(email) {
- // Clear any error messages that might still be around.
- Oobe.clearErrors();
- this.disabled = true;
- this.lastFocusedPod_ = this.getPodWithUsername_(email);
- Oobe.showSigninUI(email);
- },
-
- /**
- * Updates current image of a user.
- * @param {string} username User for which to update the image.
- */
- updateUserImage: function(username) {
- var pod = this.getPodWithUsername_(username);
- if (pod)
- pod.updateUserImage();
- },
-
- /**
- * Handler of click event.
- * @param {Event} e Click Event object.
- * @private
- */
- handleClick_: function(e) {
- if (this.disabled)
- return;
-
- // Clear all menus if the click is outside pod menu and its
- // button area.
- if (!findAncestorByClass(e.target, 'action-box-menu') &&
- !findAncestorByClass(e.target, 'action-box-area')) {
- for (var i = 0, pod; pod = this.pods[i]; ++i)
- pod.isActionBoxMenuActive = false;
- }
-
- // Clears focus if not clicked on a pod and if there's more than one pod.
- var pod = findAncestorByClass(e.target, 'pod');
- if ((!pod || pod.parentNode != this) && !this.alwaysFocusSinglePod) {
- this.focusPod();
- }
-
- if (pod)
- pod.isActionBoxMenuHovered = true;
-
- // Return focus back to single pod.
- if (this.alwaysFocusSinglePod && !pod) {
- if ($('login-header-bar').contains(e.target))
- return;
- this.focusPod(this.focusedPod_, true /* force */);
- this.focusedPod_.userTypeBubbleElement.classList.remove('bubble-shown');
- this.focusedPod_.isActionBoxMenuHovered = false;
- }
- },
-
- /**
- * Handler of mouse move event.
- * @param {Event} e Click Event object.
- * @private
- */
- handleMouseMove_: function(e) {
- if (this.disabled)
- return;
- if (e.movementX == 0 && e.movementY == 0)
- return;
-
- // Defocus (thus hide) action box, if it is focused on a user pod
- // and the pointer is not hovering over it.
- var pod = findAncestorByClass(e.target, 'pod');
- if (document.activeElement &&
- document.activeElement.parentNode != pod &&
- document.activeElement.classList.contains('action-box-area')) {
- document.activeElement.parentNode.focus();
- }
-
- if (pod)
- pod.isActionBoxMenuHovered = true;
-
- // Hide action boxes on other user pods.
- for (var i = 0, p; p = this.pods[i]; ++i)
- if (p != pod && !p.isActionBoxMenuActive)
- p.isActionBoxMenuHovered = false;
- },
-
- /**
- * Handles focus event.
- * @param {Event} e Focus Event object.
- * @private
- */
- handleFocus_: function(e) {
- if (this.disabled)
- return;
- if (e.target.parentNode == this) {
- // Focus on a pod
- if (e.target.classList.contains('focused')) {
- if (!e.target.multiProfilesPolicyApplied)
- e.target.focusInput();
- else
- e.target.userTypeBubbleElement.classList.add('bubble-shown');
- } else
- this.focusPod(e.target);
- return;
- }
-
- var pod = findAncestorByClass(e.target, 'pod');
- if (pod && pod.parentNode == this) {
- // Focus on a control of a pod but not on the action area button.
- if (!pod.classList.contains('focused')) {
- if (e.target.classList.contains('action-box-area') ||
- e.target.classList.contains('remove-warning-button')) {
- // focusPod usually moves focus on the password input box which
- // triggers virtual keyboard to show up. But the focus may move to a
- // non text input element shortly by e.target.focus. Hence, a
- // virtual keyboard flicking might be observed. We need to manually
- // prevent focus on password input box to avoid virtual keyboard
- // flicking in this case. See crbug.com/396016 for details.
- this.focusPod(pod, false, true /* opt_skipInputFocus */);
- } else {
- this.focusPod(pod);
- }
- pod.userTypeBubbleElement.classList.remove('bubble-shown');
- e.target.focus();
- }
- return;
- }
-
- // Clears pod focus when we reach here. It means new focus is neither
- // on a pod nor on a button/input for a pod.
- // Do not "defocus" user pod when it is a single pod.
- // That means that 'focused' class will not be removed and
- // input field/button will always be visible.
- if (!this.alwaysFocusSinglePod)
- this.focusPod();
- else {
- // Hide user-type-bubble in case this is one pod and we lost focus of
- // it.
- this.focusedPod_.userTypeBubbleElement.classList.remove('bubble-shown');
- }
- },
-
- /**
- * Handler of keydown event.
- * @param {Event} e KeyDown Event object.
- */
- handleKeyDown: function(e) {
- if (this.disabled)
- return;
- var editing = e.target.tagName == 'INPUT' && e.target.value;
- switch (e.key) {
- case 'ArrowLeft':
- if (!editing) {
- if (this.focusedPod_ && this.focusedPod_.previousElementSibling)
- this.focusPod(this.focusedPod_.previousElementSibling);
- else
- this.focusPod(this.lastElementChild);
-
- e.stopPropagation();
- }
- break;
- case 'ArrowRight':
- if (!editing) {
- if (this.focusedPod_ && this.focusedPod_.nextElementSibling)
- this.focusPod(this.focusedPod_.nextElementSibling);
- else
- this.focusPod(this.firstElementChild);
-
- e.stopPropagation();
- }
- break;
- case 'Enter':
- if (this.focusedPod_) {
- var targetTag = e.target.tagName;
- if (e.target == this.focusedPod_.passwordElement ||
- (this.focusedPod_.pinKeyboard &&
- e.target == this.focusedPod_.pinKeyboard.inputElement) ||
- (targetTag != 'INPUT' &&
- targetTag != 'BUTTON' &&
- targetTag != 'A')) {
- this.setActivatedPod(this.focusedPod_, e);
- e.stopPropagation();
- }
- }
- break;
- case 'Escape':
- if (!this.alwaysFocusSinglePod)
- this.focusPod();
- break;
- }
- },
-
- /**
- * Called right after the pod row is shown.
- */
- handleAfterShow: function() {
- var focusedPod = this.focusedPod_;
-
- // Without timeout changes in pods positions will be animated even though
- // it happened when 'flying-pods' class was disabled.
- setTimeout(function() {
- Oobe.getInstance().toggleClass('flying-pods', true);
- if (focusedPod)
- ensureTransitionEndEvent(focusedPod);
- }, 0);
-
- // Force input focus for user pod on show and once transition ends.
- if (focusedPod) {
- var screen = this.parentNode;
- var self = this;
- focusedPod.addEventListener('transitionend', function f(e) {
- focusedPod.removeEventListener('transitionend', f);
- focusedPod.reset(true);
- // Notify screen that it is ready.
- screen.onShow();
- });
- }
- },
-
- /**
- * Called right before the pod row is shown.
- */
- handleBeforeShow: function() {
- Oobe.getInstance().toggleClass('flying-pods', false);
- for (var event in this.listeners_) {
- this.ownerDocument.addEventListener(
- event, this.listeners_[event][0], this.listeners_[event][1]);
- }
- $('login-header-bar').buttonsTabIndex = UserPodTabOrder.HEADER_BAR;
-
- if (this.podPlacementPostponed_) {
- this.podPlacementPostponed_ = false;
- this.placePods_();
- this.maybePreselectPod();
- }
- },
-
- /**
- * Called when the element is hidden.
- */
- handleHide: function() {
- for (var event in this.listeners_) {
- this.ownerDocument.removeEventListener(
- event, this.listeners_[event][0], this.listeners_[event][1]);
- }
- $('login-header-bar').buttonsTabIndex = 0;
- },
-
- /**
- * Called when a pod's user image finishes loading.
- */
- handlePodImageLoad: function(pod) {
- var index = this.podsWithPendingImages_.indexOf(pod);
- if (index == -1) {
- return;
- }
-
- this.podsWithPendingImages_.splice(index, 1);
- if (this.podsWithPendingImages_.length == 0) {
- this.classList.remove('images-loading');
- }
- },
-
- /**
- * Preselects pod, if needed.
- */
- maybePreselectPod: function() {
- var pod = this.preselectedPod;
- this.focusPod(pod);
-
- // Hide user-type-bubble in case all user pods are disabled and we focus
- // first pod.
- if (pod && pod.multiProfilesPolicyApplied) {
- pod.userTypeBubbleElement.classList.remove('bubble-shown');
- }
- }
- };
-
- return {
- PodRow: PodRow
- };
-});
diff --git a/chromium/ui/login/account_picker/user_pod_template.css b/chromium/ui/login/account_picker/user_pod_template.css
deleted file mode 100644
index b3ea8006ec4..00000000000
--- a/chromium/ui/login/account_picker/user_pod_template.css
+++ /dev/null
@@ -1,14 +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.
- *
- * This is the stylesheet imported into the style module in
- * user_pod_template.html.
- */
-
-.action-box-remove-user-warning .remove-warning-button {
- --active-shadow-action-rgb: var(--google-red-500-rgb);
- --bg-action: var(--google-red-700);
- --hover-bg-action: rgba(var(--google-red-700-rgb), .9);
- --hover-shadow-action-rgb: var(--google-red-500-rgb);
-}
diff --git a/chromium/ui/login/account_picker/user_pod_template.html b/chromium/ui/login/account_picker/user_pod_template.html
deleted file mode 100644
index b116941e77c..00000000000
--- a/chromium/ui/login/account_picker/user_pod_template.html
+++ /dev/null
@@ -1,229 +0,0 @@
-<dom-module id="user-pod-template-shared-styles">
- <template>
- <link rel="stylesheet" href="user_pod_template.css">
- </template>
-</dom-module>
-
-<custom-style>
- <style is="custom-style" include="user-pod-template-shared-styles"></style>
-</custom-style>
-
-<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
-
-<iron-iconset-svg name="user-pod" size="24">
- <svg>
- <defs>
- <!--
- Inlined from Polymer's iron-icons to avoid importing everything.
- See http://goo.gl/Y1OdAq for instructions on adding additional icons.
- -->
- <g id="arrow-forward"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/></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"/></g>
- </defs>
- </svg>
-</iron-iconset-svg>
-
-<div id="user-pod-template" class="pod disabled" hidden>
- <div class="user-image-pane">
- <div class="user-image-container">
- <img class="user-image" alt>
- <img class="user-image animated-image" alt>
- </div>
- <div class="signed-in-indicator">$i18n{signedIn}</div>
- <div class="indicator-container">
- <div class="indicator legacy-supervised-indicator"></div>
- <div class="indicator child-indicator"></div>
- <div class="indicator locked-indicator"></div>
- </div>
- </div>
-<if expr="chromeos">
- <div class="pin-container pin-disabled pin-tag">
- <pin-keyboard enable-password hide-input enable-placeholder
- enable-letters></pin-keyboard>
- </div>
-</if>
- <div class="main-pane">
- <div class="name-container">
- <div class="learn-more-container">
- <div class="learn-more"></div>
- </div>
- <div class="name"></div>
- </div>
- <div class="auth-container">
- <!-- Password Authentication -->
- <div class="custom-icon-container" hidden></div>
-<if expr="chromeos">
- <div class="fingerprint-icon-container" hidden
- aria-label="$i18n{fingerprintIconMessage}">
- <div class="custom-icon fingerprint-icon-image"></div>
- </div>
-</if>
- <div class="password-entry-container">
- <div class="password-container">
- <input type="password" class="password"
- placeholder="$i18n{passwordHint}">
- </div>
-<if expr="chromeos">
- <div class="capslock-hint-container">
- <img class="capslock-hint"
- src="chrome://theme/IDR_LOGIN_PASSWORD_CAPS_LOCK" alt>
- </div>
- <cr-icon-button class="submit-button" disabled
- aria-label="$i18n{submitButtonAccessibleName}"
- iron-icon="user-pod:arrow-forward" tabindex="-1"></cr-icon-button>
-</if>
- </div>
- <!-- User Click Authentication -->
- <div class="password-label"></div>
- <div class="signin-transition-container">
- <span class="signing-in-label">$i18n{signingIn}</span>
- <span class="animated-ellipsis-component0">.</span>
- <span class="animated-ellipsis-component1">.</span>
- <span class="animated-ellipsis-component2">.</span>
- </div>
- <div class="reauth-hint-container">
- <span class="reauth-warning"></span>
- <span class="reauth-name-hint"></span>
- </div>
- </div>
- </div>
- <div class="action-box-area">
- <div class="custom-appearance action-box-button"></div>
- <!-- iron-icon is imported inside user_manager.html -->
- <iron-icon icon="cr:more-vert" class="action-box-icon"></iron-icon>
- </div>
- <div class="user-image-gradient-area">
- </div>
- <div class="user-type-icon-area" hidden>
- <div class="custom-appearance user-type-icon-image"></div>
- </div>
- <div class="action-box-menu">
- <div class="action-box-menu-title">
- <span class="action-box-menu-title-name"></span>
- <span class="action-box-menu-title-email"></span>
- </div>
- <div class="action-box-menu-remove">
- <span class="action-box-menu-remove-command"/>
- </div>
- <div class="action-box-remove-user-warning" hidden>
- <div class="action-box-remove-user-warning-text"></div>
- <table class="action-box-remove-user-warning-table-nonsync
- non-sync has-stats">
- <tbody>
- <tr>
- <td>$i18n{removeUserWarningTextHistory}</td>
- <td class="action-box-remove-user-warning-history
- action-box-remove-user-warning-table-numbers">
- $i18n{removeUserWarningTextCalculating}
- </td>
- </tr>
- <tr>
- <td>$i18n{removeUserWarningTextPasswords}</td>
- <td class="action-box-remove-user-warning-passwords
- action-box-remove-user-warning-table-numbers">
- $i18n{removeUserWarningTextCalculating}
- </td>
- </tr>
- <tr>
- <td>$i18n{removeUserWarningTextBookmarks}</td>
- <td class="action-box-remove-user-warning-bookmarks
- action-box-remove-user-warning-table-numbers">
- $i18n{removeUserWarningTextCalculating}
- </td>
- </tr>
- <tr>
- <td>$i18n{removeUserWarningTextAutofill}</td>
- <td class="action-box-remove-user-warning-autofill
- action-box-remove-user-warning-table-numbers">
- $i18n{removeUserWarningTextCalculating}
- </td>
- </tr>
- </tbody>
- </table>
- <div class="action-box-remove-legacy-supervised-user-warning-text">
- $i18n{removeLegacySupervisedUserWarningText}
- </div>
- <div class="action-box-remove-non-owner-user-warning-text"></div>
- <!-- cr-button is imported inside user_manager.html -->
- <cr-button class="remove-warning-button action-button">
- $i18n{removeUserWarningButtonTitle}
- </cr-button>
- </div>
- </div>
- <div class="user-type-bubble">
- <div class="user-type-bubble-header">
- <span class="mp-policy-title">
- $i18n{multiProfilesRestrictedPolicyTitle}
- </span>
- </div>
- <div class="user-type-bubble-body">
- <span class="mp-policy-not-allowed-msg" hidden>
- $i18n{multiProfilesNotAllowedPolicyMsg}
- </span>
- <span class="mp-policy-primary-only-msg" hidden>
- $i18n{multiProfilesPrimaryOnlyPolicyMsg}
- </span>
- <span class="mp-owner-primary-only-msg" hidden>
- $i18n{multiProfilesOwnerPrimaryOnlyMsg}
- </span>
- </div>
- </div>
-</div>
-
-<!-- Extra elements that are appended to above "user-pod-template" for public
- account user pod. Note that only the children of the template div are
- appended. -->
-<div id="public-account-user-pod-extras-template" hidden>
- <div class="expanded-pane">
- <div class="expanded-pane-contents">
- <div class="side-container">
- <div class="expanded-pane-name"></div>
- <div class="expanded-pane-container">
- <div class="expanded-pane-learn-more-container">
- <div class="expanded-pane-learn-more"></div>
- </div>
- <div class="info"></div>
- <div class="monitoring-container">
- <span class="monitoring-warning">
- $i18n{publicAccountMonitoringWarning}
- </span>
- <a class="monitoring-learn-more" href="#" role="button">
- $i18n{publicAccountLearnMore}
- </a>
- </div>
- <div class="reminder">$i18n{publicAccountReminder}</div>
- <div class="language-and-input-section">
- <div class="select-with-label">
- <label class="language-select-label">
- $i18n{publicSessionSelectLanguage}
- </label>
- <div class="select-container">
- <select class="language-select"></select>
- </div>
- </div>
- <div class="select-with-label">
- <label class="keyboard-select-label">
- $i18n{publicSessionSelectKeyboard}
- </label>
- <div class="select-container">
- <select class="keyboard-select"></select>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="horizontal-line"></div>
- <div class="bottom-container">
- <cr-button class="action-button enter-button"
- aria-label="$i18n{publicAccountEnterAccessibleName}">
- $i18n{publicAccountEnter}
- </cr-button>
- <div class="language-and-input-container">
- <a class="language-and-input" href="#" role="button">
- $i18n{publicSessionLanguageAndInput}
- </a>
- </div>
- </div>
- </div>
- </div>
-</div>
diff --git a/chromium/ui/login/display_manager.js b/chromium/ui/login/display_manager.js
index 547eee52eb5..f9631c6182c 100644
--- a/chromium/ui/login/display_manager.js
+++ b/chromium/ui/login/display_manager.js
@@ -19,10 +19,8 @@
/** @const */ var SCREEN_OOBE_DEMO_SETUP = 'demo-setup';
/** @const */ var SCREEN_OOBE_DEMO_PREFERENCES = 'demo-preferences';
/** @const */ var SCREEN_OOBE_KIOSK_ENABLE = 'kiosk-enable';
-/** @const */ var SCREEN_OOBE_AUTO_ENROLLMENT_CHECK = 'auto-enrollment-check';
/** @const */ var SCREEN_PACKAGED_LICENSE = 'packaged-license';
/** @const */ var SCREEN_GAIA_SIGNIN = 'gaia-signin';
-/** @const */ var SCREEN_ACCOUNT_PICKER = 'account-picker';
/** @const */ var SCREEN_ERROR_MESSAGE = 'error-message';
/** @const */ var SCREEN_PASSWORD_CHANGED = 'gaia-password-changed';
/** @const */ var SCREEN_APP_LAUNCH_SPLASH = 'app-launch-splash';
@@ -46,25 +44,11 @@
* Must be kept in sync with webui_accelerator_mapping.cc.
*/
/** @const */ var ACCELERATOR_CANCEL = 'cancel';
-/** @const */ var ACCELERATOR_ENROLLMENT = 'enrollment';
-/** @const */ var ACCELERATOR_KIOSK_ENABLE = 'kiosk_enable';
/** @const */ var ACCELERATOR_VERSION = 'version';
/** @const */ var ACCELERATOR_RESET = 'reset';
/** @const */ var ACCELERATOR_APP_LAUNCH_BAILOUT = 'app_launch_bailout';
/** @const */ var ACCELERATOR_APP_LAUNCH_NETWORK_CONFIG =
'app_launch_network_config';
-/** @const */ var ACCELERATOR_SEND_FEEDBACK = "send_feedback";
-
-/* Possible UI states of the error screen. */
-/** @const */ var ERROR_SCREEN_UI_STATE = {
- UNKNOWN: 'ui-state-unknown',
- UPDATE: 'ui-state-update',
- SIGNIN: 'ui-state-signin',
- KIOSK_MODE: 'ui-state-kiosk-mode',
- LOCAL_STATE_ERROR: 'ui-state-local-state-error',
- AUTO_ENROLLMENT_ERROR: 'ui-state-auto-enrollment-error',
- ROLLBACK_ERROR: 'ui-state-rollback-error'
-};
/** @const */ var USER_ACTION_ROLLBACK_TOGGLED = 'rollback-toggled';
@@ -90,9 +74,7 @@ cr.define('cr.ui.login', function() {
*/
var RESET_AVAILABLE_SCREEN_GROUP = [
SCREEN_OOBE_NETWORK,
- SCREEN_OOBE_AUTO_ENROLLMENT_CHECK,
SCREEN_GAIA_SIGNIN,
- SCREEN_ACCOUNT_PICKER,
SCREEN_KIOSK_ENABLE,
SCREEN_ERROR_MESSAGE,
SCREEN_PASSWORD_CHANGED,
@@ -263,10 +245,7 @@ cr.define('cr.ui.login', function() {
* @return {boolean}
*/
get hasUserPods() {
- if (this.showingViewsLogin)
- return this.userCount_ > 0;
- return this.displayType_ == DISPLAY_TYPE.USER_ADDING &&
- $('pod-row').pods.length > 0;
+ return this.showingViewsLogin && this.userCount_ > 0;
},
/**
@@ -291,6 +270,21 @@ cr.define('cr.ui.login', function() {
'--shelf-area-height-base', height + 'px');
},
+ setOrientation: function(isHorizontal) {
+ if (isHorizontal) {
+ document.documentElement.setAttribute('orientation', 'horizontal');
+ } else {
+ document.documentElement.setAttribute('orientation', 'vertical');
+ }
+ },
+
+ setDialogSize: function(width, height) {
+ document.documentElement.style.setProperty(
+ '--oobe-oobe-dialog-height-base', height + 'px');
+ document.documentElement.style.setProperty(
+ '--oobe-oobe-dialog-width-base', width + 'px');
+ },
+
/**
* Sets the hint for calculating OOBE dialog inner padding.
* @param {OobeTypes.DialogPaddingMode} mode.
@@ -374,21 +368,6 @@ cr.define('cr.ui.login', function() {
if (this.currentScreen && this.currentScreen.cancel) {
this.currentScreen.cancel();
}
- } else if (name == ACCELERATOR_ENROLLMENT) {
- if (attributes.startEnrollmentAllowed ||
- currentStepId == SCREEN_GAIA_SIGNIN ||
- currentStepId == SCREEN_PACKAGED_LICENSE ||
- currentStepId == SCREEN_ACCOUNT_PICKER) {
- chrome.send('toggleEnrollmentScreen');
- } else {
- console.warn('No action for current step ID: ' + currentStepId);
- }
- } else if (name == ACCELERATOR_KIOSK_ENABLE) {
- if (attributes.toggleKioskAllowed ||
- currentStepId == SCREEN_GAIA_SIGNIN ||
- currentStepId == SCREEN_ACCOUNT_PICKER) {
- chrome.send('toggleKioskEnableScreen');
- }
} else if (name == ACCELERATOR_VERSION) {
if (this.allowToggleVersion_)
$('version-labels').hidden = !$('version-labels').hidden;
@@ -405,8 +384,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_SEND_FEEDBACK) {
- chrome.send('sendFeedback');
}
},
@@ -577,22 +554,10 @@ cr.define('cr.ui.login', function() {
}
var screenId = screen.id;
- if (screenId == SCREEN_ACCOUNT_PICKER && this.showingViewsLogin) {
- chrome.send('hideOobeDialog');
- return;
- }
// Make sure the screen is decorated.
this.preloadScreen(screen);
-
- // Show sign-in screen instead of account picker if pod row is empty.
- if (screenId == SCREEN_ACCOUNT_PICKER && $('pod-row').pods.length == 0 &&
- cr.isChromeOS) {
- Oobe.showSigninUI();
- return;
- }
-
var data = screen.data;
var index = this.getScreenIndex_(screenId);
if (index >= 0)
@@ -860,11 +825,15 @@ cr.define('cr.ui.login', function() {
};
};
+ // Only called from user-manager code, can be removed once desktop is
+ // migrated to profile-manager UI.
/**
* Disables signin UI.
*/
DisplayManager.disableSigninUI = function() {
- $('pod-row').disabled = true;
+ if ($('pod-row')) {
+ $('pod-row').disabled = true;
+ }
};
/**
@@ -890,7 +859,6 @@ cr.define('cr.ui.login', function() {
$(SCREEN_GAIA_SIGNIN)
.reset(currentScreenId == SCREEN_GAIA_SIGNIN, forceOnline);
}
- $('pod-row').reset(currentScreenId == SCREEN_ACCOUNT_PICKER);
};
/**
@@ -945,43 +913,6 @@ cr.define('cr.ui.login', function() {
};
/**
- * Shows a warning to the user that the detachable base (keyboard) different
- * than the one previously used by the user got attached to the device. It
- * warn the user that the attached base might be untrusted.
- *
- * @param {string} username The username of the user with which the error
- * bubble is associated. For example, in the account picker screen, it
- * identifies the user pod under which the error bubble should be shown.
- * @param {string} message Error message to show.
- * @param {string} link Text to use for help link.
- * @param {number} helpId Help topic Id associated with help link.
- */
- DisplayManager.showDetachableBaseChangedWarning = function(
- username, message, link, helpId) {
- var error = DisplayManager.createErrorElement_(message, link, helpId);
-
- var currentScreen = Oobe.getInstance().currentScreen;
- if (currentScreen &&
- typeof currentScreen.showDetachableBaseWarningBubble === 'function') {
- currentScreen.showDetachableBaseWarningBubble(username, error);
- }
- };
-
- /**
- * Hides the warning bubble shown by {@code showDetachableBaseChangedWarning}.
- *
- * @param {string} username The username of the user with wich the warning was
- * associated.
- */
- DisplayManager.hideDetachableBaseChangedWarning = function(username) {
- var currentScreen = Oobe.getInstance().currentScreen;
- if (currentScreen &&
- typeof currentScreen.hideDetachableBaseWarningBubble === 'function') {
- currentScreen.hideDetachableBaseWarningBubble(username);
- }
- };
-
- /**
* Clears error bubble.
*/
DisplayManager.clearErrors = function() {
@@ -1022,20 +953,6 @@ cr.define('cr.ui.login', function() {
$('bluetooth-name').textContent = bluetoothName;
};
- /**
- * Clears password field in user-pod.
- */
- DisplayManager.clearUserPodPassword = function() {
- $('pod-row').clearFocusedPod();
- };
-
- /**
- * Restores input focus to currently selected pod.
- */
- DisplayManager.refocusCurrentPod = function() {
- $('pod-row').refocusCurrentPod();
- };
-
// Export
return {
DisplayManager: DisplayManager,
diff --git a/chromium/ui/login/display_manager_types.js b/chromium/ui/login/display_manager_types.js
index 24dd83f5a09..d7f8085e127 100644
--- a/chromium/ui/login/display_manager_types.js
+++ b/chromium/ui/login/display_manager_types.js
@@ -10,8 +10,6 @@
/**
* @typedef {{
* resetAllowed: (boolean|undefined),
- * startEnrollmentAllowed: (boolean|undefined),
- * toggleKioskAllowed: (boolean|undefined),
* }}
*/
var DisplayManagerScreenAttributes = {};
@@ -23,18 +21,6 @@ var DisplayManagerScreenAttributes = {};
DisplayManagerScreenAttributes.resetAllowed;
/**
- * True if enrollment accelerator should start enrollment.
- * @type {boolean|undefined}
- */
-DisplayManagerScreenAttributes.startEnrollmentAllowed;
-
-/**
- * True if "enable kiosk" accelerator is allowed.
- * @type {boolean|undefined}
- */
-DisplayManagerScreenAttributes.toggleKioskAllowed;
-
-/**
* Possible types of UI.
* @enum {string}
*/
@@ -43,7 +29,6 @@ var DISPLAY_TYPE = {
OOBE: 'oobe',
LOGIN: 'login',
LOCK: 'lock',
- USER_ADDING: 'user-adding',
APP_LAUNCH_SPLASH: 'app-launch-splash',
DESKTOP_USER_MANAGER: 'login-add-user',
GAIA_SIGNIN: 'gaia-signin'
@@ -71,3 +56,18 @@ var OOBE_UI_STATE = {
MIGRATION: 12,
USER_CREATION: 15,
};
+
+/**
+ * Possible UI states of the error screen.
+ * @enum {string}
+ */
+var ERROR_SCREEN_UI_STATE = {
+ UNKNOWN: 'ui-state-unknown',
+ UPDATE: 'ui-state-update',
+ SIGNIN: 'ui-state-signin',
+ KIOSK_MODE: 'ui-state-kiosk-mode',
+ LOCAL_STATE_ERROR: 'ui-state-local-state-error',
+ AUTO_ENROLLMENT_ERROR: 'ui-state-auto-enrollment-error',
+ ROLLBACK_ERROR: 'ui-state-rollback-error',
+ SUPERVISED_USER_CREATION_FLOW: 'ui-state-supervised',
+};
diff --git a/chromium/ui/login/login_ui_tools.js b/chromium/ui/login/login_ui_tools.js
index d66d64b8c10..66ed2686bf0 100644
--- a/chromium/ui/login/login_ui_tools.js
+++ b/chromium/ui/login/login_ui_tools.js
@@ -10,18 +10,19 @@ cr.define('cr.ui.LoginUITools', function() {
return {
/**
* Computes max-height for an element so that it doesn't overlap shelf.
- * @param {element} DOM element
- * @param {wholeWindow} Whether the element can go outside outer-container.
+ * @param {Element} element DOM element
+ * @param {boolean} wholeWindow Whether the element can go outside
+ * outer-container.
*/
getMaxHeightBeforeShelfOverlapping : function(element, wholeWindow) {
var maxAllowedHeight =
$('outer-container').offsetHeight -
element.getBoundingClientRect().top -
- parseInt(window.getComputedStyle(element).marginTop) -
- parseInt(window.getComputedStyle(element).marginBottom);
+ parseInt(window.getComputedStyle(element).marginTop, 10) -
+ parseInt(window.getComputedStyle(element).marginBottom, 10);
if (wholeWindow) {
maxAllowedHeight +=
- parseInt(window.getComputedStyle($('outer-container')).bottom);
+ parseInt(window.getComputedStyle($('outer-container')).bottom, 10);
}
return maxAllowedHeight;
},
@@ -29,15 +30,29 @@ cr.define('cr.ui.LoginUITools', function() {
/**
* Computes max-width for an element so that it does fit the
* outer-container.
- * @param {element} DOM element
+ * @param {Element} element DOM element
*/
getMaxWidthToFit : function(element) {
var maxAllowedWidth =
$('outer-container').offsetWidth -
element.getBoundingClientRect().left -
- parseInt(window.getComputedStyle(element).marginLeft) -
- parseInt(window.getComputedStyle(element).marginRight);
+ parseInt(window.getComputedStyle(element).marginLeft, 10) -
+ parseInt(window.getComputedStyle(element).marginRight, 10);
return maxAllowedWidth;
},
+
+ /**
+ * Listens to key events on input element.
+ * @param {Element} element DOM element
+ * @param {Object} callback
+ */
+ addSubmitListener : function(element, callback) {
+ element.addEventListener('keydown', (function(callback, e) {
+ if (e.keyCode != 13)
+ return;
+ callback();
+ }).bind(undefined, callback));
+ },
}
+
});
diff --git a/chromium/ui/login/oobe.css b/chromium/ui/login/oobe.css
index 1bbcb525e90..c8ef82e699d 100644
--- a/chromium/ui/login/oobe.css
+++ b/chromium/ui/login/oobe.css
@@ -9,6 +9,8 @@
:root {
--google-grey-700: rgb(95, 99, 104);
--shelf-area-height-base: 57px;
+ --oobe-oobe-dialog-height-base: 504px;
+ --oobe-oobe-dialog-width-base: 461px;
}
html,
@@ -44,12 +46,19 @@ html[screen=oobe] body {
background-color: white;
}
+/* New dialog size */
+html {
+ --oobe-adaptive-dialog-width: var(--oobe-oobe-dialog-width-base);
+ --oobe-adaptive-dialog-height: var(--oobe-oobe-dialog-height-base);
+}
+
/* Padding defaults */
html {
--oobe-dialog-footer-height: 96px;
--oobe-dialog-footer-padding: 32px;
--oobe-dialog-content-padding: 64px;
--oobe-dialog-content-padding-top: 20px;
+ --oobe-dialog-header-padding-top: 64px;
/* This size fits 675px screen with docked magnifier and shelf. Basically this
* is calc(675px * (1 - 1 / 3) - 10px - var(--shelf-area-height-base)) where
@@ -81,6 +90,7 @@ html[screen=gaia-signin] {
--oobe-dialog-footer-height: 80px;
--oobe-dialog-footer-padding: 24px;
--oobe-dialog-content-padding: 32px;
+ --oobe-dialog-header-padding-top: 32px;
}
}
@@ -103,6 +113,7 @@ html[screen=gaia-signin][dialog-padding=narrow] {
--oobe-dialog-footer-height: 80px;
--oobe-dialog-footer-padding: 24px;
--oobe-dialog-content-padding: 32px;
+ --oobe-dialog-header-padding-top: 32px;
}
body.solid {
@@ -114,89 +125,6 @@ button {
outline: none;
}
-/* Follow same focus coloring as in widgets.css */
-/* Do not apply this style to restricted button state. */
-button.custom-appearance:not(.button-restricted):not(.button-fancy):not(
- [is="gaia-icon-button"]) {
- border: 2px solid transparent;
- /* Don't grey out disabled buttons. */
- color: buttontext !important;
- transition: border-color 200ms;
-}
-
-/* ':focus' used three times to increase specificity. */
-button.custom-appearance:focus:focus:focus {
- border-color: rgba(66, 133, 244, 0.6); /* #4285f4 */
-}
-
-button:not(.custom-appearance) {
- min-width: 72px !important;
-}
-
-button.button-fancy {
- min-width: 72px !important;
-}
-
-button.button-blue {
- background-image: linear-gradient(rgb(93, 154, 255),
- rgb(93, 154, 255) 38%,
- rgb(88, 145, 240));
- border: 1px solid rgba(45, 102, 195, 1);
- border-radius: 2px;
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.15), inset 0 1px 2px
- rgba(255, 255, 255, 0.4);
- color: #fff;
- font-size: 14px;
- margin: 0 1px 0 0;
- min-height: 2em;
- min-width: 4em;
- text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
-}
-
-
-button.button-blue:hover {
- background-image: linear-gradient(rgb(101, 158, 253),
- rgb(101, 158, 253) 38%,
- rgb(96, 151, 241));
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25), inset 0 1px 2px
- rgba(255, 255, 255, 0.4);
-}
-
-button.button-blue:active {
- background-image: linear-gradient(rgb(96, 149, 237),
- rgb(96, 149, 237) 38%,
- rgb(96, 149, 237));
- border: 1px solid rgba(38, 84, 160, 1);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
-}
-
-button.button-red {
- background-image: linear-gradient(rgb(221, 75, 57),
- rgb(221, 75, 57) 38%,
- rgb(197, 66, 49));
- border: 1px solid rgba(167, 57, 44, 1);
- border-radius: 2px;
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.15), inset 0 1px 2px
- rgba(255, 255, 255, 0.4);
- color: #fff;
- margin: 0 1px 0 0;
- min-height: 2em;
- min-width: 4em;
- text-shadow: 0 1px 0 rgba(0, 0, 0, 0.15);
-}
-
-button.button-red:hover {
- background-image: linear-gradient(rgb(231, 78, 59),
- rgb(231, 78, 59) 38%,
- rgb(209, 70, 52));
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25), inset 0 1px 2px
- rgba(255, 255, 255, 0.4);
-}
-
-button.button-red:active {
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-}
-
.label,
.flexible-label {
display: block;
@@ -234,10 +162,6 @@ span.bold {
z-index: 1;
}
-html[screen=user-adding] #version-labels {
- color: white;
-}
-
#bluetooth-name {
background: rgba(255,255,255,.17);
border-radius: 4px;
diff --git a/chromium/ui/message_center/BUILD.gn b/chromium/ui/message_center/BUILD.gn
index dcc2ee5c555..e04e7642da3 100644
--- a/chromium/ui/message_center/BUILD.gn
+++ b/chromium/ui/message_center/BUILD.gn
@@ -26,6 +26,7 @@ aggregate_vector_icons("message_center_vector_icons") {
component("message_center") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//ui/base",
"//ui/strings",
"//url",
@@ -172,6 +173,7 @@ if (enable_message_center) {
":test_support",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//mojo/core/embedder",
"//skia",
"//testing/gmock",
diff --git a/chromium/ui/message_center/DIR_METADATA b/chromium/ui/message_center/DIR_METADATA
new file mode 100644
index 00000000000..b3b636b3d10
--- /dev/null
+++ b/chromium/ui/message_center/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+ component: "UI>Notifications"
+}
+team_email: "platform-capabilities@chromium.org"
diff --git a/chromium/ui/message_center/OWNERS b/chromium/ui/message_center/OWNERS
index 8138435d5a9..80f2be4de4d 100644
--- a/chromium/ui/message_center/OWNERS
+++ b/chromium/ui/message_center/OWNERS
@@ -3,6 +3,3 @@ estade@chromium.org
peter@chromium.org
yoshiki@chromium.org
tengs@chromium.org
-
-# COMPONENT: UI>Notifications
-# TEAM: platform-capabilities@chromium.org
diff --git a/chromium/ui/message_center/fake_message_center.cc b/chromium/ui/message_center/fake_message_center.cc
index 8a902c739be..40cc51e944c 100644
--- a/chromium/ui/message_center/fake_message_center.cc
+++ b/chromium/ui/message_center/fake_message_center.cc
@@ -29,7 +29,7 @@ void FakeMessageCenter::RemoveNotificationBlocker(
NotificationBlocker* blocker) {}
size_t FakeMessageCenter::NotificationCount() const {
- return 0u;
+ return notifications_.GetNotifications().size();
}
bool FakeMessageCenter::HasPopupNotifications() const {
@@ -110,7 +110,14 @@ void FakeMessageCenter::RemoveNotification(const std::string& id,
void FakeMessageCenter::RemoveNotificationsForNotifierId(
const NotifierId& notifier_id) {}
-void FakeMessageCenter::RemoveAllNotifications(bool by_user, RemoveType type) {}
+void FakeMessageCenter::RemoveAllNotifications(bool by_user, RemoveType type) {
+ // Only removing all is supported.
+ DCHECK_EQ(type, RemoveType::ALL);
+ for (const auto* notification : notifications_.GetNotifications()) {
+ // This is safe to remove since GetNotifications() returned a copy.
+ RemoveNotification(notification->id(), by_user);
+ }
+}
void FakeMessageCenter::SetNotificationIcon(const std::string& notification_id,
const gfx::Image& image) {}
diff --git a/chromium/ui/message_center/message_center_impl.cc b/chromium/ui/message_center/message_center_impl.cc
index fa2dc56bdea..bbf6aa269dc 100644
--- a/chromium/ui/message_center/message_center_impl.cc
+++ b/chromium/ui/message_center/message_center_impl.cc
@@ -12,9 +12,9 @@
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/macros.h"
#include "base/observer_list.h"
-#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "ui/message_center/lock_screen/lock_screen_controller.h"
diff --git a/chromium/ui/message_center/message_center_impl_unittest.cc b/chromium/ui/message_center/message_center_impl_unittest.cc
index 16523bb345b..39a383a432a 100644
--- a/chromium/ui/message_center/message_center_impl_unittest.cc
+++ b/chromium/ui/message_center/message_center_impl_unittest.cc
@@ -20,6 +20,7 @@
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/size.h"
@@ -483,7 +484,7 @@ TEST_F(MessageCenterImplTest, PopupTimersControllerRestartOnUpdate) {
popup_timers_controller->OnNotificationDisplayed("id1", DISPLAY_SOURCE_POPUP);
ASSERT_EQ(popup_timers_controller->timer_finished(), 0);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
const int dismiss_time =
popup_timers_controller->GetNotificationTimeoutDefault();
#else
@@ -842,7 +843,7 @@ TEST_F(MessageCenterImplTest, RemoveAllNotifications) {
EXPECT_TRUE(NotificationsContain(notifications, "id2"));
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(MessageCenterImplTest, RemoveAllNotificationsWithPinned) {
NotifierId notifier_id1(NotifierType::APPLICATION, "app1");
NotifierId notifier_id2(NotifierType::APPLICATION, "app2");
diff --git a/chromium/ui/message_center/notification_list.cc b/chromium/ui/message_center/notification_list.cc
index 1796054b93e..1f357c6706d 100644
--- a/chromium/ui/message_center/notification_list.cc
+++ b/chromium/ui/message_center/notification_list.cc
@@ -10,6 +10,7 @@
#include "base/check.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/image/image.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/notification_blocker.h"
@@ -341,7 +342,7 @@ void NotificationList::PushNotification(
// For critical ChromeOS system notifications, we ignore the standard quiet
// mode behaviour and show the notification anyways.
bool effective_quiet_mode = quiet_mode_;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
effective_quiet_mode &= notification->system_notification_warning_level() !=
SystemNotificationWarningLevel::CRITICAL_WARNING;
#endif
diff --git a/chromium/ui/message_center/popup_timers_controller.cc b/chromium/ui/message_center/popup_timers_controller.cc
index 213de8e2692..138edc861fc 100644
--- a/chromium/ui/message_center/popup_timers_controller.cc
+++ b/chromium/ui/message_center/popup_timers_controller.cc
@@ -6,7 +6,8 @@
#include <algorithm>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
+#include "build/chromeos_buildflags.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
namespace message_center {
@@ -16,7 +17,7 @@ namespace {
bool UseHighPriorityDelay(Notification* notification) {
// Web Notifications are given a longer on-screen time on non-Chrome OS
// platforms as there is no notification center to dismiss them to.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
const bool use_high_priority_delay =
notification->priority() > DEFAULT_PRIORITY;
#else
diff --git a/chromium/ui/message_center/public/cpp/BUILD.gn b/chromium/ui/message_center/public/cpp/BUILD.gn
index 59337d831c0..54fd58f025e 100644
--- a/chromium/ui/message_center/public/cpp/BUILD.gn
+++ b/chromium/ui/message_center/public/cpp/BUILD.gn
@@ -22,6 +22,7 @@ component("cpp") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//skia",
"//ui/gfx",
"//ui/strings",
diff --git a/chromium/ui/message_center/public/cpp/notification.cc b/chromium/ui/message_center/public/cpp/notification.cc
index a32ee610534..2e390fc184a 100644
--- a/chromium/ui/message_center/public/cpp/notification.cc
+++ b/chromium/ui/message_center/public/cpp/notification.cc
@@ -7,6 +7,7 @@
#include <map>
#include <memory>
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/paint_vector_icon.h"
@@ -146,12 +147,12 @@ gfx::Image Notification::GenerateMaskedSmallIcon(int dip_size,
// masking and resizing.
gfx::ImageSkia image = small_image().AsImageSkia();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
bool create_masked_image =
!optional_fields_.ignore_accent_color_for_small_image;
#else
bool create_masked_image = false;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
if (create_masked_image) {
image = gfx::ImageSkiaOperations::CreateMaskedImage(
diff --git a/chromium/ui/message_center/public/cpp/notification.h b/chromium/ui/message_center/public/cpp/notification.h
index 94d0c2a9ec4..6ef34b695cc 100644
--- a/chromium/ui/message_center/public/cpp/notification.h
+++ b/chromium/ui/message_center/public/cpp/notification.h
@@ -15,6 +15,7 @@
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/image/image.h"
@@ -106,11 +107,11 @@ class MESSAGE_CENTER_PUBLIC_EXPORT RichNotificationData {
// notification. Optional.
gfx::Image small_image;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// If true, we simply use the raw |small_image| icon, ignoring accent color
// styling. For example, this is used with raw icons received from Android.
bool ignore_accent_color_for_small_image = false;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Vector version of |small_image|.
// Used by Notification::GenerateMaskedSmallIcon.
@@ -148,11 +149,11 @@ class MESSAGE_CENTER_PUBLIC_EXPORT RichNotificationData {
// depending on visual assistance systems.
bool should_make_spoken_feedback_for_popup_updates = true;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Flag if the notification is pinned. If true, the notification is pinned
// and the user can't remove it.
bool pinned = false;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Vibration pattern to play when displaying the notification. There must be
// an odd number of entries in this pattern when it's set: numbers of
@@ -384,15 +385,15 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
}
bool pinned() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return optional_fields_.pinned;
#else
return false;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void set_pinned(bool pinned) { optional_fields_.pinned = pinned; }
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Gets a text for spoken feedback.
const base::string16& accessible_name() const {
@@ -441,7 +442,7 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
// method explicitly, to avoid setting it accidentally.
void SetSystemPriority();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void set_system_notification_warning_level(
SystemNotificationWarningLevel warning_level) {
system_notification_warning_level_ = warning_level;
@@ -450,7 +451,7 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
SystemNotificationWarningLevel system_notification_warning_level() const {
return system_notification_warning_level_;
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
const std::string& custom_view_type() const { return custom_view_type_; }
void set_custom_view_type(const std::string& custom_view_type) {
@@ -495,11 +496,11 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
// used to register the factory in MessageViewFactory.
std::string custom_view_type_;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// The warning level of a system notification.
SystemNotificationWarningLevel system_notification_warning_level_ =
SystemNotificationWarningLevel::NORMAL;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
};
} // namespace message_center
diff --git a/chromium/ui/message_center/views/message_popup_collection.cc b/chromium/ui/message_center/views/message_popup_collection.cc
index 87c96aa4acb..72a3c00412c 100644
--- a/chromium/ui/message_center/views/message_popup_collection.cc
+++ b/chromium/ui/message_center/views/message_popup_collection.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/timer/timer.h"
#include "ui/gfx/animation/linear_animation.h"
#include "ui/gfx/animation/tween.h"
#include "ui/message_center/message_center.h"
@@ -25,6 +26,9 @@ constexpr base::TimeDelta kFadeInFadeOutDuration =
constexpr base::TimeDelta kMoveDownDuration =
base::TimeDelta::FromMilliseconds(120);
+// Time to wait until we reset |recently_closed_by_user_|.
+constexpr base::TimeDelta kWaitForReset = base::TimeDelta::FromSeconds(10);
+
} // namespace
MessagePopupCollection::MessagePopupCollection()
@@ -132,9 +136,22 @@ void MessagePopupCollection::OnNotificationAdded(
void MessagePopupCollection::OnNotificationRemoved(
const std::string& notification_id,
bool by_user) {
+ if (by_user) {
+ recently_closed_by_user_ = true;
+ recently_closed_by_user_timer_ = std::make_unique<base::OneShotTimer>();
+ recently_closed_by_user_timer_->Start(
+ FROM_HERE, kWaitForReset,
+ base::BindOnce(&MessagePopupCollection::ResetRecentlyClosedByUser,
+ base::Unretained(this)));
+ }
Update();
}
+void MessagePopupCollection::ResetRecentlyClosedByUser() {
+ recently_closed_by_user_ = false;
+ recently_closed_by_user_timer_.reset();
+}
+
void MessagePopupCollection::OnNotificationUpdated(
const std::string& notification_id) {
if (is_updating_)
@@ -272,7 +289,9 @@ void MessagePopupCollection::TransitionToAnimation() {
MarkRemovedPopup();
// Start hot mode to allow a user to continually close many notifications.
- StartHotMode();
+ // Only start hot mode if there's a notification recently closed by user.
+ if (recently_closed_by_user_)
+ StartHotMode();
if (CloseTransparentPopups()) {
// If the popup is already transparent, skip FADE_OUT.
diff --git a/chromium/ui/message_center/views/message_popup_collection.h b/chromium/ui/message_center/views/message_popup_collection.h
index c64fa55ffcf..f144caa3c21 100644
--- a/chromium/ui/message_center/views/message_popup_collection.h
+++ b/chromium/ui/message_center/views/message_popup_collection.h
@@ -15,6 +15,10 @@
#include "ui/message_center/message_center_observer.h"
#include "ui/views/widget/widget.h"
+namespace base {
+class OneShotTimer;
+} // namespace base
+
namespace gfx {
class LinearAnimation;
} // namespace gfx
@@ -255,6 +259,10 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
// When |inverse_| is false, it's same as popup_items_[i].
PopupItem* GetPopupItem(size_t index_from_top);
+ // Reset |recently_closed_by_user_| to false. Used by
+ // |recently_closed_by_user_timer_|
+ void ResetRecentlyClosedByUser();
+
// Animation state. See the comment of State.
State state_ = State::IDLE;
@@ -279,6 +287,14 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
// Hot mode related variables. See StartHotMode() and ResetHotMode().
+ // True if a notification is just closed by an user and hot mode should start.
+ // After a brief moment, this boolean will be set to false by the timer.
+ bool recently_closed_by_user_ = false;
+
+ // Timer that fires to reset |recently_closed_by_user_| to false, indicating
+ // that we should not start hot mode.
+ std::unique_ptr<base::OneShotTimer> recently_closed_by_user_timer_;
+
// True if the close button of the popup at |hot_index_| is hot.
bool is_hot_ = false;
diff --git a/chromium/ui/message_center/views/message_popup_collection_unittest.cc b/chromium/ui/message_center/views/message_popup_collection_unittest.cc
index 91ccc31ebab..98cd33d5b22 100644
--- a/chromium/ui/message_center/views/message_popup_collection_unittest.cc
+++ b/chromium/ui/message_center/views/message_popup_collection_unittest.cc
@@ -437,14 +437,7 @@ TEST_F(MessagePopupCollectionTest, UpdateContents) {
EXPECT_TRUE(GetPopup(id)->updated());
}
-// Failiing on MacOS 10.10. https://crbug.com/1047503
-#if defined(OS_APPLE)
-#define MAYBE_UpdateContentsCausesPopupClose \
- DISABLED_UpdateContentsCausesPopupClose
-#else
-#define MAYBE_UpdateContentsCausesPopupClose UpdateContentsCausesPopupClose
-#endif
-TEST_F(MessagePopupCollectionTest, MAYBE_UpdateContentsCausesPopupClose) {
+TEST_F(MessagePopupCollectionTest, UpdateContentsCausesPopupClose) {
std::string id = AddNotification();
AnimateToEnd();
RunPendingMessages();
diff --git a/chromium/ui/message_center/views/message_popup_view.cc b/chromium/ui/message_center/views/message_popup_view.cc
index 19b670cfe2b..1eb67eadb6c 100644
--- a/chromium/ui/message_center/views/message_popup_view.cc
+++ b/chromium/ui/message_center/views/message_popup_view.cc
@@ -5,6 +5,7 @@
#include "ui/message_center/views/message_popup_view.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/display/display.h"
@@ -14,13 +15,14 @@
#include "ui/message_center/views/message_view.h"
#include "ui/message_center/views/message_view_factory.h"
#include "ui/views/layout/fill_layout.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/widget/widget.h"
#if defined(OS_WIN)
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/aura/window.h"
#include "ui/aura/window_targeter.h"
#endif
@@ -110,7 +112,9 @@ void MessagePopupView::AutoCollapse() {
void MessagePopupView::Show() {
views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
params.z_order = ui::ZOrderLevel::kFloatingWindow;
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Make the widget explicitly activatable as TYPE_POPUP is not activatable by
// default but we need focus for the inline reply textarea.
params.activatable = views::Widget::InitParams::ACTIVATABLE_YES;
@@ -122,7 +126,7 @@ void MessagePopupView::Show() {
views::Widget* widget = new views::Widget();
popup_collection_->ConfigureWidgetInitParamsForContainer(widget, &params);
widget->set_focus_on_creation(false);
- observer_.Add(widget);
+ observation_.Observe(widget);
#if defined(OS_WIN)
// We want to ensure that this toast always goes to the native desktop,
@@ -134,7 +138,7 @@ void MessagePopupView::Show() {
widget->Init(std::move(params));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// On Chrome OS, this widget is shown in the shelf container. It means this
// widget would inherit the parent's window targeter (ShelfWindowTarget) by
// default. But it is not good for popup. So we override it with the normal
@@ -179,10 +183,6 @@ void MessagePopupView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kAlertDialog;
}
-const char* MessagePopupView::GetClassName() const {
- return "MessagePopupView";
-}
-
void MessagePopupView::OnDisplayChanged() {
OnWorkAreaChanged();
}
@@ -214,11 +214,15 @@ void MessagePopupView::OnWidgetActivationChanged(views::Widget* widget,
}
void MessagePopupView::OnWidgetDestroyed(views::Widget* widget) {
- observer_.Remove(widget);
+ DCHECK(observation_.IsObservingSource(widget));
+ observation_.Reset();
}
bool MessagePopupView::IsWidgetValid() const {
return GetWidget() && !GetWidget()->IsClosed();
}
+BEGIN_METADATA(MessagePopupView, views::WidgetDelegateView)
+END_METADATA
+
} // namespace message_center
diff --git a/chromium/ui/message_center/views/message_popup_view.h b/chromium/ui/message_center/views/message_popup_view.h
index 9b5476c5dbf..21a820423e4 100644
--- a/chromium/ui/message_center/views/message_popup_view.h
+++ b/chromium/ui/message_center/views/message_popup_view.h
@@ -5,7 +5,7 @@
#ifndef UI_MESSAGE_CENTER_VIEWS_MESSAGE_POPUP_VIEW_H_
#define UI_MESSAGE_CENTER_VIEWS_MESSAGE_POPUP_VIEW_H_
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/message_center/message_center_export.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -21,8 +21,12 @@ class Notification;
class MESSAGE_CENTER_EXPORT MessagePopupView : public views::WidgetDelegateView,
public views::WidgetObserver {
public:
+ METADATA_HEADER(MessagePopupView);
+
MessagePopupView(const Notification& notification,
MessagePopupCollection* popup_collection);
+ MessagePopupView(const MessagePopupView&) = delete;
+ MessagePopupView& operator=(const MessagePopupView&) = delete;
~MessagePopupView() override;
// Update notification contents to |notification|. Virtual for unit testing.
@@ -54,7 +58,6 @@ class MESSAGE_CENTER_EXPORT MessagePopupView : public views::WidgetDelegateView,
void OnMouseExited(const ui::MouseEvent& event) override;
void ChildPreferredSizeChanged(views::View* child) override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
- const char* GetClassName() const override;
void OnDisplayChanged() override;
void OnWorkAreaChanged() override;
void OnFocus() override;
@@ -70,7 +73,7 @@ class MESSAGE_CENTER_EXPORT MessagePopupView : public views::WidgetDelegateView,
protected:
// For unit testing.
- MessagePopupView(MessagePopupCollection* popup_collection);
+ explicit MessagePopupView(MessagePopupCollection* popup_collection);
private:
// True if the view has a widget and the widget is not closed.
@@ -86,9 +89,8 @@ class MESSAGE_CENTER_EXPORT MessagePopupView : public views::WidgetDelegateView,
bool is_hovered_ = false;
bool is_active_ = false;
- ScopedObserver<views::Widget, views::WidgetObserver> observer_{this};
-
- DISALLOW_COPY_AND_ASSIGN(MessagePopupView);
+ base::ScopedObservation<views::Widget, views::WidgetObserver> observation_{
+ this};
};
} // namespace message_center
diff --git a/chromium/ui/message_center/views/message_view.cc b/chromium/ui/message_center/views/message_view.cc
index 4de15aad4e8..5e3b914c55e 100644
--- a/chromium/ui/message_center/views/message_view.cc
+++ b/chromium/ui/message_center/views/message_view.cc
@@ -6,6 +6,7 @@
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
@@ -131,7 +132,11 @@ void MessageView::SetIsNested() {
slide_out_controller_.set_slide_mode(CalculateSlideMode());
slide_out_controller_.set_update_opacity(false);
- SetNestedBorderIfNecessary();
+ SkColor border_color = GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_UnfocusedBorderColor);
+ SetBorder(views::CreateRoundedRectBorder(
+ kNotificationBorderThickness, kNotificationCornerRadius, border_color));
+
if (GetControlButtonsView())
GetControlButtonsView()->ShowCloseButton(GetMode() != Mode::PINNED);
}
@@ -326,7 +331,6 @@ void MessageView::AddedToWidget() {
void MessageView::OnThemeChanged() {
InkDropHostView::OnThemeChanged();
UpdateBackgroundPainter();
- SetNestedBorderIfNecessary();
}
ui::Layer* MessageView::GetSlideOutLayer() {
@@ -454,7 +458,7 @@ void MessageView::OnSnoozeButtonPressed(const ui::Event& event) {
}
bool MessageView::ShouldShowControlButtons() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// 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.
@@ -468,15 +472,6 @@ bool MessageView::ShouldShowControlButtons() const {
#endif
}
-void MessageView::SetNestedBorderIfNecessary() {
- if (is_nested_) {
- SkColor border_color = GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_UnfocusedBorderColor);
- SetBorder(views::CreateRoundedRectBorder(
- kNotificationBorderThickness, kNotificationCornerRadius, border_color));
- }
-}
-
void MessageView::UpdateBackgroundPainter() {
SkColor background_color = GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_NotificationDefaultBackground);
diff --git a/chromium/ui/message_center/views/message_view.h b/chromium/ui/message_center/views/message_view.h
index d7ea50425cc..f8c2e3bc1b0 100644
--- a/chromium/ui/message_center/views/message_view.h
+++ b/chromium/ui/message_center/views/message_view.h
@@ -205,9 +205,6 @@ class MESSAGE_CENTER_EXPORT MessageView
// Returns if the control buttons should be shown.
bool ShouldShowControlButtons() const;
- // Sets the border if |is_nested_| is true.
- void SetNestedBorderIfNecessary();
-
// Updates the background painter using the themed background color and radii.
void UpdateBackgroundPainter();
diff --git a/chromium/ui/message_center/views/message_view_factory.cc b/chromium/ui/message_center/views/message_view_factory.cc
index e3915498a9f..c073771e2da 100644
--- a/chromium/ui/message_center/views/message_view_factory.cc
+++ b/chromium/ui/message_center/views/message_view_factory.cc
@@ -79,7 +79,7 @@ bool MessageViewFactory::HasCustomNotificationViewFactory(
}
// static
-void MessageViewFactory::ClearCustomNotificationViewFactoryForTest(
+void MessageViewFactory::ClearCustomNotificationViewFactory(
const std::string& custom_view_type) {
g_custom_view_factories.Get().erase(custom_view_type);
}
diff --git a/chromium/ui/message_center/views/message_view_factory.h b/chromium/ui/message_center/views/message_view_factory.h
index 301dc6fadc9..8081691ee98 100644
--- a/chromium/ui/message_center/views/message_view_factory.h
+++ b/chromium/ui/message_center/views/message_view_factory.h
@@ -41,7 +41,7 @@ class MESSAGE_CENTER_EXPORT MessageViewFactory {
const CustomMessageViewFactoryFunction& factory_function);
static bool HasCustomNotificationViewFactory(
const std::string& custom_view_type);
- static void ClearCustomNotificationViewFactoryForTest(
+ static void ClearCustomNotificationViewFactory(
const std::string& custom_view_type);
};
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 f58d075a55d..2844eada9b6 100644
--- a/chromium/ui/message_center/views/notification_control_buttons_view.cc
+++ b/chromium/ui/message_center/views/notification_control_buttons_view.cc
@@ -6,6 +6,7 @@
#include <memory>
+#include "build/chromeos_buildflags.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/layer.h"
#include "ui/events/event.h"
@@ -19,12 +20,10 @@
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/background.h"
#include "ui/views/layout/box_layout.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
namespace message_center {
-const char NotificationControlButtonsView::kViewClassName[] =
- "NotificationControlButtonsView";
-
NotificationControlButtonsView::NotificationControlButtonsView(
MessageView* message_view)
: message_view_(message_view), icon_color_(gfx::kChromeIconGrey) {
@@ -145,11 +144,7 @@ void NotificationControlButtonsView::SetBackgroundColor(SkColor color) {
UpdateButtonIconColors();
}
-const char* NotificationControlButtonsView::GetClassName() const {
- return kViewClassName;
-}
-
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void NotificationControlButtonsView::OnThemeChanged() {
View::OnThemeChanged();
SetBackground(views::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
@@ -183,4 +178,7 @@ SkColor NotificationControlButtonsView::DetermineButtonIconColor() const {
return color_utils::BlendForMinContrast(icon_color_, background_color_).color;
}
+BEGIN_METADATA(NotificationControlButtonsView, views::View)
+END_METADATA
+
} // namespace message_center
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 035b632058d..162f720497b 100644
--- a/chromium/ui/message_center/views/notification_control_buttons_view.h
+++ b/chromium/ui/message_center/views/notification_control_buttons_view.h
@@ -7,6 +7,7 @@
#define UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_CONTROL_BUTTONS_VIEW_H_
#include "base/macros.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/message_center/message_center_export.h"
#include "ui/message_center/views/padded_button.h"
@@ -19,10 +20,13 @@ class MessageView;
class MESSAGE_CENTER_EXPORT NotificationControlButtonsView
: public views::View {
public:
- // String to be returned by GetClassName() method.
- static const char kViewClassName[];
+ METADATA_HEADER(NotificationControlButtonsView);
explicit NotificationControlButtonsView(MessageView* message_view);
+ NotificationControlButtonsView(const NotificationControlButtonsView&) =
+ delete;
+ NotificationControlButtonsView& operator=(
+ const NotificationControlButtonsView&) = delete;
~NotificationControlButtonsView() override;
// Change the visibility of the close button. True to show, false to hide.
@@ -50,9 +54,7 @@ class MESSAGE_CENTER_EXPORT NotificationControlButtonsView
PaddedButton* settings_button() { return settings_button_; }
PaddedButton* snooze_button() { return snooze_button_; }
- // views::View
- const char* GetClassName() const override;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void OnThemeChanged() override;
#endif
@@ -74,8 +76,6 @@ class MESSAGE_CENTER_EXPORT NotificationControlButtonsView
SkColor icon_color_;
// The background color for readability of the icons.
SkColor background_color_ = SK_ColorTRANSPARENT;
-
- DISALLOW_COPY_AND_ASSIGN(NotificationControlButtonsView);
};
} // namespace message_center
diff --git a/chromium/ui/message_center/views/notification_header_view.cc b/chromium/ui/message_center/views/notification_header_view.cc
index 12a88815cf6..9d30a8ac410 100644
--- a/chromium/ui/message_center/views/notification_header_view.cc
+++ b/chromium/ui/message_center/views/notification_header_view.cc
@@ -27,6 +27,8 @@
#include "ui/views/controls/label.h"
#include "ui/views/layout/flex_layout.h"
#include "ui/views/layout/flex_layout_types.h"
+#include "ui/views/metadata/metadata_header_macros.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/painter.h"
#include "ui/views/view_class_properties.h"
@@ -75,6 +77,7 @@ constexpr int kControlButtonSpacing = 16;
// takes tab focus for accessibility purpose.
class ExpandButton : public views::ImageView {
public:
+ METADATA_HEADER(ExpandButton);
ExpandButton();
~ExpandButton() override;
@@ -125,6 +128,9 @@ void ExpandButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->SetName(GetTooltipText(gfx::Point()));
}
+BEGIN_METADATA(ExpandButton, views::ImageView)
+END_METADATA
+
gfx::FontList GetHeaderTextFontList() {
gfx::Font default_font;
int font_size_delta = kHeaderTextFontSize - default_font.GetFontSize();
@@ -424,4 +430,7 @@ void NotificationHeaderView::UpdateColors() {
}
}
+BEGIN_METADATA(NotificationHeaderView, views::Button)
+END_METADATA
+
} // namespace message_center
diff --git a/chromium/ui/message_center/views/notification_header_view.h b/chromium/ui/message_center/views/notification_header_view.h
index eb2bf9dc257..6b59bc884ad 100644
--- a/chromium/ui/message_center/views/notification_header_view.h
+++ b/chromium/ui/message_center/views/notification_header_view.h
@@ -5,13 +5,13 @@
#ifndef UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_HEADER_VIEW_H_
#define UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_HEADER_VIEW_H_
-#include "base/macros.h"
#include "base/optional.h"
#include "base/timer/timer.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"
+#include "ui/views/metadata/metadata_header_macros.h"
namespace views {
class ImageView;
@@ -22,8 +22,13 @@ namespace message_center {
class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button {
public:
+ METADATA_HEADER(NotificationHeaderView);
+
explicit NotificationHeaderView(PressedCallback callback);
+ NotificationHeaderView(const NotificationHeaderView&) = delete;
+ NotificationHeaderView& operator=(const NotificationHeaderView&) = delete;
~NotificationHeaderView() override;
+
void SetAppIcon(const gfx::ImageSkia& img);
void SetAppName(const base::string16& name);
void SetAppNameElideBehavior(gfx::ElideBehavior elide_behavior);
@@ -106,8 +111,6 @@ class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button {
bool has_progress_ = false;
bool is_expanded_ = false;
bool using_default_app_icon_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(NotificationHeaderView);
};
} // namespace message_center
diff --git a/chromium/ui/message_center/views/notification_header_view_unittest.cc b/chromium/ui/message_center/views/notification_header_view_unittest.cc
index 936dbb95c71..e7ccc97ccdb 100644
--- a/chromium/ui/message_center/views/notification_header_view_unittest.cc
+++ b/chromium/ui/message_center/views/notification_header_view_unittest.cc
@@ -18,6 +18,7 @@
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
+#include "ui/views/test/view_metadata_test_utils.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
@@ -28,6 +29,9 @@ class NotificationHeaderViewTest : public views::ViewsTestBase {
NotificationHeaderViewTest()
: views::ViewsTestBase(
base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+ NotificationHeaderViewTest(const NotificationHeaderViewTest&) = delete;
+ NotificationHeaderViewTest& operator=(const NotificationHeaderViewTest&) =
+ delete;
~NotificationHeaderViewTest() override = default;
// ViewsTestBase:
@@ -77,8 +81,6 @@ class NotificationHeaderViewTest : public views::ViewsTestBase {
private:
views::Widget widget_;
-
- DISALLOW_COPY_AND_ASSIGN(NotificationHeaderViewTest);
};
TEST_F(NotificationHeaderViewTest, UpdatesTimestampOverTime) {
@@ -213,4 +215,8 @@ TEST_F(NotificationHeaderViewTest, DefaultFocusBehavior) {
notification_header_view_->GetFocusBehavior());
}
+TEST_F(NotificationHeaderViewTest, MetadataTest) {
+ views::test::TestViewMetadata(notification_header_view_);
+}
+
} // namespace message_center
diff --git a/chromium/ui/message_center/views/notification_view_md.h b/chromium/ui/message_center/views/notification_view_md.h
index f9131770f9f..528b642bc36 100644
--- a/chromium/ui/message_center/views/notification_view_md.h
+++ b/chromium/ui/message_center/views/notification_view_md.h
@@ -213,6 +213,9 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
void OnNotificationInputSubmit(size_t index,
const base::string16& text) override;
+ protected:
+ views::View* image_container_view() { return image_container_view_; }
+
private:
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, AppNameExtension);
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, AppNameSystemNotification);
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 80afef5aa91..25d5ecf6bc1 100644
--- a/chromium/ui/message_center/views/notification_view_md_unittest.cc
+++ b/chromium/ui/message_center/views/notification_view_md_unittest.cc
@@ -9,6 +9,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/events/event_processor.h"
@@ -857,7 +858,7 @@ TEST_F(NotificationViewMDTest, MAYBE_DisableSlideForcibly) {
}
// Pinning notification is ChromeOS only feature.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(NotificationViewMDTest, SlideOutPinned) {
notification_view()->SetIsNested();
@@ -940,7 +941,7 @@ TEST_F(NotificationViewMDTest, SnoozeButton) {
notification_view()->GetControlButtonsView()->snooze_button());
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(NotificationViewMDTest, ExpandLongMessage) {
std::unique_ptr<Notification> notification = CreateSimpleNotification();
@@ -1197,7 +1198,7 @@ TEST_F(NotificationViewMDTest, InlineSettings) {
generator.ClickLeftButton();
EXPECT_TRUE(notification_view()->settings_row_->GetVisible());
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
// 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();
diff --git a/chromium/ui/message_center/views/padded_button.cc b/chromium/ui/message_center/views/padded_button.cc
index 24409c24745..0972f1caa62 100644
--- a/chromium/ui/message_center/views/padded_button.cc
+++ b/chromium/ui/message_center/views/padded_button.cc
@@ -6,15 +6,17 @@
#include <memory>
-#include "ui/base/resource/resource_bundle.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/canvas.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
-#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/animation/ink_drop.h"
+#include "ui/views/animation/ink_drop_host_view.h"
#include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/image_button.h"
-#include "ui/views/painter.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
namespace message_center {
@@ -38,7 +40,7 @@ std::unique_ptr<views::InkDrop> PaddedButton::CreateInkDrop() {
void PaddedButton::OnThemeChanged() {
ImageButton::OnThemeChanged();
auto* theme = GetNativeTheme();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
SetBackground(views::CreateSolidBackground(theme->GetSystemColor(
ui::NativeTheme::kColorId_NotificationButtonBackground)));
#endif
@@ -46,4 +48,7 @@ void PaddedButton::OnThemeChanged() {
ui::NativeTheme::kColorId_PaddedButtonInkDropColor));
}
+BEGIN_METADATA(PaddedButton, views::ImageButton)
+END_METADATA
+
} // namespace message_center
diff --git a/chromium/ui/message_center/views/padded_button.h b/chromium/ui/message_center/views/padded_button.h
index 1fa0806d115..1732d330aed 100644
--- a/chromium/ui/message_center/views/padded_button.h
+++ b/chromium/ui/message_center/views/padded_button.h
@@ -5,12 +5,10 @@
#ifndef UI_MESSAGE_CENTER_VIEWS_PADDED_BUTTON_H_
#define UI_MESSAGE_CENTER_VIEWS_PADDED_BUTTON_H_
-#include "base/compiler_specific.h"
-#include "base/macros.h"
#include "ui/message_center/message_center_export.h"
#include "ui/views/animation/ink_drop.h"
-#include "ui/views/animation/ink_drop_ripple.h"
#include "ui/views/controls/button/image_button.h"
+#include "ui/views/metadata/metadata_header_macros.h"
namespace message_center {
@@ -23,15 +21,16 @@ namespace message_center {
// area (<http://crbug.com/168856>).
class MESSAGE_CENTER_EXPORT PaddedButton : public views::ImageButton {
public:
+ METADATA_HEADER(PaddedButton);
+
explicit PaddedButton(PressedCallback callback);
+ PaddedButton(const PaddedButton&) = delete;
+ PaddedButton& operator=(const PaddedButton&) = delete;
~PaddedButton() override = default;
// views::ImageButton:
std::unique_ptr<views::InkDrop> CreateInkDrop() override;
void OnThemeChanged() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PaddedButton);
};
} // namespace message_center
diff --git a/chromium/ui/message_center/views/proportional_image_view.cc b/chromium/ui/message_center/views/proportional_image_view.cc
index 5766c47f1c1..df2febe5da8 100644
--- a/chromium/ui/message_center/views/proportional_image_view.cc
+++ b/chromium/ui/message_center/views/proportional_image_view.cc
@@ -7,11 +7,10 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/message_center/message_center_style.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
namespace message_center {
-const char ProportionalImageView::kViewClassName[] = "ProportionalImageView";
-
ProportionalImageView::ProportionalImageView(const gfx::Size& view_size) {
SetPreferredSize(view_size);
}
@@ -43,10 +42,6 @@ void ProportionalImageView::OnPaint(gfx::Canvas* canvas) {
canvas->DrawImageInt(image, draw_bounds.x(), draw_bounds.y());
}
-const char* ProportionalImageView::GetClassName() const {
- return kViewClassName;
-}
-
gfx::Size ProportionalImageView::GetImageDrawingSize() {
if (!GetVisible())
return gfx::Size();
@@ -56,4 +51,7 @@ gfx::Size ProportionalImageView::GetImageDrawingSize() {
return GetImageSizeForContainerSize(max_size, image_.size());
}
+BEGIN_METADATA(ProportionalImageView, views::View)
+END_METADATA
+
} // namespace message_center
diff --git a/chromium/ui/message_center/views/proportional_image_view.h b/chromium/ui/message_center/views/proportional_image_view.h
index d0d28904bbb..745188768d5 100644
--- a/chromium/ui/message_center/views/proportional_image_view.h
+++ b/chromium/ui/message_center/views/proportional_image_view.h
@@ -16,10 +16,10 @@ namespace message_center {
// original proportions.
class MESSAGE_CENTER_EXPORT ProportionalImageView : public views::View {
public:
- // Internal class name.
- static const char kViewClassName[];
-
+ METADATA_HEADER(ProportionalImageView);
explicit ProportionalImageView(const gfx::Size& view_size);
+ ProportionalImageView(const ProportionalImageView&) = delete;
+ ProportionalImageView& operator=(const ProportionalImageView&) = delete;
~ProportionalImageView() override;
// |image| is scaled to fit within |view_size| and |max_image_size| while
@@ -31,17 +31,14 @@ class MESSAGE_CENTER_EXPORT ProportionalImageView : public views::View {
// Overridden from views::View:
void OnPaint(gfx::Canvas* canvas) override;
- const char* GetClassName() const override;
private:
gfx::Size GetImageDrawingSize();
gfx::ImageSkia image_;
gfx::Size max_image_size_;
-
- DISALLOW_COPY_AND_ASSIGN(ProportionalImageView);
};
} // namespace message_center
-#endif // UI_MESSAGE_CENTER_VIEWS_PROPORTIONAL_IMAGE_VIEW_H_
+#endif // UI_MESSAGE_CENTER_VIEWS_PROPORTIONAL_IMAGE_VIEW_H_
diff --git a/chromium/ui/native_theme/DIR_METADATA b/chromium/ui/native_theme/DIR_METADATA
new file mode 100644
index 00000000000..f31293e3139
--- /dev/null
+++ b/chromium/ui/native_theme/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI"
+}
diff --git a/chromium/ui/native_theme/OWNERS b/chromium/ui/native_theme/OWNERS
index b3faa6e0b26..23e41d0051c 100644
--- a/chromium/ui/native_theme/OWNERS
+++ b/chromium/ui/native_theme/OWNERS
@@ -1,5 +1,3 @@
ellyjones@chromium.org
estade@chromium.org
pkasting@chromium.org
-
-# COMPONENT: UI
diff --git a/chromium/ui/native_theme/common_theme.cc b/chromium/ui/native_theme/common_theme.cc
index 5d675682b77..8eef16d01a9 100644
--- a/chromium/ui/native_theme/common_theme.cc
+++ b/chromium/ui/native_theme/common_theme.cc
@@ -8,6 +8,7 @@
#include "base/notreached.h"
#include "base/optional.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
@@ -65,175 +66,73 @@ base::Optional<SkColor> GetHighContrastColor(
base::Optional<SkColor> GetDarkSchemeColor(NativeTheme::ColorId color_id) {
switch (color_id) {
- // Dialogs
- case NativeTheme::kColorId_WindowBackground:
- case NativeTheme::kColorId_ButtonColor:
- case NativeTheme::kColorId_DialogBackground:
- case NativeTheme::kColorId_BubbleBackground:
- case NativeTheme::kColorId_NotificationDefaultBackground:
- return color_utils::AlphaBlend(SK_ColorWHITE, gfx::kGoogleGrey900, 0.04f);
- case NativeTheme::kColorId_AvatarIconGuest:
- case NativeTheme::kColorId_DialogForeground:
- return gfx::kGoogleGrey500;
- case NativeTheme::kColorId_BubbleFooterBackground:
- return SkColorSetRGB(0x32, 0x36, 0x39);
- case NativeTheme::kColorId_AvatarHeaderArt:
- return gfx::kGoogleGrey800;
- case NativeTheme::kColorId_AvatarIconIncognito:
- return gfx::kGoogleGrey200;
+ // Alert
+ case NativeTheme::kColorId_AlertSeverityLow:
+ return gfx::kGoogleGreen300;
+ case NativeTheme::kColorId_AlertSeverityHigh:
+ return gfx::kGoogleRed300;
+ case NativeTheme::kColorId_AlertSeverityMedium:
+ return gfx::kGoogleYellow300;
- // FocusableBorder
- case NativeTheme::kColorId_FocusedBorderColor:
- return SkColorSetA(gfx::kGoogleBlue300, 0x4D);
- case NativeTheme::kColorId_UnfocusedBorderColor:
- return gfx::kGoogleGrey800;
+ // Bubble
+ case NativeTheme::kColorId_FootnoteContainerBorder:
+ return gfx::kGoogleGrey900;
// Button
- case NativeTheme::kColorId_ButtonBorderColor:
- return gfx::kGoogleGrey800;
- case NativeTheme::kColorId_ButtonCheckedColor:
- case NativeTheme::kColorId_ButtonEnabledColor:
- case NativeTheme::kColorId_ProminentButtonColor:
- return gfx::kGoogleBlue300;
- case NativeTheme::kColorId_ButtonHoverColor:
- return SkColorSetA(SK_ColorBLACK, 0x0A);
case NativeTheme::kColorId_ButtonInkDropShadowColor:
return SkColorSetA(SK_ColorBLACK, 0x7F);
+ case NativeTheme::kColorId_ButtonHoverColor:
+ return SkColorSetA(SK_ColorBLACK, 0x0A);
case NativeTheme::kColorId_ButtonInkDropFillColor:
- case NativeTheme::kColorId_ProminentButtonInkDropFillColor:
+ case NativeTheme::kColorId_ProminentButtonHoverColor:
return SkColorSetA(SK_ColorWHITE, 0x0A);
+ case NativeTheme::kColorId_ProminentButtonColor:
+ return gfx::kGoogleBlue300;
case NativeTheme::kColorId_ProminentButtonInkDropShadowColor:
return SkColorSetA(gfx::kGoogleBlue300, 0x7F);
- case NativeTheme::kColorId_ProminentButtonHoverColor:
- return SkColorSetA(SK_ColorWHITE, 0x0A);
- case NativeTheme::kColorId_ButtonUncheckedColor:
- return gfx::kGoogleGrey500;
- case NativeTheme::kColorId_TextOnProminentButtonColor:
- return gfx::kGoogleGrey900;
- case NativeTheme::kColorId_PaddedButtonInkDropColor:
- return SK_ColorWHITE;
- // MenuItem
- case NativeTheme::kColorId_HighlightedMenuItemForegroundColor:
- case NativeTheme::kColorId_MenuDropIndicator:
- return gfx::kGoogleGrey200;
- case NativeTheme::kColorId_MenuBorderColor:
- case NativeTheme::kColorId_MenuSeparatorColor:
- return gfx::kGoogleGrey800;
- case NativeTheme::kColorId_HighlightedMenuItemBackgroundColor:
- return SkColorSetRGB(0x32, 0x36, 0x39);
- case NativeTheme::kColorId_MenuItemInitialAlertBackgroundColor:
- return SkColorSetA(gfx::kGoogleBlue300, 0x4D);
- case NativeTheme::kColorId_MenuItemTargetAlertBackgroundColor:
- return SkColorSetA(gfx::kGoogleBlue300, 0x1A);
- case NativeTheme::kColorId_MenuItemMinorTextColor:
- return gfx::kGoogleGrey500;
+ // Custom tab bar
+ case NativeTheme::kColorId_CustomTabBarBackgroundColor:
+ return gfx::kGoogleGrey900;
- // Custom frame view
+ // Frame
case NativeTheme::kColorId_CustomFrameActiveColor:
return gfx::kGoogleGrey900;
case NativeTheme::kColorId_CustomFrameInactiveColor:
return gfx::kGoogleGrey800;
- // Custom tab bar
- case NativeTheme::kColorId_CustomTabBarBackgroundColor:
- return gfx::kGoogleGrey900;
-
- // Dropdown
- case NativeTheme::kColorId_DropdownBackgroundColor:
- return color_utils::AlphaBlend(SK_ColorWHITE, gfx::kGoogleGrey900, 0.04f);
- case NativeTheme::kColorId_DropdownForegroundColor:
- return gfx::kGoogleGrey200;
- case NativeTheme::kColorId_DropdownSelectedForegroundColor:
- return gfx::kGoogleGrey200;
-
// Label
- case NativeTheme::kColorId_LabelEnabledColor:
- case NativeTheme::kColorId_LabelTextSelectionColor:
- return gfx::kGoogleGrey200;
case NativeTheme::kColorId_LabelSecondaryColor:
return gfx::kGoogleGrey500;
+ case NativeTheme::kColorId_LabelEnabledColor:
+ return gfx::kGoogleGrey200;
case NativeTheme::kColorId_LabelTextSelectionBackgroundFocused:
return gfx::kGoogleBlue800;
- // Link
- case NativeTheme::kColorId_LinkEnabled:
- case NativeTheme::kColorId_LinkPressed:
- return gfx::kGoogleBlue300;
+ // Menu
+ case NativeTheme::kColorId_HighlightedMenuItemBackgroundColor:
+ return SkColorSetRGB(0x32, 0x36, 0x39);
// Separator
case NativeTheme::kColorId_SeparatorColor:
return gfx::kGoogleGrey800;
- // TabbedPane
- case NativeTheme::kColorId_TabTitleColorActive:
- case NativeTheme::kColorId_TabSelectedBorderColor:
- return gfx::kGoogleBlue300;
- case NativeTheme::kColorId_TabTitleColorInactive:
- return gfx::kGoogleGrey500;
- case NativeTheme::kColorId_TabBottomBorder:
- return gfx::kGoogleGrey800;
- case NativeTheme::kColorId_TabHighlightBackground:
- return gfx::kGoogleGrey800;
+ // Tabbed pane
case NativeTheme::kColorId_TabHighlightFocusedBackground:
return SkColorSetRGB(0x32, 0x36, 0x39);
-
- // Table
- case NativeTheme::kColorId_TableBackground:
- case NativeTheme::kColorId_TableBackgroundAlternate:
- return color_utils::AlphaBlend(SK_ColorWHITE, gfx::kGoogleGrey900, 0.04f);
- case NativeTheme::kColorId_TableText:
- case NativeTheme::kColorId_TableSelectedText:
- case NativeTheme::kColorId_TableSelectedTextUnfocused:
- return gfx::kGoogleGrey200;
-
- // Textfield
- case NativeTheme::kColorId_TextfieldDefaultColor:
- case NativeTheme::kColorId_TextfieldSelectionColor:
- return gfx::kGoogleGrey200;
- case NativeTheme::kColorId_TextfieldReadOnlyBackground: {
- return color_utils::AlphaBlend(SK_ColorWHITE, gfx::kGoogleGrey900, 0.04f);
- }
- case NativeTheme::kColorId_TextfieldSelectionBackgroundFocused:
- return gfx::kGoogleBlue800;
+ case NativeTheme::kColorId_TabHighlightBackground:
+ return gfx::kGoogleGrey800;
// Tooltip
case NativeTheme::kColorId_TooltipIcon:
return SkColorSetA(gfx::kGoogleGrey200, 0xBD);
case NativeTheme::kColorId_TooltipIconHovered:
return SK_ColorWHITE;
- case NativeTheme::kColorId_TooltipText:
- return SkColorSetA(gfx::kGoogleGrey200, 0xDE);
- // Tree
- case NativeTheme::kColorId_TreeBackground:
+ // Window
+ case NativeTheme::kColorId_WindowBackground:
return color_utils::AlphaBlend(SK_ColorWHITE, gfx::kGoogleGrey900, 0.04f);
- case NativeTheme::kColorId_TreeText:
- case NativeTheme::kColorId_TreeSelectedText:
- case NativeTheme::kColorId_TreeSelectedTextUnfocused:
- return gfx::kGoogleGrey200;
-
- // Material spinner/throbber
- case NativeTheme::kColorId_ThrobberSpinningColor:
- return gfx::kGoogleBlue300;
-
- case NativeTheme::kColorId_BubbleBorder:
- return gfx::kGoogleGrey800;
-
- case NativeTheme::kColorId_FootnoteContainerBorder:
- return gfx::kGoogleGrey900;
-
- // Alert icon colors
- case NativeTheme::kColorId_AlertSeverityLow:
- return gfx::kGoogleGreen300;
- case NativeTheme::kColorId_AlertSeverityMedium:
- return gfx::kGoogleYellow300;
- case NativeTheme::kColorId_AlertSeverityHigh:
- return gfx::kGoogleRed300;
- case NativeTheme::kColorId_MenuIconColor:
- case NativeTheme::kColorId_DefaultIconColor:
- return gfx::kGoogleGrey500;
default:
return base::nullopt;
}
@@ -242,131 +141,101 @@ base::Optional<SkColor> GetDarkSchemeColor(NativeTheme::ColorId color_id) {
SkColor GetDefaultColor(NativeTheme::ColorId color_id,
const NativeTheme* base_theme,
NativeTheme::ColorScheme color_scheme) {
- constexpr SkColor kPrimaryTextColor = gfx::kGoogleGrey900;
-
switch (color_id) {
- // Dialogs
- case NativeTheme::kColorId_WindowBackground:
- case NativeTheme::kColorId_ButtonColor:
- case NativeTheme::kColorId_DialogBackground:
- case NativeTheme::kColorId_BubbleBackground:
- case NativeTheme::kColorId_NotificationDefaultBackground:
- return SK_ColorWHITE;
+ // Alert
+ case NativeTheme::kColorId_AlertSeverityLow:
+ return gfx::kGoogleGreen700;
+ case NativeTheme::kColorId_AlertSeverityHigh:
+ return gfx::kGoogleRed600;
+ case NativeTheme::kColorId_AlertSeverityMedium:
+ return gfx::kGoogleYellow700;
+
+ // Avatar
case NativeTheme::kColorId_AvatarHeaderArt:
- return gfx::kGoogleGrey300;
- case NativeTheme::kColorId_AvatarIconIncognito:
- return kPrimaryTextColor;
+ return base_theme->GetSystemColor(NativeTheme::kColorId_SeparatorColor,
+ color_scheme);
case NativeTheme::kColorId_AvatarIconGuest:
- case NativeTheme::kColorId_DialogForeground:
- return gfx::kGoogleGrey700;
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_LabelSecondaryColor, color_scheme);
+ case NativeTheme::kColorId_AvatarIconIncognito:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_LabelEnabledColor,
+ color_scheme);
+
+ // Border
+ case NativeTheme::kColorId_UnfocusedBorderColor:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_SeparatorColor,
+ color_scheme);
+ case NativeTheme::kColorId_FocusedBorderColor: {
+ const SkColor accent = base_theme->GetSystemColor(
+ NativeTheme::kColorId_ProminentButtonColor, color_scheme);
+ return SkColorSetA(accent, 0x4D);
+ }
+
+ // Bubble
+ case NativeTheme::kColorId_BubbleBackground:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_WindowBackground,
+ color_scheme);
case NativeTheme::kColorId_BubbleFooterBackground:
- return gfx::kGoogleGrey050;
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_HighlightedMenuItemBackgroundColor,
+ color_scheme);
+ case NativeTheme::kColorId_FootnoteContainerBorder:
+ return gfx::kGoogleGrey200;
+ case NativeTheme::kColorId_BubbleBorder:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_SeparatorColor,
+ color_scheme);
- // Buttons
- case NativeTheme::kColorId_ButtonCheckedColor:
- case NativeTheme::kColorId_ButtonEnabledColor:
- return gfx::kGoogleBlue600;
- case NativeTheme::kColorId_ButtonInkDropShadowColor:
- return SkColorSetA(SK_ColorBLACK, 0x1A);
- case NativeTheme::kColorId_ButtonHoverColor:
- return SkColorSetA(SK_ColorBLACK, 0x05);
- case NativeTheme::kColorId_ButtonInkDropFillColor:
- return SkColorSetA(SK_ColorWHITE, 0x05);
- case NativeTheme::kColorId_ProminentButtonInkDropShadowColor:
- return SkColorSetA(SK_ColorBLACK, 0x3D);
+ // Button
+ case NativeTheme::kColorId_ButtonColor:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_WindowBackground,
+ color_scheme);
+ case NativeTheme::kColorId_TextOnProminentButtonColor:
+ return color_utils::GetColorWithMaxContrast(base_theme->GetSystemColor(
+ NativeTheme::kColorId_ProminentButtonColor, color_scheme));
case NativeTheme::kColorId_ProminentButtonHoverColor:
return SkColorSetA(SK_ColorWHITE, 0x0D);
case NativeTheme::kColorId_ProminentButtonInkDropFillColor:
- return SkColorSetA(SK_ColorWHITE, 0x0D);
- case NativeTheme::kColorId_ProminentButtonFocusedColor: {
- const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_ProminentButtonColor, color_scheme);
- return color_utils::BlendForMinContrast(bg, bg, base::nullopt, 1.3f)
- .color;
- }
- case NativeTheme::kColorId_ProminentButtonColor:
- return gfx::kGoogleBlue600;
- case NativeTheme::kColorId_TextOnProminentButtonColor:
- return SK_ColorWHITE;
- case NativeTheme::kColorId_ButtonUncheckedColor:
- return gfx::kGoogleGrey700;
- case NativeTheme::kColorId_ButtonDisabledColor: {
- const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_ButtonColor, color_scheme);
- const SkColor fg = base_theme->GetSystemColor(
- NativeTheme::kColorId_LabelEnabledColor, color_scheme);
- return color_utils::BlendForMinContrast(gfx::kGoogleGrey600, bg, fg)
- .color;
- }
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_ProminentButtonHoverColor, color_scheme);
+ case NativeTheme::kColorId_ButtonInkDropFillColor:
+ return SkColorSetA(SK_ColorWHITE, 0x05);
case NativeTheme::kColorId_ProminentButtonDisabledColor:
case NativeTheme::kColorId_DisabledButtonBorderColor: {
const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_ButtonColor, color_scheme);
+ NativeTheme::kColorId_WindowBackground, color_scheme);
return color_utils::BlendForMinContrast(bg, bg, base::nullopt, 1.2f)
.color;
}
case NativeTheme::kColorId_ButtonBorderColor:
- return gfx::kGoogleGrey300;
- case NativeTheme::kColorId_PaddedButtonInkDropColor:
- return gfx::kGoogleGrey900;
-
- // ToggleButton
- case NativeTheme::kColorId_ToggleButtonShadowColor:
- return SkColorSetA(
- base_theme->GetSystemColor(NativeTheme::kColorId_LabelEnabledColor,
- color_scheme),
- 0x99);
- case ui::NativeTheme::kColorId_ToggleButtonTrackColorOff:
- case ui::NativeTheme::kColorId_ToggleButtonTrackColorOn: {
- const ui::NativeTheme::ColorId base_color_id =
- color_id == ui::NativeTheme::kColorId_ToggleButtonTrackColorOff
- ? ui::NativeTheme::kColorId_LabelEnabledColor
- : ui::NativeTheme::kColorId_ProminentButtonColor;
- return SkColorSetA(
- base_theme->GetSystemColor(base_color_id, color_scheme), 0x66);
- }
-
- // MenuItem
- case NativeTheme::kColorId_EnabledMenuItemForegroundColor:
- return base_theme->GetSystemColor(
- NativeTheme::kColorId_DropdownForegroundColor, color_scheme);
- case NativeTheme::kColorId_SelectedMenuItemForegroundColor:
- return base_theme->GetSystemColor(
- NativeTheme::kColorId_DropdownSelectedForegroundColor, color_scheme);
- case NativeTheme::kColorId_HighlightedMenuItemForegroundColor:
- case NativeTheme::kColorId_MenuDropIndicator:
- return kPrimaryTextColor;
- case NativeTheme::kColorId_FocusedMenuItemBackgroundColor:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_SeparatorColor,
+ color_scheme);
+ case NativeTheme::kColorId_ButtonDisabledColor:
return base_theme->GetSystemColor(
- NativeTheme::kColorId_DropdownSelectedBackgroundColor, color_scheme);
- case NativeTheme::kColorId_MenuBorderColor:
- case NativeTheme::kColorId_MenuSeparatorColor:
- return gfx::kGoogleGrey300;
- case NativeTheme::kColorId_MenuBackgroundColor:
+ NativeTheme::kColorId_LabelDisabledColor, color_scheme);
+ case NativeTheme::kColorId_ButtonUncheckedColor:
return base_theme->GetSystemColor(
- NativeTheme::kColorId_DropdownBackgroundColor, color_scheme);
- case NativeTheme::kColorId_DisabledMenuItemForegroundColor: {
+ NativeTheme::kColorId_LabelSecondaryColor, color_scheme);
+ case NativeTheme::kColorId_PaddedButtonInkDropColor:
+ return color_utils::GetColorWithMaxContrast(base_theme->GetSystemColor(
+ NativeTheme::kColorId_WindowBackground, color_scheme));
+ case NativeTheme::kColorId_ButtonHoverColor:
+ return SkColorSetA(SK_ColorBLACK, 0x05);
+ case NativeTheme::kColorId_ButtonInkDropShadowColor:
+ return SkColorSetA(SK_ColorBLACK, gfx::kGoogleGreyAlpha200);
+ case NativeTheme::kColorId_ProminentButtonInkDropShadowColor:
+ return SkColorSetA(SK_ColorBLACK, 0x3D);
+ case NativeTheme::kColorId_ProminentButtonFocusedColor: {
const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_MenuBackgroundColor, color_scheme);
- const SkColor fg = base_theme->GetSystemColor(
- NativeTheme::kColorId_EnabledMenuItemForegroundColor, color_scheme);
- return color_utils::BlendForMinContrast(gfx::kGoogleGrey600, bg, fg)
+ NativeTheme::kColorId_ProminentButtonColor, color_scheme);
+ return color_utils::BlendForMinContrast(bg, bg, base::nullopt, 1.3f)
.color;
}
- case NativeTheme::kColorId_MenuItemMinorTextColor:
- return gfx::kGoogleGrey700;
- case NativeTheme::kColorId_HighlightedMenuItemBackgroundColor:
- return gfx::kGoogleGrey050;
- case NativeTheme::kColorId_MenuItemInitialAlertBackgroundColor:
- return SkColorSetA(gfx::kGoogleBlue600, 0x4D);
- case NativeTheme::kColorId_MenuItemTargetAlertBackgroundColor:
- return SkColorSetA(gfx::kGoogleBlue600, 0x1A);
-
- // Custom frame view
- case NativeTheme::kColorId_CustomFrameActiveColor:
- return SkColorSetRGB(0xDE, 0xE1, 0xE6);
- case NativeTheme::kColorId_CustomFrameInactiveColor:
- return SkColorSetRGB(0xE7, 0xEA, 0xED);
+ case NativeTheme::kColorId_ButtonCheckedColor:
+ case NativeTheme::kColorId_ButtonEnabledColor:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_ProminentButtonColor, color_scheme);
+ case NativeTheme::kColorId_ProminentButtonColor:
+ return gfx::kGoogleBlue600;
// Custom tab bar
case NativeTheme::kColorId_CustomTabBarBackgroundColor:
@@ -385,27 +254,49 @@ SkColor GetDefaultColor(NativeTheme::ColorId color_id,
return GetSecurityChipColor(GetSecurityChipColorId(color_id), fg, bg);
}
+ // Dialog
+ case NativeTheme::kColorId_DialogBackground:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_WindowBackground,
+ color_scheme);
+ case NativeTheme::kColorId_DialogForeground:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_LabelSecondaryColor, color_scheme);
+
// Dropdown
case NativeTheme::kColorId_DropdownBackgroundColor:
- return SK_ColorWHITE;
- case NativeTheme::kColorId_DropdownForegroundColor:
- return kPrimaryTextColor;
+ return base_theme->GetSystemColor(NativeTheme::kColorId_WindowBackground,
+ color_scheme);
case NativeTheme::kColorId_DropdownSelectedBackgroundColor: {
const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_MenuBackgroundColor, color_scheme);
+ NativeTheme::kColorId_WindowBackground, color_scheme);
return color_utils::BlendForMinContrast(bg, bg, base::nullopt, 1.67f)
.color;
}
+ case NativeTheme::kColorId_DropdownForegroundColor:
case NativeTheme::kColorId_DropdownSelectedForegroundColor:
- return kPrimaryTextColor;
+ return base_theme->GetSystemColor(NativeTheme::kColorId_LabelEnabledColor,
+ color_scheme);
+
+ // Frame
+ case NativeTheme::kColorId_CustomFrameActiveColor:
+ return SkColorSetRGB(0xDE, 0xE1, 0xE6);
+ case NativeTheme::kColorId_CustomFrameInactiveColor:
+ return SkColorSetRGB(0xE7, 0xEA, 0xED);
+
+ // Icon
+ case NativeTheme::kColorId_DefaultIconColor:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_LabelSecondaryColor, color_scheme);
+ case NativeTheme::kColorId_DisabledIconColor: {
+ const SkColor icon = base_theme->GetSystemColor(
+ NativeTheme::kColorId_LabelSecondaryColor, color_scheme);
+ return SkColorSetA(icon, gfx::kDisabledControlAlpha);
+ }
// Label
- case NativeTheme::kColorId_LabelEnabledColor:
- case NativeTheme::kColorId_LabelTextSelectionColor:
- return kPrimaryTextColor;
case NativeTheme::kColorId_LabelDisabledColor: {
const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_DialogBackground, color_scheme);
+ NativeTheme::kColorId_WindowBackground, color_scheme);
const SkColor fg = base_theme->GetSystemColor(
NativeTheme::kColorId_LabelEnabledColor, color_scheme);
return color_utils::BlendForMinContrast(gfx::kGoogleGrey600, bg, fg)
@@ -413,108 +304,209 @@ SkColor GetDefaultColor(NativeTheme::ColorId color_id,
}
case NativeTheme::kColorId_LabelSecondaryColor:
return gfx::kGoogleGrey700;
+ case NativeTheme::kColorId_LabelEnabledColor:
+ return gfx::kGoogleGrey900;
+ case NativeTheme::kColorId_LabelTextSelectionColor:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_LabelEnabledColor,
+ color_scheme);
case NativeTheme::kColorId_LabelTextSelectionBackgroundFocused:
return gfx::kGoogleBlue200;
// Link
- case NativeTheme::kColorId_LinkDisabled: {
- const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_DialogBackground, color_scheme);
- const SkColor fg = base_theme->GetSystemColor(
- NativeTheme::kColorId_LabelEnabledColor, color_scheme);
- return color_utils::BlendForMinContrast(gfx::kGoogleGrey600, bg, fg)
- .color;
- }
+ case NativeTheme::kColorId_LinkDisabled:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_LabelDisabledColor, color_scheme);
case NativeTheme::kColorId_LinkEnabled:
case NativeTheme::kColorId_LinkPressed:
- return gfx::kGoogleBlue600;
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_ProminentButtonColor, color_scheme);
- // Notification view
+ // Menu
+ case NativeTheme::kColorId_MenuBackgroundColor:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_WindowBackground,
+ color_scheme);
+ case NativeTheme::kColorId_HighlightedMenuItemBackgroundColor:
+ return gfx::kGoogleGrey050;
+ case NativeTheme::kColorId_MenuBorderColor:
+ case NativeTheme::kColorId_MenuSeparatorColor:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_SeparatorColor,
+ color_scheme);
+ case NativeTheme::kColorId_FocusedMenuItemBackgroundColor:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_DropdownSelectedBackgroundColor, color_scheme);
+ case NativeTheme::kColorId_DisabledMenuItemForegroundColor:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_LabelDisabledColor, color_scheme);
+ case NativeTheme::kColorId_MenuIconColor:
+ case NativeTheme::kColorId_MenuItemMinorTextColor:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_LabelSecondaryColor, color_scheme);
+ case NativeTheme::kColorId_EnabledMenuItemForegroundColor:
+ case NativeTheme::kColorId_HighlightedMenuItemForegroundColor:
+ case NativeTheme::kColorId_MenuDropIndicator:
+ case NativeTheme::kColorId_SelectedMenuItemForegroundColor:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_LabelEnabledColor,
+ color_scheme);
+ case NativeTheme::kColorId_MenuItemInitialAlertBackgroundColor:
+ case NativeTheme::kColorId_MenuItemTargetAlertBackgroundColor: {
+ const SkColor accent = base_theme->GetSystemColor(
+ NativeTheme::kColorId_ProminentButtonColor, color_scheme);
+ constexpr auto kInitial =
+ NativeTheme::kColorId_MenuItemInitialAlertBackgroundColor;
+ return SkColorSetA(
+ accent, (color_id == kInitial) ? 0x4D : gfx::kGoogleGreyAlpha200);
+ }
+
+ // Notification
+ case NativeTheme::kColorId_NotificationDefaultBackground:
case NativeTheme::kColorId_NotificationPlaceholderIconColor:
- return SK_ColorWHITE;
+ return base_theme->GetSystemColor(NativeTheme::kColorId_WindowBackground,
+ color_scheme);
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ case NativeTheme::kColorId_NotificationButtonBackground:
+ return SkColorSetA(SK_ColorWHITE, 0.9 * 0xff);
+#endif
+ case NativeTheme::kColorId_NotificationEmptyPlaceholderTextColor:
+ return SkColorSetA(SK_ColorWHITE, gfx::kDisabledControlAlpha);
+ case NativeTheme::kColorId_NotificationEmptyPlaceholderIconColor:
+ return SkColorSetA(SK_ColorWHITE, 0x60);
case NativeTheme::kColorId_NotificationActionsRowBackground:
case NativeTheme::kColorId_NotificationInlineSettingsBackground: {
const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_NotificationDefaultBackground, color_scheme);
- // The alpha value here (0x14) is chosen to generate 0xEEE from 0xFFF.
+ NativeTheme::kColorId_WindowBackground, color_scheme);
return color_utils::BlendTowardMaxContrast(bg, 0x14);
}
case NativeTheme::kColorId_NotificationLargeImageBackground: {
const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_NotificationDefaultBackground, color_scheme);
- // The alpha value here (0x0C) is chosen to generate 0xF5F5F5 from 0xFFF.
+ NativeTheme::kColorId_WindowBackground, color_scheme);
return color_utils::BlendTowardMaxContrast(bg, 0x0C);
}
- case NativeTheme::kColorId_NotificationEmptyPlaceholderIconColor:
- return SkColorSetA(SK_ColorWHITE, 0x60);
- case NativeTheme::kColorId_NotificationEmptyPlaceholderTextColor:
- return SkColorSetA(SK_ColorWHITE, gfx::kDisabledControlAlpha);
+ case NativeTheme::kColorId_NotificationDefaultAccentColor:
+ return gfx::kGoogleGrey700;
case NativeTheme::kColorId_NotificationInkDropBase:
return gfx::kGoogleBlue600;
-#if defined(OS_CHROMEOS)
- case NativeTheme::kColorId_NotificationButtonBackground:
- return SkColorSetA(SK_ColorWHITE, 0.9 * 0xff);
-#endif
- case NativeTheme::kColorId_NotificationDefaultAccentColor:
- return gfx::kChromeIconGrey;
// Scrollbar
- case NativeTheme::kColorId_OverlayScrollbarThumbBackground:
- return SK_ColorBLACK;
case NativeTheme::kColorId_OverlayScrollbarThumbForeground:
return SkColorSetA(SK_ColorWHITE, (kOverlayScrollbarStrokeNormalAlpha /
kOverlayScrollbarThumbNormalAlpha) *
SK_AlphaOPAQUE);
+ case NativeTheme::kColorId_OverlayScrollbarThumbBackground:
+ return SK_ColorBLACK;
+
+ // Separator
+ case NativeTheme::kColorId_SeparatorColor:
+ return gfx::kGoogleGrey300;
// Slider
- case NativeTheme::kColorId_SliderThumbDefault:
- return SkColorSetARGB(0xFF, 0x25, 0x81, 0xDF);
- case NativeTheme::kColorId_SliderTroughDefault:
- return SkColorSetARGB(0x40, 0x25, 0x81, 0xDF);
case NativeTheme::kColorId_SliderThumbMinimal:
- return SkColorSetARGB(0x6E, 0xF1, 0xF3, 0xF4);
+ return SkColorSetA(gfx::kGoogleGrey100, gfx::kGoogleGreyAlpha500);
case NativeTheme::kColorId_SliderTroughMinimal:
- return SkColorSetARGB(0x19, 0xF1, 0xF3, 0xF4);
+ return SkColorSetA(gfx::kGoogleGrey100, 0x19);
+ case NativeTheme::kColorId_SliderThumbDefault:
+ return gfx::kGoogleBlueDark600;
+ case NativeTheme::kColorId_SliderTroughDefault:
+ return SkColorSetA(gfx::kGoogleBlueDark600, 0x40);
- // Separator
- case NativeTheme::kColorId_SeparatorColor:
- return gfx::kGoogleGrey300;
+ // Sync info container
+ case NativeTheme::kColorId_SyncInfoContainerNoPrimaryAccount:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_HighlightedMenuItemBackgroundColor,
+ color_scheme);
+ case NativeTheme::kColorId_SyncInfoContainerPaused:
+ return SkColorSetA(
+ base_theme->GetSystemColor(NativeTheme::kColorId_ProminentButtonColor,
+ color_scheme),
+ 0x10);
+ case NativeTheme::kColorId_SyncInfoContainerError:
+ return SkColorSetA(
+ base_theme->GetSystemColor(NativeTheme::kColorId_AlertSeverityHigh,
+ color_scheme),
+ 0x10);
- // TabbedPane
- case NativeTheme::kColorId_TabTitleColorActive:
- case NativeTheme::kColorId_TabSelectedBorderColor:
- return gfx::kGoogleBlue600;
- case NativeTheme::kColorId_TabTitleColorInactive:
- return gfx::kGoogleGrey700;
+ // Tabbed pane
case NativeTheme::kColorId_TabBottomBorder:
- return gfx::kGoogleGrey300;
+ return base_theme->GetSystemColor(NativeTheme::kColorId_SeparatorColor,
+ color_scheme);
+ case NativeTheme::kColorId_TabTitleColorInactive:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_LabelSecondaryColor, color_scheme);
case NativeTheme::kColorId_TabHighlightBackground:
return gfx::kGoogleBlue050;
case NativeTheme::kColorId_TabHighlightFocusedBackground:
return gfx::kGoogleBlue100;
+ case NativeTheme::kColorId_TabTitleColorActive:
+ case NativeTheme::kColorId_TabSelectedBorderColor:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_ProminentButtonColor, color_scheme);
+
+ // Table
+ case NativeTheme::kColorId_TableBackground:
+ case NativeTheme::kColorId_TableBackgroundAlternate:
+ case NativeTheme::kColorId_TableHeaderBackground:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_WindowBackground,
+ color_scheme);
+ case NativeTheme::kColorId_TableGroupingIndicatorColor:
+ case NativeTheme::kColorId_TableSelectionBackgroundFocused:
+ case NativeTheme::kColorId_TableSelectionBackgroundUnfocused:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_DropdownSelectedBackgroundColor, color_scheme);
+ case NativeTheme::kColorId_TableHeaderSeparator:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_SeparatorColor,
+ color_scheme);
+ case NativeTheme::kColorId_TableHeaderText:
+ case NativeTheme::kColorId_TableSelectedText:
+ case NativeTheme::kColorId_TableSelectedTextUnfocused:
+ case NativeTheme::kColorId_TableText:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_LabelEnabledColor,
+ color_scheme);
// Textfield
- case NativeTheme::kColorId_TextfieldDefaultColor:
- case NativeTheme::kColorId_TextfieldSelectionColor:
- return kPrimaryTextColor;
+ case NativeTheme::kColorId_TextfieldReadOnlyBackground:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_WindowBackground,
+ color_scheme);
case NativeTheme::kColorId_TextfieldDefaultBackground: {
const SkColor fg = base_theme->GetSystemColor(
- NativeTheme::kColorId_TextfieldDefaultColor, color_scheme);
+ NativeTheme::kColorId_LabelEnabledColor, color_scheme);
return color_utils::GetColorWithMaxContrast(fg);
}
- case NativeTheme::kColorId_TextfieldReadOnlyBackground:
- return SK_ColorWHITE;
case NativeTheme::kColorId_TextfieldPlaceholderColor:
- case NativeTheme::kColorId_TextfieldReadOnlyColor: {
- const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_TextfieldReadOnlyBackground, color_scheme);
- const SkColor fg = base_theme->GetSystemColor(
- NativeTheme::kColorId_TextfieldDefaultColor, color_scheme);
- return color_utils::BlendForMinContrast(gfx::kGoogleGrey600, bg, fg)
- .color;
- }
+ case NativeTheme::kColorId_TextfieldReadOnlyColor:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_LabelDisabledColor, color_scheme);
+ case NativeTheme::kColorId_TextfieldDefaultColor:
+ case NativeTheme::kColorId_TextfieldSelectionColor:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_LabelEnabledColor,
+ color_scheme);
case NativeTheme::kColorId_TextfieldSelectionBackgroundFocused:
- return gfx::kGoogleBlue200;
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_LabelTextSelectionBackgroundFocused,
+ color_scheme);
+
+ // Throbber
+ case NativeTheme::kColorId_ThrobberLightColor:
+ return SkColorSetRGB(0xF4, 0xF8, 0xFD);
+ case NativeTheme::kColorId_ThrobberWaitingColor:
+ return SkColorSetRGB(0xA6, 0xA6, 0xA6);
+ case NativeTheme::kColorId_ThrobberSpinningColor:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_ProminentButtonColor, color_scheme);
+
+ // Toggle button
+ case NativeTheme::kColorId_ToggleButtonShadowColor:
+ return SkColorSetA(
+ base_theme->GetSystemColor(NativeTheme::kColorId_LabelEnabledColor,
+ color_scheme),
+ 0x99);
+ case ui::NativeTheme::kColorId_ToggleButtonTrackColorOff:
+ case ui::NativeTheme::kColorId_ToggleButtonTrackColorOn: {
+ const ui::NativeTheme::ColorId base_color_id =
+ color_id == ui::NativeTheme::kColorId_ToggleButtonTrackColorOff
+ ? ui::NativeTheme::kColorId_LabelEnabledColor
+ : ui::NativeTheme::kColorId_ProminentButtonColor;
+ return SkColorSetA(
+ base_theme->GetSystemColor(base_color_id, color_scheme), 0x66);
+ }
// Tooltip
case NativeTheme::kColorId_TooltipBackground: {
@@ -524,102 +516,31 @@ SkColor GetDefaultColor(NativeTheme::ColorId color_id,
}
case NativeTheme::kColorId_TooltipIcon:
return SkColorSetA(gfx::kGoogleGrey800, 0xBD);
+ case NativeTheme::kColorId_TooltipText: {
+ const SkColor text = base_theme->GetSystemColor(
+ NativeTheme::kColorId_LabelEnabledColor, color_scheme);
+ return SkColorSetA(text, 0xDE);
+ }
case NativeTheme::kColorId_TooltipIconHovered:
return SkColorSetA(SK_ColorBLACK, 0xBD);
- case NativeTheme::kColorId_TooltipText:
- return SkColorSetA(kPrimaryTextColor, 0xDE);
// Tree
case NativeTheme::kColorId_TreeBackground:
- return SK_ColorWHITE;
- case NativeTheme::kColorId_TreeText:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_WindowBackground,
+ color_scheme);
+ case NativeTheme::kColorId_TreeSelectionBackgroundFocused:
+ case NativeTheme::kColorId_TreeSelectionBackgroundUnfocused:
+ return base_theme->GetSystemColor(
+ NativeTheme::kColorId_DropdownSelectedBackgroundColor, color_scheme);
case NativeTheme::kColorId_TreeSelectedText:
case NativeTheme::kColorId_TreeSelectedTextUnfocused:
- return kPrimaryTextColor;
- case NativeTheme::kColorId_TreeSelectionBackgroundFocused:
- case NativeTheme::kColorId_TreeSelectionBackgroundUnfocused: {
- const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_TreeBackground, color_scheme);
- return color_utils::BlendForMinContrast(bg, bg, base::nullopt, 1.67f)
- .color;
- }
-
- // Table
- case NativeTheme::kColorId_TableBackground:
- case NativeTheme::kColorId_TableBackgroundAlternate:
- return SK_ColorWHITE;
- case NativeTheme::kColorId_TableText:
- case NativeTheme::kColorId_TableSelectedText:
- case NativeTheme::kColorId_TableSelectedTextUnfocused:
- return kPrimaryTextColor;
- case NativeTheme::kColorId_TableSelectionBackgroundFocused:
- case NativeTheme::kColorId_TableSelectionBackgroundUnfocused:
- case NativeTheme::kColorId_TableGroupingIndicatorColor: {
- const SkColor bg = base_theme->GetSystemColor(
- NativeTheme::kColorId_TableBackground, color_scheme);
- return color_utils::BlendForMinContrast(bg, bg, base::nullopt, 1.67f)
- .color;
- }
-
- // Table Header
- case NativeTheme::kColorId_TableHeaderText:
- return base_theme->GetSystemColor(NativeTheme::kColorId_TableText,
- color_scheme);
- case NativeTheme::kColorId_TableHeaderBackground:
- return base_theme->GetSystemColor(NativeTheme::kColorId_TableBackground,
- color_scheme);
- case NativeTheme::kColorId_TableHeaderSeparator:
- return base_theme->GetSystemColor(NativeTheme::kColorId_MenuBorderColor,
+ case NativeTheme::kColorId_TreeText:
+ return base_theme->GetSystemColor(NativeTheme::kColorId_LabelEnabledColor,
color_scheme);
- // FocusableBorder
- case NativeTheme::kColorId_FocusedBorderColor:
- return SkColorSetA(gfx::kGoogleBlue600, 0x4D);
- case NativeTheme::kColorId_UnfocusedBorderColor:
- return gfx::kGoogleGrey300;
-
- // Material spinner/throbber
- case NativeTheme::kColorId_ThrobberSpinningColor:
- return gfx::kGoogleBlue600;
- case NativeTheme::kColorId_ThrobberWaitingColor:
- return SkColorSetRGB(0xA6, 0xA6, 0xA6);
- case NativeTheme::kColorId_ThrobberLightColor:
- return SkColorSetRGB(0xF4, 0xF8, 0xFD);
-
- // Alert icon colors
- case NativeTheme::kColorId_AlertSeverityLow:
- return gfx::kGoogleGreen700;
- case NativeTheme::kColorId_AlertSeverityMedium:
- return gfx::kGoogleYellow700;
- case NativeTheme::kColorId_AlertSeverityHigh:
- return gfx::kGoogleRed600;
-
- case NativeTheme::kColorId_FootnoteContainerBorder:
- return gfx::kGoogleGrey200;
-
- case NativeTheme::kColorId_MenuIconColor:
- case NativeTheme::kColorId_DefaultIconColor:
- return gfx::kGoogleGrey700;
- case NativeTheme::kColorId_DisabledIconColor:
- return SkColorSetA(
- base_theme->GetSystemColor(NativeTheme::kColorId_DefaultIconColor),
- gfx::kDisabledControlAlpha);
-
- // Sync info container
- case NativeTheme::kColorId_SyncInfoContainerPaused:
- return SkColorSetA(base_theme->GetSystemColor(
- NativeTheme::kColorId_ProminentButtonColor),
- 16);
- case NativeTheme::kColorId_SyncInfoContainerError:
- return SkColorSetA(
- base_theme->GetSystemColor(NativeTheme::kColorId_AlertSeverityHigh),
- 16);
- case NativeTheme::kColorId_SyncInfoContainerNoPrimaryAccount:
- return base_theme->GetSystemColor(
- NativeTheme::kColorId_BubbleFooterBackground);
-
- case NativeTheme::kColorId_BubbleBorder:
- return gfx::kGoogleGrey300;
+ // Window
+ case NativeTheme::kColorId_WindowBackground:
+ return SK_ColorWHITE;
case NativeTheme::kColorId_NumColors:
// Keeping the kColorId_NumColors case instead of using the default case
@@ -673,7 +594,7 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
// High contrast overrides the normal colors for certain ColorIds to be much
// darker or lighter.
- if (base_theme->UsesHighContrastColors()) {
+ if (base_theme->UserHasContrastPreference()) {
base::Optional<SkColor> color =
GetHighContrastColor(color_id, color_scheme);
if (color.has_value())
diff --git a/chromium/ui/native_theme/native_theme.cc b/chromium/ui/native_theme/native_theme.cc
index 32b264749c2..d4e2f30a563 100644
--- a/chromium/ui/native_theme/native_theme.cc
+++ b/chromium/ui/native_theme/native_theme.cc
@@ -8,7 +8,7 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/containers/flat_map.h"
+#include "base/containers/fixed_flat_map.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
@@ -28,11 +28,11 @@ namespace ui {
namespace {
// clang-format off
-const base::flat_map<NativeTheme::ColorId, ColorId>&
-NativeThemeColorIdToColorIdMap() {
+bool NativeThemeColorIdToColorId(NativeTheme::ColorId native_theme_color_id,
+ ColorId* color_id) {
using NTCID = NativeTheme::ColorId;
- static const base::NoDestructor<base::flat_map<NativeTheme::ColorId, ColorId>>
- map({
+ static constexpr const auto map =
+ base::MakeFixedFlatMap<NativeTheme::ColorId, ColorId>({
{NTCID::kColorId_AlertSeverityHigh, kColorAlertHighSeverity},
{NTCID::kColorId_AlertSeverityLow, kColorAlertLowSeverity},
{NTCID::kColorId_AlertSeverityMedium, kColorAlertMediumSeverity},
@@ -150,7 +150,13 @@ NativeThemeColorIdToColorIdMap() {
kColorTreeNodeForegroundSelectedUnfocused},
{NTCID::kColorId_WindowBackground, kColorWindowBackground},
});
- return *map;
+ DCHECK(color_id);
+ auto* color_it = map.find(native_theme_color_id);
+ if (color_it != map.cend()) {
+ *color_id = color_it->second;
+ return true;
+ }
+ return false;
}
// clang-format on
@@ -191,11 +197,10 @@ SkColor NativeTheme::GetSystemColor(ColorId color_id,
// TODO(http://crbug.com/1057754): Handle high contrast modes.
auto* color_provider = ColorProviderManager::Get().GetColorProviderFor(
color_mode, ColorProviderManager::ContrastMode::kNormal);
- auto color_id_map = NativeThemeColorIdToColorIdMap();
- auto result = color_id_map.find(color_id);
- if (result != color_id_map.cend()) {
+ ui::ColorId provider_color_id;
+ if (NativeThemeColorIdToColorId(color_id, &provider_color_id)) {
ReportHistogramBooleanUsesColorProvider(true);
- return color_provider->GetColor(result->second);
+ return color_provider->GetColor(provider_color_id);
}
}
ReportHistogramBooleanUsesColorProvider(false);
@@ -212,8 +217,7 @@ SkColor NativeTheme::FocusRingColorForBaseColor(SkColor base_color) const {
float NativeTheme::GetBorderRadiusForPart(Part part,
float width,
- float height,
- float zoom) const {
+ float height) const {
return 0;
}
@@ -232,7 +236,7 @@ void NativeTheme::NotifyObservers() {
NativeTheme::NativeTheme(bool should_use_dark_colors)
: should_use_dark_colors_(should_use_dark_colors || IsForcedDarkMode()),
- is_high_contrast_(IsForcedHighContrast()),
+ forced_colors_(IsForcedHighContrast()),
preferred_color_scheme_(CalculatePreferredColorScheme()),
preferred_contrast_(CalculatePreferredContrast()) {
#if !defined(OS_ANDROID)
@@ -260,8 +264,14 @@ bool NativeTheme::ShouldUseDarkColors() const {
return should_use_dark_colors_;
}
-bool NativeTheme::UsesHighContrastColors() const {
- return is_high_contrast_;
+bool NativeTheme::UserHasContrastPreference() const {
+ return GetPreferredContrast() !=
+ NativeTheme::PreferredContrast::kNoPreference ||
+ InForcedColorsMode();
+}
+
+bool NativeTheme::InForcedColorsMode() const {
+ return forced_colors_;
}
NativeTheme::PlatformHighContrastColorScheme
@@ -336,16 +346,16 @@ void NativeTheme::set_system_colors(
bool NativeTheme::UpdateSystemColorInfo(
bool is_dark_mode,
- bool is_high_contrast,
+ bool forced_colors,
const base::flat_map<SystemThemeColor, uint32_t>& colors) {
bool did_system_color_info_change = false;
if (is_dark_mode != ShouldUseDarkColors()) {
did_system_color_info_change = true;
set_use_dark_colors(is_dark_mode);
}
- if (is_high_contrast != UsesHighContrastColors()) {
+ if (forced_colors != InForcedColorsMode()) {
did_system_color_info_change = true;
- set_high_contrast(is_high_contrast);
+ set_forced_colors(forced_colors);
}
for (const auto& color : colors) {
if (color.second != GetSystemThemeColor(color.first)) {
@@ -366,7 +376,7 @@ NativeTheme::ColorSchemeNativeThemeObserver::~ColorSchemeNativeThemeObserver() =
void NativeTheme::ColorSchemeNativeThemeObserver::OnNativeThemeUpdated(
ui::NativeTheme* observed_theme) {
bool should_use_dark_colors = observed_theme->ShouldUseDarkColors();
- bool is_high_contrast = observed_theme->UsesHighContrastColors();
+ bool forced_colors = observed_theme->InForcedColorsMode();
PreferredColorScheme preferred_color_scheme =
observed_theme->GetPreferredColorScheme();
PreferredContrast preferred_contrast = observed_theme->GetPreferredContrast();
@@ -376,8 +386,8 @@ void NativeTheme::ColorSchemeNativeThemeObserver::OnNativeThemeUpdated(
theme_to_update_->set_use_dark_colors(should_use_dark_colors);
notify_observers = true;
}
- if (theme_to_update_->UsesHighContrastColors() != is_high_contrast) {
- theme_to_update_->set_high_contrast(is_high_contrast);
+ if (theme_to_update_->InForcedColorsMode() != forced_colors) {
+ theme_to_update_->set_forced_colors(forced_colors);
notify_observers = true;
}
if (theme_to_update_->GetPreferredColorScheme() != preferred_color_scheme) {
diff --git a/chromium/ui/native_theme/native_theme.h b/chromium/ui/native_theme/native_theme.h
index 726f588a682..3577f9b8fa7 100644
--- a/chromium/ui/native_theme/native_theme.h
+++ b/chromium/ui/native_theme/native_theme.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/observer_list.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "cc/paint/paint_canvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/models/menu_separator_types.h"
@@ -51,7 +52,9 @@ class NATIVE_THEME_EXPORT NativeTheme {
// The part to be painted / sized.
enum Part {
kCheckbox,
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
kFrameTopArea,
#endif
kInnerSpinButton,
@@ -169,7 +172,6 @@ class NATIVE_THEME_EXPORT NativeTheme {
// Distinguishes between active (foreground) and inactive
// (background) window frame styles.
bool is_active;
- bool incognito;
// True when Chromium renders the titlebar. False when the window
// manager renders the titlebar.
bool use_custom_frame;
@@ -217,6 +219,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
SkColor arrow_color;
SkColor background_color;
int classic_state; // Used on Windows when uxtheme is not available.
+ float zoom;
};
struct MenuBackgroundExtraParams {
@@ -230,6 +233,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
int value_rect_y;
int value_rect_width;
int value_rect_height;
+ float zoom;
};
struct ScrollbarArrowExtraParams {
@@ -296,6 +300,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
int classic_state; // Used on Windows when uxtheme is not available.
bool has_border;
bool auto_complete_active;
+ float zoom;
};
struct TrackbarExtraParams {
@@ -335,8 +340,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
virtual float GetBorderRadiusForPart(Part part,
float width,
- float height,
- float zoom) const;
+ float height) const;
// Paint the part to the canvas.
virtual void Paint(
@@ -422,11 +426,16 @@ class NATIVE_THEME_EXPORT NativeTheme {
void RemoveObserver(NativeThemeObserver* observer);
// Notify observers of native theme changes.
- void NotifyObservers();
+ virtual void NotifyObservers();
- // Returns whether this NativeTheme uses higher-contrast colors, controlled by
- // system accessibility settings and the system theme.
- virtual bool UsesHighContrastColors() const;
+ // Returns whether the user has an explicit contrast preference, i.e. whether
+ // we are in forced colors mode or PreferredContrast is set.
+ virtual bool UserHasContrastPreference() const;
+
+ // Returns whether we are in forced colors mode, controlled by system
+ // accessibility settings. Currently, Windows high contrast is the only system
+ // setting that triggers forced colors mode.
+ virtual bool InForcedColorsMode() const;
// Returns the PlatformHighContrastColorScheme used by the OS. Returns a value
// other than kNone only if the default system color scheme is
@@ -462,9 +471,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
void set_use_dark_colors(bool should_use_dark_colors) {
should_use_dark_colors_ = should_use_dark_colors;
}
- void set_high_contrast(bool is_high_contrast) {
- is_high_contrast_ = is_high_contrast;
- }
+ void set_forced_colors(bool forced_colors) { forced_colors_ = forced_colors; }
void set_preferred_color_scheme(PreferredColorScheme preferred_color_scheme) {
preferred_color_scheme_ = preferred_color_scheme;
}
@@ -473,12 +480,12 @@ class NATIVE_THEME_EXPORT NativeTheme {
}
void set_system_colors(const std::map<SystemThemeColor, SkColor>& colors);
- // Updates the state of dark mode, high contrast, and the map of system
+ // Updates the state of dark mode, forced colors mode, and the map of system
// colors. Returns true if NativeTheme was updated as a result, or false if
// the state of NativeTheme was untouched.
bool UpdateSystemColorInfo(
bool is_dark_mode,
- bool is_high_contrast,
+ bool forced_colors,
const base::flat_map<SystemThemeColor, uint32_t>& colors);
// On certain platforms, currently only Mac, there is a unique visual for
@@ -519,8 +526,8 @@ class NATIVE_THEME_EXPORT NativeTheme {
// Allows one native theme to observe changes in another. For example, the
// web native theme for Windows observes the corresponding ui native theme in
- // order to receive changes regarding the state of dark mode, high contrast,
- // preferred color scheme and preferred contrast.
+ // order to receive changes regarding the state of dark mode, forced colors
+ // mode, preferred color scheme and preferred contrast.
class NATIVE_THEME_EXPORT ColorSchemeNativeThemeObserver
: public NativeThemeObserver {
public:
@@ -544,7 +551,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
base::ObserverList<NativeThemeObserver>::Unchecked native_theme_observers_;
bool should_use_dark_colors_ = false;
- bool is_high_contrast_ = false;
+ bool forced_colors_ = false;
PreferredColorScheme preferred_color_scheme_ = PreferredColorScheme::kLight;
PreferredContrast preferred_contrast_ = PreferredContrast::kNoPreference;
diff --git a/chromium/ui/native_theme/native_theme_android.cc b/chromium/ui/native_theme/native_theme_android.cc
index 509c9d274ae..f1d7851b850 100644
--- a/chromium/ui/native_theme/native_theme_android.cc
+++ b/chromium/ui/native_theme/native_theme_android.cc
@@ -55,6 +55,95 @@ void NativeThemeAndroid::AdjustCheckboxRadioRectForPadding(SkRect* rect) const {
static_cast<int>(rect->bottom()) - 1);
}
+float NativeThemeAndroid::AdjustBorderWidthByZoom(float border_width,
+ float zoom_level) const {
+ return border_width * zoom_level;
+}
+
+SkColor NativeThemeAndroid::ControlsAccentColorForState(
+ State state,
+ ColorScheme color_scheme) const {
+ ControlColorId color_id;
+ if (state == kPressed) {
+ color_id = kPressedAccent;
+ } else if (state == kDisabled) {
+ color_id = kDisabledAccent;
+ } else {
+ color_id = kAccent;
+ }
+ return GetControlColor(color_id, color_scheme);
+}
+
+SkColor NativeThemeAndroid::ControlsSliderColorForState(
+ State state,
+ ColorScheme color_scheme) const {
+ ControlColorId color_id;
+ if (state == kPressed) {
+ color_id = kPressedSlider;
+ } else if (state == kDisabled) {
+ color_id = kDisabledSlider;
+ } else {
+ color_id = kSlider;
+ }
+ return GetControlColor(color_id, color_scheme);
+}
+
+SkColor NativeThemeAndroid::ControlsBorderColorForState(
+ State state,
+ ColorScheme color_scheme) const {
+ ControlColorId color_id;
+ if (state == kPressed) {
+ color_id = kPressedBorder;
+ } else if (state == kDisabled) {
+ color_id = kDisabledBorder;
+ } else {
+ color_id = kBorder;
+ }
+ return GetControlColor(color_id, color_scheme);
+}
+
+SkColor NativeThemeAndroid::ButtonBorderColorForState(
+ State state,
+ ColorScheme color_scheme) const {
+ ControlColorId color_id;
+ if (state == kPressed) {
+ color_id = kButtonPressedBorder;
+ } else if (state == kDisabled) {
+ color_id = kButtonDisabledBorder;
+ } else {
+ color_id = kButtonBorder;
+ }
+ return GetControlColor(color_id, color_scheme);
+}
+
+SkColor NativeThemeAndroid::ControlsFillColorForState(
+ State state,
+ ColorScheme color_scheme) const {
+ ControlColorId color_id;
+ if (state == kPressed) {
+ color_id = kPressedFill;
+ } else if (state == kDisabled) {
+ color_id = kDisabledFill;
+ } else {
+ color_id = kFill;
+ }
+ return GetControlColor(color_id, color_scheme);
+}
+
+SkColor NativeThemeAndroid::ButtonFillColorForState(
+ State state,
+ ColorScheme color_scheme) const {
+ ControlColorId color_id;
+ if (state == kPressed) {
+ color_id = kButtonPressedFill;
+ } else if (state == kDisabled) {
+ color_id = kButtonDisabledFill;
+ } else {
+ color_id = kButtonFill;
+ }
+ return GetControlColor(color_id, color_scheme);
+}
+
NativeThemeAndroid::NativeThemeAndroid() {
}
diff --git a/chromium/ui/native_theme/native_theme_android.h b/chromium/ui/native_theme/native_theme_android.h
index 6d5c3811a0f..7635f727fac 100644
--- a/chromium/ui/native_theme/native_theme_android.h
+++ b/chromium/ui/native_theme/native_theme_android.h
@@ -28,6 +28,22 @@ class NativeThemeAndroid : public NativeThemeBase {
// NativeThemeBase:
void AdjustCheckboxRadioRectForPadding(SkRect* rect) const override;
+ float AdjustBorderWidthByZoom(float border_width,
+ float zoom_level) const override;
+ // TODO(crbug.com/1165342): Refine hover state behavior on available pointing
+ // devices.
+ SkColor ControlsAccentColorForState(State state,
+ ColorScheme color_scheme) const override;
+ SkColor ControlsSliderColorForState(State state,
+ ColorScheme color_scheme) const override;
+ SkColor ButtonBorderColorForState(State state,
+ ColorScheme color_scheme) const override;
+ SkColor ButtonFillColorForState(State state,
+ ColorScheme color_scheme) const override;
+ SkColor ControlsBorderColorForState(State state,
+ ColorScheme color_scheme) const override;
+ SkColor ControlsFillColorForState(State state,
+ ColorScheme color_scheme) const override;
private:
NativeThemeAndroid();
diff --git a/chromium/ui/native_theme/native_theme_aura.cc b/chromium/ui/native_theme/native_theme_aura.cc
index fb2297a4021..ef8d9335ae6 100644
--- a/chromium/ui/native_theme/native_theme_aura.cc
+++ b/chromium/ui/native_theme/native_theme_aura.cc
@@ -76,7 +76,7 @@ NativeThemeAura::NativeThemeAura(bool use_overlay_scrollbars,
: NativeThemeBase(should_only_use_dark_colors),
use_overlay_scrollbars_(use_overlay_scrollbars) {
// We don't draw scrollbar buttons.
-#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
set_scrollbar_button_length(0);
#endif
@@ -332,7 +332,7 @@ void NativeThemeAura::PaintScrollbarThumb(cc::PaintCanvas* canvas,
else
thumb_rect.Inset(extra_padding, kThumbPadding);
- if (UsesHighContrastColors() && features::IsForcedColorsEnabled()) {
+ if (InForcedColorsMode() && features::IsForcedColorsEnabled()) {
thumb_alpha = 0xFF;
thumb_color = GetControlColor(color_id, color_scheme);
} else {
diff --git a/chromium/ui/native_theme/native_theme_base.cc b/chromium/ui/native_theme/native_theme_base.cc
index dc879e3b41f..28661db79e7 100644
--- a/chromium/ui/native_theme/native_theme_base.cc
+++ b/chromium/ui/native_theme/native_theme_base.cc
@@ -12,6 +12,7 @@
#include "base/notreached.h"
#include "base/numerics/ranges.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_shader.h"
#include "third_party/skia/include/core/SkPath.h"
@@ -211,8 +212,7 @@ gfx::Size NativeThemeBase::GetPartSize(Part part,
float NativeThemeBase::GetBorderRadiusForPart(Part part,
float width,
- float height,
- float zoom) const {
+ float height) const {
if (!features::IsFormControlsRefreshEnabled()) {
NOTREACHED() << "GetBorderRadiusForPart only supports FormControlsRefresh.";
return 0;
@@ -220,7 +220,7 @@ float NativeThemeBase::GetBorderRadiusForPart(Part part,
switch (part) {
case kCheckbox:
- return 2.f * zoom;
+ return 2.f;
case kPushButton:
case kTextField:
return 2.f;
@@ -255,7 +255,9 @@ void NativeThemeBase::Paint(cc::PaintCanvas* canvas,
case kCheckbox:
PaintCheckbox(canvas, state, rect, extra.button, color_scheme);
break;
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
case kFrameTopArea:
PaintFrameTopArea(canvas, state, rect, extra.frame_top_area,
color_scheme);
@@ -600,8 +602,8 @@ void NativeThemeBase::PaintCheckbox(cc::PaintCanvas* canvas,
const ButtonExtraParams& button,
ColorScheme color_scheme) const {
if (features::IsFormControlsRefreshEnabled()) {
- const float border_radius = GetBorderRadiusForPart(
- kCheckbox, rect.width(), rect.height(), button.zoom);
+ const float border_radius =
+ GetBorderRadiusForPart(kCheckbox, rect.width(), rect.height());
SkRect skrect = PaintCheckboxRadioCommon(canvas, state, rect, button, true,
border_radius, color_scheme);
@@ -837,8 +839,8 @@ void NativeThemeBase::PaintRadio(cc::PaintCanvas* canvas,
if (features::IsFormControlsRefreshEnabled()) {
// Most of a radio button is the same as a checkbox, except the the rounded
// square is a circle (i.e. border radius >= 100%).
- const float border_radius = GetBorderRadiusForPart(
- kRadio, rect.width(), rect.height(), button.zoom);
+ const float border_radius =
+ GetBorderRadiusForPart(kRadio, rect.width(), rect.height());
SkRect skrect = PaintCheckboxRadioCommon(canvas, state, rect, button, false,
border_radius, color_scheme);
if (!skrect.isEmpty() && button.checked) {
@@ -885,6 +887,7 @@ void NativeThemeBase::PaintButton(cc::PaintCanvas* canvas,
if (features::IsFormControlsRefreshEnabled()) {
cc::PaintFlags flags;
SkRect skrect = gfx::RectToSkRect(rect);
+ float border_width = AdjustBorderWidthByZoom(kBorderWidth, button.zoom);
flags.setAntiAlias(true);
flags.setStyle(cc::PaintFlags::kFill_Style);
@@ -896,10 +899,10 @@ void NativeThemeBase::PaintButton(cc::PaintCanvas* canvas,
return;
}
- float border_radius = GetBorderRadiusForPart(kPushButton, rect.width(),
- rect.height(), button.zoom);
+ float border_radius =
+ GetBorderRadiusForPart(kPushButton, rect.width(), rect.height());
// Paint the background (is not visible behind the rounded corners).
- skrect.inset(kBorderWidth / 2, kBorderWidth / 2);
+ skrect.inset(border_width / 2, border_width / 2);
PaintLightenLayer(canvas, skrect, state, border_radius, color_scheme);
flags.setColor(ButtonFillColorForState(state, color_scheme));
canvas->drawRoundRect(skrect, border_radius, border_radius, flags);
@@ -907,7 +910,7 @@ void NativeThemeBase::PaintButton(cc::PaintCanvas* canvas,
// Paint the border: 1px solid.
if (button.has_border) {
flags.setStyle(cc::PaintFlags::kStroke_Style);
- flags.setStrokeWidth(kBorderWidth);
+ flags.setStrokeWidth(border_width);
flags.setColor(ButtonBorderColorForState(state, color_scheme));
canvas->drawRoundRect(skrect, border_radius, border_radius, flags);
}
@@ -970,11 +973,12 @@ void NativeThemeBase::PaintTextField(cc::PaintCanvas* canvas,
ColorScheme color_scheme) const {
if (features::IsFormControlsRefreshEnabled()) {
SkRect bounds = gfx::RectToSkRect(rect);
- const SkScalar border_radius = GetBorderRadiusForPart(
- kTextField, rect.width(), rect.height(), /*zoom level=*/1);
+ const SkScalar border_radius =
+ GetBorderRadiusForPart(kTextField, rect.width(), rect.height());
+ float border_width = AdjustBorderWidthByZoom(kBorderWidth, text.zoom);
// Paint the background (is not visible behind the rounded corners).
- bounds.inset(kBorderWidth / 2, kBorderWidth / 2);
+ bounds.inset(border_width / 2, border_width / 2);
cc::PaintFlags fill_flags;
fill_flags.setStyle(cc::PaintFlags::kFill_Style);
if (text.background_color != 0) {
@@ -994,7 +998,7 @@ void NativeThemeBase::PaintTextField(cc::PaintCanvas* canvas,
cc::PaintFlags stroke_flags;
stroke_flags.setColor(ControlsBorderColorForState(state, color_scheme));
stroke_flags.setStyle(cc::PaintFlags::kStroke_Style);
- stroke_flags.setStrokeWidth(kBorderWidth);
+ stroke_flags.setStrokeWidth(border_width);
canvas->drawRoundRect(bounds, border_radius, border_radius, stroke_flags);
}
@@ -1031,6 +1035,7 @@ void NativeThemeBase::PaintMenuList(cc::PaintCanvas* canvas,
TextFieldExtraParams text_field = {0};
text_field.background_color = menu_list.background_color;
text_field.has_border = menu_list.has_border;
+ text_field.zoom = menu_list.zoom;
PaintTextField(canvas, state, rect, text_field, color_scheme);
}
@@ -1146,14 +1151,15 @@ void NativeThemeBase::PaintSliderTrack(cc::PaintCanvas* canvas,
flags.setColor(ControlsFillColorForState(state, color_scheme));
const float track_height = kSliderTrackHeight * slider.zoom;
SkRect track_rect = AlignSliderTrack(rect, slider, false, track_height);
+ float border_width = AdjustBorderWidthByZoom(kBorderWidth, slider.zoom);
// Shrink the track by 1 pixel so the thumb can completely cover the track
// on both ends.
if (slider.vertical)
track_rect.inset(0, 1);
else
track_rect.inset(1, 0);
- float border_radius = GetBorderRadiusForPart(kSliderTrack, rect.width(),
- rect.height(), slider.zoom);
+ float border_radius =
+ GetBorderRadiusForPart(kSliderTrack, rect.width(), rect.height());
canvas->drawRoundRect(track_rect, border_radius, border_radius, flags);
// Clip the track to create rounded corners for the value bar.
@@ -1168,13 +1174,13 @@ void NativeThemeBase::PaintSliderTrack(cc::PaintCanvas* canvas,
// Paint the border.
flags.setStyle(cc::PaintFlags::kStroke_Style);
- flags.setStrokeWidth(kBorderWidth);
+ flags.setStrokeWidth(border_width);
SkColor border_color = ControlsBorderColorForState(state, color_scheme);
- if (!UsesHighContrastColors() && state != kDisabled &&
+ if (!UserHasContrastPreference() && state != kDisabled &&
color_scheme != ColorScheme::kDark)
border_color = SkColorSetA(border_color, 0x80);
flags.setColor(border_color);
- track_rect.inset(kBorderWidth / 2, kBorderWidth / 2);
+ track_rect.inset(border_width / 2, border_width / 2);
canvas->drawRoundRect(track_rect, border_radius, border_radius, flags);
return;
}
@@ -1202,8 +1208,8 @@ void NativeThemeBase::PaintSliderThumb(cc::PaintCanvas* canvas,
const SliderExtraParams& slider,
ColorScheme color_scheme) const {
if (features::IsFormControlsRefreshEnabled()) {
- const float radius = GetBorderRadiusForPart(kSliderThumb, rect.width(),
- rect.height(), slider.zoom);
+ const float radius =
+ GetBorderRadiusForPart(kSliderThumb, rect.width(), rect.height());
SkRect thumb_rect = gfx::RectToSkRect(rect);
cc::PaintFlags flags;
@@ -1305,8 +1311,8 @@ void NativeThemeBase::PaintProgressBar(
slider.vertical = false;
float track_height = rect.height() * kTrackHeightRatio;
SkRect track_rect = AlignSliderTrack(rect, slider, false, track_height);
- float border_radius = GetBorderRadiusForPart(
- kProgressBar, rect.width(), rect.height(), /*zoom level=*/1);
+ float border_radius =
+ GetBorderRadiusForPart(kProgressBar, rect.width(), rect.height());
canvas->drawRoundRect(track_rect, border_radius, border_radius, flags);
// Clip the track to create rounded corners for the value bar.
@@ -1332,13 +1338,15 @@ void NativeThemeBase::PaintProgressBar(
}
// Paint the border.
+ float border_width =
+ AdjustBorderWidthByZoom(kBorderWidth, progress_bar.zoom);
flags.setStyle(cc::PaintFlags::kStroke_Style);
- flags.setStrokeWidth(kBorderWidth);
+ flags.setStrokeWidth(border_width);
SkColor border_color = GetControlColor(kBorder, color_scheme);
- if (!UsesHighContrastColors() && color_scheme != ColorScheme::kDark)
+ if (!UserHasContrastPreference() && color_scheme != ColorScheme::kDark)
border_color = SkColorSetA(border_color, 0x80);
flags.setColor(border_color);
- track_rect.inset(kBorderWidth / 2, kBorderWidth / 2);
+ track_rect.inset(border_width / 2, border_width / 2);
canvas->drawRoundRect(track_rect, border_radius, border_radius, flags);
return;
}
@@ -1398,6 +1406,11 @@ void NativeThemeBase::AdjustCheckboxRadioRectForPadding(SkRect* rect) const {
static_cast<int>(rect->bottom()) - 1);
}
+float NativeThemeBase::AdjustBorderWidthByZoom(float border_width,
+ float) const {
+ return border_width;
+}
+
SkColor NativeThemeBase::SaturateAndBrighten(SkScalar* hsv,
SkScalar saturate_amount,
SkScalar brighten_amount) const {
@@ -1604,10 +1617,8 @@ SkColor NativeThemeBase::ControlsBackgroundColorForState(
SkColor NativeThemeBase::GetControlColor(ControlColorId color_id,
ColorScheme color_scheme) const {
-#if defined(OS_WIN)
- if (UsesHighContrastColors() && features::IsForcedColorsEnabled())
+ if (InForcedColorsMode() && features::IsForcedColorsEnabled())
return GetHighContrastControlColor(color_id, color_scheme);
-#endif
if(color_scheme == ColorScheme::kDark)
return GetDarkModeControlColor(color_id);
diff --git a/chromium/ui/native_theme/native_theme_base.h b/chromium/ui/native_theme/native_theme_base.h
index c4e206b76e6..bb16add6804 100644
--- a/chromium/ui/native_theme/native_theme_base.h
+++ b/chromium/ui/native_theme/native_theme_base.h
@@ -29,8 +29,7 @@ class NATIVE_THEME_EXPORT NativeThemeBase : public NativeTheme {
const ExtraParams& extra) const override;
float GetBorderRadiusForPart(Part part,
float width,
- float height,
- float zoom) const override;
+ float height) const override;
void Paint(cc::PaintCanvas* canvas,
Part part,
State state,
@@ -215,6 +214,9 @@ class NATIVE_THEME_EXPORT NativeThemeBase : public NativeTheme {
// crbug.com/530746 is resolved.
virtual void AdjustCheckboxRadioRectForPadding(SkRect* rect) const;
+ virtual float AdjustBorderWidthByZoom(float border_width,
+ float zoom_level) const;
+
void set_scrollbar_button_length(int length) {
scrollbar_button_length_ = length;
}
@@ -234,6 +236,18 @@ class NATIVE_THEME_EXPORT NativeThemeBase : public NativeTheme {
SkColor GetArrowColor(State state, ColorScheme color_scheme) const;
SkColor GetControlColor(ControlColorId color_id,
ColorScheme color_scheme) const;
+ virtual SkColor ControlsAccentColorForState(State state,
+ ColorScheme color_scheme) const;
+ virtual SkColor ControlsSliderColorForState(State state,
+ ColorScheme color_scheme) const;
+ virtual SkColor ButtonBorderColorForState(State state,
+ ColorScheme color_scheme) const;
+ virtual SkColor ButtonFillColorForState(State state,
+ ColorScheme color_scheme) const;
+ virtual SkColor ControlsBorderColorForState(State state,
+ ColorScheme color_scheme) const;
+ virtual SkColor ControlsFillColorForState(State state,
+ ColorScheme color_scheme) const;
int scrollbar_width_ = 15;
@@ -268,19 +282,8 @@ class NATIVE_THEME_EXPORT NativeThemeBase : public NativeTheme {
const SkScalar border_radius,
ColorScheme color_scheme) const;
- SkColor ButtonBorderColorForState(State state,
- ColorScheme color_scheme) const;
- SkColor ButtonFillColorForState(State state, ColorScheme color_scheme) const;
- SkColor ControlsAccentColorForState(State state,
- ColorScheme color_scheme) const;
- SkColor ControlsBorderColorForState(State state,
- ColorScheme color_scheme) const;
- SkColor ControlsFillColorForState(State state,
- ColorScheme color_scheme) const;
SkColor ControlsBackgroundColorForState(State state,
ColorScheme color_scheme) const;
- SkColor ControlsSliderColorForState(State state,
- ColorScheme color_scheme) const;
SkColor GetHighContrastControlColor(ControlColorId color_id,
ColorScheme color_scheme) const;
SkColor GetDarkModeControlColor(ControlColorId color_id) const;
diff --git a/chromium/ui/native_theme/native_theme_color_id.h b/chromium/ui/native_theme/native_theme_color_id.h
index 52ac7e6b292..d08b6a27c03 100644
--- a/chromium/ui/native_theme/native_theme_color_id.h
+++ b/chromium/ui/native_theme/native_theme_color_id.h
@@ -5,6 +5,8 @@
#ifndef UI_NATIVE_THEME_NATIVE_THEME_COLOR_ID_H_
#define UI_NATIVE_THEME_NATIVE_THEME_COLOR_ID_H_
+#include "build/chromeos_buildflags.h"
+
// Clang format mangles sectioned lists like the below badly.
// clang-format off
#define NATIVE_THEME_CROSS_PLATFORM_COLOR_IDS \
@@ -165,13 +167,13 @@
OP(kColorId_DefaultIconColor), \
OP(kColorId_DisabledIconColor)
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#define NATIVE_THEME_CHROMEOS_COLOR_IDS \
/* Notification view */ \
OP(kColorId_NotificationButtonBackground)
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#define NATIVE_THEME_COLOR_IDS \
NATIVE_THEME_CROSS_PLATFORM_COLOR_IDS, \
NATIVE_THEME_CHROMEOS_COLOR_IDS
diff --git a/chromium/ui/native_theme/native_theme_features.cc b/chromium/ui/native_theme/native_theme_features.cc
index 09575183833..8bd081919bd 100644
--- a/chromium/ui/native_theme/native_theme_features.cc
+++ b/chromium/ui/native_theme/native_theme_features.cc
@@ -9,8 +9,8 @@
namespace features {
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA) || \
- BUILDFLAG(IS_LACROS)
+#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || \
+ defined(OS_FUCHSIA) || BUILDFLAG(IS_CHROMEOS_LACROS)
constexpr base::FeatureState kOverlayScrollbarFeatureState =
base::FEATURE_ENABLED_BY_DEFAULT;
#else
@@ -24,10 +24,6 @@ constexpr base::FeatureState kOverlayScrollbarFeatureState =
const base::Feature kOverlayScrollbar{"OverlayScrollbar",
kOverlayScrollbarFeatureState};
-// Enables will flash all scrollbars in page after any scroll update.
-const base::Feature kOverlayScrollbarFlashAfterAnyScrollUpdate{
- "OverlayScrollbarFlashAfterAnyScrollUpdate", kOverlayScrollbarFeatureState};
-
} // namespace features
namespace ui {
@@ -36,9 +32,4 @@ bool IsOverlayScrollbarEnabled() {
return base::FeatureList::IsEnabled(features::kOverlayScrollbar);
}
-bool OverlayScrollbarFlashAfterAnyScrollUpdate() {
- return base::FeatureList::IsEnabled(
- features::kOverlayScrollbarFlashAfterAnyScrollUpdate);
-}
-
} // namespace ui
diff --git a/chromium/ui/native_theme/native_theme_features.h b/chromium/ui/native_theme/native_theme_features.h
index 218dfd6f7d2..85e898574c2 100644
--- a/chromium/ui/native_theme/native_theme_features.h
+++ b/chromium/ui/native_theme/native_theme_features.h
@@ -13,16 +13,12 @@
namespace features {
NATIVE_THEME_EXPORT extern const base::Feature kOverlayScrollbar;
-NATIVE_THEME_EXPORT extern const base::Feature
- kOverlayScrollbarFlashAfterAnyScrollUpdate;
} // namespace features
namespace ui {
NATIVE_THEME_EXPORT bool IsOverlayScrollbarEnabled();
-NATIVE_THEME_EXPORT bool OverlayScrollbarFlashAfterAnyScrollUpdate();
-NATIVE_THEME_EXPORT bool OverlayScrollbarFlashWhenMouseEnter();
} // namespace ui
diff --git a/chromium/ui/native_theme/native_theme_mac.mm b/chromium/ui/native_theme/native_theme_mac.mm
index 58226be7e1f..59727173741 100644
--- a/chromium/ui/native_theme/native_theme_mac.mm
+++ b/chromium/ui/native_theme/native_theme_mac.mm
@@ -171,7 +171,7 @@ SkColor NativeThemeMac::GetSystemColor(ColorId color_id,
color_scheme != ColorScheme::kPlatformHighContrast))
return NativeTheme::GetSystemColor(color_id, color_scheme);
- if (UsesHighContrastColors()) {
+ if (UserHasContrastPreference()) {
switch (color_id) {
case kColorId_SelectedMenuItemForegroundColor:
return color_scheme == ColorScheme::kDark ? SK_ColorBLACK
@@ -241,9 +241,8 @@ base::Optional<SkColor> NativeThemeMac::GetOSColor(
NativeThemeAura::PreferredContrast NativeThemeMac::CalculatePreferredContrast()
const {
- return UsesHighContrastColors()
- ? NativeThemeAura::PreferredContrast::kMore
- : NativeThemeAura::PreferredContrast::kNoPreference;
+ return IsHighContrast() ? NativeThemeAura::PreferredContrast::kMore
+ : NativeThemeAura::PreferredContrast::kNoPreference;
}
void NativeThemeMac::Paint(cc::PaintCanvas* canvas,
@@ -588,7 +587,7 @@ NativeThemeMac::NativeThemeMac(bool configure_web_instance,
InitializeDarkModeStateAndObserver();
if (!IsForcedHighContrast()) {
- set_high_contrast(IsHighContrast());
+ set_preferred_contrast(CalculatePreferredContrast());
__block auto theme = this;
high_contrast_notification_token_ =
[[[NSWorkspace sharedWorkspace] notificationCenter]
@@ -597,7 +596,6 @@ NativeThemeMac::NativeThemeMac(bool configure_web_instance,
object:nil
queue:nil
usingBlock:^(NSNotification* notification) {
- theme->set_high_contrast(IsHighContrast());
theme->set_preferred_contrast(
CalculatePreferredContrast());
theme->NotifyObservers();
@@ -645,10 +643,9 @@ void NativeThemeMac::ConfigureWebInstance() {
web_instance->set_use_dark_colors(IsDarkMode());
web_instance->set_preferred_color_scheme(CalculatePreferredColorScheme());
web_instance->set_preferred_contrast(CalculatePreferredContrast());
- web_instance->set_high_contrast(IsHighContrast());
- // Add the web native theme as an observer to stay in sync with dark mode,
- // high contrast, and preferred color scheme changes.
+ // Add the web native theme as an observer to stay in sync with color scheme
+ // changes.
color_scheme_observer_ =
std::make_unique<NativeTheme::ColorSchemeNativeThemeObserver>(
NativeTheme::GetInstanceForWeb());
diff --git a/chromium/ui/native_theme/native_theme_mac_unittest.mm b/chromium/ui/native_theme/native_theme_mac_unittest.mm
index 6ad349e4809..de75e9dd52b 100644
--- a/chromium/ui/native_theme/native_theme_mac_unittest.mm
+++ b/chromium/ui/native_theme/native_theme_mac_unittest.mm
@@ -34,6 +34,7 @@ TEST(NativeThemeMacTest, SystemColorsExist) {
TEST(NativeThemeMacTest, GetPlatformHighContrastColorScheme) {
using PrefScheme = NativeTheme::PreferredColorScheme;
+ using PrefContrast = NativeTheme::PreferredContrast;
constexpr NativeTheme::PlatformHighContrastColorScheme kNone =
NativeTheme::PlatformHighContrastColorScheme::kNone;
@@ -41,35 +42,25 @@ TEST(NativeThemeMacTest, GetPlatformHighContrastColorScheme) {
NativeTheme* native_theme = NativeTheme::GetInstanceForNativeUi();
ASSERT_TRUE(native_theme);
- native_theme->set_high_contrast(false);
+ native_theme->set_forced_colors(false);
+ native_theme->set_preferred_contrast(PrefContrast::kNoPreference);
native_theme->set_preferred_color_scheme(PrefScheme::kDark);
EXPECT_EQ(native_theme->GetPlatformHighContrastColorScheme(), kNone);
native_theme->set_preferred_color_scheme(PrefScheme::kLight);
EXPECT_EQ(native_theme->GetPlatformHighContrastColorScheme(), kNone);
- native_theme->set_high_contrast(true);
+ native_theme->set_forced_colors(true);
+ native_theme->set_preferred_contrast(PrefContrast::kMore);
native_theme->set_preferred_color_scheme(PrefScheme::kDark);
EXPECT_EQ(native_theme->GetPlatformHighContrastColorScheme(), kNone);
native_theme->set_preferred_color_scheme(PrefScheme::kLight);
EXPECT_EQ(native_theme->GetPlatformHighContrastColorScheme(), kNone);
- native_theme->set_high_contrast(false);
+ native_theme->set_forced_colors(false);
+ native_theme->set_preferred_contrast(PrefContrast::kNoPreference);
EXPECT_EQ(native_theme->GetPlatformHighContrastColorScheme(), kNone);
}
-TEST(NativeThemeMacTest, GetPreferredContrast) {
- using PrefContrast = NativeTheme::PreferredContrast;
-
- TestNativeThemeMac native_theme;
-
- native_theme.set_high_contrast(false);
- EXPECT_EQ(native_theme.CalculatePreferredContrast(),
- PrefContrast::kNoPreference);
-
- native_theme.set_high_contrast(true);
- EXPECT_EQ(native_theme.CalculatePreferredContrast(), PrefContrast::kMore);
-}
-
} // namespace ui
diff --git a/chromium/ui/native_theme/native_theme_win.cc b/chromium/ui/native_theme/native_theme_win.cc
index c45c48d9de7..4d0ed521015 100644
--- a/chromium/ui/native_theme/native_theme_win.cc
+++ b/chromium/ui/native_theme/native_theme_win.cc
@@ -81,7 +81,7 @@ void SetCheckerboardShader(SkPaint* paint, const RECT& align_rect) {
local_matrix.setTranslate(SkIntToScalar(align_rect.left),
SkIntToScalar(align_rect.top));
paint->setShader(bitmap.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
- &local_matrix));
+ SkSamplingOptions(), &local_matrix));
}
// <-a->
@@ -289,7 +289,7 @@ NativeThemeWin::NativeThemeWin(bool configure_web_instance,
}
}
if (!IsForcedHighContrast()) {
- set_high_contrast(IsUsingHighContrastThemeInternal());
+ set_forced_colors(IsUsingHighContrastThemeInternal());
}
// Initialize the cached system colors.
UpdateSystemColors();
@@ -305,8 +305,8 @@ NativeThemeWin::NativeThemeWin(bool configure_web_instance,
void NativeThemeWin::ConfigureWebInstance() {
if (!IsForcedDarkMode() && !IsForcedHighContrast() &&
base::SequencedTaskRunnerHandle::IsSet()) {
- // Add the web native theme as an observer to stay in sync with dark mode,
- // high contrast, and preferred color scheme changes.
+ // Add the web native theme as an observer to stay in sync with color scheme
+ // changes.
color_scheme_observer_ =
std::make_unique<NativeTheme::ColorSchemeNativeThemeObserver>(
NativeTheme::GetInstanceForWeb());
@@ -316,7 +316,7 @@ void NativeThemeWin::ConfigureWebInstance() {
// Initialize the native theme web instance with the system color info.
NativeTheme* web_instance = NativeTheme::GetInstanceForWeb();
web_instance->set_use_dark_colors(ShouldUseDarkColors());
- web_instance->set_high_contrast(UsesHighContrastColors());
+ web_instance->set_forced_colors(InForcedColorsMode());
web_instance->set_preferred_color_scheme(GetPreferredColorScheme());
web_instance->set_preferred_contrast(GetPreferredContrast());
web_instance->set_system_colors(GetSystemColors());
@@ -347,7 +347,7 @@ void NativeThemeWin::CloseHandlesInternal() {
void NativeThemeWin::OnSysColorChange() {
UpdateSystemColors();
if (!IsForcedHighContrast())
- set_high_contrast(IsUsingHighContrastThemeInternal());
+ set_forced_colors(IsUsingHighContrastThemeInternal());
set_preferred_color_scheme(CalculatePreferredColorScheme());
set_preferred_contrast(CalculatePreferredContrast());
NotifyObservers();
@@ -727,14 +727,14 @@ bool NativeThemeWin::ShouldUseDarkColors() const {
// Windows high contrast modes are entirely different themes,
// so let them take priority over dark mode.
// ...unless --force-dark-mode was specified in which case caveat emptor.
- if (UsesHighContrastColors() && !IsForcedDarkMode())
+ if (InForcedColorsMode() && !IsForcedDarkMode())
return false;
return NativeTheme::ShouldUseDarkColors();
}
NativeTheme::PreferredColorScheme
NativeThemeWin::CalculatePreferredColorScheme() const {
- if (!UsesHighContrastColors())
+ if (!InForcedColorsMode())
return NativeTheme::CalculatePreferredColorScheme();
// According to the spec, the preferred color scheme for web content is 'dark'
@@ -751,7 +751,7 @@ NativeThemeWin::CalculatePreferredColorScheme() const {
NativeTheme::PreferredContrast NativeThemeWin::CalculatePreferredContrast()
const {
- if (!UsesHighContrastColors())
+ if (!InForcedColorsMode())
return NativeTheme::CalculatePreferredContrast();
// According to the spec [1], "when the user agent can determine whether the
@@ -783,8 +783,8 @@ NativeTheme::PreferredContrast NativeThemeWin::CalculatePreferredContrast()
}
NativeTheme::ColorScheme NativeThemeWin::GetDefaultSystemColorScheme() const {
- return UsesHighContrastColors() ? ColorScheme::kPlatformHighContrast
- : NativeTheme::GetDefaultSystemColorScheme();
+ return InForcedColorsMode() ? ColorScheme::kPlatformHighContrast
+ : NativeTheme::GetDefaultSystemColorScheme();
}
void NativeThemeWin::PaintIndirect(cc::PaintCanvas* destination_canvas,
diff --git a/chromium/ui/native_theme/native_theme_win_unittest.cc b/chromium/ui/native_theme/native_theme_win_unittest.cc
index bcef984bd2d..27c3ce701b3 100644
--- a/chromium/ui/native_theme/native_theme_win_unittest.cc
+++ b/chromium/ui/native_theme/native_theme_win_unittest.cc
@@ -28,14 +28,14 @@ class TestNativeThemeWin : public NativeThemeWin {
TEST(NativeThemeWinTest, CalculatePreferredColorScheme) {
TestNativeThemeWin theme;
- theme.set_high_contrast(false);
+ theme.set_forced_colors(false);
theme.set_use_dark_colors(true);
EXPECT_EQ(theme.CalculatePreferredColorScheme(), PrefScheme::kDark);
theme.set_use_dark_colors(false);
EXPECT_EQ(theme.CalculatePreferredColorScheme(), PrefScheme::kLight);
- theme.set_high_contrast(true);
+ theme.set_forced_colors(true);
theme.SetSystemColor(SystemThemeColor::kWindow, SK_ColorBLACK);
EXPECT_EQ(theme.CalculatePreferredColorScheme(), PrefScheme::kDark);
@@ -48,7 +48,7 @@ TEST(NativeThemeWinTest, CalculatePreferredColorScheme) {
theme.SetSystemColor(SystemThemeColor::kWindow, SK_ColorYELLOW);
EXPECT_EQ(theme.CalculatePreferredColorScheme(), PrefScheme::kLight);
- theme.set_high_contrast(false);
+ theme.set_forced_colors(false);
EXPECT_EQ(theme.CalculatePreferredColorScheme(), PrefScheme::kLight);
}
@@ -57,10 +57,10 @@ TEST(NativeThemeWinTest, CalculatePreferredContrast) {
TestNativeThemeWin theme;
- theme.set_high_contrast(false);
+ theme.set_forced_colors(false);
EXPECT_EQ(theme.CalculatePreferredContrast(), PrefContrast::kNoPreference);
- theme.set_high_contrast(true);
+ theme.set_forced_colors(true);
theme.SetSystemColor(SystemThemeColor::kWindow, SK_ColorBLACK);
theme.SetSystemColor(SystemThemeColor::kWindowText, SK_ColorWHITE);
EXPECT_EQ(theme.CalculatePreferredContrast(), PrefContrast::kMore);
@@ -75,7 +75,7 @@ TEST(NativeThemeWinTest, CalculatePreferredContrast) {
theme.SetSystemColor(SystemThemeColor::kWindowText, SK_ColorYELLOW);
EXPECT_EQ(theme.CalculatePreferredContrast(), PrefContrast::kLess);
- theme.set_high_contrast(false);
+ theme.set_forced_colors(false);
EXPECT_EQ(theme.CalculatePreferredContrast(), PrefContrast::kNoPreference);
}
@@ -83,14 +83,14 @@ TEST(NativeThemeWinTest, GetDefaultSystemColorScheme) {
using ColorScheme = NativeTheme::ColorScheme;
TestNativeThemeWin theme;
- theme.set_high_contrast(false);
+ theme.set_forced_colors(false);
theme.set_use_dark_colors(true);
EXPECT_EQ(theme.GetDefaultSystemColorScheme(), ColorScheme::kDark);
theme.set_use_dark_colors(false);
EXPECT_EQ(theme.GetDefaultSystemColorScheme(), ColorScheme::kLight);
- theme.set_high_contrast(true);
+ theme.set_forced_colors(true);
theme.SetSystemColor(SystemThemeColor::kWindow, SK_ColorBLACK);
theme.SetSystemColor(SystemThemeColor::kWindowText, SK_ColorWHITE);
EXPECT_EQ(theme.GetDefaultSystemColorScheme(),
@@ -105,7 +105,7 @@ TEST(NativeThemeWinTest, GetDefaultSystemColorScheme) {
EXPECT_EQ(theme.GetDefaultSystemColorScheme(),
ColorScheme::kPlatformHighContrast);
- theme.set_high_contrast(false);
+ theme.set_forced_colors(false);
EXPECT_EQ(theme.GetDefaultSystemColorScheme(), ColorScheme::kLight);
}
@@ -123,7 +123,7 @@ TEST(NativeThemeWinTest, GetPlatformHighContrastColor) {
theme.SetSystemColor(SystemThemeColor::kHighlightText, kHighlightTextColor);
// Test that we get regular colors when HC is off.
- theme.set_high_contrast(false);
+ theme.set_forced_colors(false);
EXPECT_NE(theme.GetSystemColor(ColorId::kColorId_LabelEnabledColor),
kWindowTextColor);
EXPECT_NE(theme.GetSystemColor(ColorId::kColorId_ProminentButtonColor),
@@ -132,7 +132,7 @@ TEST(NativeThemeWinTest, GetPlatformHighContrastColor) {
kHighlightTextColor);
// Test that we get HC colors when HC is on.
- theme.set_high_contrast(true);
+ theme.set_forced_colors(true);
EXPECT_EQ(theme.GetSystemColor(ColorId::kColorId_LabelEnabledColor),
kWindowTextColor);
EXPECT_EQ(theme.GetSystemColor(ColorId::kColorId_ProminentButtonColor),
@@ -145,21 +145,21 @@ TEST(NativeThemeWinTest, GetPlatformHighContrastColorScheme) {
using HCColorScheme = NativeTheme::PlatformHighContrastColorScheme;
TestNativeThemeWin theme;
- theme.set_high_contrast(false);
+ theme.set_forced_colors(false);
theme.set_preferred_color_scheme(PrefScheme::kDark);
EXPECT_EQ(theme.GetPlatformHighContrastColorScheme(), HCColorScheme::kNone);
theme.set_preferred_color_scheme(PrefScheme::kLight);
EXPECT_EQ(theme.GetPlatformHighContrastColorScheme(), HCColorScheme::kNone);
- theme.set_high_contrast(true);
+ theme.set_forced_colors(true);
theme.set_preferred_color_scheme(PrefScheme::kDark);
EXPECT_EQ(theme.GetPlatformHighContrastColorScheme(), HCColorScheme::kDark);
theme.set_preferred_color_scheme(PrefScheme::kLight);
EXPECT_EQ(theme.GetPlatformHighContrastColorScheme(), HCColorScheme::kLight);
- theme.set_high_contrast(false);
+ theme.set_forced_colors(false);
EXPECT_EQ(theme.GetPlatformHighContrastColorScheme(), HCColorScheme::kNone);
}
diff --git a/chromium/ui/native_theme/test_native_theme.cc b/chromium/ui/native_theme/test_native_theme.cc
index 6a2524fd100..3abb74e3ca9 100644
--- a/chromium/ui/native_theme/test_native_theme.cc
+++ b/chromium/ui/native_theme/test_native_theme.cc
@@ -39,8 +39,8 @@ gfx::Rect TestNativeTheme::GetNinePatchAperture(Part part) const {
return gfx::Rect();
}
-bool TestNativeTheme::UsesHighContrastColors() const {
- return high_contrast_;
+bool TestNativeTheme::UserHasContrastPreference() const {
+ return contrast_preference_;
}
bool TestNativeTheme::ShouldUseDarkColors() const {
diff --git a/chromium/ui/native_theme/test_native_theme.h b/chromium/ui/native_theme/test_native_theme.h
index 91223678ba5..fb03c61aae8 100644
--- a/chromium/ui/native_theme/test_native_theme.h
+++ b/chromium/ui/native_theme/test_native_theme.h
@@ -30,14 +30,14 @@ class TestNativeTheme : public NativeTheme {
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 UserHasContrastPreference() const override;
bool ShouldUseDarkColors() const override;
PreferredColorScheme GetPreferredColorScheme() const override;
ColorScheme GetDefaultSystemColorScheme() const override;
void SetDarkMode(bool dark_mode) { dark_mode_ = dark_mode; }
- void SetUsesHighContrastColors(bool high_contrast) {
- high_contrast_ = high_contrast;
+ void SetUserHasContrastPreference(bool contrast_preference) {
+ contrast_preference_ = contrast_preference;
}
void SetIsPlatformHighContrast(bool is_platform_high_contrast) {
is_platform_high_contrast_ = is_platform_high_contrast;
@@ -46,7 +46,7 @@ class TestNativeTheme : public NativeTheme {
private:
bool dark_mode_ = false;
- bool high_contrast_ = false;
+ bool contrast_preference_ = false;
bool is_platform_high_contrast_ = false;
std::unique_ptr<NativeTheme::ColorSchemeNativeThemeObserver>
diff --git a/chromium/ui/ozone/BUILD.gn b/chromium/ui/ozone/BUILD.gn
index 8416fb1f493..e788273148e 100644
--- a/chromium/ui/ozone/BUILD.gn
+++ b/chromium/ui/ozone/BUILD.gn
@@ -90,6 +90,7 @@ component("ozone_base") {
"public/ozone_switches.cc",
"public/ozone_switches.h",
"public/platform_clipboard.h",
+ "public/platform_gl_egl_utility.cc",
"public/platform_gl_egl_utility.h",
"public/platform_menu_utils.cc",
"public/platform_menu_utils.h",
@@ -372,7 +373,7 @@ if (ozone_platform_x11) {
buildflag_header("buildflags") {
header = "buildflags.h"
flags = [ "OZONE_PLATFORM_X11=$ozone_platform_x11" ]
- visibility += [ "//ui/gl:gl" ]
+ visibility += [ "*" ]
}
group("unittests") {
diff --git a/chromium/ui/ozone/DIR_METADATA b/chromium/ui/ozone/DIR_METADATA
new file mode 100644
index 00000000000..826e2a2ae84
--- /dev/null
+++ b/chromium/ui/ozone/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+ component: "Internals>Ozone"
+}
+team_email: "ozone-dev@chromium.org"
diff --git a/chromium/ui/ozone/OWNERS b/chromium/ui/ozone/OWNERS
index 7288821d96e..ec43a6d2a5d 100644
--- a/chromium/ui/ozone/OWNERS
+++ b/chromium/ui/ozone/OWNERS
@@ -1,6 +1,3 @@
rjkroege@chromium.org
spang@chromium.org
alexst@chromium.org
-
-# TEAM: ozone-dev@chromium.org
-# COMPONENT: Internals>Ozone
diff --git a/chromium/ui/ozone/common/egl_util.cc b/chromium/ui/ozone/common/egl_util.cc
index 56e5ebb152a..d23a6014601 100644
--- a/chromium/ui/ozone/common/egl_util.cc
+++ b/chromium/ui/ozone/common/egl_util.cc
@@ -12,6 +12,10 @@
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_implementation.h"
+#if BUILDFLAG(USE_OPENGL_APITRACE)
+#include <stdlib.h>
+#endif
+
namespace ui {
namespace {
@@ -93,6 +97,48 @@ bool LoadEGLGLES2Bindings(const base::FilePath& egl_library_path,
}
gl::SetGLGetProcAddressProc(get_proc_address);
+
+#if BUILDFLAG(USE_OPENGL_APITRACE)
+ constexpr char kTraceLibegl[] = "TRACE_LIBEGL";
+ constexpr char kTraceLibglesv2[] = "TRACE_LIBGLESV2";
+ constexpr char kTraceFile[] = "TRACE_FILE";
+
+ if (egl_library_path.BaseName().value() != kDefaultEglSoname) {
+ LOG(ERROR) << "Unsupported EGL library '"
+ << egl_library_path.BaseName().value()
+ << "'. egltrace may not work.";
+ }
+ if (gles_library_path.BaseName().value() != kDefaultGlesSoname) {
+ LOG(ERROR) << "Unsupported GLESv2 library '"
+ << gles_library_path.BaseName().value()
+ << "'. egltrace may not work.";
+ }
+
+ // Send correct library names to egttrace.
+ setenv(kTraceLibegl, egl_library_path.BaseName().value().c_str(),
+ /*overwrite=*/0);
+ setenv(kTraceLibglesv2, gles_library_path.BaseName().value().c_str(),
+ /*overwrite=*/0);
+#if defined(OS_CHROMEOS)
+ setenv(kTraceFile, "/tmp/gltrace.dat", /*overwrite=*/0);
+#else
+ if (!getenv(kTraceFile)) {
+ LOG(ERROR) << "egltrace requires valid TRACE_FILE environment variable but "
+ "none were found. Chrome will probably crash.";
+ }
+#endif
+
+ LOG(WARNING) << "Loading egltrace.so with TRACE_LIBEGL="
+ << getenv(kTraceLibegl)
+ << " TRACE_LIBGLESV2=" << getenv(kTraceLibglesv2)
+ << " TRACE_FILE=" << getenv(kTraceFile);
+ const base::FilePath::CharType kDefaultTraceSoname[] =
+ FILE_PATH_LITERAL("egltrace.so");
+ base::NativeLibrary trace_library =
+ base::LoadNativeLibrary(base::FilePath(kDefaultTraceSoname), &error);
+ gl::AddGLNativeLibrary(trace_library);
+#endif
+
gl::AddGLNativeLibrary(egl_library);
gl::AddGLNativeLibrary(gles_library);
diff --git a/chromium/ui/ozone/common/features.cc b/chromium/ui/ozone/common/features.cc
index e8f6809760a..02f03c4dc14 100644
--- a/chromium/ui/ozone/common/features.cc
+++ b/chromium/ui/ozone/common/features.cc
@@ -10,7 +10,7 @@ namespace ui {
const base::Feature kWaylandOverlayDelegation {
"WaylandOverlayDelegation",
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/chromium/ui/ozone/common/gl_surface_egl_readback.cc b/chromium/ui/ozone/common/gl_surface_egl_readback.cc
index 128d4f02273..1345001111d 100644
--- a/chromium/ui/ozone/common/gl_surface_egl_readback.cc
+++ b/chromium/ui/ozone/common/gl_surface_egl_readback.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/ozone/common/egl_util.h"
namespace ui {
diff --git a/chromium/ui/ozone/demo/window_manager.cc b/chromium/ui/ozone/demo/window_manager.cc
index 611d6bff646..686f88da6ce 100644
--- a/chromium/ui/ozone/demo/window_manager.cc
+++ b/chromium/ui/ozone/demo/window_manager.cc
@@ -108,13 +108,10 @@ void WindowManager::OnDisplaysAcquired(
}
}
-void WindowManager::OnDisplayConfigured(
- const int64_t display_id,
- const gfx::Rect& bounds,
- const base::flat_map<int64_t, bool>& statuses) {
- DCHECK_EQ(statuses.size(), 1UL);
-
- if (statuses.at(display_id)) {
+void WindowManager::OnDisplayConfigured(const int64_t display_id,
+ const gfx::Rect& bounds,
+ bool config_success) {
+ if (config_success) {
std::unique_ptr<DemoWindow> window(
new DemoWindow(this, renderer_factory_.get(), bounds));
window->Start();
diff --git a/chromium/ui/ozone/demo/window_manager.h b/chromium/ui/ozone/demo/window_manager.h
index 0415b01bf39..db65a5b7b05 100644
--- a/chromium/ui/ozone/demo/window_manager.h
+++ b/chromium/ui/ozone/demo/window_manager.h
@@ -41,7 +41,7 @@ class WindowManager : public display::NativeDisplayObserver {
const std::vector<display::DisplaySnapshot*>& displays);
void OnDisplayConfigured(const int64_t display_id,
const gfx::Rect& bounds,
- const base::flat_map<int64_t, bool>& statuses);
+ bool config_success);
// display::NativeDisplayDelegate:
void OnConfigurationChanged() override;
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 40087309e67..d9c19703f36 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
@@ -40,7 +40,7 @@ class GLImageNativePixmapTestDelegate : public GLImageTestDelegateBase {
DCHECK(pixmap) << "Offending format: " << gfx::BufferFormatToString(format);
if (usage == gfx::BufferUsage::GPU_READ_CPU_READ_WRITE ||
usage == gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE ||
- usage == gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE) {
+ usage == gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE) {
auto client_pixmap = client_native_pixmap_factory_->ImportFromHandle(
pixmap->ExportHandle(), size, format, usage);
bool mapped = client_pixmap->Map();
@@ -120,14 +120,14 @@ using GLImageBindTestTypes = testing::Types<
GLImageNativePixmapTestDelegate<gfx::BufferUsage::GPU_READ_CPU_READ_WRITE,
gfx::BufferFormat::YVU_420>,
GLImageNativePixmapTestDelegate<
- gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE,
+ gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE,
gfx::BufferFormat::YVU_420>,
GLImageNativePixmapTestDelegate<gfx::BufferUsage::GPU_READ_CPU_READ_WRITE,
gfx::BufferFormat::YUV_420_BIPLANAR>,
GLImageNativePixmapTestDelegate<gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE,
gfx::BufferFormat::YUV_420_BIPLANAR>,
GLImageNativePixmapTestDelegate<
- gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE,
+ gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE,
gfx::BufferFormat::YUV_420_BIPLANAR>,
GLImageNativePixmapTestDelegate<gfx::BufferUsage::GPU_READ_CPU_READ_WRITE,
gfx::BufferFormat::P010>>;
diff --git a/chromium/ui/ozone/platform/cast/DIR_METADATA b/chromium/ui/ozone/platform/cast/DIR_METADATA
new file mode 100644
index 00000000000..774785b830c
--- /dev/null
+++ b/chromium/ui/ozone/platform/cast/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Chromecast"
+}
diff --git a/chromium/ui/ozone/platform/cast/OWNERS b/chromium/ui/ozone/platform/cast/OWNERS
index 58f4b71ee3c..281daa82ed2 100644
--- a/chromium/ui/ozone/platform/cast/OWNERS
+++ b/chromium/ui/ozone/platform/cast/OWNERS
@@ -1,4 +1,2 @@
halliwell@chromium.org
lcwu@chromium.org
-
-# COMPONENT: Chromecast
diff --git a/chromium/ui/ozone/platform/drm/BUILD.gn b/chromium/ui/ozone/platform/drm/BUILD.gn
index 37a412b4422..5e5c1eb225c 100644
--- a/chromium/ui/ozone/platform/drm/BUILD.gn
+++ b/chromium/ui/ozone/platform/drm/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/chromecast_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/linux/pkg_config.gni")
import("//build/config/ozone.gni")
import("//gpu/vulkan/features.gni")
@@ -119,9 +120,11 @@ source_set("gbm") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//build/config/linux/libdrm",
"//gpu/vulkan:buildflags",
"//ipc",
+ "//media:media_buildflags",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
"//skia",
@@ -158,7 +161,7 @@ source_set("gbm") {
]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//ui/base/ime/chromeos" ]
}
diff --git a/chromium/ui/ozone/platform/drm/DIR_METADATA b/chromium/ui/ozone/platform/drm/DIR_METADATA
new file mode 100644
index 00000000000..91a288c1659
--- /dev/null
+++ b/chromium/ui/ozone/platform/drm/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "OS>Systems>Display"
+}
diff --git a/chromium/ui/ozone/platform/drm/OWNERS b/chromium/ui/ozone/platform/drm/OWNERS
index 5392283e6fe..363a93a5f95 100644
--- a/chromium/ui/ozone/platform/drm/OWNERS
+++ b/chromium/ui/ozone/platform/drm/OWNERS
@@ -1,4 +1,2 @@
dcastagna@chromium.org
dnicoara@chromium.org
-
-# COMPONENT: OS>Systems>Display
diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.cc b/chromium/ui/ozone/platform/drm/common/drm_util.cc
index a03a4a94935..0c78e5fd8d5 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util.cc
+++ b/chromium/ui/ozone/platform/drm/common/drm_util.cc
@@ -13,16 +13,23 @@
#include <algorithm>
#include <memory>
+#include <string>
#include <utility>
+#include <vector>
#include "base/containers/flat_map.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/display_mode.h"
#include "ui/display/util/display_util.h"
#include "ui/display/util/edid_parser.h"
+#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
namespace ui {
@@ -118,6 +125,8 @@ display::DisplayConnectionType GetDisplayType(drmModeConnector* connector) {
case DRM_MODE_CONNECTOR_DVID:
case DRM_MODE_CONNECTOR_DVIA:
return display::DISPLAY_CONNECTION_TYPE_DVI;
+ case DRM_MODE_CONNECTOR_VIRTUAL:
+ // A display on VM is treated as an internal display.
case DRM_MODE_CONNECTOR_LVDS:
case DRM_MODE_CONNECTOR_eDP:
case DRM_MODE_CONNECTOR_DSI:
@@ -195,6 +204,20 @@ display::PrivacyScreenState GetPrivacyScreenState(int fd,
connector->prop_values[index]);
}
+std::vector<uint64_t> GetPathTopology(int fd, drmModeConnector* connector) {
+ ScopedDrmPropertyBlobPtr path_blob =
+ GetDrmPropertyBlob(fd, connector, "PATH");
+
+ if (!path_blob) {
+ DCHECK_GT(connector->connector_id, 0u);
+
+ // The topology is consisted solely of the connector id.
+ return {base::strict_cast<uint64_t>(connector->connector_id)};
+ }
+
+ return ParsePathBlob(*path_blob);
+}
+
bool IsAspectPreserving(int fd, drmModeConnector* connector) {
ScopedDrmPropertyPtr property;
int index = GetDrmProperty(fd, connector, "scaling mode", &property);
@@ -437,6 +460,12 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot(
const gfx::Size physical_size =
gfx::Size(info->connector()->mmWidth, info->connector()->mmHeight);
const display::DisplayConnectionType type = GetDisplayType(info->connector());
+ uint64_t base_connector_id = 0u;
+ std::vector<uint64_t> path_topology = GetPathTopology(fd, info->connector());
+ if (!path_topology.empty()) {
+ base_connector_id = path_topology.front();
+ path_topology.erase(path_topology.begin());
+ }
const bool is_aspect_preserving_scaling =
IsAspectPreserving(fd, info->connector());
const display::PanelOrientation panel_orientation =
@@ -454,7 +483,8 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot(
const gfx::Size maximum_cursor_size = GetMaximumCursorSize(fd);
std::string display_name;
- int64_t display_id = display_index;
+ // Make sure the ID contains non index part.
+ int64_t display_id = display_index | 0x100;
int64_t product_code = display::DisplaySnapshot::kInvalidProductCode;
int32_t year_of_manufacture = display::kInvalidYearOfManufacture;
bool has_overscan = false;
@@ -497,21 +527,13 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot(
display::DisplaySnapshot::DisplayModeList modes =
ExtractDisplayModes(info, active_pixel_size, &current_mode, &native_mode);
- // TODO(https://crbug.com/1105919): Needed for investigating an issue where
- // non-supporting devices broadcast privacy screen support on certain
- // displays.
- VLOG(1) << "DisplaySnapshot created: display_id=" << display_id
- << " type=" << type << " current_mode="
- << (current_mode ? current_mode->ToString() : "nullptr")
- << " privacy_screen_state=" << privacy_screen_state;
-
return std::make_unique<display::DisplaySnapshot>(
- display_id, origin, physical_size, type, is_aspect_preserving_scaling,
- has_overscan, privacy_screen_state, has_color_correction_matrix,
- color_correction_in_linear_space, display_color_space, bits_per_channel,
- display_name, sys_path, std::move(modes), panel_orientation, edid,
- current_mode, native_mode, product_code, year_of_manufacture,
- maximum_cursor_size);
+ display_id, origin, physical_size, type, base_connector_id, path_topology,
+ is_aspect_preserving_scaling, has_overscan, privacy_screen_state,
+ has_color_correction_matrix, color_correction_in_linear_space,
+ display_color_space, bits_per_channel, display_name, sys_path,
+ std::move(modes), panel_orientation, edid, current_mode, native_mode,
+ product_code, year_of_manufacture, maximum_cursor_size);
}
int GetFourCCFormatForOpaqueFramebuffer(gfx::BufferFormat format) {
@@ -535,6 +557,8 @@ int GetFourCCFormatForOpaqueFramebuffer(gfx::BufferFormat format) {
return DRM_FORMAT_NV12;
case gfx::BufferFormat::YVU_420:
return DRM_FORMAT_YVU420;
+ case gfx::BufferFormat::P010:
+ return DRM_FORMAT_P010;
default:
NOTREACHED();
return 0;
@@ -552,4 +576,64 @@ uint64_t GetEnumValueForName(int fd, int property_id, const char* str) {
return 0;
}
+// Returns a vector that holds the path topology of the display. Returns an
+// empty vector upon failure.
+//
+// A path topology c-string is of the format:
+// mst:{DRM_BASE_CONNECTOR_ID#}-{BRANCH_1_PORT#}-...-{BRANCH_N_PORT#}\0
+//
+// For example, the display configuration:
+// Device <--conn6-- MST1 <--port2-- MST2 <--port1-- Display
+// may produce the following topology c-string:
+// "mst:6-2-1"
+//
+// To see how this string is constructed in the DRM:
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/drm_dp_mst_topology.c?h=v5.10-rc3#n2229
+std::vector<uint64_t> ParsePathBlob(const drmModePropertyBlobRes& path_blob) {
+ if (!path_blob.length) {
+ LOG(ERROR) << "PATH property blob is empty.";
+ return {};
+ }
+
+ std::string path_str(
+ static_cast<char*>(path_blob.data),
+ base::strict_cast<std::string::size_type>(path_blob.length));
+ base::StringPiece path_string_piece(path_str);
+ path_string_piece = base::TrimString(path_string_piece, std::string("\0", 1u),
+ base::TRIM_TRAILING);
+
+ const std::string prefix("mst:");
+ if (!base::StartsWith(path_string_piece, prefix,
+ base::CompareCase::SENSITIVE)) {
+ LOG(ERROR) << "Invalid PATH string prefix. Does not contain '" << prefix
+ << "'. Input: '" << path_str << "'";
+ return {};
+ }
+ path_string_piece.remove_prefix(prefix.length());
+
+ std::vector<uint64_t> path;
+ for (const auto& string_port :
+ base::SplitStringPiece(path_string_piece, "-", base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_ALL)) {
+ uint64_t int_port = 0;
+ if (base::StringToUint64(string_port, &int_port) && int_port > 0) {
+ path.push_back(int_port);
+ } else {
+ LOG(ERROR)
+ << "One or more port values in the PATH string are invalid. Input: '"
+ << path_str << "'";
+ return {};
+ }
+ }
+
+ if (path.size() < 2) {
+ LOG(ERROR)
+ << "Insufficient number of ports (should be at least 2 but found "
+ << path.size() << "). Input: '" << path_str << "'";
+ return {};
+ }
+
+ return path;
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.h b/chromium/ui/ozone/platform/drm/common/drm_util.h
index c8fc1b71124..f86e91fdeda 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util.h
+++ b/chromium/ui/ozone/platform/drm/common/drm_util.h
@@ -100,6 +100,8 @@ bool ModeIsInterlaced(const drmModeModeInfo& mode);
uint64_t GetEnumValueForName(int fd, int property_id, const char* str);
+std::vector<uint64_t> ParsePathBlob(const drmModePropertyBlobRes& path_blob);
+
} // namespace ui
#endif // UI_OZONE_PLATFORM_DRM_COMMON_DRM_UTIL_H_
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 a0144bf0b10..3be4bc957f4 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc
@@ -16,6 +16,7 @@
#include "ui/display/types/display_snapshot.h"
#include "ui/display/util/edid_parser.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
namespace ui {
@@ -180,4 +181,176 @@ TEST_F(DrmUtilTest, TestDisplayModesExtraction) {
EXPECT_EQ(extracted_modes[1].get(), native_mode);
}
+TEST(PathBlobParser, InvalidBlob) {
+ char data[] = "this doesn't matter";
+ drmModePropertyBlobRes blob{1, 0, data};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+}
+
+TEST(PathBlobParser, EmptyOrNullString) {
+ {
+ char empty[] = "";
+ drmModePropertyBlobRes blob{1, sizeof(empty), empty};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char null[] = "\0";
+ drmModePropertyBlobRes blob{1, sizeof(null), null};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+}
+
+TEST(PathBlobParser, InvalidPathFormat) {
+ // Space(s)
+ {
+ char s[] = " ";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = " ";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Missing colon
+ {
+ char s[] = "mst6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Caps 'mst:'
+ {
+ char s[] = "MST:6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Subset of "mst:"
+ {
+ char s[] = "ms";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // No 'mst:'
+ {
+ char s[] = "6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Other colon-delimited prefix
+ {
+ char s[] = "path:6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Invalid port number or format
+ {
+ char s[] = "mst:";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst::6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:-6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6-2-1-";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:c7";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6-b-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6--2";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:---";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6- -2- -1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6 -2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6-'2'-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Null character
+ {
+ char s[] = "mst:6-\0-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+}
+
+TEST(PathBlobParser, ValidPathFormat) {
+ std::vector<uint64_t> expected = {6u, 2u, 1u};
+
+ {
+ char valid[] = "mst:6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(valid), valid};
+ EXPECT_EQ(expected, ParsePathBlob(blob));
+ }
+
+ {
+ char valid[] = "mst:6-2-1\0";
+ drmModePropertyBlobRes blob{1, sizeof(valid), valid};
+ EXPECT_EQ(expected, ParsePathBlob(blob));
+ }
+
+ {
+ char valid[] = {'m', 's', 't', ':', '6', '-', '2', '-', '1'};
+ drmModePropertyBlobRes blob{1, sizeof(valid), valid};
+ EXPECT_EQ(expected, ParsePathBlob(blob));
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/DEPS b/chromium/ui/ozone/platform/drm/gpu/DEPS
index 3fb5fa6f6a3..a4e9f0a5006 100644
--- a/chromium/ui/ozone/platform/drm/gpu/DEPS
+++ b/chromium/ui/ozone/platform/drm/gpu/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+media/media_buildflags.h",
"-ui/ozone/platform/drm",
"+ui/ozone/platform/drm/common",
"+ui/ozone/platform/drm/gpu",
diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc
index 8127e1633f2..6f4c17b6fa9 100644
--- a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc
@@ -9,6 +9,7 @@ namespace ui {
CrtcCommitRequest::CrtcCommitRequest(uint32_t crtc_id,
uint32_t connector_id,
drmModeModeInfo mode,
+ gfx::Point origin,
HardwareDisplayPlaneList* plane_list,
DrmOverlayPlaneList overlays,
bool should_enable)
@@ -16,8 +17,11 @@ CrtcCommitRequest::CrtcCommitRequest(uint32_t crtc_id,
crtc_id_(crtc_id),
connector_id_(connector_id),
mode_(mode),
+ origin_(origin),
plane_list_(plane_list),
overlays_(std::move(overlays)) {
+ // Verify that at least one overlay plane is a primary plane if we're enabling
+ // a CRTC.
DCHECK(!should_enable || DrmOverlayPlane::GetPrimaryPlane(overlays_));
}
@@ -28,6 +32,7 @@ CrtcCommitRequest::CrtcCommitRequest(const CrtcCommitRequest& other)
crtc_id_(other.crtc_id_),
connector_id_(other.connector_id_),
mode_(other.mode_),
+ origin_(other.origin_),
plane_list_(other.plane_list_),
overlays_(DrmOverlayPlane::Clone(other.overlays_)) {}
@@ -36,11 +41,12 @@ CrtcCommitRequest CrtcCommitRequest::EnableCrtcRequest(
uint32_t crtc_id,
uint32_t connector_id,
drmModeModeInfo mode,
+ gfx::Point origin,
HardwareDisplayPlaneList* plane_list,
DrmOverlayPlaneList overlays) {
DCHECK(plane_list && !overlays.empty());
- return CrtcCommitRequest(crtc_id, connector_id, mode, plane_list,
+ return CrtcCommitRequest(crtc_id, connector_id, mode, origin, plane_list,
std::move(overlays), /*should_enable=*/true);
}
@@ -49,7 +55,7 @@ CrtcCommitRequest CrtcCommitRequest::DisableCrtcRequest(
uint32_t crtc_id,
uint32_t connector_id,
HardwareDisplayPlaneList* plane_list) {
- return CrtcCommitRequest(crtc_id, connector_id, {}, plane_list,
+ return CrtcCommitRequest(crtc_id, connector_id, {}, gfx::Point(), plane_list,
DrmOverlayPlaneList(), /*should_enable=*/false);
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h
index ad8eab84e7f..f3597f3bb31 100644
--- a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h
+++ b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <xf86drmMode.h>
+#include "ui/gfx/geometry/point.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
@@ -31,6 +32,7 @@ class CrtcCommitRequest {
uint32_t crtc_id,
uint32_t connector_id,
drmModeModeInfo mode,
+ gfx::Point origin,
HardwareDisplayPlaneList* plane_list,
DrmOverlayPlaneList overlays);
@@ -43,6 +45,7 @@ class CrtcCommitRequest {
uint32_t crtc_id() const { return crtc_id_; }
uint32_t connector_id() const { return connector_id_; }
const drmModeModeInfo& mode() const { return mode_; }
+ const gfx::Point& origin() const { return origin_; }
HardwareDisplayPlaneList* plane_list() const { return plane_list_; }
const DrmOverlayPlaneList& overlays() const { return overlays_; }
@@ -50,6 +53,7 @@ class CrtcCommitRequest {
CrtcCommitRequest(uint32_t crtc_id,
uint32_t connector_id,
drmModeModeInfo mode,
+ gfx::Point origin,
HardwareDisplayPlaneList* plane_list,
DrmOverlayPlaneList overlays,
bool should_enable);
@@ -58,6 +62,7 @@ class CrtcCommitRequest {
const uint32_t crtc_id_ = 0;
const uint32_t connector_id_ = 0;
const drmModeModeInfo mode_ = {};
+ const gfx::Point origin_;
HardwareDisplayPlaneList* plane_list_ = nullptr;
const DrmOverlayPlaneList overlays_;
};
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
index cc5e8c5f213..6e262e27bbb 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -308,9 +308,15 @@ bool DrmDevice::SetCrtc(uint32_t crtc_id,
TRACE_EVENT2("drm", "DrmDevice::SetCrtc", "crtc", crtc_id, "size",
gfx::Size(mode.hdisplay, mode.vdisplay).ToString());
- return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0,
- connectors.data(), connectors.size(),
- const_cast<drmModeModeInfo*>(&mode));
+
+ if (!drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0,
+ connectors.data(), connectors.size(),
+ const_cast<drmModeModeInfo*>(&mode))) {
+ ++modeset_sequence_id_;
+ return true;
+ }
+
+ return false;
}
bool DrmDevice::DisableCrtc(uint32_t crtc_id) {
@@ -540,14 +546,45 @@ bool DrmDevice::CommitProperties(
uint32_t flags,
uint32_t crtc_count,
scoped_refptr<PageFlipRequest> page_flip_request) {
+ bool success = CommitPropertiesInternal(properties, flags, crtc_count,
+ page_flip_request);
+
+ if (success && flags == DRM_MODE_ATOMIC_ALLOW_MODESET)
+ ++modeset_sequence_id_;
+
+ return success;
+}
+
+bool DrmDevice::CommitPropertiesInternal(
+ drmModeAtomicReq* properties,
+ uint32_t flags,
+ uint32_t crtc_count,
+ scoped_refptr<PageFlipRequest> page_flip_request) {
uint64_t id = 0;
+
if (page_flip_request) {
flags |= DRM_MODE_PAGE_FLIP_EVENT;
id = page_flip_manager_->GetNextId();
}
- if (!drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags,
- reinterpret_cast<void*>(id))) {
+ int result = drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags,
+ reinterpret_cast<void*>(id));
+ if (result && errno == EBUSY && (flags & DRM_MODE_ATOMIC_NONBLOCK)) {
+ VLOG(1) << "Nonblocking atomic commit failed with EBUSY, retry without "
+ "nonblock";
+ // There have been cases where we get back EBUSY when attempting a
+ // non-blocking atomic commit. If we return false from here, that will cause
+ // the GPU process to CHECK itself. These are likely due to kernel bugs,
+ // which should be fixed, but rather than crashing we should retry the
+ // commit without the non-blocking flag and then it should work. This will
+ // cause a slight delay, but that should be imperceptible and better than
+ // crashing. We still do want the underlying driver bugs fixed, but this
+ // provide a better user experience.
+ flags &= ~DRM_MODE_ATOMIC_NONBLOCK;
+ result = drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags,
+ reinterpret_cast<void*>(id));
+ }
+ if (!result) {
if (page_flip_request) {
page_flip_manager_->RegisterCallback(id, crtc_count,
page_flip_request->AddPageFlip());
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device.h b/chromium/ui/ozone/platform/drm/gpu/drm_device.h
index fdc7f2d0a38..400c9a80e66 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_device.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_device.h
@@ -215,11 +215,10 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
// On success, true is returned and |page_flip_request| will receive a
// callback signalling completion of the flip, if provided.
- virtual bool CommitProperties(
- drmModeAtomicReq* properties,
- uint32_t flags,
- uint32_t crtc_count,
- scoped_refptr<PageFlipRequest> page_flip_request);
+ bool CommitProperties(drmModeAtomicReq* properties,
+ uint32_t flags,
+ uint32_t crtc_count,
+ scoped_refptr<PageFlipRequest> page_flip_request);
virtual bool SetCapability(uint64_t capability, uint64_t value);
@@ -230,6 +229,8 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
virtual bool SetMaster();
virtual bool DropMaster();
+ int modeset_sequence_id() const { return modeset_sequence_id_; }
+
int get_fd() const { return file_.GetPlatformFile(); }
base::FilePath device_path() const { return device_path_; }
@@ -244,8 +245,19 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
virtual ~DrmDevice();
+ virtual bool CommitPropertiesInternal(
+ drmModeAtomicReq* properties,
+ uint32_t flags,
+ uint32_t crtc_count,
+ scoped_refptr<PageFlipRequest> page_flip_request);
+
std::unique_ptr<HardwareDisplayPlaneManager> plane_manager_;
+ // Sequence ID incremented at each modeset.
+ // Currently used by DRM Framebuffer to indicate when was the fb initialized
+ // wrt the preceding modeset.
+ int modeset_sequence_id_ = 0;
+
private:
class IOWatcher;
class PageFlipManager;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
index 4f84ef488cf..b1ccd606e67 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
+#include "build/chromeos_buildflags.h"
#include "ui/display/display_features.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
@@ -156,7 +157,7 @@ std::unique_ptr<display::DisplaySnapshot> DrmDisplay::Update(
modes_ = GetDrmModeVector(info->connector());
is_hdr_capable_ =
params->bits_per_channel() > 8 && params->color_space().IsHDR();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
is_hdr_capable_ =
is_hdr_capable_ &&
base::FeatureList::IsEnabled(display::features::kUseHDRTransferFunction);
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
index bdf7db0ec19..4eb71a4d0f7 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
@@ -113,7 +113,8 @@ DrmFramebuffer::DrmFramebuffer(scoped_refptr<DrmDevice> drm_device,
opaque_framebuffer_pixel_format_(opaque_framebuffer_pixel_format),
format_modifier_(format_modifier),
preferred_modifiers_(modifiers),
- size_(size) {}
+ size_(size),
+ modeset_sequence_id_at_allocation_(drm_device_->modeset_sequence_id()) {}
DrmFramebuffer::~DrmFramebuffer() {
if (!drm_device_->RemoveFramebuffer(framebuffer_id_))
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h
index 079297ac1a7..8dbfe7f2bd4 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h
@@ -92,6 +92,10 @@ class DrmFramebuffer : public base::RefCountedThreadSafe<DrmFramebuffer> {
// Device on which the buffer was created.
const scoped_refptr<DrmDevice>& drm_device() const { return drm_device_; }
+ int modeset_sequence_id_at_allocation() const {
+ return modeset_sequence_id_at_allocation_;
+ }
+
private:
~DrmFramebuffer();
@@ -110,6 +114,10 @@ class DrmFramebuffer : public base::RefCountedThreadSafe<DrmFramebuffer> {
const std::vector<uint64_t> preferred_modifiers_;
const gfx::Size size_;
+ // The latest modeset sequence ID that was retrieved from DrmDevice when the
+ // buffer is initialized.
+ const int modeset_sequence_id_at_allocation_ = 0;
+
friend class base::RefCountedThreadSafe<DrmFramebuffer>;
};
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 8fdb11aba63..bd67bd3d60a 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
@@ -166,9 +166,8 @@ void DrmGpuDisplayManager::RelinquishDisplayControl() {
drm->DropMaster();
}
-base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays(
+bool DrmGpuDisplayManager::ConfigureDisplays(
const std::vector<display::DisplayConfigurationParams>& config_requests) {
- base::flat_map<int64_t, bool> statuses;
ScreenManager::ControllerConfigsList controllers_to_configure;
for (const auto& config : config_requests) {
@@ -176,8 +175,7 @@ base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays(
DrmDisplay* display = FindDisplay(display_id);
if (!display) {
LOG(ERROR) << "There is no display with ID " << display_id;
- statuses.insert(std::make_pair(display_id, false));
- continue;
+ return false;
}
std::unique_ptr<drmModeModeInfo> mode_ptr =
@@ -185,8 +183,7 @@ base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays(
if (config.mode) {
if (!FindModeForDisplay(mode_ptr.get(), *config.mode.value(),
display->modes(), displays_)) {
- statuses.insert(std::make_pair(display_id, false));
- continue;
+ return false;
}
}
@@ -205,41 +202,30 @@ base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays(
controllers_to_configure.push_back(std::move(params));
}
- if (controllers_to_configure.empty())
- return statuses;
-
if (clear_overlay_cache_callback_)
clear_overlay_cache_callback_.Run();
- auto config_statuses =
+ bool config_success =
screen_manager_->ConfigureDisplayControllers(controllers_to_configure);
- for (const auto& status : config_statuses) {
- int64_t display_id = status.first;
- bool success = status.second;
- DrmDisplay* display = FindDisplay(display_id);
- auto config = std::find_if(
- config_requests.begin(), config_requests.end(),
- [display_id](const auto& request) { return request.id == display_id; });
- if (success) {
- display->SetOrigin(config->origin);
+ for (const auto& controller : controllers_to_configure) {
+ if (config_success) {
+ FindDisplay(controller.display_id)->SetOrigin(controller.origin);
} else {
- if (config->mode) {
+ if (controller.mode) {
VLOG(1) << "Failed to enable device="
- << display->drm()->device_path().value()
- << " crtc=" << display->crtc()
- << " connector=" << display->connector();
+ << controller.drm->device_path().value()
+ << " crtc=" << controller.crtc
+ << " connector=" << controller.connector;
} else {
VLOG(1) << "Failed to disable device="
- << display->drm()->device_path().value()
- << " crtc=" << display->crtc();
+ << controller.drm->device_path().value()
+ << " crtc=" << controller.crtc;
}
}
-
- statuses.insert(std::make_pair(display_id, success));
}
- return statuses;
+ return config_success;
}
bool DrmGpuDisplayManager::GetHDCPState(
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 2dbe2ba68a4..5bbdc84144e 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
@@ -52,7 +52,7 @@ class DrmGpuDisplayManager {
bool TakeDisplayControl();
void RelinquishDisplayControl();
- base::flat_map<int64_t, bool> ConfigureDisplays(
+ bool ConfigureDisplays(
const std::vector<display::DisplayConfigurationParams>& config_requests);
bool GetHDCPState(int64_t display_id,
display::HDCPState* state,
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc
index 231d1728494..928ad048588 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc
@@ -40,7 +40,10 @@ std::vector<OverlaySurfaceCandidate> ToCacheKey(
} // namespace
-DrmOverlayManager::DrmOverlayManager() {
+DrmOverlayManager::DrmOverlayManager(
+ bool allow_sync_and_real_buffer_page_flip_testing) {
+ allow_sync_and_real_buffer_page_flip_testing_ =
+ allow_sync_and_real_buffer_page_flip_testing;
DETACH_FROM_THREAD(thread_checker_);
}
@@ -79,7 +82,8 @@ void DrmOverlayManager::CheckOverlaySupport(
result_candidates.back().overlay_handled = can_handle;
}
- if (features::IsSynchronousPageFlipTestingEnabled()) {
+ if (allow_sync_and_real_buffer_page_flip_testing_ &&
+ features::IsSynchronousPageFlipTestingEnabled()) {
std::vector<OverlayStatus> status =
SendOverlayValidationRequestSync(result_candidates, widget);
size_t size = candidates->size();
@@ -145,6 +149,11 @@ bool DrmOverlayManager::CanHandleCandidate(
if (candidate.transform == gfx::OVERLAY_TRANSFORM_INVALID)
return false;
+ // The remaining checks are for ensuring consistency between GL compositing
+ // and overlays. If we must use an overlay, then skip the remaining checks.
+ if (candidate.requires_overlay)
+ return true;
+
// Reject candidates that don't fall on a pixel boundary.
if (!gfx::IsNearestRectWithinDistance(candidate.display_rect, 0.01f))
return false;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h
index 87173fa824a..56112a3f508 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h
@@ -23,7 +23,8 @@ class OverlaySurfaceCandidate;
// of recent configurations.
class DrmOverlayManager : public OverlayManagerOzone {
public:
- DrmOverlayManager();
+ explicit DrmOverlayManager(
+ bool allow_sync_and_real_buffer_page_flip_testing = true);
~DrmOverlayManager() override;
// OverlayManagerOzone:
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc
index 2137523fbd8..89c86a5f80e 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc
@@ -8,13 +8,17 @@
#include "base/bind.h"
#include "base/trace_event/trace_event.h"
+#include "ui/ozone/platform/drm/gpu/drm_overlay_manager.h"
#include "ui/ozone/platform/drm/gpu/drm_thread_proxy.h"
#include "ui/ozone/public/overlay_surface_candidate.h"
namespace ui {
-DrmOverlayManagerGpu::DrmOverlayManagerGpu(DrmThreadProxy* drm_thread_proxy)
- : drm_thread_proxy_(drm_thread_proxy) {}
+DrmOverlayManagerGpu::DrmOverlayManagerGpu(
+ DrmThreadProxy* drm_thread_proxy,
+ bool allow_sync_and_real_buffer_page_flip_testing)
+ : DrmOverlayManager(allow_sync_and_real_buffer_page_flip_testing),
+ drm_thread_proxy_(drm_thread_proxy) {}
DrmOverlayManagerGpu::~DrmOverlayManagerGpu() = default;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h
index 3931e02dac5..cb759538344 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h
@@ -18,7 +18,9 @@ class DrmThreadProxy;
// overlay validations requests to the DRM thread.
class DrmOverlayManagerGpu : public DrmOverlayManager {
public:
- explicit DrmOverlayManagerGpu(DrmThreadProxy* drm_thread_proxy);
+ explicit DrmOverlayManagerGpu(
+ DrmThreadProxy* drm_thread_proxy,
+ bool allow_sync_and_real_buffer_page_flip_testing);
~DrmOverlayManagerGpu() override;
private:
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
index 4c496547411..348cba77ec8 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
@@ -46,7 +46,7 @@ scoped_refptr<DrmFramebuffer> GetBufferForPageFlipTest(
// flip commits.
std::vector<uint64_t> modifiers =
is_0th_plane
- ? drm_window->GetController()->GetFormatModifiers(fourcc_format)
+ ? drm_window->GetController()->GetSupportedModifiers(fourcc_format)
: std::vector<uint64_t>();
// Check if we can re-use existing buffers.
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
index 76577c6e485..f5938777c47 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
@@ -81,15 +81,16 @@ class DrmOverlayValidatorTest : public testing::Test {
bool ModesetController(ui::HardwareDisplayController* controller) {
ui::CommitRequest commit_request;
- ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
- controller->GetModesetProps(&commit_request, plane, kDefaultMode);
+ controller->GetModesetProps(&commit_request, modeset_planes, kDefaultMode);
ui::CommitRequest request_for_update = commit_request;
bool status = drm_->plane_manager()->Commit(std::move(commit_request),
DRM_MODE_ATOMIC_ALLOW_MODESET);
- controller->UpdateState(
- /*enable_requested=*/true,
- ui::DrmOverlayPlane::GetPrimaryPlane(request_for_update[0].overlays()));
+
+ for (const ui::CrtcCommitRequest& crtc_request : commit_request)
+ controller->UpdateState(crtc_request);
return status;
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
index d77131c3dfc..115231c7d02 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -142,7 +142,7 @@ void DrmThread::CreateBuffer(gfx::AcceleratedWidget widget,
std::vector<uint64_t> modifiers;
if (window && window->GetController() && !(flags & GBM_BO_USE_LINEAR) &&
!(client_flags & GbmPixmap::kFlagNoModifiers)) {
- modifiers = window->GetController()->GetFormatModifiers(fourcc_format);
+ modifiers = window->GetController()->GetSupportedModifiers(fourcc_format);
}
CreateBufferWithGbmFlags(drm, fourcc_format, size, framebuffer_size, flags,
@@ -328,13 +328,11 @@ void DrmThread::RefreshNativeDisplays(
void DrmThread::ConfigureNativeDisplays(
const std::vector<display::DisplayConfigurationParams>& config_requests,
- base::OnceCallback<void(const base::flat_map<int64_t, bool>&)> callback) {
+ base::OnceCallback<void(bool)> callback) {
TRACE_EVENT0("drm", "DrmThread::ConfigureNativeDisplays");
- base::flat_map<int64_t, bool> statuses =
- display_manager_->ConfigureDisplays(config_requests);
-
- std::move(callback).Run(statuses);
+ bool config_success = display_manager_->ConfigureDisplays(config_requests);
+ std::move(callback).Run(config_success);
}
void DrmThread::TakeDisplayControl(base::OnceCallback<void(bool)> callback) {
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
index fa04ef64c35..f2774c1e4aa 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/linux/gbm_wrapper.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window.cc b/chromium/ui/ozone/platform/drm/gpu/drm_window.cc
index ec3aa6b951d..d83a4f53d8b 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_window.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_window.cc
@@ -31,11 +31,9 @@ DrmWindow::DrmWindow(gfx::AcceleratedWidget widget,
ScreenManager* screen_manager)
: widget_(widget),
device_manager_(device_manager),
- screen_manager_(screen_manager) {
-}
+ screen_manager_(screen_manager) {}
-DrmWindow::~DrmWindow() {
-}
+DrmWindow::~DrmWindow() {}
void DrmWindow::Initialize() {
TRACE_EVENT1("drm", "DrmWindow::Initialize", "widget", widget_);
@@ -133,10 +131,6 @@ OverlayStatusList DrmWindow::TestPageFlip(
last_submitted_planes_);
}
-const DrmOverlayPlane* DrmWindow::GetLastModesetBuffer() const {
- return DrmOverlayPlane::GetPrimaryPlane(last_submitted_planes_);
-}
-
void DrmWindow::UpdateCursorImage() {
if (!controller_)
return;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window.h b/chromium/ui/ozone/platform/drm/gpu/drm_window.h
index ea2a2721408..ea1ef54b324 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_window.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_window.h
@@ -84,8 +84,9 @@ class DrmWindow {
OverlayStatusList TestPageFlip(
const OverlaySurfaceCandidateList& overlay_params);
- // Returns the last buffer associated with this window.
- const DrmOverlayPlane* GetLastModesetBuffer() const;
+ const DrmOverlayPlaneList& last_submitted_planes() const {
+ return last_submitted_planes_;
+ }
private:
// Draw next frame in an animated cursor.
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
index 163a89f699c..2fdc72f9a49 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -12,6 +12,7 @@
#include "base/files/file_path.h"
#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "third_party/khronos/EGL/egl.h"
#include "ui/gfx/buffer_format_util.h"
@@ -20,6 +21,7 @@
#include "ui/gfx/linux/gbm_defines.h"
#include "ui/gfx/linux/scoped_gbm_device.h"
#include "ui/gfx/native_pixmap.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/common/gl_ozone_egl.h"
@@ -275,8 +277,11 @@ GLOzone* GbmSurfaceFactory::GetGLOzone(gl::GLImplementation implementation) {
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
-GbmSurfaceFactory::CreateVulkanImplementation(bool allow_protected_memory,
+GbmSurfaceFactory::CreateVulkanImplementation(bool use_swiftshader,
+ bool allow_protected_memory,
bool enforce_protected_memory) {
+ DCHECK(!use_swiftshader)
+ << "Vulkan Swiftshader is not supported on this platform.";
return std::make_unique<ui::VulkanImplementationGbm>();
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
index 4ac05739713..4aa40139d7d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
@@ -39,6 +39,7 @@ class GbmSurfaceFactory : public SurfaceFactoryOzone {
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmapForVulkan(
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 664381d52a2..67cb75493b6 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -15,12 +15,17 @@
#include "base/trace_event/trace_event.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/presentation_feedback.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
#include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
#include "ui/ozone/platform/drm/gpu/gbm_surface_factory.h"
+#if BUILDFLAG(USE_OPENGL_APITRACE)
+#include "ui/gl/gl_implementation.h"
+#endif
+
namespace ui {
namespace {
@@ -133,6 +138,10 @@ void GbmSurfaceless::SwapBuffersAsync(
glFlush();
}
+#if BUILDFLAG(USE_OPENGL_APITRACE)
+ gl::TerminateFrame(); // Notify end of frame at buffer swap request.
+#endif
+
unsubmitted_frames_.back()->Flush();
PendingFrame* frame = unsubmitted_frames_.back().get();
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 47a684e7d22..ed387cbc7dc 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
@@ -16,9 +16,11 @@
#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"
+#include "third_party/skia/include/core/SkImage.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_fence.h"
+#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/gfx/native_pixmap.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/gfx/swap_result.h"
@@ -58,7 +60,7 @@ void DrawCursor(DrmDumbBuffer* cursor, const SkBitmap& image) {
// Clear to transparent in case |image| is smaller than the canvas.
SkCanvas* canvas = cursor->GetCanvas();
canvas->clear(SK_ColorTRANSPARENT);
- canvas->drawBitmapRect(image, damage, nullptr);
+ canvas->drawImageRect(image.asImage(), damage, SkSamplingOptions());
}
} // namespace
@@ -73,26 +75,26 @@ HardwareDisplayController::HardwareDisplayController(
HardwareDisplayController::~HardwareDisplayController() = default;
-void HardwareDisplayController::GetModesetProps(CommitRequest* commit_request,
- const DrmOverlayPlane& primary,
- const drmModeModeInfo& mode) {
- TRACE_EVENT0("drm", "HDC::GetModesetProps");
- GetModesetPropsForCrtcs(commit_request, primary,
+void HardwareDisplayController::GetModesetProps(
+ CommitRequest* commit_request,
+ const DrmOverlayPlaneList& modeset_planes,
+ const drmModeModeInfo& mode) {
+ GetModesetPropsForCrtcs(commit_request, modeset_planes,
/*use_current_crtc_mode=*/false, mode);
}
-void HardwareDisplayController::GetEnableProps(CommitRequest* commit_request,
- const DrmOverlayPlane& primary) {
- TRACE_EVENT0("drm", "HDC::GetEnableProps");
+void HardwareDisplayController::GetEnableProps(
+ CommitRequest* commit_request,
+ const DrmOverlayPlaneList& modeset_planes) {
// TODO(markyacoub): Simplify and remove the use of empty_mode.
drmModeModeInfo empty_mode = {};
- GetModesetPropsForCrtcs(commit_request, primary,
+ GetModesetPropsForCrtcs(commit_request, modeset_planes,
/*use_current_crtc_mode=*/true, empty_mode);
}
void HardwareDisplayController::GetModesetPropsForCrtcs(
CommitRequest* commit_request,
- const DrmOverlayPlane& primary,
+ const DrmOverlayPlaneList& modeset_planes,
bool use_current_crtc_mode,
const drmModeModeInfo& mode) {
DCHECK(commit_request);
@@ -103,19 +105,16 @@ void HardwareDisplayController::GetModesetPropsForCrtcs(
drmModeModeInfo modeset_mode =
use_current_crtc_mode ? controller->mode() : mode;
- DrmOverlayPlaneList overlays;
- overlays.push_back(primary.Clone());
+ DrmOverlayPlaneList overlays = DrmOverlayPlane::Clone(modeset_planes);
CrtcCommitRequest request = CrtcCommitRequest::EnableCrtcRequest(
- controller->crtc(), controller->connector(), modeset_mode,
+ controller->crtc(), controller->connector(), modeset_mode, origin_,
&owned_hardware_planes_, std::move(overlays));
commit_request->push_back(std::move(request));
}
}
void HardwareDisplayController::GetDisableProps(CommitRequest* commit_request) {
- TRACE_EVENT0("drm", "HDC::GetDisableProps");
-
for (const auto& controller : crtc_controllers_) {
CrtcCommitRequest request = CrtcCommitRequest::DisableCrtcRequest(
controller->crtc(), controller->connector(), &owned_hardware_planes_);
@@ -124,14 +123,13 @@ void HardwareDisplayController::GetDisableProps(CommitRequest* commit_request) {
}
void HardwareDisplayController::UpdateState(
- bool enable_requested,
- const DrmOverlayPlane* primary_plane) {
+ const CrtcCommitRequest& crtc_request) {
// Verify that the current state matches the requested state.
- if (enable_requested && IsEnabled()) {
- DCHECK(primary_plane);
+ if (crtc_request.should_enable() && IsEnabled()) {
+ DCHECK(!crtc_request.overlays().empty());
// TODO(markyacoub): This should be absorbed in the commit request.
ResetCursor();
- OnModesetComplete(*primary_plane);
+ OnModesetComplete(crtc_request.overlays());
}
}
@@ -146,6 +144,24 @@ void HardwareDisplayController::SchedulePageFlip(
bool status =
ScheduleOrTestPageFlip(plane_list, page_flip_request, &out_fence);
+ if (!status) {
+ for (const auto& plane : plane_list) {
+ // If the page flip failed and we see that the buffer has been allocated
+ // before the latest modeset, it could mean it was an in-flight buffer
+ // carrying an obsolete configuration.
+ // Request a buffer reallocation to reflect the new change.
+ if (plane.buffer &&
+ plane.buffer->modeset_sequence_id_at_allocation() <
+ plane.buffer->drm_device()->modeset_sequence_id()) {
+ std::move(submission_callback)
+ .Run(gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS, nullptr);
+ std::move(presentation_callback)
+ .Run(gfx::PresentationFeedback::Failure());
+ return;
+ }
+ }
+ }
+
CHECK(status) << "SchedulePageFlip failed";
if (page_flip_request->page_flip_count() == 0) {
@@ -204,17 +220,16 @@ bool HardwareDisplayController::ScheduleOrTestPageFlip(
}
std::vector<uint64_t> HardwareDisplayController::GetFormatModifiers(
- uint32_t format) const {
- std::vector<uint64_t> modifiers;
-
+ uint32_t fourcc_format) const {
if (crtc_controllers_.empty())
- return modifiers;
+ return std::vector<uint64_t>();
- modifiers = crtc_controllers_[0]->GetFormatModifiers(format);
+ std::vector<uint64_t> modifiers =
+ crtc_controllers_[0]->GetFormatModifiers(fourcc_format);
for (size_t i = 1; i < crtc_controllers_.size(); ++i) {
std::vector<uint64_t> other =
- crtc_controllers_[i]->GetFormatModifiers(format);
+ crtc_controllers_[i]->GetFormatModifiers(fourcc_format);
std::vector<uint64_t> intersection;
std::set_intersection(modifiers.begin(), modifiers.end(), other.begin(),
@@ -225,11 +240,26 @@ std::vector<uint64_t> HardwareDisplayController::GetFormatModifiers(
return modifiers;
}
-std::vector<uint64_t>
-HardwareDisplayController::GetFormatModifiersForModesetting(
+std::vector<uint64_t> HardwareDisplayController::GetSupportedModifiers(
uint32_t fourcc_format) const {
- const auto& modifiers = GetFormatModifiers(fourcc_format);
+ if (preferred_format_modifier_.empty())
+ return std::vector<uint64_t>();
+
+ auto it = preferred_format_modifier_.find(fourcc_format);
+ if (it != preferred_format_modifier_.end())
+ return std::vector<uint64_t>{it->second};
+
+ return GetFormatModifiers(fourcc_format);
+}
+
+std::vector<uint64_t>
+HardwareDisplayController::GetFormatModifiersForTestModeset(
+ uint32_t fourcc_format) {
+ // If we're about to test, clear the current preferred modifier.
+ preferred_format_modifier_.clear();
+
std::vector<uint64_t> filtered_modifiers;
+ const auto& modifiers = GetFormatModifiers(fourcc_format);
for (auto modifier : modifiers) {
// AFBC for modeset buffers doesn't work correctly, as we can't fill it with
// a valid AFBC buffer. For now, don't use AFBC for modeset buffers.
@@ -242,6 +272,18 @@ HardwareDisplayController::GetFormatModifiersForModesetting(
return filtered_modifiers;
}
+void HardwareDisplayController::UpdatePreferredModiferForFormat(
+ gfx::BufferFormat buffer_format,
+ uint64_t modifier) {
+ uint32_t fourcc_format = GetFourCCFormatFromBufferFormat(buffer_format);
+ base::InsertOrAssign(preferred_format_modifier_, fourcc_format, modifier);
+
+ uint32_t opaque_fourcc_format =
+ GetFourCCFormatForOpaqueFramebuffer(buffer_format);
+ base::InsertOrAssign(preferred_format_modifier_, opaque_fourcc_format,
+ modifier);
+}
+
void HardwareDisplayController::MoveCursor(const gfx::Point& location) {
cursor_location_ = location;
UpdateCursorLocation();
@@ -368,22 +410,21 @@ void HardwareDisplayController::OnPageFlipComplete(
time_of_last_flip_ = presentation_feedback.timestamp;
current_planes_ = std::move(pending_planes);
for (const auto& controller : crtc_controllers_) {
- GetDrmDevice()->plane_manager()->ResetModesetBufferOfCrtc(
+ GetDrmDevice()->plane_manager()->ResetModesetStateForCrtc(
controller->crtc());
}
page_flip_request_ = nullptr;
}
void HardwareDisplayController::OnModesetComplete(
- const DrmOverlayPlane& primary) {
- // drmModeSetCrtc has an immediate effect, so we can assume that the current
- // planes have been updated. However if a page flip is still pending, set the
- // pending planes to the same values so that the callback keeps the correct
- // state.
+ const DrmOverlayPlaneList& modeset_planes) {
+ // Modesetting is blocking so it has an immediate effect. We can assume that
+ // the current planes have been updated. However, if a page flip is still
+ // pending, set the pending planes to the same values so that the callback
+ // keeps the correct state.
page_flip_request_ = nullptr;
owned_hardware_planes_.legacy_page_flips.clear();
- current_planes_.clear();
- current_planes_.push_back(primary.Clone());
+ current_planes_ = DrmOverlayPlane::Clone(modeset_planes);
time_of_last_flip_ = base::TimeTicks::Now();
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h
index 17a917183ae..27e4dd4bcbf 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h
@@ -14,9 +14,11 @@
#include <vector>
#include "base/callback.h"
+#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/time/time.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/buffer_types.h"
#include "ui/gfx/swap_result.h"
#include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
@@ -96,15 +98,15 @@ class HardwareDisplayController {
// Gets the props required to modeset a CRTC with a |mode| onto
// |commit_request|.
void GetModesetProps(CommitRequest* commit_request,
- const DrmOverlayPlane& primary,
+ const DrmOverlayPlaneList& modeset_planes,
const drmModeModeInfo& mode);
// Gets the props required to enable/disable a CRTC onto |commit_request|.
void GetEnableProps(CommitRequest* commit_request,
- const DrmOverlayPlane& primary);
+ const DrmOverlayPlaneList& modeset_planes);
void GetDisableProps(CommitRequest* commit_request);
// Updates state of the controller after modeset/enable/disable is performed.
- void UpdateState(bool enable_requested, const DrmOverlayPlane* primary_plane);
+ void UpdateState(const CrtcCommitRequest& crtc_request);
// Schedules the |overlays|' framebuffers to be displayed on the next vsync
// event. The event will be posted on the graphics card file descriptor |fd_|
@@ -128,17 +130,19 @@ class HardwareDisplayController {
// doesn't change any state.
bool TestPageFlip(const DrmOverlayPlaneList& plane_list);
- // Return the supported modifiers for |fourcc_format| for this
- // controller.
- std::vector<uint64_t> GetFormatModifiers(uint32_t fourcc_format) const;
+ // Return the supported modifiers for |fourcc_format| for this controller.
+ std::vector<uint64_t> GetSupportedModifiers(uint32_t fourcc_format) const;
// Return the supported modifiers for |fourcc_format| for this
// controller to be used for modeset buffers. Currently, this only exists
// because we can't provide valid AFBC buffers during modeset.
// See https://crbug.com/852675
// TODO: Remove this.
- std::vector<uint64_t> GetFormatModifiersForModesetting(
- uint32_t fourcc_format) const;
+ std::vector<uint64_t> GetFormatModifiersForTestModeset(
+ uint32_t fourcc_format);
+
+ void UpdatePreferredModiferForFormat(gfx::BufferFormat buffer_format,
+ uint64_t modifier);
// Moves the hardware cursor to |location|.
void MoveCursor(const gfx::Point& location);
@@ -175,10 +179,10 @@ class HardwareDisplayController {
// Loops over |crtc_controllers_| and save their props into |commit_request|
// to be enabled/modeset.
void GetModesetPropsForCrtcs(CommitRequest* commit_request,
- const DrmOverlayPlane& primary,
+ const DrmOverlayPlaneList& modeset_planes,
bool use_current_crtc_mode,
const drmModeModeInfo& mode);
- void OnModesetComplete(const DrmOverlayPlane& primary);
+ void OnModesetComplete(const DrmOverlayPlaneList& modeset_planes);
bool ScheduleOrTestPageFlip(const DrmOverlayPlaneList& plane_list,
scoped_refptr<PageFlipRequest> page_flip_request,
std::unique_ptr<gfx::GpuFence>* out_fence);
@@ -189,6 +193,8 @@ class HardwareDisplayController {
void ResetCursor();
void DisableCursor();
+ std::vector<uint64_t> GetFormatModifiers(uint32_t fourcc_format) const;
+
HardwareDisplayPlaneList owned_hardware_planes_;
// Stores the CRTC configuration. This is used to identify monitors and
@@ -207,6 +213,11 @@ class HardwareDisplayController {
int cursor_frontbuffer_ = 0;
DrmDumbBuffer* current_cursor_ = nullptr;
+ // Maps each fourcc_format to its preferred modifier which was generated
+ // through modeset-test and updated in UpdatePreferredModifierForFormat().
+ base::flat_map<uint32_t /*fourcc_format*/, uint64_t /*preferred_modifier*/>
+ preferred_format_modifier_;
+
base::WeakPtrFactory<HardwareDisplayController> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(HardwareDisplayController);
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
index 739c8dd5d62..7cc0dddf155 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
@@ -9,6 +9,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/files/file_util.h"
#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -123,7 +124,7 @@ class HardwareDisplayControllerTest : public testing::Test {
}
protected:
- bool ModesetWithPlane(const ui::DrmOverlayPlane& plane);
+ bool ModesetWithPlanes(const ui::DrmOverlayPlaneList& modeset_planes);
bool DisableController();
std::unique_ptr<ui::HardwareDisplayController> controller_;
@@ -242,16 +243,15 @@ void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) {
gfx::Point());
}
-bool HardwareDisplayControllerTest::ModesetWithPlane(
- const ui::DrmOverlayPlane& plane) {
+bool HardwareDisplayControllerTest::ModesetWithPlanes(
+ const ui::DrmOverlayPlaneList& modeset_planes) {
ui::CommitRequest commit_request;
- controller_->GetModesetProps(&commit_request, plane, kDefaultMode);
+ controller_->GetModesetProps(&commit_request, modeset_planes, kDefaultMode);
ui::CommitRequest request_for_update = commit_request;
bool status = drm_->plane_manager()->Commit(std::move(commit_request),
DRM_MODE_ATOMIC_ALLOW_MODESET);
- controller_->UpdateState(
- /*enable_requested=*/true,
- ui::DrmOverlayPlane::GetPrimaryPlane(request_for_update[0].overlays()));
+ for (const ui::CrtcCommitRequest& crtc_request : commit_request)
+ controller_->UpdateState(crtc_request);
return status;
}
@@ -262,7 +262,8 @@ bool HardwareDisplayControllerTest::DisableController() {
ui::CommitRequest request_for_update = commit_request;
bool status = drm_->plane_manager()->Commit(std::move(commit_request),
DRM_MODE_ATOMIC_ALLOW_MODESET);
- controller_->UpdateState(/*enable_requested=*/false, nullptr);
+ for (const ui::CrtcCommitRequest& crtc_request : commit_request)
+ controller_->UpdateState(crtc_request);
return status;
}
@@ -301,15 +302,18 @@ uint64_t HardwareDisplayControllerTest::GetPlanePropertyValue(
}
TEST_F(HardwareDisplayControllerTest, CheckModesettingResult) {
- ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane));
- EXPECT_FALSE(plane.buffer->HasOneRef());
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
+ EXPECT_FALSE(ui::DrmOverlayPlane::GetPrimaryPlane(modeset_planes)
+ ->buffer->HasOneRef());
}
TEST_F(HardwareDisplayControllerTest, CrtcPropsAfterModeset) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
ui::ScopedDrmObjectPropertyPtr crtc_props =
drm_->GetObjectProperties(kPrimaryCrtc, DRM_MODE_OBJECT_CRTC);
@@ -328,8 +332,9 @@ TEST_F(HardwareDisplayControllerTest, CrtcPropsAfterModeset) {
}
TEST_F(HardwareDisplayControllerTest, ConnectorPropsAfterModeset) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
ui::ScopedDrmObjectPropertyPtr connector_props =
drm_->GetObjectProperties(kConnectorIdBase, DRM_MODE_OBJECT_CONNECTOR);
@@ -343,11 +348,15 @@ TEST_F(HardwareDisplayControllerTest, ConnectorPropsAfterModeset) {
TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) {
const FakeFenceFD fake_fence_fd;
- ui::DrmOverlayPlane plane1(CreateBuffer(), fake_fence_fd.GetGpuFence());
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), fake_fence_fd.GetGpuFence());
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
ui::ScopedDrmObjectPropertyPtr plane_props =
drm_->GetObjectProperties(kPlaneOffset, DRM_MODE_OBJECT_PLANE);
+ const ui::DrmOverlayPlane* primary_plane =
+ ui::DrmOverlayPlane::GetPrimaryPlane(modeset_planes);
+
{
ui::DrmDevice::Property prop = {};
ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "CRTC_ID", &prop);
@@ -358,13 +367,13 @@ TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) {
ui::DrmDevice::Property prop = {};
ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "CRTC_X", &prop);
EXPECT_EQ(kCrtcX, prop.id);
- EXPECT_EQ(plane1.display_bounds.x(), static_cast<int>(prop.value));
+ EXPECT_EQ(primary_plane->display_bounds.x(), static_cast<int>(prop.value));
}
{
ui::DrmDevice::Property prop = {};
ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "CRTC_Y", &prop);
EXPECT_EQ(kCrtcY, prop.id);
- EXPECT_EQ(plane1.display_bounds.y(), static_cast<int>(prop.value));
+ EXPECT_EQ(primary_plane->display_bounds.y(), static_cast<int>(prop.value));
}
{
ui::DrmDevice::Property prop = {};
@@ -382,13 +391,13 @@ TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) {
ui::DrmDevice::Property prop = {};
ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "FB_ID", &prop);
EXPECT_EQ(kPlaneFbId, prop.id);
- EXPECT_EQ(plane1.buffer->opaque_framebuffer_id(),
+ EXPECT_EQ(primary_plane->buffer->opaque_framebuffer_id(),
static_cast<uint32_t>(prop.value));
}
- gfx::RectF crop_rectf = plane1.crop_rect;
- crop_rectf.Scale(plane1.buffer->size().width(),
- plane1.buffer->size().height());
+ gfx::RectF crop_rectf = primary_plane->crop_rect;
+ crop_rectf.Scale(primary_plane->buffer->size().width(),
+ primary_plane->buffer->size().height());
gfx::Rect crop_rect = gfx::ToNearestRect(crop_rectf);
gfx::Rect fixed_point_rect =
gfx::Rect(crop_rect.x() << 16, crop_rect.y() << 16,
@@ -427,8 +436,10 @@ TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) {
}
TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
+ modeset_planes.push_back(plane.Clone());
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
// Test invalid fence fd
{
@@ -443,9 +454,9 @@ TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) {
}
const FakeFenceFD fake_fence_fd;
- plane1.gpu_fence = fake_fence_fd.GetGpuFence();
+ plane.gpu_fence = fake_fence_fd.GetGpuFence();
std::vector<ui::DrmOverlayPlane> planes = {};
- planes.push_back(plane1.Clone());
+ planes.push_back(plane.Clone());
SchedulePageFlip(std::move(planes));
// Verify fence FD after a GPU Fence is added to the plane.
@@ -460,8 +471,10 @@ TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) {
static_cast<int>(fence_fd_prop.value));
}
- plane1.gpu_fence = nullptr;
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ plane.gpu_fence = nullptr;
+ modeset_planes.clear();
+ modeset_planes.push_back(plane.Clone());
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
// Test an invalid FD again after the fence is removed.
{
@@ -477,9 +490,9 @@ TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) {
}
TEST_F(HardwareDisplayControllerTest, CheckDisableResetsProps) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
-
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
// Test props values after disabling.
DisableController();
@@ -581,20 +594,21 @@ TEST_F(HardwareDisplayControllerTest, CheckDisableResetsProps) {
}
TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
-
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
EXPECT_EQ(1, drm_->get_commit_count());
- ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr);
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane2.Clone());
+ ui::DrmOverlayPlane page_flip_plane(CreateBuffer(), nullptr);
+ std::vector<ui::DrmOverlayPlane> page_flip_planes;
+ page_flip_planes.push_back(page_flip_plane.Clone());
- SchedulePageFlip(std::move(planes));
+ SchedulePageFlip(std::move(page_flip_planes));
drm_->RunCallbacks();
- EXPECT_TRUE(plane1.buffer->HasOneRef());
- EXPECT_FALSE(plane2.buffer->HasOneRef());
+ EXPECT_TRUE(ui::DrmOverlayPlane::GetPrimaryPlane(modeset_planes)
+ ->buffer->HasOneRef());
+ EXPECT_FALSE(page_flip_plane.buffer->HasOneRef());
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
@@ -608,24 +622,21 @@ TEST_F(HardwareDisplayControllerTest, CheckStateIfModesetFails) {
InitializeDrmDevice(/* use_atomic */ false);
drm_->set_set_crtc_expectation(false);
- ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
-
- EXPECT_FALSE(ModesetWithPlane(plane));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_FALSE(ModesetWithPlanes(modeset_planes));
}
TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- ui::DrmOverlayPlane plane2(
- CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr);
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ planes.emplace_back(CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF),
+ true, nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ EXPECT_TRUE(ModesetWithPlanes(planes));
EXPECT_EQ(1, drm_->get_commit_count());
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- planes.push_back(plane2.Clone());
-
SchedulePageFlip(std::move(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -637,18 +648,15 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) {
}
TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- ui::DrmOverlayPlane plane2(
- CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr);
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ planes.emplace_back(CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF),
+ true, nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ EXPECT_TRUE(ModesetWithPlanes(planes));
EXPECT_EQ(1, drm_->get_commit_count());
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- planes.push_back(plane2.Clone());
-
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
EXPECT_EQ(2, drm_->get_commit_count());
// Verify both planes on the primary display have a valid framebuffer.
@@ -674,16 +682,13 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) {
}
TEST_F(HardwareDisplayControllerTest, AcceptUnderlays) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- ui::DrmOverlayPlane plane2(CreateBuffer(), -1, gfx::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(kDefaultModeSize),
- gfx::RectF(kDefaultModeSizeF), true, nullptr);
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ planes.emplace_back(CreateBuffer(), -1, gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kDefaultModeSize),
+ gfx::RectF(kDefaultModeSizeF), true, nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
-
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- planes.push_back(plane2.Clone());
+ EXPECT_TRUE(ModesetWithPlanes(planes));
SchedulePageFlip(std::move(planes));
drm_->RunCallbacks();
@@ -695,13 +700,12 @@ TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) {
controller_->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+
+ EXPECT_TRUE(ModesetWithPlanes(planes));
EXPECT_EQ(1, drm_->get_commit_count());
- ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr);
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane2.Clone());
SchedulePageFlip(std::move(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -720,10 +724,10 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
controller_->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -762,10 +766,10 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
}
TEST_F(HardwareDisplayControllerTest, PlaneStateAfterDestroyingCrtc) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+
SchedulePageFlip(std::move(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -790,10 +794,10 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) {
controller_->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -835,39 +839,52 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) {
}
TEST_F(HardwareDisplayControllerTest, ModesetWhilePageFlipping) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- SchedulePageFlip(std::move(planes));
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
+
+ EXPECT_TRUE(ModesetWithPlanes(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
}
TEST_F(HardwareDisplayControllerTest, FailPageFlipping) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ ASSERT_TRUE(ModesetWithPlanes(modeset_planes));
+
+ std::vector<ui::DrmOverlayPlane> page_flip_planes;
+ page_flip_planes.emplace_back(CreateBuffer(), nullptr);
drm_->set_commit_expectation(false);
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- EXPECT_DEATH_IF_SUPPORTED(SchedulePageFlip(std::move(planes)),
+ EXPECT_DEATH_IF_SUPPORTED(SchedulePageFlip(std::move(page_flip_planes)),
"SchedulePageFlip failed");
}
-TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlaneOnFlip) {
- ui::DrmOverlayPlane modeset_primary_plane(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(modeset_primary_plane));
-
- ui::DrmOverlayPlane plane1(CreateBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(kDefaultModeSize),
- gfx::RectF(0, 0, 1, 1), true, nullptr);
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+TEST_F(HardwareDisplayControllerTest,
+ RecreateBuffersOnOldPlanesPageFlipFailure) {
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ ASSERT_TRUE(ModesetWithPlanes(planes));
+
+ drm_->set_commit_expectation(false);
SchedulePageFlip(std::move(planes));
+ EXPECT_EQ(gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS, last_swap_result_);
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlaneOnFlip) {
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
+
+ std::vector<ui::DrmOverlayPlane> page_flip_planes;
+ page_flip_planes.emplace_back(CreateBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kDefaultModeSize),
+ gfx::RectF(0, 0, 1, 1), true, nullptr);
+ SchedulePageFlip(std::move(page_flip_planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -875,10 +892,10 @@ TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlaneOnFlip) {
}
TEST_F(HardwareDisplayControllerTest, AddCrtcMidPageFlip) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+
SchedulePageFlip(std::move(planes));
controller_->AddCrtc(std::make_unique<ui::CrtcController>(
@@ -890,10 +907,10 @@ TEST_F(HardwareDisplayControllerTest, AddCrtcMidPageFlip) {
}
TEST_F(HardwareDisplayControllerTest, RemoveCrtcMidPageFlip) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+
SchedulePageFlip(std::move(planes));
controller_->RemoveCrtc(drm_, kPrimaryCrtc);
@@ -907,16 +924,13 @@ TEST_F(HardwareDisplayControllerTest, Disable) {
// Page flipping overlays is only supported on atomic configurations.
InitializeDrmDevice(/* use_atomic= */ true);
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
-
- ui::DrmOverlayPlane plane2(
- CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr);
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- planes.push_back(plane2.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+ planes.emplace_back(CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF),
+ true, nullptr);
SchedulePageFlip(std::move(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -931,3 +945,20 @@ TEST_F(HardwareDisplayControllerTest, Disable) {
// No plane should be in use.
ASSERT_EQ(0, planes_in_use);
}
+
+TEST_F(HardwareDisplayControllerTest, MultiplePlanesModeset) {
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ ASSERT_TRUE(ModesetWithPlanes(modeset_planes));
+ EXPECT_EQ(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers.size(),
+ 2UL);
+ for (const auto& plane : modeset_planes) {
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ plane.buffer));
+ }
+}
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
index acff6ed2116..a24b5b83e70 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
@@ -4,7 +4,10 @@
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h"
+#include <drm_fourcc.h>
+
#include "base/logging.h"
+#include "media/media_buildflags.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_gpu_util.h"
@@ -20,12 +23,15 @@ uint32_t OverlayTransformToDrmRotationPropertyValue(
return DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_0;
case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
return DRM_MODE_REFLECT_Y | DRM_MODE_ROTATE_0;
+ // Driver code swaps 90 and 270 to be compliant with how xrandr uses these
+ // values, so we need to invert them here as well to get them back to the
+ // proper value.
case gfx::OVERLAY_TRANSFORM_ROTATE_90:
- return DRM_MODE_ROTATE_90;
+ return DRM_MODE_ROTATE_270;
case gfx::OVERLAY_TRANSFORM_ROTATE_180:
return DRM_MODE_ROTATE_180;
case gfx::OVERLAY_TRANSFORM_ROTATE_270:
- return DRM_MODE_ROTATE_270;
+ return DRM_MODE_ROTATE_90;
default:
NOTREACHED();
}
@@ -35,8 +41,22 @@ uint32_t OverlayTransformToDrmRotationPropertyValue(
// Rotations are dependent on modifiers. Tiled formats can be rotated,
// linear formats cannot. Atomic tests currently ignore modifiers, so there
// isn't a way of determining if the rotation is supported.
-// TODO(https://crbug/880464): Remove this.
-bool IsRotationTransformSupported(gfx::OverlayTransform transform) {
+// TODO(https://b/172210707): Atomic tests should work if we are using
+// kUseRealBuffersForPageFlipTest, so this should be revisited and tested more
+// broadly with a condition on that.
+// NOTE: This is enabled for TGL+ and NV12/P010 formats for 90/270 rotation
+// currently since we always allocate those formats as Y-tiled and 90/270
+// rotation is supported by the HW in that case. This is needed for protected
+// content that requires overlays.
+bool IsRotationTransformSupported(gfx::OverlayTransform transform,
+ uint32_t format_fourcc) {
+#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
+ if ((format_fourcc == DRM_FORMAT_NV12 || format_fourcc == DRM_FORMAT_P010) &&
+ (transform == gfx::OVERLAY_TRANSFORM_ROTATE_90 ||
+ transform == gfx::OVERLAY_TRANSFORM_ROTATE_270)) {
+ return true;
+ }
+#endif
if ((transform == gfx::OVERLAY_TRANSFORM_ROTATE_90) ||
(transform == gfx::OVERLAY_TRANSFORM_ROTATE_270) ||
(transform == gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL)) {
@@ -80,11 +100,12 @@ bool HardwareDisplayPlaneAtomic::AssignPlaneProps(
const gfx::Rect& crtc_rect,
const gfx::Rect& src_rect,
const gfx::OverlayTransform transform,
- int in_fence_fd) {
+ int in_fence_fd,
+ uint32_t format_fourcc) {
if (transform != gfx::OVERLAY_TRANSFORM_NONE && !properties_.rotation.id)
return false;
- if (!IsRotationTransformSupported(transform))
+ if (!IsRotationTransformSupported(transform, format_fourcc))
return false;
// Make a copy of properties to get the props IDs for the new intermediate
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
index 5043b987468..ae8d07997ec 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
@@ -31,7 +31,8 @@ class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane {
const gfx::Rect& crtc_rect,
const gfx::Rect& src_rect,
const gfx::OverlayTransform transform,
- int in_fence_fd);
+ int in_fence_fd,
+ uint32_t format_fourcc);
// Sets the props on |property_set| for commit.
bool SetPlaneProps(drmModeAtomicReq* property_set);
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 634fb042481..448cfa9a14b 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
@@ -459,8 +459,10 @@ void HardwareDisplayPlaneManager::UpdateCrtcAndPlaneStatesAfterModeset(
if (is_enabled) {
crtc_state.mode = crtc_request.mode();
- crtc_state.modeset_framebuffer =
- DrmOverlayPlane::GetPrimaryPlane(crtc_request.overlays())->buffer;
+ crtc_state.modeset_framebuffers.clear();
+ for (const auto& overlay : crtc_request.overlays())
+ crtc_state.modeset_framebuffers.push_back(overlay.buffer);
+
} else {
if (crtc_request.plane_list())
disable_planes_lists.insert(crtc_request.plane_list());
@@ -483,9 +485,9 @@ void HardwareDisplayPlaneManager::UpdateCrtcAndPlaneStatesAfterModeset(
}
}
-void HardwareDisplayPlaneManager::ResetModesetBufferOfCrtc(uint32_t crtc_id) {
+void HardwareDisplayPlaneManager::ResetModesetStateForCrtc(uint32_t crtc_id) {
CrtcState& crtc_state = CrtcStateForCrtcId(crtc_id);
- crtc_state.modeset_framebuffer = nullptr;
+ crtc_state.modeset_framebuffers.clear();
}
} // namespace ui
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 a4593292e8d..0cd18997ce8 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
@@ -82,7 +82,7 @@ class HardwareDisplayPlaneManager {
CrtcState(CrtcState&&);
drmModeModeInfo mode = {};
- scoped_refptr<DrmFramebuffer> modeset_framebuffer;
+ std::vector<scoped_refptr<DrmFramebuffer>> modeset_framebuffers;
CrtcProperties properties = {};
@@ -187,7 +187,7 @@ class HardwareDisplayPlaneManager {
// which resources needed to be tracked internally in
// HardwareDisplayPlaneManager and which should be taken care of by the
// caller.
- void ResetModesetBufferOfCrtc(uint32_t crtc_id);
+ void ResetModesetStateForCrtc(uint32_t crtc_id);
protected:
struct ConnectorProperties {
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 db7e3cad473..2fae9fcc8ff 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
@@ -11,10 +11,10 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/files/platform_file.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/gpu_fence_handle.h"
@@ -142,8 +142,11 @@ bool HardwareDisplayPlaneManagerAtomic::Commit(CommitRequest commit_request,
if (crtc_request.should_enable()) {
DCHECK(crtc_request.plane_list());
- status &= AssignOverlayPlanes(crtc_request.plane_list(),
- crtc_request.overlays(), crtc_id);
+ if (!AssignOverlayPlanes(crtc_request.plane_list(),
+ crtc_request.overlays(), crtc_id)) {
+ LOG_IF(ERROR, !is_testing) << "Failed to Assign Overlay Planes";
+ status = false;
+ }
enable_planes_lists.insert(crtc_request.plane_list());
}
}
@@ -204,9 +207,9 @@ void HardwareDisplayPlaneManagerAtomic::SetAtomicPropsForCommit(
plane->set_in_use(false);
HardwareDisplayPlaneAtomic* atomic_plane =
static_cast<HardwareDisplayPlaneAtomic*>(plane);
- atomic_plane->AssignPlaneProps(0, 0, gfx::Rect(), gfx::Rect(),
- gfx::OVERLAY_TRANSFORM_NONE,
- base::kInvalidPlatformFile);
+ atomic_plane->AssignPlaneProps(
+ 0, 0, gfx::Rect(), gfx::Rect(), gfx::OVERLAY_TRANSFORM_NONE,
+ base::kInvalidPlatformFile, DRM_FORMAT_INVALID);
atomic_plane->SetPlaneProps(atomic_request);
}
}
@@ -307,9 +310,9 @@ bool HardwareDisplayPlaneManagerAtomic::DisableOverlayPlanes(
HardwareDisplayPlaneAtomic* atomic_plane =
static_cast<HardwareDisplayPlaneAtomic*>(plane);
- atomic_plane->AssignPlaneProps(0, 0, gfx::Rect(), gfx::Rect(),
- gfx::OVERLAY_TRANSFORM_NONE,
- base::kInvalidPlatformFile);
+ atomic_plane->AssignPlaneProps(
+ 0, 0, gfx::Rect(), gfx::Rect(), gfx::OVERLAY_TRANSFORM_NONE,
+ base::kInvalidPlatformFile, DRM_FORMAT_INVALID);
atomic_plane->SetPlaneProps(plane_list->atomic_property_set.get());
}
ret = drm_->CommitProperties(plane_list->atomic_property_set.get(),
@@ -365,7 +368,7 @@ void HardwareDisplayPlaneManagerAtomic::RequestPlanesReadyCallback(
}
bool HardwareDisplayPlaneManagerAtomic::SetPlaneData(
- HardwareDisplayPlaneList* plane_list,
+ HardwareDisplayPlaneList*,
HardwareDisplayPlane* hw_plane,
const DrmOverlayPlane& overlay,
uint32_t crtc_id,
@@ -382,9 +385,10 @@ bool HardwareDisplayPlaneManagerAtomic::SetPlaneData(
fence_fd = gpu_fence_handle.owned_fd.get();
}
- if (!atomic_plane->AssignPlaneProps(crtc_id, framebuffer_id,
- overlay.display_bounds, src_rect,
- overlay.plane_transform, fence_fd)) {
+ if (!atomic_plane->AssignPlaneProps(
+ crtc_id, framebuffer_id, overlay.display_bounds, src_rect,
+ overlay.plane_transform, fence_fd,
+ overlay.buffer->framebuffer_pixel_format())) {
return false;
}
return true;
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 6f73d1747a0..1f23be53932 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
@@ -288,7 +288,7 @@ TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) {
ui::CrtcCommitRequest request = ui::CrtcCommitRequest::EnableCrtcRequest(
crtc_properties_[i].id, connector_properties[i].id, kDefaultMode,
- &state, std::move(overlays));
+ gfx::Point(), &state, std::move(overlays));
commit_request.push_back(std::move(request));
}
@@ -309,22 +309,22 @@ TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) {
ui::DrmOverlayPlaneList overlays;
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[0].id, kConnectorIdBase, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[0].id, kConnectorIdBase, kDefaultMode, gfx::Point(),
+ &state, std::move(overlays)));
}
{
ui::DrmOverlayPlaneList overlays;
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[1].id, kConnectorIdBase + 1, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[1].id, kConnectorIdBase + 1, kDefaultMode,
+ gfx::Point(), &state, std::move(overlays)));
}
{
ui::DrmOverlayPlaneList overlays;
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[2].id, kConnectorIdBase + 3, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[2].id, kConnectorIdBase + 3, kDefaultMode,
+ gfx::Point(), &state, std::move(overlays)));
}
EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
@@ -332,6 +332,47 @@ TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) {
}
}
+TEST_P(HardwareDisplayPlaneManagerTest, SequenceIncrementOnModesetOnly) {
+ fake_drm_->InitializeState(crtc_properties_, connector_properties_,
+ plane_properties_, property_names_,
+ /*use_atomic=*/true);
+
+ // Modeset Test
+ {
+ int pre_test_sequence_id = fake_drm_->modeset_sequence_id();
+ ASSERT_TRUE(fake_drm_->plane_manager()->Commit(
+ ui::CommitRequest(),
+ DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET));
+ EXPECT_EQ(pre_test_sequence_id, fake_drm_->modeset_sequence_id());
+ }
+
+ // Successful Modeset
+ {
+ int pre_modeset_sequence_id = fake_drm_->modeset_sequence_id();
+ ASSERT_TRUE(fake_drm_->plane_manager()->Commit(
+ ui::CommitRequest(), DRM_MODE_ATOMIC_ALLOW_MODESET));
+ EXPECT_EQ(pre_modeset_sequence_id + 1, fake_drm_->modeset_sequence_id());
+ }
+
+ // Failed Modeset
+ {
+ int pre_modeset_sequence_id = fake_drm_->modeset_sequence_id();
+ fake_drm_->set_set_crtc_expectation(false);
+ ASSERT_FALSE(fake_drm_->plane_manager()->Commit(
+ ui::CommitRequest(), DRM_MODE_ATOMIC_ALLOW_MODESET));
+ fake_drm_->set_set_crtc_expectation(true);
+ EXPECT_EQ(pre_modeset_sequence_id, fake_drm_->modeset_sequence_id());
+ }
+
+ // Page Flip
+ {
+ int pre_flip_sequence_id = fake_drm_->modeset_sequence_id();
+ ASSERT_TRUE(fake_drm_->plane_manager()->Commit(ui::CommitRequest(),
+ DRM_MODE_ATOMIC_NONBLOCK));
+ EXPECT_EQ(pre_flip_sequence_id, fake_drm_->modeset_sequence_id());
+ }
+}
+
TEST_P(HardwareDisplayPlaneManagerLegacyTest, Modeset) {
InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1);
fake_drm_->InitializeState(crtc_properties_, connector_properties_,
@@ -346,8 +387,8 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, Modeset) {
ui::DrmOverlayPlaneList overlays;
overlays.push_back(plane.Clone());
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode,
+ gfx::Point(), &state, std::move(overlays)));
EXPECT_FALSE(fake_drm_->plane_manager()->Commit(
std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
@@ -495,8 +536,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, Modeset) {
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode,
+ gfx::Point(), &state, std::move(overlays)));
EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
@@ -530,8 +571,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, CheckPropsAfterModeset) {
ui::DrmOverlayPlaneList overlays;
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode,
+ gfx::Point(), &state, std::move(overlays)));
EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
@@ -570,7 +611,7 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, CheckPropsAfterDisable) {
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode,
- &state, std::move(overlays)));
+ gfx::Point(), &state, std::move(overlays)));
EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
}
@@ -1379,7 +1420,8 @@ class HardwareDisplayPlaneAtomicMock : public ui::HardwareDisplayPlaneAtomic {
const gfx::Rect& crtc_rect,
const gfx::Rect& src_rect,
const gfx::OverlayTransform transform,
- int in_fence_fd) override {
+ int in_fence_fd,
+ uint32_t format_fourcc) override {
framebuffer_ = framebuffer;
return true;
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc
index bf00ae93cfe..1ef0fe9f11f 100644
--- a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc
@@ -9,7 +9,9 @@
#include <utility>
#include "base/check.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
+#include "base/containers/flat_map.h"
+#include "base/logging.h"
#include "skia/ext/legacy_display_globals.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -70,6 +72,13 @@ Type* FindObjectById(uint32_t id, std::vector<Type>& properties) {
return it != properties.end() ? &(*it) : nullptr;
}
+// TODO(dnicoara): Generate all IDs internal to MockDrmDevice.
+// For now generate something with a high enough ID to be unique in tests.
+uint32_t GetUniqueNumber() {
+ static uint32_t value_generator = 0xff000000;
+ return ++value_generator;
+}
+
} // namespace
MockDrmDevice::CrtcProperties::CrtcProperties() = default;
@@ -173,6 +182,34 @@ void MockDrmDevice::UpdateState(
connector_properties_ = connector_properties;
plane_properties_ = plane_properties;
property_names_ = property_names;
+
+ // Props IDs shouldn't change throughout a DRM state. Grab it once at
+ // UpdateState.
+ plane_crtc_id_prop_id_ = 0;
+ for (const PlaneProperties& plane_props : plane_properties) {
+ const std::vector<DrmDevice::Property>& props = plane_props.properties;
+ auto it = std::find_if(
+ props.begin(), props.end(),
+ [&names = property_names_](const DrmDevice::Property& prop) {
+ return names.at(prop.id) == "CRTC_ID";
+ });
+ if (it != props.end()) {
+ plane_crtc_id_prop_id_ = it->id;
+ // all planes should have the same prop ID for the name. Break right after
+ // the first one is found.
+ break;
+ }
+ }
+}
+
+void MockDrmDevice::SetModifiersOverhead(
+ base::flat_map<uint64_t /*modifier*/, int /*overhead*/>
+ modifiers_overhead) {
+ modifiers_overhead_ = modifiers_overhead;
+}
+
+void MockDrmDevice::SetSystemLimitOfModifiers(uint64_t limit) {
+ system_watermark_limitations_ = limit;
}
ScopedDrmResourcesPtr MockDrmDevice::GetResources() {
@@ -258,8 +295,9 @@ bool MockDrmDevice::AddFramebuffer2(uint32_t width,
uint32_t* framebuffer,
uint32_t flags) {
add_framebuffer_call_count_++;
- *framebuffer = add_framebuffer_call_count_;
+ *framebuffer = GetUniqueNumber();
framebuffer_ids_.insert(*framebuffer);
+ fb_props_[*framebuffer] = {width, height, modifiers[0]};
return add_framebuffer_expectation_;
}
@@ -269,6 +307,11 @@ bool MockDrmDevice::RemoveFramebuffer(uint32_t framebuffer) {
CHECK(it != framebuffer_ids_.end());
framebuffer_ids_.erase(it);
}
+ {
+ auto it = fb_props_.find(framebuffer);
+ CHECK(it != fb_props_.end());
+ fb_props_.erase(it);
+ }
remove_framebuffer_call_count_++;
std::vector<uint32_t> crtcs_to_clear;
for (auto crtc_fb : crtc_fb_) {
@@ -330,7 +373,7 @@ bool MockDrmDevice::SetProperty(uint32_t connector_id,
ScopedDrmPropertyBlob MockDrmDevice::CreatePropertyBlob(const void* blob,
size_t size) {
- uint32_t id = ++property_id_generator_;
+ uint32_t id = GetUniqueNumber();
allocated_property_blobs_.insert(id);
return std::make_unique<DrmPropertyBlobMetadata>(this, id);
}
@@ -427,25 +470,46 @@ bool MockDrmDevice::CloseBufferHandle(uint32_t handle) {
return true;
}
-bool MockDrmDevice::CommitProperties(
+bool MockDrmDevice::CommitPropertiesInternal(
drmModeAtomicReq* request,
uint32_t flags,
uint32_t crtc_count,
scoped_refptr<PageFlipRequest> page_flip_request) {
+ commit_count_++;
if (flags == kTestModesetFlags)
++test_modeset_count_;
else if (flags == kCommitModesetFlags)
++commit_modeset_count_;
- commit_count_++;
- if (!commit_expectation_)
+ if ((flags & kCommitModesetFlags && !set_crtc_expectation_) ||
+ (flags & DRM_MODE_ATOMIC_NONBLOCK && !commit_expectation_)) {
return false;
+ }
+
+ uint64_t requested_resources = 0;
+ base::flat_map<uint64_t, int> crtc_planes_counter;
for (uint32_t i = 0; i < request->cursor; ++i) {
- bool res = ValidatePropertyValue(request->items[i].property_id,
- request->items[i].value);
- if (!res)
+ const drmModeAtomicReqItem& item = request->items[i];
+ if (!ValidatePropertyValue(item.property_id, item.value))
return false;
+
+ if (fb_props_.find(item.value) != fb_props_.end()) {
+ const FramebufferProps& props = fb_props_[item.value];
+ requested_resources += modifiers_overhead_[props.modifier];
+ }
+
+ if (item.property_id == plane_crtc_id_prop_id_) {
+ if (++crtc_planes_counter[item.value] > 1 &&
+ !modeset_with_overlays_expectation_)
+ return false;
+ }
+ }
+
+ if (requested_resources > system_watermark_limitations_) {
+ LOG(ERROR) << "Requested display configuration exceeds system watermark "
+ "limitations";
+ return false;
}
if (page_flip_request)
@@ -463,6 +527,12 @@ bool MockDrmDevice::CommitProperties(
return false;
}
+ // Count all committed planes at the end just before returning true to reflect
+ // the number of planes that have successfully been committed.
+ last_planes_committed_count_ = 0;
+ for (const auto& planes_counter : crtc_planes_counter)
+ last_planes_committed_count_ += planes_counter.second;
+
return true;
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h
index 922d402147c..0c2d823f12a 100644
--- a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h
+++ b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h
@@ -8,11 +8,13 @@
#include <drm_mode.h>
#include <stddef.h>
#include <stdint.h>
+#include <limits>
#include <map>
#include <memory>
#include <set>
#include <vector>
+#include "base/containers/flat_map.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "third_party/skia/include/core/SkRefCnt.h"
@@ -90,11 +92,18 @@ class MockDrmDevice : public DrmDevice {
legacy_gamma_ramp_expectation_ = state;
}
void set_commit_expectation(bool state) { commit_expectation_ = state; }
+ void set_overlay_modeset_expecation(bool state) {
+ modeset_with_overlays_expectation_ = state;
+ }
uint32_t current_framebuffer() const { return current_framebuffer_; }
const std::vector<sk_sp<SkSurface>> buffers() const { return buffers_; }
+ int last_planes_committed_count() const {
+ return last_planes_committed_count_;
+ }
+
uint32_t get_cursor_handle_for_crtc(uint32_t crtc) const {
const auto it = crtc_cursor_map_.find(crtc);
return it != crtc_cursor_map_.end() ? it->second : 0;
@@ -122,6 +131,9 @@ class MockDrmDevice : public DrmDevice {
void SetPropertyBlob(ScopedDrmPropertyBlobPtr blob);
+ void SetModifiersOverhead(base::flat_map<uint64_t, int> modifiers_overhead);
+ void SetSystemLimitOfModifiers(uint64_t limit);
+
// DrmDevice:
ScopedDrmResourcesPtr GetResources() override;
ScopedDrmPlaneResPtr GetPlaneResources() override;
@@ -177,10 +189,6 @@ class MockDrmDevice : public DrmDevice {
bool MapDumbBuffer(uint32_t handle, size_t size, void** pixels) override;
bool UnmapDumbBuffer(void* pixels, size_t size) override;
bool CloseBufferHandle(uint32_t handle) override;
- bool CommitProperties(drmModeAtomicReq* request,
- uint32_t flags,
- uint32_t crtc_count,
- scoped_refptr<PageFlipRequest> callback) override;
bool SetGammaRamp(
uint32_t crtc_id,
const std::vector<display::GammaRampRGBEntry>& lut) override;
@@ -188,8 +196,21 @@ class MockDrmDevice : public DrmDevice {
uint32_t GetFramebufferForCrtc(uint32_t crtc_id) const;
private:
+ // Properties of the plane associated with a fb.
+ struct FramebufferProps {
+ uint32_t width = 0;
+ uint32_t height = 0;
+ uint64_t modifier = 0;
+ };
+
~MockDrmDevice() override;
+ bool CommitPropertiesInternal(
+ drmModeAtomicReq* request,
+ uint32_t flags,
+ uint32_t crtc_count,
+ scoped_refptr<PageFlipRequest> callback) override;
+
bool UpdateProperty(uint32_t id,
uint64_t value,
std::vector<DrmDevice::Property>* properties);
@@ -210,6 +231,7 @@ class MockDrmDevice : public DrmDevice {
int commit_count_ = 0;
int set_object_property_count_ = 0;
int set_gamma_ramp_count_ = 0;
+ int last_planes_committed_count_ = 0;
bool set_crtc_expectation_;
bool add_framebuffer_expectation_;
@@ -217,8 +239,10 @@ class MockDrmDevice : public DrmDevice {
bool create_dumb_buffer_expectation_;
bool legacy_gamma_ramp_expectation_ = false;
bool commit_expectation_ = true;
+ bool modeset_with_overlays_expectation_ = true;
uint32_t current_framebuffer_;
+ uint32_t plane_crtc_id_prop_id_ = 0;
std::vector<sk_sp<SkSurface>> buffers_;
@@ -237,12 +261,14 @@ class MockDrmDevice : public DrmDevice {
std::map<uint32_t, std::string> property_names_;
- // TODO(dnicoara): Generate all IDs internal to MockDrmDevice.
- // For now generate something with a high enough ID to be unique in tests.
- uint32_t property_id_generator_ = 0xff000000;
-
std::set<uint32_t> allocated_property_blobs_;
+ // Props of the plane associated with the generated fb_id.
+ base::flat_map<uint32_t /*fb_id*/, FramebufferProps> fb_props_;
+
+ uint64_t system_watermark_limitations_ = std::numeric_limits<uint64_t>::max();
+ base::flat_map<uint64_t /*modifier*/, int /*overhead*/> modifiers_overhead_;
+
DISALLOW_COPY_AND_ASSIGN(MockDrmDevice);
};
diff --git a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc
index c65c5f6825c..af364e9c0e4 100644
--- a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc
@@ -6,6 +6,8 @@
#include <utility>
+#include "base/bind.h"
+
namespace ui {
void PostSyncTask(
diff --git a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h
index d5be9bd74e3..c488aea5a1d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h
+++ b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h
@@ -7,7 +7,7 @@
#include <utility>
-#include "base/bind.h"
+#include "base/bind_post_task.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/waitable_event.h"
@@ -15,19 +15,6 @@
namespace ui {
-namespace internal {
-
-template <typename... Args>
-void PostAsyncTask(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- base::OnceCallback<void(Args...)> callback,
- Args... args) {
- auto closure = base::BindOnce(std::move(callback), std::move(args)...);
- task_runner->PostTask(FROM_HERE, std::move(closure));
-}
-
-} // namespace internal
-
// Posts a task to a different thread and blocks waiting for the task to finish
// executing.
void PostSyncTask(
@@ -40,10 +27,10 @@ void PostSyncTask(
// thread).
template <typename... Args>
base::RepeatingCallback<void(Args...)> CreateSafeRepeatingCallback(
- base::RepeatingCallback<void(Args...)> callback) {
- return base::BindRepeating(&internal::PostAsyncTask<Args...>,
- base::ThreadTaskRunnerHandle::Get(),
- std::move(callback));
+ base::RepeatingCallback<void(Args...)> callback,
+ const base::Location& location = FROM_HERE) {
+ return base::BindPostTask(base::ThreadTaskRunnerHandle::Get(),
+ std::move(callback), location);
}
// Creates a OnceCallback that will run |callback| on the calling thread. Useful
@@ -51,10 +38,10 @@ base::RepeatingCallback<void(Args...)> CreateSafeRepeatingCallback(
// task finished (and the callback needs to run on the original thread).
template <typename... Args>
base::OnceCallback<void(Args...)> CreateSafeOnceCallback(
- base::OnceCallback<void(Args...)> callback) {
- return base::BindOnce(&internal::PostAsyncTask<Args...>,
- base::ThreadTaskRunnerHandle::Get(),
- std::move(callback));
+ base::OnceCallback<void(Args...)> callback,
+ const base::Location& location = FROM_HERE) {
+ return base::BindPostTask(base::ThreadTaskRunnerHandle::Get(),
+ std::move(callback), location);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
index 5a8319fe9cd..127f4d87257 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -10,6 +10,7 @@
#include "base/files/platform_file.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/display/types/display_snapshot.h"
@@ -36,7 +37,7 @@ namespace {
bool FillModesetBuffer(const scoped_refptr<DrmDevice>& drm,
HardwareDisplayController* controller,
SkSurface* surface,
- uint32_t fourcc_format) {
+ const std::vector<uint64_t>& modifiers) {
DCHECK(!controller->crtc_controllers().empty());
CrtcController* first_crtc = controller->crtc_controllers()[0].get();
ScopedDrmCrtcPtr saved_crtc(drm->GetCrtc(first_crtc->crtc()));
@@ -45,7 +46,6 @@ bool FillModesetBuffer(const scoped_refptr<DrmDevice>& drm,
return false;
}
- const auto& modifiers = controller->GetFormatModifiers(fourcc_format);
for (const uint64_t modifier : modifiers) {
// A value of 0 means DRM_FORMAT_MOD_NONE. If the CRTC has any other
// modifier (tiling, compression, etc.) we can't read the fb and assume it's
@@ -77,7 +77,7 @@ bool FillModesetBuffer(const scoped_refptr<DrmDevice>& drm,
// Copy the source buffer. Do not perform any blending.
paint.setBlendMode(SkBlendMode::kSrc);
surface->getCanvas()->drawImage(saved_buffer.surface()->makeImageSnapshot(),
- 0, 0, &paint);
+ 0, 0, SkSamplingOptions(), &paint);
return true;
}
@@ -93,19 +93,6 @@ CrtcController* GetCrtcController(HardwareDisplayController* controller,
return nullptr;
}
-std::vector<uint64_t> GetModifiersForPrimaryFormat(
- HardwareDisplayController* controller) {
- gfx::BufferFormat format = display::DisplaySnapshot::PrimaryFormat();
- uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(format);
- return controller->GetFormatModifiersForModesetting(fourcc_format);
-}
-
-bool AreAllStatusesTrue(base::flat_map<int64_t, bool>& display_statuses) {
- auto it = find_if(display_statuses.begin(), display_statuses.end(),
- [](const auto status) { return status.second == false; });
- return (it == display_statuses.end());
-}
-
} // namespace
ScreenManager::ScreenManager() = default;
@@ -175,6 +162,9 @@ void ScreenManager::AddDisplayController(const scoped_refptr<DrmDevice>& drm,
void ScreenManager::RemoveDisplayControllers(
const CrtcsWithDrmList& controllers_to_remove) {
+ TRACE_EVENT1("drm", "ScreenManager::RemoveDisplayControllers",
+ "display_count", controllers_to_remove.size());
+
// Split them to different lists unique to each DRM Device.
base::flat_map<scoped_refptr<DrmDevice>, CrtcsWithDrmList>
controllers_for_drm_devices;
@@ -223,8 +213,10 @@ void ScreenManager::RemoveDisplayControllers(
UpdateControllerToWindowMapping();
}
-base::flat_map<int64_t, bool> ScreenManager::ConfigureDisplayControllers(
+bool ScreenManager::ConfigureDisplayControllers(
const ControllerConfigsList& controllers_params) {
+ TRACE_EVENT0("drm", "ScreenManager::ConfigureDisplayControllers");
+
// Split them to different lists unique to each DRM Device.
base::flat_map<scoped_refptr<DrmDevice>, ControllerConfigsList>
displays_for_drm_devices;
@@ -238,33 +230,81 @@ base::flat_map<int64_t, bool> ScreenManager::ConfigureDisplayControllers(
displays_for_drm_devices[params.drm].emplace_back(params);
}
- base::flat_map<int64_t, bool> statuses;
+ bool config_success = true;
// Perform display configurations together for the same DRM only.
for (const auto& configs_on_drm : displays_for_drm_devices) {
- auto display_statuses = TestAndModeset(configs_on_drm.second);
- statuses.insert(display_statuses.begin(), display_statuses.end());
+ const ControllerConfigsList& controllers_params = configs_on_drm.second;
+ bool test_modeset = TestAndSetPreferredModifiers(controllers_params) ||
+ TestAndSetLinearModifier(controllers_params);
+ config_success &= test_modeset;
+ if (!test_modeset)
+ continue;
+ bool can_modeset_with_overlays =
+ TestModesetWithOverlays(controllers_params);
+ config_success &= Modeset(controllers_params, can_modeset_with_overlays);
}
- if (AreAllStatusesTrue(statuses))
+ if (config_success)
UpdateControllerToWindowMapping();
- return statuses;
+ return config_success;
}
-base::flat_map<int64_t, bool> ScreenManager::TestAndModeset(
+bool ScreenManager::TestAndSetPreferredModifiers(
const ControllerConfigsList& controllers_params) {
- if (!TestModeset(controllers_params)) {
- base::flat_map<int64_t, bool> statuses;
- for (const auto& params : controllers_params)
- statuses.insert(std::make_pair(params.display_id, false));
- return statuses;
+ TRACE_EVENT1("drm", "ScreenManager::TestAndSetPreferredModifiers",
+ "display_count", controllers_params.size());
+
+ CrtcPreferredModifierMap crtcs_preferred_modifier;
+ CommitRequest commit_request;
+ auto drm = controllers_params[0].drm;
+
+ for (const auto& params : controllers_params) {
+ auto it = FindDisplayController(params.drm, params.crtc);
+ DCHECK(controllers_.end() != it);
+ HardwareDisplayController* controller = it->get();
+
+ if (params.mode) {
+ uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(
+ display::DisplaySnapshot::PrimaryFormat());
+ std::vector<uint64_t> modifiers =
+ controller->GetFormatModifiersForTestModeset(fourcc_format);
+ // Test with no overlays to go for a lower bandwidth usage.
+ DrmOverlayPlaneList modeset_planes = GetModesetPlanes(
+ controller, gfx::Rect(params.origin, ModeSize(*params.mode)),
+ modifiers, /*include_overlays=*/false, /*is_testing=*/true);
+ if (modeset_planes.empty())
+ return false;
+
+ uint64_t primary_modifier =
+ DrmOverlayPlane::GetPrimaryPlane(modeset_planes)
+ ->buffer->format_modifier();
+ crtcs_preferred_modifier[params.crtc] =
+ std::make_pair(modifiers.empty(), primary_modifier);
+
+ GetModesetControllerProps(&commit_request, controller, params.origin,
+ *params.mode, modeset_planes);
+ } else {
+ controller->GetDisableProps(&commit_request);
+ }
+ }
+
+ if (!drm->plane_manager()->Commit(
+ std::move(commit_request),
+ DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET)) {
+ return false;
}
- return Modeset(controllers_params);
+ SetPreferredModifiers(controllers_params, crtcs_preferred_modifier);
+ return true;
}
-bool ScreenManager::TestModeset(
+bool ScreenManager::TestAndSetLinearModifier(
const ControllerConfigsList& controllers_params) {
+ TRACE_EVENT1("drm", "ScreenManager::TestAndSetLinearModifier",
+ "display_count", controllers_params.size());
+
+ CrtcPreferredModifierMap crtcs_preferred_modifier;
CommitRequest commit_request;
auto drm = controllers_params[0].drm;
@@ -273,65 +313,151 @@ bool ScreenManager::TestModeset(
DCHECK(controllers_.end() != it);
HardwareDisplayController* controller = it->get();
+ uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(
+ display::DisplaySnapshot::PrimaryFormat());
+ std::vector<uint64_t> modifiers =
+ controller->GetFormatModifiersForTestModeset(fourcc_format);
+ // Test with an empty list if no preferred modifiers are advertised.
+ // Platforms might not support gbm_bo_create_with_modifiers(). If the
+ // platform doesn't expose modifiers, do not attempt to explicitly request
+ // LINEAR otherwise we might CHECK() when trying to allocate buffers.
+ if (!modifiers.empty())
+ modifiers = std::vector<uint64_t>{DRM_FORMAT_MOD_LINEAR};
+ crtcs_preferred_modifier[params.crtc] =
+ std::make_pair(modifiers.empty(), DRM_FORMAT_MOD_LINEAR);
+
if (params.mode) {
- DrmOverlayPlane primary_plane = GetModesetBuffer(
+ // Test with no overlays to go for a lower bandwidth usage.
+ DrmOverlayPlaneList modeset_planes = GetModesetPlanes(
controller, gfx::Rect(params.origin, ModeSize(*params.mode)),
- GetModifiersForPrimaryFormat(controller));
- if (!primary_plane.buffer)
+ modifiers, /*include_overlays=*/false, /*is_testing=*/true);
+ if (modeset_planes.empty())
return false;
GetModesetControllerProps(&commit_request, controller, params.origin,
- *params.mode, primary_plane);
+ *params.mode, modeset_planes);
+ } else {
+ controller->GetDisableProps(&commit_request);
+ }
+ }
+
+ if (!drm->plane_manager()->Commit(
+ std::move(commit_request),
+ DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET)) {
+ return false;
+ }
+
+ SetPreferredModifiers(controllers_params, crtcs_preferred_modifier);
+ return true;
+}
+
+void ScreenManager::SetPreferredModifiers(
+ const ControllerConfigsList& controllers_params,
+ const CrtcPreferredModifierMap& crtcs_preferred_modifier) {
+ for (const auto& params : controllers_params) {
+ if (params.mode) {
+ bool was_modifiers_list_empty =
+ crtcs_preferred_modifier.at(params.crtc).first;
+ // No preferred modifiers should be saved as some platforms might not have
+ // bo_create_with_modifiers implemented, this will send the preferred
+ // modifiers list as an empty list.
+ if (!was_modifiers_list_empty) {
+ uint64_t picked_modifier =
+ crtcs_preferred_modifier.at(params.crtc).second;
+ auto it = FindDisplayController(params.drm, params.crtc);
+ DCHECK(*it);
+ it->get()->UpdatePreferredModiferForFormat(
+ display::DisplaySnapshot::PrimaryFormat(), picked_modifier);
+ }
+ }
+ }
+}
+
+bool ScreenManager::TestModesetWithOverlays(
+ const ControllerConfigsList& controllers_params) {
+ TRACE_EVENT1("drm", "ScreenManager::TestModesetWithOverlays", "display_count",
+ controllers_params.size());
+
+ bool does_an_overlay_exist = false;
+
+ CommitRequest commit_request;
+ auto drm = controllers_params[0].drm;
+ for (const auto& params : controllers_params) {
+ auto it = FindDisplayController(params.drm, params.crtc);
+ DCHECK(controllers_.end() != it);
+ HardwareDisplayController* controller = it->get();
+
+ if (params.mode) {
+ uint32_t fourcc_format = GetFourCCFormatForOpaqueFramebuffer(
+ display::DisplaySnapshot::PrimaryFormat());
+ std::vector<uint64_t> modifiers =
+ controller->GetSupportedModifiers(fourcc_format);
+
+ DrmOverlayPlaneList modeset_planes = GetModesetPlanes(
+ controller, gfx::Rect(params.origin, ModeSize(*params.mode)),
+ modifiers, /*include_overlays=*/true, /*is_testing=*/true);
+ DCHECK(!modeset_planes.empty());
+ does_an_overlay_exist |= modeset_planes.size() > 1;
+
+ GetModesetControllerProps(&commit_request, controller, params.origin,
+ *params.mode, modeset_planes);
} else {
controller->GetDisableProps(&commit_request);
}
}
+ // If we have no overlays, report not modesetting with overlays as we haven't
+ // tested with overlays.
+ if (!does_an_overlay_exist)
+ return false;
return drm->plane_manager()->Commit(
std::move(commit_request),
DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET);
}
-base::flat_map<int64_t, bool> ScreenManager::Modeset(
- const ControllerConfigsList& controllers_params) {
- base::flat_map<int64_t, bool> statuses;
+bool ScreenManager::Modeset(const ControllerConfigsList& controllers_params,
+ bool can_modeset_with_overlays) {
+ TRACE_EVENT2("drm", "ScreenManager::Modeset", "display_count",
+ controllers_params.size(), "modeset_with_overlays",
+ can_modeset_with_overlays);
+
+ CommitRequest commit_request;
+ auto drm = controllers_params[0].drm;
for (const auto& params : controllers_params) {
- // Commit one controller at a time.
- CommitRequest commit_request;
- bool status = true;
if (params.mode) {
auto it = FindDisplayController(params.drm, params.crtc);
DCHECK(controllers_.end() != it);
HardwareDisplayController* controller = it->get();
- DrmOverlayPlane primary_plane = GetModesetBuffer(
- controller, gfx::Rect(params.origin, ModeSize(*params.mode)),
- GetModifiersForPrimaryFormat(controller));
- if (primary_plane.buffer) {
- SetDisplayControllerForEnableAndGetProps(
- &commit_request, params.drm, params.crtc, params.connector,
- params.origin, *params.mode, primary_plane);
- } else {
- status = false;
- }
+ uint32_t fourcc_format = GetFourCCFormatForOpaqueFramebuffer(
+ display::DisplaySnapshot::PrimaryFormat());
+ std::vector<uint64_t> modifiers =
+ controller->GetSupportedModifiers(fourcc_format);
+
+ gfx::Rect bounds = gfx::Rect(params.origin, ModeSize(*params.mode));
+ DrmOverlayPlaneList modeset_planes =
+ GetModesetPlanes(controller, bounds, modifiers,
+ can_modeset_with_overlays, /*is_testing=*/false);
+
+ SetDisplayControllerForEnableAndGetProps(
+ &commit_request, params.drm, params.crtc, params.connector,
+ params.origin, *params.mode, modeset_planes);
} else {
- status = SetDisableDisplayControllerForDisableAndGetProps(
+ bool disable_set = SetDisableDisplayControllerForDisableAndGetProps(
&commit_request, params.drm, params.crtc);
+ if (!disable_set)
+ return false;
}
+ }
- CommitRequest request_for_update = commit_request;
- if (status) {
- status &= params.drm->plane_manager()->Commit(
- std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET);
- UpdateControllerStateAfterModeset(params, request_for_update, status);
- }
+ bool commit_status = drm->plane_manager()->Commit(
+ commit_request, DRM_MODE_ATOMIC_ALLOW_MODESET);
- statuses.insert(std::make_pair(params.display_id, status));
- }
+ UpdateControllerStateAfterModeset(drm, commit_request, commit_status);
- return statuses;
+ return commit_status;
}
void ScreenManager::SetDisplayControllerForEnableAndGetProps(
@@ -341,7 +467,7 @@ void ScreenManager::SetDisplayControllerForEnableAndGetProps(
uint32_t connector,
const gfx::Point& origin,
const drmModeModeInfo& mode,
- const DrmOverlayPlane& primary) {
+ const DrmOverlayPlaneList& modeset_planes) {
HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
DCHECK(controllers_.end() != it)
<< "Display controller (crtc=" << crtc << ") doesn't exist.";
@@ -358,10 +484,10 @@ void ScreenManager::SetDisplayControllerForEnableAndGetProps(
// Otherwise it could apply a mode with the same resolution and refresh
// rate but with different timings to the other CRTC.
GetModesetControllerProps(commit_request, controller,
- controller->origin(), mode, primary);
+ controller->origin(), mode, modeset_planes);
} else {
// Just get props to re-enable the controller re-using the current state.
- GetEnableControllerProps(commit_request, controller, primary);
+ GetEnableControllerProps(commit_request, controller, modeset_planes);
}
return;
}
@@ -377,7 +503,8 @@ void ScreenManager::SetDisplayControllerForEnableAndGetProps(
controller = it->get();
}
- GetModesetControllerProps(commit_request, controller, origin, mode, primary);
+ GetModesetControllerProps(commit_request, controller, origin, mode,
+ modeset_planes);
}
bool ScreenManager::SetDisableDisplayControllerForDisableAndGetProps(
@@ -402,31 +529,32 @@ bool ScreenManager::SetDisableDisplayControllerForDisableAndGetProps(
}
void ScreenManager::UpdateControllerStateAfterModeset(
- const ControllerConfigParams& config,
+ const scoped_refptr<DrmDevice>& drm,
const CommitRequest& commit_request,
bool did_succeed) {
- for (auto& crtc_request : commit_request) {
+ for (const CrtcCommitRequest& crtc_request : commit_request) {
bool was_enabled = (crtc_request.should_enable());
HardwareDisplayControllers::iterator it =
- FindDisplayController(config.drm, crtc_request.crtc_id());
+ FindDisplayController(drm, crtc_request.crtc_id());
if (it != controllers_.end()) {
- it->get()->UpdateState(was_enabled, DrmOverlayPlane::GetPrimaryPlane(
- crtc_request.overlays()));
+ it->get()->UpdateState(crtc_request);
// If the CRTC is mirrored, move it to the mirror controller.
if (did_succeed && was_enabled)
- HandleMirrorIfExists(config, it);
+ HandleMirrorIfExists(drm, crtc_request, it);
}
}
}
void ScreenManager::HandleMirrorIfExists(
- const ControllerConfigParams& config,
+ const scoped_refptr<DrmDevice>& drm,
+ const CrtcCommitRequest& crtc_request,
const HardwareDisplayControllers::iterator& controller) {
- gfx::Rect modeset_bounds(config.origin, ModeSize(*config.mode));
+ gfx::Rect modeset_bounds(crtc_request.origin(),
+ ModeSize(crtc_request.mode()));
HardwareDisplayControllers::iterator mirror =
- FindActiveDisplayControllerByLocation(config.drm, modeset_bounds);
+ FindActiveDisplayControllerByLocation(drm, modeset_bounds);
// TODO(dnicoara): This is hacky, instead the DrmDisplay and
// CrtcController should be merged and picking the mode should be done
// properly within HardwareDisplayController.
@@ -434,7 +562,7 @@ void ScreenManager::HandleMirrorIfExists(
// TODO(markyacoub): RemoveCrtc makes a blocking commit to
// DisableOverlayPlanes. This should be redesigned and included as part of
// the Modeset commit.
- (*mirror)->AddCrtc((*controller)->RemoveCrtc(config.drm, config.crtc));
+ (*mirror)->AddCrtc((*controller)->RemoveCrtc(drm, crtc_request.crtc_id()));
controllers_.erase(controller);
}
}
@@ -541,24 +669,30 @@ void ScreenManager::UpdateControllerToWindowMapping() {
// otherwise the controller may be waiting for a page flip while the window
// tries to schedule another buffer.
if (should_enable) {
- DrmOverlayPlane primary_plane = GetModesetBuffer(
+ uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(
+ display::DisplaySnapshot::PrimaryFormat());
+ std::vector<uint64_t> modifiers =
+ controller->GetSupportedModifiers(fourcc_format);
+ DrmOverlayPlaneList modeset_planes = GetModesetPlanes(
controller,
- gfx::Rect(controller->origin(), controller->GetModeSize()),
- GetModifiersForPrimaryFormat(controller));
- DCHECK(primary_plane.buffer);
+ gfx::Rect(controller->origin(), controller->GetModeSize()), modifiers,
+ /*include_overlays=*/true, /*is_testing=*/false);
+ DCHECK(!modeset_planes.empty());
CommitRequest commit_request;
- GetEnableControllerProps(&commit_request, controller, primary_plane);
+ GetEnableControllerProps(&commit_request, controller, modeset_planes);
controller->GetDrmDevice()->plane_manager()->Commit(
std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET);
}
}
}
-DrmOverlayPlane ScreenManager::GetModesetBuffer(
+DrmOverlayPlaneList ScreenManager::GetModesetPlanes(
HardwareDisplayController* controller,
const gfx::Rect& bounds,
- const std::vector<uint64_t>& modifiers) {
+ const std::vector<uint64_t>& modifiers,
+ bool include_overlays,
+ bool is_testing) {
scoped_refptr<DrmDevice> drm = controller->GetDrmDevice();
uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(
display::DisplaySnapshot::PrimaryFormat());
@@ -569,19 +703,27 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer(
fourcc_format, bounds.size(), GBM_BO_USE_SCANOUT, modifiers);
if (!buffer) {
LOG(ERROR) << "Failed to create scanout buffer";
- return DrmOverlayPlane::Error();
+ return DrmOverlayPlaneList();
}
// If the current primary plane matches what we need for the next page flip,
- // we can clone it.
+ // clone all last_submitted_planes (matching primary + overlays).
DrmWindow* window = FindWindowAt(bounds);
if (window) {
- const DrmOverlayPlane* primary = window->GetLastModesetBuffer();
- const DrmDevice* drm = controller->GetDrmDevice().get();
+ const DrmOverlayPlaneList& last_submitted_planes =
+ window->last_submitted_planes();
+ const DrmOverlayPlane* primary =
+ DrmOverlayPlane::GetPrimaryPlane(last_submitted_planes);
if (primary && primary->buffer->size() == bounds.size() &&
- primary->buffer->drm_device() == drm) {
- if (primary->buffer->format_modifier() == buffer->GetFormatModifier())
- return primary->Clone();
+ primary->buffer->drm_device() == controller->GetDrmDevice().get() &&
+ primary->buffer->format_modifier() == buffer->GetFormatModifier()) {
+ if (include_overlays) {
+ return DrmOverlayPlane::Clone(last_submitted_planes);
+ } else {
+ DrmOverlayPlaneList modeset_plane;
+ modeset_plane.push_back(primary->Clone());
+ return modeset_plane;
+ }
}
}
@@ -589,28 +731,32 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer(
drm, buffer.get(), buffer->GetSize(), modifiers);
if (!framebuffer) {
LOG(ERROR) << "Failed to add framebuffer for scanout buffer";
- return DrmOverlayPlane::Error();
+ return DrmOverlayPlaneList();
}
- sk_sp<SkSurface> surface = buffer->GetSurface();
- if (!surface) {
- VLOG(2) << "Can't get a SkSurface from the modeset gbm buffer.";
- } else if (!FillModesetBuffer(drm, controller, surface.get(),
- buffer->GetFormat())) {
- // If we fail to fill the modeset buffer, clear it black to avoid displaying
- // an uninitialized framebuffer.
- surface->getCanvas()->clear(SK_ColorBLACK);
+ if (!is_testing) {
+ sk_sp<SkSurface> surface = buffer->GetSurface();
+ if (!surface) {
+ VLOG(2) << "Can't get a SkSurface from the modeset gbm buffer.";
+ } else if (!FillModesetBuffer(drm, controller, surface.get(), modifiers)) {
+ // If we fail to fill the modeset buffer, clear it black to avoid
+ // displaying an uninitialized framebuffer.
+ surface->getCanvas()->clear(SK_ColorBLACK);
+ }
}
- return DrmOverlayPlane(framebuffer, nullptr);
+
+ DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(framebuffer, nullptr);
+ return modeset_planes;
}
void ScreenManager::GetEnableControllerProps(
CommitRequest* commit_request,
HardwareDisplayController* controller,
- const DrmOverlayPlane& primary) {
+ const DrmOverlayPlaneList& modeset_planes) {
DCHECK(!controller->crtc_controllers().empty());
- controller->GetEnableProps(commit_request, primary);
+ controller->GetEnableProps(commit_request, modeset_planes);
}
void ScreenManager::GetModesetControllerProps(
@@ -618,11 +764,11 @@ void ScreenManager::GetModesetControllerProps(
HardwareDisplayController* controller,
const gfx::Point& origin,
const drmModeModeInfo& mode,
- const DrmOverlayPlane& primary) {
+ const DrmOverlayPlaneList& modeset_planes) {
DCHECK(!controller->crtc_controllers().empty());
controller->set_origin(origin);
- controller->GetModesetProps(commit_request, primary, mode);
+ controller->GetModesetProps(commit_request, modeset_planes, mode);
}
DrmWindow* ScreenManager::FindWindowAt(const gfx::Rect& bounds) const {
diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager.h b/chromium/ui/ozone/platform/drm/gpu/screen_manager.h
index d7ac2810b53..c102c52525d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager.h
@@ -68,7 +68,7 @@ class ScreenManager {
void RemoveDisplayControllers(const CrtcsWithDrmList& controllers_to_remove);
// Enables/Disables the display controller based on if a mode exists.
- base::flat_map<int64_t, bool> ConfigureDisplayControllers(
+ bool ConfigureDisplayControllers(
const ControllerConfigsList& controllers_params);
// Returns a reference to the display controller configured to display within
@@ -98,6 +98,9 @@ class ScreenManager {
std::vector<std::unique_ptr<HardwareDisplayController>>;
using WidgetToWindowMap =
std::unordered_map<gfx::AcceleratedWidget, std::unique_ptr<DrmWindow>>;
+ using CrtcPreferredModifierMap = base::flat_map<
+ uint32_t /*crtc_is*/,
+ std::pair<bool /*modifiers_list.empty()*/, uint64_t /*picked_modifier*/>>;
// Returns an iterator into |controllers_| for the controller identified by
// (|crtc|, |connector|).
@@ -105,13 +108,21 @@ class ScreenManager {
const scoped_refptr<DrmDevice>& drm,
uint32_t crtc);
- base::flat_map<int64_t, bool> TestAndModeset(
+ bool TestAndSetPreferredModifiers(
const ControllerConfigsList& controllers_params);
-
- bool TestModeset(const ControllerConfigsList& controllers_params);
-
- base::flat_map<int64_t, bool> Modeset(
+ bool TestAndSetLinearModifier(
const ControllerConfigsList& controllers_params);
+ // Setting the Preferred modifiers that passed from one of the Modeset Test
+ // functions. The preferred modifiers are used in Modeset.
+ void SetPreferredModifiers(
+ const ControllerConfigsList& controllers_params,
+ const CrtcPreferredModifierMap& crtcs_preferred_modifier);
+ // The planes used for modesetting can have overlays beside the primary, test
+ // if we can modeset with them. If not, return false to indicate that we must
+ // only use the primary plane.
+ bool TestModesetWithOverlays(const ControllerConfigsList& controllers_params);
+ bool Modeset(const ControllerConfigsList& controllers_params,
+ bool can_modeset_with_overlays);
// Configures a display controller to be enabled. The display controller is
// identified by (|crtc|, |connector|) and the controller is to be modeset
@@ -123,7 +134,7 @@ class ScreenManager {
uint32_t connector,
const gfx::Point& origin,
const drmModeModeInfo& mode,
- const DrmOverlayPlane& primary);
+ const DrmOverlayPlaneList& modeset_planes);
// Configures a display controller to be disabled. The display controller is
// identified by |crtc|. Controller modeset props are added into
@@ -135,12 +146,13 @@ class ScreenManager {
const scoped_refptr<DrmDevice>& drm,
uint32_t crtc);
- void UpdateControllerStateAfterModeset(const ControllerConfigParams& config,
+ void UpdateControllerStateAfterModeset(const scoped_refptr<DrmDevice>& drm,
const CommitRequest& commit_request,
bool did_succeed);
void HandleMirrorIfExists(
- const ControllerConfigParams& config,
+ const scoped_refptr<DrmDevice>& drm,
+ const CrtcCommitRequest& crtc_request,
const HardwareDisplayControllers::iterator& controller);
// Returns an iterator into |controllers_| for the controller located at
@@ -154,19 +166,21 @@ class ScreenManager {
const scoped_refptr<DrmDevice>& drm,
const gfx::Rect& bounds);
- DrmOverlayPlane GetModesetBuffer(HardwareDisplayController* controller,
- const gfx::Rect& bounds,
- const std::vector<uint64_t>& modifiers);
+ DrmOverlayPlaneList GetModesetPlanes(HardwareDisplayController* controller,
+ const gfx::Rect& bounds,
+ const std::vector<uint64_t>& modifiers,
+ bool include_overlays,
+ bool is_testing);
// Gets props for modesetting the |controller| using |origin| and |mode|.
void GetModesetControllerProps(CommitRequest* commit_request,
HardwareDisplayController* controller,
const gfx::Point& origin,
const drmModeModeInfo& mode,
- const DrmOverlayPlane& primary);
+ const DrmOverlayPlaneList& modeset_planes);
void GetEnableControllerProps(CommitRequest* commit_request,
HardwareDisplayController* controller,
- const DrmOverlayPlane& primary);
+ const DrmOverlayPlaneList& modeset_planes);
DrmWindow* FindWindowAt(const gfx::Rect& bounds) const;
diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
index d4a1a691a1e..a98d358da52 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
@@ -47,6 +47,7 @@ constexpr uint32_t kSecondaryConnector = kConnectorIdBase + 1;
constexpr uint32_t kPlaneIdBase = 300;
constexpr uint32_t kInFormatsBlobPropIdBase = 400;
+constexpr uint32_t kFbIdPropId = 3005;
constexpr uint32_t kTypePropId = 3010;
constexpr uint32_t kInFormatsPropId = 3011;
@@ -81,7 +82,8 @@ class ScreenManagerTest : public testing::Test {
void InitializeDrmState(ui::MockDrmDevice* drm,
const std::vector<CrtcState>& crtc_states,
- bool is_atomic = true) {
+ bool is_atomic,
+ bool use_modifiers_list = false) {
std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties(
crtc_states.size());
std::map<uint32_t, std::string> crtc_property_names = {
@@ -109,7 +111,7 @@ class ScreenManagerTest : public testing::Test {
{3002, "CRTC_Y"},
{3003, "CRTC_W"},
{3004, "CRTC_H"},
- {3005, "FB_ID"},
+ {kFbIdPropId, "FB_ID"},
{3006, "SRC_X"},
{3007, "SRC_Y"},
{3008, "SRC_W"},
@@ -143,9 +145,17 @@ class ScreenManagerTest : public testing::Test {
: DRM_PLANE_TYPE_OVERLAY;
} else if (pair.first == kInFormatsPropId) {
value = property_id++;
+ std::vector<drm_format_modifier> drm_format_modifiers;
+ if (use_modifiers_list) {
+ for (const auto modifier : supported_modifiers_) {
+ drm_format_modifiers.push_back(
+ {/*formats=*/1, /*offset=*/0, /*pad=*/0, modifier});
+ }
+ }
+
drm->SetPropertyBlob(ui::MockDrmDevice::AllocateInFormatsBlob(
value, crtc_states[crtc_idx].planes[plane_idx].formats,
- std::vector<drm_format_modifier>()));
+ std::move(drm_format_modifiers)));
}
crtc_plane_properties[plane_idx].properties.push_back(
@@ -165,12 +175,15 @@ class ScreenManagerTest : public testing::Test {
connector_property_names.end());
property_names.insert(plane_property_names.begin(),
plane_property_names.end());
+
+ drm->SetModifiersOverhead(modifiers_overhead_);
drm->InitializeState(crtc_properties, connector_properties,
plane_properties, property_names, is_atomic);
}
void InitializeDrmStateWithDefault(ui::MockDrmDevice* drm,
- bool is_atomic = true) {
+ bool is_atomic,
+ bool use_modifiers_list = false) {
// A Sample of CRTC states.
std::vector<CrtcState> crtc_states = {
{/* .planes = */
@@ -182,11 +195,12 @@ class ScreenManagerTest : public testing::Test {
{/* .formats = */ {DRM_FORMAT_XRGB8888}},
}},
};
- InitializeDrmState(drm, crtc_states, is_atomic);
+ InitializeDrmState(drm, crtc_states, is_atomic, use_modifiers_list);
}
void SetUp() override {
auto gbm = std::make_unique<ui::MockGbmDevice>();
+ supported_modifiers_ = gbm->GetSupportedModifiers();
drm_ = new ui::MockDrmDevice(std::move(gbm));
device_manager_ = std::make_unique<ui::DrmDeviceManager>(nullptr);
screen_manager_ = std::make_unique<ui::ScreenManager>();
@@ -218,6 +232,10 @@ class ScreenManagerTest : public testing::Test {
scoped_refptr<ui::MockDrmDevice> drm_;
std::unique_ptr<ui::DrmDeviceManager> device_manager_;
std::unique_ptr<ui::ScreenManager> screen_manager_;
+ std::vector<uint64_t> supported_modifiers_;
+ base::flat_map<uint64_t /*modifier*/, int /*overhead*/> modifiers_overhead_{
+ {DRM_FORMAT_MOD_LINEAR, 1},
+ {I915_FORMAT_MOD_Yf_TILED_CCS, 100}};
private:
DISALLOW_COPY_AND_ASSIGN(ScreenManagerTest);
@@ -231,7 +249,7 @@ TEST_F(ScreenManagerTest, CheckWithNoControllers) {
}
TEST_F(ScreenManagerTest, CheckWithValidController) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
@@ -252,7 +270,7 @@ TEST_F(ScreenManagerTest, CheckWithValidController) {
}
TEST_F(ScreenManagerTest, CheckWithInvalidBounds) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
@@ -268,7 +286,7 @@ TEST_F(ScreenManagerTest, CheckWithInvalidBounds) {
}
TEST_F(ScreenManagerTest, CheckForSecondValidController) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -287,14 +305,104 @@ TEST_F(ScreenManagerTest, CheckForSecondValidController) {
screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_EQ(drm_->get_test_modeset_count(), 1);
- EXPECT_EQ(drm_->get_commit_modeset_count(), 2);
+ EXPECT_EQ(drm_->get_commit_modeset_count(), 1);
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
+TEST_F(ScreenManagerTest, CheckMultipleDisplaysWithinModifiersLimit) {
+ int max_supported_displays_with_modifier = 2;
+ drm_->SetSystemLimitOfModifiers(
+ modifiers_overhead_[I915_FORMAT_MOD_Yf_TILED_CCS] *
+ max_supported_displays_with_modifier);
+
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true,
+ /*use_modifiers_list=*/true);
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ EXPECT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_EQ(drm_->get_test_modeset_count(), 1);
+ EXPECT_EQ(drm_->get_commit_modeset_count(), 1);
+}
+
+TEST_F(ScreenManagerTest, CheckMultipleDisplaysOutsideModifiersLimit) {
+ int max_supported_displays_with_modifier = 2;
+ drm_->SetSystemLimitOfModifiers(modifiers_overhead_[DRM_FORMAT_MOD_LINEAR] *
+ max_supported_displays_with_modifier);
+
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true,
+ /*use_modifiers_list=*/true);
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ EXPECT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ // Testing for a failed test-modeset with modifiers + a fallback to Linear
+ // Modifier and a modeset commit.
+ EXPECT_EQ(drm_->get_test_modeset_count(), 2);
+ EXPECT_EQ(drm_->get_commit_modeset_count(), 1);
+}
+
+TEST_F(ScreenManagerTest, CheckDisplaysWith0Limit) {
+ drm_->SetSystemLimitOfModifiers(0);
+
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true,
+ /*use_modifiers_list=*/true);
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ EXPECT_FALSE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ // Testing for a failed test-modeset with modifiers + failed test-modeset with
+ // Linear Modifier and no modeset due to failed tests.
+ EXPECT_EQ(drm_->get_test_modeset_count(), 2);
+ EXPECT_EQ(drm_->get_commit_modeset_count(), 0);
+}
+
TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
@@ -314,7 +422,7 @@ TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) {
}
TEST_F(ScreenManagerTest, CheckControllerAfterDisabled) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
// Enable
@@ -344,7 +452,7 @@ TEST_F(ScreenManagerTest, CheckControllerAfterDisabled) {
}
TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingRemoved) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -375,7 +483,7 @@ TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingRemoved) {
}
TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingDisabled) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
kSecondaryConnector);
@@ -407,7 +515,7 @@ TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingDisabled) {
EXPECT_EQ(drm_->get_test_modeset_count(),
test_modeset_count_before_disable + 1);
EXPECT_EQ(drm_->get_commit_modeset_count(),
- commit_modeset_count_before_disable + 2);
+ commit_modeset_count_before_disable + 1);
EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
@@ -442,7 +550,7 @@ TEST_F(ScreenManagerTest, CheckDuplicateConfiguration) {
}
TEST_F(ScreenManagerTest, CheckChangingMode) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
@@ -478,7 +586,7 @@ TEST_F(ScreenManagerTest, CheckChangingMode) {
}
TEST_F(ScreenManagerTest, CheckForControllersInMirroredMode) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -517,7 +625,7 @@ TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) {
},
},
};
- InitializeDrmState(drm_.get(), crtc_states);
+ InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -574,7 +682,7 @@ TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) {
// Make sure we're using each display's mode when doing mirror mode otherwise
// the timings may be off.
TEST_F(ScreenManagerTest, CheckMirrorModeModesettingWithDisplaysMode) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -609,7 +717,7 @@ TEST_F(ScreenManagerTest, CheckMirrorModeModesettingWithDisplaysMode) {
}
TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -641,23 +749,29 @@ TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) {
}
TEST_F(ScreenManagerTest, MonitorDisabledInMirrorMode) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
kSecondaryConnector);
- ScreenManager::ControllerConfigsList controllers_to_enable;
- controllers_to_enable.emplace_back(
- kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
- GetPrimaryBounds().origin(),
- std::make_unique<drmModeModeInfo>(kDefaultMode));
- drmModeModeInfo secondary_mode = kDefaultMode;
- controllers_to_enable.emplace_back(
- kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
- GetPrimaryBounds().origin(),
- std::make_unique<drmModeModeInfo>(secondary_mode));
+ // Enable in Mirror Mode.
+ {
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+ }
+
// Disable display Controller.
+ ScreenManager::ControllerConfigsList controllers_to_enable;
controllers_to_enable.emplace_back(0, drm_, kSecondaryCrtc, 0, gfx::Point(),
nullptr);
screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
@@ -672,7 +786,7 @@ TEST_F(ScreenManagerTest, MonitorDisabledInMirrorMode) {
}
TEST_F(ScreenManagerTest, DoNotEnterMirrorModeUnlessSameBounds) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -741,7 +855,7 @@ TEST_F(ScreenManagerTest, ReuseFramebufferIfDisabledThenReEnabled) {
}
TEST_F(ScreenManagerTest, CheckMirrorModeAfterBeginReEnabled) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -839,8 +953,8 @@ TEST_F(ScreenManagerTest,
scoped_refptr<ui::MockDrmDevice> drm2 =
new ui::MockDrmDevice(std::move(gbm_device));
- InitializeDrmStateWithDefault(drm_.get());
- InitializeDrmStateWithDefault(drm2.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
+ InitializeDrmStateWithDefault(drm2.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm2, kPrimaryCrtc, kPrimaryConnector);
@@ -868,7 +982,7 @@ TEST_F(ScreenManagerTest,
}
TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
std::unique_ptr<ui::DrmWindow> window(
new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
@@ -891,7 +1005,7 @@ TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) {
}
TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
std::unique_ptr<ui::DrmWindow> window(
new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
@@ -917,7 +1031,7 @@ TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) {
TEST_F(ScreenManagerTest,
CheckControllerToWindowMappingWithOverlappingWindows) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
const size_t kWindowCount = 2;
for (size_t i = 1; i < kWindowCount + 1; ++i) {
@@ -948,7 +1062,7 @@ TEST_F(ScreenManagerTest,
}
TEST_F(ScreenManagerTest, ShouldDissociateWindowOnControllerRemoval) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
gfx::AcceleratedWidget window_id = 1;
std::unique_ptr<ui::DrmWindow> window(new ui::DrmWindow(
@@ -1105,12 +1219,12 @@ TEST_F(ScreenManagerTest, ShouldNotHardwareMirrorDifferentDrmDevices) {
auto gbm_device1 = std::make_unique<MockGbmDevice>();
auto drm_device1 =
base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device1));
- InitializeDrmStateWithDefault(drm_device1.get());
+ InitializeDrmStateWithDefault(drm_device1.get(), /*is_atomic=*/true);
auto gbm_device2 = std::make_unique<MockGbmDevice>();
auto drm_device2 =
base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device2));
- InitializeDrmStateWithDefault(drm_device2.get());
+ InitializeDrmStateWithDefault(drm_device2.get(), /*is_atomic=*/true);
DrmDeviceManager drm_device_manager(nullptr);
ScreenManager screen_manager;
@@ -1310,4 +1424,315 @@ TEST_F(ScreenManagerTest, ShouldNotUnbindFramebufferOnJoiningMirror) {
screen_manager.RemoveWindow(1)->Shutdown();
}
+TEST_F(ScreenManagerTest, DrmFramebufferSequenceIdIncrementingAtModeset) {
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
+
+ scoped_refptr<DrmFramebuffer> pre_modeset_buffer =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0);
+
+ // Successful modeset
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ {
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+ }
+
+ scoped_refptr<DrmFramebuffer> first_post_modeset_buffer =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ CHECK_EQ(first_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1);
+ CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0);
+
+ // Unsuccessful modeset
+ {
+ drm_->set_set_crtc_expectation(false);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_FALSE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+ }
+
+ scoped_refptr<DrmFramebuffer> second_post_modeset_buffer =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ CHECK_EQ(second_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1);
+ CHECK_EQ(first_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1);
+ CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0);
+}
+
+TEST_F(ScreenManagerTest, CloningPlanesOnModeset) {
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
+
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+ scoped_refptr<DrmFramebuffer> buffer =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(buffer, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ buffer));
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, CloningMultiplePlanesOnModeset) {
+ std::vector<CrtcState> crtc_states = {{
+ /* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ },
+ }};
+ InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
+
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+ scoped_refptr<DrmFramebuffer> primary =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ scoped_refptr<DrmFramebuffer> overlay =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(primary, nullptr));
+ planes.push_back(ui::DrmOverlayPlane(overlay, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ primary));
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ overlay));
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, ModesetWithClonedPlanesNoOverlays) {
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
+
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+ scoped_refptr<DrmFramebuffer> buffer =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(buffer, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+ ASSERT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ buffer));
+
+ EXPECT_EQ(drm_->get_test_modeset_count(), 1);
+ EXPECT_EQ(drm_->last_planes_committed_count(), 1);
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, ModesetWithClonedPlanesWithOverlaySucceeding) {
+ std::vector<CrtcState> crtc_states = {{
+ /* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ },
+ }};
+ InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
+
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+ scoped_refptr<DrmFramebuffer> primary =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ scoped_refptr<DrmFramebuffer> overlay =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(primary, nullptr));
+ planes.push_back(ui::DrmOverlayPlane(overlay, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ primary));
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ overlay));
+
+ EXPECT_EQ(drm_->get_test_modeset_count(), 2);
+ EXPECT_EQ(drm_->last_planes_committed_count(), 2);
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, ModesetWithClonedPlanesWithOverlayFailing) {
+ std::vector<CrtcState> crtc_states = {{
+ /* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ },
+ }};
+ InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
+
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+ scoped_refptr<DrmFramebuffer> primary =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ scoped_refptr<DrmFramebuffer> overlay =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(primary, nullptr));
+ planes.push_back(ui::DrmOverlayPlane(overlay, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ drm_->set_overlay_modeset_expecation(false);
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ EXPECT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ primary));
+ EXPECT_FALSE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ overlay));
+
+ EXPECT_EQ(drm_->get_test_modeset_count(), 2);
+ EXPECT_EQ(drm_->last_planes_committed_count(), 1);
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, ModesetWithNewBuffersOnModifiersChange) {
+ std::vector<CrtcState> crtc_states = {{
+ /* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ },
+ }};
+ InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true,
+ /*use_modifiers_list=*/true);
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+
+ scoped_refptr<DrmFramebuffer> primary =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ scoped_refptr<DrmFramebuffer> overlay =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(primary, nullptr));
+ planes.push_back(ui::DrmOverlayPlane(overlay, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_FALSE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ primary));
+ EXPECT_FALSE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ overlay));
+
+ // Testing test modifiers only, no linear or overlays test.
+ EXPECT_EQ(drm_->get_test_modeset_count(), 1);
+ EXPECT_EQ(drm_->last_planes_committed_count(), 1);
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
index afed5c26d24..5b433602330 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
@@ -8,11 +8,12 @@
#include <utility>
#include "base/trace_event/trace_event.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/ozone/platform/drm/host/drm_window_host.h"
#include "ui/ozone/platform/drm/host/drm_window_host_manager.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/events/ozone/chromeos/cursor_controller.h"
#endif
@@ -192,7 +193,7 @@ void DrmCursor::MoveCursor(const gfx::Vector2dF& delta) {
if (window_ == gfx::kNullAcceleratedWidget)
return;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
gfx::Vector2dF transformed_delta = delta;
ui::CursorController::GetInstance()->ApplyCursorConfigForWindow(
window_, &transformed_delta);
@@ -232,7 +233,7 @@ void DrmCursor::SetCursorLocationLocked(const gfx::PointF& location) {
gfx::PointF(confined_bounds_.right() - 1, confined_bounds_.bottom() - 1));
location_ = clamped_location;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ui::CursorController::GetInstance()->SetCursorLocation(location_);
#endif
}
diff --git a/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc
index 975da5c6ab3..32818432bd4 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -237,15 +237,11 @@ void DrmDisplayHostManager::UpdateDisplays(
void DrmDisplayHostManager::ConfigureDisplays(
const std::vector<display::DisplayConfigurationParams>& config_requests,
display::ConfigureCallback callback) {
- base::flat_map<int64_t, bool> dummy_statuses;
- bool is_any_dummy = false;
for (auto& config : config_requests) {
- is_any_dummy |= GetDisplay(config.id)->is_dummy();
- dummy_statuses.insert(std::make_pair(config.id, true));
- }
- if (is_any_dummy) {
- std::move(callback).Run(dummy_statuses);
- return;
+ if (GetDisplay(config.id)->is_dummy()) {
+ std::move(callback).Run(true);
+ return;
+ }
}
proxy_->GpuConfigureNativeDisplays(config_requests, std::move(callback));
diff --git a/chromium/ui/ozone/platform/drm/host/host_drm_device.cc b/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
index 1c6c2b9ac58..9cd757ceeb6 100644
--- a/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
+++ b/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
@@ -136,16 +136,11 @@ void HostDrmDevice::GpuConfigureNativeDisplays(
if (IsConnected()) {
drm_device_->ConfigureNativeDisplays(config_requests, std::move(callback));
} else {
- // If not connected, report failure to config.
- base::flat_map<int64_t, bool> dummy_statuses;
- for (const auto& config : config_requests)
- dummy_statuses.insert(std::make_pair(config.id, false));
-
// Post this task to protect the callstack from accumulating too many
// recursive calls to ConfigureDisplaysTask::Run() in cases in which the GPU
// process crashes repeatedly.
base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), dummy_statuses));
+ FROM_HERE, base::BindOnce(std::move(callback), false));
}
}
diff --git a/chromium/ui/ozone/platform/drm/ozone_platform_drm.cc b/chromium/ui/ozone/platform/drm/ozone_platform_drm.cc
index 8a6442257df..aceccb83583 100644
--- a/chromium/ui/ozone/platform/drm/ozone_platform_drm.cc
+++ b/chromium/ui/ozone/platform/drm/ozone_platform_drm.cc
@@ -18,6 +18,7 @@
#include "base/notreached.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/chromeos_buildflags.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "ui/base/buildflags.h"
@@ -58,7 +59,7 @@
#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/base/ime/chromeos/input_method_chromeos.h"
#else
#include "ui/base/ime/input_method_minimal.h"
@@ -174,7 +175,7 @@ class OzonePlatformDrm : public OzonePlatform {
std::unique_ptr<InputMethod> CreateInputMethod(
internal::InputMethodDelegate* delegate,
gfx::AcceleratedWidget) override {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return std::make_unique<InputMethodChromeOS>(delegate);
#else
return std::make_unique<InputMethodMinimal>(delegate);
@@ -230,6 +231,12 @@ class OzonePlatformDrm : public OzonePlatform {
}
void InitializeGPU(const InitParams& args) override {
+ // Check if buffer bandwidth compression is disabled
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableBufferBWCompression)) {
+ setenv("MINIGBM_DEBUG", "nocompression", 1);
+ }
+
gpu_task_runner_ = base::ThreadTaskRunnerHandle::Get();
// NOTE: Can't start the thread here since this is called before sandbox
@@ -239,8 +246,9 @@ class OzonePlatformDrm : public OzonePlatform {
surface_factory_ =
std::make_unique<GbmSurfaceFactory>(drm_thread_proxy_.get());
- overlay_manager_ =
- std::make_unique<DrmOverlayManagerGpu>(drm_thread_proxy_.get());
+ overlay_manager_ = std::make_unique<DrmOverlayManagerGpu>(
+ drm_thread_proxy_.get(),
+ args.allow_sync_and_real_buffer_page_flip_testing);
// If gpu is in a separate process, rest of the initialization happens after
// entering the sandbox.
diff --git a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
index 01107a50f94..f6e70bb27fa 100644
--- a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
+++ b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
@@ -89,11 +89,7 @@ class OzonePlatformHeadless : public OzonePlatform {
std::unique_ptr<InputMethod> CreateInputMethod(
internal::InputMethodDelegate* delegate,
gfx::AcceleratedWidget widget) override {
-#if defined(OS_FUCHSIA)
- return std::make_unique<InputMethodFuchsia>(delegate, widget);
-#else
return std::make_unique<InputMethodMinimal>(delegate);
-#endif
}
void InitializeUI(const InitParams& params) override {
diff --git a/chromium/ui/ozone/platform/scenic/overlay_manager_scenic.cc b/chromium/ui/ozone/platform/scenic/overlay_manager_scenic.cc
index e8e4b816710..7ec96d5e05a 100644
--- a/chromium/ui/ozone/platform/scenic/overlay_manager_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/overlay_manager_scenic.cc
@@ -32,7 +32,10 @@ class OverlayCandidatesScenic : public OverlayCandidatesOzone {
} // namespace
-OverlayManagerScenic::OverlayManagerScenic() {}
+OverlayManagerScenic::OverlayManagerScenic() {
+ // Fuchsia overlays rely on ShouldUseRealBuffersForPageFlipTest.
+ allow_sync_and_real_buffer_page_flip_testing_ = true;
+}
OverlayManagerScenic::~OverlayManagerScenic() = default;
diff --git a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
index 35827691a17..5769845402e 100644
--- a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
@@ -131,7 +131,8 @@ class OzonePlatformScenic : public OzonePlatform,
std::unique_ptr<InputMethod> CreateInputMethod(
internal::InputMethodDelegate* delegate,
gfx::AcceleratedWidget widget) override {
- return std::make_unique<InputMethodFuchsia>(delegate, widget);
+ return std::make_unique<InputMethodFuchsia>(
+ delegate, window_manager_->GetWindow(widget)->CloneViewRef());
}
void InitializeUI(const InitParams& params) override {
diff --git a/chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc b/chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc
index a9709908586..f7e30451b70 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc
@@ -50,6 +50,9 @@ ScenicOverlayView::~ScenicOverlayView() {
surface->AssertBelongsToCurrentThread();
surface->RemoveOverlayView(buffer_collection_id_);
}
+
+ // Releasing |image_pipe_| implicitly also enforces cleanup.
+ image_pipe_->RemoveBufferCollection(kImagePipeBufferCollectionId);
}
void ScenicOverlayView::Initialize(
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
index d1e03bbb990..f9066115081 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
@@ -243,6 +243,7 @@ void ScenicSurfaceFactory::CreateNativePixmapAsync(
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
ScenicSurfaceFactory::CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) {
return std::make_unique<ui::VulkanImplementationScenic>(
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
index b0454ac45cb..20f7dca7608 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
@@ -63,6 +63,7 @@ class ScenicSurfaceFactory : public SurfaceFactoryOzone {
NativePixmapCallback callback) override;
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) override;
#endif
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window.cc b/chromium/ui/ozone/platform/scenic/scenic_window.cc
index 330fe7de65f..b25ec452a2b 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_window.cc
@@ -29,10 +29,11 @@ ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager,
window_id_(manager_->AddWindow(this)),
event_dispatcher_(this),
scenic_session_(manager_->GetScenic()),
+ view_ref_(std::move(properties.view_ref_pair.view_ref)),
view_(&scenic_session_,
std::move(std::move(properties.view_token)),
std::move(properties.view_ref_pair.control_ref),
- std::move(properties.view_ref_pair.view_ref),
+ CloneViewRef(),
"chromium window"),
node_(&scenic_session_),
input_node_(&scenic_session_),
@@ -245,6 +246,14 @@ void ScenicWindow::UpdateSize() {
delegate_->OnBoundsChanged(bounds_);
}
+fuchsia::ui::views::ViewRef ScenicWindow::CloneViewRef() {
+ fuchsia::ui::views::ViewRef dup;
+ zx_status_t status =
+ view_ref_.reference.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup.reference);
+ ZX_CHECK(status == ZX_OK, status) << "zx_object_duplicate";
+ return dup;
+}
+
void ScenicWindow::OnScenicError(zx_status_t status) {
LOG(ERROR) << "scenic::Session failed 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 2981db6cde8..3bf566cdca0 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_window.h
@@ -49,6 +49,9 @@ class COMPONENT_EXPORT(OZONE) ScenicWindow
// causing its contents to be displayed in this window.
void AttachSurfaceView(fuchsia::ui::views::ViewHolderToken token);
+ // Returns a ViewRef associated with this window.
+ fuchsia::ui::views::ViewRef CloneViewRef();
+
// PlatformWindow implementation.
gfx::Rect GetBounds() const override;
void SetBounds(const gfx::Rect& bounds) override;
@@ -107,6 +110,11 @@ class COMPONENT_EXPORT(OZONE) ScenicWindow
// Scenic session used for all drawing operations in this View.
scenic::Session scenic_session_;
+ // Handle to a kernel object which identifies this window's View
+ // across the system. ViewRef consumers can access the handle by
+ // calling CloneViewRef().
+ fuchsia::ui::views::ViewRef view_ref_;
+
// The view resource in |scenic_session_|.
scenic::View view_;
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
index 9487bcaea42..6a3dee239f9 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
@@ -140,8 +140,9 @@ bool SysmemBufferCollection::Initialize(
is_protected_ = force_protected;
if (register_with_image_pipe) {
- scenic_overlay_view_.emplace(scenic_surface_factory->CreateScenicSession(),
- scenic_surface_factory);
+ overlay_view_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ scenic_overlay_view_ = std::make_unique<ScenicOverlayView>(
+ scenic_surface_factory->CreateScenicSession(), scenic_surface_factory);
surface_factory_ = scenic_surface_factory;
}
@@ -335,6 +336,12 @@ SysmemBufferCollection::~SysmemBufferCollection() {
if (on_deleted_)
std::move(on_deleted_).Run();
+
+ if (scenic_overlay_view_ &&
+ !overlay_view_task_runner_->BelongsToCurrentThread()) {
+ overlay_view_task_runner_->DeleteSoon(FROM_HERE,
+ std::move(scenic_overlay_view_));
+ }
}
bool SysmemBufferCollection::InitializeInternal(
@@ -350,7 +357,7 @@ bool SysmemBufferCollection::InitializeInternal(
// overlay.
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
collection_token_for_scenic;
- if (scenic_overlay_view_.has_value()) {
+ if (scenic_overlay_view_) {
collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
collection_token_for_scenic.NewRequest());
}
@@ -361,7 +368,7 @@ bool SysmemBufferCollection::InitializeInternal(
return false;
}
- if (scenic_overlay_view_.has_value()) {
+ if (scenic_overlay_view_) {
scenic_overlay_view_->Initialize(std::move(collection_token_for_scenic));
}
@@ -450,7 +457,7 @@ bool SysmemBufferCollection::InitializeInternal(
is_protected_ = buffers_info_.settings.buffer_settings.is_secure;
// Add all images to Image pipe for presentation later.
- if (scenic_overlay_view_.has_value()) {
+ if (scenic_overlay_view_) {
scenic_overlay_view_->AddImages(buffers_info_.buffer_count, image_size_);
}
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
index 873ddbeccce..6a3ce46bd6b 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "gpu/ipc/common/vulkan_ycbcr_info.h"
#include "gpu/vulkan/fuchsia/vulkan_fuchsia_ext.h"
@@ -88,8 +89,7 @@ class SysmemBufferCollection
return buffers_info_.settings.buffer_settings.size_bytes;
}
ScenicOverlayView* scenic_overlay_view() {
- return scenic_overlay_view_.has_value() ? &scenic_overlay_view_.value()
- : nullptr;
+ return scenic_overlay_view_ ? scenic_overlay_view_.get() : nullptr;
}
ScenicSurfaceFactory* surface_factory() { return surface_factory_; }
@@ -131,10 +131,13 @@ class SysmemBufferCollection
// that is referenced by |collection_|.
VkBufferCollectionFUCHSIA vk_buffer_collection_ = VK_NULL_HANDLE;
+ // |scenic_overlay_view_| view should be used and deleted on the same thread
+ // as creation.
+ scoped_refptr<base::SingleThreadTaskRunner> overlay_view_task_runner_;
// If ScenicOverlayView is created and its ImagePipe is added as a participant
// in buffer allocation negotiations, the associated images can be displayed
// as overlays.
- base::Optional<ScenicOverlayView> scenic_overlay_view_;
+ std::unique_ptr<ScenicOverlayView> scenic_overlay_view_;
ScenicSurfaceFactory* surface_factory_ = nullptr;
// Thread checker used to verify that CreateVkImage() is always called from
diff --git a/chromium/ui/ozone/platform/wayland/BUILD.gn b/chromium/ui/ozone/platform/wayland/BUILD.gn
index 46447f33e84..d1aab09a3a6 100644
--- a/chromium/ui/ozone/platform/wayland/BUILD.gn
+++ b/chromium/ui/ozone/platform/wayland/BUILD.gn
@@ -18,7 +18,6 @@ source_set("wayland") {
"client_native_pixmap_factory_wayland.h",
"common/data_util.cc",
"common/data_util.h",
- "common/wayland.cc",
"common/wayland.h",
"common/wayland_object.cc",
"common/wayland_object.h",
@@ -51,8 +50,9 @@ source_set("wayland") {
"host/shell_object_factory.h",
"host/shell_popup_wrapper.cc",
"host/shell_popup_wrapper.h",
- "host/shell_surface_wrapper.cc",
"host/shell_surface_wrapper.h",
+ "host/shell_toplevel_wrapper.cc",
+ "host/shell_toplevel_wrapper.h",
"host/wayland_auxiliary_window.cc",
"host/wayland_auxiliary_window.h",
"host/wayland_buffer_manager_connector.cc",
@@ -65,6 +65,8 @@ source_set("wayland") {
"host/wayland_connection.h",
"host/wayland_cursor.cc",
"host/wayland_cursor.h",
+ "host/wayland_cursor_factory.cc",
+ "host/wayland_cursor_factory.h",
"host/wayland_cursor_position.cc",
"host/wayland_cursor_position.h",
"host/wayland_data_device.cc",
@@ -138,6 +140,8 @@ source_set("wayland") {
"host/xdg_popup_wrapper_impl.h",
"host/xdg_surface_wrapper_impl.cc",
"host/xdg_surface_wrapper_impl.h",
+ "host/xdg_toplevel_wrapper_impl.cc",
+ "host/xdg_toplevel_wrapper_impl.h",
"host/zwp_primary_selection_device.cc",
"host/zwp_primary_selection_device.h",
"host/zwp_primary_selection_device_manager.cc",
@@ -147,6 +151,12 @@ source_set("wayland") {
"host/zwp_text_input_wrapper.h",
"host/zwp_text_input_wrapper_v1.cc",
"host/zwp_text_input_wrapper_v1.h",
+ "host/zxdg_popup_v6_wrapper_impl.cc",
+ "host/zxdg_popup_v6_wrapper_impl.h",
+ "host/zxdg_surface_v6_wrapper_impl.cc",
+ "host/zxdg_surface_v6_wrapper_impl.h",
+ "host/zxdg_toplevel_v6_wrapper_impl.cc",
+ "host/zxdg_toplevel_v6_wrapper_impl.h",
"ozone_platform_wayland.cc",
"ozone_platform_wayland.h",
]
@@ -182,6 +192,7 @@ source_set("wayland") {
"//ui/base:buildflags",
"//ui/base/cursor",
"//ui/base/cursor:cursor_base",
+ "//ui/base/cursor:theme_manager",
"//ui/base/cursor/mojom:cursor_type",
"//ui/base/ime/linux",
"//ui/events",
@@ -202,7 +213,7 @@ source_set("wayland") {
"//ui/platform_window/wm",
]
- if (is_linux && !is_chromeos) {
+ if (is_linux || is_chromeos_lacros) {
deps += [ "//ui/base/ime/linux" ]
}
@@ -217,9 +228,12 @@ source_set("wayland") {
]
}
- # TODO(crbug.com/1052397): Rename chromeos_is_browser_only to is_lacros.
- if (chromeos_is_browser_only) {
- deps += [ "//chromeos/crosapi/cpp" ]
+ if (is_chromeos_lacros) {
+ deps += [
+ "//chromeos/crosapi/cpp",
+ "//chromeos/crosapi/mojom",
+ "//chromeos/lacros",
+ ]
}
defines = [ "OZONE_IMPLEMENTATION" ]
@@ -230,6 +244,7 @@ source_set("wayland") {
} else {
deps += [
"//third_party/wayland:wayland_client",
+ "//third_party/wayland:wayland_cursor",
"//third_party/wayland:wayland_egl",
]
}
@@ -357,9 +372,11 @@ source_set("wayland_unittests") {
testonly = true
sources = [
+ "common/wayland_util_unittest.cc",
"gpu/wayland_overlay_manager_unittest.cc",
+ "host/wayland_clipboard_unittest.cc",
"host/wayland_connection_unittest.cc",
- "host/wayland_data_device_unittest.cc",
+ "host/wayland_cursor_factory_unittest.cc",
"host/wayland_data_drag_controller_unittest.cc",
"host/wayland_event_source_unittest.cc",
"host/wayland_input_method_context_unittest.cc",
@@ -370,6 +387,9 @@ source_set("wayland_unittests") {
"host/wayland_window_drag_controller_unittest.cc",
"host/wayland_window_manager_unittests.cc",
"host/wayland_window_unittest.cc",
+ "host/wayland_zaura_shell_unittest.cc",
+ "test/wayland_drag_drop_test.cc",
+ "test/wayland_drag_drop_test.h",
"test/wayland_test.cc",
"test/wayland_test.h",
]
@@ -377,6 +397,7 @@ source_set("wayland_unittests") {
deps = [
":test_support",
":wayland",
+ "//components/exo/wayland/protocol:aura_shell_protocol",
"//testing/gmock",
"//testing/gtest",
"//third_party/wayland:wayland_server",
diff --git a/chromium/ui/ozone/platform/wayland/DEPS b/chromium/ui/ozone/platform/wayland/DEPS
index 1eeae79d79e..b7393cb1394 100644
--- a/chromium/ui/ozone/platform/wayland/DEPS
+++ b/chromium/ui/ozone/platform/wayland/DEPS
@@ -7,7 +7,7 @@ include_rules = [
"+third_party/wayland",
"+ui/base/clipboard/clipboard_constants.h",
"+ui/base/dragdrop/drag_drop_types.h",
- "+ui/base/dragdrop/file_info/file_info.h",
+ "+ui/base/clipboard/file_info.h",
"+ui/base/dragdrop/os_exchange_data.h",
"+ui/base/dragdrop/os_exchange_data_provider_non_backed.h",
]
diff --git a/chromium/ui/ozone/platform/wayland/common/data_util.cc b/chromium/ui/ozone/platform/wayland/common/data_util.cc
index 90773668cde..94c84236a2c 100644
--- a/chromium/ui/ozone/platform/wayland/common/data_util.cc
+++ b/chromium/ui/ozone/platform/wayland/common/data_util.cc
@@ -12,7 +12,7 @@
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
#include "ui/ozone/public/platform_clipboard.h"
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland.cc b/chromium/ui/ozone/platform/wayland/common/wayland.cc
deleted file mode 100644
index 8a20e3a7be3..00000000000
--- a/chromium/ui/ozone/platform/wayland/common/wayland.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2020 The Chromium 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/wayland/common/wayland.h"
-
-namespace wl {
-
-void* bind_registry(struct wl_registry* registry,
- uint32_t name,
- const struct wl_interface* interface,
- uint32_t version) {
- if (dlsym(RTLD_DEFAULT, "wl_proxy_marshal_constructor_versioned")) {
- return wl_registry_bind(registry, name, interface, version);
- } else {
- return wl_proxy_marshal_constructor(reinterpret_cast<wl_proxy*>(registry),
- WL_REGISTRY_BIND, interface, name,
- interface->name, version, nullptr);
- }
- NOTREACHED();
- return nullptr;
-}
-
-} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland.h b/chromium/ui/ozone/platform/wayland/common/wayland.h
index c645346ddcb..fd8ff58bf7d 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland.h
+++ b/chromium/ui/ozone/platform/wayland/common/wayland.h
@@ -5,26 +5,22 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_H_
#define UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_H_
-#include <dlfcn.h>
-// This header includes wayland-client-core.h and wayland-client-protocol.h
#include <wayland-client.h>
-#include "base/notreached.h"
-
namespace wl {
template <typename T>
uint32_t get_version_of_object(T* obj) {
- if (dlsym(RTLD_DEFAULT, "wl_proxy_get_version"))
- return wl_proxy_get_version(reinterpret_cast<wl_proxy*>(obj));
- // Older version of the libwayland-client didn't support version of objects.
- return 0;
+ return wl_proxy_get_version(reinterpret_cast<wl_proxy*>(obj));
}
-void* bind_registry(struct wl_registry* registry,
- uint32_t name,
- const struct wl_interface* interface,
- uint32_t version);
+template <typename T>
+T* bind_registry(struct wl_registry* registry,
+ uint32_t name,
+ const struct wl_interface* interface,
+ uint32_t version) {
+ return static_cast<T*>(wl_registry_bind(registry, name, interface, version));
+}
} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_object.cc b/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
index 7a6c5e7b849..8827a5e9f49 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
@@ -15,6 +15,7 @@
#include <primary-selection-unstable-v1-client-protocol.h>
#include <text-input-unstable-v1-client-protocol.h>
#include <viewporter-client-protocol.h>
+#include <wayland-cursor.h>
#include <wayland-drm-client-protocol.h>
#include <xdg-decoration-unstable-v1-client-protocol.h>
#include <xdg-foreign-unstable-v1-client-protocol.h>
@@ -131,6 +132,9 @@ const wl_interface* ObjectTraits<wl_compositor>::interface =
void (*ObjectTraits<wl_compositor>::deleter)(wl_compositor*) =
&wl_compositor_destroy;
+void (*ObjectTraits<wl_cursor_theme>::deleter)(wl_cursor_theme*) =
+ &wl_cursor_theme_destroy;
+
const wl_interface* ObjectTraits<wl_data_device_manager>::interface =
&wl_data_device_manager_interface;
void (*ObjectTraits<wl_data_device_manager>::deleter)(wl_data_device_manager*) =
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_object.h b/chromium/ui/ozone/platform/wayland/common/wayland_object.h
index b06cf876f91..d609c6150fa 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_object.h
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_object.h
@@ -20,6 +20,7 @@ struct zwp_primary_selection_source_v1;
struct wl_buffer;
struct wl_callback;
struct wl_compositor;
+struct wl_cursor_theme;
struct wl_data_device_manager;
struct wl_data_device;
struct wl_data_offer;
@@ -154,6 +155,11 @@ struct ObjectTraits<wl_compositor> {
};
template <>
+struct ObjectTraits<wl_cursor_theme> {
+ static void (*deleter)(wl_cursor_theme*);
+};
+
+template <>
struct ObjectTraits<wl_data_device_manager> {
static const wl_interface* interface;
static void (*deleter)(wl_data_device_manager*);
@@ -462,8 +468,8 @@ class Object : public std::unique_ptr<T, Deleter> {
template <typename T>
wl::Object<T> Bind(wl_registry* registry, uint32_t name, uint32_t version) {
- return wl::Object<T>(static_cast<T*>(
- wl::bind_registry(registry, name, ObjectTraits<T>::interface, version)));
+ return wl::Object<T>(wl::bind_registry<T>(
+ registry, name, ObjectTraits<T>::interface, version));
}
} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util.cc b/chromium/ui/ozone/platform/wayland/common/wayland_util.cc
index 042cfc8e96b..6d7b05906af 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_util.cc
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.cc
@@ -7,7 +7,11 @@
#include <xdg-shell-client-protocol.h>
#include <xdg-shell-unstable-v6-client-protocol.h>
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRegion.h"
#include "ui/base/hit_test.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gfx/transform.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
@@ -131,7 +135,7 @@ bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer) {
// Clear to transparent in case |bitmap| is smaller than the canvas.
auto* canvas = sk_surface->getCanvas();
canvas->clear(SK_ColorTRANSPARENT);
- canvas->drawBitmapRect(bitmap, damage, nullptr);
+ canvas->drawImageRect(bitmap.asImage(), damage, SkSamplingOptions());
return true;
}
@@ -276,4 +280,26 @@ gfx::Rect TranslateWindowBoundsToParentDIP(ui::WaylandWindow* window,
1.0 / window->buffer_scale());
}
+std::vector<gfx::Rect> CreateRectsFromSkPath(const SkPath& path) {
+ SkRegion clip_region;
+ clip_region.setRect(path.getBounds().round());
+ SkRegion region;
+ region.setPath(path, clip_region);
+
+ std::vector<gfx::Rect> rects;
+ for (SkRegion::Iterator it(region); !it.done(); it.next())
+ rects.push_back(gfx::SkIRectToRect(it.rect()));
+
+ return rects;
+}
+
+SkPath ConvertPathToDIP(const SkPath& path_in_pixels, const int32_t scale) {
+ SkScalar sk_scale = SkFloatToScalar(1.0f / scale);
+ gfx::Transform transform;
+ transform.Scale(sk_scale, sk_scale);
+ SkPath path_in_dips;
+ path_in_pixels.transform(SkMatrix(transform.matrix()), &path_in_dips);
+ return path_in_dips;
+}
+
} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util.h b/chromium/ui/ozone/platform/wayland/common/wayland_util.h
index d755de9e0ba..8d8b12f9cc1 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_util.h
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.h
@@ -17,6 +17,7 @@
#include "ui/platform_window/platform_window_init_properties.h"
class SkBitmap;
+class SkPath;
namespace ui {
class WaylandConnection;
@@ -87,6 +88,12 @@ ui::WaylandWindow* RootWindowFromWlSurface(wl_surface* surface);
gfx::Rect TranslateWindowBoundsToParentDIP(ui::WaylandWindow* window,
ui::WaylandWindow* parent_window);
+// Returns rectangles dictated by SkPath.
+std::vector<gfx::Rect> CreateRectsFromSkPath(const SkPath& path);
+
+// Returns converted SkPath in DIPs from the one in pixels.
+SkPath ConvertPathToDIP(const SkPath& path_in_pixels, const int32_t scale);
+
} // namespace wl
#endif // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util_unittest.cc b/chromium/ui/ozone/platform/wayland/common/wayland_util_unittest.cc
new file mode 100644
index 00000000000..57a3669cb30
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_util_unittest.cc
@@ -0,0 +1,71 @@
+// Copyright 2020 The Chromium 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/wayland/common/wayland_util.h"
+
+#include <memory>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRect.h"
+
+namespace ui {
+
+class WaylandUtilTest : public testing::Test {};
+
+TEST_F(WaylandUtilTest, TestCreateRectsFromSkPath) {
+ constexpr int width = 100;
+ constexpr int height = 100;
+
+ // Test1 consists of 2 rectangles from SkPath.
+ std::vector<gfx::Rect> expectedFor2Rects = {gfx::Rect(1, 0, 98, 1),
+ gfx::Rect(0, 1, 100, 99)};
+ SkPath pathFor2Rects;
+ const SkRect rect = SkRect::MakeIWH(width, height);
+ constexpr SkScalar corner_radius_scalar = 2.0;
+ constexpr SkScalar radii[8] = {corner_radius_scalar,
+ corner_radius_scalar, // top-left
+ corner_radius_scalar,
+ corner_radius_scalar, // top-right
+ 0,
+ 0, // bottom-right
+ 0,
+ 0}; // bottom-left
+ pathFor2Rects.addRoundRect(rect, radii, SkPathDirection::kCW);
+ EXPECT_EQ(expectedFor2Rects, wl::CreateRectsFromSkPath(pathFor2Rects));
+
+ // Test2 consists of 5 rectangles from SkPath.
+ std::vector<gfx::Rect> expectedFor5Rects = {
+ gfx::Rect(3, 0, 94, 1), gfx::Rect(1, 1, 98, 2), gfx::Rect(0, 3, 100, 94),
+ gfx::Rect(1, 97, 98, 2), gfx::Rect(3, 99, 94, 1)};
+ SkPath pathFor5Rects;
+ pathFor5Rects.moveTo(0, 3);
+ pathFor5Rects.lineTo(1, 3);
+ pathFor5Rects.lineTo(1, 1);
+ pathFor5Rects.lineTo(3, 1);
+ pathFor5Rects.lineTo(3, 0);
+
+ pathFor5Rects.lineTo(width - 3, 0);
+ pathFor5Rects.lineTo(width - 3, 1);
+ pathFor5Rects.lineTo(width - 1, 1);
+ pathFor5Rects.lineTo(width - 1, 3);
+ pathFor5Rects.lineTo(width, 3);
+
+ pathFor5Rects.lineTo(width, height - 3);
+ pathFor5Rects.lineTo(width - 1, height - 3);
+ pathFor5Rects.lineTo(width - 1, height - 1);
+ pathFor5Rects.lineTo(width - 3, height - 1);
+ pathFor5Rects.lineTo(width - 3, height);
+
+ pathFor5Rects.lineTo(3, height);
+ pathFor5Rects.lineTo(3, height - 1);
+ pathFor5Rects.lineTo(1, height - 1);
+ pathFor5Rects.lineTo(1, height - 3);
+ pathFor5Rects.lineTo(0, height - 3);
+ pathFor5Rects.close();
+
+ EXPECT_EQ(expectedFor5Rects, wl::CreateRectsFromSkPath(pathFor5Rects));
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
index 1b15b1c27f7..827cd1c9b7d 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
@@ -11,6 +11,8 @@
#include "base/task/thread_pool.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/gpu_fence.h"
+#include "ui/gfx/gpu_fence_handle.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h"
#include "ui/ozone/public/mojom/wayland/wayland_overlay_config.mojom.h"
@@ -19,12 +21,6 @@ namespace ui {
namespace {
-void WaitForEGLFence(EGLDisplay display, EGLSyncKHR fence) {
- eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
- EGL_FOREVER_KHR);
- eglDestroySyncKHR(display, fence);
-}
-
void WaitForGpuFences(std::vector<std::unique_ptr<gfx::GpuFence>> fences) {
for (auto& fence : fences)
fence->Wait();
@@ -60,9 +56,9 @@ bool GbmSurfacelessWayland::ScheduleOverlayPlane(
const gfx::RectF& crop_rect,
bool enable_blend,
std::unique_ptr<gfx::GpuFence> gpu_fence) {
- unsubmitted_frames_.back()->overlays.push_back(
- gl::GLSurfaceOverlay(z_order, transform, image, bounds_rect, crop_rect,
- enable_blend, std::move(gpu_fence)));
+ unsubmitted_frames_.back()->overlays.emplace_back(
+ z_order, transform, image, bounds_rect, crop_rect, enable_blend,
+ std::move(gpu_fence));
return true;
}
@@ -115,31 +111,23 @@ void GbmSurfacelessWayland::SwapBuffersAsync(
unsubmitted_frames_.push_back(std::make_unique<PendingFrame>());
- if (!use_egl_fence_sync_ || !frame->schedule_planes_succeeded) {
+ // If Wayland server supports linux_explicit_synchronization_protocol, fences
+ // should be shipped with buffers. Otherwise, we will wait for fences.
+ if (buffer_manager_->supports_acquire_fence() || !use_egl_fence_sync_ ||
+ !frame->schedule_planes_succeeded) {
frame->ready = true;
MaybeSubmitFrames();
return;
}
+ base::OnceClosure fence_wait_task;
std::vector<std::unique_ptr<gfx::GpuFence>> fences;
- // Uset in-fences provided in the overlays. If there are none, we insert our
- // own fence and wait.
for (auto& plane : frame->planes) {
if (plane.second.gpu_fence)
fences.push_back(std::move(plane.second.gpu_fence));
}
- base::OnceClosure fence_wait_task;
- if (!fences.empty()) {
- fence_wait_task = base::BindOnce(&WaitForGpuFences, std::move(fences));
- } else {
- // TODO(fangzhoug): the following should be replaced by a per surface flush
- // as it gets implemented in GL drivers.
- EGLSyncKHR fence = InsertFence(has_implicit_external_sync_);
- CHECK_NE(fence, EGL_NO_SYNC_KHR) << "eglCreateSyncKHR failed";
-
- fence_wait_task = base::BindOnce(&WaitForEGLFence, GetDisplay(), fence);
- }
+ fence_wait_task = base::BindOnce(&WaitForGpuFences, std::move(fences));
base::OnceClosure fence_retired_callback = base::BindOnce(
&GbmSurfacelessWayland::FenceRetired, weak_factory_.GetWeakPtr(), frame);
@@ -190,6 +178,14 @@ void GbmSurfacelessWayland::SetRelyOnImplicitSync() {
use_egl_fence_sync_ = false;
}
+bool GbmSurfacelessWayland::SupportsPlaneGpuFences() const {
+ return true;
+}
+
+bool GbmSurfacelessWayland::SupportsOverridePlatformSize() const {
+ return true;
+}
+
gfx::SurfaceOrigin GbmSurfacelessWayland::GetOrigin() const {
// GbmSurfacelessWayland's y-axis is flipped compare to GL - (0,0) is at top
// left corner.
@@ -200,9 +196,9 @@ GbmSurfacelessWayland::~GbmSurfacelessWayland() {
buffer_manager_->UnregisterSurface(widget_);
}
-GbmSurfacelessWayland::PendingFrame::PendingFrame() {}
+GbmSurfacelessWayland::PendingFrame::PendingFrame() = default;
-GbmSurfacelessWayland::PendingFrame::~PendingFrame() {}
+GbmSurfacelessWayland::PendingFrame::~PendingFrame() = default;
void GbmSurfacelessWayland::PendingFrame::ScheduleOverlayPlanes(
gfx::AcceleratedWidget widget) {
@@ -238,15 +234,19 @@ void GbmSurfacelessWayland::MaybeSubmitFrames() {
}
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs;
- for (const auto& plane : submitted_frame->planes) {
+ for (auto& plane : submitted_frame->planes) {
overlay_configs.push_back(
ui::ozone::mojom::WaylandOverlayConfig::From(plane.second));
overlay_configs.back()->buffer_id = plane.first;
- if (plane.second.z_order == 0) {
+ if (plane.second.z_order == 0)
overlay_configs.back()->damage_region = submitted_frame->damage_region_;
- submitted_frame->buffer_id = plane.first;
- }
+#if DCHECK_IS_ON()
+ if (plane.second.z_order == INT32_MIN)
+ background_buffer_id_ = plane.first;
+#endif
+ plane.second.gpu_fence.reset();
}
+
buffer_manager_->CommitOverlays(widget_, std::move(overlay_configs));
submitted_frames_.push_back(std::move(submitted_frame));
}
@@ -273,7 +273,7 @@ void GbmSurfacelessWayland::OnSubmission(BufferId buffer_id,
const gfx::SwapResult& swap_result) {
// submitted_frames_ may temporarily have more than one buffer in it if
// buffers are released out of order by the Wayland server.
- DCHECK(!submitted_frames_.empty());
+ DCHECK(!submitted_frames_.empty() || background_buffer_id_ == buffer_id);
size_t erased = 0;
for (auto& submitted_frame : submitted_frames_) {
@@ -320,7 +320,8 @@ void GbmSurfacelessWayland::OnSubmission(BufferId buffer_id,
void GbmSurfacelessWayland::OnPresentation(
BufferId buffer_id,
const gfx::PresentationFeedback& feedback) {
- DCHECK(!submitted_frames_.empty() || !pending_presentation_frames_.empty());
+ DCHECK(!submitted_frames_.empty() || !pending_presentation_frames_.empty() ||
+ background_buffer_id_ == buffer_id);
size_t erased = 0;
for (auto& frame : pending_presentation_frames_) {
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
index 910b9a7056e..8be5c32391f 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
+++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
@@ -60,6 +60,8 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
PresentationCallback presentation_callback) override;
EGLConfig GetConfig() override;
void SetRelyOnImplicitSync() override;
+ bool SupportsPlaneGpuFences() const override;
+ bool SupportsOverridePlatformSize() const override;
gfx::SurfaceOrigin GetOrigin() const override;
private:
@@ -88,9 +90,6 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
bool ready = false;
- // The id of the buffer, which represents this frame.
- BufferId buffer_id = 0;
-
// A region of the updated content in a corresponding frame. It's used to
// advice Wayland which part of a buffer is going to be updated. Passing {0,
// 0, 0, 0} results in a whole buffer update on the Wayland compositor side.
@@ -120,6 +119,12 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
WaylandBufferManagerGpu* const buffer_manager_;
+ // |background_buffer_id| is sent to WaylandBufferManagerHost once per
+ // background_buffer allocation. However WaylandBufferManagerHost may commit
+ // this buffer more often b/c buffers needs to be re-attached when wl_surface
+ // is reshown.
+ BufferId background_buffer_id_;
+
// The native surface. Deleting this is allowed to free the EGLNativeWindow.
gfx::AcceleratedWidget widget_;
std::vector<std::unique_ptr<PendingFrame>> unsubmitted_frames_;
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc
index 195d061926c..5383fb8209c 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc
@@ -116,8 +116,9 @@ void GLSurfaceEglReadbackWayland::SwapBuffersAsync(
CHECK(next_buffer->shm_mapping_.memory());
ReadPixels(next_buffer->shm_mapping_.memory());
- buffer_manager_->CommitBuffer(widget_, next_buffer->buffer_id_,
- {{0, 0}, GetSize()});
+ const auto bounds = gfx::Rect(GetSize());
+ buffer_manager_->CommitBuffer(widget_, next_buffer->buffer_id_, bounds,
+ bounds);
}
gfx::SurfaceOrigin GLSurfaceEglReadbackWayland::GetOrigin() const {
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
index e5cdaf12895..b430a061c26 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
@@ -46,21 +46,21 @@ bool GLSurfaceWayland::Resize(const gfx::Size& size,
EGLConfig GLSurfaceWayland::GetConfig() {
if (!config_) {
- GLint config_attribs[] = {EGL_BUFFER_SIZE,
- 32,
- EGL_ALPHA_SIZE,
- 8,
- EGL_BLUE_SIZE,
- 8,
- EGL_GREEN_SIZE,
- 8,
- EGL_RED_SIZE,
- 8,
- EGL_RENDERABLE_TYPE,
- EGL_OPENGL_ES2_BIT,
- EGL_SURFACE_TYPE,
- EGL_WINDOW_BIT,
- EGL_NONE};
+ EGLint config_attribs[] = {EGL_BUFFER_SIZE,
+ 32,
+ EGL_ALPHA_SIZE,
+ 8,
+ EGL_BLUE_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_RED_SIZE,
+ 8,
+ EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT,
+ EGL_NONE};
config_ = ChooseEGLConfig(GetDisplay(), config_attribs);
}
return config_;
diff --git a/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc
index 3a2be4275ef..1a3335da4e2 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc
@@ -34,8 +34,8 @@ bool InitializeVulkanFunctionPointers(
} // namespace
-VulkanImplementationWayland::VulkanImplementationWayland()
- : gpu::VulkanImplementation(false /* use_swiftshader */) {}
+VulkanImplementationWayland::VulkanImplementationWayland(bool use_swiftshader)
+ : gpu::VulkanImplementation(use_swiftshader) {}
VulkanImplementationWayland::~VulkanImplementationWayland() {}
@@ -47,14 +47,20 @@ bool VulkanImplementationWayland::InitializeVulkanInstance(bool using_surface) {
auto* vulkan_function_pointers = gpu::GetVulkanFunctionPointers();
- base::FilePath path("libvulkan.so.1");
+ base::FilePath path;
+ if (use_swiftshader()) {
+ if (!base::PathService::Get(base::DIR_MODULE, &path))
+ return false;
+
+ path = path.Append("libvk_swiftshader.so");
+ } else {
+ path = base::FilePath("libvulkan.so.1");
+ }
if (!InitializeVulkanFunctionPointers(path, vulkan_function_pointers))
return false;
- if (!vulkan_instance_.Initialize(required_extensions, {}))
- return false;
- return true;
+ return vulkan_instance_.Initialize(required_extensions, {});
}
gpu::VulkanInstance* VulkanImplementationWayland::GetVulkanInstance() {
@@ -77,13 +83,16 @@ bool VulkanImplementationWayland::GetPhysicalDevicePresentationSupport(
std::vector<const char*>
VulkanImplementationWayland::GetRequiredDeviceExtensions() {
- return {
- VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
+ std::vector<const char*> result{
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
};
+
+ if (!use_swiftshader())
+ result.push_back(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME);
+ return result;
}
std::vector<const char*>
diff --git a/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.h
index e504ac313ef..5acd1e07945 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.h
+++ b/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.h
@@ -14,7 +14,7 @@ namespace ui {
class VulkanImplementationWayland : public gpu::VulkanImplementation {
public:
- VulkanImplementationWayland();
+ explicit VulkanImplementationWayland(bool use_swiftshader = false);
~VulkanImplementationWayland() override;
VulkanImplementationWayland(const VulkanImplementationWayland&) = delete;
@@ -56,4 +56,4 @@ class VulkanImplementationWayland : public gpu::VulkanImplementation {
} // namespace ui
-#endif // UI_OZONE_PLATFORM_WAYLAND_GPU_VULKAN_IMPLEMENTATION_WAYLAND_H_ \ No newline at end of file
+#endif // UI_OZONE_PLATFORM_WAYLAND_GPU_VULKAN_IMPLEMENTATION_WAYLAND_H_
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
index 5c14a1c918f..da7ce23565e 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
@@ -44,7 +44,8 @@ void WaylandBufferManagerGpu::Initialize(
mojo::PendingRemote<ozone::mojom::WaylandBufferManagerHost> remote_host,
const base::flat_map<::gfx::BufferFormat, std::vector<uint64_t>>&
buffer_formats_with_modifiers,
- bool supports_dma_buf) {
+ bool supports_dma_buf,
+ bool supports_acquire_fence) {
DCHECK(supported_buffer_formats_with_modifiers_.empty());
supported_buffer_formats_with_modifiers_ = buffer_formats_with_modifiers;
@@ -52,6 +53,7 @@ void WaylandBufferManagerGpu::Initialize(
if (!supports_dma_buf)
set_gbm_device(nullptr);
#endif
+ supports_acquire_fence_ = supports_acquire_fence;
BindHostInterface(std::move(remote_host));
@@ -182,18 +184,16 @@ void WaylandBufferManagerGpu::CreateShmBasedBuffer(
void WaylandBufferManagerGpu::CommitBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id,
+ const gfx::Rect& bounds_rect,
const gfx::Rect& damage_region) {
- if (!remote_host_) {
- LOG(ERROR) << "Interface is not bound. Can't request "
- "WaylandBufferManagerHost to create/commit/destroy buffers.";
- return;
- }
-
- // Do the mojo call on the IO child thread.
- io_thread_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&WaylandBufferManagerGpu::CommitBufferInternal,
- base::Unretained(this), widget, buffer_id, damage_region));
+ std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs;
+ // This surface only commits one buffer per frame, use INT32_MIN to attach
+ // the buffer to root_surface of wayland window.
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, buffer_id,
+ bounds_rect, gfx::RectF(), damage_region, false, gfx::GpuFenceHandle()));
+
+ CommitOverlays(widget, std::move(overlay_configs));
}
void WaylandBufferManagerGpu::CommitOverlays(
@@ -271,14 +271,6 @@ void WaylandBufferManagerGpu::CreateShmBasedBufferInternal(
length, size, buffer_id);
}
-void WaylandBufferManagerGpu::CommitBufferInternal(
- gfx::AcceleratedWidget widget,
- uint32_t buffer_id,
- const gfx::Rect& damage_region) {
- DCHECK(io_thread_runner_->BelongsToCurrentThread());
- remote_host_->CommitBuffer(widget, buffer_id, damage_region);
-}
-
void WaylandBufferManagerGpu::CommitOverlaysInternal(
gfx::AcceleratedWidget widget,
std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays) {
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
index 1f451202652..8123ade0306 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
@@ -26,7 +26,6 @@
namespace gfx {
enum class SwapResult;
-class Rect;
} // namespace gfx
namespace ui {
@@ -51,7 +50,8 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
mojo::PendingRemote<ozone::mojom::WaylandBufferManagerHost> remote_host,
const base::flat_map<::gfx::BufferFormat, std::vector<uint64_t>>&
buffer_formats_with_modifiers,
- bool supports_dma_buf) override;
+ bool supports_dma_buf,
+ bool supports_acquire_fence) override;
// These two calls get the surface, which backs the |widget| and notifies it
// about the submission and the presentation. After the surface receives the
@@ -103,10 +103,13 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
// logic as well. This call must not be done twice for the same |widget| until
// the OnSubmission is called (which actually means the client can continue
// sending buffer swap requests).
+ //
+ // CommitBuffer() calls CommitOverlays() to commit only a primary plane
+ // buffer.
void CommitBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id,
+ const gfx::Rect& bounds_rect,
const gfx::Rect& damage_region);
-
// Send overlay configurations for a frame to a WaylandWindow identified by
// |widget|.
void CommitOverlays(
@@ -124,6 +127,8 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
}
#endif
+ bool supports_acquire_fence() const { return supports_acquire_fence_; }
+
// Adds a WaylandBufferManagerGpu binding.
void AddBindingWaylandBufferManagerGpu(
mojo::PendingReceiver<ozone::mojom::WaylandBufferManagerGpu> receiver);
@@ -148,9 +153,6 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
size_t length,
gfx::Size size,
uint32_t buffer_id);
- void CommitBufferInternal(gfx::AcceleratedWidget widget,
- uint32_t buffer_id,
- const gfx::Rect& damage_region);
void CommitOverlaysInternal(
gfx::AcceleratedWidget widget,
std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays);
@@ -178,6 +180,8 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
// A DRM render node based gbm device.
std::unique_ptr<GbmDevice> gbm_device_;
#endif
+ // Whether Wayland server allows buffer submission with acquire fence.
+ bool supports_acquire_fence_ = false;
mojo::Receiver<ozone::mojom::WaylandBufferManagerGpu> receiver_{this};
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
index deb43b013e4..bb7029b7d29 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
@@ -58,6 +58,7 @@ class WaylandCanvasSurface::SharedMemoryBuffer {
// based wl_buffer, which can be attached to a surface and have its contents
// shown on a screen.
bool Initialize(const gfx::Size& size) {
+ size_ = size;
base::CheckedNumeric<size_t> checked_length(size.width());
checked_length *= size.height();
checked_length *= 4;
@@ -92,7 +93,8 @@ class WaylandCanvasSurface::SharedMemoryBuffer {
}
void CommitBuffer(const gfx::Rect& damage) {
- buffer_manager_->CommitBuffer(widget_, buffer_id_, damage);
+ buffer_manager_->CommitBuffer(widget_, buffer_id_, gfx::Rect(size_),
+ damage);
}
void OnUse() {
@@ -134,6 +136,9 @@ class WaylandCanvasSurface::SharedMemoryBuffer {
}
private:
+ // The size of the buffer.
+ gfx::Size size_;
+
// The id of the buffer this surface is backed.
const uint32_t buffer_id_;
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
index 0f20a7c0c39..18f555b2076 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
@@ -164,9 +164,10 @@ GLOzone* WaylandSurfaceFactory::GetGLOzone(
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
WaylandSurfaceFactory::CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) {
- return std::make_unique<VulkanImplementationWayland>();
+ return std::make_unique<VulkanImplementationWayland>(use_swiftshader);
}
#endif
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
index 1de11ed0104..18a0319c1d9 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
@@ -31,6 +31,7 @@ class WaylandSurfaceFactory : public SurfaceFactoryOzone {
GLOzone* GetGLOzone(gl::GLImplementation implementation) override;
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) override;
#endif
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
index cc71dc65c2b..310d4a9be16 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
@@ -178,7 +178,7 @@ class WaylandSurfaceFactoryTest : public WaylandTest {
WaylandTest::SetUp();
auto manager_ptr = connection_->buffer_manager_host()->BindInterface();
- buffer_manager_gpu_->Initialize(std::move(manager_ptr), {}, false);
+ buffer_manager_gpu_->Initialize(std::move(manager_ptr), {}, false, false);
// Wait until initialization and mojo calls go through.
base::RunLoop().RunUntilIdle();
@@ -204,221 +204,10 @@ class WaylandSurfaceFactoryTest : public WaylandTest {
};
TEST_P(WaylandSurfaceFactoryTest,
- GbmSurfacelessWaylandCheckOrderOfCallbacksTest) {
- gl::SetGLImplementation(gl::kGLImplementationEGLGLES2);
-
- buffer_manager_gpu_->set_gbm_device(std::make_unique<MockGbmDevice>());
-
- auto* gl_ozone = surface_factory_->GetGLOzone(gl::kGLImplementationEGLGLES2);
- auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_);
- EXPECT_TRUE(gl_surface);
- gl_surface->SetRelyOnImplicitSync();
- static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get())
- ->SetNoGLFlushForTests();
-
- // Expect to create 3 buffers.
- EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(3);
-
- // Create buffers and FakeGlImageNativePixmap.
- std::vector<scoped_refptr<FakeGLImageNativePixmap>> fake_gl_image;
- for (int i = 0; i < 3; ++i) {
- auto native_pixmap = surface_factory_->CreateNativePixmap(
- widget_, nullptr, window_->GetBounds().size(),
- gfx::BufferFormat::BGRA_8888, gfx::BufferUsage::SCANOUT);
- fake_gl_image.push_back(base::MakeRefCounted<FakeGLImageNativePixmap>(
- native_pixmap, window_->GetBounds().size()));
-
- Sync();
-
- // Create one buffer at a time.
- auto params_vector = server_.zwp_linux_dmabuf_v1()->buffer_params();
- DCHECK_EQ(params_vector.size(), 1u);
- zwp_linux_buffer_params_v1_send_created(
- params_vector.front()->resource(),
- params_vector.front()->buffer_resource());
-
- Sync();
- }
-
- // Now, schedule 3 buffers for swap.
- auto* mock_surface = server_.GetObject<wl::MockSurface>(
- window_->root_surface()->GetSurfaceId());
-
- CallbacksHelper cbs_helper;
- // Submit all the available buffers.
- for (const auto& gl_image : fake_gl_image) {
- // Associate each image with swap id so that we could track released
- // buffers.
- auto swap_id = cbs_helper.GetNextLocalSwapId();
- // Associate the image with the next swap id so that we can easily track if
- // it became free to reuse.
- gl_image->AssociateWithSwapId(swap_id);
- // And set it to be busy...
- gl_image->SetBusy(true);
-
- // Prepare overlay plane.
- gl_surface->ScheduleOverlayPlane(
- INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_FLIP_VERTICAL,
- gl_image.get(), window_->GetBounds(), {}, false, nullptr);
-
- std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images;
- gl_images.push_back(gl_image);
-
- // And submit each image. They will be executed in FIFO manner.
- gl_surface->SwapBuffersAsync(
- base::BindOnce(&CallbacksHelper::FinishSwapBuffersAsync,
- base::Unretained(&cbs_helper), swap_id, gl_images),
- base::BindOnce(&CallbacksHelper::BufferPresented,
- base::Unretained(&cbs_helper), swap_id));
- }
-
- // Let's sync so that 1) GbmSurfacelessWayland submits the buffer according to
- // internal queue and fake server processes the request.
-
- // Also, we expect only one buffer to be committed.
- EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
- EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Commit()).Times(1);
-
- Sync();
-
- testing::Mock::VerifyAndClearExpectations(&mock_surface);
-
- // Give mojo the chance to pass the callbacks.
- base::RunLoop().RunUntilIdle();
-
- // We have just received Attach/DamageBuffer/Commit for buffer with swap
- // id=0u. The SwapCompletionCallback must be executed automatically as long as
- // we didn't have any buffers attached to the surface before.
- EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 0u);
-
- cbs_helper.ResetLastFinishedSwapId();
-
- for (const auto& gl_image : fake_gl_image) {
- // All the images except the first one, which was associated with swap
- // id=0u, must be busy and not displayed. The first one must be displayed.
- if (gl_image->GetAssociateWithSwapId() == 0u) {
- EXPECT_FALSE(gl_image->busy());
- EXPECT_TRUE(gl_image->displayed());
- } else {
- EXPECT_TRUE(gl_image->busy());
- EXPECT_FALSE(gl_image->displayed());
- }
- }
-
- // Expect buffer for swap with id=1u to be committed.
- EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
- EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Commit()).Times(1);
-
- // Send the frame callback so that pending buffer for swap id=1u is processed
- // and swapped.
- mock_surface->SendFrameCallback();
-
- Sync();
-
- // Give mojo the chance to pass the callbacks.
- base::RunLoop().RunUntilIdle();
-
- // Even though the second buffer was submitted, we mustn't receive
- // SwapCompletionCallback until the previous buffer is released.
- EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(),
- std::numeric_limits<uint32_t>::max());
-
- // This will result in Wayland server releasing previously attached buffer for
- // swap id=0u and calling OnSubmission for buffer with swap id=1u.
- mock_surface->ReleaseBuffer(mock_surface->prev_attached_buffer());
-
- Sync();
-
- // Give mojo the chance to pass the callbacks.
- base::RunLoop().RunUntilIdle();
-
- // We expect only one buffer to be released. Thus, the last swap id must be
- // 0 as we waited until next buffer was attached to the surface.
- EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 1u);
-
- // Reset to test further swap ids.
- cbs_helper.ResetLastFinishedSwapId();
-
- for (const auto& gl_image : fake_gl_image) {
- // The first image is not displayed and not busy, the second is displayed
- // and not busy. And others are not display and busy.
- if (gl_image->GetAssociateWithSwapId() == 0u) {
- EXPECT_FALSE(gl_image->busy());
- EXPECT_FALSE(gl_image->displayed());
- } else if (gl_image->GetAssociateWithSwapId() == 1u) {
- EXPECT_FALSE(gl_image->busy());
- EXPECT_TRUE(gl_image->displayed());
- } else {
- EXPECT_TRUE(gl_image->busy());
- EXPECT_FALSE(gl_image->displayed());
- }
- }
-
- EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
- EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Commit()).Times(1);
-
- // Send the frame callback, so that the pending buffer with swap id=2u can
- // be processed.
- mock_surface->SendFrameCallback();
-
- Sync();
-
- // Give mojo the chance to pass the callbacks.
- base::RunLoop().RunUntilIdle();
-
- // Even though the second buffer was submitted, we mustn't receive
- // SwapCompletionCallback until the previous buffer is released.
- EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(),
- std::numeric_limits<uint32_t>::max());
-
- // This will result in Wayland server releasing previously attached buffer for
- // swap id=1u and calling OnSubmission for buffer with swap id=2u.
- mock_surface->ReleaseBuffer(mock_surface->prev_attached_buffer());
-
- Sync();
-
- // Give mojo the chance to pass the callbacks.
- base::RunLoop().RunUntilIdle();
-
- // We should receive next callbacks for the next swap id.
- EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 2u);
-
- cbs_helper.ResetLastFinishedSwapId();
-
- // All images must be free now and the last one is displayed.
- for (const auto& gl_image : fake_gl_image) {
- if (gl_image->GetAssociateWithSwapId() == 2u) {
- EXPECT_TRUE(gl_image->displayed());
- EXPECT_FALSE(gl_image->busy());
- } else {
- EXPECT_FALSE(gl_image->displayed());
- EXPECT_FALSE(gl_image->busy());
- }
- }
-
- // There are no buffers left. Send last frame callback and verify that.
- EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0);
- EXPECT_CALL(*mock_surface, Frame(_)).Times(0);
- EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(0);
- EXPECT_CALL(*mock_surface, Commit()).Times(0);
-
- // Send a frame callback so that the WaylandBufferManagerHost processes the
- // pending buffers if any exist.
- mock_surface->SendFrameCallback();
-}
-
-TEST_P(WaylandSurfaceFactoryTest,
GbmSurfacelessWaylandCommitOverlaysCallbacksTest) {
- // GbmSurfacelessWaylandCheckOrderOfCallbacksTest tests with one buffer per
- // frame. This tests multiple buffers per-frame and order of
- // SwapCompletionCallbacks. Even when all OnSubmission from later frames are
- // called, their SwapCompletionCallbacks should not run until previous frames'
+ // This tests multiple buffers per-frame and order of SwapCompletionCallbacks.
+ // Even when all OnSubmission from later frames are called, their
+ // SwapCompletionCallbacks should not run until previous frames'
// SwapCompletionCallbacks run.
gl::SetGLImplementation(gl::kGLImplementationEGLGLES2);
@@ -493,10 +282,10 @@ TEST_P(WaylandSurfaceFactoryTest,
// Also, we expect only one buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
- EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*root_surface, Frame(_)).Times(0);
EXPECT_CALL(*root_surface, Commit()).Times(1);
Sync();
@@ -553,15 +342,15 @@ TEST_P(WaylandSurfaceFactoryTest,
// Expect one buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
- EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*root_surface, Frame(_)).Times(0);
EXPECT_CALL(*root_surface, Commit()).Times(1);
// Send the frame callback so that pending buffer for swap id=1u is processed
// and swapped.
- root_surface->SendFrameCallback();
+ mock_primary_surface->SendFrameCallback();
Sync();
@@ -620,12 +409,12 @@ TEST_P(WaylandSurfaceFactoryTest,
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(0);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(0);
// Expect root surface to be committed.
- EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*root_surface, Frame(_)).Times(0);
EXPECT_CALL(*root_surface, Commit()).Times(1);
// Send the frame callback so that pending buffer for swap id=2u is processed
// and swapped.
- root_surface->SendFrameCallback();
+ mock_primary_surface->SendFrameCallback();
Sync();
@@ -754,10 +543,10 @@ TEST_P(WaylandSurfaceFactoryTest,
// Also, we expect primary buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
- EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*root_surface, Frame(_)).Times(0);
EXPECT_CALL(*root_surface, Commit()).Times(1);
Sync();
@@ -829,23 +618,24 @@ TEST_P(WaylandSurfaceFactoryTest,
// Expect primary buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
// Expect overlay buffer to be committed.
EXPECT_CALL(*mock_overlay_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(1);
EXPECT_CALL(*mock_overlay_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_overlay_surface, Commit()).Times(1);
// Expect root surface to be committed without buffer.
- EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*root_surface, Frame(_)).Times(0);
EXPECT_CALL(*root_surface, Commit()).Times(1);
// Send the frame callback so that pending buffer for swap id=1u is processed
// and swapped.
- root_surface->SendFrameCallback();
+ mock_overlay_surface->SendFrameCallback();
+ mock_primary_surface->SendFrameCallback();
Sync();
diff --git a/chromium/ui/ozone/platform/wayland/host/DEPS b/chromium/ui/ozone/platform/wayland/host/DEPS
index 3ed58be77cd..b9371fab272 100644
--- a/chromium/ui/ozone/platform/wayland/host/DEPS
+++ b/chromium/ui/ozone/platform/wayland/host/DEPS
@@ -1,5 +1,7 @@
include_rules = [
# For Lacros.
+ "+chromeos/crosapi/mojom",
"+chromeos/crosapi/cpp/crosapi_constants.h",
+ "+chromeos/lacros/lacros_chrome_service_impl.h",
"+chromeos/ui/base",
]
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc
index 45540640759..ed4dc91240c 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc
@@ -41,10 +41,6 @@ void GtkPrimarySelectionDevice::OnDataOffer(
gtk_primary_selection_offer* offer) {
auto* self = static_cast<GtkPrimarySelectionDevice*>(data);
DCHECK(self);
-
- self->connection()->clipboard()->UpdateSequenceNumber(
- ClipboardBuffer::kSelection);
-
self->set_data_offer(std::make_unique<GtkPrimarySelectionOffer>(offer));
}
@@ -57,17 +53,16 @@ void GtkPrimarySelectionDevice::OnSelection(
DCHECK(self);
// 'offer' will be null to indicate that the selection is no longer valid,
- // i.e. there is no longer clipboard data available to paste.
+ // i.e. there is no longer selection data available to be fetched.
if (!offer) {
self->ResetDataOffer();
-
- // Clear Clipboard cache.
- self->connection()->clipboard()->SetData({}, {});
- return;
+ } else {
+ DCHECK(self->data_offer());
+ self->data_offer()->EnsureTextMimeTypeIfNeeded();
}
- DCHECK(self->data_offer());
- self->data_offer()->EnsureTextMimeTypeIfNeeded();
+ if (self->selection_delegate())
+ self->selection_delegate()->OnSelectionOffer(self->data_offer());
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
index 0a0e4712910..cb501cbd8f0 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
@@ -4,24 +4,31 @@
#include "ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h"
-#include <gdk/gdkwayland.h>
#include <gtk/gtk.h>
#include <memory>
#include "base/bind.h"
+#include "base/environment.h"
#include "base/logging.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
#include "ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h"
#include "ui/platform_window/platform_window_init_properties.h"
+#if GTK_CHECK_VERSION(3, 90, 0)
+#include <gdk/wayland/gdkwayland.h>
+#else
+#include <gdk/gdkwayland.h>
+
#define WEAK_GTK_FN(x) extern "C" __attribute__((weak)) decltype(x) x
WEAK_GTK_FN(gdk_wayland_window_set_transient_for_exported);
+#endif
namespace ui {
@@ -29,6 +36,9 @@ GtkUiDelegateWayland::GtkUiDelegateWayland(WaylandConnection* connection)
: connection_(connection) {
DCHECK(connection_);
gdk_set_allowed_backends("wayland");
+ // GDK_BACKEND takes precedence over gdk_set_allowed_backends(), so override
+ // it to ensure we get the wayland backend.
+ base::Environment::Create()->SetVar("GDK_BACKEND", "wayland");
}
GtkUiDelegateWayland::~GtkUiDelegateWayland() = default;
@@ -51,12 +61,14 @@ GdkWindow* GtkUiDelegateWayland::GetGdkWindow(
bool GtkUiDelegateWayland::SetGdkWindowTransientFor(
GdkWindow* window,
gfx::AcceleratedWidget parent) {
+#if !GTK_CHECK_VERSION(3, 90, 0)
if (!gdk_wayland_window_set_transient_for_exported) {
LOG(WARNING) << "set_transient_for_exported not supported in GTK version "
<< GTK_MAJOR_VERSION << '.' << GTK_MINOR_VERSION << '.'
<< GTK_MICRO_VERSION;
return false;
}
+#endif
auto* parent_window =
connection_->wayland_window_manager()->GetWindow(parent);
@@ -82,10 +94,19 @@ void GtkUiDelegateWayland::ShowGtkWindow(GtkWindow* window) {
gtk_window_present(window);
}
+int GtkUiDelegateWayland::GetGdkKeyState() {
+ // TODO(crbug/1159460): Test fcitx unikey IME on ozone/wayland.
+ return connection_->event_source()->keyboard_modifiers();
+}
+
void GtkUiDelegateWayland::OnHandle(GdkWindow* window,
const std::string& handle) {
- gdk_wayland_window_set_transient_for_exported(
- window, const_cast<char*>(handle.c_str()));
+ char* parent = const_cast<char*>(handle.c_str());
+#if GTK_CHECK_VERSION(3, 90, 0)
+ gdk_wayland_toplevel_set_transient_for_exported(GDK_TOPLEVEL(window), parent);
+#else
+ gdk_wayland_window_set_transient_for_exported(window, parent);
+#endif
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
index e5e23aeddac..d198057b8ca 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
@@ -30,6 +30,7 @@ class GtkUiDelegateWayland : public GtkUiDelegate {
gfx::AcceleratedWidget parent) override;
void ClearTransientFor(gfx::AcceleratedWidget parent) override;
void ShowGtkWindow(GtkWindow* window) override;
+ int GetGdkKeyState() override;
private:
// Called when xdg-foreign exports a parent window passed in
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc
index dea71480eb6..ed7842b76c2 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc
+++ b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc
@@ -8,20 +8,37 @@
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h"
#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h"
namespace ui {
ShellObjectFactory::ShellObjectFactory() = default;
ShellObjectFactory::~ShellObjectFactory() = default;
-std::unique_ptr<ShellSurfaceWrapper>
-ShellObjectFactory::CreateShellSurfaceWrapper(WaylandConnection* connection,
- WaylandWindow* wayland_window) {
- if (connection->shell() || connection->shell_v6()) {
+std::unique_ptr<ShellToplevelWrapper>
+ShellObjectFactory::CreateShellToplevelWrapper(WaylandConnection* connection,
+ WaylandWindow* wayland_window) {
+ if (connection->shell()) {
auto surface =
std::make_unique<XDGSurfaceWrapperImpl>(wayland_window, connection);
- return surface->Initialize(true /* with_top_level */) ? std::move(surface)
- : nullptr;
+ if (!surface->Initialize())
+ return nullptr;
+
+ auto toplevel = std::make_unique<XDGToplevelWrapperImpl>(
+ std::move(surface), wayland_window, connection);
+ return toplevel->Initialize() ? std::move(toplevel) : nullptr;
+ } else if (connection->shell_v6()) {
+ auto surface =
+ std::make_unique<ZXDGSurfaceV6WrapperImpl>(wayland_window, connection);
+ if (!surface->Initialize())
+ return nullptr;
+
+ auto toplevel = std::make_unique<ZXDGToplevelV6WrapperImpl>(
+ std::move(surface), wayland_window, connection);
+ return toplevel->Initialize() ? std::move(toplevel) : nullptr;
}
LOG(WARNING) << "Shell protocol is not available.";
return nullptr;
@@ -31,15 +48,24 @@ std::unique_ptr<ShellPopupWrapper> ShellObjectFactory::CreateShellPopupWrapper(
WaylandConnection* connection,
WaylandWindow* wayland_window,
const gfx::Rect& bounds) {
- if (connection->shell() || connection->shell_v6()) {
+ if (connection->shell()) {
auto surface =
std::make_unique<XDGSurfaceWrapperImpl>(wayland_window, connection);
- if (!surface->Initialize(false /* with_top_level */))
+ if (!surface->Initialize())
return nullptr;
auto popup = std::make_unique<XDGPopupWrapperImpl>(std::move(surface),
wayland_window);
return popup->Initialize(connection, bounds) ? std::move(popup) : nullptr;
+ } else if (connection->shell_v6()) {
+ auto surface =
+ std::make_unique<ZXDGSurfaceV6WrapperImpl>(wayland_window, connection);
+ if (!surface->Initialize())
+ return nullptr;
+
+ auto popup = std::make_unique<ZXDGPopupV6WrapperImpl>(std::move(surface),
+ wayland_window);
+ return popup->Initialize(connection, bounds) ? std::move(popup) : nullptr;
}
LOG(WARNING) << "Shell protocol is not available.";
return nullptr;
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.h b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.h
index a915326c23f..da3472a5018 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.h
+++ b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.h
@@ -13,7 +13,7 @@ class Rect;
namespace ui {
-class ShellSurfaceWrapper;
+class ShellToplevelWrapper;
class ShellPopupWrapper;
class WaylandConnection;
class WaylandWindow;
@@ -27,8 +27,8 @@ class ShellObjectFactory {
ShellObjectFactory();
~ShellObjectFactory();
- // Creates and initializes a ShellSurfaceWrapper.
- std::unique_ptr<ShellSurfaceWrapper> CreateShellSurfaceWrapper(
+ // Creates and initializes a ShellToplevelWrapper.
+ std::unique_ptr<ShellToplevelWrapper> CreateShellToplevelWrapper(
WaylandConnection* connection,
WaylandWindow* wayland_window);
@@ -41,4 +41,4 @@ class ShellObjectFactory {
} // namespace ui
-#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_ \ No newline at end of file
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc
index f9f5aaa0825..bcf8fc25847 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc
+++ b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc
@@ -6,6 +6,10 @@
#include "base/check_op.h"
#include "base/notreached.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
namespace ui {
@@ -79,4 +83,119 @@ gfx::Rect GetAnchorRect(MenuType menu_type,
return anchor_rect;
}
+WlAnchor GetAnchor(MenuType menu_type, const gfx::Rect& bounds) {
+ WlAnchor anchor = WlAnchor::None;
+ switch (menu_type) {
+ case MenuType::TYPE_RIGHT_CLICK:
+ anchor = WlAnchor::TopLeft;
+ break;
+ case MenuType::TYPE_3DOT_PARENT_MENU:
+ anchor = WlAnchor::BottomRight;
+ break;
+ case MenuType::TYPE_3DOT_CHILD_MENU:
+ // Chromium may want to manually position a child menu on the left side of
+ // its parent menu. Thus, react accordingly. Positive x means the child is
+ // located on the right side of the parent and negative - on the left
+ // side.
+ if (bounds.x() >= 0)
+ anchor = WlAnchor::TopRight;
+ else
+ anchor = WlAnchor::TopLeft;
+ break;
+ case MenuType::TYPE_UNKNOWN:
+ NOTREACHED() << "Unsupported menu type";
+ break;
+ }
+
+ return anchor;
+}
+
+WlGravity GetGravity(MenuType menu_type, const gfx::Rect& bounds) {
+ WlGravity gravity = WlGravity::None;
+ switch (menu_type) {
+ case MenuType::TYPE_RIGHT_CLICK:
+ gravity = WlGravity::BottomRight;
+ break;
+ case MenuType::TYPE_3DOT_PARENT_MENU:
+ gravity = WlGravity::BottomRight;
+ break;
+ case MenuType::TYPE_3DOT_CHILD_MENU:
+ // Chromium may want to manually position a child menu on the left side of
+ // its parent menu. Thus, react accordingly. Positive x means the child is
+ // located on the right side of the parent and negative - on the left
+ // side.
+ if (bounds.x() >= 0)
+ gravity = WlGravity::BottomRight;
+ else
+ gravity = WlGravity::BottomLeft;
+ break;
+ case MenuType::TYPE_UNKNOWN:
+ NOTREACHED() << "Unsupported menu type";
+ break;
+ }
+
+ return gravity;
+}
+
+WlConstraintAdjustment GetConstraintAdjustment(MenuType menu_type) {
+ WlConstraintAdjustment constraint = WlConstraintAdjustment::None;
+
+ switch (menu_type) {
+ case MenuType::TYPE_RIGHT_CLICK:
+ constraint =
+ WlConstraintAdjustment::SlideX | WlConstraintAdjustment::SlideY |
+ WlConstraintAdjustment::FlipY | WlConstraintAdjustment::ResizeY;
+ break;
+ case MenuType::TYPE_3DOT_PARENT_MENU:
+ constraint = WlConstraintAdjustment::SlideX |
+ WlConstraintAdjustment::FlipY |
+ WlConstraintAdjustment::ResizeY;
+ break;
+ case MenuType::TYPE_3DOT_CHILD_MENU:
+ constraint = WlConstraintAdjustment::SlideY |
+ WlConstraintAdjustment::FlipX |
+ WlConstraintAdjustment::ResizeY;
+ break;
+ case MenuType::TYPE_UNKNOWN:
+ NOTREACHED() << "Unsupported menu type";
+ break;
+ }
+
+ return constraint;
+}
+
+MenuType ShellPopupWrapper::GetMenuTypeForPositioner(
+ WaylandConnection* connection,
+ WaylandWindow* parent_window) const {
+ bool is_right_click_menu =
+ connection->event_source()->last_pointer_button_pressed() &
+ EF_RIGHT_MOUSE_BUTTON;
+
+ // Different types of menu require different anchors, constraint adjustments,
+ // gravity and etc.
+ if (is_right_click_menu)
+ return MenuType::TYPE_RIGHT_CLICK;
+ else if (!wl::IsMenuType(parent_window->type()))
+ return MenuType::TYPE_3DOT_PARENT_MENU;
+ else
+ return MenuType::TYPE_3DOT_CHILD_MENU;
+}
+
+bool ShellPopupWrapper::CanGrabPopup(WaylandConnection* connection) const {
+ // When drag process starts, as described the protocol -
+ // https://goo.gl/1Mskq3, the client must have an active implicit grab. If
+ // we try to create a popup and grab it, it will be immediately dismissed.
+ // Thus, do not take explicit grab during drag process.
+ if (connection->IsDragInProgress() || !connection->seat())
+ return false;
+
+ // According to the definition of the xdg protocol, the grab request must be
+ // used in response to some sort of user action like a button press, key
+ // press, or touch down event.
+ EventType last_event_type = connection->event_serial().event_type;
+ return last_event_type == ET_TOUCH_PRESSED ||
+ last_event_type == ET_KEY_PRESSED ||
+ last_event_type == ET_MOUSE_PRESSED;
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h
index 2970549dd09..77eaa71794d 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h
+++ b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h
@@ -11,6 +11,7 @@
namespace ui {
class WaylandConnection;
+class WaylandWindow;
enum class MenuType {
TYPE_RIGHT_CLICK,
@@ -73,11 +74,21 @@ class ShellPopupWrapper {
// Initializes the popup surface.
virtual bool Initialize(WaylandConnection* connection,
const gfx::Rect& bounds) = 0;
+
+ // Sends acknowledge configure event back to wayland.
+ virtual void AckConfigure(uint32_t serial) = 0;
+
+ MenuType GetMenuTypeForPositioner(WaylandConnection* connection,
+ WaylandWindow* parent_window) const;
+ bool CanGrabPopup(WaylandConnection* connection) const;
};
gfx::Rect GetAnchorRect(MenuType menu_type,
const gfx::Rect& menu_bounds,
const gfx::Rect& parent_window_bounds);
+WlAnchor GetAnchor(MenuType menu_type, const gfx::Rect& bounds);
+WlGravity GetGravity(MenuType menu_type, const gfx::Rect& bounds);
+WlConstraintAdjustment GetConstraintAdjustment(MenuType menu_type);
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h b/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
index c75e87a627b..d89aacbb46f 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
+++ b/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
@@ -5,8 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_SURFACE_WRAPPER_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_SURFACE_WRAPPER_H_
-#include "base/strings/string16.h"
-#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include <cstdint>
namespace gfx {
class Rect;
@@ -14,63 +13,21 @@ class Rect;
namespace ui {
-class WaylandConnection;
-
-// Wrapper interface for different wayland shells shell versions.
+// Wrapper interface for different wayland xdg-shell surface versions.
class ShellSurfaceWrapper {
public:
virtual ~ShellSurfaceWrapper() {}
- // Initializes the ShellSurface. Some protocols may require to create shell
- // surface without toplevel role and assign a popup role to it later.
- virtual bool Initialize(bool with_toplevel) = 0;
-
- // Sets a native window to maximized state.
- virtual void SetMaximized() = 0;
-
- // Unsets a native window from maximized state.
- virtual void UnSetMaximized() = 0;
-
- // Sets a native window to fullscreen state.
- virtual void SetFullscreen() = 0;
-
- // Unsets a native window from fullscreen state.
- virtual void UnSetFullscreen() = 0;
-
- // Sets a native window to minimized state.
- virtual void SetMinimized() = 0;
-
- // Tells wayland to start interactive window drag.
- virtual void SurfaceMove(WaylandConnection* connection) = 0;
-
- // Tells wayland to start interactive window resize.
- virtual void SurfaceResize(WaylandConnection* connection,
- uint32_t hittest) = 0;
-
- // Sets a title of a native window.
- virtual void SetTitle(const base::string16& title) = 0;
+ // Initializes the ShellSurface.
+ virtual bool Initialize() = 0;
// Sends acknowledge configure event back to wayland.
- virtual void AckConfigure() = 0;
+ virtual void AckConfigure(uint32_t serial) = 0;
// Sets a desired window geometry once wayland requests client to do so.
virtual void SetWindowGeometry(const gfx::Rect& bounds) = 0;
-
- // Sets the minimum size for the top level.
- virtual void SetMinSize(int32_t width, int32_t height) = 0;
-
- // Sets the maximum size for the top level.
- virtual void SetMaxSize(int32_t width, int32_t height) = 0;
-
- // Sets an app id of the native window that is shown as an application name
- // and hints the compositor that it can group application surfaces together by
- // their app id. This also helps the compositor to identify application's
- // .desktop file and use the icon set there.
- virtual void SetAppId(const std::string& app_id) = 0;
};
-bool CheckIfWlArrayHasValue(struct wl_array* wl_array, uint32_t value);
-
} // namespace ui
#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_SURFACE_WRAPPER_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.cc b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.cc
index ea7d3ca8c94..e84d7ca63bb 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.cc
+++ b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h"
namespace ui {
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h
new file mode 100644
index 00000000000..8767166a13d
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h
@@ -0,0 +1,98 @@
+// Copyright 2021 The Chromium 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_WAYLAND_HOST_SHELL_TOPLEVEL_WRAPPER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_TOPLEVEL_WRAPPER_H_
+
+#include "base/strings/string16.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+class WaylandConnection;
+
+// A wrapper around different versions of xdg toplevels. Allows
+// WaylandToplevelWindow to set window-like properties such as maximize,
+// fullscreen, and minimize, set application-specific metadata like title and
+// id, as well as trigger user interactive operations such as interactive resize
+// and move.
+class ShellToplevelWrapper {
+ public:
+ enum class DecorationMode {
+ // Client-side decoration for a window.
+ // In this case, the client is responsible for drawing decorations
+ // for a window (e.g. caption bar, close button). This is suitable for
+ // windows using custom frame.
+ kClientSide = 1,
+ // Server-side decoration for a window.
+ // In this case, the ash window manager is responsible for drawing
+ // decorations. This is suitable for windows using native frame.
+ // e.g. taskmanager.
+ kServerSide
+ };
+
+ virtual ~ShellToplevelWrapper() = default;
+
+ // Initializes the ShellToplevel.
+ virtual bool Initialize() = 0;
+
+ // Sets a native window to maximized state.
+ virtual void SetMaximized() = 0;
+
+ // Unsets a native window from maximized state.
+ virtual void UnSetMaximized() = 0;
+
+ // Sets a native window to fullscreen state.
+ virtual void SetFullscreen() = 0;
+
+ // Unsets a native window from fullscreen state.
+ virtual void UnSetFullscreen() = 0;
+
+ // Sets a native window to minimized state.
+ virtual void SetMinimized() = 0;
+
+ // Tells wayland to start interactive window drag.
+ virtual void SurfaceMove(WaylandConnection* connection) = 0;
+
+ // Tells wayland to start interactive window resize.
+ virtual void SurfaceResize(WaylandConnection* connection,
+ uint32_t hittest) = 0;
+
+ // Sets a title of a native window.
+ virtual void SetTitle(const base::string16& title) = 0;
+
+ // Sends acknowledge configure event back to wayland.
+ virtual void AckConfigure(uint32_t serial) = 0;
+
+ // Sets a desired window geometry once wayland requests client to do so.
+ virtual void SetWindowGeometry(const gfx::Rect& bounds) = 0;
+
+ // Sets the minimum size for the top level.
+ virtual void SetMinSize(int32_t width, int32_t height) = 0;
+
+ // Sets the maximum size for the top level.
+ virtual void SetMaxSize(int32_t width, int32_t height) = 0;
+
+ // Sets an app id of the native window that is shown as an application name
+ // and hints the compositor that it can group application surfaces together by
+ // their app id. This also helps the compositor to identify application's
+ // .desktop file and use the icon set there.
+ virtual void SetAppId(const std::string& app_id) = 0;
+
+ // In case of kClientSide or kServerSide, this function sends a request to the
+ // wayland compositor to update the decoration mode for a surface associated
+ // with this top level window.
+ virtual void SetDecoration(DecorationMode decoration) = 0;
+};
+
+// Look for |value| in |wl_array| in C++ style.
+bool CheckIfWlArrayHasValue(struct wl_array* wl_array, uint32_t value);
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_TOPLEVEL_WRAPPER_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
index 5139572e51b..7d8cb1086f5 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
@@ -46,7 +46,7 @@ void WaylandAuxiliaryWindow::SetBounds(const gfx::Rect& bounds) {
auto old_bounds = GetBounds();
WaylandWindow::SetBounds(bounds);
- if (old_bounds == bounds || !parent_window())
+ if (old_bounds == bounds || !parent_window() || !subsurface_)
return;
auto subsurface_bounds_dip =
@@ -58,22 +58,11 @@ void WaylandAuxiliaryWindow::SetBounds(const gfx::Rect& bounds) {
}
void WaylandAuxiliaryWindow::CreateSubsurface() {
- auto* parent = parent_window();
- if (!parent) {
- // wl_subsurface can be used for several purposes: tooltips and drag arrow
- // windows. If we are in a drag process, use the entered window. Otherwise,
- // it must be a tooltip.
- if (connection()->IsDragInProgress()) {
- parent = connection()->data_drag_controller()->entered_window();
- set_parent_window(parent);
- } else {
- // If Aura does not not provide a reference parent window, needed by
- // Wayland, we get the current focused window to place and show the
- // tooltips.
- parent =
- connection()->wayland_window_manager()->GetCurrentFocusedWindow();
- }
- }
+ auto* parent = FindParentWindow();
+ set_parent_window(parent);
+
+ // We need to make sure that buffer scale matches the parent window.
+ UpdateBufferScale(true);
// Tooltip and drag arrow creation is an async operation. By the time Aura
// actually creates them, it is possible that the user has already moved the
@@ -101,14 +90,30 @@ void WaylandAuxiliaryWindow::CreateSubsurface() {
connection()->wayland_window_manager()->NotifyWindowConfigured(this);
}
+WaylandWindow* WaylandAuxiliaryWindow::FindParentWindow() {
+ // wl_subsurface can be used for several purposes: tooltips and drag arrow
+ // windows. If we are in a drag process, use the entered window. Otherwise,
+ // it must be a tooltip.
+ if (connection()->IsDragInProgress())
+ return connection()->data_drag_controller()->entered_window();
+
+ // We get the current focused window to place and show the
+ // tooltips.
+ return connection()->wayland_window_manager()->GetCurrentFocusedWindow();
+}
+
bool WaylandAuxiliaryWindow::OnInitialize(
PlatformWindowInitProperties properties) {
DCHECK(!parent_window());
// If we do not have parent window provided, we must always use a focused
// window or a window that entered drag whenever the subsurface is created.
- if (properties.parent_widget == gfx::kNullAcceleratedWidget)
+ if (properties.parent_widget == gfx::kNullAcceleratedWidget) {
+ // Need to set the possible parent window here, so the initial scale will be
+ // calculated correctly.
+ set_parent_window(FindParentWindow());
return true;
+ }
set_parent_window(
connection()->wayland_window_manager()->FindParentForNewWindow(
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h
index 0db19755696..0fb87289e10 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h
@@ -31,6 +31,9 @@ class WaylandAuxiliaryWindow : public WaylandWindow {
// Creates (if necessary) and shows a subsurface window.
void CreateSubsurface();
+ // Finds an appropriate parent window.
+ WaylandWindow* FindParentWindow();
+
wl::Object<wl_subsurface> subsurface_;
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
index da4fdd5fa93..0a6e6d5b9d6 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
@@ -84,9 +84,9 @@ void WaylandBufferManagerConnector::OnBufferManagerHostPtrBinded(
#if defined(WAYLAND_GBM)
supports_dma_buf = buffer_manager_host_->SupportsDmabuf();
#endif
- buffer_manager_gpu_remote->Initialize(std::move(buffer_manager_host),
- buffer_formats_with_modifiers,
- supports_dma_buf);
+ buffer_manager_gpu_remote->Initialize(
+ std::move(buffer_manager_host), buffer_formats_with_modifiers,
+ supports_dma_buf, buffer_manager_host_->SupportsAcquireFence());
}
void WaylandBufferManagerConnector::OnTerminateGpuProcess(std::string message) {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
index fc9e374dc63..831babb51b4 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
@@ -7,11 +7,14 @@
#include <presentation-time-client-protocol.h>
#include <memory>
+#include "base/bind.h"
#include "base/i18n/number_formatting.h"
+#include "base/stl_util.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/current_thread.h"
#include "base/trace_event/trace_event.h"
+#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_drm.h"
@@ -58,6 +61,46 @@ std::string NumberToString(uint32_t number) {
} // namespace
+struct WaylandBufferManagerHost::Frame {
+ explicit Frame(WaylandSurface* root_surface,
+ WaylandBufferManagerHost* manager)
+ : root_surface(root_surface),
+ buffer_manager_(manager),
+ weak_factory(this) {}
+ void IncrementPendingActions() { ++pending_actions; }
+ void PendingActionComplete() {
+ DCHECK(base::CurrentUIThread::IsSet());
+ CHECK_GT(pending_actions, 0u);
+ if (!--pending_actions)
+ if (!std::move(frame_commit_cb).Run()) {
+ buffer_manager_->error_message_ =
+ base::StrCat({"Buffer with ", NumberToString(buffer_id),
+ " id does not exist or failed to be created."});
+ buffer_manager_->TerminateGpuProcess();
+ }
+ }
+
+ // |root_surface| and |buffer_id| are saved so this Frame can be destroyed to
+ // prevent running |frame_commit_cb| in case the corresponding surface/buffer
+ // is removed.
+ WaylandSurface* root_surface;
+ uint32_t buffer_id = 0u;
+
+ // Calls TerminateGpuProcess() if buffer does not exist.
+ WaylandBufferManagerHost* const buffer_manager_;
+
+ // Number of actions to be completed before |frame_commit_cb| is run
+ // automatically. Such actions include:
+ // 1) End Frame;
+ // 2) Commit of a subsurface in this frame;
+ size_t pending_actions = 0u;
+
+ // This runs WaylandBufferManagerHost::Surface::CommitBuffer() of
+ // |root_surface| with |buffer_id|.
+ base::OnceCallback<bool()> frame_commit_cb;
+ base::WeakPtrFactory<WaylandBufferManagerHost::Frame> weak_factory;
+};
+
class WaylandBufferManagerHost::Surface {
public:
Surface(WaylandSurface* wayland_surface,
@@ -68,16 +111,22 @@ class WaylandBufferManagerHost::Surface {
buffer_manager_(buffer_manager) {}
~Surface() = default;
- bool CommitBuffer(uint32_t buffer_id,
- const gfx::Rect& damage_region,
- bool wait_for_frame_callback) {
+ bool CommitBuffer(
+ uint32_t buffer_id,
+ const gfx::Rect& damage_region,
+ bool wait_for_frame_callback,
+ base::OnceClosure post_commit_cb,
+ gfx::GpuFenceHandle access_fence_handle = gfx::GpuFenceHandle()) {
+ DCHECK(!post_commit_cb.is_null());
// The window has already been destroyed.
if (!wayland_surface_)
return true;
// This is a buffer-less commit, do not lookup buffers.
if (buffer_id == kInvalidBufferId) {
- pending_commits_.push_back({nullptr, wait_for_frame_callback});
+ DCHECK(access_fence_handle.is_null());
+ pending_commits_.push_back({nullptr, wait_for_frame_callback, nullptr,
+ std::move(post_commit_cb)});
MaybeProcessPendingBuffer();
return true;
}
@@ -107,7 +156,10 @@ class WaylandBufferManagerHost::Surface {
if (buffer->attached && !buffer->wl_buffer)
return false;
- pending_commits_.push_back({buffer, wait_for_frame_callback});
+ pending_commits_.push_back(
+ {buffer, wait_for_frame_callback,
+ std::make_unique<gfx::GpuFence>(std::move(access_fence_handle)),
+ std::move(post_commit_cb)});
MaybeProcessPendingBuffer();
return true;
}
@@ -122,8 +174,10 @@ class WaylandBufferManagerHost::Surface {
MaybeProcessSubmittedBuffers();
for (auto it = pending_commits_.begin(); it != pending_commits_.end();
++it) {
- if (it->buffer == buffer)
+ if (it->buffer == buffer) {
+ std::move(it->post_commit_cb).Run();
pending_commits_.erase(it++);
+ }
}
}
@@ -155,6 +209,8 @@ class WaylandBufferManagerHost::Surface {
ResetSurfaceContents();
submitted_buffers_.clear();
+ for (auto& pending_commit : pending_commits_)
+ std::move(pending_commit.post_commit_cb).Run();
pending_commits_.clear();
connection_->ScheduleFlush();
@@ -227,9 +283,16 @@ class WaylandBufferManagerHost::Surface {
// Whether this commit must wait for a wl_frame_callback and setup another
// wl_frame_callback.
bool wait_for_callback = false;
+ // Fence to wait on before the |buffer| content is available to read by
+ // Wayland host.
+ std::unique_ptr<gfx::GpuFence> access_fence;
+ // Callback to run once this commit is applied.
+ base::OnceClosure post_commit_cb;
};
- bool CommitBufferInternal(WaylandBuffer* buffer, bool wait_for_callback) {
+ bool CommitBufferInternal(WaylandBuffer* buffer,
+ bool wait_for_callback,
+ const gfx::GpuFenceHandle& access_fence_handle) {
DCHECK(buffer && wayland_surface_);
// If the same buffer has been submitted again right after the client
@@ -242,7 +305,7 @@ class WaylandBufferManagerHost::Surface {
// Once the BufferRelease is called, the buffer will be released.
DCHECK(buffer->released);
buffer->released = false;
- AttachBuffer(buffer);
+ AttachBuffer(buffer, access_fence_handle);
}
// If the client submits the same buffer twice, we need to store it twice,
@@ -278,8 +341,11 @@ class WaylandBufferManagerHost::Surface {
buffer->size);
}
- void AttachBuffer(WaylandBuffer* buffer) {
+ void AttachBuffer(WaylandBuffer* buffer,
+ const gfx::GpuFenceHandle& access_fence_handle) {
DCHECK(wayland_surface_ && configured_);
+ if (!access_fence_handle.is_null())
+ wayland_surface_->SetAcquireFence(access_fence_handle);
wayland_surface_->AttachBuffer(buffer->wl_buffer.get());
}
@@ -552,27 +618,30 @@ class WaylandBufferManagerHost::Surface {
//
// The third case happens if the window hasn't been configured until a
// request to attach a buffer to its surface is sent.
- auto pending_commit = std::move(pending_commits_.front());
+ const auto& pending_commit = pending_commits_.front();
if ((pending_commit.buffer && !pending_commit.buffer->wl_buffer) ||
(wl_frame_callback_ && pending_commit.wait_for_callback) ||
!configured_) {
return;
}
+ auto commit = std::move(pending_commits_.front());
+ pending_commits_.erase(pending_commits_.begin());
+
// A Commit without attaching buffers only needs to setup wl_frame_callback.
- if (!pending_commit.buffer) {
- pending_commits_.erase(pending_commits_.begin());
- if (pending_commit.wait_for_callback)
+ if (!commit.buffer) {
+ if (commit.wait_for_callback)
SetupFrameCallback();
CommitSurface();
+ std::move(commit.post_commit_cb).Run();
connection_->ScheduleFlush();
MaybeProcessSubmittedBuffers();
return;
}
- pending_commits_.erase(pending_commits_.begin());
- CommitBufferInternal(pending_commit.buffer,
- pending_commit.wait_for_callback);
+ CommitBufferInternal(commit.buffer, commit.wait_for_callback,
+ commit.access_fence->GetGpuFenceHandle());
+ std::move(commit.post_commit_cb).Run();
}
// Widget this helper surface backs and has 1:1 relationship with the
@@ -645,6 +714,8 @@ void WaylandBufferManagerHost::OnWindowRemoved(WaylandWindow* window) {
surface_graveyard_.emplace_back(std::move(it->second));
}
surfaces_.erase(it);
+
+ RemovePendingFrames(window->root_surface(), 0u);
}
void WaylandBufferManagerHost::OnWindowConfigured(WaylandWindow* window) {
@@ -675,6 +746,8 @@ void WaylandBufferManagerHost::OnSubsurfaceRemoved(
surface_graveyard_.emplace_back(std::move(it->second));
}
surfaces_.erase(it);
+
+ RemovePendingFrames(subsurface->wayland_surface(), 0u);
}
void WaylandBufferManagerHost::SetSurfaceConfigured(WaylandSurface* surface) {
@@ -709,6 +782,7 @@ void WaylandBufferManagerHost::OnChannelDestroyed() {
surface_pair.second->ClearState();
anonymous_buffers_.clear();
+ pending_frames_.clear();
}
wl::BufferFormatsWithModifiersMap
@@ -727,6 +801,10 @@ bool WaylandBufferManagerHost::SupportsDmabuf() const {
(connection_->drm() && connection_->drm()->SupportsDrmPrime());
}
+bool WaylandBufferManagerHost::SupportsAcquireFence() const {
+ return !!connection_->linux_explicit_synchronization_v1();
+}
+
void WaylandBufferManagerHost::SetWaylandBufferManagerGpu(
mojo::PendingAssociatedRemote<ozone::mojom::WaylandBufferManagerGpu>
buffer_manager_gpu_associated) {
@@ -803,19 +881,72 @@ void WaylandBufferManagerHost::CreateShmBasedBuffer(mojo::PlatformHandle shm_fd,
connection_->ScheduleFlush();
}
+void WaylandBufferManagerHost::StartFrame(WaylandSurface* root_surface) {
+ RemovePendingFrames(nullptr, 0u);
+ DCHECK_LE(pending_frames_.size(), 10u);
+ pending_frames_.push_back(
+ std::make_unique<WaylandBufferManagerHost::Frame>(root_surface, this));
+ pending_frames_.back()->IncrementPendingActions();
+}
+
+void WaylandBufferManagerHost::EndFrame(uint32_t buffer_id,
+ const gfx::Rect& damage_region) {
+ DCHECK(base::CurrentUIThread::IsSet());
+
+ // If TerminateGpuProcess() is called, pending_frames_ would be cleared.
+ if (pending_frames_.empty())
+ return;
+
+ pending_frames_.back()->buffer_id = buffer_id;
+ Surface* surface = GetSurface(pending_frames_.back()->root_surface);
+ if (!surface) {
+ pending_frames_.erase(--pending_frames_.end());
+ return;
+ }
+
+ base::OnceClosure post_commit_cb = base::DoNothing();
+ pending_frames_.back()->frame_commit_cb = base::BindOnce(
+ &WaylandBufferManagerHost::Surface::CommitBuffer,
+ base::Unretained(surface), buffer_id, damage_region, !!buffer_id,
+ std::move(post_commit_cb), gfx::GpuFenceHandle());
+
+ pending_frames_.back()->PendingActionComplete();
+}
+
+void WaylandBufferManagerHost::RemovePendingFrames(WaylandSurface* root_surface,
+ uint32_t buffer_id) {
+ base::EraseIf(pending_frames_,
+ [buffer_id, root_surface](const std::unique_ptr<Frame>& frame) {
+ return !frame->pending_actions ||
+ (frame->buffer_id == buffer_id && buffer_id) ||
+ (frame->root_surface == root_surface && root_surface);
+ });
+}
+
bool WaylandBufferManagerHost::CommitBufferInternal(
WaylandSurface* wayland_surface,
uint32_t buffer_id,
const gfx::Rect& damage_region,
- bool wait_for_frame_callback) {
+ bool wait_for_frame_callback,
+ bool commit_synced_subsurface,
+ gfx::GpuFenceHandle access_fence_handle) {
DCHECK(base::CurrentUIThread::IsSet());
Surface* surface = GetSurface(wayland_surface);
if (!surface || !ValidateBufferIdFromGpu(buffer_id))
return false;
- if (!surface->CommitBuffer(buffer_id, damage_region,
- wait_for_frame_callback)) {
+ base::OnceClosure subsurface_committed_cb = base::DoNothing();
+ if (!pending_frames_.empty() && commit_synced_subsurface) {
+ pending_frames_.back()->IncrementPendingActions();
+ subsurface_committed_cb.Reset();
+ subsurface_committed_cb =
+ base::BindOnce(&WaylandBufferManagerHost::Frame::PendingActionComplete,
+ pending_frames_.back()->weak_factory.GetWeakPtr());
+ }
+ if (!surface->CommitBuffer(buffer_id, damage_region, wait_for_frame_callback,
+ std::move(subsurface_committed_cb),
+ std::move(access_fence_handle))) {
error_message_ =
base::StrCat({"Buffer with ", NumberToString(buffer_id),
" id does not exist or failed to be created."});
@@ -826,45 +957,6 @@ bool WaylandBufferManagerHost::CommitBufferInternal(
return true;
}
-bool WaylandBufferManagerHost::CommitWithoutBufferInternal(
- WaylandSurface* wayland_surface,
- bool wait_for_frame_callback) {
- DCHECK(base::CurrentUIThread::IsSet());
-
- Surface* surface = GetSurface(wayland_surface);
- if (!surface)
- return false;
-
- bool result = surface->CommitBuffer(kInvalidBufferId, gfx::Rect(),
- wait_for_frame_callback);
- DCHECK(result);
-
- if (!error_message_.empty())
- TerminateGpuProcess();
- return true;
-}
-
-void WaylandBufferManagerHost::CommitBuffer(gfx::AcceleratedWidget widget,
- uint32_t buffer_id,
- const gfx::Rect& damage_region) {
- DCHECK(base::CurrentUIThread::IsSet());
-
- TRACE_EVENT1("wayland", "WaylandBufferManagerHost::CommitBuffer", "Buffer id",
- buffer_id);
-
- DCHECK(error_message_.empty());
-
- if (widget == gfx::kNullAcceleratedWidget) {
- error_message_ = "Invalid widget.";
- TerminateGpuProcess();
- } else {
- auto* window = connection_->wayland_window_manager()->GetWindow(widget);
- if (!window)
- return;
- CommitBufferInternal(window->root_surface(), buffer_id, damage_region);
- }
-}
-
void WaylandBufferManagerHost::CommitOverlays(
gfx::AcceleratedWidget widget,
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays) {
@@ -954,6 +1046,8 @@ void WaylandBufferManagerHost::DestroyBuffer(gfx::AcceleratedWidget widget,
}
}
+ RemovePendingFrames(nullptr, buffer_id);
+
// Ensure that we can't destroy more than 1 buffer. This can be 0 as well
// if no buffers are destroyed.
DCHECK_LE(destroyed_count, 1u);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
index 28dc77dc8d0..8137f562f07 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
@@ -5,7 +5,6 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_MANAGER_HOST_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_MANAGER_HOST_H_
-#include <map>
#include <memory>
#include <vector>
@@ -18,6 +17,7 @@
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/gpu_fence_handle.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/gfx/swap_result.h"
@@ -109,6 +109,7 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
wl::BufferFormatsWithModifiersMap GetSupportedBufferFormats() const;
bool SupportsDmabuf() const;
+ bool SupportsAcquireFence() const;
// ozone::mojom::WaylandBufferManagerHost overrides:
//
@@ -139,13 +140,6 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
// Called by the GPU to destroy the imported wl_buffer with a |buffer_id|.
void DestroyBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id) override;
- // Called by the GPU and asks to attach a wl_buffer with a |buffer_id| to a
- // WaylandWindow with the specified |widget|.
- // Calls OnSubmission and OnPresentation on successful swap and pixels
- // presented.
- void CommitBuffer(gfx::AcceleratedWidget widget,
- uint32_t buffer_id,
- const gfx::Rect& damage_region) override;
// Called by the GPU and asks to configure the surface/subsurfaces and attach
// wl_buffers to WaylandWindow with the specified |widget|. Calls OnSubmission
// and OnPresentation on successful swap and pixels presented.
@@ -153,6 +147,15 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
gfx::AcceleratedWidget widget,
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays) override;
+ // Called by WaylandWindow to start recording a frame. This helps record the
+ // number of subsurface commits needed to finish for this frame before
+ // |root_surface| can be committed.
+ // This pairs with an EndCommitFrame(). Every CommitBufferInternal() in
+ // between increases the number of needed pending commits by 1.
+ void StartFrame(WaylandSurface* root_surface);
+ void EndFrame(uint32_t buffer_id = 0u,
+ const gfx::Rect& damage_region = gfx::Rect());
+
// Called by the WaylandWindow and asks to attach a wl_buffer with a
// |buffer_id| to a WaylandSurface.
// Calls OnSubmission and OnPresentation on successful swap and pixels
@@ -163,16 +166,16 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
// commit will move an entire wl_surface tree from pending state to ready
// state. This root_surface commit must wait for wl_frame_callback, such that
// in effect all other surface updates wait for this wl_frame_callback, too.
- bool CommitBufferInternal(WaylandSurface* wayland_surface,
- uint32_t buffer_id,
- const gfx::Rect& damage_region,
- bool wait_for_frame_callback = true);
-
- // Does a wl_surface commit without attaching any buffers. This commit will
- // still wait for previous wl_frame_callback. Similar to above but for
- // commits that do not change the root_surface.
- bool CommitWithoutBufferInternal(WaylandSurface* wayland_surface,
- bool wait_for_frame_callback = true);
+ // |access_fence_handle| specifies a gpu fence created by the gpu process.
+ // It's to be waited on before content of the buffer is ready to be read by
+ // Wayland host.
+ bool CommitBufferInternal(
+ WaylandSurface* wayland_surface,
+ uint32_t buffer_id,
+ const gfx::Rect& damage_region,
+ bool wait_for_frame_callback = true,
+ bool commit_synced_subsurface = false,
+ gfx::GpuFenceHandle access_fence_handle = gfx::GpuFenceHandle());
// When a surface is hidden, the client may want to detach the buffer attached
// to the surface to ensure Wayland does not present those contents and do not
@@ -189,10 +192,17 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
// presentation callbacks for that surface.
class Surface;
+ // This represents a frame that consists of state changes to multiple
+ // synchronized wl_surfaces that are in the same hierarchy. It defers
+ // committing the root surface until all child surfaces' states are ready.
+ struct Frame;
+
bool CreateBuffer(const gfx::Size& size, uint32_t buffer_id);
Surface* GetSurface(WaylandSurface* wayland_surface) const;
+ void RemovePendingFrames(WaylandSurface* root_surface, uint32_t buffer_id);
+
// Validates data sent from GPU. If invalid, returns false and sets an error
// message to |error_message_|.
bool ValidateDataFromGpu(const base::ScopedFD& file,
@@ -230,6 +240,10 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
base::flat_map<WaylandSurface*, std::unique_ptr<Surface>> surfaces_;
+ // When StartCommitFrame() is called, a Frame is pushed to
+ // |pending_frames_|. See StartCommitFrame().
+ std::vector<std::unique_ptr<Frame>> pending_frames_;
+
// When a WaylandWindow/WaylandSubsurface is removed, its corresponding
// Surface may still have an un-released buffer and un-acked presentation.
// Thus, we keep removed surfaces in the graveyard. It's safe to delete them
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
index 43d14126367..f6984d4ff54 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
@@ -8,18 +8,22 @@
#include <string>
#include "base/check.h"
+#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
+#include "base/optional.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h"
-#include "ui/ozone/platform/wayland/host/zwp_primary_selection_device.h"
-#include "ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device_base.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_offer_base.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/zwp_primary_selection_device.h"
+#include "ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h"
#include "ui/ozone/public/platform_clipboard.h"
namespace wl {
@@ -36,15 +40,20 @@ class Clipboard {
virtual std::vector<std::string> ReadMimeTypes() = 0;
// Asynchronously reads clipboard content with |mime_type| format. The result
- // data is expected to arrive through WaylandClipboard::SetData().
- // TODO(nickdiego): Decouple DataDevice impls from WaylandClipboard.
- virtual bool Read(const std::string& mime_type) = 0;
+ // data is expected to arrive through OnSelectionDataReceived() callback.
+ virtual bool Read(const std::string& mime_type,
+ ui::PlatformClipboard::DataMap* data_map,
+ ui::PlatformClipboard::RequestDataClosure callback) = 0;
// Synchronously stores and announces |data| as available from this clipboard.
virtual void Write(const ui::PlatformClipboard::DataMap* data) = 0;
// Tells if this clipboard instance is the current selection owner.
virtual bool IsSelectionOwner() const = 0;
+
+ // Sets the callback in charge of updating the clipboard sequence number.
+ virtual void SetSequenceNumberUpdateCb(
+ ui::PlatformClipboard::SequenceNumberUpdateCb callback) = 0;
};
// Templated wl::Clipboard implementation. Whereas DataSource is the data source
@@ -55,41 +64,70 @@ class Clipboard {
template <typename Manager,
typename DataSource = typename Manager::DataSource,
typename DataDevice = typename Manager::DataDevice>
-class ClipboardImpl final : public Clipboard, public DataSource::Delegate {
+class ClipboardImpl final : public Clipboard,
+ public DataSource::Delegate,
+ public DataDevice::SelectionDelegate {
public:
- explicit ClipboardImpl(Manager* manager) : manager_(manager) {}
+ explicit ClipboardImpl(Manager* manager, ui::ClipboardBuffer buffer)
+ : manager_(manager), buffer_(buffer) {
+ GetDevice()->set_selection_delegate(this);
+ }
+ ~ClipboardImpl() final { GetDevice()->set_selection_delegate(nullptr); }
+
ClipboardImpl(const ClipboardImpl&) = delete;
ClipboardImpl& operator=(const ClipboardImpl&) = delete;
- virtual ~ClipboardImpl() = default;
- virtual bool Read(const std::string& mime_type) override {
- return GetDevice()->RequestSelectionData(mime_type);
+ // TODO(crbug.com/1165466): Support nested clipboard requests.
+ bool Read(const std::string& mime_type,
+ ui::PlatformClipboard::DataMap* data_map,
+ ui::PlatformClipboard::RequestDataClosure callback) final {
+ DCHECK(data_map);
+ received_data_ = data_map;
+ read_clipboard_closure_ = std::move(callback);
+
+ if (GetDevice()->RequestSelectionData(mime_type))
+ return true;
+ SetData(base::MakeRefCounted<base::RefCountedBytes>(), mime_type);
+ return false;
}
- std::vector<std::string> ReadMimeTypes() override {
+ std::vector<std::string> ReadMimeTypes() final {
return GetDevice()->GetAvailableMimeTypes();
}
- virtual void Write(const ui::PlatformClipboard::DataMap* data) override {
+ // Once this client sends wl_data_source::offer, it is responsible for holding
+ // onto its clipboard contents. At future points in time, the wayland server
+ // may send a wl_data_source::send event, in which case this client is
+ // responsible for writing the clipboard contents into the supplied fd. This
+ // client can only drop the clipboard contents when it receives a
+ // wl_data_source::cancelled event.
+ void Write(const ui::PlatformClipboard::DataMap* data) final {
if (!data || data->empty()) {
- data_.clear();
+ offered_data_.clear();
source_.reset();
} else {
- data_ = *data;
+ offered_data_ = *data;
source_ = manager_->CreateSource(this);
source_->Offer(GetMimeTypes());
GetDevice()->SetSelectionSource(source_.get());
}
}
- bool IsSelectionOwner() const override { return !!source_; }
+ bool IsSelectionOwner() const final { return !!source_; }
+
+ void SetSequenceNumberUpdateCb(
+ ui::PlatformClipboard::SequenceNumberUpdateCb callback) final {
+ CHECK(update_sequence_cb_.is_null())
+ << "The callback can be installed only once.";
+ update_sequence_cb_ = callback;
+ }
private:
DataDevice* GetDevice() { return manager_->GetDevice(); }
std::vector<std::string> GetMimeTypes() {
std::vector<std::string> mime_types;
- for (const auto& data : data_) {
+ for (const auto& data : offered_data_) {
mime_types.push_back(data.first);
if (data.first == ui::kMimeTypeText)
mime_types.push_back(ui::kMimeTypeTextUtf8);
@@ -97,6 +135,36 @@ class ClipboardImpl final : public Clipboard, public DataSource::Delegate {
return mime_types;
}
+ void SetData(ui::PlatformClipboard::Data contents,
+ const std::string& mime_type) {
+ if (!received_data_)
+ return;
+
+ DCHECK(contents);
+ (*received_data_)[mime_type] = contents;
+
+ if (!read_clipboard_closure_.is_null()) {
+ auto it = received_data_->find(mime_type);
+ DCHECK(it != received_data_->end());
+ std::move(read_clipboard_closure_).Run(it->second);
+ }
+ received_data_ = nullptr;
+ }
+
+ // WaylandDataDeviceBase::SelectionDelegate:
+ void OnSelectionOffer(ui::WaylandDataOfferBase* offer) final {
+ if (!update_sequence_cb_.is_null())
+ update_sequence_cb_.Run(buffer_);
+
+ if (!offer)
+ SetData({}, {});
+ }
+
+ void OnSelectionDataReceived(const std::string& mime_type,
+ ui::PlatformClipboard::Data contents) final {
+ SetData(contents, mime_type);
+ }
+
// WaylandDataSource::Delegate:
void OnDataSourceFinish(bool completed) override {
if (!completed)
@@ -106,21 +174,34 @@ class ClipboardImpl final : public Clipboard, public DataSource::Delegate {
void OnDataSourceSend(const std::string& mime_type,
std::string* contents) override {
DCHECK(contents);
- auto it = data_.find(mime_type);
- if (it == data_.end() && mime_type == ui::kMimeTypeTextUtf8)
- it = data_.find(ui::kMimeTypeText);
- if (it != data_.end())
+ auto it = offered_data_.find(mime_type);
+ if (it == offered_data_.end() && mime_type == ui::kMimeTypeTextUtf8)
+ it = offered_data_.find(ui::kMimeTypeText);
+ if (it != offered_data_.end())
contents->assign(it->second->data().begin(), it->second->data().end());
}
// The device manager used to access data device and create data sources.
Manager* const manager_;
+ // The clipboard buffer managed by this |this|.
+ const ui::ClipboardBuffer buffer_;
+
// The current data source used to offer clipboard data.
std::unique_ptr<DataSource> source_;
// The data currently stored in a given clipboard buffer.
- ui::PlatformClipboard::DataMap data_;
+ ui::PlatformClipboard::DataMap offered_data_;
+
+ // Holds a temporary instance of the client's clipboard content
+ // so that we can asynchronously write to it.
+ ui::PlatformClipboard::DataMap* received_data_ = nullptr;
+
+ // Stores the callback to be invoked upon data reading from clipboard.
+ ui::PlatformClipboard::RequestDataClosure read_clipboard_closure_;
+
+ // Notifies when clipboard sequence must change. Can be empty if not set.
+ ui::PlatformClipboard::SequenceNumberUpdateCb update_sequence_cb_;
};
} // namespace wl
@@ -132,7 +213,8 @@ WaylandClipboard::WaylandClipboard(WaylandConnection* connection,
: connection_(connection),
copypaste_clipboard_(
std::make_unique<wl::ClipboardImpl<WaylandDataDeviceManager>>(
- manager)) {
+ manager,
+ ClipboardBuffer::kCopyPaste)) {
DCHECK(manager);
DCHECK(connection_);
DCHECK(copypaste_clipboard_);
@@ -149,19 +231,16 @@ void WaylandClipboard::OfferClipboardData(
std::move(callback).Run();
}
+// TODO(crbug.com/1165466): Support nested clipboard requests.
void WaylandClipboard::RequestClipboardData(
ClipboardBuffer buffer,
const std::string& mime_type,
PlatformClipboard::DataMap* data_map,
PlatformClipboard::RequestDataClosure callback) {
- DCHECK(data_map);
- data_map_ = data_map;
- read_clipboard_closure_ = std::move(callback);
- auto* clipboard = GetClipboard(buffer);
- if (!clipboard || !clipboard->Read(mime_type)) {
- SetData(scoped_refptr<base::RefCountedBytes>(new base::RefCountedBytes()),
- mime_type);
- }
+ if (auto* clipboard = GetClipboard(buffer))
+ clipboard->Read(mime_type, data_map, std::move(callback));
+ else
+ std::move(callback).Run(base::nullopt);
}
bool WaylandClipboard::IsSelectionOwner(ClipboardBuffer buffer) {
@@ -172,9 +251,9 @@ bool WaylandClipboard::IsSelectionOwner(ClipboardBuffer buffer) {
void WaylandClipboard::SetSequenceNumberUpdateCb(
PlatformClipboard::SequenceNumberUpdateCb cb) {
- CHECK(update_sequence_cb_.is_null())
- << " The callback can be installed only once.";
- update_sequence_cb_ = std::move(cb);
+ copypaste_clipboard_->SetSequenceNumberUpdateCb(cb);
+ if (auto* selection_clipboard = GetClipboard(ClipboardBuffer::kSelection))
+ selection_clipboard->SetSequenceNumberUpdateCb(cb);
}
void WaylandClipboard::GetAvailableMimeTypes(
@@ -191,27 +270,6 @@ bool WaylandClipboard::IsSelectionBufferAvailable() const {
(connection_->gtk_primary_selection_device_manager() != nullptr);
}
-void WaylandClipboard::SetData(PlatformClipboard::Data contents,
- const std::string& mime_type) {
- if (!data_map_)
- return;
-
- DCHECK(contents);
- (*data_map_)[mime_type] = contents;
-
- if (!read_clipboard_closure_.is_null()) {
- auto it = data_map_->find(mime_type);
- DCHECK(it != data_map_->end());
- std::move(read_clipboard_closure_).Run(it->second);
- }
- data_map_ = nullptr;
-}
-
-void WaylandClipboard::UpdateSequenceNumber(ClipboardBuffer buffer) {
- if (!update_sequence_cb_.is_null())
- update_sequence_cb_.Run(buffer);
-}
-
wl::Clipboard* WaylandClipboard::GetClipboard(ClipboardBuffer buffer) {
if (buffer == ClipboardBuffer::kCopyPaste)
return copypaste_clipboard_.get();
@@ -219,16 +277,17 @@ wl::Clipboard* WaylandClipboard::GetClipboard(ClipboardBuffer buffer) {
if (buffer == ClipboardBuffer::kSelection) {
if (auto* manager = connection_->zwp_primary_selection_device_manager()) {
if (!primary_selection_clipboard_) {
- primary_selection_clipboard_ =
- std::make_unique<wl::ClipboardImpl<ZwpPrimarySelectionDeviceManager>>(
- manager);
+ primary_selection_clipboard_ = std::make_unique<
+ wl::ClipboardImpl<ZwpPrimarySelectionDeviceManager>>(
+ manager, ClipboardBuffer::kSelection);
}
return primary_selection_clipboard_.get();
} else if (auto* manager =
connection_->gtk_primary_selection_device_manager()) {
if (!primary_selection_clipboard_) {
primary_selection_clipboard_ = std::make_unique<
- wl::ClipboardImpl<GtkPrimarySelectionDeviceManager>>(manager);
+ wl::ClipboardImpl<GtkPrimarySelectionDeviceManager>>(
+ manager, ClipboardBuffer::kSelection);
}
return primary_selection_clipboard_.get();
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
index 515c85ca6c3..1b15f4f488e 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
@@ -7,13 +7,10 @@
#include <memory>
#include <string>
-#include <vector>
#include "base/callback.h"
-#include "base/containers/flat_map.h"
-#include "base/macros.h"
-#include "base/optional.h"
#include "ui/base/clipboard/clipboard_buffer.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include "ui/ozone/public/platform_clipboard.h"
namespace wl {
@@ -25,7 +22,12 @@ namespace ui {
class WaylandConnection;
class WaylandDataDeviceManager;
-// Handles clipboard operations.
+// This class is a wrapper around Wayland data_device protocols that simulates
+// typical clipboard operations. Unlike some other platforms, data-transfer is
+// an async, lazy operation. This means that even after "writing" data to the
+// system clipboard, this class must still hold on to a local cache of the
+// clipboard contents, since it may be read (repeatedly) by other Wayland
+// clients.
//
// WaylandDataDeviceManager singleton is required to be up and running for
// WaylandClipboard to be minimally functional.
@@ -55,11 +57,6 @@ class WaylandClipboard : public PlatformClipboard {
PlatformClipboard::SequenceNumberUpdateCb cb) override;
bool IsSelectionBufferAvailable() const override;
- // TODO(nickdiego): Get rid of these methods once DataDevice implementations
- // are decoupled from WaylandClipboard.
- void SetData(PlatformClipboard::Data contents, const std::string& mime_type);
- void UpdateSequenceNumber(ClipboardBuffer buffer);
-
private:
// Get the wl::Clipboard instance owning a given |buffer|. Can return null in
// case |buffer| is unsupported. E.g: primary selection is not available.
@@ -69,17 +66,6 @@ class WaylandClipboard : public PlatformClipboard {
// primary selection.
WaylandConnection* const connection_;
- // Holds a temporary instance of the client's clipboard content
- // so that we can asynchronously write to it.
- PlatformClipboard::DataMap* data_map_ = nullptr;
-
- // Notifies whenever clipboard sequence number is changed. Can be empty if
- // not set.
- PlatformClipboard::SequenceNumberUpdateCb update_sequence_cb_;
-
- // Stores the callback to be invoked upon data reading from clipboard.
- PlatformClipboard::RequestDataClosure read_clipboard_closure_;
-
const std::unique_ptr<wl::Clipboard> copypaste_clipboard_;
std::unique_ptr<wl::Clipboard> primary_selection_clipboard_;
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc
new file mode 100644
index 00000000000..9318149af79
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_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 <wayland-server.h>
+
+#include <cstring>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/containers/contains.h"
+#include "base/containers/flat_set.h"
+#include "base/location.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/mock_callback.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/clipboard/clipboard_buffer.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_data_device.h"
+#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
+#include "ui/ozone/platform/wayland/test/test_data_offer.h"
+#include "ui/ozone/platform/wayland/test/test_data_source.h"
+#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
+#include "ui/ozone/public/platform_clipboard.h"
+
+using testing::_;
+using testing::Mock;
+
+namespace ui {
+
+namespace {
+
+constexpr char kSampleClipboardText[] = "This is a sample text for clipboard.";
+
+template <typename StringType>
+ui::PlatformClipboard::Data ToClipboardData(const StringType& data_string) {
+ std::vector<uint8_t> data_vector;
+ data_vector.assign(data_string.begin(), data_string.end());
+ return base::RefCountedBytes::TakeVector(&data_vector);
+}
+
+} // namespace
+
+class WaylandClipboardTest : public WaylandTest {
+ public:
+ WaylandClipboardTest() = default;
+
+ void SetUp() override {
+ WaylandTest::SetUp();
+
+ Sync();
+
+ data_device_manager_ = server_.data_device_manager();
+ ASSERT_TRUE(data_device_manager_);
+
+ clipboard_ = connection_->clipboard();
+ ASSERT_TRUE(clipboard_);
+
+ offered_data_.clear();
+ }
+
+ protected:
+ // Fill the clipboard backing store with sample data.
+ void OfferData(ClipboardBuffer buffer,
+ const char* data,
+ const std::string& mime_type) {
+ std::vector<uint8_t> data_vector(data, data + std::strlen(data));
+ offered_data_[mime_type] = base::RefCountedBytes::TakeVector(&data_vector);
+
+ base::MockCallback<PlatformClipboard::OfferDataClosure> offer_callback;
+ EXPECT_CALL(offer_callback, Run()).Times(1);
+ clipboard_->OfferClipboardData(buffer, offered_data_, offer_callback.Get());
+ }
+
+ wl::TestDataDeviceManager* data_device_manager_;
+ PlatformClipboard* clipboard_;
+ PlatformClipboard::DataMap offered_data_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WaylandClipboardTest);
+};
+
+TEST_P(WaylandClipboardTest, WriteToClipboard) {
+ // The client writes data to the clipboard ...
+ OfferData(ClipboardBuffer::kCopyPaste, kSampleClipboardText,
+ {kMimeTypeTextUtf8});
+ Sync();
+
+ // ... and the server reads it.
+ base::RunLoop run_loop;
+ auto callback = base::BindOnce(
+ [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
+ std::string string_data(data.begin(), data.end());
+ EXPECT_EQ(kSampleClipboardText, string_data);
+ loop->Quit();
+ },
+ &run_loop);
+
+ data_device_manager_->data_source()->ReadData(kMimeTypeTextUtf8,
+ std::move(callback));
+ run_loop.Run();
+}
+
+TEST_P(WaylandClipboardTest, ReadFromClipboard) {
+ auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
+ data_offer->OnOffer(kMimeTypeTextUtf8,
+ ToClipboardData(std::string(kSampleClipboardText)));
+ data_device_manager_->data_device()->OnSelection(data_offer);
+ Sync();
+
+ // The client requests to read the clipboard data from the server. The Server
+ // writes in some sample data, and we check it matches expectation.
+ base::RunLoop run_loop;
+ auto callback = base::BindOnce(
+ [](base::OnceClosure quit_closure,
+ const base::Optional<PlatformClipboard::Data>& data) {
+ auto& bytes = data->get()->data();
+ std::string string_data = std::string(bytes.begin(), bytes.end());
+ EXPECT_EQ(kSampleClipboardText, string_data);
+ std::move(quit_closure).Run();
+ },
+ run_loop.QuitClosure());
+
+ PlatformClipboard::DataMap read_data_;
+ clipboard_->RequestClipboardData(ClipboardBuffer::kCopyPaste,
+ kMimeTypeTextUtf8, &read_data_,
+ std::move(callback));
+ Sync();
+ run_loop.Run();
+}
+
+TEST_P(WaylandClipboardTest, ReadFromClipboardWithoutOffer) {
+ // When no data offer is advertised and client requests clipboard data
+ // from the server, the response callback should be gracefully called with
+ // an empty string.
+ auto callback =
+ base::BindOnce([](const base::Optional<PlatformClipboard::Data>& data) {
+ auto& bytes = data->get()->data();
+ std::string string_data = std::string(bytes.begin(), bytes.end());
+ EXPECT_EQ("", string_data);
+ });
+ PlatformClipboard::DataMap read_data_;
+ clipboard_->RequestClipboardData(ClipboardBuffer::kCopyPaste,
+ kMimeTypeTextUtf8, &read_data_,
+ std::move(callback));
+}
+
+TEST_P(WaylandClipboardTest, IsSelectionOwner) {
+ OfferData(ClipboardBuffer::kCopyPaste, kSampleClipboardText,
+ {kMimeTypeTextUtf8});
+ Sync();
+ ASSERT_TRUE(clipboard_->IsSelectionOwner(ClipboardBuffer::kCopyPaste));
+
+ // The compositor sends OnCancelled whenever another application
+ // on the system sets a new selection. It means we are not the application
+ // that owns the current selection data.
+ data_device_manager_->data_source()->OnCancelled();
+ Sync();
+
+ ASSERT_FALSE(clipboard_->IsSelectionOwner(ClipboardBuffer::kCopyPaste));
+}
+
+// Ensures WaylandClipboard correctly handles overlapping read requests for
+// different clipboard buffers.
+TEST_P(WaylandClipboardTest, OverlapReadingFromDifferentBuffers) {
+ // Offer a piece of text in kCopyPaste clipboard buffer.
+ auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
+ data_offer->OnOffer(kMimeTypeTextUtf8,
+ ToClipboardData(std::string(kSampleClipboardText)));
+ data_device_manager_->data_device()->OnSelection(data_offer);
+ Sync();
+
+ // Post a read request for kSelection buffer, which will start its execution
+ // after kCopyPaste request (below) starts.
+ PlatformClipboard::DataMap selection_data_;
+ base::MockCallback<PlatformClipboard::RequestDataClosure> selection_callback;
+ EXPECT_CALL(selection_callback, Run(_)).Times(1);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&PlatformClipboard::RequestClipboardData,
+ base::Unretained(clipboard_), ClipboardBuffer::kSelection,
+ kMimeTypeTextUtf8, base::Unretained(&selection_data_),
+ selection_callback.Get()));
+
+ // Instantly start a clipboard read request for kCopyPaste buffer (the actual
+ // data transfer will take place asynchronously. See WaylandDataDevice impl)
+ // and ensure read callback is called and |copy_paste_data_| is filled as
+ // expected, regardless any other request that may arrive in the meantime.
+ PlatformClipboard::DataMap copy_paste_data_;
+ base::RunLoop run_loop;
+ clipboard_->RequestClipboardData(
+ ClipboardBuffer::kCopyPaste, kMimeTypeTextUtf8, &copy_paste_data_,
+ base::BindOnce(
+ [](base::OnceClosure quit_closure,
+ const base::Optional<PlatformClipboard::Data>& data) {
+ ASSERT_TRUE(data.has_value());
+ EXPECT_EQ(kSampleClipboardText,
+ std::string(data->get()->front_as<const char>(),
+ data->get()->size()));
+ std::move(quit_closure).Run();
+ },
+ run_loop.QuitClosure()));
+
+ Sync();
+ run_loop.Run();
+
+ EXPECT_TRUE(selection_data_.empty());
+
+ EXPECT_EQ(1u, copy_paste_data_.size());
+ EXPECT_TRUE(base::Contains(copy_paste_data_, kMimeTypeTextUtf8));
+ auto contents = copy_paste_data_[kMimeTypeTextUtf8];
+ EXPECT_EQ(kSampleClipboardText,
+ std::string(contents->front_as<const char>(), contents->size()));
+}
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
+ WaylandClipboardTest,
+ ::testing::Values(kXdgShellStable));
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
+ WaylandClipboardTest,
+ ::testing::Values(kXdgShellV6));
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
index 73b76474df1..702328d0e9f 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -53,7 +53,10 @@
namespace ui {
namespace {
-constexpr uint32_t kMaxAuraShellVersion = 11;
+// The maximum supported versions for a given interface.
+// The version bound will be the minimum of the value and the version
+// advertised by the server.
+constexpr uint32_t kMaxAuraShellVersion = 16;
constexpr uint32_t kMaxCompositorVersion = 4;
constexpr uint32_t kMaxCursorShapesVersion = 1;
constexpr uint32_t kMaxGtkPrimarySelectionDeviceManagerVersion = 1;
@@ -67,10 +70,13 @@ constexpr uint32_t kMaxWpPresentationVersion = 1;
constexpr uint32_t kMaxWpViewporterVersion = 1;
constexpr uint32_t kMaxTextInputManagerVersion = 1;
constexpr uint32_t kMaxExplicitSyncVersion = 2;
-constexpr uint32_t kMinWlDrmVersion = 2;
-constexpr uint32_t kMinWlOutputVersion = 2;
constexpr uint32_t kMaxXdgDecorationVersion = 1;
constexpr uint32_t kMaxExtendedDragVersion = 1;
+// The minimum required version for a given interface.
+// Ensures that the version bound (advertised by server) is higher than this
+// value.
+constexpr uint32_t kMinWlDrmVersion = 2;
+constexpr uint32_t kMinWlOutputVersion = 2;
} // namespace
WaylandConnection::WaylandConnection() = default;
@@ -89,8 +95,22 @@ bool WaylandConnection::Initialize() {
LOG(ERROR) << "Failed to load wayland client libraries.";
return false;
}
+
if (void* libwayland_egl = dlopen("libwayland-egl.so.1", dlopen_flags))
third_party_wayland::InitializeLibwaylandegl(libwayland_egl);
+
+ // TODO(crbug.com/1081784): consider handling this in more flexible way.
+ // libwayland-cursor is said to be part of the standard shipment of Wayland,
+ // and it seems unlikely (although possible) that it would be unavailable
+ // while libwayland-client was present. To handle that gracefully, chrome can
+ // fall back to the generic Ozone behaviour.
+ if (void* libwayland_cursor =
+ dlopen("libwayland-cursor.so.0", dlopen_flags)) {
+ third_party_wayland::InitializeLibwaylandcursor(libwayland_cursor);
+ } else {
+ LOG(ERROR) << "Failed to load libwayland-cursor.so.0.";
+ return false;
+ }
#endif
static const wl_registry_listener registry_listener = {
@@ -163,6 +183,21 @@ void WaylandConnection::SetShutdownCb(base::OnceCallback<void()> shutdown_cb) {
event_source()->SetShutdownCb(std::move(shutdown_cb));
}
+void WaylandConnection::SetPlatformCursor(wl_cursor* cursor_data,
+ int buffer_scale) {
+ if (!cursor_)
+ return;
+ cursor_->SetPlatformShape(cursor_data, serial(), buffer_scale);
+}
+
+void WaylandConnection::SetCursorBufferListener(
+ WaylandCursorBufferListener* listener) {
+ listener_ = listener;
+ if (!cursor_)
+ return;
+ cursor_->set_listener(listener_);
+}
+
void WaylandConnection::SetCursorBitmap(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& hotspot_in_dips,
int buffer_scale) {
@@ -205,6 +240,7 @@ void WaylandConnection::UpdateInputDevices(wl_seat* seat,
pointer_ =
std::make_unique<WaylandPointer>(pointer, this, event_source());
cursor_ = std::make_unique<WaylandCursor>(pointer_.get(), this);
+ cursor_->set_listener(listener_);
wayland_cursor_position_ = std::make_unique<WaylandCursorPosition>();
} else {
LOG(ERROR) << "Failed to get wl_pointer from seat";
@@ -362,7 +398,8 @@ void WaylandConnection::Global(void* data,
strcmp(interface, "gtk_primary_selection_device_manager") == 0) {
wl::Object<::gtk_primary_selection_device_manager> manager =
wl::Bind<::gtk_primary_selection_device_manager>(
- registry, name, kMaxGtkPrimarySelectionDeviceManagerVersion);
+ registry, name,
+ std::min(version, kMaxGtkPrimarySelectionDeviceManagerVersion));
connection->gtk_primary_selection_device_manager_ =
std::make_unique<GtkPrimarySelectionDeviceManager>(manager.release(),
connection);
@@ -371,7 +408,8 @@ void WaylandConnection::Global(void* data,
0) {
wl::Object<zwp_primary_selection_device_manager_v1> manager =
wl::Bind<zwp_primary_selection_device_manager_v1>(
- registry, name, kMaxGtkPrimarySelectionDeviceManagerVersion);
+ registry, name,
+ std::min(version, kMaxGtkPrimarySelectionDeviceManagerVersion));
connection->zwp_primary_selection_device_manager_ =
std::make_unique<ZwpPrimarySelectionDeviceManager>(manager.release(),
connection);
@@ -390,16 +428,16 @@ void WaylandConnection::Global(void* data,
zwp_linux_dmabuf.release(), connection);
} else if (!connection->presentation_ &&
(strcmp(interface, "wp_presentation") == 0)) {
- connection->presentation_ =
- wl::Bind<wp_presentation>(registry, name, kMaxWpPresentationVersion);
+ connection->presentation_ = wl::Bind<wp_presentation>(
+ registry, name, std::min(version, kMaxWpPresentationVersion));
} else if (!connection->viewporter_ &&
(strcmp(interface, "wp_viewporter") == 0)) {
- connection->viewporter_ =
- wl::Bind<wp_viewporter>(registry, name, kMaxWpViewporterVersion);
+ connection->viewporter_ = wl::Bind<wp_viewporter>(
+ registry, name, std::min(version, kMaxWpViewporterVersion));
} else if (!connection->zcr_cursor_shapes_ &&
strcmp(interface, "zcr_cursor_shapes_v1") == 0) {
- auto zcr_cursor_shapes =
- wl::Bind<zcr_cursor_shapes_v1>(registry, name, kMaxCursorShapesVersion);
+ auto zcr_cursor_shapes = wl::Bind<zcr_cursor_shapes_v1>(
+ registry, name, std::min(version, kMaxCursorShapesVersion));
if (!zcr_cursor_shapes) {
LOG(ERROR) << "Failed to bind zcr_cursor_shapes_v1";
return;
@@ -409,7 +447,7 @@ void WaylandConnection::Global(void* data,
} else if (!connection->keyboard_extension_v1_ &&
strcmp(interface, "zcr_keyboard_extension_v1") == 0) {
connection->keyboard_extension_v1_ = wl::Bind<zcr_keyboard_extension_v1>(
- registry, name, kMaxKeyboardExtensionVersion);
+ registry, name, std::min(version, kMaxKeyboardExtensionVersion));
if (!connection->keyboard_extension_v1_) {
LOG(ERROR) << "Failed to bind zcr_keyboard_extension_v1";
return;
@@ -447,12 +485,12 @@ void WaylandConnection::Global(void* data,
} else if (!connection->xdg_decoration_manager_ &&
strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
connection->xdg_decoration_manager_ =
- wl::Bind<struct zxdg_decoration_manager_v1>(registry, name,
- kMaxXdgDecorationVersion);
+ wl::Bind<struct zxdg_decoration_manager_v1>(
+ registry, name, std::min(version, kMaxXdgDecorationVersion));
} else if (!connection->extended_drag_v1_ &&
strcmp(interface, "zcr_extended_drag_v1") == 0) {
- connection->extended_drag_v1_ =
- wl::Bind<zcr_extended_drag_v1>(registry, name, kMaxExtendedDragVersion);
+ connection->extended_drag_v1_ = wl::Bind<zcr_extended_drag_v1>(
+ registry, name, std::min(version, kMaxExtendedDragVersion));
if (!connection->extended_drag_v1_) {
LOG(ERROR) << "Failed to bind to zcr_extended_drag_v1 global";
return;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
index b7f2981a074..7624abc23d6 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -16,6 +16,8 @@
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
+struct wl_cursor;
+
namespace gfx {
class Point;
}
@@ -24,6 +26,7 @@ namespace ui {
class WaylandBufferManagerHost;
class WaylandCursor;
+class WaylandCursorBufferListener;
class WaylandDrm;
class WaylandEventSource;
class WaylandKeyboard;
@@ -65,6 +68,8 @@ class WaylandConnection {
wl_display* display() const { return display_.get(); }
wl_compositor* compositor() const { return compositor_.get(); }
+ // The server version of the compositor interface (might be higher than the
+ // version binded).
uint32_t compositor_version() const { return compositor_version_; }
wl_subcompositor* subcompositor() const { return subcompositor_.get(); }
wp_viewporter* viewporter() const { return viewporter_.get(); }
@@ -92,6 +97,10 @@ class WaylandConnection {
uint32_t serial() const { return serial_.serial; }
EventSerial event_serial() const { return serial_; }
+ void SetPlatformCursor(wl_cursor* cursor_data, int buffer_scale);
+
+ void SetCursorBufferListener(WaylandCursorBufferListener* listener);
+
void SetCursorBitmap(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& hotspot_in_dips,
int buffer_scale);
@@ -250,6 +259,8 @@ class WaylandConnection {
// Manages Wayland windows.
WaylandWindowManager wayland_window_manager_;
+ WaylandCursorBufferListener* listener_ = nullptr;
+
bool scheduled_flush_ = false;
EventSerial serial_;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc
index cfce7dba945..4d6cabb6a2e 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc
@@ -8,8 +8,10 @@
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/ozone/platform/wayland/common/wayland.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
+#include "ui/ozone/platform/wayland/test/test_compositor.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
namespace ui {
@@ -30,6 +32,9 @@ TEST(WaylandConnectionTest, Ping) {
base::RunLoop().RunUntilIdle();
server.Pause();
+ EXPECT_EQ(wl::TestCompositor::kVersion,
+ wl::get_version_of_object(connection.compositor()));
+
xdg_wm_base_send_ping(server.xdg_shell()->resource(), 1234);
EXPECT_CALL(*server.xdg_shell(), Pong(1234));
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
index 44218ecc612..bd32821c243 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
@@ -4,6 +4,7 @@
#include "ui/ozone/platform/wayland/host/wayland_cursor.h"
+#include <wayland-cursor.h>
#include <memory>
#include <vector>
@@ -74,6 +75,30 @@ void WaylandCursor::UpdateBitmap(const std::vector<SkBitmap>& cursor_image,
auto* address = buffer.get();
buffers_.emplace(address, std::move(buffer));
+
+ if (listener_)
+ listener_->OnCursorBufferAttached(nullptr);
+}
+
+void WaylandCursor::SetPlatformShape(wl_cursor* cursor_data,
+ uint32_t serial,
+ int buffer_scale) {
+ if (!pointer_)
+ return;
+
+ wl_cursor_image* cursor_image = cursor_data->images[0];
+ wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(cursor_image);
+
+ wl_pointer_set_cursor(pointer_->wl_object(), serial, pointer_surface_.get(),
+ cursor_image->hotspot_x, cursor_image->hotspot_y);
+ wl_surface_set_buffer_scale(pointer_surface_.get(), buffer_scale);
+ wl_surface_damage(pointer_surface_.get(), 0, 0, cursor_image->width,
+ cursor_image->height);
+ wl_surface_attach(pointer_surface_.get(), cursor_buffer, 0, 0);
+ wl_surface_commit(pointer_surface_.get());
+
+ if (listener_)
+ listener_->OnCursorBufferAttached(cursor_data);
}
void WaylandCursor::HideCursor(uint32_t serial) {
@@ -84,6 +109,9 @@ void WaylandCursor::HideCursor(uint32_t serial) {
wl_surface_commit(pointer_surface_.get());
connection_->ScheduleFlush();
+
+ if (listener_)
+ listener_->OnCursorBufferAttached(nullptr);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
index e60191eced4..16af372b4c0 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
@@ -15,6 +15,8 @@
class SkBitmap;
+struct wl_cursor;
+
namespace gfx {
class Point;
}
@@ -24,12 +26,23 @@ namespace ui {
class WaylandConnection;
class WaylandPointer;
+// Interface through which WaylandCursor notifies the listener that it has
+// attached another buffer to the pointer surface. The listener may free the
+// previous buffer if it was holding it.
+class WaylandCursorBufferListener {
+ public:
+ // Tells the listener that a new buffer is attached. |cursor_data| may be
+ // non-nullptr if the platform shape is used, or nullptr if the cursor has
+ // been hidden, or a custom bitmap has been set.
+ virtual void OnCursorBufferAttached(wl_cursor* cursor_data) = 0;
+
+ protected:
+ virtual ~WaylandCursorBufferListener() = default;
+};
+
// Manages the actual visual representation (what users see drawn) of the
// 'pointer' (which is the Wayland term for mouse/mice).
//
-// An instance of this class is aggregated by an instance of WaylandPointer
-// and is exposed for updating the pointer bitmap with the single method call.
-//
// Encapsulates the low-level job such as surface and buffer management and
// Wayland protocol calls.
class WaylandCursor {
@@ -48,6 +61,15 @@ class WaylandCursor {
uint32_t serial,
int buffer_scale);
+ // Takes data managed by the platform (without taking ownership).
+ void SetPlatformShape(wl_cursor* cursor_data,
+ uint32_t serial,
+ int buffer_scale);
+
+ void set_listener(WaylandCursorBufferListener* listener) {
+ listener_ = listener;
+ }
+
private:
// wl_buffer_listener:
static void OnBufferRelease(void* data, wl_buffer* wl_buffer);
@@ -57,6 +79,8 @@ class WaylandCursor {
WaylandPointer* const pointer_;
WaylandConnection* const connection_;
+ WaylandCursorBufferListener* listener_ = nullptr;
+
// Holds the buffers and their memory until the compositor releases them.
base::flat_map<wl_buffer*, WaylandShmBuffer> buffers_;
const wl::Object<wl_surface> pointer_surface_;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc
new file mode 100644
index 00000000000..5c0a72ebe2a
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc
@@ -0,0 +1,156 @@
+// Copyright 2021 The Chromium 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/wayland/host/wayland_cursor_factory.h"
+
+#include <wayland-cursor.h>
+
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/task_runner_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_shm.h"
+
+namespace ui {
+
+namespace {
+
+wl_cursor_theme* LoadCursorTheme(const std::string& name,
+ int size,
+ wl_shm* shm) {
+ // wl_cursor_theme_load() can return nullptr. We don't check that here but
+ // have to be cautious when we actually load the shape.
+ return wl_cursor_theme_load((name.empty() ? nullptr : name.c_str()), size,
+ shm);
+}
+
+} // namespace
+
+WaylandCursorFactory::ThemeData::ThemeData() = default;
+
+WaylandCursorFactory::ThemeData::~ThemeData() = default;
+
+WaylandCursorFactory::WaylandCursorFactory(WaylandConnection* connection)
+ : connection_(connection) {
+ connection_->SetCursorBufferListener(this);
+ ReloadThemeCursors();
+}
+
+WaylandCursorFactory::~WaylandCursorFactory() = default;
+
+void WaylandCursorFactory::ObserveThemeChanges() {
+ auto* cursor_theme_manager = CursorThemeManager::GetInstance();
+ DCHECK(cursor_theme_manager);
+ cursor_theme_observer_.Observe(cursor_theme_manager);
+}
+
+base::Optional<PlatformCursor> WaylandCursorFactory::GetDefaultCursor(
+ mojom::CursorType type) {
+ if (type == mojom::CursorType::kNone)
+ return nullptr; // nullptr is used for the hidden cursor.
+
+ if (current_theme_->cache.count(type) == 0) {
+ for (const std::string& name : CursorNamesFromType(type)) {
+ wl_cursor* cursor = GetCursorFromTheme(name);
+ if (!cursor)
+ continue;
+
+ current_theme_->cache[type] =
+ base::MakeRefCounted<BitmapCursorOzone>(type, cursor);
+ break;
+ }
+ }
+ if (current_theme_->cache.count(type) == 0)
+ current_theme_->cache[type] = nullptr;
+
+ // Fall back to the base class implementation if the theme has't provided
+ // a shape for the requested type.
+ if (current_theme_->cache[type].get() == nullptr)
+ return BitmapCursorFactoryOzone::GetDefaultCursor(type);
+
+ return static_cast<PlatformCursor>(current_theme_->cache[type].get());
+}
+
+wl_cursor* WaylandCursorFactory::GetCursorFromTheme(const std::string& name) {
+ // Possible if the theme could not be loaded.
+ if (!current_theme_->theme)
+ return nullptr;
+
+ return wl_cursor_theme_get_cursor(current_theme_->theme.get(), name.c_str());
+}
+
+void WaylandCursorFactory::OnCursorThemeNameChanged(
+ const std::string& cursor_theme_name) {
+ if (name_ == cursor_theme_name)
+ return;
+
+ name_ = cursor_theme_name;
+ ReloadThemeCursors();
+}
+
+void WaylandCursorFactory::OnCursorThemeSizeChanged(int cursor_theme_size) {
+ if (size_ == cursor_theme_size)
+ return;
+
+ size_ = cursor_theme_size;
+ ReloadThemeCursors();
+}
+
+void WaylandCursorFactory::OnCursorBufferAttached(wl_cursor* cursor_data) {
+ if (!unloaded_theme_)
+ return;
+ if (!cursor_data) {
+ unloaded_theme_.reset();
+ return;
+ }
+ for (auto& item : current_theme_->cache) {
+ if (item.second->platform_data() == cursor_data) {
+ // The cursor that has been just attached is from the current theme. That
+ // means that the theme that has been unloaded earlier can now be deleted.
+ unloaded_theme_.reset();
+ return;
+ }
+ }
+}
+
+void WaylandCursorFactory::ReloadThemeCursors() {
+ // If we use any cursor when the theme is reloaded, the one can be only from
+ // the theme that is currently used. As soon as we take the next cursor from
+ // the next theme, we will destroy it (see OnCursorBufferAttached() above).
+ // If more than one theme has been changed but we didn't take any cursors from
+ // them (which is possible if the user played with settings but didn't switch
+ // into Chromium), we don't need to track them all.
+ if (!unloaded_theme_ && current_theme_ && current_theme_->cache.size() > 0)
+ unloaded_theme_ = std::move(current_theme_);
+
+ current_theme_ = std::make_unique<ThemeData>();
+
+ // The task environment is normally not created in tests. As this factory is
+ // part of the platform that is created always and early, posting a task to
+ // the pool would fail in many many tests.
+ if (!base::ThreadPoolInstance::Get())
+ return;
+
+ base::PostTaskAndReplyWithResult(
+ FROM_HERE,
+ {base::ThreadPool(), base::MayBlock(),
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+ base::BindOnce(LoadCursorTheme, name_, size_, connection_->shm()->get()),
+ base::BindOnce(&WaylandCursorFactory::OnThemeLoaded,
+ weak_factory_.GetWeakPtr(), name_, size_));
+}
+
+void WaylandCursorFactory::OnThemeLoaded(const std::string& loaded_theme_name,
+ int loaded_theme_size,
+ wl_cursor_theme* loaded_theme) {
+ if (loaded_theme_name == name_ && loaded_theme_size == size_) {
+ // wl_cursor_theme_load() can return nullptr. We don't check that here but
+ // have to be cautious when we actually load the shape.
+ current_theme_->theme.reset(loaded_theme);
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h
new file mode 100644
index 00000000000..0be03bc1b43
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h
@@ -0,0 +1,90 @@
+// Copyright 2021 The Chromium 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_WAYLAND_HOST_WAYLAND_CURSOR_FACTORY_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_FACTORY_H_
+
+#include <string>
+
+#include "base/containers/flat_map.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "base/scoped_observation.h"
+#include "ui/base/cursor/cursor_theme_manager.h"
+#include "ui/base/cursor/cursor_theme_manager_observer.h"
+#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor.h"
+
+struct wl_cursor_theme;
+
+namespace ui {
+
+class WaylandConnection;
+
+// CursorFactory implementation for Wayland.
+class WaylandCursorFactory : public BitmapCursorFactoryOzone,
+ public CursorThemeManagerObserver,
+ public WaylandCursorBufferListener {
+ public:
+ explicit WaylandCursorFactory(WaylandConnection* connection);
+ WaylandCursorFactory(const WaylandCursorFactory&) = delete;
+ WaylandCursorFactory& operator=(const WaylandCursorFactory&) = delete;
+ ~WaylandCursorFactory() override;
+
+ // CursorFactory:
+ void ObserveThemeChanges() override;
+
+ // CursorFactoryOzone:
+ base::Optional<PlatformCursor> GetDefaultCursor(
+ mojom::CursorType type) override;
+
+ protected:
+ // Returns the actual wl_cursor record from the currently loaded theme.
+ // Virtual for tests where themes can be empty.
+ virtual wl_cursor* GetCursorFromTheme(const std::string& name);
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(WaylandCursorFactoryTest,
+ RetainOldThemeUntilNewBufferIsAttached);
+
+ struct ThemeData {
+ ThemeData();
+ ~ThemeData();
+ wl::Object<wl_cursor_theme> theme;
+ base::flat_map<mojom::CursorType, scoped_refptr<BitmapCursorOzone>> cache;
+ };
+
+ // CusorThemeManagerObserver:
+ void OnCursorThemeNameChanged(const std::string& cursor_theme_name) override;
+ void OnCursorThemeSizeChanged(int cursor_theme_size) override;
+
+ // WaylandCursorBufferListener:
+ void OnCursorBufferAttached(wl_cursor* cursor_data) override;
+
+ void ReloadThemeCursors();
+ void OnThemeLoaded(const std::string& loaded_theme_name,
+ int loaded_theme_size,
+ wl_cursor_theme* loaded_theme);
+
+ WaylandConnection* const connection_;
+
+ base::ScopedObservation<CursorThemeManager, CursorThemeManagerObserver>
+ cursor_theme_observer_{this};
+
+ // Name of the current theme.
+ std::string name_;
+ // Current size of cursors
+ int size_ = 24;
+
+ std::unique_ptr<ThemeData> current_theme_;
+ // Holds the reference on the unloaded theme until the cursor is released.
+ std::unique_ptr<ThemeData> unloaded_theme_;
+
+ base::WeakPtrFactory<WaylandCursorFactory> weak_factory_{this};
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_FACTORY_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc
new file mode 100644
index 00000000000..1ea0e04b6cc
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright 2021 The Chromium 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/wayland/host/wayland_cursor_factory.h"
+
+#include <wayland-cursor.h>
+
+#include "base/containers/flat_map.h"
+#include "base/gtest_prod_util.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
+
+namespace ui {
+
+namespace {
+
+// Overrides WaylandCursorFactory::GetCursorFromTheme() to pretend that cursors
+// are really loaded.
+class DryRunningWaylandCursorFactory : public WaylandCursorFactory {
+ public:
+ explicit DryRunningWaylandCursorFactory(WaylandConnection* connection)
+ : WaylandCursorFactory(connection) {}
+ DryRunningWaylandCursorFactory(const DryRunningWaylandCursorFactory&) =
+ delete;
+ DryRunningWaylandCursorFactory& operator=(
+ const DryRunningWaylandCursorFactory&) = delete;
+ ~DryRunningWaylandCursorFactory() override = default;
+
+ protected:
+ // Pretends to load a cursor by creating an empty wl_cursor.
+ wl_cursor* GetCursorFromTheme(const std::string& name) override {
+ if (cursors_.count(name) == 0) {
+ cursors_[name] = std::make_unique<wl_cursor>();
+ cursors_[name]->image_count = 0;
+ cursors_[name]->images = nullptr;
+ cursors_[name]->name = nullptr;
+ }
+ return cursors_[name].get();
+ }
+
+ private:
+ base::flat_map<std::string, std::unique_ptr<wl_cursor>> cursors_;
+};
+
+} // namespace
+
+class WaylandCursorFactoryTest : public WaylandTest {
+ public:
+ WaylandCursorFactoryTest() = default;
+
+ void SetUp() override {
+ WaylandTest::SetUp();
+
+ cursor_factory_ =
+ std::make_unique<DryRunningWaylandCursorFactory>(connection_.get());
+ }
+
+ protected:
+ std::unique_ptr<WaylandCursorFactory> cursor_factory_;
+};
+
+// Tests that the factory holds the cursor theme until a buffer taken from it
+// released.
+TEST_P(WaylandCursorFactoryTest, RetainOldThemeUntilNewBufferIsAttached) {
+ // The default theme should be loaded right away. The unloaded theme should
+ // not be set.
+ EXPECT_NE(cursor_factory_->current_theme_, nullptr);
+ EXPECT_EQ(cursor_factory_->unloaded_theme_, nullptr);
+
+ // Trigger theme reload and ensure that the theme instance has changed.
+ // As we didn't request any buffers, the unloaded theme should not be held.
+ {
+ auto* const current_theme = cursor_factory_->current_theme_.get();
+ cursor_factory_->OnCursorThemeNameChanged("Theme1");
+ EXPECT_NE(cursor_factory_->current_theme_, nullptr);
+ EXPECT_NE(cursor_factory_->current_theme_.get(), current_theme);
+ EXPECT_EQ(cursor_factory_->unloaded_theme_, nullptr);
+ }
+
+ // Now request some buffer, and while "holding" it (i.e., not notifying the
+ // factory about attaching any other buffer), reload the theme a couple times.
+ // This time the unloaded theme should be set and survive these reloads.
+ // In the end, tell the factory that we have attached a buffer belonging to
+ // the cursor from the "unloaded" theme. This must not trigger unloading of
+ // that theme.
+ {
+ auto* const current_theme = cursor_factory_->current_theme_.get();
+ auto const cursor =
+ cursor_factory_->GetDefaultCursor(mojom::CursorType::kPointer);
+ EXPECT_NE(cursor, nullptr);
+ EXPECT_GT(cursor_factory_->current_theme_->cache.size(), 0U);
+
+ cursor_factory_->OnCursorThemeNameChanged("Theme2");
+
+ EXPECT_EQ(cursor_factory_->current_theme_->cache.size(), 0U);
+ EXPECT_NE(cursor_factory_->current_theme_, nullptr);
+ EXPECT_NE(cursor_factory_->current_theme_.get(), current_theme);
+ EXPECT_EQ(cursor_factory_->unloaded_theme_.get(), current_theme);
+
+ cursor_factory_->OnCursorThemeNameChanged("Theme3");
+
+ EXPECT_EQ(cursor_factory_->current_theme_->cache.size(), 0U);
+ EXPECT_NE(cursor_factory_->current_theme_, nullptr);
+ EXPECT_NE(cursor_factory_->current_theme_.get(), current_theme);
+ EXPECT_EQ(cursor_factory_->unloaded_theme_.get(), current_theme);
+
+ cursor_factory_->OnCursorBufferAttached(reinterpret_cast<wl_cursor*>(
+ reinterpret_cast<BitmapCursorOzone*>(*cursor)->platform_data()));
+ EXPECT_EQ(cursor_factory_->unloaded_theme_.get(), current_theme);
+ }
+
+ // Finally, tell the factory that we have attached a buffer from the current
+ // theme. This time the old theme held since a while ago should be freed.
+ {
+ auto const cursor =
+ cursor_factory_->GetDefaultCursor(mojom::CursorType::kPointer);
+ EXPECT_NE(cursor, nullptr);
+
+ cursor_factory_->OnCursorBufferAttached(reinterpret_cast<wl_cursor*>(
+ reinterpret_cast<BitmapCursorOzone*>(*cursor)->platform_data()));
+
+ EXPECT_EQ(cursor_factory_->unloaded_theme_.get(), nullptr);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
+ WaylandCursorFactoryTest,
+ ::testing::Values(kXdgShellStable));
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
+ WaylandCursorFactoryTest,
+ ::testing::Values(kXdgShellV6));
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
index 8f4b62fa68e..01f32113363 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/files/scoped_file.h"
-#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/ozone/platform/wayland/common/data_util.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
@@ -94,10 +93,7 @@ void WaylandDataDevice::OnOffer(void* data,
wl_data_device* data_device,
wl_data_offer* offer) {
auto* self = static_cast<WaylandDataDevice*>(data);
-
- self->connection()->clipboard()->UpdateSequenceNumber(
- ClipboardBuffer::kCopyPaste);
-
+ DCHECK(self);
DCHECK(!self->new_offer_);
self->new_offer_ = std::make_unique<WaylandDataOffer>(offer);
}
@@ -163,7 +159,7 @@ void WaylandDataDevice::OnLeave(void* data, wl_data_device* data_device) {
// potential use-after-free. Above call to OnDragLeave() may result in
// |drag_delegate_| being reset, so it must be checked here as well.
if (self->drag_delegate_ && !self->drag_delegate_->IsDragSource())
- self->drag_delegate_ = nullptr;
+ self->ResetDragDelegate();
}
void WaylandDataDevice::OnSelection(void* data,
@@ -173,19 +169,17 @@ void WaylandDataDevice::OnSelection(void* data,
DCHECK(self);
// 'offer' will be null to indicate that the selection is no longer valid,
- // i.e. there is no longer clipboard data available to paste.
+ // i.e. there is no longer selection data available to fetch.
if (!offer) {
self->ResetDataOffer();
-
- // Clear Clipboard cache.
- self->connection()->clipboard()->SetData({}, {});
- return;
+ } else {
+ DCHECK(self->new_offer_);
+ self->set_data_offer(std::move(self->new_offer_));
+ self->data_offer()->EnsureTextMimeTypeIfNeeded();
}
- DCHECK(self->new_offer_);
- self->set_data_offer(std::move(self->new_offer_));
-
- self->data_offer()->EnsureTextMimeTypeIfNeeded();
+ if (self->selection_delegate())
+ self->selection_delegate()->OnSelectionOffer(self->data_offer());
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
index f43ba2e8dfa..b13551eaf66 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
@@ -74,6 +74,15 @@ class WaylandDataDevice : public WaylandDataDeviceBase {
// Returns the underlying wl_data_device singleton object.
wl_data_device* data_device() const { return data_device_.get(); }
+ // wl_data_device::set_selection makes the corresponding wl_data_source the
+ // target of future wl_data_device::data_offer events. In non-Wayland terms,
+ // this is equivalent to "writing" to the clipboard or DnD, although the
+ // actual transfer of data happens asynchronously, on-demand-only.
+ //
+ // The API relies on the assumption that the Wayland client is responding to a
+ // keyboard or mouse event with a serial number. This is cached in
+ // WaylandConnection. However, this may not exist or be set properly in tests,
+ // resulting in the Wayland server ignoring the set_selection() request.
void SetSelectionSource(WaylandDataSource* source);
private:
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc
index 7df5d9ec709..50be3ad35bc 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc
@@ -56,10 +56,10 @@ void WaylandDataDeviceBase::ReadClipboardDataFromFD(
const std::string& mime_type) {
std::vector<uint8_t> contents;
wl::ReadDataFromFD(std::move(fd), &contents);
- connection_->clipboard()->SetData(
- scoped_refptr<base::RefCountedBytes>(
- base::RefCountedBytes::TakeVector(&contents)),
- mime_type);
+ if (!selection_delegate_)
+ return;
+ selection_delegate_->OnSelectionDataReceived(
+ mime_type, base::RefCountedBytes::TakeVector(&contents));
}
void WaylandDataDeviceBase::RegisterDeferredReadCallback() {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h
index e331243fc5e..1775790bef2 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_offer_base.h"
+#include "ui/ozone/public/platform_clipboard.h"
namespace ui {
@@ -20,9 +21,25 @@ class WaylandConnection;
// Implements high level (protocol-agnostic) interface to a Wayland data device.
class WaylandDataDeviceBase {
public:
+ class SelectionDelegate {
+ public:
+ virtual void OnSelectionOffer(WaylandDataOfferBase* offer) = 0;
+ virtual void OnSelectionDataReceived(const std::string& mime_type,
+ PlatformClipboard::Data contents) = 0;
+
+ protected:
+ virtual ~SelectionDelegate() = default;
+ };
+
explicit WaylandDataDeviceBase(WaylandConnection* connection);
virtual ~WaylandDataDeviceBase();
+ // Sets the delegate instance responsible for handling section events.
+ void set_selection_delegate(SelectionDelegate* selection_delegate) {
+ DCHECK(!selection_delegate_ || !selection_delegate);
+ selection_delegate_ = selection_delegate;
+ }
+
// Returns MIME types given by the current data offer.
const std::vector<std::string>& GetAvailableMimeTypes() const;
@@ -50,6 +67,8 @@ class WaylandDataDeviceBase {
void RegisterDeferredReadClosure(base::OnceClosure closure);
+ SelectionDelegate* selection_delegate() { return selection_delegate_; }
+
private:
// wl_callback_listener callback
static void DeferredReadCallback(void* data,
@@ -58,9 +77,11 @@ class WaylandDataDeviceBase {
void DeferredReadCallbackInternal(struct wl_callback* cb, uint32_t time);
- // Used to call out to WaylandConnection once clipboard data
- // has been successfully read.
- WaylandConnection* const connection_ = nullptr;
+ SelectionDelegate* selection_delegate_ = nullptr;
+
+ // Used to call out to WaylandConnection once clipboard data has been
+ // successfully read.
+ WaylandConnection* const connection_;
// Offer that holds the most-recent clipboard selection, or null if no
// clipboard data is available.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc
deleted file mode 100644
index 855982cf567..00000000000
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <wayland-server.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/containers/flat_set.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/events/base_event_utils.h"
-#include "ui/ozone/platform/wayland/test/mock_surface.h"
-#include "ui/ozone/platform/wayland/test/test_data_device.h"
-#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
-#include "ui/ozone/platform/wayland/test/test_data_offer.h"
-#include "ui/ozone/platform/wayland/test/test_data_source.h"
-#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/test/wayland_test.h"
-#include "ui/ozone/public/platform_clipboard.h"
-
-using testing::_;
-using testing::Mock;
-
-namespace ui {
-
-namespace {
-
-constexpr char kSampleClipboardText[] = "This is a sample text for clipboard.";
-
-template <typename StringType>
-ui::PlatformClipboard::Data ToClipboardData(const StringType& data_string) {
- std::vector<uint8_t> data_vector;
- data_vector.assign(data_string.begin(), data_string.end());
- return scoped_refptr<base::RefCountedBytes>(
- base::RefCountedBytes::TakeVector(&data_vector));
-}
-
-} // namespace
-
-// This class mocks how a real clipboard/ozone client would
-// 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::GetPlatformClipboard.
-class MockClipboardClient {
- public:
- explicit MockClipboardClient(WaylandConnection* connection) {
- DCHECK(connection);
- // See comment above for reasoning to access the WaylandConnection
- // directly from here.
- delegate_ = connection->clipboard();
-
- DCHECK(delegate_);
- }
- ~MockClipboardClient() = default;
-
- // Fill the clipboard backing store with sample data.
- void SetData(PlatformClipboard::Data data,
- const std::string& mime_type,
- PlatformClipboard::OfferDataClosure callback) {
- data_types_[mime_type] = data;
- delegate_->OfferClipboardData(ClipboardBuffer::kCopyPaste, data_types_,
- std::move(callback));
- }
-
- void ReadData(const std::string& mime_type,
- PlatformClipboard::RequestDataClosure callback) {
- delegate_->RequestClipboardData(ClipboardBuffer::kCopyPaste, mime_type,
- &data_types_, std::move(callback));
- }
-
- bool IsSelectionOwner() {
- return delegate_->IsSelectionOwner(ClipboardBuffer::kCopyPaste);
- }
-
- private:
- PlatformClipboard* delegate_ = nullptr;
- PlatformClipboard::DataMap data_types_;
-
- DISALLOW_COPY_AND_ASSIGN(MockClipboardClient);
-};
-
-class WaylandDataDeviceManagerTest : public WaylandTest {
- public:
- WaylandDataDeviceManagerTest() {}
-
- void SetUp() override {
- WaylandTest::SetUp();
-
- Sync();
-
- data_device_manager_ = server_.data_device_manager();
- DCHECK(data_device_manager_);
-
- clipboard_client_ =
- std::make_unique<MockClipboardClient>(connection_.get());
- }
-
- protected:
- wl::TestDataDeviceManager* data_device_manager_;
- std::unique_ptr<MockClipboardClient> clipboard_client_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WaylandDataDeviceManagerTest);
-};
-
-TEST_P(WaylandDataDeviceManagerTest, WriteToClipboard) {
- // The client writes data to the clipboard ...
- std::vector<uint8_t> data_vector(
- kSampleClipboardText,
- kSampleClipboardText + strlen(kSampleClipboardText));
- clipboard_client_->SetData(
- scoped_refptr<base::RefCountedBytes>(
- base::RefCountedBytes::TakeVector(&data_vector)),
- {kMimeTypeTextUtf8}, base::BindOnce([]() {}));
- Sync();
-
- // ... and the server reads it.
- base::RunLoop run_loop;
- auto callback = base::BindOnce(
- [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
- std::string string_data(data.begin(), data.end());
- EXPECT_EQ(kSampleClipboardText, string_data);
- loop->Quit();
- },
- &run_loop);
- data_device_manager_->data_source()->ReadData(kMimeTypeTextUtf8,
- std::move(callback));
- run_loop.Run();
-}
-
-TEST_P(WaylandDataDeviceManagerTest, ReadFromClipboard) {
- // TODO(nickdiego): implement this in terms of an actual wl_surface that
- // gets focused and compositor sends data_device data to it.
- auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
- data_offer->OnOffer(kMimeTypeTextUtf8,
- ToClipboardData(std::string(kSampleClipboardText)));
- data_device_manager_->data_device()->OnSelection(data_offer);
- Sync();
-
- // The client requests to reading clipboard data from the server.
- // The Server writes in some sample data, and we check it matches
- // expectation.
- auto callback =
- base::BindOnce([](const base::Optional<PlatformClipboard::Data>& data) {
- auto& bytes = data->get()->data();
- std::string string_data = std::string(bytes.begin(), bytes.end());
- EXPECT_EQ(kSampleClipboardText, string_data);
- });
- clipboard_client_->ReadData(kMimeTypeTextUtf8, std::move(callback));
- Sync();
-}
-
-TEST_P(WaylandDataDeviceManagerTest, ReadFromClipboardWithoutOffer) {
- // When no data offer is advertised and client requests clipboard data
- // from the server, the response callback should be gracefully called with
- // an empty string.
- auto callback =
- base::BindOnce([](const base::Optional<PlatformClipboard::Data>& data) {
- auto& bytes = data->get()->data();
- std::string string_data = std::string(bytes.begin(), bytes.end());
- EXPECT_EQ("", string_data);
- });
- clipboard_client_->ReadData(kMimeTypeTextUtf8, std::move(callback));
-}
-
-TEST_P(WaylandDataDeviceManagerTest, IsSelectionOwner) {
- auto callback = base::BindOnce([]() {});
- std::vector<uint8_t> data_vector(
- kSampleClipboardText,
- kSampleClipboardText + strlen(kSampleClipboardText));
- clipboard_client_->SetData(
- scoped_refptr<base::RefCountedBytes>(
- base::RefCountedBytes::TakeVector(&data_vector)),
- {kMimeTypeTextUtf8}, std::move(callback));
- Sync();
- ASSERT_TRUE(clipboard_client_->IsSelectionOwner());
-
- // The compositor sends OnCancelled whenever another application
- // on the system sets a new selection. It means we are not the application
- // that owns the current selection data.
- data_device_manager_->data_source()->OnCancelled();
- Sync();
-
- ASSERT_FALSE(clipboard_client_->IsSelectionOwner());
-}
-
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
- WaylandDataDeviceManagerTest,
- ::testing::Values(kXdgShellStable));
-
-INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
- WaylandDataDeviceManagerTest,
- ::testing::Values(kXdgShellV6));
-
-} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
index 736c40d3cbe..d81ce6155af 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
@@ -7,13 +7,13 @@
#include <cstdint>
#include "base/check.h"
+#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
-#include "ui/gfx/geometry/point_f.h"
#include "ui/ozone/platform/wayland/common/data_util.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
@@ -28,31 +28,22 @@ namespace ui {
namespace {
-// Returns actions possible with the given source and drag'n'drop actions.
-// Also converts enums: input params are wl_data_device_manager_dnd_action but
-// the result is ui::DragDropTypes.
-int GetPossibleActions(uint32_t source_actions, uint32_t dnd_action) {
- // If drag'n'drop action is set, use it but check for ASK action (see below).
- uint32_t action = dnd_action != WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE
- ? dnd_action
- : source_actions;
-
- // We accept any action except ASK (see below).
- int operation = DragDropTypes::DRAG_NONE;
- if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
- operation |= DragDropTypes::DRAG_COPY;
- if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
- operation |= DragDropTypes::DRAG_MOVE;
- if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) {
- // This is very rare and non-standard. Chromium doesn't set this when
- // anything is dragged from it, neither it provides any UI for asking
- // the user about the desired drag'n'drop action when data is dragged
- // from an external source.
- // We are safe with not adding anything here. However, keep NOTIMPLEMENTED
- // for an (unlikely) event of this being hit in distant future.
- NOTIMPLEMENTED_LOG_ONCE();
- }
- return operation;
+int DndActionsToDragOperations(uint32_t actions) {
+ int operations = DragDropTypes::DRAG_NONE;
+ if (actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
+ operations |= DragDropTypes::DRAG_COPY;
+ if (actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
+ operations |= DragDropTypes::DRAG_MOVE;
+ return operations;
+}
+
+uint32_t DragOperationsToDndActions(int operations) {
+ uint32_t dnd_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+ if (operations & DragDropTypes::DRAG_COPY)
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ if (operations & DragDropTypes::DRAG_MOVE)
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+ return dnd_actions;
}
const SkBitmap* GetDragImage(const OSExchangeData& data) {
@@ -94,21 +85,27 @@ void WaylandDataDragController::StartSession(const OSExchangeData& data,
Offer(data, operation);
// Create drag icon surface (if any) and store the data to be exchanged.
- CreateIconSurfaceIfNeeded(data);
+ icon_bitmap_ = GetDragImage(data);
+ if (icon_bitmap_) {
+ icon_surface_ = connection_->CreateSurface();
+ wl_surface_set_buffer_scale(icon_surface_.get(),
+ origin_window_->buffer_scale());
+ }
data_ = std::make_unique<OSExchangeData>(data.provider().Clone());
// Starts the wayland drag session setting |this| object as delegate.
state_ = State::kStarted;
data_device_->StartDrag(*data_source_, *origin_window_, icon_surface_.get(),
this);
+
+ window_manager_->AddObserver(this);
}
-// Sessions initiated from Chromium, will have |origin_window_| pointing to the
-// window where the drag started in. In such cases, |data_| is expected to be
-// non-null, which can be used to save some IO cycles.
+// Sessions initiated from Chromium, will have |data_source_| set. In which
+// case, |data_| is expected to be non-null as well.
bool WaylandDataDragController::IsDragSource() const {
- DCHECK(!origin_window_ || data_);
- return !!origin_window_;
+ DCHECK(!data_source_ || data_);
+ return !!data_source_;
}
void WaylandDataDragController::DrawIcon() {
@@ -125,7 +122,6 @@ void WaylandDataDragController::DrawIcon() {
return;
}
}
- // TODO(crbug.com/1085418): Fix drag icon scaling
wl::DrawBitmap(*icon_bitmap_, shm_buffer_.get());
wl_surface_attach(icon_surface_.get(), shm_buffer_->get(), 0, 0);
wl_surface_damage(icon_surface_.get(), 0, 0, size.width(), size.height());
@@ -142,6 +138,7 @@ void WaylandDataDragController::OnDragEnter(WaylandWindow* window,
const gfx::PointF& location,
uint32_t serial) {
DCHECK(window);
+ DCHECK(data_offer_);
window_ = window;
// TODO(crbug.com/1004715): Set mime type the client can accept. Now it sets
@@ -153,39 +150,53 @@ void WaylandDataDragController::OnDragEnter(WaylandWindow* window,
data_offer_->Accept(serial, mime);
}
- std::unique_ptr<OSExchangeData> dragged_data;
- // If the DND session was initiated from a Chromium window, |data_| already
- // holds the data to be exchanged, so no needed to read it through Wayland,
- // thus just copy it here.
- if (IsDragSource())
- dragged_data = std::make_unique<OSExchangeData>(data_->provider().Clone());
- window_->OnDragEnter(location, std::move(dragged_data),
- GetPossibleActions(data_offer_->source_actions(),
- data_offer_->dnd_action()));
+ if (IsDragSource()) {
+ // If the DND session was initiated from a Chromium window, |data_| already
+ // holds the data to be exchanged, so we don't need to read it through
+ // Wayland and can just copy it here.
+ DCHECK(data_);
+ PropagateOnDragEnter(
+ location, std::make_unique<OSExchangeData>(data_->provider().Clone()));
+ } else {
+ // Otherwise, we are about to accept data dragged from another application.
+ // Reading the data may take some time so set |state_| to |kTrasferring|,
+ // which will defer sending OnDragEnter to the client until the data
+ // is ready.
+ state_ = State::kTransferring;
+ received_data_ = std::make_unique<OSExchangeData>(
+ std::make_unique<OSExchangeDataProviderNonBacked>());
+ last_drag_location_ = location;
+ HandleUnprocessedMimeTypes(base::TimeTicks::Now());
+ }
}
void WaylandDataDragController::OnDragMotion(const gfx::PointF& location) {
if (!window_)
return;
- int client_operation = window_->OnDragMotion(
- location, GetPossibleActions(data_offer_->source_actions(),
- data_offer_->dnd_action()));
- SetOperation(client_operation);
+ if (state_ == State::kTransferring) {
+ last_drag_location_ = location;
+ return;
+ }
+
+ DCHECK(data_offer_);
+ int available_operations =
+ DndActionsToDragOperations(data_offer_->source_actions());
+ int client_operations = window_->OnDragMotion(location, available_operations);
+
+ data_offer_->SetActions(DragOperationsToDndActions(client_operations));
}
void WaylandDataDragController::OnDragLeave() {
- if (!window_)
- return;
-
- // Leave event can arrive while data is being transferred. As it cannot be
- // handled right away, just mark it to be processed when the data is ready.
if (state_ == State::kTransferring) {
+ // We cannot leave until the transfer is finished. Postponing.
is_leave_pending_ = true;
return;
}
- window_->OnDragLeave();
+ if (window_)
+ window_->OnDragLeave();
+
window_ = nullptr;
data_offer_.reset();
is_leave_pending_ = false;
@@ -195,40 +206,32 @@ void WaylandDataDragController::OnDragDrop() {
if (!window_)
return;
- if (IsDragSource()) {
- // This means the data is being exchanged between Chromium windows. In this
- // case, data is supposed to have already been sent to the drop handler
- // before (see OnDragEnter()), expecting to receive null at this stage.
- OnDataTransferFinished(nullptr);
- return;
- }
+ window_->OnDragDrop();
- // Otherwise, we are about to accept data dragged from another application.
- // Reading the data may take some time so set |state_| to |kTrasfering|, which
- // will make final "leave" event handling to be postponed until data is ready.
- state_ = State::kTransferring;
- received_data_ = std::make_unique<OSExchangeData>(
- std::make_unique<OSExchangeDataProviderNonBacked>());
- HandleUnprocessedMimeTypes();
+ // Offer must be finished and destroyed here as some compositors may delay to
+ // send wl_data_source::finished|cancelled until owning client destroys the
+ // drag offer. e.g: Exosphere.
+ data_offer_->FinishOffer();
+ data_offer_.reset();
}
void WaylandDataDragController::OnDataSourceFinish(bool completed) {
DCHECK(data_source_);
- DCHECK(origin_window_);
-
- origin_window_->OnDragSessionClose(data_source_->dnd_action());
- // DnD handlers expect DragLeave to be sent for drag sessions that end up
- // with no data transfer (wl_data_source::cancelled event).
- if (!completed)
- origin_window_->OnDragLeave();
+ if (origin_window_) {
+ origin_window_->OnDragSessionClose(data_source_->dnd_action());
+ // DnD handlers expect DragLeave to be sent for drag sessions that end up
+ // with no data transfer (wl_data_source::cancelled event).
+ if (!completed)
+ origin_window_->OnDragLeave();
+ origin_window_ = nullptr;
+ }
- origin_window_ = nullptr;
+ window_manager_->RemoveObserver(this);
data_source_.reset();
data_offer_.reset();
data_.reset();
data_device_->ResetDragDelegate();
-
state_ = State::kIdle;
}
@@ -243,6 +246,14 @@ void WaylandDataDragController::OnDataSourceSend(const std::string& mime_type,
}
}
+void WaylandDataDragController::OnWindowRemoved(WaylandWindow* window) {
+ if (window == window_)
+ window_ = nullptr;
+
+ if (window == origin_window_)
+ origin_window_ = nullptr;
+}
+
void WaylandDataDragController::Offer(const OSExchangeData& data,
int operation) {
DCHECK(data_source_);
@@ -271,36 +282,29 @@ void WaylandDataDragController::Offer(const OSExchangeData& data,
data_source_->SetAction(operation);
}
-void WaylandDataDragController::CreateIconSurfaceIfNeeded(
- const OSExchangeData& data) {
- icon_bitmap_ = GetDragImage(data);
- if (icon_bitmap_)
- icon_surface_ = connection_->CreateSurface();
-}
-
// Asynchronously requests and reads data for every negotiated/supported mime
// type, one after another, OnMimeTypeDataTransferred calls back into this
// function once it finishes reading data for each mime type, until there is no
// more unprocessed mime types on the |unprocessed_mime_types_| queue. Once this
// process is finished, OnDataTransferFinished is called to deliver the
// |received_data_| to the drop handler.
-void WaylandDataDragController::HandleUnprocessedMimeTypes() {
- DCHECK_EQ(state_, State::kTransferring);
+void WaylandDataDragController::HandleUnprocessedMimeTypes(
+ base::TimeTicks start_time) {
std::string mime_type = GetNextUnprocessedMimeType();
- if (mime_type.empty()) {
- OnDataTransferFinished(std::move(received_data_));
+ if (mime_type.empty() || is_leave_pending_ || state_ == State::kIdle) {
+ OnDataTransferFinished(start_time, std::move(received_data_));
} else {
DCHECK(data_offer_);
data_device_->RequestData(
data_offer_.get(), mime_type,
base::BindOnce(&WaylandDataDragController::OnMimeTypeDataTransferred,
- weak_factory_.GetWeakPtr()));
+ weak_factory_.GetWeakPtr(), start_time));
}
}
void WaylandDataDragController::OnMimeTypeDataTransferred(
+ base::TimeTicks start_time,
PlatformClipboard::Data contents) {
- DCHECK_EQ(state_, State::kTransferring);
DCHECK(contents);
if (!contents->data().empty()) {
std::string mime_type = unprocessed_mime_types_.front();
@@ -309,21 +313,37 @@ void WaylandDataDragController::OnMimeTypeDataTransferred(
unprocessed_mime_types_.pop_front();
// Continue reading data for other negotiated mime types.
- HandleUnprocessedMimeTypes();
+ HandleUnprocessedMimeTypes(start_time);
}
void WaylandDataDragController::OnDataTransferFinished(
+ base::TimeTicks start_time,
std::unique_ptr<OSExchangeData> received_data) {
- data_offer_->FinishOffer();
- window_->OnDragDrop(std::move(received_data));
-
unprocessed_mime_types_.clear();
+ if (state_ == State::kIdle)
+ return;
+
state_ = State::kIdle;
// If |is_leave_pending_| is set, it means a 'leave' event was fired while
- // data was on transit, so process it here (See OnDragLeave for more context).
- if (is_leave_pending_)
- OnDragLeave();
+ // data was on transit (see OnDragLeave for more context). Sending
+ // OnDragEnter to the window makes no sense anymore because the drag is no
+ // longer over it. Reset and exit.
+ if (is_leave_pending_) {
+ if (data_offer_) {
+ data_offer_->FinishOffer();
+ data_offer_.reset();
+ }
+ data_.reset();
+ data_device_->ResetDragDelegate();
+ is_leave_pending_ = false;
+ return;
+ }
+
+ UMA_HISTOGRAM_TIMES("Event.WaylandDragDrop.IncomingDataTransferTime",
+ base::TimeTicks::Now() - start_time);
+
+ PropagateOnDragEnter(last_drag_location_, std::move(received_data));
}
// Returns the next MIME type to be received from the source process, or an
@@ -342,21 +362,15 @@ std::string WaylandDataDragController::GetNextUnprocessedMimeType() {
return {};
}
-void WaylandDataDragController::SetOperation(const int operation) {
- uint32_t dnd_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
- uint32_t preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-
- if (operation & DragDropTypes::DRAG_COPY) {
- dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- }
+void WaylandDataDragController::PropagateOnDragEnter(
+ const gfx::PointF& location,
+ std::unique_ptr<OSExchangeData> data) {
+ DCHECK(window_);
- if (operation & DragDropTypes::DRAG_MOVE) {
- dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
- if (preferred_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE)
- preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
- }
- data_offer_->SetAction(dnd_actions, preferred_action);
+ window_->OnDragEnter(
+ location, std::move(data),
+ DndActionsToDragOperations(data_offer_->source_actions()));
+ OnDragMotion(location);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
index 5e4c15dd08b..e4a7efbe2ab 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
@@ -11,9 +11,11 @@
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
+#include "ui/gfx/geometry/point_f.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_window_observer.h"
struct wl_surface;
class SkBitmap;
@@ -28,15 +30,41 @@ class WaylandWindow;
class WaylandWindowManager;
class WaylandShmBuffer;
-// WaylandDataDragController implements regular data exchanging between Chromium
-// and other client applications on top of the Wayland Drag and Drop protocol.
-// By implementing both DataDevice::DragDelegate and DataSource::Delegate,
-// it is responsible for handling both DND sessions initiated from Chromium
-// windows as well as those triggered by other clients.
+// WaylandDataDragController implements regular data exchange on top of the
+// Wayland Drag and Drop protocol. The data can be dragged within the Chromium
+// window, or between Chromium and other application in both directions.
+//
+// The outgoing drag starts via the StartSession() method. For more context,
+// see WaylandTopLevelWindow::StartDrag().
+//
+// The incoming drag starts with the call to OnDragEnter() from the Wayland side
+// (the data device), and ends up in call to WaylandWindow::OnDragEnter(), but
+// two ways of coming there are possible:
+//
+// 1. The drag has been initiated by a Chromium window. In this case, the data
+// that is being dragged is available right away, and therefore the controller
+// can forward the data to the window immediately.
+//
+// 2. The data is being dragged from another application. Before notifying the
+// window, the controller requests the data from the source side, which results
+// in a number of requests to Wayland and data transfers from it. Only after
+// data records of all supported MIME types have been received, the window will
+// be notified.
+//
+// It is possible that further drag events come while the data is still being
+// transferred. The drag motion event is ignored; the window will first receive
+// OnDragEnter, and any OnDragMotion that comes after that. The drag leave
+// event stops the transfer and cancels the operation; the window will not
+// receive anything at all.
class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
- public WaylandDataSource::Delegate {
+ public WaylandDataSource::Delegate,
+ public WaylandWindowObserver {
public:
- enum class State { kIdle, kStarted, kTransferring };
+ enum class State {
+ kIdle, // Doing nothing special
+ kStarted, // The outgoing drag is in progress.
+ kTransferring, // The incoming data is transferred from the source.
+ };
WaylandDataDragController(WaylandConnection* connection,
WaylandDataDeviceManager* data_device_manager);
@@ -77,14 +105,21 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
void OnDataSourceSend(const std::string& mime_type,
std::string* contents) override;
+ // WaylandWindowObserver:
+ void OnWindowRemoved(WaylandWindow* window) override;
+
void Offer(const OSExchangeData& data, int operation);
- void CreateIconSurfaceIfNeeded(const OSExchangeData& data);
- void HandleUnprocessedMimeTypes();
- void OnMimeTypeDataTransferred(PlatformClipboard::Data contents);
+ void HandleUnprocessedMimeTypes(base::TimeTicks start_time);
+ void OnMimeTypeDataTransferred(base::TimeTicks start_time,
+ PlatformClipboard::Data contents);
void OnDataTransferFinished(
+ base::TimeTicks start_time,
std::unique_ptr<ui::OSExchangeData> received_data);
std::string GetNextUnprocessedMimeType();
- void SetOperation(const int operation);
+ // Calls the window's OnDragEnter with the given location and data,
+ // then immediately calls OnDragMotion to get the actual operation.
+ void PropagateOnDragEnter(const gfx::PointF& location,
+ std::unique_ptr<OSExchangeData> data);
WaylandConnection* const connection_;
WaylandDataDeviceManager* const data_device_manager_;
@@ -93,6 +128,7 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
State state_ = State::kIdle;
+ // Data offered by us to the other side.
std::unique_ptr<WaylandDataSource> data_source_;
// When dragging is started from Chromium, |data_| holds the data to be sent
@@ -117,6 +153,9 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
// Current window under pointer.
WaylandWindow* window_ = nullptr;
+ // The most recent location received while dragging the data.
+ gfx::PointF last_drag_location_;
+
// The data delivered from Wayland
std::unique_ptr<ui::OSExchangeData> received_data_;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
index 8bd11603863..3e827a00928 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
@@ -14,24 +14,26 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/events/base_event_utils.h"
#include "ui/gfx/geometry/point.h"
#include "ui/ozone/platform/wayland/common/data_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
-#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
#include "ui/ozone/platform/wayland/test/test_data_device.h"
#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
#include "ui/ozone/platform/wayland/test/test_data_offer.h"
#include "ui/ozone/platform/wayland/test/test_data_source.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
+#include "ui/ozone/platform/wayland/test/wayland_drag_drop_test.h"
#include "ui/ozone/platform/wayland/test/wayland_test.h"
#include "ui/ozone/public/platform_clipboard.h"
#include "ui/platform_window/platform_window_init_properties.h"
@@ -78,12 +80,8 @@ class MockDropHandler : public WmDropHandler {
MockDropHandler() = default;
~MockDropHandler() override = default;
- MOCK_METHOD4(OnDragEnter,
- void(const gfx::PointF& point,
- std::unique_ptr<OSExchangeData> data,
- int operation,
- int modifiers));
- MOCK_METHOD3(OnDragMotion,
+ MOCK_METHOD0(MockOnDragEnter, void());
+ MOCK_METHOD3(MockDragMotion,
int(const gfx::PointF& point, int operation, int modifiers));
MOCK_METHOD0(MockOnDragDrop, void());
MOCK_METHOD0(OnDragLeave, void());
@@ -92,34 +90,52 @@ class MockDropHandler : public WmDropHandler {
on_drop_closure_ = closure;
}
+ void SetPreferredOperations(int preferred_operations) {
+ preferred_operations_ = preferred_operations;
+ }
+
OSExchangeData* dropped_data() { return dropped_data_.get(); }
+ int available_operations() const { return available_operations_; }
+
protected:
+ void OnDragEnter(const gfx::PointF& point,
+ std::unique_ptr<ui::OSExchangeData> data,
+ int operation,
+ int modifiers) override {
+ dropped_data_ = std::move(data);
+ MockOnDragEnter();
+ }
void OnDragDrop(std::unique_ptr<OSExchangeData> data,
int modifiers) override {
- dropped_data_ = std::move(data);
MockOnDragDrop();
on_drop_closure_.Run();
on_drop_closure_.Reset();
}
+ int OnDragMotion(const gfx::PointF& point,
+ int operation,
+ int modifiers) override {
+ available_operations_ = operation;
+ MockDragMotion(point, operation, modifiers);
+ return preferred_operations_;
+ }
+
private:
base::RepeatingClosure on_drop_closure_;
std::unique_ptr<OSExchangeData> dropped_data_;
+ int preferred_operations_ = ui::DragDropTypes::DRAG_COPY;
+ int available_operations_ = ui::DragDropTypes::DRAG_NONE;
};
-class WaylandDataDragControllerTest : public WaylandTest {
+class WaylandDataDragControllerTest : public WaylandDragDropTest {
public:
WaylandDataDragControllerTest() = default;
+ ~WaylandDataDragControllerTest() override = default;
void SetUp() override {
- WaylandTest::SetUp();
-
- Sync();
-
- data_device_manager_ = server_.data_device_manager();
- DCHECK(data_device_manager_);
+ WaylandDragDropTest::SetUp();
drag_handler_delegate_ = std::make_unique<MockDragHandlerDelegate>();
drop_handler_ = std::make_unique<MockDropHandler>();
@@ -134,63 +150,68 @@ class WaylandDataDragControllerTest : public WaylandTest {
return connection_->data_device_manager()->GetDevice();
}
+ MockDropHandler* drop_handler() { return drop_handler_.get(); }
+
+ MockDragHandlerDelegate* drag_handler() {
+ return drag_handler_delegate_.get();
+ }
+
+ wl::MockSurface* GetMockSurface(uint32_t id) {
+ return server_.GetObject<wl::MockSurface>(id);
+ }
+
+ WaylandConnection* connection() { return connection_.get(); }
+
+ WaylandWindow* window() { return window_.get(); }
+
base::string16 sample_text_for_dnd() const {
static auto text = base::ASCIIToUTF16(kSampleTextForDragAndDrop);
return text;
}
- void ReadDataWhenSourceIsReady() {
+ void RunDragLoopWithSampleData(WaylandWindow* origin_window, int operations) {
+ ASSERT_TRUE(origin_window);
+ OSExchangeData os_exchange_data;
+ os_exchange_data.SetString(sample_text_for_dnd());
+ origin_window->StartDrag(os_exchange_data, operations, /*cursor=*/{},
+ /*can_grab_pointer=*/true,
+ drag_handler_delegate_.get());
Sync();
+ }
- if (!data_device_manager_->data_source()) {
- // The data source is created asynchronously via the window's data drag
- // controller. If it is null now, it means that the task for that has not
- // yet executed, and we have to come later.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(
- &WaylandDataDragControllerTest::ReadDataWhenSourceIsReady,
- base::Unretained(this)));
- return;
- }
-
- // Now the server can read the data and give it to our callback.
- base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
- auto callback = base::BindOnce(
- [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
- std::string result(data.begin(), data.end());
- EXPECT_EQ(kSampleTextForDragAndDrop, result);
- loop->Quit();
- },
- &run_loop);
- data_device_manager_->data_source()->ReadData(kMimeTypeTextUtf8,
- std::move(callback));
- run_loop.Run();
-
- data_device_manager_->data_source()->OnCancelled();
+ std::unique_ptr<WaylandWindow> CreateTestWindow(
+ PlatformWindowType type,
+ const gfx::Size& size,
+ MockPlatformWindowDelegate* delegate) {
+ DCHECK(delegate);
+ PlatformWindowInitProperties properties{gfx::Rect(size)};
+ properties.type = type;
+ EXPECT_CALL(*delegate, OnAcceleratedWidgetAvailable(_)).Times(1);
+ auto window = WaylandWindow::Create(delegate, connection_.get(),
+ std::move(properties));
+ SetWmDropHandler(window.get(), drop_handler_.get());
+ EXPECT_NE(gfx::kNullAcceleratedWidget, window->GetWidget());
Sync();
+ return window;
}
void ScheduleDragCancel() {
- Sync();
+ ScheduleTestTask(base::BindOnce(
+ [](WaylandDataDragControllerTest* self) {
+ self->SendDndCancelled();
- if (!data_device_manager_->data_source()) {
- // The data source is created asynchronously by the data drag controller.
- // If it is null at this point, it means that the task for that has not
- // yet executed, and we have to try again a bit later.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&WaylandDataDragControllerTest::ScheduleDragCancel,
- base::Unretained(this)));
- return;
- }
+ // DnD handlers expect DragLeave to be sent before DragFinished when
+ // drag sessions end up with no data transfer (cancelled). Otherwise,
+ // it might lead to issues like https://crbug.com/1109324.
+ EXPECT_CALL(*self->drop_handler(), OnDragLeave).Times(1);
+ EXPECT_CALL(*self->drag_handler(), OnDragFinished).Times(1);
- data_device_manager_->data_source()->OnCancelled();
- Sync();
+ self->Sync();
+ },
+ base::Unretained(this)));
}
protected:
- wl::TestDataDeviceManager* data_device_manager_;
std::unique_ptr<MockDropHandler> drop_handler_;
std::unique_ptr<MockDragHandlerDelegate> drag_handler_delegate_;
};
@@ -199,22 +220,31 @@ TEST_P(WaylandDataDragControllerTest, StartDrag) {
const bool restored_focus = window_->has_pointer_focus();
window_->SetPointerFocus(true);
- // The client starts dragging.
- ASSERT_EQ(PlatformWindowType::kWindow, window_->type());
- OSExchangeData os_exchange_data;
- os_exchange_data.SetString(sample_text_for_dnd());
+ auto test = [](WaylandDataDragControllerTest* self) {
+ // Now the server can read the data and give it to our callback.
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ auto read_callback = base::BindOnce(
+ [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
+ std::string result(data.begin(), data.end());
+ EXPECT_EQ(kSampleTextForDragAndDrop, result);
+ loop->Quit();
+ },
+ &run_loop);
+ self->ReadData(kMimeTypeTextUtf8, std::move(read_callback));
+ run_loop.Run();
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&WaylandDataDragControllerTest::ReadDataWhenSourceIsReady,
- base::Unretained(this)));
+ self->SendDndCancelled();
+ self->Sync();
+ };
- static_cast<WaylandToplevelWindow*>(window_.get())
- ->StartDrag(os_exchange_data,
- DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE, {}, true,
- drag_handler_delegate_.get());
- Sync();
+ // Post test task to be performed asynchronously once the dnd-related protocol
+ // objects are ready.
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this)));
+ RunDragLoopWithSampleData(
+ window_.get(), DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE);
+
+ // Ensure drag delegate it properly reset when the drag loop quits.
EXPECT_FALSE(data_device()->drag_delegate_);
window_->SetPointerFocus(restored_focus);
@@ -286,6 +316,8 @@ TEST_P(WaylandDataDragControllerTest, ReceiveDrag) {
1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
wl_fixed_from_int(entered_point.y()), data_offer);
+ Sync();
+
int64_t time =
(EventTimeForNow() - base::TimeTicks()).InMilliseconds() & UINT32_MAX;
gfx::Point motion_point(11, 11);
@@ -323,27 +355,27 @@ TEST_P(WaylandDataDragControllerTest, DropSeveralMimeTypes) {
kMimeTypeURIList,
ToClipboardData(std::string("file:///home/user/file\r\n")));
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _, _)).Times(1);
+ EXPECT_CALL(*drop_handler_, MockOnDragEnter()).Times(1);
gfx::Point entered_point(10, 10);
data_device_manager_->data_device()->OnEnter(
1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
wl_fixed_from_int(entered_point.y()), data_offer);
+ // Here we are expecting three data items, so there will be three roundtrips
+ // to the Wayland and back. Hence Sync() three times.
+ Sync();
+ Sync();
Sync();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
base::RunLoop loop;
drop_handler_->SetOnDropClosure(loop.QuitClosure());
data_device_manager_->data_device()->OnDrop();
- // Here we are expecting three data items, so there will be three roundtrips
- // to the Wayland and back. Hence Sync() three times.
- Sync();
- Sync();
Sync();
loop.Run();
Mock::VerifyAndClearExpectations(drop_handler_.get());
+ ASSERT_NE(drop_handler_->dropped_data(), nullptr);
EXPECT_TRUE(drop_handler_->dropped_data()->HasString());
EXPECT_TRUE(drop_handler_->dropped_data()->HasFile());
EXPECT_TRUE(drop_handler_->dropped_data()->HasURL(kFilenameToURLPolicy));
@@ -370,13 +402,12 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedUriList) {
auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
data_offer->OnOffer(kMimeTypeURIList, ToClipboardData(kCase.content));
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _, _)).Times(1);
+ EXPECT_CALL(*drop_handler_, MockOnDragEnter()).Times(1);
gfx::Point entered_point(10, 10);
data_device_manager_->data_device()->OnEnter(
1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
wl_fixed_from_int(entered_point.y()), data_offer);
Sync();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
base::RunLoop loop;
@@ -425,13 +456,12 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedXMozUrl) {
data_offer->OnOffer(kMimeTypeMozillaURL,
ToClipboardData(base::UTF8ToUTF16(kCase.content)));
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _, _)).Times(1);
+ EXPECT_CALL(*drop_handler_, MockOnDragEnter()).Times(1);
gfx::Point entered_point(10, 10);
data_device_manager_->data_device()->OnEnter(
1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
wl_fixed_from_int(entered_point.y()), data_offer);
Sync();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
base::RunLoop loop;
@@ -468,27 +498,253 @@ TEST_P(WaylandDataDragControllerTest, StartAndCancel) {
const bool restored_focus = window_->has_pointer_focus();
window_->SetPointerFocus(true);
- ASSERT_EQ(PlatformWindowType::kWindow, window_->type());
+ // Schedule a wl_data_source::cancelled event to be sent asynchronously
+ // once the drag session gets started.
+ ScheduleDragCancel();
+
+ RunDragLoopWithSampleData(window_.get(), DragDropTypes::DRAG_COPY);
+
+ window_->SetPointerFocus(restored_focus);
+}
+
+TEST_P(WaylandDataDragControllerTest, ForeignDragHandleAskAction) {
+ auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
+ data_offer->OnOffer(kMimeTypeText,
+ ToClipboardData(std::string(kSampleTextForDragAndDrop)));
+ data_offer->OnSourceActions(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
+ data_offer->OnAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK);
+
+ gfx::Point entered_point(10, 10);
+ // The server sends an enter event.
+ data_device_manager_->data_device()->OnEnter(
+ 1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
+ wl_fixed_from_int(entered_point.y()), data_offer);
+ Sync();
+
+ int64_t time = 1;
+ gfx::Point motion_point(11, 11);
+
+ // Verify ask handling with drop handler preferring "copy" operation.
+ drop_handler_->SetPreferredOperations(ui::DragDropTypes::DRAG_COPY);
+ data_device_manager_->data_device()->OnMotion(
+ time, wl_fixed_from_int(motion_point.x()),
+ wl_fixed_from_int(motion_point.y()));
+ Sync();
+
+ EXPECT_EQ(WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY,
+ data_offer->preferred_action());
+ EXPECT_EQ(WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY,
+ data_offer->supported_actions());
+
+ data_device_manager_->data_device()->OnLeave();
+}
+
+// Verifies entered surface destruction is properly handled.
+// Regression test for https://crbug.com/1143707.
+TEST_P(WaylandDataDragControllerTest, DestroyEnteredSurface) {
+ auto* window_1 = window_.get();
+ const bool restored_focus = window_1->has_pointer_focus();
+ window_1->SetPointerFocus(true);
+ ASSERT_EQ(PlatformWindowType::kWindow, window_1->type());
+
+ auto test = [](WaylandDataDragControllerTest* self) {
+ // Init and open |target_window|.
+ MockPlatformWindowDelegate delegate_2;
+ auto window_2 = self->CreateTestWindow(PlatformWindowType::kWindow,
+ gfx::Size(80, 80), &delegate_2);
+
+ // Leave |window_1| and enter |window_2|.
+ self->SendDndLeave();
+ self->SendDndEnter(window_2.get(), gfx::Point(20, 20));
+ self->Sync();
+
+ // Destroy the entered window at client side and emulates a
+ // wl_data_device::leave to ensure no UAF happens.
+ window_2->PrepareForShutdown();
+ window_2.reset();
+ self->SendDndLeave();
+ self->Sync();
+
+ // Emulate server sending an wl_data_source::cancelled event so the drag
+ // loop is finished.
+ self->SendDndCancelled();
+ self->Sync();
+ };
+
+ // Post test task to be performed asynchronously once the drag session gets
+ // started.
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this)));
+
+ RunDragLoopWithSampleData(window_.get(), DragDropTypes::DRAG_COPY);
+
+ window_1->SetPointerFocus(restored_focus);
+}
+
+// Verifies that early origin surface destruction is properly handled.
+// Regression test for https://crbug.com/1143707.
+TEST_P(WaylandDataDragControllerTest, DestroyOriginSurface) {
+ auto* window_1 = window_.get();
+ const bool restored_focus = window_1->has_pointer_focus();
+ window_1->SetPointerFocus(false);
+ ASSERT_EQ(PlatformWindowType::kWindow, window_1->type());
+
+ auto test = [](WaylandDataDragControllerTest* self,
+ std::unique_ptr<WaylandWindow>* origin) {
+ // Leave origin surface and enter |window_|.
+ self->SendDndLeave();
+ self->SendDndEnter(self->window(), gfx::Point(20, 20));
+ self->Sync();
+
+ // Shutdown and destroy the popup window where the drag session was
+ // initiated, which leads to the drag loop to finish.
+ (*origin)->PrepareForShutdown();
+ origin->reset();
+ };
+
+ // Init and open |target_window|.
+ MockPlatformWindowDelegate delegate_2;
+ auto window_2 = CreateTestWindow(PlatformWindowType::kPopup,
+ gfx::Size(80, 80), &delegate_2);
+ window_2->SetPointerFocus(true);
+ Sync();
+
+ // Post test task to be performed asynchronously once the drag session gets
+ // started.
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this),
+ base::Unretained(&window_2)));
+
+ // Request to start the drag session, which spins a nested run loop.
OSExchangeData os_exchange_data;
os_exchange_data.SetString(sample_text_for_dnd());
+ window_2->StartDrag(os_exchange_data, DragDropTypes::DRAG_COPY, {}, true,
+ drag_handler_delegate_.get());
+ Sync();
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&WaylandDataDragControllerTest::ScheduleDragCancel,
- base::Unretained(this)));
+ // Send wl_data_source::cancelled event. The drag controller is then
+ // expected to gracefully reset its internal state.
+ SendDndLeave();
+ SendDndCancelled();
+ Sync();
- // DnD handlers expect DragLeave to be sent before DragFinished when drag
- // sessions end up with no data transfer (cancelled). Otherwise, it might lead
- // to issues like https://crbug.com/1109324.
- EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(1);
- EXPECT_CALL(*drag_handler_delegate_, OnDragFinished(_)).Times(1);
+ window_1->SetPointerFocus(restored_focus);
+}
- static_cast<WaylandToplevelWindow*>(window_.get())
- ->StartDrag(os_exchange_data, DragDropTypes::DRAG_COPY, {}, true,
- drag_handler_delegate_.get());
- Sync();
+// Ensures drag/drop events are properly propagated to non-toplevel windows.
+TEST_P(WaylandDataDragControllerTest, DragToNonToplevelWindows) {
+ auto* origin_window = window_.get();
+ const bool restored_focus = origin_window->has_pointer_focus();
+ origin_window->SetPointerFocus(true);
+
+ auto test = [](WaylandDataDragControllerTest* self,
+ PlatformWindowType window_type) {
+ // Init and open |target_window|.
+ MockPlatformWindowDelegate aux_window_delegate;
+ auto aux_window = self->CreateTestWindow(window_type, gfx::Size(100, 40),
+ &aux_window_delegate);
+
+ // Leave |origin_window| and enter non-toplevel |aux_window|.
+ self->SendDndLeave();
+ EXPECT_CALL(*self->drop_handler(), OnDragLeave).Times(1);
+ self->Sync();
+
+ self->SendDndEnter(aux_window.get(), {});
+ EXPECT_CALL(*self->drop_handler(), MockOnDragEnter()).Times(1);
+ EXPECT_CALL(*self->drop_handler(), MockDragMotion(_, _, _)).Times(1);
+ self->Sync();
+
+ // Goes back to |origin_window|, as |aux_window| is going to get destroyed
+ // once this test task finishes.
+ self->SendDndLeave();
+ EXPECT_CALL(*self->drop_handler(), OnDragLeave).Times(1);
+ self->Sync();
+
+ self->SendDndEnter(self->window(), {});
+ EXPECT_CALL(*self->drop_handler(), MockOnDragEnter()).Times(1);
+ EXPECT_CALL(*self->drop_handler(), MockDragMotion(_, _, _)).Times(1);
+ self->Sync();
+ };
+
+ // Post test tasks, for each non-toplevel window type, to be performed
+ // asynchronously once the dnd-related protocol objects are ready.
+ constexpr PlatformWindowType kNonToplevelWindowTypes[]{
+ PlatformWindowType::kPopup, PlatformWindowType::kMenu,
+ PlatformWindowType::kTooltip, PlatformWindowType::kBubble};
+ for (auto window_type : kNonToplevelWindowTypes)
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this), window_type));
+
+ // Post a wl_data_source::cancelled notifying the client to tear down the drag
+ // session.
+ ScheduleDragCancel();
+
+ // Request to start the drag session, which spins a nested run loop.
+ RunDragLoopWithSampleData(origin_window, DragDropTypes::DRAG_COPY);
+
+ origin_window->SetPointerFocus(restored_focus);
+}
- window_->SetPointerFocus(restored_focus);
+// Ensures that requests to create a |PlatformWindowType::kPopup| during drag
+// sessions return wl_subsurface-backed windows.
+TEST_P(WaylandDataDragControllerTest, PopupRequestCreatesAuxiliaryWindow) {
+ auto* origin_window = window_.get();
+ const bool restored_focus = origin_window->has_pointer_focus();
+ origin_window->SetPointerFocus(true);
+
+ auto test = [](WaylandDataDragControllerTest* self) {
+ MockPlatformWindowDelegate delegate;
+ auto popup_window = self->CreateTestWindow(PlatformWindowType::kPopup,
+ gfx::Size(100, 40), &delegate);
+ popup_window->Show(false);
+ self->Sync();
+
+ auto* surface =
+ self->GetMockSurface(popup_window->root_surface()->GetSurfaceId());
+ ASSERT_TRUE(surface);
+ EXPECT_NE(nullptr, surface->sub_surface());
+ };
+
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this)));
+
+ // Post a wl_data_source::cancelled notifying the client to tear down the drag
+ // session.
+ ScheduleDragCancel();
+
+ // Request to start the drag session, which spins a nested run loop.
+ RunDragLoopWithSampleData(origin_window, DragDropTypes::DRAG_COPY);
+
+ origin_window->SetPointerFocus(restored_focus);
+}
+
+// Ensures that requests to create a |PlatformWindowType::kMenu| during drag
+// sessions return xdg_popup-backed windows.
+TEST_P(WaylandDataDragControllerTest, MenuRequestCreatesPopupWindow) {
+ auto* origin_window = window_.get();
+ const bool restored_focus = origin_window->has_pointer_focus();
+ origin_window->SetPointerFocus(true);
+
+ auto test = [](WaylandDataDragControllerTest* self) {
+ MockPlatformWindowDelegate delegate;
+ auto menu_window = self->CreateTestWindow(PlatformWindowType::kMenu,
+ gfx::Size(100, 40), &delegate);
+ menu_window->Show(false);
+ self->Sync();
+
+ auto* surface =
+ self->GetMockSurface(menu_window->root_surface()->GetSurfaceId());
+ ASSERT_TRUE(surface);
+ EXPECT_EQ(nullptr, surface->sub_surface());
+ };
+
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this)));
+
+ // Post a wl_data_source::cancelled notifying the client to tear down the drag
+ // session.
+ ScheduleDragCancel();
+
+ // Request to start the drag session, which spins a nested run loop.
+ RunDragLoopWithSampleData(origin_window, DragDropTypes::DRAG_COPY);
+
+ origin_window->SetPointerFocus(restored_focus);
}
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc
index 84d29d32b60..7e2a7143fd7 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc
@@ -24,14 +24,6 @@ WaylandDataOffer::~WaylandDataOffer() {
data_offer_.reset();
}
-void WaylandDataOffer::SetAction(uint32_t dnd_actions,
- uint32_t preferred_action) {
- if (wl::get_version_of_object(data_offer_.get()) >=
- WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) {
- wl_data_offer_set_actions(data_offer_.get(), dnd_actions, preferred_action);
- }
-}
-
void WaylandDataOffer::Accept(uint32_t serial, const std::string& mime_type) {
wl_data_offer_accept(data_offer_.get(), serial, mime_type.c_str());
}
@@ -68,12 +60,21 @@ void WaylandDataOffer::FinishOffer() {
}
}
-uint32_t WaylandDataOffer::source_actions() const {
- return source_actions_;
-}
+void WaylandDataOffer::SetActions(uint32_t dnd_actions) {
+ if (wl::get_version_of_object(data_offer_.get()) <
+ WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) {
+ return;
+ }
+
+ // Determine preferred action based on the given |dnd_actions|, prioritizing
+ // "copy" over "move", if both are set.
+ uint32_t preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+ if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
+ preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ else if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
+ preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
-uint32_t WaylandDataOffer::dnd_action() const {
- return dnd_action_;
+ wl_data_offer_set_actions(data_offer_.get(), dnd_actions, preferred_action);
}
// static
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h
index a724709c9c1..467e4c48d4c 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h
@@ -27,16 +27,16 @@ class WaylandDataOffer : public WaylandDataOfferBase {
explicit WaylandDataOffer(wl_data_offer* data_offer);
~WaylandDataOffer() override;
- void SetAction(uint32_t dnd_actions, uint32_t preferred_action);
void Accept(uint32_t serial, const std::string& mime_type);
void Reject(uint32_t serial);
+ void FinishOffer();
// WaylandDataOfferBase overrides:
base::ScopedFD Receive(const std::string& mime_type) override;
- void FinishOffer();
- uint32_t source_actions() const;
- uint32_t dnd_action() const;
+ uint32_t source_actions() const { return source_actions_; }
+ uint32_t dnd_action() const { return dnd_action_; }
+ void SetActions(uint32_t dnd_actions);
private:
// wl_data_offer_listener callbacks.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc
index cbdd82a25d0..bf4393a9a17 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc
@@ -4,7 +4,7 @@
#include "ui/ozone/platform/wayland/host/wayland_data_offer_base.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "ui/base/clipboard/clipboard_constants.h"
namespace ui {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
index 15eb6b6e2c2..28f5892a0e9 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
@@ -17,6 +17,8 @@
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/pointer_details.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/point_f.h"
@@ -85,17 +87,6 @@ bool WaylandEventSource::StopProcessingEvents() {
return event_watcher_->StopProcessingEvents();
}
-void WaylandEventSource::OnKeyboardCreated(WaylandKeyboard* keyboard) {
- DCHECK(keyboard);
- keyboard_ = keyboard;
-}
-
-void WaylandEventSource::OnKeyboardDestroyed(WaylandKeyboard* keyboard) {
- DCHECK_EQ(keyboard_, keyboard);
- keyboard_modifiers_ = 0;
- keyboard_ = nullptr;
-}
-
void WaylandEventSource::OnKeyboardFocusChanged(WaylandWindow* window,
bool focused) {
DCHECK(window);
@@ -109,14 +100,15 @@ void WaylandEventSource::OnKeyboardModifiersChanged(int modifiers) {
uint32_t WaylandEventSource::OnKeyboardKeyEvent(EventType type,
DomCode dom_code,
bool repeat,
- base::TimeTicks timestamp) {
+ base::TimeTicks timestamp,
+ int device_id) {
DCHECK(type == ET_KEY_PRESSED || type == ET_KEY_RELEASED);
- if (!keyboard_)
- return POST_DISPATCH_NONE;
DomKey dom_key;
KeyboardCode key_code;
- if (!keyboard_->Decode(dom_code, keyboard_modifiers_, &dom_key, &key_code)) {
+ auto* layout_engine = KeyboardLayoutEngineManager::GetKeyboardLayoutEngine();
+ if (!layout_engine || !layout_engine->Lookup(dom_code, keyboard_modifiers_,
+ &dom_key, &key_code)) {
LOG(ERROR) << "Failed to decode key event.";
return POST_DISPATCH_NONE;
}
@@ -128,30 +120,12 @@ uint32_t WaylandEventSource::OnKeyboardKeyEvent(EventType type,
KeyEvent event(type, key_code, dom_code, keyboard_modifiers_, dom_key,
timestamp);
- event.set_source_device_id(keyboard_->device_id());
+ event.set_source_device_id(device_id);
return DispatchEvent(&event);
}
-void WaylandEventSource::OnPointerCreated(WaylandPointer* pointer) {
- DCHECK(pointer);
- pointer_ = pointer;
-}
-
-void WaylandEventSource::OnPointerDestroyed(WaylandPointer* pointer) {
- DCHECK_EQ(pointer_, pointer);
-
- // Clear focused window, if any.
- HandlePointerFocusChange(nullptr);
-
- ResetPointerFlags();
- pointer_ = nullptr;
-}
-
void WaylandEventSource::OnPointerFocusChanged(WaylandWindow* window,
const gfx::PointF& location) {
- if (!pointer_)
- return;
-
// Save new pointer location.
pointer_location_ = location;
@@ -174,9 +148,6 @@ void WaylandEventSource::OnPointerButtonEvent(EventType type,
DCHECK(type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED);
DCHECK(HasAnyPointerButtonFlag(changed_button));
- if (!pointer_)
- return;
-
auto* prev_focused_window = window_with_pointer_focus_;
if (window)
HandlePointerFocusChange(window);
@@ -212,6 +183,10 @@ void WaylandEventSource::OnPointerAxisEvent(const gfx::Vector2d& offset) {
current_pointer_frame_.dy += offset.y();
}
+void WaylandEventSource::OnResetPointerFlags() {
+ ResetPointerFlags();
+}
+
void WaylandEventSource::OnPointerFrameEvent() {
base::TimeTicks now = EventTimeForNow();
current_pointer_frame_.dt = now - last_pointer_frame_time_;
@@ -255,17 +230,6 @@ void WaylandEventSource::OnPointerAxisStopEvent(uint32_t axis) {
current_pointer_frame_.is_axis_stop = true;
}
-void WaylandEventSource::OnTouchCreated(WaylandTouch* touch) {
- DCHECK(touch);
- touch_ = touch;
-}
-
-void WaylandEventSource::OnTouchDestroyed(WaylandTouch* touch) {
- DCHECK_EQ(touch_, touch);
- touch_points_.clear();
- touch_ = nullptr;
-}
-
void WaylandEventSource::OnTouchPressEvent(WaylandWindow* window,
const gfx::PointF& location,
base::TimeTicks timestamp,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
index dfda62810e5..ed0a6f85250 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
@@ -81,18 +81,15 @@ class WaylandEventSource : public PlatformEventSource,
protected:
// WaylandKeyboard::Delegate
- void OnKeyboardCreated(WaylandKeyboard* keyboard) override;
- void OnKeyboardDestroyed(WaylandKeyboard* keyboard) override;
void OnKeyboardFocusChanged(WaylandWindow* window, bool focused) override;
void OnKeyboardModifiersChanged(int modifiers) override;
uint32_t OnKeyboardKeyEvent(EventType type,
DomCode dom_code,
bool repeat,
- base::TimeTicks timestamp) override;
+ base::TimeTicks timestamp,
+ int device_id) override;
// WaylandPointer::Delegate
- void OnPointerCreated(WaylandPointer* pointer) override;
- void OnPointerDestroyed(WaylandPointer* pointer) override;
void OnPointerFocusChanged(WaylandWindow* window,
const gfx::PointF& location) override;
void OnPointerButtonEvent(EventType evtype,
@@ -103,10 +100,9 @@ class WaylandEventSource : public PlatformEventSource,
void OnPointerFrameEvent() override;
void OnPointerAxisSourceEvent(uint32_t axis_source) override;
void OnPointerAxisStopEvent(uint32_t axis) override;
+ void OnResetPointerFlags() override;
// WaylandTouch::Delegate
- void OnTouchCreated(WaylandTouch* touch) override;
- void OnTouchDestroyed(WaylandTouch* touch) override;
void OnTouchPressEvent(WaylandWindow* window,
const gfx::PointF& location,
base::TimeTicks timestamp,
@@ -146,11 +142,6 @@ class WaylandEventSource : public PlatformEventSource,
WaylandWindowManager* const window_manager_;
- // Input device objects. Owned by WaylandConnection.
- WaylandKeyboard* keyboard_ = nullptr;
- WaylandPointer* pointer_ = nullptr;
- WaylandTouch* touch_ = nullptr;
-
// Bitmask of EventFlags used to keep track of the the pointer state.
int pointer_flags_ = 0;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
index 9fd65bd9afa..c97a0e31bd3 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
@@ -4,8 +4,11 @@
#include "ui/ozone/platform/wayland/host/wayland_event_watcher.h"
+#include <cstring>
+
#include "base/bind.h"
#include "base/check.h"
+#include "base/logging.h"
#include "base/task/current_thread.h"
#include "ui/events/event.h"
#include "ui/ozone/platform/wayland/common/wayland.h"
@@ -55,6 +58,8 @@ void WaylandEventWatcher::OnFileCanReadWithoutBlocking(int fd) {
if (prepared_) {
prepared_ = false;
+ // Errors will be checked the next time OnFileCanReadWithoutBlocking calls
+ // CheckForErrors.
if (wl_display_read_events(display_) == -1)
return;
wl_display_dispatch_pending(display_);
@@ -114,13 +119,38 @@ void WaylandEventWatcher::MaybePrepareReadQueue() {
}
bool WaylandEventWatcher::CheckForErrors() {
+ // Errors are fatal. If this function returns non-zero the display can no
+ // longer be used.
int err = wl_display_get_error(display_);
- if (err == EPROTO) {
+
+ // TODO(crbug.com/1172305): Wayland display_error message should be printed
+ // automatically by wl_log(). However, wl_log() does not print anything. Needs
+ // investigation.
+ if (err) {
+ // When |err| is EPROTO, we can still use the |display_| to retrieve the
+ // protocol error. Otherwise, get the error string from strerror and
+ // shutdown the browser.
+ if (err == EPROTO) {
+ uint32_t ec, id;
+ const struct wl_interface* intf;
+ ec = wl_display_get_protocol_error(display_, &intf, &id);
+ if (intf) {
+ LOG(ERROR) << "Fatal Wayland protocol error " << ec << " on interface "
+ << intf->name << " (object " << id << "). Shutting down..";
+ } else {
+ LOG(ERROR) << "Fatal Wayland protocol error " << ec
+ << ". Shutting down..";
+ }
+ } else {
+ LOG(ERROR) << "Fatal Wayland communication error: " << std::strerror(err);
+ }
+
// This can be null in tests.
if (!shutdown_cb_.is_null())
std::move(shutdown_cb_).Run();
return false;
}
+
return true;
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
index a7bd5baba4f..b7e3c6b3238 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
@@ -12,6 +12,7 @@
#include "base/optional.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/ime/composition_text.h"
#include "ui/base/ime/ime_text_span.h"
#include "ui/events/base_event_utils.h"
@@ -24,9 +25,16 @@
#include "ui/ozone/public/ozone_switches.h"
#if BUILDFLAG(USE_XKBCOMMON)
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h"
#endif
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "base/check.h"
+#include "chromeos/crosapi/mojom/crosapi.mojom.h"
+#include "chromeos/lacros/lacros_chrome_service_impl.h"
+#endif
+
namespace ui {
namespace {
@@ -42,6 +50,41 @@ base::Optional<size_t> OffsetFromUTF8Offset(const base::StringPiece& text,
return converted.size();
}
+bool IsImeEnabled() {
+ base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ // We do not expect both switches are set at the same time.
+ DCHECK(!cmd_line->HasSwitch(switches::kEnableWaylandIme) ||
+ !cmd_line->HasSwitch(switches::kDisableWaylandIme));
+ // Force enable/disable wayland IMEs, when explictly specified via commandline
+ // arguments.
+ if (cmd_line->HasSwitch(switches::kEnableWaylandIme))
+ return true;
+ if (cmd_line->HasSwitch(switches::kDisableWaylandIme))
+ return false;
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ // On Lacros chrome, we check whether ash-chrome supports IME, then
+ // enable IME if so. This allows us to control IME enabling state in
+ // Lacros-chrome side, which helps us on releasing.
+ // TODO(crbug.com/1159237): In the future, we may want to unify the behavior
+ // of ozone/wayland across platforms.
+ const auto* lacros_chrome_service = chromeos::LacrosChromeServiceImpl::Get();
+
+ // Note: |init_params| may be null, if ash-chrome is too old.
+ // TODO(crbug.com/1156033): Clean up the condition, after ash-chrome in the
+ // world becomes new enough.
+ const crosapi::mojom::BrowserInitParams* init_params =
+ lacros_chrome_service->init_params();
+ if (init_params && init_params->exo_ime_support !=
+ crosapi::mojom::ExoImeSupport::kUnsupported) {
+ return true;
+ }
+#endif
+
+ // Do not enable wayland IME by default.
+ return false;
+}
+
} // namespace
WaylandInputMethodContext::WaylandInputMethodContext(
@@ -65,10 +108,8 @@ WaylandInputMethodContext::~WaylandInputMethodContext() {
}
void WaylandInputMethodContext::Init(bool initialize_for_testing) {
- bool use_ozone_wayland_vkb =
- initialize_for_testing ||
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableWaylandIme);
+ bool use_ozone_wayland_vkb = initialize_for_testing || IsImeEnabled();
+
// If text input instance is not created then all ime context operations
// are noop. This option is because in some environments someone might not
// want to enable ime/virtual keyboard even if it's available.
@@ -215,16 +256,24 @@ void WaylandInputMethodContext::OnKeysym(uint32_t keysym,
uint32_t state,
uint32_t modifiers) {
#if BUILDFLAG(USE_XKBCOMMON)
+ auto* layout_engine = KeyboardLayoutEngineManager::GetKeyboardLayoutEngine();
+ if (!layout_engine)
+ return;
+
// TODO(crbug.com/1079353): Handle modifiers.
- DomCode dom_code =
- connection_->keyboard()->layout_engine()->GetDomCodeByKeysym(keysym);
+ DomCode dom_code = static_cast<XkbKeyboardLayoutEngine*>(layout_engine)
+ ->GetDomCodeByKeysym(keysym);
if (dom_code == DomCode::NONE)
return;
+ // Keyboard might not exist.
+ int device_id =
+ connection_->keyboard() ? connection_->keyboard()->device_id() : 0;
+
EventType type =
state == WL_KEYBOARD_KEY_STATE_PRESSED ? ET_KEY_PRESSED : ET_KEY_RELEASED;
key_delegate_->OnKeyboardKeyEvent(type, dom_code, /*repeat=*/false,
- EventTimeForNow());
+ EventTimeForNow(), device_id);
#else
NOTIMPLEMENTED();
#endif
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
index 7b1e06e7ad5..812bdfcaf5a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
@@ -51,9 +51,6 @@ WaylandKeyboard::WaylandKeyboard(
&WaylandKeyboard::Modifiers, &WaylandKeyboard::RepeatInfo,
};
- DCHECK(delegate_);
- delegate_->OnKeyboardCreated(this);
-
wl_keyboard_add_listener(obj_.get(), &listener, this);
// TODO(tonikitoo): Default auto-repeat to ON here?
@@ -63,7 +60,8 @@ WaylandKeyboard::WaylandKeyboard(
}
WaylandKeyboard::~WaylandKeyboard() {
- delegate_->OnKeyboardDestroyed(this);
+ // Reset keyboard modifiers on destruction.
+ delegate_->OnKeyboardModifiersChanged(0);
}
void WaylandKeyboard::Keymap(void* data,
@@ -194,8 +192,9 @@ void WaylandKeyboard::DispatchKey(uint32_t key,
// Pass empty DomKey and KeyboardCode here so the delegate can pre-process
// and decode it when needed.
- uint32_t result = delegate_->OnKeyboardKeyEvent(
- down ? ET_KEY_PRESSED : ET_KEY_RELEASED, dom_code, repeat, timestamp);
+ uint32_t result =
+ delegate_->OnKeyboardKeyEvent(down ? ET_KEY_PRESSED : ET_KEY_RELEASED,
+ dom_code, repeat, timestamp, device_id);
if (extended_keyboard_v1_) {
bool handled = result & POST_DISPATCH_STOP_PROPAGATION;
@@ -204,15 +203,6 @@ void WaylandKeyboard::DispatchKey(uint32_t key,
}
}
-bool WaylandKeyboard::Decode(DomCode dom_code,
- int modifiers,
- DomKey* out_dom_key,
- KeyboardCode* out_key_code) {
- DCHECK(out_dom_key);
- DCHECK(out_key_code);
- return layout_engine_->Lookup(dom_code, modifiers, out_dom_key, out_key_code);
-}
-
void WaylandKeyboard::SyncCallback(void* data,
struct wl_callback* cb,
uint32_t time) {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
index d655dc09cc3..d6f0b0bb025 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
@@ -17,7 +17,6 @@
namespace ui {
-class DomKey;
class KeyboardLayoutEngine;
class WaylandConnection;
class WaylandWindow;
@@ -29,14 +28,6 @@ class WaylandKeyboard : public EventAutoRepeatHandler::Delegate {
public:
class Delegate;
- using LayoutEngine =
-#if BUILDFLAG(USE_XKBCOMMON)
- XkbKeyboardLayoutEngine
-#else
- KeyboardLayoutEngine
-#endif
- ;
-
WaylandKeyboard(wl_keyboard* keyboard,
zcr_keyboard_extension_v1* keyboard_extension_v1,
WaylandConnection* connection,
@@ -45,13 +36,16 @@ class WaylandKeyboard : public EventAutoRepeatHandler::Delegate {
virtual ~WaylandKeyboard();
int device_id() const { return obj_.id(); }
- bool Decode(DomCode dom_code,
- int modifiers,
- DomKey* out_dom_key,
- KeyboardCode* out_key_code);
- LayoutEngine* layout_engine() const { return layout_engine_; }
private:
+ using LayoutEngine =
+#if BUILDFLAG(USE_XKBCOMMON)
+ XkbKeyboardLayoutEngine
+#else
+ KeyboardLayoutEngine
+#endif
+ ;
+
// wl_keyboard_listener
static void Keymap(void* data,
wl_keyboard* obj,
@@ -113,8 +107,6 @@ class WaylandKeyboard : public EventAutoRepeatHandler::Delegate {
class WaylandKeyboard::Delegate {
public:
- virtual void OnKeyboardCreated(WaylandKeyboard* keyboard) = 0;
- virtual void OnKeyboardDestroyed(WaylandKeyboard* keyboard) = 0;
virtual void OnKeyboardFocusChanged(WaylandWindow* window, bool focused) = 0;
virtual void OnKeyboardModifiersChanged(int modifiers) = 0;
// Returns a mask of ui::PostDispatchAction indicating how the event was
@@ -122,7 +114,8 @@ class WaylandKeyboard::Delegate {
virtual uint32_t OnKeyboardKeyEvent(EventType type,
DomCode dom_code,
bool repeat,
- base::TimeTicks timestamp) = 0;
+ base::TimeTicks timestamp,
+ int device_id) = 0;
protected:
// Prevent deletion through a WaylandKeyboard::Delegate pointer.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
index b4fb4f09c5c..50d55f66b5c 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -27,14 +27,15 @@ WaylandPointer::WaylandPointer(wl_pointer* pointer,
&WaylandPointer::AxisSource, &WaylandPointer::AxisStop,
&WaylandPointer::AxisDiscrete};
- DCHECK(delegate_);
- delegate_->OnPointerCreated(this);
-
wl_pointer_add_listener(obj_.get(), &listener, this);
}
WaylandPointer::~WaylandPointer() {
- delegate_->OnPointerDestroyed(this);
+ // Even though, WaylandPointer::Leave is always called when Wayland destroys
+ // wl_pointer, it's better to be explicit as some Wayland compositors may have
+ // bugs.
+ delegate_->OnPointerFocusChanged(nullptr, {});
+ delegate_->OnResetPointerFlags();
}
// static
@@ -130,7 +131,7 @@ void WaylandPointer::Axis(void* data,
offset.set_y(-wl_fixed_to_double(value) / kAxisValueScale *
MouseWheelEvent::kWheelDelta);
} else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
- offset.set_x(wl_fixed_to_double(value) / kAxisValueScale *
+ offset.set_x(-wl_fixed_to_double(value) / kAxisValueScale *
MouseWheelEvent::kWheelDelta);
} else {
return;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
index 2ebb8419769..f9ad83b385a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
@@ -80,8 +80,6 @@ class WaylandPointer {
class WaylandPointer::Delegate {
public:
- virtual void OnPointerCreated(WaylandPointer* pointer) = 0;
- virtual void OnPointerDestroyed(WaylandPointer* pointer) = 0;
virtual void OnPointerFocusChanged(WaylandWindow* window,
const gfx::PointF& location) = 0;
virtual void OnPointerButtonEvent(EventType evtype,
@@ -92,6 +90,7 @@ class WaylandPointer::Delegate {
virtual void OnPointerFrameEvent() = 0;
virtual void OnPointerAxisSourceEvent(uint32_t axis_source) = 0;
virtual void OnPointerAxisStopEvent(uint32_t axis) = 0;
+ virtual void OnResetPointerFlags() = 0;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
index 91e9b9707c6..94d56df903a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
@@ -234,7 +234,7 @@ TEST_P(WaylandPointerTest, AxisHorizontal) {
ASSERT_TRUE(event);
ASSERT_TRUE(event->IsMouseWheelEvent());
auto* mouse_wheel_event = event->AsMouseWheelEvent();
- EXPECT_EQ(gfx::Vector2d(MouseWheelEvent::kWheelDelta, 0),
+ EXPECT_EQ(gfx::Vector2d(-MouseWheelEvent::kWheelDelta, 0),
mouse_wheel_event->offset());
EXPECT_EQ(EF_LEFT_MOUSE_BUTTON, mouse_wheel_event->button_flags());
EXPECT_EQ(0, mouse_wheel_event->changed_button_flags());
@@ -340,11 +340,11 @@ TEST_P(WaylandPointerTest, FlingVertical) {
EXPECT_EQ(ET_SCROLL_FLING_START, scroll_event->type());
EXPECT_EQ(gfx::PointF(50, 75), scroll_event->location_f());
EXPECT_EQ(0.0f, scroll_event->x_offset());
+ EXPECT_EQ(0.0f, scroll_event->x_offset_ordinal());
// Initial vertical velocity depends on the implementation outside of
// WaylandPointer, but it should be negative value based on the direction of
// recent two axis events.
EXPECT_GT(0.0f, scroll_event->y_offset());
- EXPECT_EQ(0.0f, scroll_event->x_offset_ordinal());
EXPECT_GT(0.0f, scroll_event->y_offset_ordinal());
}
@@ -393,13 +393,13 @@ TEST_P(WaylandPointerTest, FlingHorizontal) {
auto* scroll_event = event3->AsScrollEvent();
EXPECT_EQ(ET_SCROLL_FLING_START, scroll_event->type());
EXPECT_EQ(gfx::PointF(50, 75), scroll_event->location_f());
- // Initial horizontal velocity depends on the implementation outside of
- // WaylandPointer, but it should be positive value based on the direction of
- // recent two axis events.
- EXPECT_LT(0.0f, scroll_event->x_offset());
EXPECT_EQ(0.0f, scroll_event->y_offset());
- EXPECT_LT(0.0f, scroll_event->x_offset_ordinal());
EXPECT_EQ(0.0f, scroll_event->y_offset_ordinal());
+ // Initial horizontal velocity depends on the implementation outside of
+ // WaylandPointer, but it should be negative value based on the direction of
+ // recent two axis events.
+ EXPECT_GT(0.0f, scroll_event->x_offset());
+ EXPECT_GT(0.0f, scroll_event->x_offset_ordinal());
}
TEST_P(WaylandPointerTest, FlingCancel) {
@@ -518,10 +518,10 @@ TEST_P(WaylandPointerTest, FlingDiagonal) {
auto* scroll_event = event5->AsScrollEvent();
EXPECT_EQ(ET_SCROLL_FLING_START, scroll_event->type());
EXPECT_EQ(gfx::PointF(50, 75), scroll_event->location_f());
- // Check the offset direction. It should non-zero in both directions.
- EXPECT_LT(0.0f, scroll_event->x_offset());
+ // Check the offset direction. It should non-zero in both axes.
+ EXPECT_GT(0.0f, scroll_event->x_offset());
EXPECT_GT(0.0f, scroll_event->y_offset());
- EXPECT_LT(0.0f, scroll_event->x_offset_ordinal());
+ EXPECT_GT(0.0f, scroll_event->x_offset_ordinal());
EXPECT_GT(0.0f, scroll_event->y_offset_ordinal());
// Horizontal offset should be larger than vertical one, given the scroll
// offset in each direction.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
index 62601c3dde5..736b2388374 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
@@ -4,11 +4,14 @@
#include "ui/ozone/platform/wayland/host/wayland_popup.h"
+#include <aura-shell-client-protocol.h>
+
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_zaura_shell.h"
namespace ui {
@@ -33,9 +36,22 @@ bool WaylandPopup::CreateShellPopup() {
}
parent_window()->set_child_window(this);
+ InitializeAuraShellSurface();
return true;
}
+void WaylandPopup::InitializeAuraShellSurface() {
+ DCHECK(shell_popup_);
+ if (!connection()->zaura_shell() || aura_surface_)
+ return;
+ aura_surface_.reset(zaura_shell_get_aura_surface(
+ connection()->zaura_shell()->wl_object(), root_surface()->surface()));
+ if (shadow_type_ == PlatformWindowShadowType::kDrop) {
+ zaura_surface_set_frame(aura_surface_.get(),
+ ZAURA_SURFACE_FRAME_TYPE_SHADOW);
+ }
+}
+
void WaylandPopup::Show(bool inactive) {
if (shell_popup_)
return;
@@ -121,6 +137,10 @@ void WaylandPopup::HandlePopupConfigure(const gfx::Rect& bounds_dip) {
SetBoundsDip(new_bounds_dip);
}
+void WaylandPopup::HandleSurfaceConfigure(uint32_t serial) {
+ shell_popup()->AckConfigure(serial);
+}
+
void WaylandPopup::OnCloseRequest() {
// Before calling OnCloseRequest, the |shell_popup_| must become hidden and
// only then call OnCloseRequest().
@@ -133,6 +153,7 @@ bool WaylandPopup::OnInitialize(PlatformWindowInitProperties properties) {
DCHECK(parent_window());
root_surface()->SetBufferScale(parent_window()->buffer_scale(), false);
set_ui_scale(parent_window()->ui_scale());
+ shadow_type_ = properties.shadow_type;
return true;
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.h b/chromium/ui/ozone/platform/wayland/host/wayland_popup.h
index a5810317d86..38af4fa80b4 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_popup.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.h
@@ -27,12 +27,17 @@ class WaylandPopup : public WaylandWindow {
private:
// WaylandWindow overrides:
void HandlePopupConfigure(const gfx::Rect& bounds) override;
+ void HandleSurfaceConfigure(uint32_t serial) override;
void OnCloseRequest() override;
bool OnInitialize(PlatformWindowInitProperties properties) override;
// Creates a popup window, which is visible as a menu window.
bool CreateShellPopup();
+ // Initializes the aura-shell surface, in the case aura-shell EXO extension
+ // is available.
+ void InitializeAuraShellSurface();
+
// Returns bounds with origin relative to parent window's origin.
gfx::Rect AdjustPopupWindowPosition();
@@ -40,6 +45,10 @@ class WaylandPopup : public WaylandWindow {
// know anything about the version.
std::unique_ptr<ShellPopupWrapper> shell_popup_;
+ wl::Object<zaura_surface> aura_surface_;
+
+ PlatformWindowShadowType shadow_type_ = PlatformWindowShadowType::kNone;
+
DISALLOW_COPY_AND_ASSIGN(WaylandPopup);
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
index 07e4c2864ec..42c13a25090 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -7,7 +7,7 @@
#include <set>
#include <vector>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "ui/display/display.h"
@@ -40,7 +40,7 @@ WaylandScreen::WaylandScreen(WaylandConnection* connection)
auto format = buffer_format.first;
// TODO(crbug.com/1127822): Investigate a better fix for this.
-#if !BUILDFLAG(IS_LACROS)
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
// RGBA_8888 is the preferred format, except when running on ChromiumOS. See
// crbug.com/1127558.
if (format == gfx::BufferFormat::RGBA_8888)
@@ -50,7 +50,7 @@ WaylandScreen::WaylandScreen(WaylandConnection* connection)
// available, but for some reason Chromium gets broken when it's used.
// Though, we can import RGBX_8888 dma buffer to EGLImage successfully.
// Enable that back when the issue is resolved.
-#endif // !BUILDFLAG(IS_LACROS)
+#endif // !BUILDFLAG(IS_CHROMEOS_LACROS)
if (!image_format_alpha_ && format == gfx::BufferFormat::BGRA_8888)
image_format_alpha_ = gfx::BufferFormat::BGRA_8888;
@@ -99,10 +99,12 @@ void WaylandScreen::AddOrUpdateDisplay(uint32_t output_id,
const gfx::Rect& new_bounds,
int32_t scale_factor) {
display::Display changed_display(output_id);
- if (!display::Display::HasForceDeviceScaleFactor())
- changed_display.set_device_scale_factor(scale_factor);
- changed_display.set_bounds(new_bounds);
- changed_display.set_work_area(new_bounds);
+ if (!display::Display::HasForceDeviceScaleFactor()) {
+ changed_display.SetScaleAndBounds(scale_factor, new_bounds);
+ } else {
+ changed_display.set_bounds(new_bounds);
+ changed_display.set_work_area(new_bounds);
+ }
gfx::DisplayColorSpaces color_spaces;
color_spaces.SetOutputBufferFormats(image_format_no_alpha_.value(),
@@ -235,6 +237,9 @@ gfx::AcceleratedWidget WaylandScreen::GetLocalProcessWidgetAtPoint(
display::Display WaylandScreen::GetDisplayNearestPoint(
const gfx::Point& point) const {
+ auto displays = GetAllDisplays();
+ if (displays.size() <= 1)
+ return GetPrimaryDisplay();
return *FindDisplayNearestPoint(display_list_.displays(), point);
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
index 46b30f43b54..865ebbe730b 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
@@ -232,9 +232,13 @@ TEST_P(WaylandScreenTest, OutputPropertyChanges) {
Sync();
- changed_values = display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
+ changed_values =
+ display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
+ display::DisplayObserver::DISPLAY_METRIC_WORK_AREA |
+ display::DisplayObserver::DISPLAY_METRIC_BOUNDS;
EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
EXPECT_EQ(observer.GetDisplay().device_scale_factor(), new_scale_value);
+ EXPECT_EQ(observer.GetDisplay().bounds(), gfx::Rect(50, 50));
platform_screen_->RemoveObserver(&observer);
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_shm.h b/chromium/ui/ozone/platform/wayland/host/wayland_shm.h
index 4f7f13ea8bf..0b484ed6e87 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_shm.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_shm.h
@@ -24,6 +24,8 @@ class WaylandShm {
WaylandShm(wl_shm* shm, WaylandConnection* connection);
~WaylandShm();
+ wl_shm* get() const { return shm_.get(); }
+
// Creates a wl_buffer based on shared memory handle for the specified
// |widget|.
wl::Object<struct wl_buffer> CreateBuffer(base::ScopedFD fd,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
index f3092c43e31..99906d1c6dd 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -4,8 +4,10 @@
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
+#include <linux-explicit-synchronization-unstable-v1-client-protocol.h>
#include <viewporter-client-protocol.h>
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
@@ -50,7 +52,19 @@ bool WaylandSurface::Initialize() {
LOG(ERROR) << "Failed to create wp_viewport";
return false;
}
+ } else {
+ LOG(WARNING) << "Server doesn't support wp_viewporter.";
+ }
+
+ // The server needs to support the linux_explicit_synchronization protocol.
+ if (!connection_->linux_explicit_synchronization_v1()) {
+ LOG(WARNING)
+ << "Server doesn't support zwp_linux_explicit_synchronization_v1.";
+ return true;
}
+ surface_sync_.reset(zwp_linux_explicit_synchronization_v1_get_synchronization(
+ connection_->linux_explicit_synchronization_v1(), surface_.get()));
+ DCHECK(surface_sync());
return true;
}
@@ -60,6 +74,11 @@ void WaylandSurface::UnsetRootWindow() {
root_window_ = nullptr;
}
+void WaylandSurface::SetAcquireFence(const gfx::GpuFenceHandle& acquire_fence) {
+ zwp_linux_surface_synchronization_v1_set_acquire_fence(
+ surface_sync(), acquire_fence.owned_fd.get());
+}
+
void WaylandSurface::AttachBuffer(wl_buffer* buffer) {
// The logic in DamageBuffer currently relies on attachment coordinates of
// (0, 0). If this changes, then the calculation in DamageBuffer will also
@@ -87,10 +106,12 @@ void WaylandSurface::UpdateBufferDamageRegion(
if (!crop_rect_.IsEmpty()) {
viewport_src = gfx::ToEnclosedRect(
gfx::ScaleRect(crop_rect_, bounds.width(), bounds.height()));
- wp_viewport_set_source(viewport(), wl_fixed_from_int(viewport_src.x()),
- wl_fixed_from_int(viewport_src.y()),
- wl_fixed_from_int(viewport_src.width()),
- wl_fixed_from_int(viewport_src.height()));
+ if (viewport()) {
+ wp_viewport_set_source(viewport(), wl_fixed_from_int(viewport_src.x()),
+ wl_fixed_from_int(viewport_src.y()),
+ wl_fixed_from_int(viewport_src.width()),
+ wl_fixed_from_int(viewport_src.height()));
+ }
}
// Apply viewport scale (wp_viewport.set_destination).
gfx::Size viewport_dst = bounds;
@@ -162,8 +183,10 @@ void WaylandSurface::SetBufferScale(int32_t new_scale, bool update_bounds) {
if (!display_size_px_.IsEmpty()) {
gfx::Size viewport_dst =
gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
- wp_viewport_set_destination(viewport(), viewport_dst.width(),
- viewport_dst.height());
+ if (viewport()) {
+ wp_viewport_set_destination(viewport(), viewport_dst.width(),
+ viewport_dst.height());
+ }
}
connection_->ScheduleFlush();
@@ -175,42 +198,83 @@ void WaylandSurface::SetOpaqueRegion(const gfx::Rect& region_px) {
if (!root_window_ || !root_window_->IsOpaqueWindow())
return;
- wl::Object<wl_region> region(
- wl_compositor_create_region(connection_->compositor()));
- gfx::Rect region_dip =
- gfx::ScaleToEnclosingRect(region_px, 1.f / buffer_scale_);
- wl_region_add(region.get(), region_dip.x(), region_dip.y(),
- region_dip.width(), region_dip.height());
+ wl_surface_set_opaque_region(surface_.get(),
+ CreateAndAddRegion(region_px).get());
+
+ connection_->ScheduleFlush();
+}
+
+void WaylandSurface::SetInputRegion(const gfx::Rect& region_px) {
+ // Don't set input region when use_native_frame is enabled.
+ if (!root_window_ || root_window_->ShouldUseNativeFrame())
+ return;
- wl_surface_set_opaque_region(surface_.get(), region.get());
+ // Sets input region for input events to allow go through and
+ // for the compositor to ignore the parts of the input region that fall
+ // outside of the surface.
+ wl_surface_set_input_region(surface_.get(),
+ CreateAndAddRegion(region_px).get());
connection_->ScheduleFlush();
}
+wl::Object<wl_region> WaylandSurface::CreateAndAddRegion(
+ const gfx::Rect& region_px) {
+ DCHECK(root_window_);
+
+ wl::Object<wl_region> region(
+ wl_compositor_create_region(connection_->compositor()));
+
+ auto window_shape_in_dips = root_window_->GetWindowShape();
+ if (window_shape_in_dips.has_value()) {
+ for (const auto& rect : window_shape_in_dips.value())
+ wl_region_add(region.get(), rect.x(), rect.y(), rect.width(),
+ rect.height());
+ } else {
+ gfx::Rect region_dip =
+ gfx::ScaleToEnclosingRect(region_px, 1.f / buffer_scale_);
+ wl_region_add(region.get(), region_dip.x(), region_dip.y(),
+ region_dip.width(), region_dip.height());
+ }
+ return region;
+}
+
void WaylandSurface::SetViewportSource(const gfx::RectF& src_rect) {
- if (src_rect == crop_rect_) {
+ if (src_rect == crop_rect_)
return;
- } else if (src_rect.IsEmpty() || src_rect == gfx::RectF{0.f, 0.f, 1.f, 1.f}) {
- wp_viewport_set_source(viewport(), wl_fixed_from_int(-1),
- wl_fixed_from_int(-1), wl_fixed_from_int(-1),
- wl_fixed_from_int(-1));
+ // |src_rect| {1.f, 1.f} does not apply cropping so set it to empty.
+ if (src_rect.IsEmpty() || src_rect == gfx::RectF{1.f, 1.f}) {
+ crop_rect_ = gfx::RectF();
+ if (viewport()) {
+ wp_viewport_set_source(viewport(), wl_fixed_from_int(-1),
+ wl_fixed_from_int(-1), wl_fixed_from_int(-1),
+ wl_fixed_from_int(-1));
+ }
return;
}
+ // wp_viewport_set_source() needs pixel inputs. Store |src_rect| and calculate
+ // in UpdateBufferDamageRegion().
crop_rect_ = src_rect;
}
void WaylandSurface::SetViewportDestination(const gfx::Size& dest_size_px) {
- if (dest_size_px == display_size_px_) {
+ if (dest_size_px == display_size_px_)
+ return;
+ if (dest_size_px.IsEmpty()) {
+ display_size_px_ = gfx::Size();
+ if (viewport()) {
+ wp_viewport_set_destination(viewport(), -1, -1);
+ }
return;
- } else if (dest_size_px.IsEmpty()) {
- wp_viewport_set_destination(viewport(), -1, -1);
}
display_size_px_ = dest_size_px;
gfx::Size viewport_dst =
gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
- wp_viewport_set_destination(viewport(), viewport_dst.width(),
- viewport_dst.height());
+ if (viewport()) {
+ wp_viewport_set_destination(viewport(), viewport_dst.width(),
+ viewport_dst.height());
+ }
}
wl::Object<wl_subsurface> WaylandSurface::CreateSubsurface(
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
index c026bc22cb7..2f7284aeac3 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
@@ -9,6 +9,7 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/gpu_fence_handle.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
@@ -29,6 +30,9 @@ class WaylandSurface {
WaylandWindow* root_window() const { return root_window_; }
wl_surface* surface() const { return surface_.get(); }
wp_viewport* viewport() const { return viewport_.get(); }
+ zwp_linux_surface_synchronization_v1* surface_sync() const {
+ return surface_sync_.get();
+ }
int32_t buffer_scale() const { return buffer_scale_; }
void set_buffer_scale(int32_t scale) { buffer_scale_ = scale; }
@@ -47,6 +51,10 @@ class WaylandSurface {
// (e.g: window/tab dragging sessions).
void UnsetRootWindow();
+ // Sets a non-null in-fence, must be combined with an AttachBuffer() and a
+ // Commit().
+ void SetAcquireFence(const gfx::GpuFenceHandle& acquire_fence);
+
// Attaches the given wl_buffer to the underlying wl_surface at (0, 0).
void AttachBuffer(wl_buffer* buffer);
@@ -67,8 +75,16 @@ class WaylandSurface {
// Sets the region that is opaque on this surface in physical pixels. This is
// expected to be called whenever the region that the surface span changes or
- // the opacity changes.
- void SetOpaqueRegion(const gfx::Rect& bounds_px);
+ // the opacity changes. |region_px| is specified surface-local, in physical
+ // pixels.
+ void SetOpaqueRegion(const gfx::Rect& region_px);
+
+ // Sets the input region on this surface in physical pixels.
+ // The input region indicates which parts of the surface accept pointer and
+ // touch input events. This is expected to be called from ToplevelWindow
+ // whenever the region that the surface span changes or window state changes
+ // when custom frame is used.
+ void SetInputRegion(const gfx::Rect& region_px);
// Set the source rectangle of the associated wl_surface.
// See:
@@ -89,10 +105,13 @@ class WaylandSurface {
wl::Object<wl_subsurface> CreateSubsurface(WaylandSurface* parent);
private:
+ wl::Object<wl_region> CreateAndAddRegion(const gfx::Rect& region_px);
+
WaylandConnection* const connection_;
WaylandWindow* root_window_ = nullptr;
wl::Object<wl_surface> surface_;
wl::Object<wp_viewport> viewport_;
+ wl::Object<zwp_linux_surface_synchronization_v1> surface_sync_;
// Transformation for how the compositor interprets the contents of the
// buffer.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
index f58063afdb3..8290a7ea497 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -9,23 +9,20 @@
#include "base/run_loop.h"
#include "base/unguessable_token.h"
#include "build/chromeos_buildflags.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/os_exchange_data.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/base/hit_test.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
-#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
-#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_zaura_shell.h"
#include "ui/platform_window/extensions/wayland_extension.h"
-#include "ui/platform_window/wm/wm_drop_handler.h"
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
// TODO(jamescook): The nogncheck is to work around false-positive failures on
// the code search bot. Remove after https://crrev.com/c/2432137 lands.
#include "chromeos/crosapi/cpp/crosapi_constants.h" // nogncheck
@@ -40,45 +37,41 @@ WaylandToplevelWindow::WaylandToplevelWindow(PlatformWindowDelegate* delegate,
// Set a class property key, which allows |this| to be used for interactive
// events, e.g. move or resize.
SetWmMoveResizeHandler(this, AsWmMoveResizeHandler());
-
- // Set a class property key, which allows |this| to be used for drag action.
- SetWmDragHandler(this, this);
}
-WaylandToplevelWindow::~WaylandToplevelWindow() {
- if (drag_handler_delegate_) {
- drag_handler_delegate_->OnDragFinished(
- DragDropTypes::DragOperation::DRAG_NONE);
- }
- CancelDrag();
-}
+WaylandToplevelWindow::~WaylandToplevelWindow() = default;
-bool WaylandToplevelWindow::CreateShellSurface() {
+bool WaylandToplevelWindow::CreateShellToplevel() {
ShellObjectFactory factory;
- shell_surface_ = factory.CreateShellSurfaceWrapper(connection(), this);
- if (!shell_surface_) {
- LOG(ERROR) << "Failed to create a ShellSurface.";
+ shell_toplevel_ = factory.CreateShellToplevelWrapper(connection(), this);
+ if (!shell_toplevel_) {
+ LOG(ERROR) << "Failed to create a ShellToplevel.";
return false;
}
-#if BUILDFLAG(IS_LACROS)
- shell_surface_->SetAppId(window_unique_id_);
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ shell_toplevel_->SetAppId(window_unique_id_);
#else
- shell_surface_->SetAppId(wm_class_class_);
+ shell_toplevel_->SetAppId(wm_class_class_);
#endif
- shell_surface_->SetTitle(window_title_);
+ shell_toplevel_->SetTitle(window_title_);
SetSizeConstraints();
TriggerStateChanges();
+ InitializeAuraShellSurface();
+ OnDecorationModeChanged();
+ // This could be the proper time to update window mask using
+ // NonClientView::GetWindowMask, since |non_client_view| is not created yet
+ // during the call to WaylandWindow::Initialize().
+ UpdateWindowMask();
return true;
}
void WaylandToplevelWindow::ApplyPendingBounds() {
if (pending_bounds_dip_.IsEmpty())
return;
- DCHECK(shell_surface_);
+ DCHECK(shell_toplevel_);
SetBoundsDip(pending_bounds_dip_);
- shell_surface_->SetWindowGeometry(pending_bounds_dip_);
pending_bounds_dip_ = gfx::Rect();
connection()->ScheduleFlush();
}
@@ -86,47 +79,22 @@ void WaylandToplevelWindow::ApplyPendingBounds() {
void WaylandToplevelWindow::DispatchHostWindowDragMovement(
int hittest,
const gfx::Point& pointer_location_in_px) {
- DCHECK(shell_surface_);
+ DCHECK(shell_toplevel_);
connection()->event_source()->ResetPointerFlags();
if (hittest == HTCAPTION)
- shell_surface_->SurfaceMove(connection());
+ shell_toplevel_->SurfaceMove(connection());
else
- shell_surface_->SurfaceResize(connection(), hittest);
+ shell_toplevel_->SurfaceResize(connection(), hittest);
connection()->ScheduleFlush();
}
-bool WaylandToplevelWindow::StartDrag(const ui::OSExchangeData& data,
- int operation,
- gfx::NativeCursor cursor,
- bool can_grab_pointer,
- WmDragHandler::Delegate* delegate) {
- DCHECK(!drag_handler_delegate_);
- drag_handler_delegate_ = delegate;
- connection()->data_drag_controller()->StartSession(data, operation);
-
- base::RunLoop drag_loop(base::RunLoop::Type::kNestableTasksAllowed);
- drag_loop_quit_closure_ = drag_loop.QuitClosure();
-
- auto alive = weak_ptr_factory_.GetWeakPtr();
- drag_loop.Run();
- if (!alive)
- return false;
- return true;
-}
-
-void WaylandToplevelWindow::CancelDrag() {
- if (drag_loop_quit_closure_.is_null())
- return;
- std::move(drag_loop_quit_closure_).Run();
-}
-
void WaylandToplevelWindow::Show(bool inactive) {
- if (shell_surface_)
+ if (shell_toplevel_)
return;
- if (!CreateShellSurface()) {
+ if (!CreateShellToplevel()) {
Close();
return;
}
@@ -140,7 +108,7 @@ void WaylandToplevelWindow::Show(bool inactive) {
}
void WaylandToplevelWindow::Hide() {
- if (!shell_surface_)
+ if (!shell_toplevel_)
return;
if (child_window()) {
@@ -148,7 +116,7 @@ void WaylandToplevelWindow::Hide() {
set_child_window(nullptr);
}
- shell_surface_.reset();
+ shell_toplevel_.reset();
connection()->ScheduleFlush();
// Detach buffer from surface in order to completely shutdown menus and
@@ -159,7 +127,7 @@ void WaylandToplevelWindow::Hide() {
bool WaylandToplevelWindow::IsVisible() const {
// X and Windows return true if the window is minimized. For consistency, do
// the same.
- return !!shell_surface_ || state_ == PlatformWindowState::kMinimized;
+ return !!shell_toplevel_ || state_ == PlatformWindowState::kMinimized;
}
void WaylandToplevelWindow::SetTitle(const base::string16& title) {
@@ -168,8 +136,8 @@ void WaylandToplevelWindow::SetTitle(const base::string16& title) {
window_title_ = title;
- if (shell_surface_) {
- shell_surface_->SetTitle(title);
+ if (shell_toplevel_) {
+ shell_toplevel_->SetTitle(title);
connection()->ScheduleFlush();
}
}
@@ -203,7 +171,7 @@ void WaylandToplevelWindow::Minimize() {
}
void WaylandToplevelWindow::Restore() {
- DCHECK(shell_surface_);
+ DCHECK(shell_toplevel_);
// Differently from other platforms, under Wayland, unmaximizing the dragged
// window before starting the drag loop is not needed as it is assumed to be
@@ -222,30 +190,59 @@ PlatformWindowState WaylandToplevelWindow::GetPlatformWindowState() const {
return state_;
}
+void WaylandToplevelWindow::Activate() {
+ // Only supported by compositors that support zaura_shell (e.g. exo).
+ // TODO(https://crbug.com/1175327): Use standard Wayland extensions, such as
+ // xdg-activation, when those are available.
+ if (aura_surface_)
+ zaura_surface_activate(aura_surface_.get());
+}
+
void WaylandToplevelWindow::SizeConstraintsChanged() {
// Size constraints only make sense for normal windows.
- if (!shell_surface_)
+ if (!shell_toplevel_)
return;
- DCHECK(delegate());
- min_size_ = delegate()->GetMinimumSizeForWindow();
- max_size_ = delegate()->GetMaximumSizeForWindow();
SetSizeConstraints();
}
std::string WaylandToplevelWindow::GetWindowUniqueId() const {
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
return window_unique_id_;
#else
return std::string();
#endif
}
-void WaylandToplevelWindow::HandleSurfaceConfigure(int32_t width,
- int32_t height,
- bool is_maximized,
- bool is_fullscreen,
- bool is_activated) {
+void WaylandToplevelWindow::SetUseNativeFrame(bool use_native_frame) {
+ if (use_native_frame_ == use_native_frame)
+ return;
+ use_native_frame_ = use_native_frame;
+ if (shell_toplevel_)
+ OnDecorationModeChanged();
+
+ UpdateWindowMask();
+}
+
+bool WaylandToplevelWindow::ShouldUseNativeFrame() const {
+ // This depends on availability of xdg-decoration protocol extension.
+ // Returns false if there is no xdg-decoration protocol extension provided
+ // even if use_native_frame_ is true.
+ return use_native_frame_ && const_cast<WaylandToplevelWindow*>(this)
+ ->connection()
+ ->xdg_decoration_manager_v1();
+}
+
+base::Optional<std::vector<gfx::Rect>> WaylandToplevelWindow::GetWindowShape()
+ const {
+ return window_shape_in_dips_;
+}
+
+void WaylandToplevelWindow::HandleToplevelConfigure(int32_t width,
+ int32_t height,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated) {
// Store the old state to propagte state changes if Wayland decides to change
// the state to something else.
PlatformWindowState old_state = state_;
@@ -259,9 +256,14 @@ void WaylandToplevelWindow::HandleSurfaceConfigure(int32_t width,
state_ = PlatformWindowState::kNormal;
}
- const bool state_changed = old_state != state_;
const bool is_normal = state_ == PlatformWindowState::kNormal;
+ bool did_send_delegate_notification = !!requested_window_show_state_count_;
+ if (requested_window_show_state_count_)
+ requested_window_show_state_count_--;
+
+ const bool did_window_show_state_change = old_state != state_;
+
// Update state before notifying delegate.
const bool did_active_change = is_active_ != is_activated;
is_active_ = is_activated;
@@ -287,7 +289,6 @@ void WaylandToplevelWindow::HandleSurfaceConfigure(int32_t width,
gfx::ScaleToRoundedSize(GetRestoredBoundsInPixels().IsEmpty()
? GetBounds().size()
: GetRestoredBoundsInPixels().size(),
-
1.0 / buffer_scale()));
}
@@ -295,71 +296,60 @@ void WaylandToplevelWindow::HandleSurfaceConfigure(int32_t width,
// It can be client or compositor side change from normal to something else.
// Thus, we must store previous bounds to restore later.
SetOrResetRestoredBounds();
- ApplyPendingBounds();
- if (state_changed)
+ if (did_window_show_state_change && !did_send_delegate_notification) {
+ previous_state_ = old_state;
delegate()->OnWindowStateChanged(state_);
+ }
if (did_active_change)
delegate()->OnActivationChanged(is_active_);
}
-void WaylandToplevelWindow::OnDragEnter(const gfx::PointF& point,
- std::unique_ptr<OSExchangeData> data,
- int operation) {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
- return;
+void WaylandToplevelWindow::HandleSurfaceConfigure(uint32_t serial) {
+ if (pending_bounds_dip_.size() ==
+ gfx::ScaleToRoundedSize(GetBounds().size(), 1.f / buffer_scale())) {
+ // If |pending_bounds_dip_| matches GetBounds(), then a frame matching
+ // |pending_bounds_dip_| may not arrive soon, despite the window delegate
+ // receives the updated bounds. Without a new frame, UpdateVisualSize() is
+ // not invoked, leaving this |configure| unacknowledged.
+ // E.g. With static window content, |configure| that does not
+ // change window size will not cause the window to redraw.
+ // Hence, acknowledge this |configure| now to tell the Wayland compositor
+ // that this window has been configured.
+ shell_toplevel()->SetWindowGeometry(pending_bounds_dip_);
+ shell_toplevel()->AckConfigure(serial);
+ } else {
+ // Otherwise, push the pending |configure| to |pending_configures_|, wait
+ // for a frame update, which will invoke UpdateVisualSize().
+ DCHECK_LT(pending_configures_.size(), 25u);
+ pending_configures_.push_back({pending_bounds_dip_.size(), serial});
+ }
- // Wayland sends locations in DIP so they need to be translated to
- // physical pixels.
- // TODO(crbug.com/1102857): get the real event modifier here.
- drop_handler->OnDragEnter(
- gfx::ScalePoint(point, buffer_scale(), buffer_scale()), std::move(data),
- operation,
- /*modifiers=*/0);
+ ApplyPendingBounds();
}
-int WaylandToplevelWindow::OnDragMotion(const gfx::PointF& point,
- int operation) {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
- return 0;
+void WaylandToplevelWindow::UpdateVisualSize(const gfx::Size& size_px) {
+ WaylandWindow::UpdateVisualSize(size_px);
- // Wayland sends locations in DIP so they need to be translated to
- // physical pixels.
- // TODO(crbug.com/1102857): get the real event modifier here.
- return drop_handler->OnDragMotion(
- gfx::ScalePoint(point, buffer_scale(), buffer_scale()), operation,
- /*modifiers=*/0);
-}
-
-void WaylandToplevelWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
+ if (!shell_toplevel_)
return;
- // TODO(crbug.com/1102857): get the real event modifier here.
- drop_handler->OnDragDrop(std::move(data), /*modifiers=*/0);
-}
+ auto size_dip = gfx::ScaleToRoundedSize(size_px, 1.f / buffer_scale());
+ auto result = std::find_if(
+ pending_configures_.begin(), pending_configures_.end(),
+ [&size_dip](auto& configure) { return size_dip == configure.size_dip; });
-void WaylandToplevelWindow::OnDragLeave() {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
+ if (result == pending_configures_.end())
return;
- drop_handler->OnDragLeave();
-}
-void WaylandToplevelWindow::OnDragSessionClose(uint32_t dnd_action) {
- DCHECK(drag_handler_delegate_);
- drag_handler_delegate_->OnDragFinished(dnd_action);
- drag_handler_delegate_ = nullptr;
- connection()->event_source()->ResetPointerFlags();
- std::move(drag_loop_quit_closure_).Run();
+ shell_toplevel()->SetWindowGeometry(gfx::Rect(size_dip));
+ shell_toplevel()->AckConfigure(result->serial);
+ pending_configures_.erase(pending_configures_.begin(), ++result);
}
bool WaylandToplevelWindow::OnInitialize(
PlatformWindowInitProperties properties) {
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
auto token = base::UnguessableToken::Create();
window_unique_id_ =
std::string(crosapi::kLacrosAppIdPrefix) + token.ToString();
@@ -368,7 +358,6 @@ bool WaylandToplevelWindow::OnInitialize(
#endif
SetWaylandExtension(this, static_cast<WaylandExtension*>(this));
SetWmMoveLoopHandler(this, static_cast<WmMoveLoopHandler*>(this));
- InitializeAuraShell();
return true;
}
@@ -391,34 +380,99 @@ void WaylandToplevelWindow::StartWindowDraggingSessionIfNeeded() {
connection()->window_drag_controller()->StartDragSession();
}
-void WaylandToplevelWindow::TriggerStateChanges() {
- if (!shell_surface_)
+void WaylandToplevelWindow::SetImmersiveFullscreenStatus(bool status) {
+ if (aura_surface_) {
+ auto mode = status ? ZAURA_SURFACE_FULLSCREEN_MODE_IMMERSIVE
+ : ZAURA_SURFACE_FULLSCREEN_MODE_PLAIN;
+ zaura_surface_set_fullscreen_mode(aura_surface_.get(), mode);
+ } else {
+ // TODO(https://crbug.com/1113900): Implement AuraShell support for
+ // non-browser windows and replace this if-else clause by a DCHECK.
+ NOTIMPLEMENTED_LOG_ONCE()
+ << "Implement AuraShell support for non-browser windows.";
+ }
+}
+
+void WaylandToplevelWindow::ShowSnapPreview(
+ WaylandWindowSnapDirection snap_direction) {
+ if (aura_surface_ && zaura_surface_get_version(aura_surface_.get()) >=
+ ZAURA_SURFACE_INTENT_TO_SNAP_SINCE_VERSION) {
+ uint32_t zaura_shell_snap_direction = ZAURA_SURFACE_SNAP_DIRECTION_NONE;
+ switch (snap_direction) {
+ case WaylandWindowSnapDirection::kLeft:
+ zaura_shell_snap_direction = ZAURA_SURFACE_SNAP_DIRECTION_LEFT;
+ break;
+ case WaylandWindowSnapDirection::kRight:
+ zaura_shell_snap_direction = ZAURA_SURFACE_SNAP_DIRECTION_RIGHT;
+ break;
+ case WaylandWindowSnapDirection::kNone:
+ break;
+ }
+ zaura_surface_intent_to_snap(aura_surface_.get(),
+ zaura_shell_snap_direction);
return;
+ }
- if (state_ == PlatformWindowState::kFullScreen)
- shell_surface_->SetFullscreen();
- else
- shell_surface_->UnSetFullscreen();
+ NOTIMPLEMENTED_LOG_ONCE()
+ << "Window snapping isn't available for non-lacros builds.";
+}
+
+void WaylandToplevelWindow::CommitSnap(
+ WaylandWindowSnapDirection snap_direction) {
+ if (aura_surface_ && zaura_surface_get_version(aura_surface_.get()) >=
+ ZAURA_SURFACE_UNSET_SNAP_SINCE_VERSION) {
+ switch (snap_direction) {
+ case WaylandWindowSnapDirection::kLeft:
+ zaura_surface_set_snap_left(aura_surface_.get());
+ return;
+ case WaylandWindowSnapDirection::kRight:
+ zaura_surface_set_snap_right(aura_surface_.get());
+ return;
+ case WaylandWindowSnapDirection::kNone:
+ zaura_surface_unset_snap(aura_surface_.get());
+ return;
+ }
+ }
+
+ NOTIMPLEMENTED_LOG_ONCE()
+ << "Window snapping isn't available for non-lacros builds.";
+}
+
+void WaylandToplevelWindow::TriggerStateChanges() {
+ if (!shell_toplevel_)
+ return;
// Call UnSetMaximized only if current state is normal. Otherwise, if the
// current state is fullscreen and the previous is maximized, calling
// UnSetMaximized may result in wrong restored window position that clients
// are not allowed to know about.
- if (state_ == PlatformWindowState::kMaximized)
- shell_surface_->SetMaximized();
- else if (state_ == PlatformWindowState::kNormal)
- shell_surface_->UnSetMaximized();
+ if (state_ == PlatformWindowState::kMinimized) {
+ shell_toplevel_->SetMinimized();
+ } else if (state_ == PlatformWindowState::kFullScreen) {
+ shell_toplevel_->SetFullscreen();
+ } else if (previous_state_ == PlatformWindowState::kFullScreen) {
+ shell_toplevel_->UnSetFullscreen();
+ } else if (state_ == PlatformWindowState::kMaximized) {
+ shell_toplevel_->SetMaximized();
+ } else if (state_ == PlatformWindowState::kNormal) {
+ shell_toplevel_->UnSetMaximized();
+ }
- if (state_ == PlatformWindowState::kMinimized)
- shell_surface_->SetMinimized();
+ delegate()->OnWindowStateChanged(state_);
connection()->ScheduleFlush();
}
void WaylandToplevelWindow::SetWindowState(PlatformWindowState state) {
- previous_state_ = state_;
- state_ = state;
- TriggerStateChanges();
+ if (state_ != state) {
+ previous_state_ = state_;
+ state_ = state;
+
+ // Tracks this window show state change request, coming from the Browser.
+ requested_window_show_state_count_++;
+
+ TriggerStateChanges();
+ }
}
WmMoveResizeHandler* WaylandToplevelWindow::AsWmMoveResizeHandler() {
@@ -426,10 +480,22 @@ WmMoveResizeHandler* WaylandToplevelWindow::AsWmMoveResizeHandler() {
}
void WaylandToplevelWindow::SetSizeConstraints() {
- if (min_size_.has_value())
- shell_surface_->SetMinSize(min_size_->width(), min_size_->height());
- if (max_size_.has_value())
- shell_surface_->SetMaxSize(max_size_->width(), max_size_->height());
+ DCHECK(delegate());
+
+ min_size_ = delegate()->GetMinimumSizeForWindow();
+ max_size_ = delegate()->GetMaximumSizeForWindow();
+
+ if (min_size_.has_value()) {
+ auto min_size_dip =
+ gfx::ScaleToRoundedSize(min_size_.value(), 1.0f / buffer_scale());
+ shell_toplevel_->SetMinSize(min_size_dip.width(), min_size_dip.height());
+ }
+
+ if (max_size_.has_value()) {
+ auto max_size_dip =
+ gfx::ScaleToRoundedSize(max_size_.value(), 1.0f / buffer_scale());
+ shell_toplevel_->SetMaxSize(max_size_dip.width(), max_size_dip.height());
+ }
connection()->ScheduleFlush();
}
@@ -447,14 +513,56 @@ void WaylandToplevelWindow::SetOrResetRestoredBounds() {
}
}
-void WaylandToplevelWindow::InitializeAuraShell() {
- if (connection()->zaura_shell()) {
- DCHECK(!aura_surface_);
+void WaylandToplevelWindow::InitializeAuraShellSurface() {
+ // InitializeAuraShellSurface() should be called after the XDG surface is
+ // initialized.
+ DCHECK(shell_toplevel_);
+
+ if (connection()->zaura_shell() && !aura_surface_) {
aura_surface_.reset(zaura_shell_get_aura_surface(
connection()->zaura_shell()->wl_object(), root_surface()->surface()));
- zaura_surface_set_fullscreen_mode(aura_surface_.get(),
- ZAURA_SURFACE_FULLSCREEN_MODE_IMMERSIVE);
+ SetImmersiveFullscreenStatus(false);
+ }
+}
+
+void WaylandToplevelWindow::OnDecorationModeChanged() {
+ DCHECK(shell_toplevel_);
+ if (use_native_frame_) {
+ // Set server-side decoration for windows using a native frame,
+ // e.g. taskmanager
+ shell_toplevel_->SetDecoration(
+ ShellToplevelWrapper::DecorationMode::kServerSide);
+ } else if (aura_surface_ &&
+ zaura_surface_get_version(aura_surface_.get()) >=
+ ZAURA_SURFACE_SET_SERVER_START_RESIZE_SINCE_VERSION) {
+ // Sets custom-decoration mode for window that supports aura_shell.
+ // e.g. lacros-browser.
+ zaura_surface_set_server_start_resize(aura_surface_.get());
+ } else {
+ shell_toplevel_->SetDecoration(
+ ShellToplevelWrapper::DecorationMode::kClientSide);
+ }
+}
+
+void WaylandToplevelWindow::UpdateWindowMask() {
+ // TODO(http://crbug.com/1158733): When supporting PlatformWindow::SetShape,
+ // update window region with the given |shape|.
+ WaylandWindow::UpdateWindowMask();
+ root_surface()->SetInputRegion(gfx::Rect(visual_size_px()));
+}
+
+void WaylandToplevelWindow::UpdateWindowShape() {
+ // Create |window_shape_in_dips_| using the window mask of
+ // PlatformWindowDelegate otherwise resets it.
+ SkPath window_mask_in_pixels =
+ delegate()->GetWindowMaskForWindowShapeInPixels();
+ if (window_mask_in_pixels.isEmpty()) {
+ window_shape_in_dips_.reset();
+ return;
}
+ SkPath window_mask_in_dips =
+ wl::ConvertPathToDIP(window_mask_in_pixels, buffer_scale());
+ window_shape_in_dips_ = wl::CreateRectsFromSkPath(window_mask_in_dips);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
index 7f091d3f48f..849ee9ae60d 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
@@ -5,21 +5,20 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_
+#include "base/containers/circular_deque.h"
#include "build/chromeos_buildflags.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/platform_window/extensions/wayland_extension.h"
-#include "ui/platform_window/wm/wm_drag_handler.h"
#include "ui/platform_window/wm/wm_move_loop_handler.h"
#include "ui/platform_window/wm/wm_move_resize_handler.h"
namespace ui {
-class ShellSurfaceWrapper;
+class ShellToplevelWrapper;
class WaylandToplevelWindow : public WaylandWindow,
public WmMoveResizeHandler,
- public WmDragHandler,
public WmMoveLoopHandler,
public WaylandExtension {
public:
@@ -29,7 +28,7 @@ class WaylandToplevelWindow : public WaylandWindow,
WaylandToplevelWindow& operator=(const WaylandToplevelWindow&) = delete;
~WaylandToplevelWindow() override;
- ShellSurfaceWrapper* shell_surface() const { return shell_surface_.get(); }
+ ShellToplevelWrapper* shell_toplevel() const { return shell_toplevel_.get(); }
// Apply the bounds specified in the most recent configure event. This should
// be called after processing all pending events in the wayland connection.
@@ -40,15 +39,7 @@ class WaylandToplevelWindow : public WaylandWindow,
int hittest,
const gfx::Point& pointer_location_in_px) override;
- // WmDragHandler
- bool StartDrag(const ui::OSExchangeData& data,
- int operation,
- gfx::NativeCursor cursor,
- bool can_grab_pointer,
- WmDragHandler::Delegate* delegate) override;
- void CancelDrag() override;
-
- // PlatformWindow
+ // PlatformWindow:
void Show(bool inactive) override;
void Hide() override;
bool IsVisible() const override;
@@ -58,25 +49,33 @@ class WaylandToplevelWindow : public WaylandWindow,
void Minimize() override;
void Restore() override;
PlatformWindowState GetPlatformWindowState() const override;
+ void Activate() override;
void SizeConstraintsChanged() override;
std::string GetWindowUniqueId() const override;
+ // SetUseNativeFrame and ShouldUseNativeFrame decide on
+ // xdg-decoration mode for a window.
+ void SetUseNativeFrame(bool use_native_frame) override;
+ bool ShouldUseNativeFrame() const override;
+
+ // WaylandWindow overrides:
+ base::Optional<std::vector<gfx::Rect>> GetWindowShape() const override;
private:
// WaylandWindow overrides:
- void HandleSurfaceConfigure(int32_t widht,
- int32_t height,
- bool is_maximized,
- bool is_fullscreen,
- bool is_activated) override;
- void OnDragEnter(const gfx::PointF& point,
- std::unique_ptr<OSExchangeData> data,
- int operation) override;
- int OnDragMotion(const gfx::PointF& point, int operation) override;
- void OnDragDrop(std::unique_ptr<OSExchangeData> data) override;
- void OnDragLeave() override;
- void OnDragSessionClose(uint32_t dnd_action) override;
+ void HandleToplevelConfigure(int32_t width,
+ int32_t height,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated) override;
+ void HandleSurfaceConfigure(uint32_t serial) override;
+ void UpdateVisualSize(const gfx::Size& size_px) override;
bool OnInitialize(PlatformWindowInitProperties properties) override;
bool IsActive() const override;
+ // Calls UpdateWindowShape, set_input_region and set_opaque_region
+ // for this toplevel window.
+ void UpdateWindowMask() override;
+ // Update the window shape using the window mask of PlatformWindowDelegate.
+ void UpdateWindowShape() override;
// WmMoveLoopHandler:
bool RunMoveLoop(const gfx::Vector2d& drag_offset) override;
@@ -84,27 +83,32 @@ class WaylandToplevelWindow : public WaylandWindow,
// WaylandExtension:
void StartWindowDraggingSessionIfNeeded() override;
+ void SetImmersiveFullscreenStatus(bool status) override;
+ void ShowSnapPreview(WaylandWindowSnapDirection snap) override;
+ void CommitSnap(WaylandWindowSnapDirection snap) override;
void TriggerStateChanges();
void SetWindowState(PlatformWindowState state);
// Creates a surface window, which is visible as a main window.
- bool CreateShellSurface();
+ bool CreateShellToplevel();
WmMoveResizeHandler* AsWmMoveResizeHandler();
- // Propagates the |min_size_| and |max_size_| to the ShellSurface.
+ // Propagates the |min_size_| and |max_size_| to the ShellToplevel.
void SetSizeConstraints();
void SetOrResetRestoredBounds();
- // Initializes the aura-shell EXO extension, if available.
- void InitializeAuraShell();
+ // Initializes the aura-shell surface, in the case aura-shell EXO extension
+ // is available.
+ void InitializeAuraShellSurface();
- // Wrappers around shell surface.
- std::unique_ptr<ShellSurfaceWrapper> shell_surface_;
+ // Sets decoration mode for a window.
+ void OnDecorationModeChanged();
- WmDragHandler::Delegate* drag_handler_delegate_ = nullptr;
+ // Wrappers around shell surface.
+ std::unique_ptr<ShellToplevelWrapper> shell_toplevel_;
// These bounds attributes below have suffices that indicate units used.
// Wayland operates in DIP but the platform operates in physical pixels so
@@ -125,7 +129,7 @@ class WaylandToplevelWindow : public WaylandWindow,
bool is_active_ = false;
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
// Unique ID for this window. May be shared over non-Wayland IPC transports
// (e.g. mojo) to identify the window.
std::string window_unique_id_;
@@ -137,18 +141,40 @@ class WaylandToplevelWindow : public WaylandWindow,
std::string wm_class_class_;
#endif
- // Title of the ShellSurface.
+ // Title of the ShellToplevel.
base::string16 window_title_;
// Max and min sizes of the WaylandToplevelWindow window.
base::Optional<gfx::Size> min_size_;
base::Optional<gfx::Size> max_size_;
- base::OnceClosure drag_loop_quit_closure_;
-
wl::Object<zaura_surface> aura_surface_;
- base::WeakPtrFactory<WaylandToplevelWindow> weak_ptr_factory_{this};
+ // When use_native_frame is false, client-side decoration is set,
+ // e.g. lacros-browser.
+ // When use_native_frame is true, server-side decoration is set,
+ // e.g. lacros-taskmanager.
+ bool use_native_frame_ = false;
+
+ base::Optional<std::vector<gfx::Rect>> window_shape_in_dips_;
+
+ // Pending xdg-shell configures, once this window is drawn to |size_dip|,
+ // ack_configure with |serial| will be sent to the Wayland compositor.
+ struct PendingConfigure {
+ gfx::Size size_dip;
+ uint32_t serial;
+ };
+ base::circular_deque<PendingConfigure> pending_configures_;
+
+ // Tracks how many the window show state requests by made by the Browser
+ // are currently being processed by the Wayland Compositor. In practice,
+ // each individual increment corresponds to an explicit window show state
+ // change request, and gets a response by the Compositor.
+ //
+ // This mechanism allows Ozone/Wayland to filter out notifying the delegate
+ // (PlatformWindowDelegate) more than once, for the same window show state
+ // change.
+ uint32_t requested_window_show_state_count_ = 0;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc b/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
index 6bb9802ed9a..8eba29721e8 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
@@ -22,14 +22,11 @@ WaylandTouch::WaylandTouch(wl_touch* touch,
&WaylandTouch::Frame, &WaylandTouch::Cancel,
};
- DCHECK(delegate_);
- delegate_->OnTouchCreated(this);
-
wl_touch_add_listener(obj_.get(), &listener, this);
}
WaylandTouch::~WaylandTouch() {
- delegate_->OnTouchDestroyed(this);
+ delegate_->OnTouchCancelEvent();
}
void WaylandTouch::Down(void* data,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_touch.h b/chromium/ui/ozone/platform/wayland/host/wayland_touch.h
index 14c9aaa0f78..4c3e3b7aaac 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_touch.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_touch.h
@@ -61,8 +61,6 @@ class WaylandTouch {
class WaylandTouch::Delegate {
public:
- virtual void OnTouchCreated(WaylandTouch* touch) = 0;
- virtual void OnTouchDestroyed(WaylandTouch* touch) = 0;
virtual void OnTouchPressEvent(WaylandWindow* window,
const gfx::PointF& location,
base::TimeTicks timestamp,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
index f59e227aba9..edc21c70b89 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -4,27 +4,37 @@
#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include <wayland-cursor.h>
#include <algorithm>
#include <memory>
#include "base/bind.h"
+#include "base/run_loop.h"
#include "build/chromeos_buildflags.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/ozone/events_ozone.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/common/features.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
+#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
#include "ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h"
#include "ui/ozone/public/mojom/wayland/wayland_overlay_config.mojom.h"
+#include "ui/platform_window/wm/wm_drag_handler.h"
+#include "ui/platform_window/wm/wm_drop_handler.h"
namespace {
@@ -42,9 +52,13 @@ WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate,
WaylandConnection* connection)
: delegate_(delegate),
connection_(connection),
- wayland_overlay_delegation_enabled_(IsWaylandOverlayDelegationEnabled()),
+ wayland_overlay_delegation_enabled_(connection->viewporter() &&
+ IsWaylandOverlayDelegationEnabled()),
accelerated_widget_(
- connection->wayland_window_manager()->AllocateAcceleratedWidget()) {}
+ connection->wayland_window_manager()->AllocateAcceleratedWidget()) {
+ // Set a class property key, which allows |this| to be used for drag action.
+ SetWmDragHandler(this, this);
+}
WaylandWindow::~WaylandWindow() {
shutting_down_ = true;
@@ -97,11 +111,11 @@ void WaylandWindow::UpdateBufferScale(bool update_bounds) {
else
ui_scale_ = display.device_scale_factor();
}
- // At this point, buffer_scale() still returns the old scale.
- if (update_bounds)
- SetBoundsDip(gfx::ScaleToRoundedRect(bounds_px_, 1.0 / buffer_scale()));
-
+ int32_t old_scale = buffer_scale();
root_surface_->SetBufferScale(new_scale, update_bounds);
+ // We need to keep DIP size of the window the same whenever the scale changes.
+ if (update_bounds)
+ SetBoundsDip(gfx::ScaleToRoundedRect(bounds_px_, 1.0 / old_scale));
}
gfx::AcceleratedWidget WaylandWindow::GetWidget() const {
@@ -115,14 +129,46 @@ void WaylandWindow::SetPointerFocus(bool focus) {
// cursor. Otherwise, it is invalidated whenever the pointer leaves the
// surface and is not restored by the Wayland compositor.
if (has_pointer_focus_ && bitmap_) {
- // Translate physical pixels to DIPs.
- gfx::Point hotspot_in_dips =
- gfx::ScaleToRoundedPoint(bitmap_->hotspot(), 1.0f / ui_scale_);
- connection_->SetCursorBitmap(bitmap_->bitmaps(), hotspot_in_dips,
- buffer_scale());
+ // Check for theme-provided cursor.
+ if (bitmap_->platform_data()) {
+ connection_->SetPlatformCursor(
+ reinterpret_cast<wl_cursor*>(bitmap_->platform_data()),
+ buffer_scale());
+ } else {
+ // Translate physical pixels to DIPs.
+ gfx::Point hotspot_in_dips =
+ gfx::ScaleToRoundedPoint(bitmap_->hotspot(), 1.0f / ui_scale_);
+ connection_->SetCursorBitmap(bitmap_->bitmaps(), hotspot_in_dips,
+ buffer_scale());
+ }
}
}
+bool WaylandWindow::StartDrag(const ui::OSExchangeData& data,
+ int operation,
+ gfx::NativeCursor cursor,
+ bool can_grab_pointer,
+ WmDragHandler::Delegate* delegate) {
+ DCHECK(!drag_handler_delegate_);
+ drag_handler_delegate_ = delegate;
+ connection()->data_drag_controller()->StartSession(data, operation);
+
+ base::RunLoop drag_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ drag_loop_quit_closure_ = drag_loop.QuitClosure();
+
+ auto alive = weak_ptr_factory_.GetWeakPtr();
+ drag_loop.Run();
+ if (!alive)
+ return false;
+ return true;
+}
+
+void WaylandWindow::CancelDrag() {
+ if (drag_loop_quit_closure_.is_null())
+ return;
+ std::move(drag_loop_quit_closure_).Run();
+}
+
void WaylandWindow::Show(bool inactive) {
if (background_buffer_id_ != 0u)
should_attach_background_buffer_ = true;
@@ -141,14 +187,18 @@ bool WaylandWindow::IsVisible() const {
return false;
}
-void WaylandWindow::PrepareForShutdown() {}
+void WaylandWindow::PrepareForShutdown() {
+ if (drag_handler_delegate_)
+ OnDragSessionClose(DragDropTypes::DRAG_NONE);
+}
void WaylandWindow::SetBounds(const gfx::Rect& bounds_px) {
if (bounds_px_ == bounds_px)
return;
bounds_px_ = bounds_px;
- root_surface_->SetOpaqueRegion(bounds_px);
+ if (update_visual_size_immediately_)
+ UpdateVisualSize(bounds_px.size());
delegate_->OnBoundsChanged(bounds_px_);
}
@@ -194,22 +244,20 @@ PlatformWindowState WaylandWindow::GetPlatformWindowState() const {
return PlatformWindowState::kNormal;
}
-void WaylandWindow::Activate() {
- NOTIMPLEMENTED_LOG_ONCE();
-}
+void WaylandWindow::Activate() {}
void WaylandWindow::Deactivate() {
NOTIMPLEMENTED_LOG_ONCE();
}
void WaylandWindow::SetUseNativeFrame(bool use_native_frame) {
- // See comment below in ShouldUseNativeFrame.
- NOTIMPLEMENTED_LOG_ONCE();
+ // Do nothing here since only shell surfaces can handle server-side
+ // decoration.
}
bool WaylandWindow::ShouldUseNativeFrame() const {
- // This depends on availability of XDG-Decoration protocol extension.
- NOTIMPLEMENTED_LOG_ONCE();
+ // Always returns false here since only shell surfaces can handle server-side
+ // decoration.
return false;
}
@@ -227,6 +275,12 @@ void WaylandWindow::SetCursor(PlatformCursor cursor) {
buffer_scale());
return;
}
+ // Check for theme-provided cursor.
+ if (bitmap_->platform_data()) {
+ connection_->SetPlatformCursor(
+ reinterpret_cast<wl_cursor*>(bitmap_->platform_data()), buffer_scale());
+ return;
+ }
// Check for Wayland server-side cursor support (e.g. exo for lacros).
if (connection_->zcr_cursor_shapes()) {
base::Optional<int32_t> shape =
@@ -282,6 +336,10 @@ void WaylandWindow::SetWindowIcons(const gfx::ImageSkia& window_icon,
void WaylandWindow::SizeConstraintsChanged() {}
+bool WaylandWindow::ShouldUseLayerForShapedWindow() const {
+ return true;
+}
+
bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) {
if (event->IsMouseEvent())
return has_pointer_focus_;
@@ -304,6 +362,7 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
// Wayland sends locations in DIP so they need to be translated to
// physical pixels.
+ UpdateCursorPositionFromEvent(Event::Clone(*event));
event->AsLocatedEvent()->set_location_f(gfx::ScalePoint(
event->AsLocatedEvent()->location_f(), buffer_scale(), buffer_scale()));
@@ -333,36 +392,98 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
return DispatchEventToDelegate(native_event);
}
-void WaylandWindow::HandleSurfaceConfigure(int32_t widht,
- int32_t height,
- bool is_maximized,
- bool is_fullscreen,
- bool is_activated) {
+void WaylandWindow::HandleSurfaceConfigure(uint32_t serial) {
NOTREACHED()
<< "Only shell surfaces must receive HandleSurfaceConfigure calls.";
}
+void WaylandWindow::HandleToplevelConfigure(int32_t widht,
+ int32_t height,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated) {
+ NOTREACHED()
+ << "Only shell toplevels must receive HandleToplevelConfigure calls.";
+}
+
void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) {
NOTREACHED() << "Only shell popups must receive HandlePopupConfigure calls.";
}
+void WaylandWindow::UpdateVisualSize(const gfx::Size& size_px) {
+ visual_size_px_ = size_px;
+ UpdateWindowMask();
+}
+
void WaylandWindow::OnCloseRequest() {
delegate_->OnCloseRequest();
}
+base::Optional<std::vector<gfx::Rect>> WaylandWindow::GetWindowShape() const {
+ return base::nullopt;
+}
+
+void WaylandWindow::UpdateWindowMask() {
+ UpdateWindowShape();
+ root_surface_->SetOpaqueRegion(gfx::Rect(visual_size_px()));
+}
+
+void WaylandWindow::UpdateWindowShape() {}
+
void WaylandWindow::OnDragEnter(const gfx::PointF& point,
std::unique_ptr<OSExchangeData> data,
- int operation) {}
+ int operation) {
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return;
+
+ auto location_px = gfx::ScalePoint(TranslateLocationToRootWindow(point),
+ buffer_scale(), buffer_scale());
+
+ // Wayland sends locations in DIP so they need to be translated to
+ // physical pixels.
+ // TODO(crbug.com/1102857): get the real event modifier here.
+ drop_handler->OnDragEnter(location_px, std::move(data), operation,
+ /*modifiers=*/0);
+}
int WaylandWindow::OnDragMotion(const gfx::PointF& point, int operation) {
- return -1;
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return 0;
+
+ auto location_px = gfx::ScalePoint(TranslateLocationToRootWindow(point),
+ buffer_scale(), buffer_scale());
+
+ // Wayland sends locations in DIP so they need to be translated to
+ // physical pixels.
+ // TODO(crbug.com/1102857): get the real event modifier here.
+ return drop_handler->OnDragMotion(location_px, operation,
+ /*modifiers=*/0);
}
-void WaylandWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {}
+void WaylandWindow::OnDragDrop() {
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return;
+ // TODO(crbug.com/1102857): get the real event modifier here.
+ drop_handler->OnDragDrop({}, /*modifiers=*/0);
+}
-void WaylandWindow::OnDragLeave() {}
+void WaylandWindow::OnDragLeave() {
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return;
+ drop_handler->OnDragLeave();
+}
-void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {}
+void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {
+ DCHECK(drag_handler_delegate_);
+ drag_handler_delegate_->OnDragFinished(dnd_action);
+ drag_handler_delegate_ = nullptr;
+ connection()->event_source()->ResetPointerFlags();
+ std::move(drag_loop_quit_closure_).Run();
+}
void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) {
SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale()));
@@ -403,7 +524,7 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
// Will do nothing for menus because they have got their scale above.
UpdateBufferScale(false);
- root_surface_->SetOpaqueRegion(bounds_px_);
+ root_surface_->SetOpaqueRegion(gfx::Rect(bounds_px_.size()));
return true;
}
@@ -416,7 +537,7 @@ void WaylandWindow::AddEnteredOutputId(struct wl_output* output) {
// Wayland does weird things for menus so instead of tracking outputs that
// we entered or left, we take that from the parent window and ignore this
// event.
- if (wl::IsMenuType(type()))
+ if (wl::IsMenuType(type()) || type() == ui::PlatformWindowType::kTooltip)
return;
const uint32_t entered_output_id =
@@ -480,8 +601,16 @@ void WaylandWindow::UpdateCursorPositionFromEvent(
}
}
-WaylandWindow* WaylandWindow::GetTopLevelWindow() {
- return parent_window_ ? parent_window_->GetTopLevelWindow() : this;
+gfx::PointF WaylandWindow::TranslateLocationToRootWindow(
+ const gfx::PointF& location) {
+ auto* root_window = GetRootParentWindow();
+ DCHECK(root_window);
+ if (root_window == this)
+ return location;
+
+ gfx::Vector2d offset =
+ GetBounds().origin() - root_window->GetBounds().origin();
+ return location + gfx::Vector2dF(offset);
}
WaylandWindow* WaylandWindow::GetTopMostChildWindow() {
@@ -499,10 +628,6 @@ bool WaylandWindow::IsActive() const {
uint32_t WaylandWindow::DispatchEventToDelegate(
const PlatformEvent& native_event) {
- auto* event = static_cast<Event*>(native_event);
- if (event->IsLocatedEvent())
- UpdateCursorPositionFromEvent(Event::Clone(*event));
-
bool handled = DispatchEventFromNativeUiEvent(
native_event, base::BindOnce(&PlatformWindowDelegate::DispatchEvent,
base::Unretained(delegate_)));
@@ -584,6 +709,9 @@ bool WaylandWindow::CommitOverlays(
if (!ArrangeSubsurfaceStack(above, below))
return false;
+ if (wayland_overlay_delegation_enabled_)
+ connection_->buffer_manager_host()->StartFrame(root_surface());
+
{
// Iterate through |subsurface_stack_below_|, setup subsurfaces and place
// them in corresponding order. Commit wl_buffers once a subsurface is
@@ -608,7 +736,9 @@ bool WaylandWindow::CommitOverlays(
nullptr, reference_above);
connection_->buffer_manager_host()->CommitBufferInternal(
(*iter)->wayland_surface(), (*overlay_iter)->buffer_id, gfx::Rect(),
- /*wait_for_frame_callback=*/false);
+ /*wait_for_frame_callback=*/true,
+ /*commit_synced_subsurface=*/true,
+ std::move((*overlay_iter)->access_fence_handle));
} else {
// If there're more subsurfaces requested that we don't need at the
// moment, hide them.
@@ -637,7 +767,9 @@ bool WaylandWindow::CommitOverlays(
reference_below, nullptr);
connection_->buffer_manager_host()->CommitBufferInternal(
(*iter)->wayland_surface(), (*overlay_iter)->buffer_id, gfx::Rect(),
- /*wait_for_frame_callback=*/false);
+ /*wait_for_frame_callback=*/true,
+ /*commit_synced_subsurface=*/true,
+ std::move((*overlay_iter)->access_fence_handle));
} else {
// If there're more subsurfaces requested that we don't need at the
// moment, hide them.
@@ -646,7 +778,13 @@ bool WaylandWindow::CommitOverlays(
}
}
+ if (!num_primary_planes && overlays.front()->z_order == INT32_MIN)
+ split = overlays.begin();
+ UpdateVisualSize((*split)->bounds_rect.size());
+ root_surface_->SetViewportDestination(visual_size_px_);
+
if (!wayland_overlay_delegation_enabled_) {
+ root_surface_->SetViewportSource((*split)->crop_rect);
connection_->buffer_manager_host()->CommitBufferInternal(
root_surface(), (*split)->buffer_id, (*split)->damage_region,
/*wait_for_frame_callback=*/true);
@@ -659,26 +797,27 @@ bool WaylandWindow::CommitOverlays(
(*split)->enable_blend, nullptr, nullptr);
connection_->buffer_manager_host()->CommitBufferInternal(
primary_subsurface_->wayland_surface(), (*split)->buffer_id,
- (*split)->damage_region, /*wait_for_frame_callback=*/false);
+ (*split)->damage_region,
+ /*wait_for_frame_callback=*/true,
+ /*commit_synced_subsurface=*/true,
+ std::move((*split)->access_fence_handle));
}
- root_surface_->SetViewportDestination(bounds_px_.size());
-
+ gfx::Rect background_damage;
if (overlays.front()->z_order == INT32_MIN) {
background_buffer_id_ = overlays.front()->buffer_id;
+ background_damage = overlays.front()->damage_region;
should_attach_background_buffer_ = true;
}
if (should_attach_background_buffer_) {
- connection_->buffer_manager_host()->CommitBufferInternal(
- root_surface(), background_buffer_id_, /*damage_region=*/gfx::Rect(),
- /*wait_for_frame_callback=*/true);
+ connection_->buffer_manager_host()->EndFrame(background_buffer_id_,
+ background_damage);
should_attach_background_buffer_ = false;
} else {
// Subsurfaces are set to sync, above surface configs will only take effect
// when root_surface is committed.
- connection_->buffer_manager_host()->CommitWithoutBufferInternal(
- root_surface(), /*wait_for_frame_callback=*/true);
+ connection_->buffer_manager_host()->EndFrame();
}
return true;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_window.h
index e719914fdd4..8bcc007f766 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.h
@@ -15,6 +15,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
@@ -23,10 +24,7 @@
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_init_properties.h"
-
-namespace gfx {
-class PointF;
-}
+#include "ui/platform_window/wm/wm_drag_handler.h"
namespace ui {
@@ -38,7 +36,9 @@ class WaylandWindowDragController;
using WidgetSubsurfaceSet = base::flat_set<std::unique_ptr<WaylandSubsurface>>;
-class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+class WaylandWindow : public PlatformWindow,
+ public PlatformEventDispatcher,
+ public WmDragHandler {
public:
~WaylandWindow() override;
@@ -111,6 +111,21 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Returns current type of the window.
PlatformWindowType type() const { return type_; }
+ gfx::Size visual_size_px() const { return visual_size_px_; }
+
+ // This is never intended to be used except in unit tests.
+ void set_update_visual_size_immediately(bool update_immediately) {
+ update_visual_size_immediately_ = update_immediately;
+ }
+
+ // WmDragHandler
+ bool StartDrag(const ui::OSExchangeData& data,
+ int operation,
+ gfx::NativeCursor cursor,
+ bool can_grab_pointer,
+ WmDragHandler::Delegate* delegate) override;
+ void CancelDrag() override;
+
// PlatformWindow
void Show(bool inactive) override;
void Hide() override;
@@ -142,6 +157,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
void SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) override;
void SizeConstraintsChanged() override;
+ bool ShouldUseLayerForShapedWindow() const override;
// PlatformEventDispatcher
bool CanDispatchEvent(const PlatformEvent& event) override;
@@ -150,12 +166,14 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Handles the configuration events coming from the shell objects.
// The width and height come in DIP of the output that the surface is
// currently bound to.
- virtual void HandleSurfaceConfigure(int32_t widht,
- int32_t height,
- bool is_maximized,
- bool is_fullscreen,
- bool is_activated);
+ virtual void HandleSurfaceConfigure(uint32_t serial);
+ virtual void HandleToplevelConfigure(int32_t widht,
+ int32_t height,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated);
virtual void HandlePopupConfigure(const gfx::Rect& bounds);
+ virtual void UpdateVisualSize(const gfx::Size& size_px);
// Handles close requests.
virtual void OnCloseRequest();
@@ -165,10 +183,12 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
std::unique_ptr<OSExchangeData> data,
int operation);
virtual int OnDragMotion(const gfx::PointF& point, int operation);
- virtual void OnDragDrop(std::unique_ptr<OSExchangeData> data);
+ virtual void OnDragDrop();
virtual void OnDragLeave();
virtual void OnDragSessionClose(uint32_t dnd_action);
+ virtual base::Optional<std::vector<gfx::Rect>> GetWindowShape() const;
+
// Returns a root parent window within the same hierarchy.
WaylandWindow* GetRootParentWindow();
@@ -203,6 +223,9 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
void set_ui_scale(int32_t ui_scale) { ui_scale_ = ui_scale; }
+ // Calls set_opaque_region for this window.
+ virtual void UpdateWindowMask();
+
private:
FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetBufferScale);
@@ -211,13 +234,15 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
void UpdateCursorPositionFromEvent(std::unique_ptr<Event> event);
- WaylandWindow* GetTopLevelWindow();
+ gfx::PointF TranslateLocationToRootWindow(const gfx::PointF& location);
uint32_t DispatchEventToDelegate(const PlatformEvent& native_event);
// Additional initialization of derived classes.
virtual bool OnInitialize(PlatformWindowInitProperties properties) = 0;
+ virtual void UpdateWindowShape();
+
// WaylandWindowDragController might need to take ownership of the wayland
// surface whether the window that originated the DND session gets destroyed
// in the middle of that session (e.g: when it is snapped into a tab strip).
@@ -253,10 +278,23 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// The current cursor bitmap (immutable).
scoped_refptr<BitmapCursorOzone> bitmap_;
- // Current bounds of the platform window.
+ // Current bounds of the platform window. This is either initialized, or the
+ // requested size by the Wayland compositor. When this is set in SetBounds(),
+ // delegate_->OnBoundsChanged() is called and updates current_surface_size in
+ // Viz. However, it is not guaranteed that the next arriving frame will match
+ // |bounds_px_|.
gfx::Rect bounds_px_;
// The bounds of the platform window before it went maximized or fullscreen.
gfx::Rect restored_bounds_px_;
+ // The size presented by the gpu process. This is the visible size of the
+ // window, which can be different from |bounds_px_| due to renderers taking
+ // time to produce a compositor frame.
+ // The rough flow of size changes:
+ // Wayland compositor -> xdg_surface.configure()
+ // -> WaylandWindow::SetBounds() -> IPC -> DisplayPrivate::Resize()
+ // -> OutputSurface::SwapBuffers() -> WaylandWindow::UpdateVisualSize()
+ // -> xdg_surface.ack_configure() -> Wayland compositor.
+ gfx::Size visual_size_px_;
bool has_pointer_focus_ = false;
bool has_keyboard_focus_ = false;
@@ -285,9 +323,21 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Set when the window enters in shutdown process.
bool shutting_down_ = false;
+ // In a non-test environment, a frame update makes a SetBounds() change
+ // visible in |visual_size_px_|, but in some unit tests there will never be
+ // any frame updates. This flag causes UpdateVisualSize() to be invoked during
+ // SetBounds() in unit tests.
+ bool update_visual_size_immediately_ = false;
+
// AcceleratedWidget for this window. This will be unique even over time.
gfx::AcceleratedWidget accelerated_widget_;
+ WmDragHandler::Delegate* drag_handler_delegate_ = nullptr;
+
+ base::OnceClosure drag_loop_quit_closure_;
+
+ base::WeakPtrFactory<WaylandWindow> weak_ptr_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(WaylandWindow);
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
index 05f6bcc2ec7..3431631b596 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
@@ -36,7 +36,6 @@
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_data_offer.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
-#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
@@ -142,11 +141,14 @@ bool WaylandWindowDragController::Drag(WaylandToplevelWindow* window,
RunLoop();
SetDraggedWindow(nullptr, {});
- DCHECK(state_ == State::kAttached || state_ == State::kDropped);
- bool dropped = state_ == State::kDropped;
- if (dropped)
- HandleDropAndResetState();
- return dropped;
+ DCHECK(state_ == State::kAttaching || state_ == State::kDropped);
+ if (state_ == State::kAttaching) {
+ state_ = State::kAttached;
+ return false;
+ }
+
+ HandleDropAndResetState();
+ return true;
}
void WaylandWindowDragController::StopDragging() {
@@ -158,7 +160,7 @@ void WaylandWindowDragController::StopDragging() {
// This function is supposed to be called to indicate that the window was just
// snapped into a tab strip. So switch to |kAttached| state, store the focused
// window as the pointer grabber and ask to quit the nested loop.
- state_ = State::kAttached;
+ state_ = State::kAttaching;
pointer_grab_owner_ = window_manager_->GetCurrentFocusedWindow();
DCHECK(pointer_grab_owner_);
QuitLoop();
@@ -209,7 +211,7 @@ void WaylandWindowDragController::OnDragEnter(WaylandWindow* window,
DCHECK_EQ(data_offer_->mime_types().front(), kMimeTypeChromiumWindow);
// Accept the offer and set the dnd action.
- data_offer_->SetAction(kDndActionWindowDrag, kDndActionWindowDrag);
+ data_offer_->SetActions(kDndActionWindowDrag);
data_offer_->Accept(serial, kMimeTypeChromiumWindow);
}
@@ -217,6 +219,11 @@ void WaylandWindowDragController::OnDragMotion(const gfx::PointF& location) {
DCHECK_GE(state_, State::kAttached);
VLOG(2) << "OnMotion. location=" << location.ToString();
+ // Motion events are not expected to be dispatched while waiting for the drag
+ // loop to exit, ie: kAttaching transitional state. See crbug.com/1169446.
+ if (state_ == State::kAttaching)
+ return;
+
// Forward cursor location update info to the input handling delegate.
should_process_drag_event_ = true;
pointer_location_ = location;
@@ -225,7 +232,6 @@ void WaylandWindowDragController::OnDragMotion(const gfx::PointF& location) {
void WaylandWindowDragController::OnDragLeave() {
DCHECK_GE(state_, State::kAttached);
- DCHECK_LE(state_, State::kDetached);
// In order to guarantee ET_MOUSE_RELEASED event is delivered once the DND
// session finishes, the focused window is not reset here. This is similar to
@@ -324,8 +330,6 @@ uint32_t WaylandWindowDragController::DispatchEvent(
DCHECK_EQ(state_, State::kDetached);
DCHECK(base::CurrentUIThread::IsSet());
- VLOG(2) << "Dispatch. event=" << event->GetName();
-
if (event->type() == ET_MOUSE_MOVED || event->type() == ET_MOUSE_DRAGGED) {
HandleMotionEvent(event->AsMouseEvent());
return POST_DISPATCH_STOP_PROPAGATION;
@@ -348,7 +352,6 @@ void WaylandWindowDragController::OnToplevelWindowCreated(
<< " calculated_offset=" << offset.ToString();
SetDraggedWindow(window, offset);
- state_ = State::kDetached;
}
void WaylandWindowDragController::OnWindowRemoved(WaylandWindow* window) {
@@ -395,7 +398,6 @@ void WaylandWindowDragController::HandleDropAndResetState() {
VLOG(1) << "Notifying drop. window=" << pointer_grab_owner_;
EventFlags pointer_button = EF_LEFT_MOUSE_BUTTON;
- DCHECK(connection_->event_source()->IsPointerButtonPressed(pointer_button));
pointer_delegate_->OnPointerButtonEvent(ET_MOUSE_RELEASED, pointer_button,
pointer_grab_owner_);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
index 94dae03f336..96da9124b5c 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
@@ -46,10 +46,11 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
public:
// Constants used to keep track of the drag controller state.
enum class State {
- kIdle, // No DnD session nor drag loop running.
- kAttached, // DnD session ongoing but no drag loop running.
- kDetached, // Drag loop running. ie: blocked in a Drag() call.
- kDropped // Drop event was just received.
+ kIdle, // No DnD session nor drag loop running.
+ kAttached, // DnD session ongoing but no drag loop running.
+ kDetached, // Drag loop running. ie: blocked in a Drag() call.
+ kDropped, // Drop event was just received.
+ kAttaching, // About to transition back to |kAttached|.
};
WaylandWindowDragController(WaylandConnection* connection,
@@ -153,8 +154,10 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
std::unique_ptr<ScopedEventDispatcher> nested_dispatcher_;
base::OnceClosure quit_loop_closure_;
- // Tells if the current drag event should be processedc. E.g: received through
- // wl_data_device::motion wayland event.
+ // Tells if the current drag event should be processed. Buggy compositors may
+ // send wl_pointer::motion events, for example, while a DND session is still
+ // in progress, which leads to issues in window dragging sessions, this flag
+ // is used to make window drag controller resistant to such scenarios.
bool should_process_drag_event_ = false;
base::WeakPtrFactory<WaylandWindowDragController> weak_factory_{this};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
index db3944812a3..79f66eb7db1 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
@@ -10,6 +10,7 @@
#include <cstdint>
+#include "base/bind.h"
#include "base/notreached.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/base_event_utils.h"
@@ -30,7 +31,7 @@
#include "ui/ozone/platform/wayland/test/test_data_offer.h"
#include "ui/ozone/platform/wayland/test/test_data_source.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/test/wayland_test.h"
+#include "ui/ozone/platform/wayland/test/wayland_drag_drop_test.h"
#include "ui/ozone/test/mock_platform_window_delegate.h"
#include "ui/platform_window/extensions/wayland_extension.h"
#include "ui/platform_window/platform_window_delegate.h"
@@ -41,14 +42,14 @@ using testing::Mock;
namespace ui {
-class WaylandWindowDragControllerTest : public WaylandTest,
- public wl::TestDataDevice::Delegate {
+class WaylandWindowDragControllerTest : public WaylandDragDropTest {
public:
WaylandWindowDragControllerTest() = default;
~WaylandWindowDragControllerTest() override = default;
void SetUp() override {
- WaylandTest::SetUp();
+ WaylandDragDropTest::SetUp();
+
screen_ = std::make_unique<WaylandScreen>(connection_.get());
wl_seat_send_capabilities(server_.seat()->resource(),
@@ -59,16 +60,6 @@ class WaylandWindowDragControllerTest : public WaylandTest,
EXPECT_FALSE(window_->has_pointer_focus());
EXPECT_EQ(State::kIdle, drag_controller()->state());
-
- data_device_manager_ = server_.data_device_manager();
- DCHECK(data_device_manager_);
-
- source_ = nullptr;
- data_device_manager_->data_device()->set_delegate(this);
- }
-
- void TearDown() override {
- data_device_manager_->data_device()->set_delegate(nullptr);
}
WaylandWindowDragController* drag_controller() const {
@@ -79,52 +70,11 @@ class WaylandWindowDragControllerTest : public WaylandTest,
return connection_->wayland_window_manager();
}
- uint32_t NextSerial() const {
- static uint32_t serial = 0;
- return ++serial;
- }
-
- uint32_t NextTime() const {
- static uint32_t timestamp = 0;
- return ++timestamp;
- }
+ MockPlatformWindowDelegate& delegate() { return delegate_; }
protected:
using State = WaylandWindowDragController::State;
- // wl::TestDataDevice::Delegate:
- void StartDrag(wl::TestDataSource* source,
- wl::MockSurface* origin,
- uint32_t serial) override {
- EXPECT_FALSE(source_);
- source_ = source;
- OfferAndEnter(origin);
- }
-
- // Helper functions
- void SendDndMotion(const gfx::Point& location) {
- EXPECT_TRUE(source_);
- wl_fixed_t x = wl_fixed_from_int(location.x());
- wl_fixed_t y = wl_fixed_from_int(location.y());
- data_device_manager_->data_device()->OnMotion(NextTime(), x, y);
- }
-
- void SendDndEnter(WaylandWindow* window) {
- EXPECT_TRUE(window);
- OfferAndEnter(server_.GetObject<wl::MockSurface>(
- window->root_surface()->GetSurfaceId()));
- }
-
- void SendDndLeave() {
- EXPECT_TRUE(source_);
- data_device_manager_->data_device()->OnLeave();
- }
-
- void SendDndDrop() {
- EXPECT_TRUE(source_);
- source_->OnCancelled();
- }
-
void SendPointerEnter(WaylandWindow* window,
MockPlatformWindowDelegate* delegate) {
auto* surface = server_.GetObject<wl::MockSurface>(
@@ -181,24 +131,17 @@ class WaylandWindowDragControllerTest : public WaylandTest,
screen_->GetLocalProcessWidgetAtPoint(location, {}));
}
- void OfferAndEnter(wl::MockSurface* surface) {
- EXPECT_TRUE(source_);
- auto* data_device = data_device_manager_->data_device();
- auto* offer = data_device->OnDataOffer();
- EXPECT_EQ(1u, source_->mime_types().size());
- for (const auto& mime_type : source_->mime_types())
- offer->OnOffer(mime_type, {});
-
- wl_data_device_send_enter(data_device->resource(), NextSerial(),
- surface->resource(), 0, 0, offer->resource());
- }
+ // For the context of window drag, "drop" is detected through
+ // wl_data_source::cancelled in the regular case. Unless extended-drag
+ // protocol is available.
+ //
+ // TODO(crbug.com/1116431): Support extended-drag in test compositor.
+ void SendDndDrop() { SendDndCancelled(); }
// client objects
std::unique_ptr<WaylandScreen> screen_;
// server objects
- wl::TestDataDeviceManager* data_device_manager_;
- wl::TestDataSource* source_;
wl::MockPointer* pointer_;
};
@@ -471,7 +414,7 @@ TEST_P(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop) {
// Exit |source_window| and enter the |target_window|.
SendDndLeave();
- SendDndEnter(target_window);
+ SendDndEnter(target_window, {});
test_step = kEnteredTarget;
});
@@ -723,6 +666,65 @@ TEST_P(WaylandWindowDragControllerTest, IgnorePointerEventsUntilDrop) {
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
}
+// Regression test for https://crbug.com/1169446.
+TEST_P(WaylandWindowDragControllerTest, MotionEventsSkippedWhileReattaching) {
+ auto* dragged_window = window_.get();
+ EXPECT_TRUE(dragged_window);
+
+ SendPointerEnter(dragged_window, &delegate_);
+ SendPointerPress(dragged_window, &delegate_, BTN_LEFT);
+ SendPointerMotion(dragged_window, &delegate_, {10, 10});
+
+ auto* wayland_extension = GetWaylandExtension(*window_);
+ wayland_extension->StartWindowDraggingSessionIfNeeded();
+ EXPECT_EQ(State::kAttached, drag_controller()->state());
+
+ auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
+ ASSERT_TRUE(move_loop_handler);
+
+ auto test = [](WaylandWindowDragControllerTest* self,
+ WmMoveLoopHandler* move_loop_handler) {
+ // While in |kDetached| state, motion events are expected to be propagated
+ // by window drag controller.
+ EXPECT_EQ(State::kDetached, self->drag_controller()->state());
+ self->SendDndMotion({30, 30});
+ EXPECT_CALL(self->delegate(), DispatchEvent(_)).Times(1);
+ self->Sync();
+
+ move_loop_handler->EndMoveLoop();
+ self->Sync();
+
+ // Otherwise, after the move loop is requested to quit, but before it really
+ // ends (ie. kAttaching state), motion events are **not** expected to be
+ // propagated.
+ EXPECT_EQ(State::kAttaching, self->drag_controller()->state());
+ self->SendDndMotion({30, 30});
+ EXPECT_CALL(self->delegate(), DispatchEvent(_)).Times(0);
+ self->Sync();
+ };
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this),
+ base::Unretained(move_loop_handler)));
+
+ // Spins move loop for |window_1|.
+ move_loop_handler->RunMoveLoop({});
+
+ // When the transition to |kAttached| state is finally done (ie. nested loop
+ // quits), motion events are then expected to be propagated by window drag
+ // controller as usual.
+ EXPECT_EQ(State::kAttached, drag_controller()->state());
+ SendDndMotion({30, 30});
+ EXPECT_CALL(delegate(), DispatchEvent(_)).Times(1);
+ Sync();
+
+ SendDndDrop();
+ EXPECT_CALL(delegate(), DispatchEvent(_)).Times(1);
+ Sync();
+
+ SendPointerEnter(window_.get(), &delegate_);
+
+ EXPECT_EQ(State::kIdle, drag_controller()->state());
+}
+
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandWindowDragControllerTest,
::testing::Values(kXdgShellStable));
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
index 7cca6ba6a82..90f2b76a2b0 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
@@ -4,12 +4,14 @@
#include <memory>
+#include "base/compiler_specific.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/wayland_auxiliary_window.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_popup.h"
#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/platform_window/platform_window_init_properties.h"
namespace ui {
@@ -20,32 +22,32 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create(
PlatformWindowInitProperties properties) {
std::unique_ptr<WaylandWindow> window;
switch (properties.type) {
- case PlatformWindowType::kMenu:
case PlatformWindowType::kPopup:
if (connection->IsDragInProgress()) {
// We are in the process of drag and requested a popup. Most probably,
// it is an arrow window.
window = std::make_unique<WaylandAuxiliaryWindow>(delegate, connection);
+ break;
+ }
+ FALLTHROUGH;
+ case PlatformWindowType::kMenu:
+ // Set the parent window in advance otherwise it is not possible to know
+ // if the popup is able to find one and if WaylandWindow::Initialize()
+ // fails or not. Otherwise, WaylandWindow::Create() returns nullptr and
+ // makes the browser to fail. To fix this problem, search for the parent
+ // window and if one is not found, create WaylandToplevelWindow instead.
+ // It's also worth noting that searching twice (one time here and
+ // another by WaylandPopup) is a bad practice, and the parent window is
+ // set here instead. TODO(crbug.com/1078328): Feed ozone/wayland with full
+ // layout info required to properly position popup windows.
+ if (auto* parent_window =
+ connection->wayland_window_manager()->FindParentForNewWindow(
+ properties.parent_widget)) {
+ window = std::make_unique<WaylandPopup>(delegate, connection);
+ window->set_parent_window(parent_window);
} else {
- auto* parent_window =
- connection->wayland_window_manager()->FindParentForNewWindow(
- properties.parent_widget);
- if (parent_window) {
- // Set the parent window in advance otherwise it is not possible to
- // know if the WaylandPopup is able to find one and if
- // WaylandWindow::Initialize() fails or not. Otherwise,
- // WaylandWindow::Create() returns nullptr and makes the browser to
- // fail. To fix this problem, search for the parent window and if
- // one is not found, create WaylandToplevelWindow instead. It's
- // also worth noting that searching twice (one time here and another
- // by WaylandPopup) is a bad practice, and the parent window is set
- // here instead.
- window = std::make_unique<WaylandPopup>(delegate, connection);
- window->set_parent_window(parent_window);
- } else {
- window =
- std::make_unique<WaylandToplevelWindow>(delegate, connection);
- }
+ DLOG(WARNING) << "Failed to determine for menu/popup window.";
+ window = std::make_unique<WaylandToplevelWindow>(delegate, connection);
}
break;
case PlatformWindowType::kTooltip:
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index 458f6b5f0a4..f6be452b0a1 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -34,6 +34,7 @@
#include "ui/ozone/platform/wayland/test/mock_pointer.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
#include "ui/ozone/platform/wayland/test/test_keyboard.h"
+#include "ui/ozone/platform/wayland/test/test_output.h"
#include "ui/ozone/platform/wayland/test/test_region.h"
#include "ui/ozone/platform/wayland/test/test_touch.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
@@ -44,7 +45,9 @@
#include "ui/platform_window/wm/wm_move_resize_handler.h"
using ::testing::_;
+using ::testing::DoAll;
using ::testing::Eq;
+using ::testing::InvokeWithoutArgs;
using ::testing::Mock;
using ::testing::Return;
using ::testing::SaveArg;
@@ -270,6 +273,146 @@ TEST_P(WaylandWindowTest, SetTitle) {
window_->SetTitle(base::ASCIIToUTF16("hello"));
}
+TEST_P(WaylandWindowTest, UpdateVisualSizeConfiguresWaylandWindow) {
+ const auto kNormalBounds = gfx::Rect{0, 0, 500, 300};
+ uint32_t serial = 0;
+ auto state = InitializeWlArrayWithActivatedState();
+
+ window_->set_update_visual_size_immediately(false);
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+
+ // Configure event makes Wayland update bounds, but does not change toplevel
+ // input region, opaque region or window geometry immediately. Such actions
+ // are postponed to UpdateVisualSize();
+ EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
+ kNormalBounds.height()))
+ .Times(0);
+ EXPECT_CALL(*xdg_surface_, AckConfigure(1)).Times(0);
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).Times(0);
+ EXPECT_CALL(*mock_surface, SetInputRegion(_)).Times(0);
+ SendConfigureEvent(xdg_surface_, kNormalBounds.width(),
+ kNormalBounds.height(), ++serial, state.get());
+
+ Sync();
+
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
+ kNormalBounds.height()));
+ EXPECT_CALL(*xdg_surface_, AckConfigure(1));
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_));
+ EXPECT_CALL(*mock_surface, SetInputRegion(_));
+ window_->UpdateVisualSize(kNormalBounds.size());
+}
+
+TEST_P(WaylandWindowTest, ShuffledUpdateVisualSizeOrder) {
+ const auto kNormalBounds1 = gfx::Rect{0, 0, 500, 300};
+ const auto kNormalBounds2 = gfx::Rect{0, 0, 800, 600};
+ const auto kNormalBounds3 = gfx::Rect{0, 0, 700, 400};
+ uint32_t serial = 1;
+
+ window_->set_update_visual_size_immediately(false);
+
+ // Send 3 configures and only ack the second one, the first pending configure
+ // is cleared. The second can still be ack'ed.
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds1.width(),
+ kNormalBounds1.height()))
+ .Times(0);
+ EXPECT_CALL(*xdg_surface_, AckConfigure(2)).Times(0);
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds2.width(),
+ kNormalBounds2.height()));
+ EXPECT_CALL(*xdg_surface_, AckConfigure(3));
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds3.width(),
+ kNormalBounds3.height()));
+ EXPECT_CALL(*xdg_surface_, AckConfigure(4));
+
+ auto state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds1.width(),
+ kNormalBounds1.height(), ++serial, state.get());
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds2.width(),
+ kNormalBounds2.height(), ++serial, state.get());
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds3.width(),
+ kNormalBounds3.height(), ++serial, state.get());
+ Sync();
+
+ window_->UpdateVisualSize(kNormalBounds2.size());
+ window_->UpdateVisualSize(kNormalBounds1.size());
+ window_->UpdateVisualSize(kNormalBounds3.size());
+}
+
+TEST_P(WaylandWindowTest, MismatchUpdateVisualSize) {
+ const auto kNormalBounds1 = gfx::Rect{0, 0, 500, 300};
+ const auto kNormalBounds2 = gfx::Rect{0, 0, 800, 600};
+ const auto kNormalBounds3 = gfx::Rect{0, 0, 700, 400};
+ uint32_t serial = 1;
+
+ window_->set_update_visual_size_immediately(false);
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+
+ // UpdateVisualSize with different size from configure events does not
+ // acknowledge toplevel configure.
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(_, _, _, _)).Times(0);
+ EXPECT_CALL(*xdg_surface_, AckConfigure(_)).Times(0);
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_));
+ EXPECT_CALL(*mock_surface, SetInputRegion(_));
+
+ auto state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds1.width(),
+ kNormalBounds1.height(), ++serial, state.get());
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds2.width(),
+ kNormalBounds2.height(), ++serial, state.get());
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds3.width(),
+ kNormalBounds3.height(), ++serial, state.get());
+ Sync();
+
+ window_->UpdateVisualSize({100, 100});
+}
+
+TEST_P(WaylandWindowTest, UpdateVisualSizeClearsPreviousUnackedConfigures) {
+ const auto kNormalBounds1 = gfx::Rect{0, 0, 500, 300};
+ const auto kNormalBounds2 = gfx::Rect{0, 0, 800, 600};
+ const auto kNormalBounds3 = gfx::Rect{0, 0, 700, 400};
+ uint32_t serial = 1;
+ auto state = InitializeWlArrayWithActivatedState();
+
+ window_->set_update_visual_size_immediately(false);
+
+ // Send 3 configures and only ack the second one, the first pending configure
+ // is cleared. The second can still be ack'ed.
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds1.width(),
+ kNormalBounds1.height()))
+ .Times(0);
+ EXPECT_CALL(*xdg_surface_, AckConfigure(2)).Times(0);
+ SendConfigureEvent(xdg_surface_, kNormalBounds1.width(),
+ kNormalBounds1.height(), ++serial, state.get());
+ Sync();
+
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds2.width(),
+ kNormalBounds2.height()));
+ EXPECT_CALL(*xdg_surface_, AckConfigure(3));
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds2.width(),
+ kNormalBounds2.height(), ++serial, state.get());
+ Sync();
+
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds3.width(),
+ kNormalBounds3.height()));
+ EXPECT_CALL(*xdg_surface_, AckConfigure(4));
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds3.width(),
+ kNormalBounds3.height(), ++serial, state.get());
+ Sync();
+
+ window_->UpdateVisualSize(kNormalBounds2.size());
+ window_->UpdateVisualSize(kNormalBounds1.size());
+ window_->UpdateVisualSize(kNormalBounds3.size());
+}
+
TEST_P(WaylandWindowTest, MaximizeAndRestore) {
const auto kNormalBounds = gfx::Rect{0, 0, 500, 300};
const auto kMaximizedBounds = gfx::Rect{0, 0, 800, 600};
@@ -295,7 +438,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
kMaximizedBounds.height()));
EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds));
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Maximize();
SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
kMaximizedBounds.height(), ++serial,
@@ -326,7 +469,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
kNormalBounds.height()));
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
EXPECT_CALL(delegate_, OnActivationChanged(_)).Times(0);
EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized());
@@ -346,7 +489,7 @@ TEST_P(WaylandWindowTest, Minimize) {
Sync();
EXPECT_CALL(*GetXdgToplevel(), SetMinimized());
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Minimize();
EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized);
@@ -363,8 +506,14 @@ TEST_P(WaylandWindowTest, Minimize) {
// Send one additional empty configuration event (which means the surface is
// not maximized, fullscreen or activated) to ensure, WaylandWindow stays in
- // the same minimized state and doesn't notify its delegate.
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ // the same minimized state, but the delegate is always notified.
+ //
+ // TODO(tonikito): Improve filtering of delegate notification here.
+ ui::PlatformWindowState state;
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_))
+ .WillRepeatedly(DoAll(SaveArg<0>(&state), InvokeWithoutArgs([&]() {
+ EXPECT_EQ(state, PlatformWindowState::kMinimized);
+ })));
SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get());
Sync();
@@ -384,7 +533,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
EXPECT_CALL(*GetXdgToplevel(), SetFullscreen());
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->ToggleFullscreen();
// Make sure than WaylandWindow manually handles fullscreen states. Check the
// comment in the WaylandWindow::ToggleFullscreen.
@@ -394,7 +543,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
Sync();
EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen());
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Restore();
EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
// Reinitialize wl_array, which removes previous old states.
@@ -467,12 +616,11 @@ TEST_P(WaylandWindowTest, StartMaximized) {
// Make sure the window is initialized to normal state from the beginning.
EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
- // The state must not be changed to the fullscreen before the surface is
- // activated.
+ // The state gets changed to maximize and the delegate notified.
auto* mock_surface = server_.GetObject<wl::MockSurface>(
window->root_surface()->GetSurfaceId());
EXPECT_FALSE(mock_surface->xdg_surface());
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Maximize();
// The state of the window must already be fullscreen one.
@@ -480,8 +628,8 @@ TEST_P(WaylandWindowTest, StartMaximized) {
Sync();
- // Once the surface will be activated, the window state mustn't be changed
- // and retain the same.
+ // Window show state should be already up to date, so delegate is not
+ // notified.
EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized);
@@ -521,6 +669,8 @@ TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(),
normal_bounds.height()));
+ Sync();
+
// Now, set to fullscreen.
AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
SendConfigureEvent(xdg_surface_, 2005, 2005, 3, states.get());
@@ -598,7 +748,7 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
kMaximizedBounds.height()));
EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds));
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Maximize();
// State changes are synchronous.
EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState());
@@ -614,7 +764,7 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
kMaximizedBounds.height()));
EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0);
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->ToggleFullscreen();
// State changes are synchronous.
EXPECT_EQ(PlatformWindowState::kFullScreen,
@@ -632,9 +782,8 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
kNormalBounds.height()));
EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen());
- EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized());
EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Restore();
EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
// Reinitialize wl_array, which removes previous old states.
@@ -808,6 +957,51 @@ TEST_P(WaylandWindowTest, SendsBoundsOnRequest) {
EXPECT_EQ(restored_bounds, gfx::Rect());
}
+TEST_P(WaylandWindowTest, UpdateWindowRegion) {
+ wl::MockSurface* mock_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+
+ // Change bounds.
+ const gfx::Rect initial_bounds = window_->GetBounds();
+ const gfx::Rect new_bounds = gfx::Rect(0, 0, initial_bounds.width() + 10,
+ initial_bounds.height() + 10);
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).Times(1);
+ EXPECT_CALL(*mock_surface, SetInputRegion(_)).Times(1);
+ window_->SetBounds(new_bounds);
+ Sync();
+ VerifyAndClearExpectations();
+ EXPECT_EQ(mock_surface->opaque_region(), new_bounds);
+ EXPECT_EQ(mock_surface->input_region(), new_bounds);
+
+ // Maximize.
+ ScopedWlArray states = InitializeWlArrayWithActivatedState();
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).Times(1);
+ EXPECT_CALL(*mock_surface, SetInputRegion(_)).Times(1);
+ const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768);
+ window_->Maximize();
+ AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
+ SendConfigureEvent(xdg_surface_, maximized_bounds.width(),
+ maximized_bounds.height(), 1, states.get());
+ Sync();
+ VerifyAndClearExpectations();
+ EXPECT_EQ(mock_surface->opaque_region(), maximized_bounds);
+ EXPECT_EQ(mock_surface->input_region(), maximized_bounds);
+
+ // Restore.
+ const gfx::Rect restored_bounds = window_->GetRestoredBoundsInPixels();
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).Times(1);
+ EXPECT_CALL(*mock_surface, SetInputRegion(_)).Times(1);
+ window_->Restore();
+ // Reinitialize wl_array, which removes previous old states.
+ auto active = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, 0, 0, 2, active.get());
+ Sync();
+ VerifyAndClearExpectations();
+
+ EXPECT_EQ(mock_surface->opaque_region(), restored_bounds);
+ EXPECT_EQ(mock_surface->input_region(), restored_bounds);
+}
+
TEST_P(WaylandWindowTest, CanDispatchMouseEventDefault) {
EXPECT_FALSE(window_->CanDispatchEvent(&test_mouse_event_));
}
@@ -1397,6 +1591,102 @@ TEST_P(WaylandWindowTest, DispatchWindowResize) {
}
}
+TEST_P(WaylandWindowTest, ToplevelWindowUpdateBufferScale) {
+ VerifyAndClearExpectations();
+
+ // Buffer scale must be 1 when no output has been entered by the window.
+ EXPECT_EQ(1, window_->buffer_scale());
+
+ // Creating an output with scale 1.
+ wl::TestOutput* output1 = server_.CreateAndInitializeOutput();
+ output1->SetRect(gfx::Rect(0, 0, 1920, 1080));
+ output1->SetScale(1);
+ Sync();
+
+ // Creating an output with scale 2.
+ wl::TestOutput* output2 = server_.CreateAndInitializeOutput();
+ output2->SetRect(gfx::Rect(0, 0, 1920, 1080));
+ output2->SetScale(2);
+ Sync();
+
+ // Send the window to |output1|.
+ wl::MockSurface* surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+ ASSERT_TRUE(surface);
+ wl_surface_send_enter(surface->resource(), output1->resource());
+ Sync();
+
+ // The window's scale and bounds must remain unchanged.
+ EXPECT_EQ(1, window_->buffer_scale());
+ EXPECT_EQ(gfx::Rect(0, 0, 800, 600), window_->GetBounds());
+
+ // Simulating drag process from |output1| to |output2|.
+ wl_surface_send_enter(surface->resource(), output2->resource());
+ wl_surface_send_leave(surface->resource(), output1->resource());
+ Sync();
+
+ // The window must change its scale and bounds to keep DIP bounds the same.
+ EXPECT_EQ(2, window_->buffer_scale());
+ EXPECT_EQ(gfx::Rect(0, 0, 1600, 1200), window_->GetBounds());
+}
+
+TEST_P(WaylandWindowTest, AuxiliaryWindowUpdateBufferScale) {
+ VerifyAndClearExpectations();
+
+ // Creating an output with scale 1.
+ wl::TestOutput* output1 = server_.CreateAndInitializeOutput();
+ output1->SetRect(gfx::Rect(0, 0, 1920, 1080));
+ output1->SetScale(1);
+ Sync();
+
+ // Creating an output with scale 2.
+ wl::TestOutput* output2 = server_.CreateAndInitializeOutput();
+ output2->SetRect(gfx::Rect(0, 0, 1920, 1080));
+ output2->SetScale(2);
+ Sync();
+
+ // Send the window to |output1|.
+ wl::MockSurface* surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+ ASSERT_TRUE(surface);
+ wl_surface_send_enter(surface->resource(), output1->resource());
+ Sync();
+
+ // Creating a tooltip on |window_|.
+ window_->SetPointerFocus(true);
+ gfx::Rect subsurface_bounds(15, 15, 10, 10);
+ std::unique_ptr<WaylandWindow> auxiliary_window =
+ CreateWaylandWindowWithParams(PlatformWindowType::kTooltip,
+ gfx::kNullAcceleratedWidget,
+ subsurface_bounds, &delegate_);
+ EXPECT_TRUE(auxiliary_window);
+
+ auxiliary_window->Show(false);
+
+ // |auxiliary_window| should inherit its buffer scale from the focused window.
+ EXPECT_EQ(1, auxiliary_window->buffer_scale());
+ EXPECT_EQ(subsurface_bounds, auxiliary_window->GetBounds());
+ auxiliary_window->Hide();
+
+ // Send the window to |output2|.
+ wl_surface_send_enter(surface->resource(), output2->resource());
+ wl_surface_send_leave(surface->resource(), output1->resource());
+ Sync();
+
+ EXPECT_EQ(2, window_->buffer_scale());
+ auxiliary_window->Show(false);
+
+ // |auxiliary_window|'s scale and bounds must change whenever its parents
+ // scale is changed.
+ EXPECT_EQ(2, window_->buffer_scale());
+ EXPECT_EQ(2, auxiliary_window->buffer_scale());
+ EXPECT_EQ(gfx::ScaleToRoundedRect(subsurface_bounds, 2),
+ auxiliary_window->GetBounds());
+
+ auxiliary_window->Hide();
+ window_->SetPointerFocus(false);
+}
+
// Tests WaylandWindow repositions menu windows to be relative to parent window
// in a right way.
TEST_P(WaylandWindowTest, AdjustPopupBounds) {
@@ -1408,26 +1698,29 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_RIGHT,
ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT,
ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X |
- ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y};
+ ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y |
+ ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y};
nested_menu_window_positioner = {
gfx::Rect(4, 80, 279, 1), gfx::Size(305, 99),
ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_RIGHT,
ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT,
ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X |
- ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y};
+ ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y |
+ ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y};
} else {
- menu_window_positioner = {gfx::Rect(439, 46, 1, 30), gfx::Size(287, 409),
- XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT,
- XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X |
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y};
-
+ menu_window_positioner = {
+ gfx::Rect(439, 46, 1, 30), gfx::Size(287, 409),
+ XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y};
nested_menu_window_positioner = {
gfx::Rect(4, 80, 279, 1), gfx::Size(305, 99),
XDG_POSITIONER_ANCHOR_TOP_RIGHT, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X |
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y};
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y};
}
auto* toplevel_window = window_.get();
@@ -1590,6 +1883,7 @@ TEST_P(WaylandWindowTest, SetOpaqueRegion) {
Sync();
VerifyAndClearExpectations();
+ EXPECT_EQ(mock_surface->opaque_region(), new_bounds);
new_bounds.set_size(gfx::Size(1000, 534));
SendConfigureEvent(xdg_surface_, new_bounds.width(), new_bounds.height(), 2,
@@ -1601,6 +1895,7 @@ TEST_P(WaylandWindowTest, SetOpaqueRegion) {
Sync();
VerifyAndClearExpectations();
+ EXPECT_EQ(mock_surface->opaque_region(), new_bounds);
}
TEST_P(WaylandWindowTest, OnCloseRequest) {
@@ -1617,23 +1912,16 @@ TEST_P(WaylandWindowTest, OnCloseRequest) {
TEST_P(WaylandWindowTest, AuxiliaryWindowSimpleParent) {
VerifyAndClearExpectations();
- std::unique_ptr<WaylandWindow> second_window = CreateWaylandWindowWithParams(
- PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
- gfx::Rect(0, 0, 640, 480), &delegate_);
- EXPECT_TRUE(second_window);
-
- // Test case 1: if the subsurface is provided with a parent widget, it must
- // always use that as a parent.
+ // Auxiliary window must ignore the parent provided by aura and should always
+ // use focused window instead.
gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
std::unique_ptr<WaylandWindow> auxiliary_window =
CreateWaylandWindowWithParams(PlatformWindowType::kTooltip,
- window_->GetWidget(), subsurface_bounds,
- &delegate_);
+ gfx::kNullAcceleratedWidget,
+ subsurface_bounds, &delegate_);
EXPECT_TRUE(auxiliary_window);
- // The subsurface mustn't take the focused window as a parent, but use the
- // provided one.
- second_window->SetPointerFocus(true);
+ window_->SetPointerFocus(true);
auxiliary_window->Show(false);
Sync();
@@ -1644,6 +1932,8 @@ TEST_P(WaylandWindowTest, AuxiliaryWindowSimpleParent) {
EXPECT_EQ(test_subsurface->position(), subsurface_bounds.origin());
EXPECT_FALSE(test_subsurface->sync());
+ EXPECT_EQ(mock_surface_subsurface->opaque_region(),
+ gfx::Rect(subsurface_bounds.size()));
auto* parent_resource =
server_
@@ -1651,47 +1941,7 @@ TEST_P(WaylandWindowTest, AuxiliaryWindowSimpleParent) {
->resource();
EXPECT_EQ(parent_resource, test_subsurface->parent_resource());
- // Test case 2: the subsurface must use the focused window as its parent.
- auxiliary_window = CreateWaylandWindowWithParams(
- PlatformWindowType::kTooltip, gfx::kNullAcceleratedWidget,
- subsurface_bounds, &delegate_);
- EXPECT_TRUE(auxiliary_window);
-
- // The tooltip must take the focused window.
- second_window->SetPointerFocus(true);
- auxiliary_window->Show(false);
-
- Sync();
-
- // Get new surface after recreating the WaylandAuxiliaryWindow.
- mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
- auxiliary_window->root_surface()->GetSurfaceId());
- test_subsurface = mock_surface_subsurface->sub_surface();
-
- auto* second_parent_resource =
- server_
- .GetObject<wl::MockSurface>(
- second_window->root_surface()->GetSurfaceId())
- ->resource();
- EXPECT_EQ(second_parent_resource, test_subsurface->parent_resource());
-
auxiliary_window->Hide();
-
- Sync();
-
- // The subsurface must take the focused window.
- second_window->SetPointerFocus(false);
- window_->SetPointerFocus(true);
- auxiliary_window->Show(false);
-
- Sync();
-
- // The subsurface is invalidated on each Hide call.
- test_subsurface = mock_surface_subsurface->sub_surface();
-
- // The |window_|'s resource must be the parent resource.
- EXPECT_EQ(parent_resource, test_subsurface->parent_resource());
-
window_->SetPointerFocus(false);
}
@@ -1850,6 +2100,7 @@ TEST_P(WaylandWindowTest, AuxiliaryWindowNestedParent) {
EXPECT_TRUE(menu_window);
VerifyAndClearExpectations();
+ menu_window->SetPointerFocus(true);
gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
std::unique_ptr<WaylandWindow> auxiliary_window =
@@ -1860,8 +2111,6 @@ TEST_P(WaylandWindowTest, AuxiliaryWindowNestedParent) {
VerifyAndClearExpectations();
- menu_window->SetPointerFocus(true);
-
auxiliary_window->Show(false);
Sync();
@@ -1873,6 +2122,8 @@ TEST_P(WaylandWindowTest, AuxiliaryWindowNestedParent) {
auto new_origin = subsurface_bounds.origin() -
menu_window_bounds.origin().OffsetFromOrigin();
EXPECT_EQ(test_subsurface->position(), new_origin);
+ EXPECT_EQ(mock_surface_subsurface->opaque_region(),
+ gfx::Rect(subsurface_bounds.size()));
menu_window->SetPointerFocus(false);
}
@@ -1969,7 +2220,7 @@ TEST_P(WaylandWindowTest, RemovesReattachesBackgroundOnHideShow) {
EXPECT_TRUE(connection_->buffer_manager_host());
auto interface_ptr = connection_->buffer_manager_host()->BindInterface();
- buffer_manager_gpu_->Initialize(std::move(interface_ptr), {}, false);
+ buffer_manager_gpu_->Initialize(std::move(interface_ptr), {}, false, false);
// Setup wl_buffers.
constexpr uint32_t buffer_id1 = 1;
@@ -2078,8 +2329,12 @@ TEST_P(WaylandWindowTest, SetsPropertiesOnShow) {
// Now, propagate size constraints and title.
base::Optional<gfx::Size> min_size(gfx::Size(1, 1));
base::Optional<gfx::Size> max_size(gfx::Size(100, 100));
- EXPECT_CALL(delegate, GetMinimumSizeForWindow()).WillOnce(Return(min_size));
- EXPECT_CALL(delegate, GetMaximumSizeForWindow()).WillOnce(Return(max_size));
+ EXPECT_CALL(delegate, GetMinimumSizeForWindow())
+ .Times(2)
+ .WillRepeatedly(Return(min_size));
+ EXPECT_CALL(delegate, GetMaximumSizeForWindow())
+ .Times(2)
+ .WillRepeatedly(Return(max_size));
EXPECT_CALL(*mock_xdg_toplevel,
SetMinSize(min_size.value().width(), min_size.value().height()));
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
index 518a1a7cce6..2f926a008a2 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
@@ -21,12 +21,17 @@ WaylandZAuraShell::WaylandZAuraShell(zaura_shell* aura_shell,
static const zaura_shell_listener zaura_shell_listener = {
&WaylandZAuraShell::OnLayoutMode,
+ &WaylandZAuraShell::OnBugFix,
};
zaura_shell_add_listener(obj_.get(), &zaura_shell_listener, this);
}
WaylandZAuraShell::~WaylandZAuraShell() = default;
+bool WaylandZAuraShell::HasBugFix(uint32_t id) {
+ return bug_fix_ids_.find(id) != bug_fix_ids_.end();
+}
+
// static
void WaylandZAuraShell::OnLayoutMode(void* data,
struct zaura_shell* zaura_shell,
@@ -47,4 +52,12 @@ void WaylandZAuraShell::OnLayoutMode(void* data,
}
}
+// static
+void WaylandZAuraShell::OnBugFix(void* data,
+ struct zaura_shell* zaura_shell,
+ uint32_t id) {
+ auto* self = static_cast<WaylandZAuraShell*>(data);
+ self->bug_fix_ids_.insert(id);
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h
index 3057ff66ce8..9c0e8251b1b 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h
@@ -5,6 +5,9 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZAURA_SHELL_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZAURA_SHELL_H_
+#include <string>
+
+#include "base/containers/flat_set.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
namespace ui {
@@ -20,15 +23,24 @@ class WaylandZAuraShell {
~WaylandZAuraShell();
zaura_shell* wl_object() const { return obj_.get(); }
+ // Due to version skew between Lacros and Ash, there may be certain bug
+ // fixes in one but not in the other (crbug.com/1151508). Lacros can use
+ // |HasBugFix| to provide a temporary workaround to an exo bug until Ash
+ // uprevs and starts reporting that a given bug ID has been fixed.
+ bool HasBugFix(uint32_t id);
private:
- // zaura_shell_listener
+ // zaura_shell_listeners
static void OnLayoutMode(void* data,
struct zaura_shell* zaura_shell,
uint32_t layout_mode);
+ static void OnBugFix(void* data,
+ struct zaura_shell* zaura_shell,
+ uint32_t id);
wl::Object<zaura_shell> obj_;
WaylandConnection* const connection_;
+ base::flat_set<uint32_t> bug_fix_ids_;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc
new file mode 100644
index 00000000000..a8bba1eb24d
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc
@@ -0,0 +1,53 @@
+// Copyright 2020 The Chromium 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 <aura-shell-server-protocol.h>
+
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_zaura_shell.h"
+#include "ui/ozone/platform/wayland/test/global_object.h"
+#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
+
+namespace ui {
+
+namespace {
+
+constexpr uint32_t kXdgVersionStable = 7;
+constexpr uint32_t kZAuraShellVersion = 14;
+
+} // namespace
+
+TEST(WaylandZauraShellTest, Foo) {
+ base::test::SingleThreadTaskEnvironment task_environment(
+ base::test::SingleThreadTaskEnvironment::MainThreadType::UI);
+ wl::TestWaylandServerThread server;
+ ASSERT_TRUE(server.Start(kXdgVersionStable));
+ wl::GlobalObject zaura_shell_obj(
+ &zaura_shell_interface, nullptr /* implementation */, kZAuraShellVersion);
+ zaura_shell_obj.Initialize(server.display());
+
+ WaylandConnection connection;
+ ASSERT_TRUE(connection.Initialize());
+ connection.event_source()->StartProcessingEvents();
+
+ base::RunLoop().RunUntilIdle();
+ server.Pause();
+
+ zaura_shell_send_bug_fix(zaura_shell_obj.resource(), 1);
+ zaura_shell_send_bug_fix(zaura_shell_obj.resource(), 3);
+
+ server.Resume();
+ base::RunLoop().RunUntilIdle();
+ server.Pause();
+
+ ASSERT_TRUE(connection.zaura_shell()->HasBugFix(1));
+ ASSERT_TRUE(connection.zaura_shell()->HasBugFix(3));
+ ASSERT_FALSE(connection.zaura_shell()->HasBugFix(2));
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
index cee4e46e6c1..c43f6c212fd 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
@@ -17,17 +17,17 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
-#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
#include "ui/ozone/platform/wayland/host/wayland_popup.h"
#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h"
namespace ui {
namespace {
-uint32_t TranslateAnchorStable(WlAnchor anchor) {
+uint32_t TranslateAnchor(WlAnchor anchor) {
switch (anchor) {
case WlAnchor::None:
return XDG_POSITIONER_ANCHOR_NONE;
@@ -50,7 +50,7 @@ uint32_t TranslateAnchorStable(WlAnchor anchor) {
}
}
-uint32_t TranslateGravityStable(WlGravity gravity) {
+uint32_t TranslateGravity(WlGravity gravity) {
switch (gravity) {
case WlGravity::None:
return XDG_POSITIONER_GRAVITY_NONE;
@@ -73,7 +73,7 @@ uint32_t TranslateGravityStable(WlGravity gravity) {
}
}
-uint32_t TranslateContraintAdjustmentStable(
+uint32_t TranslateContraintAdjustment(
WlConstraintAdjustment constraint_adjustment) {
uint32_t res = 0;
if ((constraint_adjustment & WlConstraintAdjustment::SlideX) !=
@@ -97,175 +97,14 @@ uint32_t TranslateContraintAdjustmentStable(
return res;
}
-uint32_t TranslateAnchorV6(WlAnchor anchor) {
- switch (anchor) {
- case WlAnchor::None:
- return ZXDG_POSITIONER_V6_ANCHOR_NONE;
- case WlAnchor::Top:
- return ZXDG_POSITIONER_V6_ANCHOR_TOP;
- case WlAnchor::Bottom:
- return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
- case WlAnchor::Left:
- return ZXDG_POSITIONER_V6_ANCHOR_LEFT;
- case WlAnchor::Right:
- return ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
- case WlAnchor::TopLeft:
- return ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_LEFT;
- case WlAnchor::BottomLeft:
- return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_LEFT;
- case WlAnchor::TopRight:
- return ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
- case WlAnchor::BottomRight:
- return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
- }
-}
-
-uint32_t TranslateGravityV6(WlGravity gravity) {
- switch (gravity) {
- case WlGravity::None:
- return ZXDG_POSITIONER_V6_GRAVITY_NONE;
- case WlGravity::Top:
- return ZXDG_POSITIONER_V6_GRAVITY_TOP;
- case WlGravity::Bottom:
- return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
- case WlGravity::Left:
- return ZXDG_POSITIONER_V6_GRAVITY_LEFT;
- case WlGravity::Right:
- return ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
- case WlGravity::TopLeft:
- return ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_LEFT;
- case WlGravity::BottomLeft:
- return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
- ZXDG_POSITIONER_V6_GRAVITY_LEFT;
- case WlGravity::TopRight:
- return ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
- case WlGravity::BottomRight:
- return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
- ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
- }
-}
-
-uint32_t TranslateContraintAdjustmentV6(
- WlConstraintAdjustment constraint_adjustment) {
- uint32_t res = 0;
- if ((constraint_adjustment & WlConstraintAdjustment::SlideX) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X;
- if ((constraint_adjustment & WlConstraintAdjustment::SlideY) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
- if ((constraint_adjustment & WlConstraintAdjustment::FlipX) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X;
- if ((constraint_adjustment & WlConstraintAdjustment::FlipY) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y;
- if ((constraint_adjustment & WlConstraintAdjustment::ResizeX) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X;
- if ((constraint_adjustment & WlConstraintAdjustment::ResizeY) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
- return res;
-}
-
-uint32_t GetAnchor(MenuType menu_type, const gfx::Rect& bounds, bool stable) {
- WlAnchor anchor = WlAnchor::None;
- switch (menu_type) {
- case MenuType::TYPE_RIGHT_CLICK:
- anchor = WlAnchor::TopLeft;
- break;
- case MenuType::TYPE_3DOT_PARENT_MENU:
- anchor = WlAnchor::BottomRight;
- break;
- case MenuType::TYPE_3DOT_CHILD_MENU:
- // Chromium may want to manually position a child menu on the left side of
- // its parent menu. Thus, react accordingly. Positive x means the child is
- // located on the right side of the parent and negative - on the left
- // side.
- if (bounds.x() >= 0)
- anchor = WlAnchor::TopRight;
- else
- anchor = WlAnchor::TopLeft;
- break;
- case MenuType::TYPE_UNKNOWN:
- NOTREACHED() << "Unsupported menu type";
- break;
- }
-
- if (stable)
- return TranslateAnchorStable(anchor);
- else {
- return TranslateAnchorV6(anchor);
- }
-}
-
-uint32_t GetGravity(MenuType menu_type, const gfx::Rect& bounds, bool stable) {
- WlGravity gravity = WlGravity::None;
- switch (menu_type) {
- case MenuType::TYPE_RIGHT_CLICK:
- gravity = WlGravity::BottomRight;
- break;
- case MenuType::TYPE_3DOT_PARENT_MENU:
- gravity = WlGravity::BottomRight;
- break;
- case MenuType::TYPE_3DOT_CHILD_MENU:
- // Chromium may want to manually position a child menu on the left side of
- // its parent menu. Thus, react accordingly. Positive x means the child is
- // located on the right side of the parent and negative - on the left
- // side.
- if (bounds.x() >= 0)
- gravity = WlGravity::BottomRight;
- else
- gravity = WlGravity::BottomLeft;
- break;
- case MenuType::TYPE_UNKNOWN:
- NOTREACHED() << "Unsupported menu type";
- break;
- }
-
- if (stable)
- return TranslateGravityStable(gravity);
- else {
- return TranslateGravityV6(gravity);
- }
-}
-
-uint32_t GetConstraintAdjustment(MenuType menu_type, bool stable) {
- WlConstraintAdjustment constraint = WlConstraintAdjustment::None;
-
- switch (menu_type) {
- case MenuType::TYPE_RIGHT_CLICK:
- constraint = WlConstraintAdjustment::SlideX |
- WlConstraintAdjustment::SlideY |
- WlConstraintAdjustment::FlipY;
- break;
- case MenuType::TYPE_3DOT_PARENT_MENU:
- constraint =
- WlConstraintAdjustment::SlideX | WlConstraintAdjustment::FlipY;
- break;
- case MenuType::TYPE_3DOT_CHILD_MENU:
- constraint =
- WlConstraintAdjustment::SlideY | WlConstraintAdjustment::FlipX;
- break;
- case MenuType::TYPE_UNKNOWN:
- NOTREACHED() << "Unsupported menu type";
- break;
- }
- if (stable)
- return TranslateContraintAdjustmentStable(constraint);
- else {
- return TranslateContraintAdjustmentV6(constraint);
- }
-}
-
} // namespace
XDGPopupWrapperImpl::XDGPopupWrapperImpl(
std::unique_ptr<XDGSurfaceWrapperImpl> surface,
WaylandWindow* wayland_window)
- : wayland_window_(wayland_window), xdg_surface_(std::move(surface)) {
- DCHECK(xdg_surface_);
+ : wayland_window_(wayland_window),
+ xdg_surface_wrapper_(std::move(surface)) {
+ DCHECK(xdg_surface_wrapper_);
DCHECK(wayland_window_ && wayland_window_->parent_window());
}
@@ -286,15 +125,16 @@ bool XDGPopupWrapperImpl::Initialize(WaylandConnection* connection,
static_cast<WaylandPopup*>(wayland_window_->parent_window());
XDGPopupWrapperImpl* popup =
static_cast<XDGPopupWrapperImpl*>(wayland_popup->shell_popup());
- parent_xdg_surface = popup->xdg_surface();
+ parent_xdg_surface = popup->xdg_surface_wrapper();
} else {
WaylandToplevelWindow* wayland_surface =
static_cast<WaylandToplevelWindow*>(wayland_window_->parent_window());
parent_xdg_surface =
- static_cast<XDGSurfaceWrapperImpl*>(wayland_surface->shell_surface());
+ static_cast<XDGToplevelWrapperImpl*>(wayland_surface->shell_toplevel())
+ ->xdg_surface_wrapper();
}
- if (!xdg_surface_ || !parent_xdg_surface)
+ if (!xdg_surface_wrapper_ || !parent_xdg_surface)
return false;
auto new_bounds = bounds;
@@ -306,8 +146,6 @@ bool XDGPopupWrapperImpl::Initialize(WaylandConnection* connection,
if (connection->shell())
return InitializeStable(connection, new_bounds, parent_xdg_surface);
- else if (connection->shell_v6())
- return InitializeV6(connection, new_bounds, parent_xdg_surface);
return false;
}
@@ -316,16 +154,16 @@ bool XDGPopupWrapperImpl::InitializeStable(
const gfx::Rect& bounds,
XDGSurfaceWrapperImpl* parent_xdg_surface) {
static const struct xdg_popup_listener xdg_popup_listener = {
- &XDGPopupWrapperImpl::ConfigureStable,
- &XDGPopupWrapperImpl::PopupDoneStable,
+ &XDGPopupWrapperImpl::Configure,
+ &XDGPopupWrapperImpl::PopupDone,
};
- struct xdg_positioner* positioner = CreatePositionerStable(
- connection, wayland_window_->parent_window(), bounds);
+ struct xdg_positioner* positioner =
+ CreatePositioner(connection, wayland_window_->parent_window(), bounds);
if (!positioner)
return false;
- xdg_popup_.reset(xdg_surface_get_popup(xdg_surface_->xdg_surface(),
+ xdg_popup_.reset(xdg_surface_get_popup(xdg_surface_wrapper_->xdg_surface(),
parent_xdg_surface->xdg_surface(),
positioner));
if (!xdg_popup_)
@@ -342,7 +180,12 @@ bool XDGPopupWrapperImpl::InitializeStable(
return true;
}
-struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable(
+void XDGPopupWrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(xdg_surface_wrapper_);
+ xdg_surface_wrapper_->AckConfigure(serial);
+}
+
+struct xdg_positioner* XDGPopupWrapperImpl::CreatePositioner(
WaylandConnection* connection,
WaylandWindow* parent_window,
const gfx::Rect& bounds) {
@@ -366,115 +209,19 @@ struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable(
xdg_positioner_set_anchor_rect(positioner, anchor_rect.x(), anchor_rect.y(),
anchor_rect.width(), anchor_rect.height());
xdg_positioner_set_size(positioner, bounds.width(), bounds.height());
- xdg_positioner_set_anchor(positioner, GetAnchor(menu_type, bounds, true));
- xdg_positioner_set_gravity(positioner, GetGravity(menu_type, bounds, true));
+ xdg_positioner_set_anchor(positioner,
+ TranslateAnchor(GetAnchor(menu_type, bounds)));
+ xdg_positioner_set_gravity(positioner,
+ TranslateGravity(GetGravity(menu_type, bounds)));
xdg_positioner_set_constraint_adjustment(
- positioner, GetConstraintAdjustment(menu_type, true));
+ positioner,
+ TranslateContraintAdjustment(GetConstraintAdjustment(menu_type)));
return positioner;
}
-bool XDGPopupWrapperImpl::InitializeV6(
- WaylandConnection* connection,
- const gfx::Rect& bounds,
- XDGSurfaceWrapperImpl* parent_xdg_surface) {
- static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = {
- &XDGPopupWrapperImpl::ConfigureV6,
- &XDGPopupWrapperImpl::PopupDoneV6,
- };
-
- zxdg_positioner_v6* positioner =
- CreatePositionerV6(connection, wayland_window_->parent_window(), bounds);
- if (!positioner)
- return false;
-
- zxdg_popup_v6_.reset(zxdg_surface_v6_get_popup(
- xdg_surface_->zxdg_surface(), parent_xdg_surface->zxdg_surface(),
- positioner));
- if (!zxdg_popup_v6_)
- return false;
-
- zxdg_positioner_v6_destroy(positioner);
-
- if (CanGrabPopup(connection)) {
- zxdg_popup_v6_grab(zxdg_popup_v6_.get(), connection->seat(),
- connection->serial());
- }
- zxdg_popup_v6_add_listener(zxdg_popup_v6_.get(), &zxdg_popup_v6_listener,
- this);
-
- wayland_window_->root_surface()->Commit();
- return true;
-}
-
-zxdg_positioner_v6* XDGPopupWrapperImpl::CreatePositionerV6(
- WaylandConnection* connection,
- WaylandWindow* parent_window,
- const gfx::Rect& bounds) {
- struct zxdg_positioner_v6* positioner;
- positioner = zxdg_shell_v6_create_positioner(connection->shell_v6());
- if (!positioner)
- return nullptr;
-
- auto menu_type = GetMenuTypeForPositioner(connection, parent_window);
-
- // The parent we got must be the topmost in the stack of the same family
- // windows.
- DCHECK_EQ(parent_window->GetTopMostChildWindow(), parent_window);
-
- // Place anchor to the end of the possible position.
- gfx::Rect anchor_rect = GetAnchorRect(
- menu_type, bounds,
- gfx::ScaleToRoundedRect(parent_window->GetBounds(),
- 1.0 / parent_window->buffer_scale()));
-
- zxdg_positioner_v6_set_anchor_rect(positioner, anchor_rect.x(),
- anchor_rect.y(), anchor_rect.width(),
- anchor_rect.height());
- zxdg_positioner_v6_set_size(positioner, bounds.width(), bounds.height());
- zxdg_positioner_v6_set_anchor(positioner,
- GetAnchor(menu_type, bounds, false));
- zxdg_positioner_v6_set_gravity(positioner,
- GetGravity(menu_type, bounds, false));
- zxdg_positioner_v6_set_constraint_adjustment(
- positioner, GetConstraintAdjustment(menu_type, false));
- return positioner;
-}
-
-MenuType XDGPopupWrapperImpl::GetMenuTypeForPositioner(
- WaylandConnection* connection,
- WaylandWindow* parent_window) const {
- bool is_right_click_menu =
- connection->event_source()->last_pointer_button_pressed() &
- EF_RIGHT_MOUSE_BUTTON;
-
- // Different types of menu require different anchors, constraint adjustments,
- // gravity and etc.
- if (is_right_click_menu)
- return MenuType::TYPE_RIGHT_CLICK;
- else if (!wl::IsMenuType(parent_window->type()))
- return MenuType::TYPE_3DOT_PARENT_MENU;
- else
- return MenuType::TYPE_3DOT_CHILD_MENU;
-}
-
-bool XDGPopupWrapperImpl::CanGrabPopup(WaylandConnection* connection) const {
- // When drag process starts, as described the protocol -
- // https://goo.gl/1Mskq3, the client must have an active implicit grab. If
- // we try to create a popup and grab it, it will be immediately dismissed.
- // Thus, do not take explicit grab during drag process.
- if (connection->IsDragInProgress() || !connection->seat())
- return false;
-
- // According to the definition of the xdg protocol, the grab request must be
- // used in response to some sort of user action like a button press, key
- // press, or touch down event.
- EventType last_event_type = connection->event_serial().event_type;
- return last_event_type == ET_TOUCH_PRESSED ||
- last_event_type == ET_KEY_PRESSED ||
- last_event_type == ET_MOUSE_PRESSED;
-}
-
+// static
void XDGPopupWrapperImpl::Configure(void* data,
+ struct xdg_popup* xdg_popup,
int32_t x,
int32_t y,
int32_t width,
@@ -492,7 +239,7 @@ void XDGPopupWrapperImpl::Configure(void* data,
}
// static
-void XDGPopupWrapperImpl::PopupDone(void* data) {
+void XDGPopupWrapperImpl::PopupDone(void* data, struct xdg_popup* xdg_popup) {
WaylandWindow* window =
static_cast<XDGPopupWrapperImpl*>(data)->wayland_window_;
DCHECK(window);
@@ -500,41 +247,9 @@ void XDGPopupWrapperImpl::PopupDone(void* data) {
window->OnCloseRequest();
}
-// static
-void XDGPopupWrapperImpl::ConfigureStable(void* data,
- struct xdg_popup* xdg_popup,
- int32_t x,
- int32_t y,
- int32_t width,
- int32_t height) {
- Configure(data, x, y, width, height);
-}
-
-// static
-void XDGPopupWrapperImpl::PopupDoneStable(void* data,
- struct xdg_popup* xdg_popup) {
- PopupDone(data);
-}
-
-// static
-void XDGPopupWrapperImpl::ConfigureV6(void* data,
- struct zxdg_popup_v6* zxdg_popup_v6,
- int32_t x,
- int32_t y,
- int32_t width,
- int32_t height) {
- Configure(data, x, y, width, height);
-}
-
-// static
-void XDGPopupWrapperImpl::PopupDoneV6(void* data,
- struct zxdg_popup_v6* zxdg_popup_v6) {
- PopupDone(data);
-}
-
-XDGSurfaceWrapperImpl* XDGPopupWrapperImpl::xdg_surface() {
- DCHECK(xdg_surface_.get());
- return xdg_surface_.get();
+XDGSurfaceWrapperImpl* XDGPopupWrapperImpl::xdg_surface_wrapper() const {
+ DCHECK(xdg_surface_wrapper_.get());
+ return xdg_surface_wrapper_.get();
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
index 62f38a2dc6a..0ffd6674836 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
@@ -16,7 +16,7 @@ class XDGSurfaceWrapperImpl;
class WaylandConnection;
class WaylandWindow;
-// Popup wrapper for xdg-shell stable and xdg-shell-unstable-v6
+// Popup wrapper for xdg-shell stable
class XDGPopupWrapperImpl : public ShellPopupWrapper {
public:
XDGPopupWrapperImpl(std::unique_ptr<XDGSurfaceWrapperImpl> surface,
@@ -26,61 +26,35 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper {
// XDGPopupWrapper:
bool Initialize(WaylandConnection* connection,
const gfx::Rect& bounds) override;
+ void AckConfigure(uint32_t serial) override;
private:
bool InitializeStable(WaylandConnection* connection,
const gfx::Rect& bounds,
- XDGSurfaceWrapperImpl* parent_xdg_surface);
- struct xdg_positioner* CreatePositionerStable(WaylandConnection* connection,
- WaylandWindow* parent_window,
- const gfx::Rect& bounds);
-
- bool InitializeV6(WaylandConnection* connection,
- const gfx::Rect& bounds,
- XDGSurfaceWrapperImpl* parent_xdg_surface);
- struct zxdg_positioner_v6* CreatePositionerV6(WaylandConnection* connection,
- WaylandWindow* parent_window,
- const gfx::Rect& bounds);
-
- MenuType GetMenuTypeForPositioner(WaylandConnection* connection,
- WaylandWindow* parent_window) const;
-
- bool CanGrabPopup(WaylandConnection* connection) const;
+ XDGSurfaceWrapperImpl* parent_xdg_surface_wrapper);
+ struct xdg_positioner* CreatePositioner(WaylandConnection* connection,
+ WaylandWindow* parent_window,
+ const gfx::Rect& bounds);
// xdg_popup_listener
static void Configure(void* data,
- int32_t x,
- int32_t y,
- int32_t width,
- int32_t height);
- static void ConfigureStable(void* data,
struct xdg_popup* xdg_popup,
int32_t x,
int32_t y,
int32_t width,
int32_t height);
- static void ConfigureV6(void* data,
- struct zxdg_popup_v6* zxdg_popup_v6,
- int32_t x,
- int32_t y,
- int32_t width,
- int32_t height);
- static void PopupDone(void* data);
- static void PopupDoneStable(void* data, struct xdg_popup* xdg_popup);
- static void PopupDoneV6(void* data, struct zxdg_popup_v6* zxdg_popup_v6);
-
- XDGSurfaceWrapperImpl* xdg_surface();
+ static void PopupDone(void* data, struct xdg_popup* xdg_popup);
+
+ XDGSurfaceWrapperImpl* xdg_surface_wrapper() const;
// Non-owned WaylandWindow that uses this popup.
WaylandWindow* const wayland_window_;
// Ground surface for this popup.
- std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface_;
+ std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface_wrapper_;
// XDG Shell Stable object.
wl::Object<xdg_popup> xdg_popup_;
- // XDG Shell V6 object.
- wl::Object<zxdg_popup_v6> zxdg_popup_v6_;
DISALLOW_COPY_AND_ASSIGN(XDGPopupWrapperImpl);
};
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
index 6ee18c65b7e..852573ae6fc 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
@@ -4,13 +4,8 @@
#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
-#include <xdg-decoration-unstable-v1-client-protocol.h>
#include <xdg-shell-client-protocol.h>
-#include <xdg-shell-unstable-v6-client-protocol.h>
-#include "base/strings/utf_string_conversions.h"
-#include "ui/base/hit_test.h"
-#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
@@ -20,244 +15,51 @@ XDGSurfaceWrapperImpl::XDGSurfaceWrapperImpl(WaylandWindow* wayland_window,
WaylandConnection* connection)
: wayland_window_(wayland_window), connection_(connection) {}
-XDGSurfaceWrapperImpl::~XDGSurfaceWrapperImpl() {}
+XDGSurfaceWrapperImpl::~XDGSurfaceWrapperImpl() = default;
-bool XDGSurfaceWrapperImpl::Initialize(bool with_toplevel) {
- if (connection_->shell())
- return InitializeStable(with_toplevel);
- else if (connection_->shell_v6())
- return InitializeV6(with_toplevel);
- NOTREACHED() << "Wrong shell protocol";
- return false;
-}
-
-void XDGSurfaceWrapperImpl::SetMaximized() {
- if (xdg_toplevel_) {
- xdg_toplevel_set_maximized(xdg_toplevel_.get());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_maximized(zxdg_toplevel_v6_.get());
- }
-}
-
-void XDGSurfaceWrapperImpl::UnSetMaximized() {
- if (xdg_toplevel_) {
- xdg_toplevel_unset_maximized(xdg_toplevel_.get());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_unset_maximized(zxdg_toplevel_v6_.get());
- }
-}
-
-void XDGSurfaceWrapperImpl::SetFullscreen() {
- if (xdg_toplevel_) {
- xdg_toplevel_set_fullscreen(xdg_toplevel_.get(), nullptr);
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_fullscreen(zxdg_toplevel_v6_.get(), nullptr);
- }
-}
-
-void XDGSurfaceWrapperImpl::UnSetFullscreen() {
- if (xdg_toplevel_) {
- xdg_toplevel_unset_fullscreen(xdg_toplevel_.get());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_unset_fullscreen(zxdg_toplevel_v6_.get());
- }
-}
-
-void XDGSurfaceWrapperImpl::SetMinimized() {
- if (xdg_toplevel_) {
- xdg_toplevel_set_minimized(xdg_toplevel_.get());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_minimized(zxdg_toplevel_v6_.get());
+bool XDGSurfaceWrapperImpl::Initialize() {
+ if (!connection_->shell()) {
+ NOTREACHED() << "Wrong shell protocol";
+ return false;
}
-}
-void XDGSurfaceWrapperImpl::SurfaceMove(WaylandConnection* connection) {
- if (xdg_toplevel_) {
- xdg_toplevel_move(xdg_toplevel_.get(), connection_->seat(),
- connection_->serial());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_move(zxdg_toplevel_v6_.get(), connection_->seat(),
- connection_->serial());
- }
-}
+ static const xdg_surface_listener xdg_surface_listener = {
+ &XDGSurfaceWrapperImpl::Configure,
+ };
-void XDGSurfaceWrapperImpl::SurfaceResize(WaylandConnection* connection,
- uint32_t hittest) {
- if (xdg_toplevel_) {
- xdg_toplevel_resize(xdg_toplevel_.get(), connection_->seat(),
- connection_->serial(),
- wl::IdentifyDirection(*connection, hittest));
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_resize(zxdg_toplevel_v6_.get(), connection_->seat(),
- connection_->serial(),
- wl::IdentifyDirection(*connection, hittest));
+ xdg_surface_.reset(xdg_wm_base_get_xdg_surface(
+ connection_->shell(), wayland_window_->root_surface()->surface()));
+ if (!xdg_surface_) {
+ LOG(ERROR) << "Failed to create xdg_surface";
+ return false;
}
-}
-void XDGSurfaceWrapperImpl::SetTitle(const base::string16& title) {
- if (xdg_toplevel_) {
- xdg_toplevel_set_title(xdg_toplevel_.get(),
- base::UTF16ToUTF8(title).c_str());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_title(zxdg_toplevel_v6_.get(),
- base::UTF16ToUTF8(title).c_str());
- }
+ xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this);
+ connection_->ScheduleFlush();
+ return true;
}
-void XDGSurfaceWrapperImpl::AckConfigure() {
- if (xdg_surface_) {
- xdg_surface_ack_configure(xdg_surface_.get(), pending_configure_serial_);
- } else {
- DCHECK(zxdg_surface_v6_);
- zxdg_surface_v6_ack_configure(zxdg_surface_v6_.get(),
- pending_configure_serial_);
- }
+void XDGSurfaceWrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(xdg_surface_);
+ xdg_surface_ack_configure(xdg_surface_.get(), serial);
connection_->wayland_window_manager()->NotifyWindowConfigured(
wayland_window_);
}
void XDGSurfaceWrapperImpl::SetWindowGeometry(const gfx::Rect& bounds) {
- if (xdg_surface_) {
- xdg_surface_set_window_geometry(xdg_surface_.get(), bounds.x(), bounds.y(),
- bounds.width(), bounds.height());
- } else {
- DCHECK(zxdg_surface_v6_);
- zxdg_surface_v6_set_window_geometry(zxdg_surface_v6_.get(), bounds.x(),
- bounds.y(), bounds.width(),
- bounds.height());
- }
-}
-
-void XDGSurfaceWrapperImpl::SetMinSize(int32_t width, int32_t height) {
- if (xdg_toplevel_) {
- xdg_toplevel_set_min_size(xdg_toplevel_.get(), width, height);
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_min_size(zxdg_toplevel_v6_.get(), width, height);
- }
-}
-
-void XDGSurfaceWrapperImpl::SetMaxSize(int32_t width, int32_t height) {
- if (xdg_toplevel_) {
- xdg_toplevel_set_max_size(xdg_toplevel_.get(), width, height);
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_max_size(zxdg_toplevel_v6_.get(), width, height);
- }
-}
-
-void XDGSurfaceWrapperImpl::SetAppId(const std::string& app_id) {
- if (xdg_toplevel_) {
- xdg_toplevel_set_app_id(xdg_toplevel_.get(), app_id.c_str());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_app_id(zxdg_toplevel_v6_.get(), app_id.c_str());
- }
-}
-
-// static
-void XDGSurfaceWrapperImpl::ConfigureStable(void* data,
- struct xdg_surface* xdg_surface,
- uint32_t serial) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
- surface->pending_configure_serial_ = serial;
-
- surface->AckConfigure();
-}
-
-// static
-void XDGSurfaceWrapperImpl::ConfigureTopLevelStable(
- void* data,
- struct xdg_toplevel* xdg_toplevel,
- int32_t width,
- int32_t height,
- struct wl_array* states) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
-
- bool is_maximized =
- CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_MAXIMIZED);
- bool is_fullscreen =
- CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_FULLSCREEN);
- bool is_activated =
- CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_ACTIVATED);
-
- surface->wayland_window_->HandleSurfaceConfigure(width, height, is_maximized,
- is_fullscreen, is_activated);
-}
-
-// static
-void XDGSurfaceWrapperImpl::CloseTopLevelStable(
- void* data,
- struct xdg_toplevel* xdg_toplevel) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
- surface->wayland_window_->OnCloseRequest();
-}
-
-void XDGSurfaceWrapperImpl::SetTopLevelDecorationMode(
- zxdg_toplevel_decoration_v1_mode requested_mode) {
- if (requested_mode == decoration_mode_)
- return;
-
- decoration_mode_ = requested_mode;
- zxdg_toplevel_decoration_v1_set_mode(zxdg_toplevel_decoration_.get(),
- requested_mode);
-}
-
-// static
-void XDGSurfaceWrapperImpl::ConfigureV6(void* data,
- struct zxdg_surface_v6* zxdg_surface_v6,
- uint32_t serial) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
- surface->pending_configure_serial_ = serial;
-
- surface->AckConfigure();
-}
-
-// static
-void XDGSurfaceWrapperImpl::ConfigureTopLevelV6(
- void* data,
- struct zxdg_toplevel_v6* zxdg_toplevel_v6,
- int32_t width,
- int32_t height,
- struct wl_array* states) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
-
- bool is_maximized =
- CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED);
- bool is_fullscreen =
- CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN);
- bool is_activated =
- CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_ACTIVATED);
-
- surface->wayland_window_->HandleSurfaceConfigure(width, height, is_maximized,
- is_fullscreen, is_activated);
+ DCHECK(xdg_surface_);
+ xdg_surface_set_window_geometry(xdg_surface_.get(), bounds.x(), bounds.y(),
+ bounds.width(), bounds.height());
}
// static
-void XDGSurfaceWrapperImpl::CloseTopLevelV6(
- void* data,
- struct zxdg_toplevel_v6* zxdg_toplevel_v6) {
+void XDGSurfaceWrapperImpl::Configure(void* data,
+ struct xdg_surface* xdg_surface,
+ uint32_t serial) {
auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
DCHECK(surface);
- surface->wayland_window_->OnCloseRequest();
-}
-zxdg_surface_v6* XDGSurfaceWrapperImpl::zxdg_surface() const {
- DCHECK(zxdg_surface_v6_);
- return zxdg_surface_v6_.get();
+ surface->wayland_window_->HandleSurfaceConfigure(serial);
}
xdg_surface* XDGSurfaceWrapperImpl::xdg_surface() const {
@@ -265,112 +67,4 @@ xdg_surface* XDGSurfaceWrapperImpl::xdg_surface() const {
return xdg_surface_.get();
}
-// static
-void XDGSurfaceWrapperImpl::ConfigureDecoration(
- void* data,
- struct zxdg_toplevel_decoration_v1* decoration,
- uint32_t mode) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
- surface->SetTopLevelDecorationMode(
- static_cast<zxdg_toplevel_decoration_v1_mode>(mode));
-}
-
-bool XDGSurfaceWrapperImpl::InitializeStable(bool with_toplevel) {
- static const xdg_surface_listener xdg_surface_listener = {
- &XDGSurfaceWrapperImpl::ConfigureStable,
- };
- static const xdg_toplevel_listener xdg_toplevel_listener = {
- &XDGSurfaceWrapperImpl::ConfigureTopLevelStable,
- &XDGSurfaceWrapperImpl::CloseTopLevelStable,
- };
-
- // if this surface is created for the popup role, mark that it requires
- // configuration acknowledgement on each configure event.
- surface_for_popup_ = !with_toplevel;
-
- xdg_surface_.reset(xdg_wm_base_get_xdg_surface(
- connection_->shell(), wayland_window_->root_surface()->surface()));
- if (!xdg_surface_) {
- LOG(ERROR) << "Failed to create xdg_surface";
- return false;
- }
- xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this);
- // XDGPopup requires a separate surface to be created, so this is just a
- // request to get an xdg_surface for it.
- if (surface_for_popup_) {
- connection_->ScheduleFlush();
- return true;
- }
-
- xdg_toplevel_.reset(xdg_surface_get_toplevel(xdg_surface_.get()));
- if (!xdg_toplevel_) {
- LOG(ERROR) << "Failed to create xdg_toplevel";
- return false;
- }
-
- xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this);
-
- InitializeXdgDecoration();
-
- wayland_window_->root_surface()->Commit();
- connection_->ScheduleFlush();
- return true;
-}
-
-bool XDGSurfaceWrapperImpl::InitializeV6(bool with_toplevel) {
- static const zxdg_surface_v6_listener zxdg_surface_v6_listener = {
- &XDGSurfaceWrapperImpl::ConfigureV6,
- };
- static const zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
- &XDGSurfaceWrapperImpl::ConfigureTopLevelV6,
- &XDGSurfaceWrapperImpl::CloseTopLevelV6,
- };
-
- // if this surface is created for the popup role, mark that it requires
- // configuration acknowledgement on each configure event.
- surface_for_popup_ = !with_toplevel;
-
- zxdg_surface_v6_.reset(zxdg_shell_v6_get_xdg_surface(
- connection_->shell_v6(), wayland_window_->root_surface()->surface()));
- if (!zxdg_surface_v6_) {
- LOG(ERROR) << "Failed to create zxdg_surface";
- return false;
- }
- zxdg_surface_v6_add_listener(zxdg_surface_v6_.get(),
- &zxdg_surface_v6_listener, this);
- // XDGPopupV6 requires a separate surface to be created, so this is just a
- // request to get an xdg_surface for it.
- if (surface_for_popup_) {
- connection_->ScheduleFlush();
- return true;
- }
-
- zxdg_toplevel_v6_.reset(zxdg_surface_v6_get_toplevel(zxdg_surface_v6_.get()));
- if (!zxdg_toplevel_v6_) {
- LOG(ERROR) << "Failed to create zxdg_toplevel";
- return false;
- }
- zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(),
- &zxdg_toplevel_v6_listener, this);
-
- wayland_window_->root_surface()->Commit();
- connection_->ScheduleFlush();
- return true;
-}
-
-void XDGSurfaceWrapperImpl::InitializeXdgDecoration() {
- if (connection_->xdg_decoration_manager_v1()) {
- DCHECK(!zxdg_toplevel_decoration_);
- static const zxdg_toplevel_decoration_v1_listener decoration_listener = {
- &XDGSurfaceWrapperImpl::ConfigureDecoration,
- };
- zxdg_toplevel_decoration_.reset(
- zxdg_decoration_manager_v1_get_toplevel_decoration(
- connection_->xdg_decoration_manager_v1(), xdg_toplevel_.get()));
- zxdg_toplevel_decoration_v1_add_listener(zxdg_toplevel_decoration_.get(),
- &decoration_listener, this);
- }
-}
-
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
index da945779a76..c88eccfba82 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
@@ -7,8 +7,6 @@
#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
-#include <xdg-decoration-unstable-v1-client-protocol.h>
-
#include <cstdint>
#include <string>
@@ -24,7 +22,7 @@ namespace ui {
class WaylandConnection;
class WaylandWindow;
-// Surface wrapper for xdg-shell stable and xdg-shell-unstable-v6
+// Surface wrapper for xdg-shell stable
class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper {
public:
XDGSurfaceWrapperImpl(WaylandWindow* wayland_window,
@@ -34,84 +32,23 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper {
~XDGSurfaceWrapperImpl() override;
// ShellSurfaceWrapper overrides:
- bool Initialize(bool with_toplevel) override;
- void SetMaximized() override;
- void UnSetMaximized() override;
- void SetFullscreen() override;
- void UnSetFullscreen() override;
- void SetMinimized() override;
- void SurfaceMove(WaylandConnection* connection) override;
- void SurfaceResize(WaylandConnection* connection, uint32_t hittest) override;
- void SetTitle(const base::string16& title) override;
- void AckConfigure() override;
+ bool Initialize() override;
+ void AckConfigure(uint32_t serial) override;
void SetWindowGeometry(const gfx::Rect& bounds) override;
- void SetMinSize(int32_t width, int32_t height) override;
- void SetMaxSize(int32_t width, int32_t height) override;
- void SetAppId(const std::string& app_id) override;
// xdg_surface_listener
- static void ConfigureV6(void* data,
- struct zxdg_surface_v6* zxdg_surface_v6,
- uint32_t serial);
- static void ConfigureTopLevelV6(void* data,
- struct zxdg_toplevel_v6* zxdg_toplevel_v6,
- int32_t width,
- int32_t height,
- struct wl_array* states);
-
- static void ConfigureStable(void* data,
- struct xdg_surface* xdg_surface,
- uint32_t serial);
- static void ConfigureTopLevelStable(void* data,
- struct xdg_toplevel* xdg_toplevel,
- int32_t width,
- int32_t height,
- struct wl_array* states);
-
- // xdg_toplevel_listener
- static void CloseTopLevelStable(void* data,
- struct xdg_toplevel* xdg_toplevel);
- static void CloseTopLevelV6(void* data,
- struct zxdg_toplevel_v6* zxdg_toplevel_v6);
-
- void SetTopLevelDecorationMode(
- zxdg_toplevel_decoration_v1_mode requested_mode);
- // zxdg_decoration_listener
- static void ConfigureDecoration(
- void* data,
- struct zxdg_toplevel_decoration_v1* decoration,
- uint32_t mode);
+ static void Configure(void* data,
+ struct xdg_surface* xdg_surface,
+ uint32_t serial);
struct xdg_surface* xdg_surface() const;
- zxdg_surface_v6* zxdg_surface() const;
private:
- // Initializes using XDG Shell Stable protocol.
- bool InitializeStable(bool with_toplevel);
- // Initializes using XDG Shell V6 protocol.
- bool InitializeV6(bool with_toplevel);
-
- // Initializes the xdg-decoration protocol extension, if available.
- void InitializeXdgDecoration();
-
// Non-owing WaylandWindow that uses this surface wrapper.
WaylandWindow* const wayland_window_;
WaylandConnection* const connection_;
- uint32_t pending_configure_serial_ = 0;
-
- wl::Object<zxdg_surface_v6> zxdg_surface_v6_;
- wl::Object<zxdg_toplevel_v6> zxdg_toplevel_v6_;
wl::Object<struct xdg_surface> xdg_surface_;
- wl::Object<xdg_toplevel> xdg_toplevel_;
- wl::Object<zxdg_toplevel_decoration_v1> zxdg_toplevel_decoration_;
-
- bool surface_for_popup_ = false;
-
- // Keeps track of the decoration mode currently in use if xdg-decoration
- // protocol extension is available, otherwise CLIENT_SIDE is assumed.
- enum zxdg_toplevel_decoration_v1_mode decoration_mode_ =
- ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc
new file mode 100644
index 00000000000..cd57c613a36
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc
@@ -0,0 +1,202 @@
+// Copyright 2021 The Chromium 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/wayland/host/xdg_toplevel_wrapper_impl.h"
+
+#include <xdg-decoration-unstable-v1-client-protocol.h>
+#include <xdg-shell-client-protocol.h>
+#include <xdg-shell-unstable-v6-client-protocol.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/hit_test.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
+
+namespace ui {
+
+XDGToplevelWrapperImpl::XDGToplevelWrapperImpl(
+ std::unique_ptr<XDGSurfaceWrapperImpl> surface,
+ WaylandWindow* wayland_window,
+ WaylandConnection* connection)
+ : xdg_surface_wrapper_(std::move(surface)),
+ wayland_window_(wayland_window),
+ connection_(connection),
+ decoration_mode_(DecorationMode::kClientSide) {}
+
+XDGToplevelWrapperImpl::~XDGToplevelWrapperImpl() = default;
+
+bool XDGToplevelWrapperImpl::Initialize() {
+ if (!connection_->shell()) {
+ NOTREACHED() << "Wrong shell protocol";
+ return false;
+ }
+
+ static const xdg_toplevel_listener xdg_toplevel_listener = {
+ &XDGToplevelWrapperImpl::ConfigureTopLevel,
+ &XDGToplevelWrapperImpl::CloseTopLevel,
+ };
+
+ if (!xdg_surface_wrapper_)
+ return false;
+
+ xdg_toplevel_.reset(
+ xdg_surface_get_toplevel(xdg_surface_wrapper_->xdg_surface()));
+ if (!xdg_toplevel_) {
+ LOG(ERROR) << "Failed to create xdg_toplevel";
+ return false;
+ }
+
+ xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this);
+
+ InitializeXdgDecoration();
+
+ wayland_window_->root_surface()->Commit();
+ connection_->ScheduleFlush();
+ return true;
+}
+
+void XDGToplevelWrapperImpl::SetMaximized() {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_maximized(xdg_toplevel_.get());
+}
+
+void XDGToplevelWrapperImpl::UnSetMaximized() {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_unset_maximized(xdg_toplevel_.get());
+}
+
+void XDGToplevelWrapperImpl::SetFullscreen() {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_fullscreen(xdg_toplevel_.get(), nullptr);
+}
+
+void XDGToplevelWrapperImpl::UnSetFullscreen() {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_unset_fullscreen(xdg_toplevel_.get());
+}
+
+void XDGToplevelWrapperImpl::SetMinimized() {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_minimized(xdg_toplevel_.get());
+}
+
+void XDGToplevelWrapperImpl::SurfaceMove(WaylandConnection* connection) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_move(xdg_toplevel_.get(), connection->seat(),
+ connection->serial());
+}
+
+void XDGToplevelWrapperImpl::SurfaceResize(WaylandConnection* connection,
+ uint32_t hittest) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_resize(xdg_toplevel_.get(), connection->seat(),
+ connection->serial(),
+ wl::IdentifyDirection(*connection, hittest));
+}
+
+void XDGToplevelWrapperImpl::SetTitle(const base::string16& title) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_title(xdg_toplevel_.get(), base::UTF16ToUTF8(title).c_str());
+}
+
+void XDGToplevelWrapperImpl::SetWindowGeometry(const gfx::Rect& bounds) {
+ xdg_surface_wrapper_->SetWindowGeometry(bounds);
+}
+
+void XDGToplevelWrapperImpl::SetMinSize(int32_t width, int32_t height) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_min_size(xdg_toplevel_.get(), width, height);
+}
+
+void XDGToplevelWrapperImpl::SetMaxSize(int32_t width, int32_t height) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_max_size(xdg_toplevel_.get(), width, height);
+}
+
+void XDGToplevelWrapperImpl::SetAppId(const std::string& app_id) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_app_id(xdg_toplevel_.get(), app_id.c_str());
+}
+
+void XDGToplevelWrapperImpl::SetDecoration(DecorationMode decoration) {
+ SetTopLevelDecorationMode(decoration);
+}
+
+void XDGToplevelWrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(xdg_surface_wrapper_);
+ xdg_surface_wrapper_->AckConfigure(serial);
+}
+
+// static
+void XDGToplevelWrapperImpl::ConfigureTopLevel(
+ void* data,
+ struct xdg_toplevel* xdg_toplevel,
+ int32_t width,
+ int32_t height,
+ struct wl_array* states) {
+ auto* surface = static_cast<XDGToplevelWrapperImpl*>(data);
+ DCHECK(surface);
+
+ bool is_maximized =
+ CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_MAXIMIZED);
+ bool is_fullscreen =
+ CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_FULLSCREEN);
+ bool is_activated =
+ CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_ACTIVATED);
+
+ surface->wayland_window_->HandleToplevelConfigure(
+ width, height, is_maximized, is_fullscreen, is_activated);
+}
+
+// static
+void XDGToplevelWrapperImpl::CloseTopLevel(void* data,
+ struct xdg_toplevel* xdg_toplevel) {
+ auto* surface = static_cast<XDGToplevelWrapperImpl*>(data);
+ DCHECK(surface);
+ surface->wayland_window_->OnCloseRequest();
+}
+
+void XDGToplevelWrapperImpl::SetTopLevelDecorationMode(
+ DecorationMode requested_mode) {
+ if (!zxdg_toplevel_decoration_ || requested_mode == decoration_mode_)
+ return;
+
+ decoration_mode_ = requested_mode;
+ zxdg_toplevel_decoration_v1_set_mode(zxdg_toplevel_decoration_.get(),
+ static_cast<uint32_t>(requested_mode));
+}
+
+// static
+void XDGToplevelWrapperImpl::ConfigureDecoration(
+ void* data,
+ struct zxdg_toplevel_decoration_v1* decoration,
+ uint32_t mode) {
+ auto* surface = static_cast<XDGToplevelWrapperImpl*>(data);
+ DCHECK(surface);
+ surface->SetTopLevelDecorationMode(static_cast<DecorationMode>(mode));
+}
+
+void XDGToplevelWrapperImpl::InitializeXdgDecoration() {
+ if (connection_->xdg_decoration_manager_v1()) {
+ DCHECK(!zxdg_toplevel_decoration_);
+ static const zxdg_toplevel_decoration_v1_listener decoration_listener = {
+ &XDGToplevelWrapperImpl::ConfigureDecoration,
+ };
+ zxdg_toplevel_decoration_.reset(
+ zxdg_decoration_manager_v1_get_toplevel_decoration(
+ connection_->xdg_decoration_manager_v1(), xdg_toplevel_.get()));
+ zxdg_toplevel_decoration_v1_add_listener(zxdg_toplevel_decoration_.get(),
+ &decoration_listener, this);
+ }
+}
+
+XDGSurfaceWrapperImpl* XDGToplevelWrapperImpl::xdg_surface_wrapper() const {
+ DCHECK(xdg_surface_wrapper_.get());
+ return xdg_surface_wrapper_.get();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h
new file mode 100644
index 00000000000..867a54dd79e
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h
@@ -0,0 +1,88 @@
+// Copyright 2021 The Chromium 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_WAYLAND_HOST_XDG_TOPLEVEL_WRAPPER_IMPL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_TOPLEVEL_WRAPPER_IMPL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h"
+
+namespace ui {
+
+class XDGSurfaceWrapperImpl;
+class WaylandConnection;
+class WaylandWindow;
+
+// Toplevel wrapper for xdg-shell stable
+class XDGToplevelWrapperImpl : public ShellToplevelWrapper {
+ public:
+ XDGToplevelWrapperImpl(std::unique_ptr<XDGSurfaceWrapperImpl> surface,
+ WaylandWindow* wayland_window,
+ WaylandConnection* connection);
+ XDGToplevelWrapperImpl(const XDGToplevelWrapperImpl&) = delete;
+ XDGToplevelWrapperImpl& operator=(const XDGToplevelWrapperImpl&) = delete;
+ ~XDGToplevelWrapperImpl() override;
+
+ // ShellSurfaceWrapper overrides:
+ bool Initialize() override;
+ void SetMaximized() override;
+ void UnSetMaximized() override;
+ void SetFullscreen() override;
+ void UnSetFullscreen() override;
+ void SetMinimized() override;
+ void SurfaceMove(WaylandConnection* connection) override;
+ void SurfaceResize(WaylandConnection* connection, uint32_t hittest) override;
+ void SetTitle(const base::string16& title) override;
+ void AckConfigure(uint32_t serial) override;
+ void SetWindowGeometry(const gfx::Rect& bounds) override;
+ void SetMinSize(int32_t width, int32_t height) override;
+ void SetMaxSize(int32_t width, int32_t height) override;
+ void SetAppId(const std::string& app_id) override;
+ void SetDecoration(DecorationMode decoration) override;
+
+ XDGSurfaceWrapperImpl* xdg_surface_wrapper() const;
+
+ private:
+ // xdg_toplevel_listener
+ static void ConfigureTopLevel(void* data,
+ struct xdg_toplevel* xdg_toplevel,
+ int32_t width,
+ int32_t height,
+ struct wl_array* states);
+ static void CloseTopLevel(void* data, struct xdg_toplevel* xdg_toplevel);
+
+ // zxdg_decoration_listener
+ static void ConfigureDecoration(
+ void* data,
+ struct zxdg_toplevel_decoration_v1* decoration,
+ uint32_t mode);
+
+ // Send request to wayland compositor to enable a requested decoration mode.
+ void SetTopLevelDecorationMode(DecorationMode requested_mode);
+
+ // Initializes the xdg-decoration protocol extension, if available.
+ void InitializeXdgDecoration();
+
+ // Ground surface for this toplevel wrapper.
+ std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface_wrapper_;
+
+ // Non-owing WaylandWindow that uses this toplevel wrapper.
+ WaylandWindow* const wayland_window_;
+ WaylandConnection* const connection_;
+
+ // XDG Shell Stable object.
+ wl::Object<xdg_toplevel> xdg_toplevel_;
+
+ wl::Object<zxdg_toplevel_decoration_v1> zxdg_toplevel_decoration_;
+
+ // On client side, it keeps track of the decoration mode currently in
+ // use if xdg-decoration protocol extension is available.
+ DecorationMode decoration_mode_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_TOPLEVEL_WRAPPER_IMPL_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc
index afa819257d6..a9e657d387b 100644
--- a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc
+++ b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc
@@ -6,9 +6,9 @@
#include <primary-selection-unstable-v1-client-protocol.h>
-#include "ui/ozone/platform/wayland/host/zwp_primary_selection_offer.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/zwp_primary_selection_offer.h"
namespace ui {
@@ -18,7 +18,8 @@ ZwpPrimarySelectionDevice::ZwpPrimarySelectionDevice(
zwp_primary_selection_device_v1* data_device)
: WaylandDataDeviceBase(connection), data_device_(data_device) {
static const struct zwp_primary_selection_device_v1_listener kListener = {
- ZwpPrimarySelectionDevice::OnDataOffer, ZwpPrimarySelectionDevice::OnSelection};
+ ZwpPrimarySelectionDevice::OnDataOffer,
+ ZwpPrimarySelectionDevice::OnSelection};
zwp_primary_selection_device_v1_add_listener(data_device_.get(), &kListener,
this);
}
@@ -40,10 +41,6 @@ void ZwpPrimarySelectionDevice::OnDataOffer(
zwp_primary_selection_offer_v1* offer) {
auto* self = static_cast<ZwpPrimarySelectionDevice*>(data);
DCHECK(self);
-
- self->connection()->clipboard()->UpdateSequenceNumber(
- ClipboardBuffer::kSelection);
-
self->set_data_offer(std::make_unique<ZwpPrimarySelectionOffer>(offer));
}
@@ -56,17 +53,16 @@ void ZwpPrimarySelectionDevice::OnSelection(
DCHECK(self);
// 'offer' will be null to indicate that the selection is no longer valid,
- // i.e. there is no longer clipboard data available to paste.
+ // i.e. there is no longer selection data available to be fetched.
if (!offer) {
self->ResetDataOffer();
-
- // Clear Clipboard cache.
- self->connection()->clipboard()->SetData({}, {});
- return;
+ } else {
+ DCHECK(self->data_offer());
+ self->data_offer()->EnsureTextMimeTypeIfNeeded();
}
- DCHECK(self->data_offer());
- self->data_offer()->EnsureTextMimeTypeIfNeeded();
+ if (self->selection_delegate())
+ self->selection_delegate()->OnSelectionOffer(self->data_offer());
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h
index 69a7ee2c397..c4d36a2ee51 100644
--- a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h
+++ b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h
@@ -19,10 +19,11 @@ class WaylandConnection;
class ZwpPrimarySelectionDevice : public WaylandDataDeviceBase {
public:
ZwpPrimarySelectionDevice(WaylandConnection* connection,
- zwp_primary_selection_device_v1* data_device);
+ zwp_primary_selection_device_v1* data_device);
ZwpPrimarySelectionDevice(const ZwpPrimarySelectionDevice&) = delete;
- ZwpPrimarySelectionDevice& operator =(const ZwpPrimarySelectionDevice&) = delete;
+ ZwpPrimarySelectionDevice& operator=(const ZwpPrimarySelectionDevice&) =
+ delete;
~ZwpPrimarySelectionDevice() override;
diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h
index 4f48f897065..8fa4d2f74db 100644
--- a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h
+++ b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h
@@ -23,7 +23,8 @@ class ZwpPrimarySelectionDeviceManager {
ZwpPrimarySelectionDeviceManager(
zwp_primary_selection_device_manager_v1* manager,
WaylandConnection* connection);
- ZwpPrimarySelectionDeviceManager(const ZwpPrimarySelectionDeviceManager&) = delete;
+ ZwpPrimarySelectionDeviceManager(const ZwpPrimarySelectionDeviceManager&) =
+ delete;
ZwpPrimarySelectionDeviceManager& operator=(
const ZwpPrimarySelectionDeviceManager&) = delete;
~ZwpPrimarySelectionDeviceManager();
diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_offer.cc b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_offer.cc
index 9a869e789b4..667cfd5abb4 100644
--- a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_offer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_offer.cc
@@ -10,8 +10,8 @@
#include <algorithm>
#include "base/check.h"
+#include "base/containers/contains.h"
#include "base/files/file_util.h"
-#include "base/stl_util.h"
#include "ui/base/clipboard/clipboard_constants.h"
namespace ui {
diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
index 8ae6849a3fe..456b19474f1 100644
--- a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
+++ b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
@@ -82,7 +82,21 @@ void ZWPTextInputWrapperV1::SetCursorRect(const gfx::Rect& rect) {
void ZWPTextInputWrapperV1::SetSurroundingText(
const base::string16& text,
const gfx::Range& selection_range) {
+ static constexpr size_t kWaylandMessageDataMaxLength = 4000;
const std::string text_utf8 = base::UTF16ToUTF8(text);
+ // The text length for set_surrounding_text can not be longer than the maximum
+ // length of wayland messages. The maximum length of the text is explicitly
+ // specified as 4000 in the protocol spec of text-input-unstable-v3.
+ // If the client is unware of the text around the cursor, we can skip sending
+ // set_surrounding_text requests. We fall back to this case when the text is
+ // too long.
+ // TODO(fukino): If the length of |text| doesn't fit into the 4000 bytes
+ // limitation, we should truncate the text and adjust indices of
+ // |selection_range| to make use of set_surrounding_text as much as possible.
+ // crbug.com/1173465.
+ if (text_utf8.size() > kWaylandMessageDataMaxLength)
+ return;
+
zwp_text_input_v1_set_surrounding_text(obj_.get(), text_utf8.c_str(),
selection_range.start(),
selection_range.end());
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.cc
new file mode 100644
index 00000000000..f506f0af5f9
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.cc
@@ -0,0 +1,262 @@
+// Copyright 2021 The Chromium 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/wayland/host/zxdg_popup_v6_wrapper_impl.h"
+
+#include <xdg-shell-unstable-v6-client-protocol.h>
+
+#include <memory>
+
+#include "base/environment.h"
+#include "base/nix/xdg_util.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/types/event_type.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
+#include "ui/ozone/platform/wayland/host/wayland_popup.h"
+#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
+#include "ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h"
+
+namespace ui {
+
+namespace {
+
+uint32_t TranslateAnchor(WlAnchor anchor) {
+ switch (anchor) {
+ case WlAnchor::None:
+ return ZXDG_POSITIONER_V6_ANCHOR_NONE;
+ case WlAnchor::Top:
+ return ZXDG_POSITIONER_V6_ANCHOR_TOP;
+ case WlAnchor::Bottom:
+ return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
+ case WlAnchor::Left:
+ return ZXDG_POSITIONER_V6_ANCHOR_LEFT;
+ case WlAnchor::Right:
+ return ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
+ case WlAnchor::TopLeft:
+ return ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_LEFT;
+ case WlAnchor::BottomLeft:
+ return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_LEFT;
+ case WlAnchor::TopRight:
+ return ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
+ case WlAnchor::BottomRight:
+ return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
+ }
+}
+
+uint32_t TranslateGravity(WlGravity gravity) {
+ switch (gravity) {
+ case WlGravity::None:
+ return ZXDG_POSITIONER_V6_GRAVITY_NONE;
+ case WlGravity::Top:
+ return ZXDG_POSITIONER_V6_GRAVITY_TOP;
+ case WlGravity::Bottom:
+ return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
+ case WlGravity::Left:
+ return ZXDG_POSITIONER_V6_GRAVITY_LEFT;
+ case WlGravity::Right:
+ return ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
+ case WlGravity::TopLeft:
+ return ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_LEFT;
+ case WlGravity::BottomLeft:
+ return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
+ ZXDG_POSITIONER_V6_GRAVITY_LEFT;
+ case WlGravity::TopRight:
+ return ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
+ case WlGravity::BottomRight:
+ return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
+ ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
+ }
+}
+
+uint32_t TranslateConstraintAdjustment(
+ WlConstraintAdjustment constraint_adjustment) {
+ uint32_t res = 0;
+ if ((constraint_adjustment & WlConstraintAdjustment::SlideX) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X;
+ if ((constraint_adjustment & WlConstraintAdjustment::SlideY) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
+ if ((constraint_adjustment & WlConstraintAdjustment::FlipX) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X;
+ if ((constraint_adjustment & WlConstraintAdjustment::FlipY) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y;
+ if ((constraint_adjustment & WlConstraintAdjustment::ResizeX) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X;
+ if ((constraint_adjustment & WlConstraintAdjustment::ResizeY) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
+ return res;
+}
+
+} // namespace
+
+ZXDGPopupV6WrapperImpl::ZXDGPopupV6WrapperImpl(
+ std::unique_ptr<ZXDGSurfaceV6WrapperImpl> surface,
+ WaylandWindow* wayland_window)
+ : wayland_window_(wayland_window),
+ zxdg_surface_v6_wrapper_(std::move(surface)) {
+ DCHECK(zxdg_surface_v6_wrapper_);
+ DCHECK(wayland_window_ && wayland_window_->parent_window());
+}
+
+ZXDGPopupV6WrapperImpl::~ZXDGPopupV6WrapperImpl() = default;
+
+bool ZXDGPopupV6WrapperImpl::Initialize(WaylandConnection* connection,
+ const gfx::Rect& bounds) {
+ if (!connection->shell() && !connection->shell_v6()) {
+ NOTREACHED() << "Wrong shell protocol";
+ return false;
+ }
+
+ ZXDGSurfaceV6WrapperImpl* parent_xdg_surface = nullptr;
+ // If the parent window is a popup, the surface of that popup must be used as
+ // a parent.
+ if (wl::IsMenuType(wayland_window_->parent_window()->type())) {
+ auto* wayland_popup =
+ static_cast<WaylandPopup*>(wayland_window_->parent_window());
+ ZXDGPopupV6WrapperImpl* popup =
+ static_cast<ZXDGPopupV6WrapperImpl*>(wayland_popup->shell_popup());
+ parent_xdg_surface = popup->zxdg_surface_v6_wrapper();
+ } else {
+ WaylandToplevelWindow* wayland_surface =
+ static_cast<WaylandToplevelWindow*>(wayland_window_->parent_window());
+ parent_xdg_surface = static_cast<ZXDGToplevelV6WrapperImpl*>(
+ wayland_surface->shell_toplevel())
+ ->zxdg_surface_v6_wrapper();
+ }
+
+ if (!zxdg_surface_v6_wrapper_ || !parent_xdg_surface)
+ return false;
+
+ auto new_bounds = bounds;
+ // Wayland doesn't allow empty bounds. If a zero or negative size is set, the
+ // invalid_input error is raised. Thus, use the least possible one.
+ // WaylandPopup will update its bounds upon the following configure event.
+ if (new_bounds.IsEmpty())
+ new_bounds.set_size({1, 1});
+
+ if (connection->shell_v6())
+ return InitializeV6(connection, new_bounds, parent_xdg_surface);
+
+ return false;
+}
+
+bool ZXDGPopupV6WrapperImpl::InitializeV6(
+ WaylandConnection* connection,
+ const gfx::Rect& bounds,
+ ZXDGSurfaceV6WrapperImpl* parent_xdg_surface) {
+ static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = {
+ &ZXDGPopupV6WrapperImpl::Configure,
+ &ZXDGPopupV6WrapperImpl::PopupDone,
+ };
+
+ zxdg_positioner_v6* positioner =
+ CreatePositioner(connection, wayland_window_->parent_window(), bounds);
+ if (!positioner)
+ return false;
+
+ zxdg_popup_v6_.reset(zxdg_surface_v6_get_popup(
+ zxdg_surface_v6_wrapper_->zxdg_surface(),
+ parent_xdg_surface->zxdg_surface(), positioner));
+ if (!zxdg_popup_v6_)
+ return false;
+
+ zxdg_positioner_v6_destroy(positioner);
+
+ if (CanGrabPopup(connection)) {
+ zxdg_popup_v6_grab(zxdg_popup_v6_.get(), connection->seat(),
+ connection->serial());
+ }
+ zxdg_popup_v6_add_listener(zxdg_popup_v6_.get(), &zxdg_popup_v6_listener,
+ this);
+
+ wayland_window_->root_surface()->Commit();
+ return true;
+}
+
+void ZXDGPopupV6WrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(zxdg_surface_v6_wrapper_);
+ zxdg_surface_v6_wrapper_->AckConfigure(serial);
+}
+
+zxdg_positioner_v6* ZXDGPopupV6WrapperImpl::CreatePositioner(
+ WaylandConnection* connection,
+ WaylandWindow* parent_window,
+ const gfx::Rect& bounds) {
+ struct zxdg_positioner_v6* positioner;
+ positioner = zxdg_shell_v6_create_positioner(connection->shell_v6());
+ if (!positioner)
+ return nullptr;
+
+ auto menu_type = GetMenuTypeForPositioner(connection, parent_window);
+
+ // The parent we got must be the topmost in the stack of the same family
+ // windows.
+ DCHECK_EQ(parent_window->GetTopMostChildWindow(), parent_window);
+
+ // Place anchor to the end of the possible position.
+ gfx::Rect anchor_rect = GetAnchorRect(
+ menu_type, bounds,
+ gfx::ScaleToRoundedRect(parent_window->GetBounds(),
+ 1.0 / parent_window->buffer_scale()));
+
+ zxdg_positioner_v6_set_anchor_rect(positioner, anchor_rect.x(),
+ anchor_rect.y(), anchor_rect.width(),
+ anchor_rect.height());
+ zxdg_positioner_v6_set_size(positioner, bounds.width(), bounds.height());
+ zxdg_positioner_v6_set_anchor(positioner,
+ TranslateAnchor(GetAnchor(menu_type, bounds)));
+ zxdg_positioner_v6_set_gravity(
+ positioner, TranslateGravity(GetGravity(menu_type, bounds)));
+ zxdg_positioner_v6_set_constraint_adjustment(
+ positioner,
+ TranslateConstraintAdjustment(GetConstraintAdjustment(menu_type)));
+ return positioner;
+}
+
+// static
+void ZXDGPopupV6WrapperImpl::Configure(void* data,
+ struct zxdg_popup_v6* zxdg_popup_v6,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height) {
+ // As long as the Wayland compositor repositions/requires to position windows
+ // relative to their parents, do not propagate final bounds information to
+ // Chromium. The browser places windows in respect to screen origin, but
+ // Wayland requires doing so in respect to parent window's origin. To properly
+ // place windows, the bounds are translated and adjusted according to the
+ // Wayland compositor needs during WaylandWindow::CreateXdgPopup call.
+ WaylandWindow* window =
+ static_cast<ZXDGPopupV6WrapperImpl*>(data)->wayland_window_;
+ DCHECK(window);
+ window->HandlePopupConfigure({x, y, width, height});
+}
+
+// static
+void ZXDGPopupV6WrapperImpl::PopupDone(void* data,
+ struct zxdg_popup_v6* zxdg_popup_v6) {
+ WaylandWindow* window =
+ static_cast<ZXDGPopupV6WrapperImpl*>(data)->wayland_window_;
+ DCHECK(window);
+ window->Hide();
+ window->OnCloseRequest();
+}
+
+ZXDGSurfaceV6WrapperImpl* ZXDGPopupV6WrapperImpl::zxdg_surface_v6_wrapper()
+ const {
+ DCHECK(zxdg_surface_v6_wrapper_.get());
+ return zxdg_surface_v6_wrapper_.get();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.h
new file mode 100644
index 00000000000..4c32a1e8f51
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.h
@@ -0,0 +1,64 @@
+// Copyright 2021 The Chromium 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_WAYLAND_HOST_ZXDG_POPUP_V6_WRAPPER_IMPL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_POPUP_V6_WRAPPER_IMPL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h"
+
+namespace ui {
+
+class ZXDGSurfaceV6WrapperImpl;
+class WaylandConnection;
+class WaylandWindow;
+
+// Popup wrapper for xdg-shell-unstable-v6
+class ZXDGPopupV6WrapperImpl : public ShellPopupWrapper {
+ public:
+ ZXDGPopupV6WrapperImpl(std::unique_ptr<ZXDGSurfaceV6WrapperImpl> surface,
+ WaylandWindow* wayland_window);
+ ~ZXDGPopupV6WrapperImpl() override;
+
+ // XDGPopupWrapper:
+ bool Initialize(WaylandConnection* connection,
+ const gfx::Rect& bounds) override;
+ void AckConfigure(uint32_t serial) override;
+
+ private:
+ bool InitializeV6(WaylandConnection* connection,
+ const gfx::Rect& bounds,
+ ZXDGSurfaceV6WrapperImpl* parent_zxdg_surface_v6_wrapper);
+ struct zxdg_positioner_v6* CreatePositioner(WaylandConnection* connection,
+ WaylandWindow* parent_window,
+ const gfx::Rect& bounds);
+
+ // zxdg_popup_v6_listener
+ static void Configure(void* data,
+ struct zxdg_popup_v6* zxdg_popup_v6,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height);
+ static void PopupDone(void* data, struct zxdg_popup_v6* zxdg_popup_v6);
+
+ ZXDGSurfaceV6WrapperImpl* zxdg_surface_v6_wrapper() const;
+
+ // Non-owned WaylandWindow that uses this popup.
+ WaylandWindow* const wayland_window_;
+
+ // Ground surface for this popup.
+ std::unique_ptr<ZXDGSurfaceV6WrapperImpl> zxdg_surface_v6_wrapper_;
+
+ // XDG Shell V6 object.
+ wl::Object<zxdg_popup_v6> zxdg_popup_v6_;
+
+ DISALLOW_COPY_AND_ASSIGN(ZXDGPopupV6WrapperImpl);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_POPUP_V6_WRAPPER_IMPL_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.cc
new file mode 100644
index 00000000000..385638d528b
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.cc
@@ -0,0 +1,74 @@
+// Copyright 2021 The Chromium 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/wayland/host/zxdg_surface_v6_wrapper_impl.h"
+
+#include <xdg-shell-unstable-v6-client-protocol.h>
+
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+
+namespace ui {
+
+ZXDGSurfaceV6WrapperImpl::ZXDGSurfaceV6WrapperImpl(
+ WaylandWindow* wayland_window,
+ WaylandConnection* connection)
+ : wayland_window_(wayland_window), connection_(connection) {}
+
+ZXDGSurfaceV6WrapperImpl::~ZXDGSurfaceV6WrapperImpl() = default;
+
+bool ZXDGSurfaceV6WrapperImpl::Initialize() {
+ if (!connection_->shell_v6()) {
+ NOTREACHED() << "Wrong shell protocol";
+ return false;
+ }
+
+ static const zxdg_surface_v6_listener zxdg_surface_v6_listener = {
+ &ZXDGSurfaceV6WrapperImpl::Configure,
+ };
+
+ zxdg_surface_v6_.reset(zxdg_shell_v6_get_xdg_surface(
+ connection_->shell_v6(), wayland_window_->root_surface()->surface()));
+ if (!zxdg_surface_v6_) {
+ LOG(ERROR) << "Failed to create zxdg_surface";
+ return false;
+ }
+
+ zxdg_surface_v6_add_listener(zxdg_surface_v6_.get(),
+ &zxdg_surface_v6_listener, this);
+ connection_->ScheduleFlush();
+ return true;
+}
+
+void ZXDGSurfaceV6WrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(zxdg_surface_v6_);
+ zxdg_surface_v6_ack_configure(zxdg_surface_v6_.get(), serial);
+ connection_->wayland_window_manager()->NotifyWindowConfigured(
+ wayland_window_);
+}
+
+void ZXDGSurfaceV6WrapperImpl::SetWindowGeometry(const gfx::Rect& bounds) {
+ DCHECK(zxdg_surface_v6_);
+ zxdg_surface_v6_set_window_geometry(zxdg_surface_v6_.get(), bounds.x(),
+ bounds.y(), bounds.width(),
+ bounds.height());
+}
+
+// static
+void ZXDGSurfaceV6WrapperImpl::Configure(
+ void* data,
+ struct zxdg_surface_v6* zxdg_surface_v6,
+ uint32_t serial) {
+ auto* surface = static_cast<ZXDGSurfaceV6WrapperImpl*>(data);
+ DCHECK(surface);
+
+ surface->wayland_window_->HandleSurfaceConfigure(serial);
+}
+
+zxdg_surface_v6* ZXDGSurfaceV6WrapperImpl::zxdg_surface() const {
+ DCHECK(zxdg_surface_v6_);
+ return zxdg_surface_v6_.get();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h
new file mode 100644
index 00000000000..8fa9a289b6b
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h
@@ -0,0 +1,56 @@
+// Copyright 2021 The Chromium 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_WAYLAND_HOST_ZXDG_SURFACE_V6_WRAPPER_IMPL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_SURFACE_V6_WRAPPER_IMPL_H_
+
+#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+
+#include <cstdint>
+#include <string>
+
+#include "base/strings/string16.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+class WaylandConnection;
+class WaylandWindow;
+
+// Surface wrapper for xdg-shell-unstable-v6
+class ZXDGSurfaceV6WrapperImpl : public ShellSurfaceWrapper {
+ public:
+ ZXDGSurfaceV6WrapperImpl(WaylandWindow* wayland_window,
+ WaylandConnection* connection);
+ ZXDGSurfaceV6WrapperImpl(const ZXDGSurfaceV6WrapperImpl&) = delete;
+ ZXDGSurfaceV6WrapperImpl& operator=(const ZXDGSurfaceV6WrapperImpl&) = delete;
+ ~ZXDGSurfaceV6WrapperImpl() override;
+
+ // ShellSurfaceWrapper overrides:
+ bool Initialize() override;
+ void AckConfigure(uint32_t serial) override;
+ void SetWindowGeometry(const gfx::Rect& bounds) override;
+
+ // zxdg_surface_v6_listener
+ static void Configure(void* data,
+ struct zxdg_surface_v6* zxdg_surface_v6,
+ uint32_t serial);
+
+ zxdg_surface_v6* zxdg_surface() const;
+
+ private:
+ // Non-owing WaylandWindow that uses this surface wrapper.
+ WaylandWindow* const wayland_window_;
+ WaylandConnection* const connection_;
+
+ wl::Object<zxdg_surface_v6> zxdg_surface_v6_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_SURFACE_V6_WRAPPER_IMPL_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc
new file mode 100644
index 00000000000..ea31771a618
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc
@@ -0,0 +1,166 @@
+// Copyright 2021 The Chromium 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/wayland/host/zxdg_toplevel_v6_wrapper_impl.h"
+
+#include <xdg-decoration-unstable-v1-client-protocol.h>
+#include <xdg-shell-client-protocol.h>
+#include <xdg-shell-unstable-v6-client-protocol.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/hit_test.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h"
+
+namespace ui {
+
+ZXDGToplevelV6WrapperImpl::ZXDGToplevelV6WrapperImpl(
+ std::unique_ptr<ZXDGSurfaceV6WrapperImpl> surface,
+ WaylandWindow* wayland_window,
+ WaylandConnection* connection)
+ : zxdg_surface_v6_wrapper_(std::move(surface)),
+ wayland_window_(wayland_window),
+ connection_(connection) {}
+
+ZXDGToplevelV6WrapperImpl::~ZXDGToplevelV6WrapperImpl() = default;
+
+bool ZXDGToplevelV6WrapperImpl::Initialize() {
+ if (!connection_->shell_v6()) {
+ NOTREACHED() << "Wrong shell protocol";
+ return false;
+ }
+
+ static const zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
+ &ZXDGToplevelV6WrapperImpl::ConfigureTopLevel,
+ &ZXDGToplevelV6WrapperImpl::CloseTopLevel,
+ };
+
+ if (!zxdg_surface_v6_wrapper_)
+ return false;
+
+ zxdg_toplevel_v6_.reset(
+ zxdg_surface_v6_get_toplevel(zxdg_surface_v6_wrapper_->zxdg_surface()));
+ if (!zxdg_toplevel_v6_) {
+ LOG(ERROR) << "Failed to create zxdg_toplevel";
+ return false;
+ }
+ zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(),
+ &zxdg_toplevel_v6_listener, this);
+
+ wayland_window_->root_surface()->Commit();
+ connection_->ScheduleFlush();
+ return true;
+}
+
+void ZXDGToplevelV6WrapperImpl::SetMaximized() {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_maximized(zxdg_toplevel_v6_.get());
+}
+
+void ZXDGToplevelV6WrapperImpl::UnSetMaximized() {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_unset_maximized(zxdg_toplevel_v6_.get());
+}
+
+void ZXDGToplevelV6WrapperImpl::SetFullscreen() {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_fullscreen(zxdg_toplevel_v6_.get(), nullptr);
+}
+
+void ZXDGToplevelV6WrapperImpl::UnSetFullscreen() {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_unset_fullscreen(zxdg_toplevel_v6_.get());
+}
+
+void ZXDGToplevelV6WrapperImpl::SetMinimized() {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_minimized(zxdg_toplevel_v6_.get());
+}
+
+void ZXDGToplevelV6WrapperImpl::SurfaceMove(WaylandConnection* connection) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_move(zxdg_toplevel_v6_.get(), connection->seat(),
+ connection->serial());
+}
+
+void ZXDGToplevelV6WrapperImpl::SurfaceResize(WaylandConnection* connection,
+ uint32_t hittest) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_resize(zxdg_toplevel_v6_.get(), connection->seat(),
+ connection->serial(),
+ wl::IdentifyDirection(*connection, hittest));
+}
+
+void ZXDGToplevelV6WrapperImpl::SetTitle(const base::string16& title) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_title(zxdg_toplevel_v6_.get(),
+ base::UTF16ToUTF8(title).c_str());
+}
+
+void ZXDGToplevelV6WrapperImpl::SetWindowGeometry(const gfx::Rect& bounds) {
+ zxdg_surface_v6_wrapper_->SetWindowGeometry(bounds);
+}
+
+void ZXDGToplevelV6WrapperImpl::SetMinSize(int32_t width, int32_t height) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_min_size(zxdg_toplevel_v6_.get(), width, height);
+}
+
+void ZXDGToplevelV6WrapperImpl::SetMaxSize(int32_t width, int32_t height) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_max_size(zxdg_toplevel_v6_.get(), width, height);
+}
+
+void ZXDGToplevelV6WrapperImpl::SetAppId(const std::string& app_id) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_app_id(zxdg_toplevel_v6_.get(), app_id.c_str());
+}
+
+void ZXDGToplevelV6WrapperImpl::SetDecoration(DecorationMode decoration) {}
+
+void ZXDGToplevelV6WrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(zxdg_surface_v6_wrapper_);
+ zxdg_surface_v6_wrapper_->AckConfigure(serial);
+}
+
+// static
+void ZXDGToplevelV6WrapperImpl::ConfigureTopLevel(
+ void* data,
+ struct zxdg_toplevel_v6* zxdg_toplevel_v6,
+ int32_t width,
+ int32_t height,
+ struct wl_array* states) {
+ auto* surface = static_cast<ZXDGToplevelV6WrapperImpl*>(data);
+ DCHECK(surface);
+
+ bool is_maximized =
+ CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED);
+ bool is_fullscreen =
+ CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN);
+ bool is_activated =
+ CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_ACTIVATED);
+
+ surface->wayland_window_->HandleToplevelConfigure(
+ width, height, is_maximized, is_fullscreen, is_activated);
+}
+
+// static
+void ZXDGToplevelV6WrapperImpl::CloseTopLevel(
+ void* data,
+ struct zxdg_toplevel_v6* zxdg_toplevel_v6) {
+ auto* surface = static_cast<ZXDGToplevelV6WrapperImpl*>(data);
+ DCHECK(surface);
+ surface->wayland_window_->OnCloseRequest();
+}
+
+ZXDGSurfaceV6WrapperImpl* ZXDGToplevelV6WrapperImpl::zxdg_surface_v6_wrapper()
+ const {
+ DCHECK(zxdg_surface_v6_wrapper_.get());
+ return zxdg_surface_v6_wrapper_.get();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h
new file mode 100644
index 00000000000..7727bfec007
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h
@@ -0,0 +1,72 @@
+// Copyright 2021 The Chromium 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_WAYLAND_HOST_ZXDG_TOPLEVEL_V6_WRAPPER_IMPL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_TOPLEVEL_V6_WRAPPER_IMPL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h"
+
+namespace ui {
+
+class ZXDGSurfaceV6WrapperImpl;
+class WaylandConnection;
+class WaylandWindow;
+
+// Toplevel wrapper for xdg-shell-unstable-v6
+class ZXDGToplevelV6WrapperImpl : public ShellToplevelWrapper {
+ public:
+ ZXDGToplevelV6WrapperImpl(std::unique_ptr<ZXDGSurfaceV6WrapperImpl> surface,
+ WaylandWindow* wayland_window,
+ WaylandConnection* connection);
+ ZXDGToplevelV6WrapperImpl(const ZXDGToplevelV6WrapperImpl&) = delete;
+ ZXDGToplevelV6WrapperImpl& operator=(const ZXDGToplevelV6WrapperImpl&) =
+ delete;
+ ~ZXDGToplevelV6WrapperImpl() override;
+
+ // ShellSurfaceWrapper overrides:
+ bool Initialize() override;
+ void SetMaximized() override;
+ void UnSetMaximized() override;
+ void SetFullscreen() override;
+ void UnSetFullscreen() override;
+ void SetMinimized() override;
+ void SurfaceMove(WaylandConnection* connection) override;
+ void SurfaceResize(WaylandConnection* connection, uint32_t hittest) override;
+ void SetTitle(const base::string16& title) override;
+ void AckConfigure(uint32_t serial) override;
+ void SetWindowGeometry(const gfx::Rect& bounds) override;
+ void SetMinSize(int32_t width, int32_t height) override;
+ void SetMaxSize(int32_t width, int32_t height) override;
+ void SetAppId(const std::string& app_id) override;
+ void SetDecoration(DecorationMode decoration) override;
+
+ ZXDGSurfaceV6WrapperImpl* zxdg_surface_v6_wrapper() const;
+
+ private:
+ // zxdg_toplevel_v6_listener
+ static void ConfigureTopLevel(void* data,
+ struct zxdg_toplevel_v6* zxdg_toplevel_v6,
+ int32_t width,
+ int32_t height,
+ struct wl_array* states);
+ static void CloseTopLevel(void* data,
+ struct zxdg_toplevel_v6* zxdg_toplevel_v6);
+
+ // Ground surface for this toplevel wrapper.
+ std::unique_ptr<ZXDGSurfaceV6WrapperImpl> zxdg_surface_v6_wrapper_;
+
+ // Non-owing WaylandWindow that uses this toplevel wrapper.
+ WaylandWindow* const wayland_window_;
+ WaylandConnection* const connection_;
+
+ // XDG Shell V6 object.
+ wl::Object<zxdg_toplevel_v6> zxdg_toplevel_v6_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_TOPLEVEL_V6_WRAPPER_IMPL_H_
diff --git a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index ab143cad1e2..b568018a8dc 100644
--- a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -16,7 +16,6 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "ui/base/buildflags.h"
#include "ui/base/cursor/cursor_factory.h"
-#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/base/ime/linux/input_method_auralinux.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
@@ -31,6 +30,7 @@
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor_factory.h"
#include "ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h"
#include "ui/ozone/platform/wayland/host/wayland_menu_utils.h"
#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
@@ -171,7 +171,11 @@ class OzonePlatformWayland : public OzonePlatform {
buffer_manager_connector_ = std::make_unique<WaylandBufferManagerConnector>(
connection_->buffer_manager_host());
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
cursor_factory_ = std::make_unique<BitmapCursorFactoryOzone>();
+#else
+ cursor_factory_ = std::make_unique<WaylandCursorFactory>(connection_.get());
+#endif
input_controller_ = CreateStubInputController();
gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
@@ -224,6 +228,8 @@ class OzonePlatformWayland : public OzonePlatform {
// https://github.com/wayland-project/wayland-protocols/commit/76d1ae8c65739eff3434ef219c58a913ad34e988
properties->custom_frame_pref_default = true;
+ properties->uses_external_vulkan_image_factory = true;
+
// Wayland doesn't provide clients with global screen coordinates.
// Instead, it forces clients to position windows relative to their top
// level windows if the have child-parent relationship. In case of
@@ -250,7 +256,8 @@ class OzonePlatformWayland : public OzonePlatform {
properties;
static bool initialized = false;
if (!initialized) {
- properties->supports_overlays = ui::IsWaylandOverlayDelegationEnabled();
+ properties->supports_overlays =
+ ui::IsWaylandOverlayDelegationEnabled() && connection_->viewporter();
initialized = true;
}
return *properties;
diff --git a/chromium/ui/ozone/platform/wayland/test/mock_surface.cc b/chromium/ui/ozone/platform/wayland/test/mock_surface.cc
index d7ec1ec227b..33b9ae348c0 100644
--- a/chromium/ui/ozone/platform/wayland/test/mock_surface.cc
+++ b/chromium/ui/ozone/platform/wayland/test/mock_surface.cc
@@ -4,6 +4,8 @@
#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_region.h"
+
namespace wl {
namespace {
@@ -20,13 +22,13 @@ void Attach(wl_client* client,
void SetOpaqueRegion(wl_client* client,
wl_resource* resource,
wl_resource* region) {
- GetUserDataAs<MockSurface>(resource)->SetOpaqueRegion(region);
+ GetUserDataAs<MockSurface>(resource)->SetOpaqueRegionImpl(region);
}
void SetInputRegion(wl_client* client,
wl_resource* resource,
wl_resource* region) {
- GetUserDataAs<MockSurface>(resource)->SetInputRegion(region);
+ GetUserDataAs<MockSurface>(resource)->SetInputRegionImpl(region);
}
void Damage(wl_client* client,
@@ -100,6 +102,35 @@ MockSurface* MockSurface::FromResource(wl_resource* resource) {
return GetUserDataAs<MockSurface>(resource);
}
+void MockSurface::SetOpaqueRegionImpl(wl_resource* region) {
+ if (!region) {
+ opaque_region_ = gfx::Rect(-1, -1, 0, 0);
+ return;
+ }
+ auto bounds = GetUserDataAs<TestRegion>(region)->getBounds();
+ opaque_region_ =
+ gfx::Rect(bounds.fLeft, bounds.fTop, bounds.fRight - bounds.fLeft,
+ bounds.fBottom - bounds.fTop);
+
+ SetOpaqueRegion(region);
+}
+
+void MockSurface::SetInputRegionImpl(wl_resource* region) {
+ // It is unsafe to always treat |region| as a valid pointer.
+ // According to the protocol about wl_surface::set_input_region
+ // "A NULL wl_region cuases the input region to be set to infinite."
+ if (!region) {
+ input_region_ = gfx::Rect(-1, -1, 0, 0);
+ return;
+ }
+ auto bounds = GetUserDataAs<TestRegion>(region)->getBounds();
+ input_region_ =
+ gfx::Rect(bounds.fLeft, bounds.fTop, bounds.fRight - bounds.fLeft,
+ bounds.fBottom - bounds.fTop);
+
+ SetInputRegion(region);
+}
+
void MockSurface::AttachNewBuffer(wl_resource* buffer_resource,
int32_t x,
int32_t y) {
diff --git a/chromium/ui/ozone/platform/wayland/test/mock_surface.h b/chromium/ui/ozone/platform/wayland/test/mock_surface.h
index 5c4e5cfb795..fd682b8fa87 100644
--- a/chromium/ui/ozone/platform/wayland/test/mock_surface.h
+++ b/chromium/ui/ozone/platform/wayland/test/mock_surface.h
@@ -56,6 +56,9 @@ class MockSurface : public ServerObject {
void set_viewport(TestViewport* viewport) { viewport_ = viewport; }
TestViewport* viewport() { return viewport_; }
+ gfx::Rect opaque_region() const { return opaque_region_; }
+ gfx::Rect input_region() const { return input_region_; }
+
void set_frame_callback(wl_resource* callback_resource) {
DCHECK(!frame_callback_);
frame_callback_ = callback_resource;
@@ -66,6 +69,8 @@ class MockSurface : public ServerObject {
bool has_role() const { return !!xdg_surface_ || !!sub_surface_; }
+ void SetOpaqueRegionImpl(wl_resource* region);
+ void SetInputRegionImpl(wl_resource* region);
void AttachNewBuffer(wl_resource* buffer_resource, int32_t x, int32_t y);
void DestroyPrevAttachedBuffer();
void ReleaseBuffer(wl_resource* buffer);
@@ -75,6 +80,8 @@ class MockSurface : public ServerObject {
MockXdgSurface* xdg_surface_ = nullptr;
TestSubSurface* sub_surface_ = nullptr;
TestViewport* viewport_ = nullptr;
+ gfx::Rect opaque_region_ = {-1, -1, 0, 0};
+ gfx::Rect input_region_ = {-1, -1, 0, 0};
wl_resource* frame_callback_ = nullptr;
diff --git a/chromium/ui/ozone/platform/wayland/test/test_compositor.cc b/chromium/ui/ozone/platform/wayland/test/test_compositor.cc
index 9a6244b0cb3..80fab9ab4bb 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_compositor.cc
+++ b/chromium/ui/ozone/platform/wayland/test/test_compositor.cc
@@ -12,9 +12,9 @@
namespace wl {
-namespace {
+constexpr uint32_t TestCompositor::kVersion;
-constexpr uint32_t kCompositorVersion = 4;
+namespace {
void CreateSurface(wl_client* client,
wl_resource* compositor_resource,
@@ -42,11 +42,9 @@ const struct wl_compositor_interface kTestCompositorImpl = {
};
TestCompositor::TestCompositor()
- : GlobalObject(&wl_compositor_interface,
- &kTestCompositorImpl,
- kCompositorVersion) {}
+ : GlobalObject(&wl_compositor_interface, &kTestCompositorImpl, kVersion) {}
-TestCompositor::~TestCompositor() {}
+TestCompositor::~TestCompositor() = default;
void TestCompositor::AddSurface(MockSurface* surface) {
surfaces_.push_back(surface);
diff --git a/chromium/ui/ozone/platform/wayland/test/test_compositor.h b/chromium/ui/ozone/platform/wayland/test/test_compositor.h
index 1b54cfb4173..6cc6c0f5759 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_compositor.h
+++ b/chromium/ui/ozone/platform/wayland/test/test_compositor.h
@@ -17,6 +17,8 @@ class MockSurface;
// Manage wl_compositor object.
class TestCompositor : public GlobalObject {
public:
+ static constexpr uint32_t kVersion = 4;
+
TestCompositor();
~TestCompositor() override;
diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc b/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc
index 73736c7b002..861e685ae9a 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc
+++ b/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc
@@ -54,7 +54,8 @@ void DataOfferSetActions(wl_client* client,
wl_resource* resource,
uint32_t dnd_actions,
uint32_t preferred_action) {
- NOTIMPLEMENTED();
+ GetUserDataAs<TestDataOffer>(resource)->SetActions(dnd_actions,
+ preferred_action);
}
} // namespace
@@ -85,4 +86,19 @@ void TestDataOffer::OnOffer(const std::string& mime_type,
wl_data_offer_send_offer(resource(), mime_type.c_str());
}
+void TestDataOffer::SetActions(uint32_t dnd_actions,
+ uint32_t preferred_action) {
+ client_supported_actions_ = dnd_actions;
+ client_preferred_action_ = preferred_action;
+ OnAction(client_preferred_action_);
+}
+
+void TestDataOffer::OnSourceActions(uint32_t source_actions) {
+ wl_data_offer_send_source_actions(resource(), source_actions);
+}
+
+void TestDataOffer::OnAction(uint32_t dnd_action) {
+ wl_data_offer_send_action(resource(), dnd_action);
+}
+
} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_offer.h b/chromium/ui/ozone/platform/wayland/test/test_data_offer.h
index 6b96582da7d..77c389c6919 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_data_offer.h
+++ b/chromium/ui/ozone/platform/wayland/test/test_data_offer.h
@@ -34,11 +34,21 @@ class TestDataOffer : public ServerObject {
void Receive(const std::string& mime_type, base::ScopedFD fd);
void OnOffer(const std::string& mime_type, ui::PlatformClipboard::Data data);
+ void SetActions(uint32_t dnd_actions, uint32_t preferred_action);
+
+ void OnSourceActions(uint32_t source_actions);
+ void OnAction(uint32_t dnd_action);
+
+ uint32_t supported_actions() const { return client_supported_actions_; }
+ uint32_t preferred_action() const { return client_preferred_action_; }
private:
const scoped_refptr<base::SequencedTaskRunner> task_runner_;
ui::PlatformClipboard::DataMap data_to_offer_;
+ uint32_t client_supported_actions_ = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+ uint32_t client_preferred_action_ = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+
base::WeakPtrFactory<TestDataOffer> write_data_weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(TestDataOffer);
diff --git a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
index 6cf79816b5c..7cf3193cbc2 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
+++ b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
@@ -36,6 +36,10 @@ TestWaylandServerThread::~TestWaylandServerThread() {
if (client_)
wl_client_destroy(client_);
+ // Stop watching the descriptor here to guarantee that no new events will come
+ // during or after the destruction of the display.
+ controller_.StopWatchingFileDescriptor();
+
Resume();
Stop();
}
@@ -146,7 +150,8 @@ TestWaylandServerThread::CreateMessagePump() {
void TestWaylandServerThread::OnFileCanReadWithoutBlocking(int fd) {
wl_event_loop_dispatch(event_loop_, 0);
- wl_display_flush_clients(display_.get());
+ if (display_)
+ wl_display_flush_clients(display_.get());
}
void TestWaylandServerThread::OnFileCanWriteWithoutBlocking(int fd) {}
diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc b/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
new file mode 100644
index 00000000000..259e8541c78
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
@@ -0,0 +1,127 @@
+// Copyright 2021 The Chromium 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/wayland/test/wayland_drag_drop_test.h"
+
+#include <wayland-util.h>
+
+#include <cstdint>
+
+#include "base/callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_data_device.h"
+#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
+#include "ui/ozone/platform/wayland/test/test_data_offer.h"
+#include "ui/ozone/platform/wayland/test/test_data_source.h"
+
+namespace ui {
+
+WaylandDragDropTest::WaylandDragDropTest() = default;
+
+void WaylandDragDropTest::SendDndEnter(WaylandWindow* window,
+ const gfx::Point& location) {
+ auto* surface = server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId());
+ OfferAndEnter(surface, location);
+}
+
+void WaylandDragDropTest::SendDndLeave() {
+ data_device_manager_->data_device()->OnLeave();
+}
+
+void WaylandDragDropTest::SendDndMotion(const gfx::Point& location) {
+ EXPECT_TRUE(data_source_);
+ wl_fixed_t x = wl_fixed_from_int(location.x());
+ wl_fixed_t y = wl_fixed_from_int(location.y());
+ data_device_manager_->data_device()->OnMotion(NextTime(), x, y);
+}
+
+void WaylandDragDropTest::SendDndCancelled() {
+ EXPECT_TRUE(data_source_);
+ data_source_->OnCancelled();
+}
+
+void WaylandDragDropTest::ReadData(
+ const std::string& mime_type,
+ wl::TestDataSource::ReadDataCallback callback) {
+ ASSERT_TRUE(data_source_);
+ data_source_->ReadData(mime_type, std::move(callback));
+}
+
+void WaylandDragDropTest::SetUp() {
+ WaylandTest::SetUp();
+ Sync();
+
+ data_device_manager_ = server_.data_device_manager();
+ ASSERT_TRUE(data_device_manager_);
+
+ data_source_ = nullptr;
+ data_device_manager_->data_device()->set_delegate(this);
+}
+
+void WaylandDragDropTest::TearDown() {
+ data_device_manager_->data_device()->set_delegate(nullptr);
+ data_device_manager_ = nullptr;
+}
+
+// wl::TestDataDevice::Delegate:
+void WaylandDragDropTest::StartDrag(wl::TestDataSource* source,
+ wl::MockSurface* origin,
+ uint32_t serial) {
+ EXPECT_FALSE(data_source_);
+ data_source_ = source;
+ OfferAndEnter(origin, {});
+}
+
+uint32_t WaylandDragDropTest::NextSerial() const {
+ static uint32_t serial = 0;
+ return ++serial;
+}
+
+uint32_t WaylandDragDropTest::NextTime() const {
+ static uint32_t timestamp = 0;
+ return ++timestamp;
+}
+
+void WaylandDragDropTest::OfferAndEnter(wl::MockSurface* surface,
+ const gfx::Point& location) {
+ ASSERT_TRUE(data_source_);
+ auto* data_device = data_device_manager_->data_device();
+
+ // Emulate server sending an wl_data_device::offer event.
+ auto* data_offer = data_device->OnDataOffer();
+ for (const auto& mime_type : data_source_->mime_types())
+ data_offer->OnOffer(mime_type, {});
+
+ // Emulate server sending an wl_data_device::enter event.
+ wl_data_device_send_enter(
+ data_device->resource(), NextSerial(), surface->resource(),
+ wl_fixed_from_int(location.x()), wl_fixed_from_int(location.y()),
+ data_offer->resource());
+}
+
+void WaylandDragDropTest::ScheduleTestTask(base::OnceClosure test_task) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&WaylandDragDropTest::RunTestTask,
+ base::Unretained(this), std::move(test_task)));
+}
+
+void WaylandDragDropTest::RunTestTask(base::OnceClosure test_task) {
+ Sync();
+
+ // The data source is created asynchronously by the drag controller. If it is
+ // null at this point, it means that the task for that has not yet executed,
+ // so try again a bit later.
+ if (!data_device_manager_->data_source()) {
+ ScheduleTestTask(std::move(test_task));
+ return;
+ }
+
+ std::move(test_task).Run();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h b/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
new file mode 100644
index 00000000000..3455909c765
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
@@ -0,0 +1,68 @@
+// Copyright 2021 The Chromium 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_WAYLAND_TEST_WAYLAND_DRAG_DROP_TEST_H_
+#define UI_OZONE_PLATFORM_WAYLAND_TEST_WAYLAND_DRAG_DROP_TEST_H_
+
+#include "base/callback_forward.h"
+#include "ui/ozone/platform/wayland/test/test_data_device.h"
+#include "ui/ozone/platform/wayland/test/test_data_source.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace wl {
+class MockSurface;
+class TestDataDeviceManager;
+} // namespace wl
+
+namespace ui {
+
+class WaylandWindow;
+
+// Base class for Wayland drag-and-drop tests. Public methods allow test code to
+// emulate dnd-related events from the test compositor and can be used in both
+// data and window dragging test cases.
+class WaylandDragDropTest : public WaylandTest,
+ public wl::TestDataDevice::Delegate {
+ public:
+ WaylandDragDropTest();
+ WaylandDragDropTest(const WaylandDragDropTest&) = delete;
+ WaylandDragDropTest& operator=(const WaylandDragDropTest&) = delete;
+
+ // These are public for convenience, as they must be callable from lambda
+ // functions, usually posted to task queue while the drag loop runs.
+ void SendDndEnter(WaylandWindow* window, const gfx::Point& location);
+ void SendDndLeave();
+ void SendDndMotion(const gfx::Point& location);
+ void SendDndCancelled();
+ void ReadData(const std::string& mime_type,
+ wl::TestDataSource::ReadDataCallback callback);
+
+ protected:
+ // WaylandTest:
+ void SetUp() override;
+ void TearDown() override;
+
+ // wl::TestDataDevice::Delegate:
+ void StartDrag(wl::TestDataSource* source,
+ wl::MockSurface* origin,
+ uint32_t serial) override;
+
+ void OfferAndEnter(wl::MockSurface* surface, const gfx::Point& location);
+ uint32_t NextSerial() const;
+ uint32_t NextTime() const;
+ void ScheduleTestTask(base::OnceClosure test_task);
+ void RunTestTask(base::OnceClosure test_task);
+
+ // Server objects
+ wl::TestDataDeviceManager* data_device_manager_;
+ wl::TestDataSource* data_source_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_TEST_WAYLAND_DRAG_DROP_TEST_H_
diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
index 58e395d8e82..b226e31dbc3 100644
--- a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
+++ b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
@@ -69,6 +69,7 @@ void WaylandTest::SetUp() {
properties.type = PlatformWindowType::kWindow;
window_ = WaylandWindow::Create(&delegate_, connection_.get(),
std::move(properties));
+ window_->set_update_visual_size_immediately(true);
ASSERT_NE(widget_, gfx::kNullAcceleratedWidget);
window_->Show(false);
@@ -118,17 +119,17 @@ void WaylandTest::SendConfigureEvent(wl::MockXdgSurface* xdg_surface,
// Please note that toplevel surfaces may not exist if the surface was created
// for the popup role.
if (GetParam() == kXdgShellV6) {
- zxdg_surface_v6_send_configure(xdg_surface->resource(), serial);
if (xdg_surface->xdg_toplevel()) {
zxdg_toplevel_v6_send_configure(xdg_surface->xdg_toplevel()->resource(),
width, height, states);
}
+ zxdg_surface_v6_send_configure(xdg_surface->resource(), serial);
} else {
- xdg_surface_send_configure(xdg_surface->resource(), serial);
if (xdg_surface->xdg_toplevel()) {
xdg_toplevel_send_configure(xdg_surface->xdg_toplevel()->resource(),
width, height, states);
}
+ xdg_surface_send_configure(xdg_surface->resource(), serial);
}
}
diff --git a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
index 8721395d80b..a8767ae8265 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
@@ -84,7 +84,7 @@ class WaylandBufferManagerTest : public WaylandTest {
// callback and bind the interface again if the manager failed.
manager_host_->SetTerminateGpuCallback(callback_.Get());
auto interface_ptr = manager_host_->BindInterface();
- buffer_manager_gpu_->Initialize(std::move(interface_ptr), {}, false);
+ buffer_manager_gpu_->Initialize(std::move(interface_ptr), {}, false, false);
}
protected:
@@ -119,7 +119,7 @@ class WaylandBufferManagerTest : public WaylandTest {
// Recreate the gpu side manager (the production code does the
// same).
buffer_manager_gpu_ = std::make_unique<WaylandBufferManagerGpu>();
- buffer_manager_gpu_->Initialize(std::move(interface_ptr), {},
+ buffer_manager_gpu_->Initialize(std::move(interface_ptr), {}, false,
false);
}));
}
@@ -341,7 +341,8 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {
CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
kBufferId1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds());
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds(),
+ window_->GetBounds());
CreateDmabufBasedBufferAndSetTerminateExpectation(true /*fail*/,
kBufferId1);
@@ -364,7 +365,8 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {
CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
kBufferId1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds());
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds(),
+ window_->GetBounds());
DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget,
kBufferId1, true /*fail*/);
@@ -385,7 +387,8 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {
CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
kBufferId1);
// Attach to a surface.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds());
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds(),
+ window_->GetBounds());
// Created non-attached buffer as well.
CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
@@ -418,7 +421,32 @@ TEST_P(WaylandBufferManagerTest, CommitBufferNonExistingBufferId) {
// Can't commit for non-existing buffer id.
SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/);
buffer_manager_gpu_->CommitBuffer(window_->GetWidget(), 5u,
- window_->GetBounds());
+ window_->GetBounds(), window_->GetBounds());
+
+ Sync();
+}
+
+TEST_P(WaylandBufferManagerTest, CommitOverlaysNonExistingBufferId) {
+ EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, 1u);
+
+ // Can't commit for non-existing buffer id.
+ SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/);
+
+ std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs;
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, 1u,
+ window_->GetBounds(), gfx::RectF(), window_->GetBounds(), false,
+ gfx::GpuFenceHandle()));
+
+ // Non-existing buffer id
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, 2u,
+ window_->GetBounds(), gfx::RectF(), window_->GetBounds(), false,
+ gfx::GpuFenceHandle()));
+
+ buffer_manager_gpu_->CommitOverlays(window_->GetWidget(),
+ std::move(overlay_configs));
Sync();
}
@@ -431,7 +459,7 @@ TEST_P(WaylandBufferManagerTest, CommitBufferNullWidget) {
// Can't commit for non-existing widget.
SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/);
buffer_manager_gpu_->CommitBuffer(gfx::kNullAcceleratedWidget, kBufferId,
- window_->GetBounds());
+ window_->GetBounds(), window_->GetBounds());
Sync();
}
@@ -474,7 +502,7 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) {
ASSERT_TRUE(!connection_->presentation());
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -485,7 +513,7 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) {
Sync();
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -514,7 +542,7 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) {
.Times(1);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -591,7 +619,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(mock_surface_gpu,
OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK))
.Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
@@ -600,7 +628,7 @@ TEST_P(WaylandBufferManagerTest,
mock_wp_presentation->set_presentation_callback(nullptr);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
@@ -621,7 +649,7 @@ TEST_P(WaylandBufferManagerTest,
// Commit buffer 3 then send the presentation callback for it. This should
// not call OnPresentation as OnSubmission hasn't been called yet.
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, bounds);
mock_surface->SendFrameCallback();
mock_wp_presentation->SendPresentationCallback();
Sync();
@@ -703,7 +731,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
// Commit first buffer
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -721,7 +749,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
// Commit second buffer
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -741,7 +769,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
// Commit third buffer
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, bounds);
Sync();
@@ -826,7 +854,7 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) {
EXPECT_CALL(*mock_surface, Commit()).Times(0);
buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId,
- window_->GetBounds());
+ window_->GetBounds(), window_->GetBounds());
Sync();
EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
@@ -859,7 +887,7 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) {
EXPECT_CALL(*mock_surface, Commit()).Times(0);
buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId2,
- window_->GetBounds());
+ window_->GetBounds(), window_->GetBounds());
Sync();
@@ -925,14 +953,16 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditionsAckConfigured) {
EXPECT_CALL(*mock_surface, Frame(_)).Times(0);
EXPECT_CALL(*mock_surface, Commit()).Times(0);
- buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId,
- window_->GetBounds());
+ buffer_manager_gpu_->CommitBuffer(
+ widget, kDmabufBufferId, window_->GetBounds(), window_->GetBounds());
Sync();
if (type != PlatformWindowType::kTooltip) {
DCHECK(mock_surface->xdg_surface());
ActivateSurface(mock_surface->xdg_surface());
} else {
+ // WaylandAuxiliaryWindow uses the focused window as a parent.
+ window_->SetPointerFocus(true);
// See the comment near Show() call above.
temp_window->Show(false);
}
@@ -943,6 +973,7 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditionsAckConfigured) {
Sync();
+ window_->SetPointerFocus(false);
temp_window.reset();
DestroyBufferAndSetTerminateExpectation(widget, kDmabufBufferId,
false /*fail*/);
@@ -991,7 +1022,7 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) {
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -1015,7 +1046,7 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) {
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -1039,7 +1070,7 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) {
.Times(0);
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId3, _)).Times(0);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, bounds);
Sync();
@@ -1075,7 +1106,7 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferForDestroyedWindow) {
Sync();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId,
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId, temp_window->GetBounds(),
temp_window->GetBounds());
Sync();
@@ -1108,7 +1139,7 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionSingleBuffer) {
temp_window.reset();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId, bounds, bounds);
Sync();
@@ -1149,7 +1180,7 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) {
EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _)).Times(1);
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -1169,7 +1200,7 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) {
.Times(1);
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -1181,7 +1212,7 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) {
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
temp_window.reset();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -1217,7 +1248,7 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferCommittedTwiceInARow) {
.Times(1);
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu);
@@ -1226,11 +1257,11 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferCommittedTwiceInARow) {
EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _)).Times(0);
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
@@ -1281,7 +1312,7 @@ TEST_P(WaylandBufferManagerTest, ReleaseBufferCommittedTwiceInARow) {
.Times(1);
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu);
@@ -1291,11 +1322,11 @@ TEST_P(WaylandBufferManagerTest, ReleaseBufferCommittedTwiceInARow) {
EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _)).Times(0);
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
@@ -1346,7 +1377,7 @@ TEST_P(WaylandBufferManagerTest, ReleaseOrderDifferentToCommitOrder) {
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu);
@@ -1357,12 +1388,12 @@ TEST_P(WaylandBufferManagerTest, ReleaseOrderDifferentToCommitOrder) {
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(2);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
auto* wl_buffer2 = mock_surface->attached_buffer();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
@@ -1432,7 +1463,7 @@ TEST_P(WaylandBufferManagerTest,
.Times(1);
EXPECT_CALL(*mock_surface, Commit()).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -1454,7 +1485,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(*mock_surface, Commit()).Times(1);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -1496,7 +1527,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(*mock_surface, Commit()).Times(1);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -1530,7 +1561,7 @@ TEST_P(WaylandBufferManagerTest,
.Times(1);
EXPECT_CALL(*mock_surface, Commit()).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -1579,12 +1610,77 @@ TEST_P(WaylandBufferManagerTest, OnSubmissionCalledForSingleBuffer) {
.Times(1);
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/);
}
+// Tests that when CommitOverlays(), root_surface can only be committed once all
+// overlays in the frame are committed.
+TEST_P(WaylandBufferManagerTest, RootSurfaceIsCommittedLast) {
+ constexpr uint32_t kBufferId1 = 1;
+ constexpr uint32_t kBufferId2 = 2;
+ constexpr uint32_t kBufferId3 = 3;
+
+ const gfx::AcceleratedWidget widget = window_->GetWidget();
+ const gfx::Rect bounds = window_->GetBounds();
+
+ MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget);
+
+ auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1();
+ EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(3);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId3);
+
+ Sync();
+
+ // Ack creation for only the first 2 wl_buffers.
+ LOG(ERROR) << linux_dmabuf->buffer_params().size();
+ zwp_linux_buffer_params_v1_send_created(
+ linux_dmabuf->buffer_params()[0]->resource(),
+ linux_dmabuf->buffer_params()[0]->buffer_resource());
+ zwp_linux_buffer_params_v1_send_created(
+ linux_dmabuf->buffer_params()[1]->resource(),
+ linux_dmabuf->buffer_params()[1]->buffer_resource());
+
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+
+ // root_surface shall not be committed as one of its subsurface is not
+ // committed yet due to pending wl_buffer creation.
+ EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0);
+ EXPECT_CALL(*mock_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_surface, Commit()).Times(0);
+
+ std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs;
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, kBufferId1,
+ bounds, gfx::RectF(), bounds, false, gfx::GpuFenceHandle()));
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, kBufferId2, bounds,
+ gfx::RectF(), bounds, false, gfx::GpuFenceHandle()));
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ 1, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, kBufferId3, bounds,
+ gfx::RectF(), bounds, false, gfx::GpuFenceHandle()));
+ buffer_manager_gpu_->CommitOverlays(window_->GetWidget(),
+ std::move(overlay_configs));
+ Sync();
+ testing::Mock::VerifyAndClearExpectations(mock_surface);
+
+ // Once wl_buffer is created, all subsurfaces are committed, hence
+ // root_surface can be committed.
+ zwp_linux_buffer_params_v1_send_created(
+ linux_dmabuf->buffer_params()[0]->resource(),
+ linux_dmabuf->buffer_params()[0]->buffer_resource());
+ EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
+ EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*mock_surface, Commit()).Times(1);
+
+ Sync();
+}
+
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandBufferManagerTest,
::testing::Values(kXdgShellStable));
diff --git a/chromium/ui/ozone/platform/x11/BUILD.gn b/chromium/ui/ozone/platform/x11/BUILD.gn
index 731c7d7c0a0..7cf0bfdff6c 100644
--- a/chromium/ui/ozone/platform/x11/BUILD.gn
+++ b/chromium/ui/ozone/platform/x11/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/linux/gtk/gtk.gni")
import("//gpu/vulkan/features.gni")
import("//ui/base/ui_features.gni")
@@ -37,6 +38,7 @@ source_set("x11") {
deps = [
"//base",
"//build:chromecast_buildflags",
+ "//build:chromeos_buildflags",
"//gpu/vulkan:buildflags",
"//skia",
"//ui/base:base",
@@ -57,6 +59,8 @@ source_set("x11") {
"//ui/events/x",
"//ui/gfx",
"//ui/gfx/geometry",
+ "//ui/gfx/linux:gbm",
+ "//ui/gfx/linux:gpu_memory_buffer_support_x11",
"//ui/gfx/x",
"//ui/gl",
"//ui/ozone:ozone_base",
@@ -66,7 +70,7 @@ source_set("x11") {
"//ui/platform_window/x11",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//ui/base/ime/chromeos" ]
} else {
sources += [
diff --git a/chromium/ui/ozone/platform/x11/client_native_pixmap_factory_x11.cc b/chromium/ui/ozone/platform/x11/client_native_pixmap_factory_x11.cc
index 13d2b2d9048..d7346528ff0 100644
--- a/chromium/ui/ozone/platform/x11/client_native_pixmap_factory_x11.cc
+++ b/chromium/ui/ozone/platform/x11/client_native_pixmap_factory_x11.cc
@@ -4,12 +4,12 @@
#include "ui/ozone/platform/x11/client_native_pixmap_factory_x11.h"
-#include "ui/ozone/common/stub_client_native_pixmap_factory.h"
+#include "ui/gfx/linux/client_native_pixmap_factory_dmabuf.h"
namespace ui {
gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryX11() {
- return CreateStubClientNativePixmapFactory();
+ return gfx::CreateClientNativePixmapFactoryDmabuf();
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.cc b/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.cc
index 3c8e0d04ce4..d5612033adc 100644
--- a/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.cc
+++ b/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.cc
@@ -38,4 +38,17 @@ bool GLEGLUtilityX11::X11DoesVisualHaveAlphaForTest() const {
return ui::DoesVisualHaveAlphaForTest();
}
+bool GLEGLUtilityX11::HasVisualManager() {
+ return true;
+}
+
+bool GLEGLUtilityX11::UpdateVisualsOnGpuInfoChanged(
+ bool software_rendering,
+ uint32_t default_visual_id,
+ uint32_t transparent_visual_id) {
+ return ui::UpdateVisualsOnGpuInfoChanged(
+ software_rendering, static_cast<x11::VisualId>(default_visual_id),
+ static_cast<x11::VisualId>(transparent_visual_id));
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.h b/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.h
index 807d3a7d20c..1ca2ddf3878 100644
--- a/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.h
+++ b/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.h
@@ -27,6 +27,10 @@ class GLEGLUtilityX11 : public PlatformGLEGLUtility {
void CollectGpuExtraInfo(bool enable_native_gpu_memory_buffers,
gfx::GpuExtraInfo& gpu_extra_info) const override;
bool X11DoesVisualHaveAlphaForTest() const override;
+ bool HasVisualManager() override;
+ bool UpdateVisualsOnGpuInfoChanged(bool software_rendering,
+ uint32_t default_visual_id,
+ uint32_t transparent_visual_id) override;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
index 399bd0678bb..455f238ac68 100644
--- a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
+++ b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
@@ -9,10 +9,13 @@
#include "base/message_loop/message_pump_type.h"
#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task/thread_pool.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/buildflags.h"
#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
@@ -25,6 +28,7 @@
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/common/stub_overlay_manager.h"
#include "ui/ozone/platform/x11/gl_egl_utility_x11.h"
@@ -41,7 +45,7 @@
#include "ui/platform_window/platform_window_init_properties.h"
#include "ui/platform_window/x11/x11_window.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
#include "ui/base/ime/chromeos/input_method_chromeos.h"
#else
@@ -123,13 +127,15 @@ class OzonePlatformX11 : public OzonePlatform,
}
PlatformGLEGLUtility* GetPlatformGLEGLUtility() override {
+ if (!gl_egl_utility_)
+ gl_egl_utility_ = std::make_unique<GLEGLUtilityX11>();
return gl_egl_utility_.get();
}
std::unique_ptr<InputMethod> CreateInputMethod(
internal::InputMethodDelegate* delegate,
gfx::AcceleratedWidget) override {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return std::make_unique<InputMethodChromeOS>(delegate);
#else
// This method is used by upper layer components (e.g: GtkUi) to determine
@@ -147,7 +153,7 @@ class OzonePlatformX11 : public OzonePlatform,
}
std::unique_ptr<OSExchangeDataProvider> CreateProvider() override {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return std::make_unique<OSExchangeDataProviderNonBacked>();
#else
return std::make_unique<X11OSExchangeDataProviderOzone>();
@@ -169,9 +175,12 @@ class OzonePlatformX11 : public OzonePlatform,
properties->message_pump_type_for_viz_compositor =
base::MessagePumpType::UI;
properties->supports_vulkan_swap_chain = true;
+ properties->uses_external_vulkan_image_factory = true;
+ properties->skia_can_fall_back_to_x11 = true;
properties->platform_shows_drag_image = false;
properties->supports_global_application_menus = true;
properties->app_modal_dialogs_use_event_blocker = true;
+ properties->fetch_buffer_formats_for_gmb_on_gpu = true;
initialised = true;
}
@@ -179,6 +188,13 @@ class OzonePlatformX11 : public OzonePlatform,
return *properties;
}
+ bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
+ gfx::BufferUsage usage) const override {
+ // Native pixmap support is determined on gpu process via gpu extra info
+ // that gets this information from GpuMemoryBufferSupportX11.
+ return false;
+ }
+
void InitializeUI(const InitParams& params) override {
InitializeCommon(params);
CreatePlatformEventSource();
@@ -215,7 +231,13 @@ class OzonePlatformX11 : public OzonePlatform,
void InitializeGPU(const InitParams& params) override {
InitializeCommon(params);
-
+ if (params.enable_native_gpu_memory_buffers) {
+ base::ThreadPool::PostTask(
+ FROM_HERE, base::BindOnce([]() {
+ SCOPED_UMA_HISTOGRAM_TIMER("Linux.X11.GbmSupportX11CreationTime");
+ ui::GpuMemoryBufferSupportX11::GetInstance();
+ }));
+ }
// In single process mode either the UI thread will create an event source
// or it's a test and an event source isn't desired.
if (!params.single_process)
@@ -227,7 +249,6 @@ class OzonePlatformX11 : public OzonePlatform,
connection->DetachFromSequence();
surface_factory_ozone_ =
std::make_unique<X11SurfaceFactory>(std::move(connection));
- gl_egl_utility_ = std::make_unique<GLEGLUtilityX11>();
}
void PostMainMessageLoopStart(
@@ -253,7 +274,7 @@ class OzonePlatformX11 : public OzonePlatform,
// If opening the connection failed there is nothing we can do. Crash here
// instead of crashing later. If you are crashing here, make sure there is
// an X server running and $DISPLAY is set.
- CHECK(x11::Connection::Get()) << "Missing X server or $DISPLAY";
+ CHECK(x11::Connection::Get()->Ready()) << "Missing X server or $DISPLAY";
common_initialized_ = true;
}
diff --git a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
index 40945c6dbf1..5944973e00c 100644
--- a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
@@ -7,11 +7,12 @@
#include <algorithm>
#include <vector>
+#include "base/containers/contains.h"
#include "base/containers/span.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/x/x11_util.h"
+#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/extension_manager.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
@@ -78,12 +79,12 @@ struct X11ClipboardOzone::SelectionState {
};
X11ClipboardOzone::X11ClipboardOzone()
- : atom_clipboard_(gfx::GetAtom(kClipboard)),
- atom_targets_(gfx::GetAtom(kTargets)),
- atom_timestamp_(gfx::GetAtom(kTimestamp)),
- x_property_(gfx::GetAtom(kChromeSelection)),
+ : atom_clipboard_(x11::GetAtom(kClipboard)),
+ atom_targets_(x11::GetAtom(kTargets)),
+ atom_timestamp_(x11::GetAtom(kTimestamp)),
+ x_property_(x11::GetAtom(kChromeSelection)),
connection_(x11::Connection::Get()),
- x_window_(CreateDummyWindow("Chromium Clipboard Window")) {
+ x_window_(x11::CreateDummyWindow("Chromium Clipboard Window")) {
connection_->xfixes().QueryVersion(
{x11::XFixes::major_version, x11::XFixes::minor_version});
if (!connection_->xfixes().present())
@@ -91,7 +92,7 @@ X11ClipboardOzone::X11ClipboardOzone()
using_xfixes_ = true;
// Register to receive standard X11 events.
- X11EventSource::GetInstance()->AddXEventDispatcher(this);
+ connection_->AddEventObserver(this);
for (auto atom : {atom_clipboard_, x11::Atom::PRIMARY}) {
// Register the selection state.
@@ -105,29 +106,31 @@ X11ClipboardOzone::X11ClipboardOzone()
}
X11ClipboardOzone::~X11ClipboardOzone() {
- X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+ connection_->RemoveEventObserver(this);
}
-bool X11ClipboardOzone::DispatchXEvent(x11::Event* xev) {
- if (auto* request = xev->As<x11::SelectionRequestEvent>())
- return request->owner == x_window_ && OnSelectionRequest(*request);
- if (auto* notify = xev->As<x11::SelectionNotifyEvent>())
- return notify->requestor == x_window_ && OnSelectionNotify(*notify);
- if (auto* notify = xev->As<x11::XFixes::SelectionNotifyEvent>())
- return notify->window == x_window_ && OnSetSelectionOwnerNotify(*notify);
-
- return false;
+void X11ClipboardOzone::OnEvent(const x11::Event& xev) {
+ if (auto* request = xev.As<x11::SelectionRequestEvent>()) {
+ if (request->owner == x_window_)
+ OnSelectionRequest(*request);
+ } else if (auto* notify = xev.As<x11::SelectionNotifyEvent>()) {
+ if (notify->requestor == x_window_)
+ OnSelectionNotify(*notify);
+ } else if (auto* notify = xev.As<x11::XFixes::SelectionNotifyEvent>()) {
+ if (notify->window == x_window_)
+ OnSetSelectionOwnerNotify(*notify);
+ }
}
// We are the clipboard owner, and a remote peer has requested either:
// TARGETS: List of mime types that we support for the clipboard.
// TIMESTAMP: Time when we took ownership of the clipboard.
// <mime-type>: Mime type to receive clipboard as.
-bool X11ClipboardOzone::OnSelectionRequest(
+void X11ClipboardOzone::OnSelectionRequest(
const x11::SelectionRequestEvent& event) {
// The property must be set.
if (event.property == x11::Atom::None)
- return false;
+ return;
// target=TARGETS.
auto& selection_state =
@@ -145,14 +148,13 @@ bool X11ClipboardOzone::OnSelectionRequest(
ExpandTypes(&targets);
std::vector<x11::Atom> atoms;
for (auto& entry : targets)
- atoms.push_back(gfx::GetAtom(entry.c_str()));
- ui::SetArrayProperty(event.requestor, event.property, x11::Atom::ATOM,
- atoms);
+ atoms.push_back(x11::GetAtom(entry.c_str()));
+ SetArrayProperty(event.requestor, event.property, x11::Atom::ATOM, atoms);
} else if (target == atom_timestamp_) {
// target=TIMESTAMP.
- ui::SetProperty(event.requestor, event.property, x11::Atom::INTEGER,
- selection_state.acquired_selection_timestamp);
+ SetProperty(event.requestor, event.property, x11::Atom::INTEGER,
+ selection_state.acquired_selection_timestamp);
} else {
// Send clipboard data.
std::string target_name;
@@ -170,8 +172,8 @@ bool X11ClipboardOzone::OnSelectionRequest(
}
auto it = offer_data_map.find(key);
if (it != offer_data_map.end()) {
- ui::SetArrayProperty(event.requestor, event.property, event.target,
- it->second->data());
+ SetArrayProperty(event.requestor, event.property, event.target,
+ it->second->data());
}
}
@@ -185,20 +187,19 @@ bool X11ClipboardOzone::OnSelectionRequest(
};
x11::SendEvent(selection_event, selection_event.requestor,
x11::EventMask::NoEvent);
- return true;
}
// A remote peer owns the clipboard. This event is received in response to
// our request for TARGETS (GetAvailableMimeTypes), or a specific mime type
// (RequestClipboardData).
-bool X11ClipboardOzone::OnSelectionNotify(
+void X11ClipboardOzone::OnSelectionNotify(
const x11::SelectionNotifyEvent& event) {
// GetAvailableMimeTypes.
auto selection = static_cast<x11::Atom>(event.selection);
auto& selection_state = GetSelectionState(selection);
if (static_cast<x11::Atom>(event.target) == atom_targets_) {
std::vector<x11::Atom> targets;
- ui::GetArrayProperty(x_window_, x_property_, &targets);
+ GetArrayProperty(x_window_, x_property_, &targets);
selection_state.mime_types.clear();
for (auto target : targets) {
@@ -217,16 +218,14 @@ bool X11ClipboardOzone::OnSelectionNotify(
selection_state.data_mime_type = kMimeTypeText;
ReadRemoteClipboard(selection);
}
-
- return true;
}
// RequestClipboardData.
if (static_cast<x11::Atom>(event.property) == x_property_) {
x11::Atom type;
std::vector<uint8_t> data;
- ui::GetArrayProperty(x_window_, x_property_, &data, &type);
- ui::DeleteProperty(x_window_, x_property_);
+ GetArrayProperty(x_window_, x_property_, &data, &type);
+ x11::DeleteProperty(x_window_, x_property_);
if (type != x11::Atom::None)
selection_state.data = scoped_refptr<base::RefCountedBytes>(
base::RefCountedBytes::TakeVector(&data));
@@ -240,20 +239,16 @@ bool X11ClipboardOzone::OnSelectionNotify(
std::move(selection_state.request_clipboard_data_callback)
.Run(selection_state.data);
}
- return true;
} else if (static_cast<x11::Atom>(event.property) == x11::Atom::None &&
selection_state.request_clipboard_data_callback) {
// If the remote peer could not send data in the format we requested,
// or failed for any reason, we will send empty data.
std::move(selection_state.request_clipboard_data_callback)
.Run(selection_state.data);
- return true;
}
-
- return false;
}
-bool X11ClipboardOzone::OnSetSelectionOwnerNotify(
+void X11ClipboardOzone::OnSetSelectionOwnerNotify(
const x11::XFixes::SelectionNotifyEvent& event) {
// Reset state and fetch remote clipboard if there is a new remote owner.
x11::Atom selection = event.selection;
@@ -268,8 +263,6 @@ bool X11ClipboardOzone::OnSetSelectionOwnerNotify(
// Increase the sequence number if the callback is set.
if (update_sequence_cb_)
update_sequence_cb_.Run(BufferForSelectionAtom(selection));
-
- return true;
}
x11::Atom X11ClipboardOzone::SelectionAtomForBuffer(
@@ -320,7 +313,7 @@ void X11ClipboardOzone::ReadRemoteClipboard(x11::Atom selection) {
}
}
- connection_->ConvertSelection({x_window_, selection, gfx::GetAtom(target),
+ connection_->ConvertSelection({x_window_, selection, x11::GetAtom(target),
x_property_, x11::Time::CurrentTime});
}
@@ -361,6 +354,14 @@ void X11ClipboardOzone::RequestClipboardData(
std::move(callback).Run(selection_state.data);
return;
}
+
+ // If we know the available mime types, and it is not this, send empty now.
+ if (!selection_state.mime_types.empty() &&
+ !Contains(selection_state.mime_types, mime_type)) {
+ std::move(callback).Run(PlatformClipboard::Data());
+ return;
+ }
+
selection_state.data_mime_type = mime_type;
selection_state.request_data_map = data_map;
DCHECK(selection_state.request_clipboard_data_callback.is_null());
diff --git a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h
index 9592b8df86c..4802f02ee08 100644
--- a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h
@@ -10,7 +10,7 @@
#include "base/callback.h"
#include "base/containers/flat_map.h"
-#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/xfixes.h"
#include "ui/gfx/x/xproto.h"
@@ -26,7 +26,7 @@ namespace ui {
// text/plain. Otherwise GetAvailableMimeTypes and RequestClipboardData call
// the appropriate X11 functions and invoke callbacks when the associated events
// are received.
-class X11ClipboardOzone : public PlatformClipboard, public XEventDispatcher {
+class X11ClipboardOzone : public PlatformClipboard, public x11::EventObserver {
public:
X11ClipboardOzone();
~X11ClipboardOzone() override;
@@ -52,12 +52,12 @@ class X11ClipboardOzone : public PlatformClipboard, public XEventDispatcher {
private:
struct SelectionState;
- // XEventDispatcher:
- bool DispatchXEvent(x11::Event* xev) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& xev) override;
- bool OnSelectionRequest(const x11::SelectionRequestEvent& event);
- bool OnSelectionNotify(const x11::SelectionNotifyEvent& event);
- bool OnSetSelectionOwnerNotify(
+ void OnSelectionRequest(const x11::SelectionRequestEvent& event);
+ void OnSelectionNotify(const x11::SelectionNotifyEvent& event);
+ void OnSetSelectionOwnerNotify(
const x11::XFixes::SelectionNotifyEvent& event);
// Returns an X atom for a clipboard buffer type.
diff --git a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc
index 4c3b56653dd..8409a940dbc 100644
--- a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc
@@ -20,12 +20,12 @@ X11OSExchangeDataProviderOzone::X11OSExchangeDataProviderOzone(
X11OSExchangeDataProviderOzone::X11OSExchangeDataProviderOzone() {
DCHECK(own_window());
- X11EventSource::GetInstance()->AddXEventDispatcher(this);
+ x11::Connection::Get()->AddEventObserver(this);
}
X11OSExchangeDataProviderOzone::~X11OSExchangeDataProviderOzone() {
if (own_window())
- X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+ x11::Connection::Get()->RemoveEventObserver(this);
}
std::unique_ptr<OSExchangeDataProvider> X11OSExchangeDataProviderOzone::Clone()
@@ -36,13 +36,10 @@ std::unique_ptr<OSExchangeDataProvider> X11OSExchangeDataProviderOzone::Clone()
return std::move(ret);
}
-bool X11OSExchangeDataProviderOzone::DispatchXEvent(x11::Event* xev) {
- auto* selection_request = xev->As<x11::SelectionRequestEvent>();
- if (selection_request && selection_request->owner == x_window()) {
- selection_owner().OnSelectionRequest(*xev);
- return true;
- }
- return false;
+void X11OSExchangeDataProviderOzone::OnEvent(const x11::Event& xev) {
+ auto* selection_request = xev.As<x11::SelectionRequestEvent>();
+ if (selection_request && selection_request->owner == x_window())
+ selection_owner().OnSelectionRequest(*selection_request);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h
index 65542ea14d3..cc544e464a4 100644
--- a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h
@@ -6,14 +6,14 @@
#define UI_OZONE_PLATFORM_X11_X11_OS_EXCHANGE_DATA_PROVIDER_OZONE_H_
#include "ui/base/x/x11_os_exchange_data_provider.h"
-#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
namespace ui {
// OSExchangeDataProvider implementation for Ozone/X11.
class X11OSExchangeDataProviderOzone : public XOSExchangeDataProvider,
- public XEventDispatcher {
+ public x11::EventObserver {
public:
X11OSExchangeDataProviderOzone(x11::Window x_window,
const SelectionFormatMap& selection);
@@ -27,8 +27,8 @@ class X11OSExchangeDataProviderOzone : public XOSExchangeDataProvider,
// OSExchangeDataProvider:
std::unique_ptr<OSExchangeDataProvider> Clone() const override;
- // XEventDispatcher:
- bool DispatchXEvent(x11::Event* xev) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& xev) override;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
index d9ea9078d14..718cb627f4f 100644
--- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
@@ -42,17 +42,13 @@ X11ScreenOzone::X11ScreenOzone()
}
X11ScreenOzone::~X11ScreenOzone() {
- if (x11_display_manager_->IsXrandrAvailable() &&
- X11EventSource::HasInstance()) {
- X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
- }
+ if (x11_display_manager_->IsXrandrAvailable())
+ x11::Connection::Get()->RemoveEventObserver(this);
}
void X11ScreenOzone::Init() {
- if (x11_display_manager_->IsXrandrAvailable() &&
- X11EventSource::HasInstance()) {
- X11EventSource::GetInstance()->AddXEventDispatcher(this);
- }
+ if (x11_display_manager_->IsXrandrAvailable())
+ x11::Connection::Get()->AddEventObserver(this);
x11_display_manager_->Init();
}
@@ -154,8 +150,8 @@ base::Value X11ScreenOzone::GetGpuExtraInfoAsListValue(
gpu_extra_info.rgba_visual);
}
-bool X11ScreenOzone::DispatchXEvent(x11::Event* xev) {
- return x11_display_manager_->ProcessEvent(xev);
+void X11ScreenOzone::OnEvent(const x11::Event& xev) {
+ x11_display_manager_->OnEvent(xev);
}
gfx::Point X11ScreenOzone::GetCursorLocation() const {
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
index 2d61903d35f..4f498468610 100644
--- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
@@ -12,7 +12,6 @@
#include "base/macros.h"
#include "base/observer_list.h"
#include "ui/base/x/x11_display_manager.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/x/event.h"
#include "ui/ozone/public/platform_screen.h"
@@ -23,7 +22,7 @@ class X11WindowManager;
// A PlatformScreen implementation for X11.
class X11ScreenOzone : public PlatformScreen,
- public XEventDispatcher,
+ public x11::EventObserver,
public XDisplayManager::Delegate {
public:
X11ScreenOzone();
@@ -56,8 +55,8 @@ class X11ScreenOzone : public PlatformScreen,
base::Value GetGpuExtraInfoAsListValue(
const gfx::GpuExtraInfo& gpu_extra_info) override;
- // Overridden from ui::XEventDispatcher:
- bool DispatchXEvent(x11::Event* event) override;
+ // Overridden from x11::EventObserver:
+ void OnEvent(const x11::Event& event) override;
private:
friend class X11ScreenOzoneTest;
diff --git a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
index e416f3fa817..e081380d06f 100644
--- a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
+++ b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
@@ -8,6 +8,9 @@
#include "gpu/vulkan/buildflags.h"
#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/linux/gbm_buffer.h"
+#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h"
+#include "ui/gfx/linux/native_pixmap_dmabuf.h"
#include "ui/gfx/x/connection.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/gl_surface_egl_x11_gles2.h"
@@ -102,9 +105,10 @@ GLOzone* X11SurfaceFactory::GetGLOzone(gl::GLImplementation implementation) {
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
-X11SurfaceFactory::CreateVulkanImplementation(bool allow_protected_memory,
+X11SurfaceFactory::CreateVulkanImplementation(bool use_swiftshader,
+ bool allow_protected_memory,
bool enforce_protected_memory) {
- return std::make_unique<gpu::VulkanImplementationX11>();
+ return std::make_unique<gpu::VulkanImplementationX11>(use_swiftshader);
}
#endif
@@ -121,4 +125,37 @@ std::unique_ptr<SurfaceOzoneCanvas> X11SurfaceFactory::CreateCanvasForWidget(
return std::make_unique<X11CanvasSurface>(widget);
}
+scoped_refptr<gfx::NativePixmap> X11SurfaceFactory::CreateNativePixmap(
+ gfx::AcceleratedWidget widget,
+ VkDevice vk_device,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ base::Optional<gfx::Size> framebuffer_size) {
+ scoped_refptr<gfx::NativePixmapDmaBuf> pixmap;
+ auto buffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBuffer(
+ format, size, usage);
+ if (buffer) {
+ gfx::NativePixmapHandle handle = buffer->ExportHandle();
+ pixmap = base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format,
+ std::move(handle));
+ }
+
+ // CreateNativePixmap is non-blocking operation. Thus, it is safe to call it
+ // and return the result with the provided callback.
+ return pixmap;
+}
+
+void X11SurfaceFactory::CreateNativePixmapAsync(gfx::AcceleratedWidget widget,
+ VkDevice vk_device,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ NativePixmapCallback callback) {
+ // CreateNativePixmap is non-blocking operation. Thus, it is safe to call it
+ // and return the result with the provided callback.
+ std::move(callback).Run(
+ CreateNativePixmap(widget, vk_device, size, format, usage));
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_surface_factory.h b/chromium/ui/ozone/platform/x11/x11_surface_factory.h
index fb5431bf47a..70209cc94be 100644
--- a/chromium/ui/ozone/platform/x11/x11_surface_factory.h
+++ b/chromium/ui/ozone/platform/x11/x11_surface_factory.h
@@ -28,11 +28,25 @@ class X11SurfaceFactory : public SurfaceFactoryOzone {
GLOzone* GetGLOzone(gl::GLImplementation implementation) override;
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) override;
#endif
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget) override;
+ scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
+ gfx::AcceleratedWidget widget,
+ VkDevice vk_device,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ base::Optional<gfx::Size> framebuffer_size = base::nullopt) override;
+ void CreateNativePixmapAsync(gfx::AcceleratedWidget widget,
+ VkDevice vk_device,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ NativePixmapCallback callback) override;
private:
std::unique_ptr<GLOzone> glx_implementation_;
diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc b/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
index 07c43384e1a..63037c7c771 100644
--- a/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
+++ b/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
@@ -70,8 +70,7 @@ class X11WindowOzoneTest : public testing::Test {
~X11WindowOzoneTest() override = default;
void SetUp() override {
- auto* connection = x11::Connection::Get();
- event_source_ = std::make_unique<X11EventSource>(connection);
+ event_source_ = std::make_unique<X11EventSource>(x11::Connection::Get());
test_screen_ = new TestScreen();
display::Screen::SetScreenInstance(test_screen_);
@@ -96,7 +95,7 @@ class X11WindowOzoneTest : public testing::Test {
auto* device_event = event->As<x11::Input::DeviceEvent>();
DCHECK(device_event);
device_event->event = static_cast<x11::Window>(widget);
- event_source_->ProcessXEvent(event);
+ x11::Connection::Get()->DispatchEvent(*event);
}
X11WindowManager* window_manager() const {
diff --git a/chromium/ui/ozone/public/input_controller.cc b/chromium/ui/ozone/public/input_controller.cc
index 43e5fca8d2e..35fdf8c9a06 100644
--- a/chromium/ui/ozone/public/input_controller.cc
+++ b/chromium/ui/ozone/public/input_controller.cc
@@ -50,6 +50,9 @@ class StubInputController : public InputController {
void SuspendMouseAcceleration() override {}
void EndMouseAccelerationSuspension() override {}
void SetMouseScrollAcceleration(bool enabled) override {}
+ void SetPointingStickSensitivity(int value) override {}
+ void SetPointingStickPrimaryButtonRight(bool right) override {}
+ void SetPointingStickAcceleration(bool enabled) override {}
void SetTouchpadAcceleration(bool enabled) override {}
void SetTouchpadScrollAcceleration(bool enabled) override {}
void SetTapToClickPaused(bool state) override {}
diff --git a/chromium/ui/ozone/public/input_controller.h b/chromium/ui/ozone/public/input_controller.h
index 27b5ad3acd8..c18ba9c72ef 100644
--- a/chromium/ui/ozone/public/input_controller.h
+++ b/chromium/ui/ozone/public/input_controller.h
@@ -71,6 +71,9 @@ class COMPONENT_EXPORT(OZONE_BASE) InputController {
// Mouse settings.
virtual void SetMouseSensitivity(int value) = 0;
virtual void SetMouseScrollSensitivity(int value) = 0;
+
+ // Sets the primary button for the mouse. Passing true sets the right button
+ // as primary, while false (the default) sets the left as primary.
virtual void SetPrimaryButtonRight(bool right) = 0;
virtual void SetMouseReverseScroll(bool enabled) = 0;
virtual void SetMouseAcceleration(bool enabled) = 0;
@@ -78,6 +81,14 @@ class COMPONENT_EXPORT(OZONE_BASE) InputController {
virtual void EndMouseAccelerationSuspension() = 0;
virtual void SetMouseScrollAcceleration(bool enabled) = 0;
+ // Pointing stick settings.
+ virtual void SetPointingStickSensitivity(int value) = 0;
+
+ // Sets the primary button for the pointing stick. Passing true sets the right
+ // button as primary, while false (the default) sets the left as primary.
+ virtual void SetPointingStickPrimaryButtonRight(bool right) = 0;
+ virtual void SetPointingStickAcceleration(bool enabled) = 0;
+
// Touch log collection.
virtual void GetTouchDeviceStatus(GetTouchDeviceStatusReply reply) = 0;
virtual void GetTouchEventLog(const base::FilePath& out_dir,
diff --git a/chromium/ui/ozone/public/mojom/device_cursor.mojom b/chromium/ui/ozone/public/mojom/device_cursor.mojom
index a86e09970f0..f165e5eb833 100644
--- a/chromium/ui/ozone/public/mojom/device_cursor.mojom
+++ b/chromium/ui/ozone/public/mojom/device_cursor.mojom
@@ -15,11 +15,10 @@ interface DeviceCursor {
// Sets the cursor |bitmaps| on |window| at |point| with
// |frame_delay_ms|.
SetCursor(gfx.mojom.AcceleratedWidget window,
- array<skia.mojom.Bitmap> bitmaps,
+ array<skia.mojom.BitmapN32> bitmaps,
gfx.mojom.Point point,
int32 frame_delay_ms);
// Moves the cursor in |window| to |point|.
MoveCursor(gfx.mojom.AcceleratedWidget window, gfx.mojom.Point point);
};
-
diff --git a/chromium/ui/ozone/public/mojom/drm_device.mojom b/chromium/ui/ozone/public/mojom/drm_device.mojom
index caf4a7e5a7b..cf0e17009a1 100644
--- a/chromium/ui/ozone/public/mojom/drm_device.mojom
+++ b/chromium/ui/ozone/public/mojom/drm_device.mojom
@@ -51,11 +51,11 @@ interface DrmDevice {
// Instructs the GPU to abandon a DRM device.
RemoveGraphicsDevice(mojo_base.mojom.FilePath path);
- // Configures (Enables/Disables) DRM displays, returns a map: each configured
- // display ID to its status, true on success.
+ // Configures (Enables/Disables) DRM displays, returns whether or not the
+ // configuration was successful.
ConfigureNativeDisplays(
array<display.mojom.DisplayConfigurationParams> config_requests) =>
- (map<int64, bool> statuses);
+ (bool config_success);
// Gets high-definition content protection (HDCP) (DRM as in
// digital rights management) state.
diff --git a/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom b/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom
index 37fcaa56ace..1a99bc0bb98 100644
--- a/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom
+++ b/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom
@@ -33,7 +33,7 @@ interface WaylandBufferManagerHost {
// buffer, which is used to identify imported wl_buffers on the browser
// process side and map them with the buffer objects on the gpu process side.
// The buffer will be associated with an AcceleratedWidget as soon as the
- // very first CommitBuffer request comes from viz to browser process.
+ // very first CommitOverlays request comes from viz to browser process.
// If the buffer has been committed at least once, it is not possible to
// reassign it to another AcceleratedWidget.
CreateDmabufBasedBuffer(handle<platform> dmabuf_fd,
@@ -50,7 +50,7 @@ interface WaylandBufferManagerHost {
// The |length| is the length of the shared memory, |size|
// is the size of buffer and |buffer_id| is the id of the buffer.
// The buffer will be associated with an AcceleratedWidget as soon as the
- // very first CommitBuffer request comes from viz to browser process. If
+ // very first CommitOverlays request comes from viz to browser process. If
// the buffer has been committed at least once, it is not possible to
// reassign it to another AcceleratedWidget.
CreateShmBasedBuffer(handle<platform> shm_fd,
@@ -69,14 +69,6 @@ interface WaylandBufferManagerHost {
// |buffer_id| will result in the termination of the GPU process.
DestroyBuffer(gfx.mojom.AcceleratedWidget widget, uint32 buffer_id);
- // Attaches a wl_buffer to a WaylandWindow's surface with the following
- // |widget|. The |damage_region| describes the changed region of the buffer.
- // The |buffer_id| is a unique id for the buffer, which is used to
- // identify imported wl_buffers on the browser process side mapped with
- // the ones on the gpu process.
- CommitBuffer(gfx.mojom.AcceleratedWidget widget, uint32 buffer_id,
- gfx.mojom.Rect damage_region);
-
// Send overlay configurations for a frame to a WaylandWindow with the
// following |widget|.
CommitOverlays(gfx.mojom.AcceleratedWidget widget,
@@ -95,10 +87,14 @@ interface WaylandBufferManagerGpu {
// instance to avoid using zwp_linux_dmabuf protocol by setting
// |supports_dma_buf| to false, which results in using wl_egl_surface in a
// single process mode, and software rendering in a multiple process mode.
+ // |supports_acquire_fence| indicates whether acquire fences can be submitted
+ // with buffers for wayland servers to wait on before accessing buffer
+ // contents.
Initialize(pending_remote<WaylandBufferManagerHost> remote_host,
map<gfx.mojom.BufferFormat,
array<uint64>> buffer_formats_with_modifiers,
- bool supports_dma_buf);
+ bool supports_dma_buf,
+ bool supports_acquire_fence);
// Signals about swap completion.
OnSubmission(gfx.mojom.AcceleratedWidget widget,
diff --git a/chromium/ui/ozone/public/overlay_manager_ozone.h b/chromium/ui/ozone/public/overlay_manager_ozone.h
index 54e73e58933..c72edc50752 100644
--- a/chromium/ui/ozone/public/overlay_manager_ozone.h
+++ b/chromium/ui/ozone/public/overlay_manager_ozone.h
@@ -22,6 +22,15 @@ class OverlayManagerOzone {
// Get the hal struct to check for overlay support.
virtual std::unique_ptr<OverlayCandidatesOzone> CreateOverlayCandidates(
gfx::AcceleratedWidget w) = 0;
+
+ bool allow_sync_and_real_buffer_page_flip_testing() const {
+ return allow_sync_and_real_buffer_page_flip_testing_;
+ }
+
+ protected:
+ // TODO(fangzhoug): Some Chrome OS boards still use the legacy video decoder.
+ // Remove this once ChromeOSVideoDecoder is on everywhere.
+ bool allow_sync_and_real_buffer_page_flip_testing_ = false;
};
} // namespace ui
diff --git a/chromium/ui/ozone/public/overlay_surface_candidate.h b/chromium/ui/ozone/public/overlay_surface_candidate.h
index ebd82e96706..46b7e85d7f6 100644
--- a/chromium/ui/ozone/public/overlay_surface_candidate.h
+++ b/chromium/ui/ozone/public/overlay_surface_candidate.h
@@ -67,6 +67,8 @@ class COMPONENT_EXPORT(OZONE_BASE) OverlaySurfaceCandidate {
// To be modified by the implementer if this candidate can go into
// an overlay.
bool overlay_handled = false;
+ // If this candidate requires an overlay for proper display.
+ bool requires_overlay = false;
};
using OverlaySurfaceCandidateList = std::vector<OverlaySurfaceCandidate>;
diff --git a/chromium/ui/ozone/public/ozone_platform.cc b/chromium/ui/ozone/public/ozone_platform.cc
index 898a9c5c1b2..29fd78fa4c7 100644
--- a/chromium/ui/ozone/public/ozone_platform.cc
+++ b/chromium/ui/ozone/public/ozone_platform.cc
@@ -87,7 +87,7 @@ OzonePlatform* OzonePlatform::GetInstance() {
}
// static
-const char* OzonePlatform::GetPlatformName() {
+std::string OzonePlatform::GetPlatformNameForTest() {
return GetOzonePlatformName();
}
diff --git a/chromium/ui/ozone/public/ozone_platform.h b/chromium/ui/ozone/public/ozone_platform.h
index 739ffae079d..274915a23e7 100644
--- a/chromium/ui/ozone/public/ozone_platform.h
+++ b/chromium/ui/ozone/public/ozone_platform.h
@@ -6,6 +6,7 @@
#define UI_OZONE_PUBLIC_OZONE_PLATFORM_H_
#include <memory>
+#include <string>
#include <vector>
#include "base/callback.h"
@@ -69,6 +70,18 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
// operate as a single process for platforms (i.e. drm) that are usually
// split between a host and viz specific portion.
bool single_process = false;
+
+ // Setting this to true indicates the the platform can do additional
+ // initialization for the GpuMemoryBuffer framework.
+ bool enable_native_gpu_memory_buffers = false;
+
+ // The direct VideoDecoder is disallowed on some particular SoC/platforms.
+ // This flag is a reflection of whatever the ChromeOS command line builder
+ // says. If false, overlay manager will not use synchronous pageflip
+ // testing with real buffer.
+ // TODO(fangzhoug): Some Chrome OS boards still use the legacy video
+ // decoder. Remove this once ChromeOSVideoDecoder is on everywhere.
+ bool allow_sync_and_real_buffer_page_flip_testing = false;
};
// Struct used to indicate platform properties.
@@ -103,6 +116,13 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
// Determines if the platform supports vulkan swap chain.
bool supports_vulkan_swap_chain = false;
+ // Linux only: determines if the platform uses the external Vulkan image
+ // factory.
+ bool uses_external_vulkan_image_factory = false;
+
+ // Linux only: determines if Skia can fall back to the X11 output device.
+ bool skia_can_fall_back_to_x11 = false;
+
// Wayland only: determines if the client must ignore the screen bounds when
// calculating bounds of menu windows.
bool ignore_screen_bounds_for_menus = false;
@@ -121,6 +141,10 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
// Determines if the application modal dialogs should use the event blocker
// to allow the only browser window receiving UI events.
bool app_modal_dialogs_use_event_blocker = false;
+
+ // Determines whether buffer formats should be fetched on GPU and passed
+ // back via gpu extra info.
+ bool fetch_buffer_formats_for_gmb_on_gpu = false;
};
// Properties available in the host process after initialization.
@@ -168,12 +192,8 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
static OzonePlatform* GetInstance();
// Returns the current ozone platform name.
- // TODO(crbug.com/1002674): This is temporary and meant to make it possible
- // for higher level components to take run-time actions depending on the
- // current ozone platform selected. Which implies in layering violations,
- // which are tolerated during the X11 migration to Ozone and must be fixed
- // once it is done.
- static const char* GetPlatformName();
+ // Some tests may skip based on the platform name.
+ static std::string GetPlatformNameForTest();
// Factory getters to override in subclasses. The returned objects will be
// injected into the appropriate layer at startup. Subclasses should not
diff --git a/chromium/ui/ozone/public/ozone_switches.cc b/chromium/ui/ozone/public/ozone_switches.cc
index b9754475467..2d308f9ee30 100644
--- a/chromium/ui/ozone/public/ozone_switches.cc
+++ b/chromium/ui/ozone/public/ozone_switches.cc
@@ -15,6 +15,9 @@ const char kOzoneDumpFile[] = "ozone-dump-file";
// Try to enable wayland input method editor.
const char kEnableWaylandIme[] = "enable-wayland-ime";
+// Disable wayland input method editor.
+const char kDisableWaylandIme[] = "disable-wayland-ime";
+
// Disable explicit DMA-fences
const char kDisableExplicitDmaFences[] = "disable-explicit-dma-fences";
@@ -22,4 +25,7 @@ const char kDisableExplicitDmaFences[] = "disable-explicit-dma-fences";
const char kDisableRunningAsSystemCompositor[] =
"disable-running-as-system-compositor";
+// Disable buffer bandwidth compression
+const char kDisableBufferBWCompression[] = "disable-buffer-bw-compression";
+
} // namespace switches
diff --git a/chromium/ui/ozone/public/ozone_switches.h b/chromium/ui/ozone/public/ozone_switches.h
index 12dd34e2b51..baabdfdd8fe 100644
--- a/chromium/ui/ozone/public/ozone_switches.h
+++ b/chromium/ui/ozone/public/ozone_switches.h
@@ -16,11 +16,15 @@ COMPONENT_EXPORT(OZONE_BASE) extern const char kOzoneDumpFile[];
COMPONENT_EXPORT(OZONE_BASE) extern const char kEnableWaylandIme[];
+COMPONENT_EXPORT(OZONE_BASE) extern const char kDisableWaylandIme[];
+
COMPONENT_EXPORT(OZONE_BASE) extern const char kDisableExplicitDmaFences[];
COMPONENT_EXPORT(OZONE_BASE)
extern const char kDisableRunningAsSystemCompositor[];
+COMPONENT_EXPORT(OZONE_BASE) extern const char kDisableBufferBWCompression[];
+
} // namespace switches
#endif // UI_OZONE_PUBLIC_OZONE_SWITCHES_H_
diff --git a/chromium/ui/ozone/public/platform_gl_egl_utility.cc b/chromium/ui/ozone/public/platform_gl_egl_utility.cc
new file mode 100644
index 00000000000..38a135e4a0b
--- /dev/null
+++ b/chromium/ui/ozone/public/platform_gl_egl_utility.cc
@@ -0,0 +1,29 @@
+// Copyright 2020 The Chromium 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/public/platform_gl_egl_utility.h"
+
+#include "base/logging.h"
+#include "base/notreached.h"
+
+namespace ui {
+
+PlatformGLEGLUtility::PlatformGLEGLUtility() = default;
+
+PlatformGLEGLUtility::~PlatformGLEGLUtility() = default;
+
+bool PlatformGLEGLUtility::HasVisualManager() {
+ return false;
+}
+
+bool PlatformGLEGLUtility::UpdateVisualsOnGpuInfoChanged(
+ bool software_rendering,
+ uint32_t default_visual_id,
+ uint32_t transparent_visual_id) {
+ NOTREACHED() << "This must not be called if the platform does not support "
+ "X11 visuals.";
+ return false;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/public/platform_gl_egl_utility.h b/chromium/ui/ozone/public/platform_gl_egl_utility.h
index 96acbaf1ad9..568ea5644a7 100644
--- a/chromium/ui/ozone/public/platform_gl_egl_utility.h
+++ b/chromium/ui/ozone/public/platform_gl_egl_utility.h
@@ -18,7 +18,8 @@ namespace ui {
// Provides platform specific EGL attributes/configs.
class COMPONENT_EXPORT(OZONE_BASE) PlatformGLEGLUtility {
public:
- virtual ~PlatformGLEGLUtility() = default;
+ PlatformGLEGLUtility();
+ virtual ~PlatformGLEGLUtility();
// Gets additional display attributes based on |platform_type|.
virtual void GetAdditionalEGLAttributes(
@@ -41,6 +42,17 @@ class COMPONENT_EXPORT(OZONE_BASE) PlatformGLEGLUtility {
// X11 specific; returns whether the test configuration supports alpha for
// window visuals.
virtual bool X11DoesVisualHaveAlphaForTest() const = 0;
+
+ // X11 specific; returns whether the platform supports visuals.
+ virtual bool HasVisualManager();
+
+ // X11 specific; sets new visuals.
+ // Must be called only if the X11 visual manager is available.
+ // Should be called when the updated GPU info is available.
+ // Returns whether the visuals provided were valid.
+ virtual bool UpdateVisualsOnGpuInfoChanged(bool software_rendering,
+ uint32_t default_visual_id,
+ uint32_t transparent_visual_id);
};
} // namespace ui
diff --git a/chromium/ui/ozone/public/surface_factory_ozone.cc b/chromium/ui/ozone/public/surface_factory_ozone.cc
index e297254340f..c42cea806b1 100644
--- a/chromium/ui/ozone/public/surface_factory_ozone.cc
+++ b/chromium/ui/ozone/public/surface_factory_ozone.cc
@@ -35,7 +35,8 @@ GLOzone* SurfaceFactoryOzone::GetGLOzone(gl::GLImplementation implementation) {
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
-SurfaceFactoryOzone::CreateVulkanImplementation(bool allow_protected_memory,
+SurfaceFactoryOzone::CreateVulkanImplementation(bool use_swiftshader,
+ bool allow_protected_memory,
bool enforce_protected_memory) {
return nullptr;
}
diff --git a/chromium/ui/ozone/public/surface_factory_ozone.h b/chromium/ui/ozone/public/surface_factory_ozone.h
index 773537d40e4..c68f421852a 100644
--- a/chromium/ui/ozone/public/surface_factory_ozone.h
+++ b/chromium/ui/ozone/public/surface_factory_ozone.h
@@ -78,11 +78,14 @@ class COMPONENT_EXPORT(OZONE_BASE) SurfaceFactoryOzone {
#if BUILDFLAG(ENABLE_VULKAN)
// Creates the vulkan implementation. This object should be capable of
// creating surfaces that swap to a platform window.
+ // |use_swiftshader| suggests using Swiftshader. The actual support depends
+ // on the platform.
// |allow_protected_memory| suggests that the vulkan implementation should
// create protected-capable resources, such as VkQueue.
// |enforce_protected_memory| suggests that the vulkan implementation should
// always use protected memory and resources, such as CommandBuffers.
virtual std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory);
diff --git a/chromium/ui/platform_window/DEPS b/chromium/ui/platform_window/DEPS
index b51da65b022..baa2776c5d5 100644
--- a/chromium/ui/platform_window/DEPS
+++ b/chromium/ui/platform_window/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+third_party/skia/include",
"+ui/base",
"+ui/gfx",
]
diff --git a/chromium/ui/platform_window/DIR_METADATA b/chromium/ui/platform_window/DIR_METADATA
new file mode 100644
index 00000000000..d00c92336b8
--- /dev/null
+++ b/chromium/ui/platform_window/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals>PlatformIntegration"
+}
diff --git a/chromium/ui/platform_window/OWNERS b/chromium/ui/platform_window/OWNERS
deleted file mode 100644
index 700cb96a07e..00000000000
--- a/chromium/ui/platform_window/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# COMPONENT: Internals>PlatformIntegration
diff --git a/chromium/ui/platform_window/extensions/wayland_extension.h b/chromium/ui/platform_window/extensions/wayland_extension.h
index 36e34420ddb..810dce5d7ca 100644
--- a/chromium/ui/platform_window/extensions/wayland_extension.h
+++ b/chromium/ui/platform_window/extensions/wayland_extension.h
@@ -11,6 +11,12 @@ namespace ui {
class PlatformWindow;
+enum class WaylandWindowSnapDirection {
+ kNone,
+ kLeft,
+ kRight,
+};
+
class COMPONENT_EXPORT(PLATFORM_WINDOW) WaylandExtension {
public:
// Starts a window dragging session for the owning platform window, if
@@ -18,6 +24,21 @@ class COMPONENT_EXPORT(PLATFORM_WINDOW) WaylandExtension {
// platform drag-and-drop session.
virtual void StartWindowDraggingSessionIfNeeded() = 0;
+ // Signals the underneath platform that browser is entering (or exiting)
+ // 'immersive fullscreen mode'.
+ // Under lacros, it controls for instance interaction with the system shelf
+ // widget, when browser goes in fullscreen.
+ virtual void SetImmersiveFullscreenStatus(bool status) = 0;
+
+ // Signals the underneath platform to shows a preview for the given window
+ // snap direction.
+ virtual void ShowSnapPreview(WaylandWindowSnapDirection snap) = 0;
+
+ // Requests the underneath platform to snap the window in the given direction,
+ // if not WaylandWindowSnapDirection::kNone, otherwise cancels the window
+ // snapping.
+ virtual void CommitSnap(WaylandWindowSnapDirection snap) = 0;
+
protected:
virtual ~WaylandExtension();
diff --git a/chromium/ui/platform_window/extensions/x11_extension_delegate.h b/chromium/ui/platform_window/extensions/x11_extension_delegate.h
index 86ec59d2f14..381f29945aa 100644
--- a/chromium/ui/platform_window/extensions/x11_extension_delegate.h
+++ b/chromium/ui/platform_window/extensions/x11_extension_delegate.h
@@ -12,12 +12,6 @@
using AtkKeyEventStruct = struct _AtkKeyEventStruct;
#endif
-class SkPath;
-
-namespace gfx {
-class Size;
-}
-
namespace ui {
class COMPONENT_EXPORT(PLATFORM_WINDOW) X11ExtensionDelegate {
@@ -30,10 +24,6 @@ class COMPONENT_EXPORT(PLATFORM_WINDOW) X11ExtensionDelegate {
// (menu) windows.
virtual void OnLostMouseGrab() = 0;
- // Returns a mask to be used to clip the window for the given
- // size. This is used to create the non-rectangular window shape.
- virtual void GetWindowMask(const gfx::Size& size, SkPath* window_mask) = 0;
-
#if BUILDFLAG(USE_ATK)
// Notifies an ATK key event to be processed. The transient parameter will be
// true if the event target is a transient window (e.g. a modal dialog)
diff --git a/chromium/ui/platform_window/platform_window.cc b/chromium/ui/platform_window/platform_window.cc
index 19b5fc55ade..0560e2ef6ee 100644
--- a/chromium/ui/platform_window/platform_window.cc
+++ b/chromium/ui/platform_window/platform_window.cc
@@ -54,4 +54,8 @@ std::string PlatformWindow::GetWindowUniqueId() const {
return std::string();
}
+bool PlatformWindow::ShouldUseLayerForShapedWindow() const {
+ return false;
+}
+
} // namespace ui
diff --git a/chromium/ui/platform_window/platform_window.h b/chromium/ui/platform_window/platform_window.h
index 41452bace43..58262d37d59 100644
--- a/chromium/ui/platform_window/platform_window.h
+++ b/chromium/ui/platform_window/platform_window.h
@@ -145,6 +145,10 @@ class COMPONENT_EXPORT(PLATFORM_WINDOW) PlatformWindow
// Returns a unique ID for the window. The interpretation of the ID is
// platform specific. Overriding this method is optional.
virtual std::string GetWindowUniqueId() const;
+
+ // Returns true if window shape should be updated in layer,
+ // otherwise false when platform window updates the window shape.
+ virtual bool ShouldUseLayerForShapedWindow() const;
};
} // namespace ui
diff --git a/chromium/ui/platform_window/platform_window_delegate.cc b/chromium/ui/platform_window/platform_window_delegate.cc
index fb685b3852f..8947a82bf78 100644
--- a/chromium/ui/platform_window/platform_window_delegate.cc
+++ b/chromium/ui/platform_window/platform_window_delegate.cc
@@ -4,6 +4,7 @@
#include "ui/platform_window/platform_window_delegate.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/gfx/geometry/size.h"
namespace ui {
@@ -20,4 +21,8 @@ base::Optional<gfx::Size> PlatformWindowDelegate::GetMaximumSizeForWindow() {
return base::nullopt;
}
+SkPath PlatformWindowDelegate::GetWindowMaskForWindowShapeInPixels() {
+ return SkPath();
+}
+
} // namespace ui
diff --git a/chromium/ui/platform_window/platform_window_delegate.h b/chromium/ui/platform_window/platform_window_delegate.h
index 6ffdaa15b90..0de1b436dcf 100644
--- a/chromium/ui/platform_window/platform_window_delegate.h
+++ b/chromium/ui/platform_window/platform_window_delegate.h
@@ -14,6 +14,8 @@ class Rect;
class Size;
} // namespace gfx
+class SkPath;
+
namespace ui {
class Event;
@@ -63,6 +65,11 @@ class COMPONENT_EXPORT(PLATFORM_WINDOW) PlatformWindowDelegate {
virtual base::Optional<gfx::Size> GetMinimumSizeForWindow();
virtual base::Optional<gfx::Size> GetMaximumSizeForWindow();
+ // Returns a mask to be used to clip the window for the size of
+ // |WindowTreeHost::GetBoundsInPixels|.
+ // This is used to create the non-rectangular window shape.
+ virtual SkPath GetWindowMaskForWindowShapeInPixels();
+
// Called when the location of mouse pointer entered the window. This is
// different from ui::ET_MOUSE_ENTERED which may not be generated when mouse
// is captured either by implicitly or explicitly.
diff --git a/chromium/ui/platform_window/platform_window_init_properties.cc b/chromium/ui/platform_window/platform_window_init_properties.cc
index 706217e7a2f..e7d37c9e84b 100644
--- a/chromium/ui/platform_window/platform_window_init_properties.cc
+++ b/chromium/ui/platform_window/platform_window_init_properties.cc
@@ -9,8 +9,11 @@ namespace ui {
PlatformWindowInitProperties::PlatformWindowInitProperties() = default;
PlatformWindowInitProperties::PlatformWindowInitProperties(
- const gfx::Rect& bounds)
- : bounds(bounds) {}
+ const gfx::Rect& bounds,
+ bool to_enable_compositing_based_throttling)
+ : bounds(bounds),
+ enable_compositing_based_throttling(
+ to_enable_compositing_based_throttling) {}
PlatformWindowInitProperties::PlatformWindowInitProperties(
PlatformWindowInitProperties&& props) = default;
diff --git a/chromium/ui/platform_window/platform_window_init_properties.h b/chromium/ui/platform_window/platform_window_init_properties.h
index faf1c2a8525..d1953619790 100644
--- a/chromium/ui/platform_window/platform_window_init_properties.h
+++ b/chromium/ui/platform_window/platform_window_init_properties.h
@@ -39,6 +39,12 @@ enum class PlatformWindowOpacity {
kTranslucentWindow,
};
+enum class PlatformWindowShadowType {
+ kDefault,
+ kNone,
+ kDrop,
+};
+
class WorkspaceExtensionDelegate;
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
@@ -51,7 +57,9 @@ struct COMPONENT_EXPORT(PLATFORM_WINDOW) PlatformWindowInitProperties {
PlatformWindowInitProperties();
// Initializes properties with the specified |bounds|.
- explicit PlatformWindowInitProperties(const gfx::Rect& bounds);
+ explicit PlatformWindowInitProperties(
+ const gfx::Rect& bounds,
+ bool enable_compositing_based_throttling = false);
PlatformWindowInitProperties(PlatformWindowInitProperties&& props);
@@ -83,6 +91,8 @@ struct COMPONENT_EXPORT(PLATFORM_WINDOW) PlatformWindowInitProperties {
WorkspaceExtensionDelegate* workspace_extension_delegate = nullptr;
+ PlatformWindowShadowType shadow_type = PlatformWindowShadowType::kDefault;
+
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
bool prefer_dark_theme = false;
gfx::ImageSkia* icon = nullptr;
@@ -97,6 +107,8 @@ struct COMPONENT_EXPORT(PLATFORM_WINDOW) PlatformWindowInitProperties {
X11ExtensionDelegate* x11_extension_delegate = nullptr;
#endif
+
+ bool enable_compositing_based_throttling = false;
};
} // namespace ui
diff --git a/chromium/ui/platform_window/win/BUILD.gn b/chromium/ui/platform_window/win/BUILD.gn
index 519c51c2821..bf545a46ddb 100644
--- a/chromium/ui/platform_window/win/BUILD.gn
+++ b/chromium/ui/platform_window/win/BUILD.gn
@@ -9,6 +9,7 @@ component("win") {
"//base",
"//skia",
"//ui/base",
+ "//ui/base/cursor",
"//ui/events",
"//ui/gfx",
"//ui/gfx/geometry",
diff --git a/chromium/ui/platform_window/win/win_window.cc b/chromium/ui/platform_window/win/win_window.cc
index 96acebd7f29..cf00aaeb770 100644
--- a/chromium/ui/platform_window/win/win_window.cc
+++ b/chromium/ui/platform_window/win/win_window.cc
@@ -8,6 +8,8 @@
#include <memory>
#include "base/strings/string16.h"
+#include "base/strings/string_util_win.h"
+#include "ui/base/cursor/win/win_cursor.h"
#include "ui/base/win/shell.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
@@ -100,7 +102,7 @@ gfx::Rect WinWindow::GetBounds() const {
}
void WinWindow::SetTitle(const base::string16& title) {
- SetWindowText(hwnd(), title.c_str());
+ SetWindowText(hwnd(), base::as_wcstr(title));
}
void WinWindow::SetCapture() {
@@ -145,7 +147,8 @@ bool WinWindow::ShouldUseNativeFrame() const {
}
void WinWindow::SetCursor(PlatformCursor cursor) {
- ::SetCursor(cursor);
+ DCHECK(cursor);
+ ::SetCursor(static_cast<WinCursor*>(cursor)->hcursor());
}
void WinWindow::MoveCursorTo(const gfx::Point& location) {
diff --git a/chromium/ui/platform_window/x11/BUILD.gn b/chromium/ui/platform_window/x11/BUILD.gn
index 1e1e9cf1c65..5b47c902e7d 100644
--- a/chromium/ui/platform_window/x11/BUILD.gn
+++ b/chromium/ui/platform_window/x11/BUILD.gn
@@ -13,6 +13,7 @@ component("x11") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//skia",
"//ui/base",
"//ui/base/x",
@@ -62,6 +63,7 @@ test("x11_unittests") {
":x11",
"//base/test:run_all_unittests",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//skia",
"//testing/gmock",
"//testing/gtest",
diff --git a/chromium/ui/platform_window/x11/atk_event_conversion.cc b/chromium/ui/platform_window/x11/atk_event_conversion.cc
index 88e4b0fad5d..882d846602f 100644
--- a/chromium/ui/platform_window/x11/atk_event_conversion.cc
+++ b/chromium/ui/platform_window/x11/atk_event_conversion.cc
@@ -14,11 +14,10 @@
namespace ui {
std::unique_ptr<AtkKeyEventStruct> AtkKeyEventFromXEvent(
- x11::Event* x11_event) {
- DCHECK(x11_event);
+ const x11::Event& x11_event) {
auto atk_key_event = std::make_unique<AtkKeyEventStruct>();
- auto* xkey = x11_event->As<x11::KeyEvent>();
+ auto* xkey = x11_event.As<x11::KeyEvent>();
DCHECK(xkey);
atk_key_event->type = xkey->opcode == x11::KeyEvent::Press
@@ -39,7 +38,7 @@ std::unique_ptr<AtkKeyEventStruct> AtkKeyEventFromXEvent(
atk_key_event->string = nullptr;
atk_key_event->length = 0;
- int flags = ui::EventFlagsFromXEvent(*x11_event);
+ int flags = ui::EventFlagsFromXEvent(x11_event);
if (flags & ui::EF_SHIFT_DOWN)
atk_key_event->state |= AtkKeyModifierMask::kAtkShiftMask;
if (flags & ui::EF_CAPS_LOCK_ON)
diff --git a/chromium/ui/platform_window/x11/atk_event_conversion.h b/chromium/ui/platform_window/x11/atk_event_conversion.h
index 84226a4e157..5741dbcc25c 100644
--- a/chromium/ui/platform_window/x11/atk_event_conversion.h
+++ b/chromium/ui/platform_window/x11/atk_event_conversion.h
@@ -27,7 +27,7 @@ typedef enum {
KAtkMod5Mask = 1 << 7,
} AtkKeyModifierMask;
-std::unique_ptr<AtkKeyEventStruct> AtkKeyEventFromXEvent(x11::Event* xev);
+std::unique_ptr<AtkKeyEventStruct> AtkKeyEventFromXEvent(const x11::Event& xev);
} // namespace ui
diff --git a/chromium/ui/platform_window/x11/x11_window.cc b/chromium/ui/platform_window/x11/x11_window.cc
index 4e5c3ddfd63..967dd5f1c09 100644
--- a/chromium/ui/platform_window/x11/x11_window.cc
+++ b/chromium/ui/platform_window/x11/x11_window.cc
@@ -6,6 +6,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/trace_event/trace_event.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/buildflags.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/ui_base_features.h"
@@ -23,7 +24,7 @@
#include "ui/events/platform/platform_event_source.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/events/x/x11_event_translation.h"
-#include "ui/events/x/x11_window_event_manager.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
#include "ui/platform_window/common/platform_window_defaults.h"
#include "ui/platform_window/extensions/workspace_extension_delegate.h"
#include "ui/platform_window/extensions/x11_extension_delegate.h"
@@ -98,11 +99,11 @@ ui::XWindow::Configuration ConvertInitPropertiesToXWindowConfig(
}
// Coalesce touch/mouse events if needed
-bool CoalesceEventsIfNeeded(x11::Event* const xev,
+bool CoalesceEventsIfNeeded(const x11::Event& xev,
EventType type,
x11::Event* out) {
- if (xev->As<x11::MotionNotifyEvent>() ||
- (xev->As<x11::Input::DeviceEvent>() &&
+ if (xev.As<x11::MotionNotifyEvent>() ||
+ (xev.As<x11::Input::DeviceEvent>() &&
(type == ui::ET_TOUCH_MOVED || type == ui::ET_MOUSE_MOVED ||
type == ui::ET_MOUSE_DRAGGED))) {
return ui::CoalescePendingMotionEvents(xev, out) > 0;
@@ -214,8 +215,9 @@ bool X11Window::IsVisible() const {
}
void X11Window::PrepareForShutdown() {
+ connection()->RemoveEventObserver(this);
DCHECK(X11EventSource::HasInstance());
- X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+ X11EventSource::GetInstance()->RemovePlatformEventDispatcher(this);
}
void X11Window::SetBounds(const gfx::Rect& bounds) {
@@ -526,63 +528,37 @@ void X11Window::SetX11ExtensionDelegate(X11ExtensionDelegate* delegate) {
x11_extension_delegate_ = delegate;
}
-bool X11Window::HandleAsAtkEvent(x11::Event* x11_event, bool transient) {
+bool X11Window::HandleAsAtkEvent(const x11::Event& x11_event, bool transient) {
#if !BUILDFLAG(USE_ATK)
// TODO(crbug.com/1014934): Support ATK in Ozone/X11.
NOTREACHED();
return false;
#else
- DCHECK(x11_event);
- if (!x11_extension_delegate_ || !x11_event->As<x11::KeyEvent>())
+ if (!x11_extension_delegate_ || !x11_event.As<x11::KeyEvent>())
return false;
auto atk_key_event = AtkKeyEventFromXEvent(x11_event);
return x11_extension_delegate_->OnAtkKeyEvent(atk_key_event.get(), transient);
#endif
}
-// CheckCanDispatchNextPlatformEvent is called by X11EventSource so that
-// X11Window (XEventDispatcher implementation) can inspect |xev| and determine
-// whether it should be dispatched by this window once it gets translated into a
-// PlatformEvent.
-void X11Window::CheckCanDispatchNextPlatformEvent(x11::Event* xev) {
- if (is_shutting_down_)
- return;
- if (XWindow::IsTargetedBy(*xev)) {
- current_xevent_ = xev;
- return;
- }
- if (XWindow::IsTransientWindowTargetedBy(*xev)) {
- current_xevent_ = xev;
- current_xevent_target_transient_ = true;
- }
-}
-
-void X11Window::PlatformEventDispatchFinished() {
- current_xevent_ = nullptr;
- current_xevent_target_transient_ = false;
-}
-
-PlatformEventDispatcher* X11Window::GetPlatformEventDispatcher() {
- return this;
-}
-
-bool X11Window::DispatchXEvent(x11::Event* xev) {
- auto* prop = xev->As<x11::PropertyNotifyEvent>();
+void X11Window::OnEvent(const x11::Event& xev) {
+ auto* prop = xev.As<x11::PropertyNotifyEvent>();
auto* target_current_context = drag_drop_client_->target_current_context();
if (prop && target_current_context &&
prop->window == target_current_context->source_window()) {
- return target_current_context->DispatchPropertyNotifyEvent(*prop);
+ target_current_context->DispatchPropertyNotifyEvent(*prop);
}
- if (!XWindow::IsTargetedBy(*xev))
- return false;
- XWindow::ProcessEvent(xev);
- return true;
+ if (XWindow::IsTargetedBy(xev))
+ XWindow::OnEvent(xev);
}
bool X11Window::CanDispatchEvent(const PlatformEvent& xev) {
+ if (is_shutting_down_)
+ return false;
DCHECK_NE(window(), x11::Window::None);
- return !!current_xevent_;
+ auto* dispatching_event = connection()->dispatching_event();
+ return dispatching_event && XWindow::IsTargetedBy(*dispatching_event);
}
uint32_t X11Window::DispatchEvent(const PlatformEvent& event) {
@@ -591,27 +567,30 @@ uint32_t X11Window::DispatchEvent(const PlatformEvent& event) {
DCHECK_NE(window(), x11::Window::None);
DCHECK(event);
- DCHECK(current_xevent_);
+
+ auto& current_xevent = *connection()->dispatching_event();
if (event->IsMouseEvent())
X11WindowManager::GetInstance()->MouseOnWindow(this);
#if BUILDFLAG(USE_ATK)
// TODO(crbug.com/1014934): Support ATK in Ozone/X11.
- if (HandleAsAtkEvent(current_xevent_, current_xevent_target_transient_))
+ bool current_xevent_target_transient =
+ XWindow::IsTransientWindowTargetedBy(current_xevent);
+ if (HandleAsAtkEvent(current_xevent, current_xevent_target_transient))
return POST_DISPATCH_STOP_PROPAGATION;
#endif
- DispatchUiEvent(event, current_xevent_);
+ DispatchUiEvent(event, current_xevent);
return POST_DISPATCH_STOP_PROPAGATION;
}
-void X11Window::DispatchUiEvent(ui::Event* event, x11::Event* xev) {
+void X11Window::DispatchUiEvent(ui::Event* event, const x11::Event& xev) {
auto* window_manager = X11WindowManager::GetInstance();
DCHECK(window_manager);
// Process X11-specific bits
- if (XWindow::IsTargetedBy(*xev))
- XWindow::ProcessEvent(xev);
+ if (XWindow::IsTargetedBy(xev))
+ XWindow::OnEvent(xev);
// If |event| is a located event (mouse, touch, etc) and another X11 window
// is set as the current located events grabber, the |event| must be
@@ -632,8 +611,7 @@ void X11Window::DispatchUiEvent(ui::Event* event, x11::Event* xev) {
x11::Event last_xev;
std::unique_ptr<ui::Event> last_motion;
- bool coalesced = CoalesceEventsIfNeeded(xev, event->type(), &last_xev);
- if (coalesced) {
+ if (CoalesceEventsIfNeeded(xev, event->type(), &last_xev)) {
last_motion = ui::BuildEventFromXEvent(last_xev);
event = last_motion.get();
}
@@ -665,8 +643,9 @@ void X11Window::DispatchUiEvent(ui::Event* event, x11::Event* xev) {
void X11Window::OnXWindowCreated() {
X11WindowManager::GetInstance()->AddWindow(this);
+ connection()->AddEventObserver(this);
DCHECK(X11EventSource::HasInstance());
- X11EventSource::GetInstance()->AddXEventDispatcher(this);
+ X11EventSource::GetInstance()->AddPlatformEventDispatcher(this);
x11_window_move_client_ =
std::make_unique<ui::X11DesktopWindowMoveClient>(this);
@@ -762,18 +741,18 @@ void X11Window::OnXWindowLostPointerGrab() {
x11_extension_delegate_->OnLostMouseGrab();
}
-void X11Window::OnXWindowSelectionEvent(x11::Event* xev) {
+void X11Window::OnXWindowSelectionEvent(const x11::SelectionNotifyEvent& xev) {
if (x_event_delegate_)
x_event_delegate_->OnXWindowSelectionEvent(xev);
DCHECK(drag_drop_client_);
- drag_drop_client_->OnSelectionNotify(*xev->As<x11::SelectionNotifyEvent>());
+ drag_drop_client_->OnSelectionNotify(xev);
}
-void X11Window::OnXWindowDragDropEvent(x11::Event* xev) {
+void X11Window::OnXWindowDragDropEvent(const x11::ClientMessageEvent& xev) {
if (x_event_delegate_)
x_event_delegate_->OnXWindowDragDropEvent(xev);
DCHECK(drag_drop_client_);
- drag_drop_client_->HandleXdndEvent(*xev->As<x11::ClientMessageEvent>());
+ drag_drop_client_->HandleXdndEvent(xev);
}
base::Optional<gfx::Size> X11Window::GetMinimumSizeForXWindow() {
@@ -784,10 +763,8 @@ base::Optional<gfx::Size> X11Window::GetMaximumSizeForXWindow() {
return platform_window_delegate_->GetMaximumSizeForWindow();
}
-void X11Window::GetWindowMaskForXWindow(const gfx::Size& size,
- SkPath* window_mask) {
- if (x11_extension_delegate_)
- x11_extension_delegate_->GetWindowMask(size, window_mask);
+SkPath X11Window::GetWindowMaskForXWindow() {
+ return platform_window_delegate_->GetWindowMaskForWindowShapeInPixels();
}
void X11Window::DispatchHostWindowDragMovement(
@@ -885,7 +862,7 @@ void X11Window::UpdateCursor(
void X11Window::OnBeginForeignDrag(x11::Window window) {
notified_enter_ = false;
- source_window_events_ = std::make_unique<ui::XScopedEventSelector>(
+ source_window_events_ = std::make_unique<x11::XScopedEventSelector>(
window, x11::EventMask::PropertyChange);
}
@@ -945,7 +922,7 @@ void X11Window::QuitDragLoop() {
gfx::Size X11Window::AdjustSizeForDisplay(
const gfx::Size& requested_size_in_pixels) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// We do not need to apply the workaround for the ChromeOS.
return requested_size_in_pixels;
#else
diff --git a/chromium/ui/platform_window/x11/x11_window.h b/chromium/ui/platform_window/x11/x11_window.h
index e5ebe7f14a0..4693ac5f148 100644
--- a/chromium/ui/platform_window/x11/x11_window.h
+++ b/chromium/ui/platform_window/x11/x11_window.h
@@ -10,7 +10,6 @@
#include "ui/base/x/x11_move_loop_delegate.h"
#include "ui/base/x/x11_window.h"
#include "ui/events/platform/platform_event_dispatcher.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/event.h"
#include "ui/platform_window/extensions/workspace_extension.h"
#include "ui/platform_window/extensions/x11_extension.h"
@@ -38,8 +37,9 @@ class X11_WINDOW_EXPORT XEventDelegate {
// TODO(crbug.com/990756): We need to implement/reuse ozone interface for
// these.
- virtual void OnXWindowSelectionEvent(x11::Event* xev) = 0;
- virtual void OnXWindowDragDropEvent(x11::Event* xev) = 0;
+ virtual void OnXWindowSelectionEvent(
+ const x11::SelectionNotifyEvent& xev) = 0;
+ virtual void OnXWindowDragDropEvent(const x11::ClientMessageEvent& xev) = 0;
};
// PlatformWindow implementation for X11.
@@ -47,7 +47,7 @@ class X11_WINDOW_EXPORT X11Window : public PlatformWindow,
public WmMoveResizeHandler,
public XWindow,
public PlatformEventDispatcher,
- public XEventDispatcher,
+ public x11::EventObserver,
public WorkspaceExtension,
public X11Extension,
public WmDragHandler,
@@ -128,11 +128,8 @@ class X11_WINDOW_EXPORT X11Window : public PlatformWindow,
void SetOverrideRedirect(bool override_redirect) override;
void SetX11ExtensionDelegate(X11ExtensionDelegate* delegate) override;
- // Overridden from ui::XEventDispatcher:
- void CheckCanDispatchNextPlatformEvent(x11::Event* xev) override;
- void PlatformEventDispatchFinished() override;
- PlatformEventDispatcher* GetPlatformEventDispatcher() override;
- bool DispatchXEvent(x11::Event* event) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& event) override;
protected:
PlatformWindowDelegate* platform_window_delegate() const {
@@ -152,19 +149,18 @@ class X11_WINDOW_EXPORT X11Window : public PlatformWindow,
void OnXWindowIsActiveChanged(bool active) override;
void OnXWindowWorkspaceChanged() override;
void OnXWindowLostPointerGrab() override;
- void OnXWindowSelectionEvent(x11::Event* xev) override;
- void OnXWindowDragDropEvent(x11::Event* xev) override;
+ void OnXWindowSelectionEvent(const x11::SelectionNotifyEvent& xev) override;
+ void OnXWindowDragDropEvent(const x11::ClientMessageEvent& xev) override;
base::Optional<gfx::Size> GetMinimumSizeForXWindow() override;
base::Optional<gfx::Size> GetMaximumSizeForXWindow() override;
- void GetWindowMaskForXWindow(const gfx::Size& size,
- SkPath* window_mask) override;
+ SkPath GetWindowMaskForXWindow() override;
private:
// PlatformEventDispatcher:
bool CanDispatchEvent(const PlatformEvent& event) override;
uint32_t DispatchEvent(const PlatformEvent& event) override;
- void DispatchUiEvent(ui::Event* event, x11::Event* xev);
+ void DispatchUiEvent(ui::Event* event, const x11::Event& xev);
// WmMoveResizeHandler
void DispatchHostWindowDragMovement(
@@ -203,7 +199,7 @@ class X11_WINDOW_EXPORT X11Window : public PlatformWindow,
void QuitDragLoop();
// Handles |xevent| as a Atk Key Event
- bool HandleAsAtkEvent(x11::Event* xevent, bool transient);
+ bool HandleAsAtkEvent(const x11::Event& xevent, bool transient);
// Adjusts |requested_size_in_pixels| to avoid the WM "feature" where setting
// the window size to the monitor size causes the WM to set the EWMH for
@@ -238,15 +234,6 @@ class X11_WINDOW_EXPORT X11Window : public PlatformWindow,
// The bounds of our window before the window was maximized.
gfx::Rect restored_bounds_in_pixels_;
- // Tells if this dispatcher can process next translated event based on a
- // previous check in ::CheckCanDispatchNextPlatformEvent based on a
- // x11::Window target.
- x11::Event* current_xevent_ = nullptr;
-
- // True if the current_xevent_ target is not this window but a transient
- // window that hangs from this one.
- bool current_xevent_target_transient_ = false;
-
std::unique_ptr<X11DesktopWindowMoveClient> x11_window_move_client_;
// Whether the drop handler has notified that the drag has entered.
@@ -262,7 +249,7 @@ class X11_WINDOW_EXPORT X11Window : public PlatformWindow,
std::unique_ptr<X11MoveLoop> drag_loop_;
// Events that we have selected on the source window of the incoming drag.
- std::unique_ptr<ui::XScopedEventSelector> source_window_events_;
+ std::unique_ptr<x11::XScopedEventSelector> source_window_events_;
base::WeakPtrFactory<X11Window> weak_ptr_factory_{this};
diff --git a/chromium/ui/platform_window/x11/x11_window_manager.cc b/chromium/ui/platform_window/x11/x11_window_manager.cc
index 5aef03785b8..97d36a33e24 100644
--- a/chromium/ui/platform_window/x11/x11_window_manager.cc
+++ b/chromium/ui/platform_window/x11/x11_window_manager.cc
@@ -4,7 +4,7 @@
#include "ui/platform_window/x11/x11_window_manager.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "ui/platform_window/x11/x11_window.h"
namespace ui {
diff --git a/chromium/ui/resources/BUILD.gn b/chromium/ui/resources/BUILD.gn
index b9762945654..1182b83714b 100644
--- a/chromium/ui/resources/BUILD.gn
+++ b/chromium/ui/resources/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//tools/grit/grit_rule.gni")
import("//tools/grit/repack.gni")
import("//ui/webui/webui_features.gni")
@@ -40,7 +41,7 @@ grit("webui_resources_grd") {
source = "../webui/resources/webui_resources.grd"
deps = [ "//ui/webui/resources:modulize" ]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//ui/chromeos/colors:cros_colors_css" ]
}
@@ -153,7 +154,7 @@ repack("repack_ui_test_pak_100_percent") {
"$root_gen_dir/ui/strings/ui_strings_en-US.pak",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [
"$root_gen_dir/ui/chromeos/resources/ui_chromeos_resources_100_percent.pak",
"$root_gen_dir/ui/chromeos/strings/ui_chromeos_strings_en-US.pak",
@@ -176,7 +177,7 @@ repack("repack_ui_test_pak_100_percent") {
deps += [ ":copy_ui_resources_100_percent" ]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [
"//ui/chromeos/resources",
"//ui/chromeos/strings",
diff --git a/chromium/ui/resources/DIR_METADATA b/chromium/ui/resources/DIR_METADATA
new file mode 100644
index 00000000000..f31293e3139
--- /dev/null
+++ b/chromium/ui/resources/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI"
+}
diff --git a/chromium/ui/resources/OWNERS b/chromium/ui/resources/OWNERS
index 501a708ca62..39929b0e02c 100644
--- a/chromium/ui/resources/OWNERS
+++ b/chromium/ui/resources/OWNERS
@@ -2,5 +2,3 @@ oshima@chromium.org
# For WebUI related GN targets.
per-file BUILD.gn=file://ui/webui/PLATFORM_OWNERS
-
-# COMPONENT: UI
diff --git a/chromium/ui/shell_dialogs/BUILD.gn b/chromium/ui/shell_dialogs/BUILD.gn
index 24a925dd7f1..a7ef6364dc0 100644
--- a/chromium/ui/shell_dialogs/BUILD.gn
+++ b/chromium/ui/shell_dialogs/BUILD.gn
@@ -57,6 +57,7 @@ component("shell_dialogs") {
deps = [
"//base",
"//base:i18n",
+ "//build:chromeos_buildflags",
"//skia",
"//ui/base",
"//ui/strings",
@@ -101,8 +102,8 @@ component("shell_dialogs") {
sources += [ "select_file_dialog_fuchsia.cc" ]
}
- # TODO(crbug.com/1052397): Rename chromeos_is_browser_only.
- if (chromeos_is_browser_only) {
+ # TODO(crbug.com/1052397): Rename is_chromeos_lacros.
+ if (is_chromeos_lacros) {
sources += [
"select_file_dialog_lacros.cc",
"select_file_dialog_lacros.h",
diff --git a/chromium/ui/shell_dialogs/DIR_METADATA b/chromium/ui/shell_dialogs/DIR_METADATA
new file mode 100644
index 00000000000..d00c92336b8
--- /dev/null
+++ b/chromium/ui/shell_dialogs/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals>PlatformIntegration"
+}
diff --git a/chromium/ui/shell_dialogs/OWNERS b/chromium/ui/shell_dialogs/OWNERS
index 7179f1f92fe..051e54938f3 100644
--- a/chromium/ui/shell_dialogs/OWNERS
+++ b/chromium/ui/shell_dialogs/OWNERS
@@ -4,4 +4,3 @@ per-file *android*=qinmin@chromium.org
per-file *lacros*=file://chromeos/LACROS_OWNERS
per-file *win*=robliao@chromium.org
-# COMPONENT: Internals>PlatformIntegration
diff --git a/chromium/ui/shell_dialogs/execute_select_file_win.cc b/chromium/ui/shell_dialogs/execute_select_file_win.cc
index 22f5eed21a0..7b5a8506a9c 100644
--- a/chromium/ui/shell_dialogs/execute_select_file_win.cc
+++ b/chromium/ui/shell_dialogs/execute_select_file_win.cc
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
+#include "base/strings/string_util.h"
#include "base/win/com_init_util.h"
#include "base/win/registry.h"
#include "base/win/scoped_co_mem.h"
@@ -30,7 +31,7 @@ bool IsDirectory(const base::FilePath& path) {
}
// Given |extension|, if it's not empty, then remove the leading dot.
-base::string16 GetExtensionWithoutLeadingDot(const base::string16& extension) {
+std::wstring GetExtensionWithoutLeadingDot(const std::wstring& extension) {
DCHECK(extension.empty() || extension[0] == L'.');
return extension.empty() ? extension : extension.substr(1);
}
@@ -76,8 +77,8 @@ bool SetFilters(IFileDialog* file_dialog,
std::vector<COMDLG_FILTERSPEC> comdlg_filterspec(filter.size());
for (size_t i = 0; i < filter.size(); ++i) {
- comdlg_filterspec[i].pszName = filter[i].description.c_str();
- comdlg_filterspec[i].pszSpec = filter[i].extension_spec.c_str();
+ comdlg_filterspec[i].pszName = base::as_wcstr(filter[i].description);
+ comdlg_filterspec[i].pszSpec = base::as_wcstr(filter[i].extension_spec);
}
return SUCCEEDED(file_dialog->SetFileTypes(comdlg_filterspec.size(),
@@ -108,12 +109,12 @@ bool ConfigureDialog(IFileDialog* file_dialog,
DWORD dialog_options) {
// Set title.
if (!title.empty()) {
- if (FAILED(file_dialog->SetTitle(title.c_str())))
+ if (FAILED(file_dialog->SetTitle(base::as_wcstr(title))))
return false;
}
if (!ok_button_label.empty()) {
- if (FAILED(file_dialog->SetOkButtonLabel(ok_button_label.c_str())))
+ if (FAILED(file_dialog->SetOkButtonLabel(base::as_wcstr(ok_button_label))))
return false;
}
@@ -137,7 +138,7 @@ bool RunSaveFileDialog(HWND owner,
const base::FilePath& default_path,
const std::vector<FileFilterSpec>& filter,
DWORD dialog_options,
- const base::string16& def_ext,
+ const std::wstring& def_ext,
int* filter_index,
base::FilePath* path) {
Microsoft::WRL::ComPtr<IFileSaveDialog> file_save_dialog;
@@ -312,7 +313,7 @@ bool ExecuteSelectMultipleFile(HWND owner,
bool ExecuteSaveFile(HWND owner,
const base::FilePath& default_path,
const std::vector<FileFilterSpec>& filter,
- const base::string16& def_ext,
+ const std::wstring& def_ext,
int* filter_index,
base::FilePath* path) {
DCHECK(path);
@@ -340,20 +341,20 @@ bool ExecuteSaveFile(HWND owner,
// '*.something', for example '*.*' or it can be blank (which is treated as
// *.*). |suggested_ext| should contain the extension without the dot (.) in
// front, for example 'jpg'.
-base::string16 AppendExtensionIfNeeded(const base::string16& filename,
- const base::string16& filter_selected,
- const base::string16& suggested_ext) {
+std::wstring AppendExtensionIfNeeded(const std::wstring& filename,
+ const std::wstring& filter_selected,
+ const std::wstring& suggested_ext) {
DCHECK(!filename.empty());
- base::string16 return_value = filename;
+ std::wstring return_value = filename;
// If we wanted a specific extension, but the user's filename deleted it or
// changed it to something that the system doesn't understand, re-append.
// Careful: Checking net::GetMimeTypeFromExtension() will only find
// extensions with a known MIME type, which many "known" extensions on Windows
// don't have. So we check directly for the "known extension" registry key.
- base::string16 file_extension(
+ std::wstring file_extension(
GetExtensionWithoutLeadingDot(base::FilePath(filename).Extension()));
- base::string16 key(L"." + file_extension);
+ std::wstring key(L"." + file_extension);
if (!(filter_selected.empty() || filter_selected == L"*.*") &&
!base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).Valid() &&
file_extension != suggested_ext) {
@@ -376,7 +377,7 @@ void ExecuteSelectFile(
const base::FilePath& default_path,
const std::vector<FileFilterSpec>& filter,
int file_type_index,
- const base::string16& default_extension,
+ const std::wstring& default_extension,
HWND owner,
OnSelectFileExecutedCallback on_select_file_executed_callback) {
base::win::AssertComInitialized();
diff --git a/chromium/ui/shell_dialogs/execute_select_file_win.h b/chromium/ui/shell_dialogs/execute_select_file_win.h
index 4d2880be039..74735f6259e 100644
--- a/chromium/ui/shell_dialogs/execute_select_file_win.h
+++ b/chromium/ui/shell_dialogs/execute_select_file_win.h
@@ -21,10 +21,10 @@ class FilePath;
namespace ui {
// Implementation detail exported for unit tests.
-SHELL_DIALOGS_EXPORT base::string16 AppendExtensionIfNeeded(
- const base::string16& filename,
- const base::string16& filter_selected,
- const base::string16& suggested_ext);
+SHELL_DIALOGS_EXPORT std::wstring AppendExtensionIfNeeded(
+ const std::wstring& filename,
+ const std::wstring& filter_selected,
+ const std::wstring& suggested_ext);
// Describes a filter for a file dialog.
struct FileFilterSpec {
@@ -49,7 +49,7 @@ void ExecuteSelectFile(
const base::FilePath& default_path,
const std::vector<FileFilterSpec>& filter,
int file_type_index,
- const base::string16& default_extension,
+ const std::wstring& default_extension,
HWND owner,
OnSelectFileExecutedCallback on_select_file_executed_callback);
diff --git a/chromium/ui/shell_dialogs/execute_select_file_win_unittest.cc b/chromium/ui/shell_dialogs/execute_select_file_win_unittest.cc
index 6f13dd770b6..d7c915b97f2 100644
--- a/chromium/ui/shell_dialogs/execute_select_file_win_unittest.cc
+++ b/chromium/ui/shell_dialogs/execute_select_file_win_unittest.cc
@@ -46,7 +46,7 @@ TEST(ShellDialogsWin, AppendExtensionIfNeeded) {
for (size_t i = 0; i < base::size(test_cases); ++i) {
SCOPED_TRACE(base::StringPrintf("i=%zu", i));
- EXPECT_EQ(base::string16(test_cases[i].expected_filename),
+ EXPECT_EQ(std::wstring(test_cases[i].expected_filename),
ui::AppendExtensionIfNeeded(test_cases[i].filename,
test_cases[i].filter_selected,
test_cases[i].suggested_ext));
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_fuchsia.cc b/chromium/ui/shell_dialogs/select_file_dialog_fuchsia.cc
index c60f0c9bc77..8e92f8dd8ba 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_fuchsia.cc
+++ b/chromium/ui/shell_dialogs/select_file_dialog_fuchsia.cc
@@ -5,6 +5,7 @@
#include "ui/shell_dialogs/select_file_dialog.h"
#include "base/notreached.h"
+#include "ui/shell_dialogs/select_file_policy.h"
namespace ui {
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 8b65d667414..8531ce767d2 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm
+++ b/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm
@@ -166,6 +166,9 @@ TEST_F(SelectFileDialogMacTest, ExtensionPopup) {
EXPECT_EQ(0, [popup indexOfSelectedItem]);
EXPECT_TRUE([[panel allowedFileTypes] containsObject:@"htm"]);
EXPECT_TRUE([[panel allowedFileTypes] containsObject:@"html"]);
+ // Extensions should appear in order of input.
+ EXPECT_LT([[panel allowedFileTypes] indexOfObject:@"html"],
+ [[panel allowedFileTypes] indexOfObject:@"htm"]);
EXPECT_FALSE([[panel allowedFileTypes] containsObject:@"jpg"]);
// Select the second item.
@@ -173,6 +176,9 @@ TEST_F(SelectFileDialogMacTest, ExtensionPopup) {
EXPECT_EQ(1, [popup indexOfSelectedItem]);
EXPECT_TRUE([[panel allowedFileTypes] containsObject:@"jpg"]);
EXPECT_TRUE([[panel allowedFileTypes] containsObject:@"jpeg"]);
+ // Extensions should appear in order of input.
+ EXPECT_LT([[panel allowedFileTypes] indexOfObject:@"jpeg"],
+ [[panel allowedFileTypes] indexOfObject:@"jpg"]);
EXPECT_FALSE([[panel allowedFileTypes] containsObject:@"html"]);
}
@@ -428,10 +434,6 @@ TEST_F(SelectFileDialogMacTest, DialogMessage) {
// Verify that multiple file dialogs are corrected handled.
TEST_F(SelectFileDialogMacTest, MultipleDialogs) {
- // TODO(https://crbug.com/852536): Test fails on 10.10.
- if (base::mac::IsOS10_10())
- return;
-
FileDialogArguments args(GetDefaultArguments());
SelectFileWithParams(args);
NSSavePanel* panel1 = GetPanel();
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_win.cc b/chromium/ui/shell_dialogs/select_file_dialog_win.cc
index 37fe4b5fa35..89705c5b8b8 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_win.cc
+++ b/chromium/ui/shell_dialogs/select_file_dialog_win.cc
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/notreached.h"
#include "base/single_thread_task_runner.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/win/registry.h"
@@ -39,13 +40,17 @@ namespace {
bool GetRegistryDescriptionFromExtension(const base::string16& file_ext,
base::string16* reg_description) {
DCHECK(reg_description);
- base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ);
- base::string16 reg_app;
+ base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, base::as_wcstr(file_ext),
+ KEY_READ);
+ std::wstring reg_app;
if (reg_ext.ReadValue(nullptr, &reg_app) == ERROR_SUCCESS &&
!reg_app.empty()) {
base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ);
- if (reg_link.ReadValue(nullptr, reg_description) == ERROR_SUCCESS)
+ std::wstring description;
+ if (reg_link.ReadValue(nullptr, &description) == ERROR_SUCCESS) {
+ *reg_description = base::WideToUTF16(description);
return true;
+ }
}
return false;
}
@@ -65,7 +70,7 @@ std::vector<FileFilterSpec> FormatFilterForExtensions(
const std::vector<base::string16>& ext_desc,
bool include_all_files,
bool keep_extension_visible) {
- const base::string16 all_ext = L"*.*";
+ const base::string16 all_ext = STRING16_LITERAL("*.*");
const base::string16 all_desc =
l10n_util::GetStringUTF16(IDS_APP_SAVEAS_ALL_FILES);
@@ -91,15 +96,17 @@ std::vector<FileFilterSpec> FormatFilterForExtensions(
}
if (desc.empty()) {
- DCHECK(ext.find(L'.') != base::string16::npos);
- base::string16 first_extension = ext.substr(ext.find(L'.'));
- size_t first_separator_index = first_extension.find(L';');
+ DCHECK(ext.find(STRING16_LITERAL('.')) != base::string16::npos);
+ base::string16 first_extension =
+ ext.substr(ext.find(STRING16_LITERAL('.')));
+ size_t first_separator_index =
+ first_extension.find(STRING16_LITERAL(';'));
if (first_separator_index != base::string16::npos)
first_extension = first_extension.substr(0, first_separator_index);
// Find the extension name without the preceeding '.' character.
base::string16 ext_name = first_extension;
- size_t ext_index = ext_name.find_first_not_of(L'.');
+ size_t ext_index = ext_name.find_first_not_of(STRING16_LITERAL('.'));
if (ext_index != base::string16::npos)
ext_name = ext_name.substr(ext_index);
@@ -112,12 +119,13 @@ std::vector<FileFilterSpec> FormatFilterForExtensions(
include_all_files = true;
}
if (desc.empty())
- desc = L"*." + ext_name;
+ desc = STRING16_LITERAL("*.") + ext_name;
} else if (keep_extension_visible) {
// Having '*' in the description could cause the windows file dialog to
// not include the file extension in the file dialog. So strip out any '*'
// characters if `keep_extension_visible` is set.
- base::ReplaceChars(desc, L"*", L"", &desc);
+ base::ReplaceChars(desc, STRING16_LITERAL("*"), base::StringPiece16(),
+ &desc);
}
result.push_back({desc, ext});
@@ -214,7 +222,7 @@ void DoSelectFileOnDialogTaskRunner(
const base::FilePath& default_path,
const std::vector<ui::FileFilterSpec>& filter,
int file_type_index,
- const base::string16& default_extension,
+ const std::wstring& default_extension,
HWND owner,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
OnSelectFileExecutedCallback on_select_file_executed_callback) {
@@ -314,13 +322,13 @@ std::vector<FileFilterSpec> SelectFileDialogImpl::GetFilterForFileTypes(
std::vector<base::string16> exts;
for (size_t i = 0; i < file_types->extensions.size(); ++i) {
- const std::vector<base::string16>& inner_exts = file_types->extensions[i];
+ const std::vector<std::wstring>& inner_exts = file_types->extensions[i];
base::string16 ext_string;
for (size_t j = 0; j < inner_exts.size(); ++j) {
if (!ext_string.empty())
- ext_string.push_back(L';');
- ext_string.append(L"*.");
- ext_string.append(inner_exts[j]);
+ ext_string.push_back(STRING16_LITERAL(';'));
+ ext_string.append(STRING16_LITERAL("*."));
+ ext_string.append(base::WideToUTF16(inner_exts[j]));
}
exts.push_back(ext_string);
}
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_win.h b/chromium/ui/shell_dialogs/select_file_dialog_win.h
index 6d09000b96e..c699fe29536 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_win.h
+++ b/chromium/ui/shell_dialogs/select_file_dialog_win.h
@@ -31,7 +31,7 @@ using ExecuteSelectFileCallback = base::RepeatingCallback<void(
const base::FilePath& default_path,
const std::vector<FileFilterSpec>& filter,
int file_type_index,
- const base::string16& default_extension,
+ const std::wstring& default_extension,
HWND owner,
OnSelectFileExecutedCallback on_select_file_executed_callback)>;
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_win_unittest.cc b/chromium/ui/shell_dialogs/select_file_dialog_win_unittest.cc
index 90e29c495e7..d16397c34fa 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_win_unittest.cc
+++ b/chromium/ui/shell_dialogs/select_file_dialog_win_unittest.cc
@@ -16,6 +16,7 @@
#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/task_environment.h"
#include "base/threading/platform_thread.h"
#include "base/win/scoped_com_initializer.h"
@@ -34,15 +35,15 @@ constexpr wchar_t kSelectFileDefaultTitle[] = L"Open";
constexpr wchar_t kSaveFileDefaultTitle[] = L"Save As";
// Returns the title of |window|.
-base::string16 GetWindowTitle(HWND window) {
+std::wstring GetWindowTitle(HWND window) {
wchar_t buffer[256];
UINT count = ::GetWindowText(window, buffer, base::size(buffer));
- return base::string16(buffer, count);
+ return std::wstring(buffer, count);
}
// Waits for a dialog window whose title is |dialog_title| to show and returns
// its handle.
-HWND WaitForDialogWindow(const base::string16& dialog_title) {
+HWND WaitForDialogWindow(const std::wstring& dialog_title) {
// File dialogs uses this class name.
static constexpr wchar_t kDialogClassName[] = L"#32770";
@@ -104,14 +105,14 @@ HWND WaitForDialogPrompt(HWND owner) {
}
// Returns the text of the dialog item in |window| whose id is |dialog_item_id|.
-base::string16 GetDialogItemText(HWND window, int dialog_item_id) {
+std::wstring GetDialogItemText(HWND window, int dialog_item_id) {
if (!window)
- return base::string16();
+ return std::wstring();
wchar_t buffer[256];
UINT count =
::GetDlgItemText(window, dialog_item_id, buffer, base::size(buffer));
- return base::string16(buffer, count);
+ return std::wstring(buffer, count);
}
// Sends a command to |window| using PostMessage().
@@ -221,7 +222,7 @@ TEST_F(SelectFileDialogWinTest, CancelAllDialogs) {
dialog->SelectFile(test_case.dialog_type, base::string16(),
base::FilePath(), file_type_info.get(),
- file_type_info_index, base::string16(), native_window(),
+ file_type_info_index, std::wstring(), native_window(),
nullptr);
// Accept the default value.
@@ -252,14 +253,14 @@ TEST_F(SelectFileDialogWinTest, UploadFolderCheckStrings) {
// Wait for the window to open and make sure the window title was changed from
// the default title for a regular select folder operation.
- HWND window = WaitForDialogWindow(
- l10n_util::GetStringUTF16(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE));
+ HWND window = WaitForDialogWindow(base::UTF16ToWide(
+ l10n_util::GetStringUTF16(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE)));
EXPECT_NE(GetWindowTitle(window), kSelectFolderDefaultTitle);
// Check the OK button text.
- EXPECT_EQ(
- GetDialogItemText(window, 1),
- l10n_util::GetStringUTF16(IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON));
+ EXPECT_EQ(GetDialogItemText(window, 1),
+ base::UTF16ToWide(l10n_util::GetStringUTF16(
+ IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON)));
// Close the dialog.
SendCommand(window, IDOK);
@@ -274,7 +275,7 @@ TEST_F(SelectFileDialogWinTest, UploadFolderCheckStrings) {
// Specifying the title when opening a dialog to select a file, select multiple
// files or save a file doesn't do anything.
TEST_F(SelectFileDialogWinTest, SpecifyTitle) {
- static constexpr wchar_t kTitle[] = L"FooBar Title";
+ static constexpr base::char16 kTitle[] = STRING16_LITERAL("FooBar Title");
// Create some file in a test folder.
base::ScopedTempDir scoped_temp_dir;
diff --git a/chromium/ui/shell_dialogs/shell_dialog_linux.cc b/chromium/ui/shell_dialogs/shell_dialog_linux.cc
index f5999fb0cf0..f97dc0ed641 100644
--- a/chromium/ui/shell_dialogs/shell_dialog_linux.cc
+++ b/chromium/ui/shell_dialogs/shell_dialog_linux.cc
@@ -5,6 +5,7 @@
#include "ui/shell_dialogs/shell_dialog_linux.h"
#include "base/notreached.h"
+#include "build/chromeos_buildflags.h"
#include "ui/shell_dialogs/select_file_policy.h"
namespace {
@@ -26,7 +27,7 @@ const ShellDialogLinux* ShellDialogLinux::instance() {
SelectFileDialog* CreateSelectFileDialog(
SelectFileDialog::Listener* listener,
std::unique_ptr<SelectFilePolicy> policy) {
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
const ui::ShellDialogLinux* shell_dialogs = ui::ShellDialogLinux::instance();
if (shell_dialogs)
return shell_dialogs->CreateSelectFileDialog(listener, std::move(policy));
diff --git a/chromium/ui/snapshot/DIR_METADATA b/chromium/ui/snapshot/DIR_METADATA
new file mode 100644
index 00000000000..d366dc73213
--- /dev/null
+++ b/chromium/ui/snapshot/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals"
+}
diff --git a/chromium/ui/snapshot/OWNERS b/chromium/ui/snapshot/OWNERS
index aad3b1d341e..4e993324db0 100644
--- a/chromium/ui/snapshot/OWNERS
+++ b/chromium/ui/snapshot/OWNERS
@@ -1,3 +1,2 @@
# Android
per-file *android*=tedchoc@chromium.org
-# COMPONENT: Internals
diff --git a/chromium/ui/snapshot/screenshot_grabber.h b/chromium/ui/snapshot/screenshot_grabber.h
index a19a4cb6bda..f27e0322ef2 100644
--- a/chromium/ui/snapshot/screenshot_grabber.h
+++ b/chromium/ui/snapshot/screenshot_grabber.h
@@ -32,7 +32,10 @@ enum class ScreenshotResult {
CHECK_DIR_FAILED,
CREATE_FILE_FAILED,
WRITE_FILE_FAILED,
- DISABLED
+ // Disabled by an enterprise policy or special modes.
+ DISABLED,
+ // Disabled by Data Leak Prevention feature.
+ DISABLED_BY_DLP
};
class SNAPSHOT_EXPORT ScreenshotGrabber {
diff --git a/chromium/ui/snapshot/snapshot_mac_unittest.mm b/chromium/ui/snapshot/snapshot_mac_unittest.mm
index a8823335f19..9feeb03876d 100644
--- a/chromium/ui/snapshot/snapshot_mac_unittest.mm
+++ b/chromium/ui/snapshot/snapshot_mac_unittest.mm
@@ -8,7 +8,6 @@
#include <memory>
-#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsobject.h"
#include "testing/platform_test.h"
#import "ui/base/test/cocoa_helper.h"
@@ -20,11 +19,8 @@ namespace {
typedef CocoaTest GrabWindowSnapshotTest;
-TEST_F(GrabWindowSnapshotTest, TestGrabWindowSnapshot) {
- // TODO(https://crbug.com/685088): This test fails on MacOS 10.11 and above.
- if (base::mac::IsAtLeastOS10_11())
- return;
-
+// TODO(https://crbug.com/685088): This test fails.
+TEST_F(GrabWindowSnapshotTest, DISABLED_TestGrabWindowSnapshot) {
// Launch a test window so we can take a snapshot.
NSRect frame = NSMakeRect(0, 0, 400, 400);
NSWindow* window = test_window();
diff --git a/chromium/ui/strings/DIR_METADATA b/chromium/ui/strings/DIR_METADATA
new file mode 100644
index 00000000000..d412a599f91
--- /dev/null
+++ b/chromium/ui/strings/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI>Internationalization"
+}
diff --git a/chromium/ui/strings/OWNERS b/chromium/ui/strings/OWNERS
index 18c7688ba43..72e8ffc0db8 100644
--- a/chromium/ui/strings/OWNERS
+++ b/chromium/ui/strings/OWNERS
@@ -1,2 +1 @@
*
-# COMPONENT: UI>Internationalization
diff --git a/chromium/ui/strings/app_locale_settings.grd b/chromium/ui/strings/app_locale_settings.grd
index 62ccf7adf29..62e20b803cb 100644
--- a/chromium/ui/strings/app_locale_settings.grd
+++ b/chromium/ui/strings/app_locale_settings.grd
@@ -34,6 +34,9 @@
<output filename="app_locale_settings_zh-HK.pak" type="data_package" lang="zh-HK" />
<output filename="app_locale_settings_zu.pak" type="data_package" lang="zu" />
</if>
+ <if expr="chromeos or lacros">
+ <output filename="app_locale_settings_is.pak" type="data_package" lang="is" />
+ </if>
<output filename="app_locale_settings_am.pak" type="data_package" lang="am" />
<output filename="app_locale_settings_ar.pak" type="data_package" lang="ar" />
<output filename="app_locale_settings_bg.pak" type="data_package" lang="bg" />
@@ -55,7 +58,6 @@
</if>
<output filename="app_locale_settings_et.pak" type="data_package" lang="et" />
<output filename="app_locale_settings_fa.pak" type="data_package" lang="fa" />
- <output filename="app_locale_settings_fake-bidi.pak" type="data_package" lang="fake-bidi" />
<output filename="app_locale_settings_fi.pak" type="data_package" lang="fi" />
<output filename="app_locale_settings_fil.pak" type="data_package" lang="fil" />
<output filename="app_locale_settings_fr.pak" type="data_package" lang="fr" />
@@ -102,6 +104,10 @@
<output filename="app_locale_settings_vi.pak" type="data_package" lang="vi" />
<output filename="app_locale_settings_zh-CN.pak" type="data_package" lang="zh-CN" />
<output filename="app_locale_settings_zh-TW.pak" type="data_package" lang="zh-TW" />
+
+ <!-- Pseudolocales -->
+ <output filename="app_locale_settings_ar-XB.pak" type="data_package" lang="ar-XB" />
+ <output filename="app_locale_settings_en-XA.pak" type="data_package" lang="en-XA" />
</outputs>
<translations>
<file path="translations/app_locale_settings_am.xtb" lang="am" />
@@ -217,7 +223,7 @@
75%
</message>
</if>
- <if expr="(is_linux or is_android or is_bsd) and not chromeos">
+ <if expr="(is_linux or is_android or is_bsd) and not (chromeos or lacros)">
<!-- The font used in Web UI (e.g. History). Note that these are only
backups. We try to use the system font if possible. -->
<message name="IDS_WEB_FONT_FAMILY" use_name_for_id="true">
@@ -230,7 +236,7 @@
</message>
</if>
<!-- For Chrome OS -->
- <if expr="chromeos">
+ <if expr="chromeos or lacros">
<!-- The font name like: 'Font Name, 12px' -->
<message name="IDS_UI_FONT_FAMILY_CROS" use_name_for_id="true">
Roboto, 12px
diff --git a/chromium/ui/strings/translations/ui_strings_af.xtb b/chromium/ui/strings/translations/ui_strings_af.xtb
index 9745d0eef02..8db98433805 100644
--- a/chromium/ui/strings/translations/ui_strings_af.xtb
+++ b/chromium/ui/strings/translations/ui_strings_af.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ingeboude skerm</translation>
<translation id="335581015389089642">Spraak</translation>
<translation id="3389286852084373014">Teks is te groot</translation>
+<translation id="3406306243914553062">HTML-inhoud</translation>
<translation id="348799646910989694">Rak is outoversteek</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> is vasgespeld</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag oor}other{# dae oor}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Nommer</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Hou aan lees op jou mobiele toestel <ph name="TITLE" /></translation>
<translation id="385051799172605136">Terug</translation>
<translation id="3889424535448813030">Regspyltjie</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 maand gelede}other{# maande gelede}}</translation>
<translation id="4289300219472526559">Begin praat</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> is geskuif na vouer <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Verwyder van knipbord af.</translation>
<translation id="4316910396681052118">ALLE PROGRAMME</translation>
<translation id="4491109536499578614">Prent</translation>
<translation id="4588090240171750605">Rollees na regs</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Vee hierdie soektog in jou geskiedenis uit?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emosiekone</translation>
+<translation id="7620655452534002301">Verwyder.</translation>
<translation id="7658239707568436148">Kanselleer</translation>
<translation id="7781829728241885113">Gister</translation>
<translation id="7814458197256864873">Kopieer</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 uur gelede}other{# uur gelede}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 sek. oor}other{# sek. oor}}</translation>
<translation id="8134065097954893699">Herlaai tans hierdie bladsy</translation>
-<translation id="8144660977431427332">Jou soektogte word aangedryf deur die Google Assistent. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, outovoltooi</translation>
<translation id="815598010540052116">Rollees na onder</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Bladsy af</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Oortjie</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, program</translation>
<translation id="8259556432390118667">Heksadesimale kleurwaarde</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_am.xtb b/chromium/ui/strings/translations/ui_strings_am.xtb
index ff4bcf71976..869c6bdd9ee 100644
--- a/chromium/ui/strings/translations/ui_strings_am.xtb
+++ b/chromium/ui/strings/translations/ui_strings_am.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">አብሮገነብ ማሳያ</translation>
<translation id="335581015389089642">ንግግር</translation>
<translation id="3389286852084373014">ጽሑፍ ከልክ በላይ ግዙፍ ነው</translation>
+<translation id="3406306243914553062">የHTML ይዘት</translation>
<translation id="348799646910989694">መደርደሪያ በራስ-ሰር ተደብቋል</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> ተያይዟል</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 ቀን ቀርቷል}one{# ቀኖች ቀርቷል}other{# ቀኖች ቀርተዋል}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">ቁጥር</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> ጊባ/ሰ</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> ጊባ</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />። <ph name="TYPE_2" />።</translation>
<translation id="3842239759367498783">ከእርስዎ ተንቀሳቃሽ መሣሪያ <ph name="TITLE" /> ማንበብ ይቀጥሉ</translation>
<translation id="385051799172605136">ተመለስ</translation>
<translation id="3889424535448813030">ቀኝ ቀስት</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{ከ1 ወር በፊት}one{ከ# ወሮች በፊት}other{ከ# ወሮች በፊት}}</translation>
<translation id="4289300219472526559">መናገር ይጀምሩ</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> ወደ <ph name="FOLDER_NAME" /> አቃፊ ተንቀሳቅሷል።</translation>
+<translation id="4306392492252714209">ከቅንጥብ ሰሌዳ ላይ አስወግድ።</translation>
<translation id="4316910396681052118">ሁሉም መተግበሪያዎች</translation>
<translation id="4491109536499578614">ምስል</translation>
<translation id="4588090240171750605">ወደ ቀኝ ሸብልል</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">ይሄ ፍለጋ ከታሪክዎ ይሰረዝ?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ቴባ</translation>
<translation id="7507604095951736240">ስሜት ገላጭ ምስል</translation>
+<translation id="7620655452534002301">ተወግዷል።</translation>
<translation id="7658239707568436148">ይቅር</translation>
<translation id="7781829728241885113">ትናንት</translation>
<translation id="7814458197256864873">&amp;ቅዳ</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 ሰዓት በፊት}one{# ሰዓቶች በፊት}other{# ሰዓቶች በፊት}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 ሰከንድ ቀርቷል}one{# ሰከንዶች ቀርቷል}other{# ሰከንዶች ቀርተዋል}}</translation>
<translation id="8134065097954893699">ይህን ገጽ ዳግም በመጫን ላይ</translation>
-<translation id="8144660977431427332">የእርስዎ ፍለጋዎች የቀረቡት በ Google ረዳቱ ነው። <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />፣ ራስሰር ሙላ</translation>
<translation id="815598010540052116">ወደ ታች ሸብልል</translation>
<translation id="8179976553408161302">አስገባ</translation>
<translation id="8210608804940886430">ወደታች አንቀሳቅስ</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />፣ <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ትር</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />፣ መተግበሪያ</translation>
<translation id="8259556432390118667">የአስራስድስትዮሽ ቀለም እሴት</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ar.xtb b/chromium/ui/strings/translations/ui_strings_ar.xtb
index f74867184a8..1b3e05bbda3 100644
--- a/chromium/ui/strings/translations/ui_strings_ar.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ar.xtb
@@ -11,7 +11,7 @@
<translation id="1218444235442067213">‏<ph name="APP_NAME" />، تطبيق من "متجر Play"</translation>
<translation id="1243314992276662751">تحميل</translation>
<translation id="1266864766717917324">تعذَّرت مشاركة <ph name="CONTENT_TYPE" />.</translation>
-<translation id="1269641567813814718">الفوز</translation>
+<translation id="1269641567813814718">Win</translation>
<translation id="1290982764014248209">نقل <ph name="DRAGGED_APP" /> إلى مجلد <ph name="FOLDER_NAME" />.</translation>
<translation id="1291104554099683393">يُرجى تجربة مشاركة النص في مجموعات أصغر.</translation>
<translation id="1293699935367580298">Esc</translation>
@@ -30,7 +30,7 @@
<translation id="1710340000377843106">الآن</translation>
<translation id="1752946267035950200">{MINUTES,plural, =1{دقيقة واحدة}zero{# من الدقائق}two{دقيقتان (#)}few{# دقائق}many{# دقيقة}other{# من الدقائق}}</translation>
<translation id="1761785978543082658"><ph name="QUANTITY" /> بايت</translation>
-<translation id="1801827354178857021">الفترة</translation>
+<translation id="1801827354178857021">نقطة</translation>
<translation id="1803208670097017349">{MONTHS,plural, =1{شهر واحد}zero{# شهر}two{شهران (#)}few{# أشهر}many{# شهرًا}other{# شهر}}</translation>
<translation id="1809410197924942083"><ph name="QUANTITY" /> ميغابايات/ثانية</translation>
<translation id="1830179671306812954">{HOURS,plural, =1{ساعة واحدة و }zero{# من الساعات و }two{ساعتان (#) و }few{# ساعات و }many{# ساعة و }other{# من الساعات و }}</translation>
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">عرض مُضمَّن</translation>
<translation id="335581015389089642">الحديث</translation>
<translation id="3389286852084373014">النص كبير جدًا</translation>
+<translation id="3406306243914553062">‏محتوى HTML</translation>
<translation id="348799646910989694">إخفاء الرف تلقائيًا</translation>
<translation id="3554637740840164787">تم تثبيت <ph name="ITEM_TITLE" /></translation>
<translation id="3600566671520689681">{DAYS,plural, =1{يتبقى يوم واحد}zero{يتبقى عدد # من الأيام}two{يتبقى يومان (#)}few{يتبقى # أيام}many{يتبقى # يومًا}other{يتبقى # من الأيام}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">رقم</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> غيغابايت/ثانية</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> غيغابايت</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">متابعة القراءة من جهازك الجوّال <ph name="TITLE" /></translation>
<translation id="385051799172605136">رجوع</translation>
<translation id="3889424535448813030">مفتاح سهم إلى اليمين</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{قبل شهر واحد}zero{قبل # شهر}two{قبل شهرين (#)}few{قبل # أشهر}many{قبل # شهرًا}other{قبل # شهر}}</translation>
<translation id="4289300219472526559">بدء التحدث</translation>
<translation id="430191667033048642">تم نقل <ph name="MOVED_APP_NAME" /> إلى المجلد <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">إزالة من الحافظة</translation>
<translation id="4316910396681052118">جميع التطبيقات</translation>
<translation id="4491109536499578614">صورة</translation>
<translation id="4588090240171750605">التمرير إلى اليسار</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">هل تريد حذف هذا البحث من السجل؟</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> تيرابايت</translation>
<translation id="7507604095951736240">الرموز التعبيرية</translation>
+<translation id="7620655452534002301">تمت الإزالة.</translation>
<translation id="7658239707568436148">إلغاء</translation>
<translation id="7781829728241885113">أمس</translation>
<translation id="7814458197256864873">&amp;نسخ</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">إعادة تحميل هذه الصفحة</translation>
-<translation id="8144660977431427332">‏عمليات بحثك يوفّرها "مساعد Google". <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />، الإكمال التلقائي</translation>
<translation id="815598010540052116">التمرير إلى أسفل</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">صفحة إلى أسفل</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />، <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">علامة تبويب</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />، تطبيق</translation>
<translation id="8259556432390118667">القيمة السداسية للّون</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_as.xtb b/chromium/ui/strings/translations/ui_strings_as.xtb
index 44a4f01562b..583fcdfae0d 100644
--- a/chromium/ui/strings/translations/ui_strings_as.xtb
+++ b/chromium/ui/strings/translations/ui_strings_as.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">বিল্ট-ইন ডিছপ্লে’</translation>
<translation id="335581015389089642">কথন</translation>
<translation id="3389286852084373014">পাঠখিনি যথেষ্ট দীঘল</translation>
+<translation id="3406306243914553062">HTML সমল</translation>
<translation id="348799646910989694">শ্বেল্ফ স্বয়ংক্রিয়ভাৱে লুকুওৱা হয়</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> পিন কৰা হৈছে</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{১ দিন বাকী আছে}one{# দিন বাকী আছে}other{# দিন বাকী আছে}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">নম্বৰ</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> জি. বি./ছেকেণ্ড</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> জিবি</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />। <ph name="TYPE_2" />।</translation>
<translation id="3842239759367498783">আপোনাৰ ম’বাইল ডিভাইচ <ph name="TITLE" />ৰ পৰা পঢ়ি থাকক</translation>
<translation id="385051799172605136">উভতি যাওক</translation>
<translation id="3889424535448813030">সোঁমুৱা কাঁড়</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{১মাহ পূর্বে}one{#মাহ পূর্বে}other{#মাহ পূর্বে}}</translation>
<translation id="4289300219472526559">কথা কওক</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" />ক <ph name="FOLDER_NAME" /> ফ’ল্ডাৰলৈ স্থানান্তৰ কৰা হ’ল।</translation>
+<translation id="4306392492252714209">ক্লিপব’ৰ্ডৰ পৰা আঁতৰাওক।</translation>
<translation id="4316910396681052118">সকলো এপ্</translation>
<translation id="4491109536499578614">প্ৰতিচ্ছবি</translation>
<translation id="4588090240171750605">সোঁফাললৈ স্ক্ৰ’ল কৰক</translation>
@@ -211,6 +214,7 @@
<translation id="7430878839542012341">এই সন্ধানৰ তথ্য আপোনাৰ ইতিহাসৰ পৰা বিলোপ কৰিব নেকি?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> টি.বি.</translation>
<translation id="7507604095951736240">ইম’জি</translation>
+<translation id="7620655452534002301">আঁতৰোৱা হ’ল।</translation>
<translation id="7658239707568436148">বাতিল কৰক</translation>
<translation id="7781829728241885113">কালি</translation>
<translation id="7814458197256864873">&amp;প্ৰতিলিপি কৰক</translation>
@@ -226,11 +230,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{১ ঘণ্টা পূৰ্বে}one{# ঘণ্টা পূৰ্বে}other{# ঘণ্টা পূৰ্বে}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{১ ছেকেণ্ড বাকী আছে}one{# ছেকেণ্ড বাকী আছে}other{# ছেকেণ্ড বাকী আছে}}</translation>
<translation id="8134065097954893699">এই পৃষ্ঠাটো পুনৰ ল'ড হৈ আছে</translation>
-<translation id="8144660977431427332">আপোনাৰ সন্ধানসমূহ Google Assistantৰ দ্বাৰা সঞ্চালিত। <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, স্বয়ংক্ৰিয়ভাৱে সম্পূৰ্ণ কৰা হৈছে</translation>
<translation id="815598010540052116">তললৈ স্ক্ৰল কৰক</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Page Down</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">টেব</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, এপ্‌</translation>
<translation id="8259556432390118667">হেক্স ৰঙৰ মান</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_az.xtb b/chromium/ui/strings/translations/ui_strings_az.xtb
index e54c79bba92..e99e759387f 100644
--- a/chromium/ui/strings/translations/ui_strings_az.xtb
+++ b/chromium/ui/strings/translations/ui_strings_az.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Daxili displey</translation>
<translation id="335581015389089642">Nitq</translation>
<translation id="3389286852084373014">Mətn çox böyükdür</translation>
+<translation id="3406306243914553062">HTML məzmunu</translation>
<translation id="348799646910989694">Rəf avtomatik olaraq gizlədilib</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> bərkidildi</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 gün qaldı}other{# gün qaldı}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Nömrə</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Mobil cihazdan oxumağa davam edin <ph name="TITLE" /></translation>
<translation id="385051799172605136">Geri</translation>
<translation id="3889424535448813030">Sağa</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 ay əvvəl}other{# ay əvvəl}}</translation>
<translation id="4289300219472526559">Danışmağa başlayın</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> <ph name="FOLDER_NAME" /> qovluğuna köçürülüb.</translation>
+<translation id="4306392492252714209">Mübadilə buferindən silin.</translation>
<translation id="4316910396681052118">BÜTÜN TƏTBİQLƏR</translation>
<translation id="4491109536499578614">Şəkil</translation>
<translation id="4588090240171750605">Sağa Sürüşdürün</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Bu axtarış tarixçədən silinsin?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Silindi.</translation>
<translation id="7658239707568436148">Ləğv edin</translation>
<translation id="7781829728241885113">Dünən</translation>
<translation id="7814458197256864873">&amp;Kopyalayın</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 saat öncə}other{# saat öncə}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 san qalıb}other{# san qalıb}}</translation>
<translation id="8134065097954893699">Bu səhifə yenidən yüklənir</translation>
-<translation id="8144660977431427332">Axtarışlarınız Google Assistent tərəfindən dəstəklənir. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, Avto-tamamlama</translation>
<translation id="815598010540052116">Aşağı Sürüşdürün</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Aşağı Səhifə</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, Tətbiq</translation>
<translation id="8259556432390118667">Onaltılıq rəngin dəyəri</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_be.xtb b/chromium/ui/strings/translations/ui_strings_be.xtb
index a5534cf0aaa..2cb86d8ccf3 100644
--- a/chromium/ui/strings/translations/ui_strings_be.xtb
+++ b/chromium/ui/strings/translations/ui_strings_be.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Убудаваны дысплэй</translation>
<translation id="335581015389089642">Маўленне</translation>
<translation id="3389286852084373014">Тэкст занадта вялікі</translation>
+<translation id="3406306243914553062">Змесціва HTML.</translation>
<translation id="348799646910989694">Паліца аўтаматычна схавана</translation>
<translation id="3554637740840164787">Элемент "<ph name="ITEM_TITLE" />" замацаваны</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Застаўся 1 дзень}one{Застаўся # дзень}few{Засталося # дні}many{Засталося # дзён}other{Засталося # дня}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Нумар</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> ГБ/с</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> ГБ</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Працягвайце чытаць на мабільнай прыладзе <ph name="TITLE" /></translation>
<translation id="385051799172605136">Назад</translation>
<translation id="3889424535448813030">Стрэлка ўправа</translation>
@@ -118,10 +120,11 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 месяц таму}one{# месяц таму}few{# месяцы таму}many{# месяцаў таму}other{# месяца таму}}</translation>
<translation id="4289300219472526559">Пачаць галасавы ўвод</translation>
<translation id="430191667033048642">Праграма <ph name="MOVED_APP_NAME" /> перамешчана ў папку <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Выдаліць з буфера абмену.</translation>
<translation id="4316910396681052118">УСЕ ПРАГРАМЫ</translation>
<translation id="4491109536499578614">Відарыс</translation>
<translation id="4588090240171750605">Прагартаць управа</translation>
-<translation id="4631891353005174729"><ph name="APP_NAME_TYPE" />, ацэнка ў зорках: <ph name="RATING_SCORE" /></translation>
+<translation id="4631891353005174729"><ph name="APP_NAME_TYPE" />, ацэнка: <ph name="RATING_SCORE" /></translation>
<translation id="4648249871170053485">Рэкамендаваная праграма (<ph name="APP_NAME" />)</translation>
<translation id="4690510401873698237">Паліца ўнізе</translation>
<translation id="4724120544754982507">Цэнтр апавяшчэнняў. Непрачытаных апавяшчэнняў: <ph name="UNREAD_NOTIFICATION_COUNT" /></translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Выдаліць гэты пошукавы запыт з вашай гісторыі?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ТБ</translation>
<translation id="7507604095951736240">Эмодзі</translation>
+<translation id="7620655452534002301">Выдалена.</translation>
<translation id="7658239707568436148">Скасаваць</translation>
<translation id="7781829728241885113">Учора</translation>
<translation id="7814458197256864873">&amp;Капіраваць</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Гэта старонка перазагружаецца</translation>
-<translation id="8144660977431427332">Вашы пошукавыя запыты апрацоўваюцца на платформе Памочніка Google. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, аўтазапаўненне</translation>
<translation id="815598010540052116">Прагартаць уніз</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Page Down</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446">Праграма (<ph name="APP_NAME" />)</translation>
<translation id="8259556432390118667">Шаснаццатковае значэнне колеру</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_bg.xtb b/chromium/ui/strings/translations/ui_strings_bg.xtb
index 2fd67866dc7..b082ff7918a 100644
--- a/chromium/ui/strings/translations/ui_strings_bg.xtb
+++ b/chromium/ui/strings/translations/ui_strings_bg.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Вграден екран</translation>
<translation id="335581015389089642">Speech</translation>
<translation id="3389286852084373014">Текстът е твърде голям</translation>
+<translation id="3406306243914553062">HTML съдържание</translation>
<translation id="348799646910989694">Лавицата се скрива автоматично</translation>
<translation id="3554637740840164787">Фиксирахте <ph name="ITEM_TITLE" /></translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Остава 1 ден}other{Остават # дни}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Номер</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> ГБ/сек</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> ГБ</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Продължете четенето от мобилното си устройство <ph name="TITLE" /></translation>
<translation id="385051799172605136">Назад</translation>
<translation id="3889424535448813030">Стрелка надясно</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Преди 1 месец}other{Преди # месеца}}</translation>
<translation id="4289300219472526559">Start Speaking</translation>
<translation id="430191667033048642">Приложението <ph name="MOVED_APP_NAME" /> бе преместено в папката <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Премахване от буферната памет.</translation>
<translation id="4316910396681052118">ВСИЧКИ ПРИЛОЖЕНИЯ</translation>
<translation id="4491109536499578614">Изображение</translation>
<translation id="4588090240171750605">Превъртане надясно</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Да се изтрие ли това търсене от историята ви?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ТБ</translation>
<translation id="7507604095951736240">Емоджи</translation>
+<translation id="7620655452534002301">Премахнато.</translation>
<translation id="7658239707568436148">Отказ</translation>
<translation id="7781829728241885113">Вчера</translation>
<translation id="7814458197256864873">&amp;Копиране</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{Преди 1 час}other{Преди # часа}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Остава 1 сек}other{Остават # сек}}</translation>
<translation id="8134065097954893699">Презаредете страницата</translation>
-<translation id="8144660977431427332">Търсенията се извършват с помощта на Google Асистент. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, автоматично довършване</translation>
<translation id="815598010540052116">Превъртане надолу</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Страница надолу</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" /> и <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Табулатор</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, приложение</translation>
<translation id="8259556432390118667">Шестнадесетична стойност за цвета</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_bn.xtb b/chromium/ui/strings/translations/ui_strings_bn.xtb
index b9540c92b88..eb648211a6e 100644
--- a/chromium/ui/strings/translations/ui_strings_bn.xtb
+++ b/chromium/ui/strings/translations/ui_strings_bn.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">আগে থেকেই তৈরি করা আভ্যন্তরীণ ডিসপ্লে</translation>
<translation id="335581015389089642">স্পিচ</translation>
<translation id="3389286852084373014">টেক্সটটি অনেক বড়</translation>
+<translation id="3406306243914553062">HTML কন্টেন্ট</translation>
<translation id="348799646910989694">শেল্ফ অটোমেটিক লুকানো হবে</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> পিন করা হয়েছে</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{১ দিন বাকি}one{# দিন বাকি}other{# দিন বাকি}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">নম্বর</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> জিবি/সেকেণ্ড</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> জিবি</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />। <ph name="TYPE_2" />।</translation>
<translation id="3842239759367498783">আপনার মোবাইল ডিভাইস <ph name="TITLE" /> থেকে পড়ুন</translation>
<translation id="385051799172605136">ফিরুন</translation>
<translation id="3889424535448813030">Right Arrow</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{১ মাস আগে}one{# মাস আগে}other{# মাস আগে}}</translation>
<translation id="4289300219472526559">কথা বলা শুরু করুন</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> অ্যাপ <ph name="FOLDER_NAME" /> ফোল্ডারে সরানো হয়েছে।</translation>
+<translation id="4306392492252714209">ক্লিপবোর্ড থেকে সরান।</translation>
<translation id="4316910396681052118">সব অ্যাপ</translation>
<translation id="4491109536499578614">ছবি</translation>
<translation id="4588090240171750605">ডান দিকে স্ক্রল করুন</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">এই সার্চ কি ইতিহাস থেকে মুছে দিতে চান?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">ইমোজি</translation>
+<translation id="7620655452534002301">সরানো হয়েছে।</translation>
<translation id="7658239707568436148">বাতিল</translation>
<translation id="7781829728241885113">গতকাল</translation>
<translation id="7814458197256864873">&amp;কপি করুন</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{১ ঘণ্টা পূর্বে}one{# ঘণ্টা পূর্বে}other{# ঘণ্টা পূর্বে}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{১ সেকেন্ড বাকি}one{# সেকেন্ড বাকি}other{# সেকেন্ড বাকি}}</translation>
<translation id="8134065097954893699">এই পৃষ্ঠা আবার লোড করা হচ্ছে</translation>
-<translation id="8144660977431427332">Google অ্যাসিস্ট্যান্ট আপনার সার্চ পরিচালনা করে। <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, নিজে থেকে সম্পূর্ন করা</translation>
<translation id="815598010540052116">নিচে স্ক্রল করুন</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">পৃষ্ঠা উপরে</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ট্যাব</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, অ্যাপ</translation>
<translation id="8259556432390118667">হেক্স রঙের মান</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_bs.xtb b/chromium/ui/strings/translations/ui_strings_bs.xtb
index 406e3a59646..a3e40cc10e0 100644
--- a/chromium/ui/strings/translations/ui_strings_bs.xtb
+++ b/chromium/ui/strings/translations/ui_strings_bs.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ugrađeni ekran</translation>
<translation id="335581015389089642">Govor</translation>
<translation id="3389286852084373014">Tekst je predug</translation>
+<translation id="3406306243914553062">HTML sadržaj</translation>
<translation id="348799646910989694">Polica je automatski skrivena</translation>
<translation id="3554637740840164787">Stavka <ph name="ITEM_TITLE" /> je zakačena</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Preostao je još 1 dan}one{Preostao je još # dan}few{Preostala su još # dana}other{Preostalo je još # dana}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Broj</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Nastavite čitati s mobilnog uređaja <ph name="TITLE" /></translation>
<translation id="385051799172605136">Nazad</translation>
<translation id="3889424535448813030">Strelica nadesno</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Prije 1 mjesec}one{Prije # mjesec}few{Prije # mjeseca}other{Prije # mjeseci}}</translation>
<translation id="4289300219472526559">Započinjanje govora</translation>
<translation id="430191667033048642">Aplikacija <ph name="MOVED_APP_NAME" /> je premještena u folder <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Uklanjanje iz međumemorije.</translation>
<translation id="4316910396681052118">SVE APLIKACIJE</translation>
<translation id="4491109536499578614">Slika</translation>
<translation id="4588090240171750605">Kliznite udesno</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Izbrisati ovo pretraživanje iz historije?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji sličice</translation>
+<translation id="7620655452534002301">Uklonjeno.</translation>
<translation id="7658239707568436148">Otkaži</translation>
<translation id="7781829728241885113">Jučer</translation>
<translation id="7814458197256864873">&amp;Kopiraj</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Ponovno učitavanje stranice</translation>
-<translation id="8144660977431427332">Vaša pretraživanja omogućava Google Asistent. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, automatsko dovršavanje</translation>
<translation id="815598010540052116">Klizni prema dolje</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Stranica prema dolje</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplikacija</translation>
<translation id="8259556432390118667">Hex vrijednost boje</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ca.xtb b/chromium/ui/strings/translations/ui_strings_ca.xtb
index 94f29f6710b..3bc501284d0 100644
--- a/chromium/ui/strings/translations/ui_strings_ca.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ca.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Pantalla integrada</translation>
<translation id="335581015389089642">Veu</translation>
<translation id="3389286852084373014">El text és massa llarg</translation>
+<translation id="3406306243914553062">Contingut HTML</translation>
<translation id="348799646910989694">El prestatge s'amaga automàticament</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> s'ha fixat</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dia restant}other{# dies restants}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Número</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" /> i <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Continua la lectura des del dispositiu mòbil <ph name="TITLE" /></translation>
<translation id="385051799172605136">Enrere</translation>
<translation id="3889424535448813030">Fletxa dreta</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Fa 1 mes}other{Fa # mesos}}</translation>
<translation id="4289300219472526559">Comença a parlar</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> s'ha mogut a la carpeta <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Suprimeix del porta-retalls.</translation>
<translation id="4316910396681052118">TOTES LES APLICACIONS</translation>
<translation id="4491109536499578614">Imatge</translation>
<translation id="4588090240171750605">Desplaçament a la dreta</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Vols suprimir aquesta cerca de l'historial?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emojis</translation>
+<translation id="7620655452534002301">S'ha suprimit.</translation>
<translation id="7658239707568436148">Cancel·la</translation>
<translation id="7781829728241885113">Ahir</translation>
<translation id="7814458197256864873">&amp;Copia</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">S'està tornant a carregar aquesta pàgina</translation>
-<translation id="8144660977431427332">Les cerques es duen a terme amb la tecnologia de l'Assistent de Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabulador</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplicació</translation>
<translation id="8259556432390118667">Valor del color hexadecimal</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_cs.xtb b/chromium/ui/strings/translations/ui_strings_cs.xtb
index 22d0f9cea1c..e6a6de2374d 100644
--- a/chromium/ui/strings/translations/ui_strings_cs.xtb
+++ b/chromium/ui/strings/translations/ui_strings_cs.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Integrovaný displej</translation>
<translation id="335581015389089642">Řeč</translation>
<translation id="3389286852084373014">Text je příliš dlouhý</translation>
+<translation id="3406306243914553062">Obsah ve formátu HTML</translation>
<translation id="348799646910989694">Polička byla automaticky skryta</translation>
<translation id="3554637740840164787">Položka <ph name="ITEM_TITLE" /> byla připnuta</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Zbývá 1 den}few{Zbývají # dny}many{Zbývá # dne}other{Zbývá # dnů}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Číslo</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Pokračujte ve čtení v mobilním zařízení <ph name="TITLE" /></translation>
<translation id="385051799172605136">Zpět</translation>
<translation id="3889424535448813030">Klávesa šipka vpravo</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{před 1 měsícem}few{před # měsíci}many{před # měsíce}other{před # měsíci}}</translation>
<translation id="4289300219472526559">Začít mluvit</translation>
<translation id="430191667033048642">Aplikace <ph name="MOVED_APP_NAME" /> byla přesunuta do složky <ph name="FOLDER_NAME" /></translation>
+<translation id="4306392492252714209">Odstranit ze schránky.</translation>
<translation id="4316910396681052118">VŠECHNY APLIKACE</translation>
<translation id="4491109536499578614">Obrázek</translation>
<translation id="4588090240171750605">Posuv doprava</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Vymazat toto vyhledávání z historie?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emodži</translation>
+<translation id="7620655452534002301">Odstraněno.</translation>
<translation id="7658239707568436148">Zrušit</translation>
<translation id="7781829728241885113">Včera</translation>
<translation id="7814458197256864873">&amp;Kopírovat</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Načíst tuto stránku znovu</translation>
-<translation id="8144660977431427332">Pro vaše vyhledávání se používá technologie Asistenta Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplikace</translation>
<translation id="8259556432390118667">Hexadecimální kód barvy</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_da.xtb b/chromium/ui/strings/translations/ui_strings_da.xtb
index d230c709d41..0a5e34502a2 100644
--- a/chromium/ui/strings/translations/ui_strings_da.xtb
+++ b/chromium/ui/strings/translations/ui_strings_da.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Indbygget skærm</translation>
<translation id="335581015389089642">Tale</translation>
<translation id="3389286852084373014">Teksten er for lang</translation>
+<translation id="3406306243914553062">HTML-indhold</translation>
<translation id="348799646910989694">Hylden skjules automatisk</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> blev fastgjort</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag tilbage}one{# dage tilbage}other{# dage tilbage}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Nummer</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/sek.</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />, <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Fortsæt med at læse via din mobilenhed <ph name="TITLE" /></translation>
<translation id="385051799172605136">Tilbage</translation>
<translation id="3889424535448813030">Højrepil</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{For 1 måned siden}one{For # måned siden}other{For # måneder siden}}</translation>
<translation id="4289300219472526559">Start indtaling</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> blev flyttet til mappen <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Fjern fra udklipsholder.</translation>
<translation id="4316910396681052118">ALLE APPS</translation>
<translation id="4491109536499578614">Billede</translation>
<translation id="4588090240171750605">Scroll til højre</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Vil du slette denne søgning fra historikken?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Fjernet.</translation>
<translation id="7658239707568436148">Annuller</translation>
<translation id="7781829728241885113">I går</translation>
<translation id="7814458197256864873">&amp;Kopier</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Genindlæs siden</translation>
-<translation id="8144660977431427332">Dine søgninger leveres af Google Assistent. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, app</translation>
<translation id="8259556432390118667">Hex-farveværdi</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_de.xtb b/chromium/ui/strings/translations/ui_strings_de.xtb
index aca0aff3e00..c46456cbabf 100644
--- a/chromium/ui/strings/translations/ui_strings_de.xtb
+++ b/chromium/ui/strings/translations/ui_strings_de.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Integriertes Display</translation>
<translation id="335581015389089642">Sprachausgabe</translation>
<translation id="3389286852084373014">SMS zu lang</translation>
+<translation id="3406306243914553062">HTML-Inhalte</translation>
<translation id="348799646910989694">Ablage automatisch ausgeblendet</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> wurde angepinnt</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 Tag übrig}other{# Tage übrig}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Nummer</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783"><ph name="TITLE" /> auf meinem Mobilgerät weiterlesen</translation>
<translation id="385051799172605136">Zurück</translation>
<translation id="3889424535448813030">Rechtspfeil</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{vor 1 Monat}other{vor # Monaten}}</translation>
<translation id="4289300219472526559">Sprachausgabe starten</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> verschoben in <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Aus der Zwischenablage entfernen.</translation>
<translation id="4316910396681052118">ALLE APPS</translation>
<translation id="4491109536499578614">Bild</translation>
<translation id="4588090240171750605">Nach rechts blättern</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Diese Suchanfrage aus dem Verlauf löschen?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emojis</translation>
+<translation id="7620655452534002301">Entfernt.</translation>
<translation id="7658239707568436148">Abbrechen</translation>
<translation id="7781829728241885113">Gestern</translation>
<translation id="7814458197256864873">&amp;Kopieren</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 Stunde her}other{# Stunden her}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Noch 1 s}other{Noch # s}}</translation>
<translation id="8134065097954893699">Diese Seite neu laden</translation>
-<translation id="8144660977431427332">Ihre Suchanfragen werden mit Google Assistant durchgeführt. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, automatische Vervollständigung</translation>
<translation id="815598010540052116">Nach unten blättern</translation>
<translation id="8179976553408161302">Eingabetaste</translation>
<translation id="8210608804940886430">Nach unten</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabulatortaste</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, App</translation>
<translation id="8259556432390118667">Hex-Farbwert</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_el.xtb b/chromium/ui/strings/translations/ui_strings_el.xtb
index 57c26a230b7..5150ab12820 100644
--- a/chromium/ui/strings/translations/ui_strings_el.xtb
+++ b/chromium/ui/strings/translations/ui_strings_el.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ενσωματωμένη οθόνη</translation>
<translation id="335581015389089642">Ομιλία</translation>
<translation id="3389286852084373014">Το κείμενο είναι υπερβολικά μεγάλο</translation>
+<translation id="3406306243914553062">Περιεχόμενο HTML</translation>
<translation id="348799646910989694">Αυτόματη απόκρυψη ραφιού</translation>
<translation id="3554637740840164787">Το στοιχείο <ph name="ITEM_TITLE" /> καρφιτσώθηκε</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Απομένει 1 ημέρα}other{Απομένουν # ημέρες}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Αριθμός</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Συνέχεια ανάγνωσης από την κινητή συσκευή σας <ph name="TITLE" /></translation>
<translation id="385051799172605136">Πίσω</translation>
<translation id="3889424535448813030">Δεξιό βέλος</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Πριν από 1 μήνα}other{Πριν από # μήνες}}</translation>
<translation id="4289300219472526559">Έναρξη ομιλίας</translation>
<translation id="430191667033048642">Η εφαρμογή <ph name="MOVED_APP_NAME" /> μεταφέρθηκε στον φάκελο <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Κατάργηση από το πρόχειρο.</translation>
<translation id="4316910396681052118">ΟΛΕΣ ΟΙ ΕΦΑΡΜΟΓΕΣ</translation>
<translation id="4491109536499578614">Εικόνα</translation>
<translation id="4588090240171750605">Κύλιση δεξιά</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Να διαγραφεί αυτή η αναζήτηση από το ιστορικό σας;</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Καταργήθηκε.</translation>
<translation id="7658239707568436148">Ακύρωση</translation>
<translation id="7781829728241885113">Χθες</translation>
<translation id="7814458197256864873">&amp;Αντιγραφή</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{Πριν από 1 ώρα}other{Πριν από # ώρες}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Απομένει 1 δευτερόλεπτο}other{Απομένουν # δευτερόλεπτα}}</translation>
<translation id="8134065097954893699">Επαναφόρτωση αυτής της σελίδας</translation>
-<translation id="8144660977431427332">Οι αναζητήσεις σας παρέχονται από τον Βοηθό Google. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, αυτόματη συμπλήρωση</translation>
<translation id="815598010540052116">Κύλιση κάτω</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Επόμενη σελίδα</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Πλήκτρο tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, Εφαρμογή</translation>
<translation id="8259556432390118667">Δεκαεξαδική τιμή χρώματος</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_en-GB.xtb b/chromium/ui/strings/translations/ui_strings_en-GB.xtb
index af74bb1b47e..ba3a9cf957d 100644
--- a/chromium/ui/strings/translations/ui_strings_en-GB.xtb
+++ b/chromium/ui/strings/translations/ui_strings_en-GB.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Built-in display</translation>
<translation id="335581015389089642">Speech</translation>
<translation id="3389286852084373014">Text is too large</translation>
+<translation id="3406306243914553062">HTML content</translation>
<translation id="348799646910989694">Shelf auto hidden</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> was pinned</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 day left}other{# days left}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Number</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Continue reading from your mobile device <ph name="TITLE" /></translation>
<translation id="385051799172605136">Back</translation>
<translation id="3889424535448813030">Right Arrow</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 month ago}other{# months ago}}</translation>
<translation id="4289300219472526559">Start Speaking</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> moved to folder <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Remove from clipboard.</translation>
<translation id="4316910396681052118">ALL APPS</translation>
<translation id="4491109536499578614">Image</translation>
<translation id="4588090240171750605">Scroll Right</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Delete this search from your history?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Removed.</translation>
<translation id="7658239707568436148">Cancel</translation>
<translation id="7781829728241885113">Yesterday</translation>
<translation id="7814458197256864873">&amp;Copy</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Reloading this page</translation>
-<translation id="8144660977431427332">Your searches are powered by the Google Assistant. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, app</translation>
<translation id="8259556432390118667">Hex colour value</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_es-419.xtb b/chromium/ui/strings/translations/ui_strings_es-419.xtb
index b84790f4064..e1ad3117db3 100644
--- a/chromium/ui/strings/translations/ui_strings_es-419.xtb
+++ b/chromium/ui/strings/translations/ui_strings_es-419.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Pantalla integrada</translation>
<translation id="335581015389089642">Voz</translation>
<translation id="3389286852084373014">El texto es demasiado largo</translation>
+<translation id="3406306243914553062">Contenido HTML</translation>
<translation id="348799646910989694">Se ocultará la biblioteca automáticamente</translation>
<translation id="3554637740840164787">Se fijó <ph name="ITEM_TITLE" /></translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Falta 1 día.}other{Faltan # días.}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Número</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Sigue leyendo desde tu dispositivo móvil (<ph name="TITLE" />)</translation>
<translation id="385051799172605136">Atrás</translation>
<translation id="3889424535448813030">Flecha derecha</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Hace 1 mes}other{Hace # meses}}</translation>
<translation id="4289300219472526559">Empezar a hablar</translation>
<translation id="430191667033048642">Se movió <ph name="MOVED_APP_NAME" /> a la carpeta <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Quitar del portapapeles.</translation>
<translation id="4316910396681052118">TODAS LAS APPS</translation>
<translation id="4491109536499578614">Imagen</translation>
<translation id="4588090240171750605">Desplazar a la derecha</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">¿Deseas borrar esta búsqueda de tu Historial?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Eliminado.</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ayer</translation>
<translation id="7814458197256864873">&amp;Copiar</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Vuelve a cargar esta página</translation>
-<translation id="8144660977431427332">Tus búsquedas cuentan con la tecnología del Asistente de Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabulador</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, app</translation>
<translation id="8259556432390118667">Valor de color hexadecimal</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_es.xtb b/chromium/ui/strings/translations/ui_strings_es.xtb
index 1837231ea79..877c50f75c3 100644
--- a/chromium/ui/strings/translations/ui_strings_es.xtb
+++ b/chromium/ui/strings/translations/ui_strings_es.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Pantalla integrada</translation>
<translation id="335581015389089642">Voz</translation>
<translation id="3389286852084373014">El texto es demasiado largo</translation>
+<translation id="3406306243914553062">Contenido HTML</translation>
<translation id="348799646910989694">La estantería se ocultará automáticamente</translation>
<translation id="3554637740840164787">Se ha fijado <ph name="ITEM_TITLE" /></translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Queda 1 día}other{Quedan # días}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Número</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Continúa leyendo en tu dispositivo móvil <ph name="TITLE" /></translation>
<translation id="385051799172605136">Volver</translation>
<translation id="3889424535448813030">Flecha derecha</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Hace 1 mes}other{Hace # meses}}</translation>
<translation id="4289300219472526559">Empezar a hablar</translation>
<translation id="430191667033048642">Se ha movido <ph name="MOVED_APP_NAME" /> a la carpeta <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Quitar del portapapeles.</translation>
<translation id="4316910396681052118">TODAS LAS APLICACIONES</translation>
<translation id="4491109536499578614">Imagen</translation>
<translation id="4588090240171750605">Desplazar a la derecha</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">¿Eliminar esta búsqueda de tu historial?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Eliminado.</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ayer</translation>
<translation id="7814458197256864873">&amp;Copiar</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Vuelve a cargar esta página</translation>
-<translation id="8144660977431427332">Tus búsquedas usan la tecnología del Asistente de Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" /> o <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabulador</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplicación</translation>
<translation id="8259556432390118667">Valor de color hexadecimal</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_et.xtb b/chromium/ui/strings/translations/ui_strings_et.xtb
index e15f3cca2df..7f87fe2834e 100644
--- a/chromium/ui/strings/translations/ui_strings_et.xtb
+++ b/chromium/ui/strings/translations/ui_strings_et.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Sisseehitatud ekraan</translation>
<translation id="335581015389089642">Kõne</translation>
<translation id="3389286852084373014">Tekst on liiga pikk</translation>
+<translation id="3406306243914553062">HTML-sisu</translation>
<translation id="348799646910989694">Riiul on automaatselt peidetud</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> kinnitati</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 päev on jäänud}other{# päeva on jäänud}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Number</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Jätkake lugemist mobiilseadmes <ph name="TITLE" /></translation>
<translation id="385051799172605136">Tagasi</translation>
<translation id="3889424535448813030">Paremnool</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 kuu tagasi}other{# kuud tagasi}}</translation>
<translation id="4289300219472526559">Alusta rääkimist</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> teisaldati kausta <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Eemalda lõikelaualt.</translation>
<translation id="4316910396681052118">KÕIK RAKENDUSED</translation>
<translation id="4491109536499578614">Image</translation>
<translation id="4588090240171750605">Keri paremale</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Kas kustutada see otsing teie ajaloost?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emotikonid</translation>
+<translation id="7620655452534002301">Eemaldatud.</translation>
<translation id="7658239707568436148">Tühista</translation>
<translation id="7781829728241885113">Eile</translation>
<translation id="7814458197256864873">&amp;Kopeeri</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Lehe uuesti laadimine</translation>
-<translation id="8144660977431427332">Teie otsingud toimuvad Google'i assistendi toel. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabeldusklahv</translation>
<translation id="8247998213073982446">Rakendus, <ph name="APP_NAME" /></translation>
<translation id="8259556432390118667">Värvi kuueteistkümnendväärtus</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_eu.xtb b/chromium/ui/strings/translations/ui_strings_eu.xtb
index 518250170f3..0c9a17dbcd5 100644
--- a/chromium/ui/strings/translations/ui_strings_eu.xtb
+++ b/chromium/ui/strings/translations/ui_strings_eu.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Pantaila integratua</translation>
<translation id="335581015389089642">Hizketa</translation>
<translation id="3389286852084373014">Testua luzeegia da</translation>
+<translation id="3406306243914553062">HTML edukia</translation>
<translation id="348799646910989694">Apala automatikoki ezkutatuko da</translation>
<translation id="3554637740840164787">Ainguratu da <ph name="ITEM_TITLE" /></translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 egun gelditzen da}other{# egun gelditzen dira}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Zenbakia</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Jarraitu irakurtzen gailu mugikorrean <ph name="TITLE" /></translation>
<translation id="385051799172605136">Atzera</translation>
<translation id="3889424535448813030">Eskuin gezia</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Duela 1 hilabete}other{Duela # hilabete}}</translation>
<translation id="4289300219472526559">Hasi hitz egiten</translation>
<translation id="430191667033048642">Eraman da <ph name="MOVED_APP_NAME" /> aplikazioa <ph name="FOLDER_NAME" /> karpetara.</translation>
+<translation id="4306392492252714209">Kendu arbeletik.</translation>
<translation id="4316910396681052118">APLIKAZIO GUZTIAK</translation>
<translation id="4491109536499578614">Irudia</translation>
<translation id="4588090240171750605">Joan eskuinera</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Bilaketa hori historiatik ezabatu nahi duzu?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emojiak</translation>
+<translation id="7620655452534002301">Kendu da.</translation>
<translation id="7658239707568436148">Utzi</translation>
<translation id="7781829728241885113">Atzo</translation>
<translation id="7814458197256864873">&amp;Kopiatu</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{Duela 1 ordu}other{Duela # ordu}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 s gelditzen da}other{# s gelditzen dira}}</translation>
<translation id="8134065097954893699">Orri hau berriro kargatzea</translation>
-<translation id="8144660977431427332">Google-ren Laguntzailea eginbideak egiten ditu bilaketak. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, automatikoki betea</translation>
<translation id="815598010540052116">Egin behera</translation>
<translation id="8179976553408161302">Sartu</translation>
<translation id="8210608804940886430">Orrian behera</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabuladorea</translation>
<translation id="8247998213073982446">Aplikazioa (<ph name="APP_NAME" />)</translation>
<translation id="8259556432390118667">Kolore hamaseitarraren balioa</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fa.xtb b/chromium/ui/strings/translations/ui_strings_fa.xtb
index c7bd23b90b7..277c08f5d21 100644
--- a/chromium/ui/strings/translations/ui_strings_fa.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fa.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">نمایشگر داخلی</translation>
<translation id="335581015389089642">صدا</translation>
<translation id="3389286852084373014">نوشتار خیلی بزرگ است</translation>
+<translation id="3406306243914553062">‏محتوای HTML</translation>
<translation id="348799646910989694">پنهان شدن خودکار قفسه</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> پین شد</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{۱ روز باقی مانده است}one{# روز باقی مانده است}other{# روز باقی مانده است}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">عدد</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> گیگابایت/ثانیه</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> گیگابایت</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">ادامه خواندن در دستگاه همراه <ph name="TITLE" /></translation>
<translation id="385051799172605136">بازگشت</translation>
<translation id="3889424535448813030">پیکان راست</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{۱ ماه قبل}one{# ماه قبل}other{# ماه قبل}}</translation>
<translation id="4289300219472526559">شروع صحبت</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> به پوشه <ph name="FOLDER_NAME" /> منتقل شد.</translation>
+<translation id="4306392492252714209">برداشتن از بریده‌دان.</translation>
<translation id="4316910396681052118">همه برنامه‌ها</translation>
<translation id="4491109536499578614">تصویر</translation>
<translation id="4588090240171750605">پیمایش به راست</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">این جستجو از سابقه‌تان حذف شود؟</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ترابایت</translation>
<translation id="7507604095951736240">اموجی</translation>
+<translation id="7620655452534002301">حذف شد.</translation>
<translation id="7658239707568436148">لغو</translation>
<translation id="7781829728241885113">دیروز</translation>
<translation id="7814458197256864873">&amp;کپی</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{۱ ساعت قبل}one{# ساعت قبل}other{# ساعت قبل}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{۱ ثانیه باقی مانده است}one{# ثانیه باقی مانده است}other{# ثانیه باقی مانده است}}</translation>
<translation id="8134065097954893699">درحال تازه‌سازی این صفحه</translation>
-<translation id="8144660977431427332">‏جستجوهایتان را «دستیار Google» انجام می‌دهد. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />، تکمیل خودکار</translation>
<translation id="815598010540052116">پیمایش به پایین</translation>
<translation id="8179976553408161302">ورود</translation>
<translation id="8210608804940886430">صفحه پایین</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />،‏ <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />، برنامه</translation>
<translation id="8259556432390118667">مقدار رنگ در مبنای شانزده</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fi.xtb b/chromium/ui/strings/translations/ui_strings_fi.xtb
index ebddd035e8e..bfe749330e7 100644
--- a/chromium/ui/strings/translations/ui_strings_fi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fi.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Sisäänrakennettu näyttö</translation>
<translation id="335581015389089642">Puhe</translation>
<translation id="3389286852084373014">Teksti on liian suuri</translation>
+<translation id="3406306243914553062">HTML-sisältö</translation>
<translation id="348799646910989694">Hylly piilotettu automaattisesti</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> kiinnitettiin</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 päivä jäljellä}other{# päivää jäljellä}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Numero</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> Gt/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> Gt</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Jatka lukemista mobiililaitteella <ph name="TITLE" /></translation>
<translation id="385051799172605136">Takaisin</translation>
<translation id="3889424535448813030">Nuoli oik.</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 kuukausi sitten}other{# kuukautta sitten}}</translation>
<translation id="4289300219472526559">Aloita puhuminen</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> siirrettiin kansioon <ph name="FOLDER_NAME" /></translation>
+<translation id="4306392492252714209">Poista leikepöydältä.</translation>
<translation id="4316910396681052118">KAIKKI SOVELLUKSET</translation>
<translation id="4491109536499578614">Kuva</translation>
<translation id="4588090240171750605">Vieritä oikealle</translation>
@@ -212,7 +215,8 @@
<translation id="7430878839542012341">Poistetaanko tämä haku historiastasi?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> Tt</translation>
<translation id="7507604095951736240">Emoji</translation>
-<translation id="7658239707568436148">Peruuta</translation>
+<translation id="7620655452534002301">Poistettu</translation>
+<translation id="7658239707568436148">Peru</translation>
<translation id="7781829728241885113">Eilen</translation>
<translation id="7814458197256864873">K&amp;opioi</translation>
<translation id="7848989271541991537">Siirretty, nyt sivulla <ph name="PAGE_NUMBER" />, rivillä <ph name="ROW_NUMBER" />, sarakkeessa <ph name="COLUMN_NUMBER" />.</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Ladataan sivu uudelleen</translation>
-<translation id="8144660977431427332">Hakupalvelun tarjoaa Google Assistant. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Sarkain</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, sovellus</translation>
<translation id="8259556432390118667">Värin heksadesimaaliarvo</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fil.xtb b/chromium/ui/strings/translations/ui_strings_fil.xtb
index 5a1fc074076..de4b07423df 100644
--- a/chromium/ui/strings/translations/ui_strings_fil.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fil.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Built-in na display</translation>
<translation id="335581015389089642">Pananalita</translation>
<translation id="3389286852084373014">Masyadong malaki ang text</translation>
+<translation id="3406306243914553062">HTML na Content</translation>
<translation id="348799646910989694">Awtomatikong itinago ang shelf</translation>
<translation id="3554637740840164787">Na-pin ang <ph name="ITEM_TITLE" /></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>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Numero</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> (na) GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> (na) GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Magpatuloy sa pagbabasa mula sa iyong mobile device na <ph name="TITLE" /></translation>
<translation id="385051799172605136">Bumalik</translation>
<translation id="3889424535448813030">Right Arrow</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 buwan ang nakalipas}one{# buwan ang nakalipas}other{# na buwan ang nakalipas}}</translation>
<translation id="4289300219472526559">Simulan ang Pagsasalita</translation>
<translation id="430191667033048642">Inilipat ang <ph name="MOVED_APP_NAME" /> sa folder na <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Alisin sa clipboard.</translation>
<translation id="4316910396681052118">LAHAT NG APP</translation>
<translation id="4491109536499578614">Larawan</translation>
<translation id="4588090240171750605">Mag-scroll Pakanan</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">I-delete ang paghahanap na ito mula sa iyong history?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> (na) TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Inalis.</translation>
<translation id="7658239707568436148">Kanselahin</translation>
<translation id="7781829728241885113">Kahapon</translation>
<translation id="7814458197256864873">&amp;Kopyahin</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Nire-reload ang page na ito</translation>
-<translation id="8144660977431427332">Pinapatakbo ng Google Assistant ang iyong mga paghahanap. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, App</translation>
<translation id="8259556432390118667">Value ng kulay ng hex</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fr-CA.xtb b/chromium/ui/strings/translations/ui_strings_fr-CA.xtb
index bda0e9bc905..6a93df1cd4e 100644
--- a/chromium/ui/strings/translations/ui_strings_fr-CA.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fr-CA.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Écran intégré</translation>
<translation id="335581015389089642">Parole</translation>
<translation id="3389286852084373014">La taille du texte est trop grande</translation>
+<translation id="3406306243914553062">Contenu HTML</translation>
<translation id="348799646910989694">L'étagère est masquée automatiquement</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> a été épinglé</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 jour restant}one{# jour restant}other{# jours restants}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Numéro</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> Go/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> Go</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Poursuivez la lecture de <ph name="TITLE" /> sur votre appareil mobile</translation>
<translation id="385051799172605136">Retour</translation>
<translation id="3889424535448813030">Flèche vers la droite</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Il y a un mois}one{Il y a # mois}other{Il y a # mois}}</translation>
<translation id="4289300219472526559">Commencer la lecture</translation>
<translation id="430191667033048642">L'application <ph name="MOVED_APP_NAME" /> a été déplacée dans le dossier <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Retirer du presse-papiers.</translation>
<translation id="4316910396681052118">TOUTES LES APPLICATIONS</translation>
<translation id="4491109536499578614">Image</translation>
<translation id="4588090240171750605">Défilement vers la droite</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Supprimer cette recherche de votre historique?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> To</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Retiré.</translation>
<translation id="7658239707568436148">Annuler</translation>
<translation id="7781829728241885113">Hier</translation>
<translation id="7814458197256864873">&amp;Copier</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Actualiser cette page</translation>
-<translation id="8144660977431427332">Vos recherches sont optimisées par l'Assistant Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabulation</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, application</translation>
<translation id="8259556432390118667">Valeur de la couleur hexadécimale</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fr.xtb b/chromium/ui/strings/translations/ui_strings_fr.xtb
index 1576b867dfe..c5f063c88cd 100644
--- a/chromium/ui/strings/translations/ui_strings_fr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fr.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Écran de l'appareil</translation>
<translation id="335581015389089642">Voix</translation>
<translation id="3389286852084373014">Volume de texte trop important</translation>
+<translation id="3406306243914553062">Contenu HTML</translation>
<translation id="348799646910989694">Étagère automatiquement masquée</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> a été épinglé</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 jour restant}one{# jour restant}other{# jours restants}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Numéro</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> Go/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> Go</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Poursuivre la lecture de "<ph name="TITLE" />" depuis votre appareil mobile</translation>
<translation id="385051799172605136">Retour</translation>
<translation id="3889424535448813030">Droite</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Il y a 1 mois}one{Il y a # mois}other{Il y a # mois}}</translation>
<translation id="4289300219472526559">Commencer à parler</translation>
<translation id="430191667033048642">L'application <ph name="MOVED_APP_NAME" /> a été déplacée vers le dossier "<ph name="FOLDER_NAME" />".</translation>
+<translation id="4306392492252714209">Supprimer du presse-papiers.</translation>
<translation id="4316910396681052118">TOUTES LES APPLICATIONS</translation>
<translation id="4491109536499578614">Image</translation>
<translation id="4588090240171750605">Défilement vers la droite</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Supprimer cette recherche de votre historique ?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> To</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Supprimé</translation>
<translation id="7658239707568436148">Annuler</translation>
<translation id="7781829728241885113">Hier</translation>
<translation id="7814458197256864873">&amp;Copier</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Actualiser cette page</translation>
-<translation id="8144660977431427332">Vos recherches sont optimisées par l'Assistant Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabulation</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, application</translation>
<translation id="8259556432390118667">Valeur de couleur hexadécimale</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_gl.xtb b/chromium/ui/strings/translations/ui_strings_gl.xtb
index 9b5d6992761..835e2f9ab5c 100644
--- a/chromium/ui/strings/translations/ui_strings_gl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_gl.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Pantalla integrada</translation>
<translation id="335581015389089642">Voz</translation>
<translation id="3389286852084373014">O texto é demasiado longo</translation>
+<translation id="3406306243914553062">Contido HTML</translation>
<translation id="348799646910989694">O estante ocúltase automaticamente</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" />(fixouse)</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Queda 1 día}other{Quedan # días}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Número</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Continúa coa lectura desde o dispositivo móbil <ph name="TITLE" /></translation>
<translation id="385051799172605136">Atrás</translation>
<translation id="3889424535448813030">Frecha cara á dereita</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Hai un mes}other{Hai # meses}}</translation>
<translation id="4289300219472526559">Comeza a falar</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> moveuse ao cartafol <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Quitar do portapapeis.</translation>
<translation id="4316910396681052118">TODAS AS APLICACIÓNS</translation>
<translation id="4491109536499578614">Imaxe</translation>
<translation id="4588090240171750605">Desprazar cara á dereita</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Queres eliminar esta busca do historial?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emojis</translation>
+<translation id="7620655452534002301">Eliminouse.</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Onte</translation>
<translation id="7814458197256864873">&amp;Copiar</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{Hai unha hora}other{Hai # horas}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Queda un segundo}other{Quedan # segundos}}</translation>
<translation id="8134065097954893699">Volvendo cargar esta páxina</translation>
-<translation id="8144660977431427332">As túas buscas realízanse coa tecnoloxía do Asistente de Google. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, autocompletar</translation>
<translation id="815598010540052116">Desprazarse cara abaixo</translation>
<translation id="8179976553408161302">Intro</translation>
<translation id="8210608804940886430">Avanzar páxina</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabulador</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplicación</translation>
<translation id="8259556432390118667">Valor hexadecimal da cor</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_gu.xtb b/chromium/ui/strings/translations/ui_strings_gu.xtb
index 5b9c64db43e..3d6cc7c8708 100644
--- a/chromium/ui/strings/translations/ui_strings_gu.xtb
+++ b/chromium/ui/strings/translations/ui_strings_gu.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">બિલ્ટ-ઇન ડિસ્પ્લે</translation>
<translation id="335581015389089642">ભાષા</translation>
<translation id="3389286852084373014">ટેક્સ્ટ ખૂબ મોટી છે</translation>
+<translation id="3406306243914553062">HTML કન્ટેન્ટ</translation>
<translation id="348799646910989694">શેલ્ફ ઑટોમૅટિક રીતે છુપાવવામાં આવશે</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> પિન કરી હતી</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 દિવસ બાકી}one{# દિવસ બાકી}other{# દિવસ બાકી}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">નંબર</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">તમારા મોબાઇલ ઉપકરણ <ph name="TITLE" />માંથી વાંચવાનું ચાલુ રાખો</translation>
<translation id="385051799172605136">પાછળ</translation>
<translation id="3889424535448813030">જમણો એરો</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 મહિના પહેલાં}one{# મહિના પહેલાં}other{# મહિના પહેલાં}}</translation>
<translation id="4289300219472526559">બોલવાનું પ્રારંભ કરો</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" />ને ફોલ્ડર <ph name="FOLDER_NAME" />માં ખસેડી.</translation>
+<translation id="4306392492252714209">ક્લિપબોર્ડમાંથી કાઢી નાખો.</translation>
<translation id="4316910396681052118">બધી ઍપ્લિકેશનો</translation>
<translation id="4491109536499578614">છબી</translation>
<translation id="4588090240171750605">જમણે સ્ક્રોલ કરો</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">તમારા ઇતિહાસમાંથી આ શોધ ડિલીટ કરીએ?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">ઇમોજી</translation>
+<translation id="7620655452534002301">કાઢી નાખી.</translation>
<translation id="7658239707568436148">રદ કરો</translation>
<translation id="7781829728241885113">ગઈ કાલે</translation>
<translation id="7814458197256864873">&amp;કૉપિ કરો</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 કલાક પહેલા}one{# કલાક પહેલાં}other{# કલાક પહેલાં}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 સે બાકી}one{# સે બાકી}other{# સે બાકી}}</translation>
<translation id="8134065097954893699">આ પેજને ફરીથી લોડ કરી રહ્યાં છીએ</translation>
-<translation id="8144660977431427332">તમારી શોધ Google આસિસ્ટંટ દ્વારા પૂરી પાડવામાં આવે છે. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, ઑટોમેટિક રીતે પૂર્ણ</translation>
<translation id="815598010540052116">નીચે સ્ક્રોલ કરો</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">પૃષ્ઠ નીચે</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ટૅબ</translation>
<translation id="8247998213073982446">ઍપ: <ph name="APP_NAME" /></translation>
<translation id="8259556432390118667">રંગનું હેક્સ મૂલ્ય</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hi.xtb b/chromium/ui/strings/translations/ui_strings_hi.xtb
index 8eddf5d100e..c8ebddc81e9 100644
--- a/chromium/ui/strings/translations/ui_strings_hi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hi.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">पहले से मौजूद डिसप्ले</translation>
<translation id="335581015389089642">बोली</translation>
<translation id="3389286852084373014">टेक्स्ट बहुत बड़ा है</translation>
+<translation id="3406306243914553062">एचटीएमएल कॉन्टेंट</translation>
<translation id="348799646910989694">शेल्फ़ के अपने आप छिपने की सुविधा चालू है</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> को पिन किया गया</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 दिन शेष}one{# दिन शेष}other{# दिन शेष}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">कार्ड नंबर</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> जीबी/सेकंड</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> जीबी</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">अपने मोबाइल डिवाइस से <ph name="TITLE" /> पढ़ना जारी रखें</translation>
<translation id="385051799172605136">वापस जाएं</translation>
<translation id="3889424535448813030">दायां तीर</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 माह पहले}one{# माह पहले}other{# माह पहले}}</translation>
<translation id="4289300219472526559">बोलना प्रारंभ करें</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> को <ph name="FOLDER_NAME" /> में ले जाया गया</translation>
+<translation id="4306392492252714209">क्लिपबोर्ड से हटाएं.</translation>
<translation id="4316910396681052118">सभी ऐप्लिकेशन</translation>
<translation id="4491109536499578614">इमेज</translation>
<translation id="4588090240171750605">दाएं स्क्रोल करें</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">अपने इतिहास से यह खोज मिटाना चाहते हैं?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">इमोजी</translation>
+<translation id="7620655452534002301">हटाया गया.</translation>
<translation id="7658239707568436148">अभी नहीं</translation>
<translation id="7781829728241885113">बीता कल</translation>
<translation id="7814458197256864873">&amp;प्रतिलिपि बनाएं</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 घंटा पहले}one{# घंटे पहले}other{# घंटे पहले}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 सेकंड शेष}one{# सेकंड शेष}other{# सेकंड शेष}}</translation>
<translation id="8134065097954893699">इस पेज को फिर से लोड करें</translation>
-<translation id="8144660977431427332">आप जो चीज़ें खोजते हैं उनमें Google Assistant की मदद ली जाती है.<ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, अपने आप पूरा</translation>
<translation id="815598010540052116">नीचे स्क्रोल करें</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Page Down</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">टैब</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, ऐप्लिकेशन</translation>
<translation id="8259556432390118667">हेक्स रंग मान</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hr.xtb b/chromium/ui/strings/translations/ui_strings_hr.xtb
index 3975c2e0ed9..a578edb56a3 100644
--- a/chromium/ui/strings/translations/ui_strings_hr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hr.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ugrađeni zaslon</translation>
<translation id="335581015389089642">Govor</translation>
<translation id="3389286852084373014">Tekst je prevelik</translation>
+<translation id="3406306243914553062">HTML sadržaj</translation>
<translation id="348799646910989694">Polica je automatski skrivena</translation>
<translation id="3554637740840164787">Prikvačena je stavka <ph name="ITEM_TITLE" /></translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Još 1 dan}one{Još # dan}few{Još # dana}other{Još # dana}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Broj</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Nastavite čitati s mobilnog uređaja <ph name="TITLE" /></translation>
<translation id="385051799172605136">Natrag</translation>
<translation id="3889424535448813030">Strelica desno</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Prije mjesec dana}one{Prije # mjeseca}few{Prije # mjeseca}other{Prije # mjeseci}}</translation>
<translation id="4289300219472526559">Počni govoriti</translation>
<translation id="430191667033048642">Aplikacija <ph name="MOVED_APP_NAME" /> premještena je u mapu <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Ukloni iz međuspremnika.</translation>
<translation id="4316910396681052118">SVE APLIKACIJE</translation>
<translation id="4491109536499578614">Slika</translation>
<translation id="4588090240171750605">Pomakni se desno</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Želite li izbrisati to pretraživanje iz povijesti?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Uklonjeno.</translation>
<translation id="7658239707568436148">Odustani</translation>
<translation id="7781829728241885113">Danas</translation>
<translation id="7814458197256864873">&amp;Kopiraj</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Ponovno učitavanje te stranice</translation>
-<translation id="8144660977431427332">Vaša pretraživanja pokreće Google asistent. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Kartica</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplikacija</translation>
<translation id="8259556432390118667">Heksadecimalna vrijednost boje</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hu.xtb b/chromium/ui/strings/translations/ui_strings_hu.xtb
index c4b2bdfe231..b567884c2ef 100644
--- a/chromium/ui/strings/translations/ui_strings_hu.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hu.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Beépített kijelző</translation>
<translation id="335581015389089642">Beszéd</translation>
<translation id="3389286852084373014">A szöveg túl nagy</translation>
+<translation id="3406306243914553062">HTML-tartalom</translation>
<translation id="348799646910989694">A polc automatikusan elrejti magát</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> rögzítve</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 nap van hátra}other{# nap van hátra}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Szám</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783"><ph name="TITLE" /> olvasásának folytatása a mobileszközön</translation>
<translation id="385051799172605136">Vissza</translation>
<translation id="3889424535448813030">Jobb nyíl</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 hónapja}other{# hónapja}}</translation>
<translation id="4289300219472526559">Beszéd megkezdése</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> áthelyezve a következő mappába: <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Eltávolítás a vágólapról.</translation>
<translation id="4316910396681052118">MINDEN ALKALMAZÁS</translation>
<translation id="4491109536499578614">Kép</translation>
<translation id="4588090240171750605">Görgetés jobbra</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Törli ezt a keresést az előzmények közül?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Hangulatjel</translation>
+<translation id="7620655452534002301">Eltávolítva</translation>
<translation id="7658239707568436148">Mégse</translation>
<translation id="7781829728241885113">Tegnap</translation>
<translation id="7814458197256864873">&amp;Másolás</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Az oldal újratöltése</translation>
-<translation id="8144660977431427332">Kereséseit a Google Segéd teszi lehetővé. <ph name="LEARN_MORE" />.</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>
+<translation id="822964464349305906"><ph name="TYPE_1" /> és <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Lap</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, alkalmazás</translation>
<translation id="8259556432390118667">Hexadecimális színérték</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hy.xtb b/chromium/ui/strings/translations/ui_strings_hy.xtb
index 5b088169ff1..919e244cf48 100644
--- a/chromium/ui/strings/translations/ui_strings_hy.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hy.xtb
@@ -4,7 +4,7 @@
<translation id="1028699632127661925">Ուղարկվում է <ph name="DEVICE_NAME" /> սարքին...</translation>
<translation id="111910763555783249">Ծանուցման կարգավորումներ</translation>
<translation id="1127811143501539442">{DAYS,plural, =1{1 օր առաջ}one{# օր առաջ}other{# օր առաջ}}</translation>
-<translation id="1156623771253174079">{SECONDS,plural, =1{1 րոպե առաջ}one{# minutes ago}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="1201402288615127009">Հաջորդը</translation>
@@ -31,7 +31,7 @@
<translation id="1752946267035950200">{MINUTES,plural, =1{1 րոպե}one{# րոպե}other{# րոպե}}</translation>
<translation id="1761785978543082658"><ph name="QUANTITY" /> Բ</translation>
<translation id="1801827354178857021">Վերջակետ</translation>
-<translation id="1803208670097017349">{MONTHS,plural, =1{1 ամիս}one{# months}other{# ամիս}}</translation>
+<translation id="1803208670097017349">{MONTHS,plural, =1{1 ամիս}one{# ամիս}other{# ամիս}}</translation>
<translation id="1809410197924942083"><ph name="QUANTITY" /> ՄԲ/վ</translation>
<translation id="1830179671306812954">{HOURS,plural, =1{1 ժամ }one{# ժամ }other{# ժամ }}</translation>
<translation id="1830308660060964064">«<ph name="ITEM_TITLE" />» տարրն ապամրացվեց</translation>
@@ -76,7 +76,7 @@
<translation id="2743387203779672305">Պատճենել սեղմատախտակին</translation>
<translation id="2749082172777216925"><ph name="APP_NAME_INFO" />, <ph name="PRICE" /></translation>
<translation id="2803313416453193357">Բացել պանակը</translation>
-<translation id="2824719307700604149">{YEARS,plural, =1{1 տարի առաջ}one{# years ago}other{# տարի առաջ}}</translation>
+<translation id="2824719307700604149">{YEARS,plural, =1{1 տարի առաջ}one{# տարի առաջ}other{# տարի առաջ}}</translation>
<translation id="2878511608894704031">Ջնջել բոլորը</translation>
<translation id="2907671656515444832">{DAYS,plural, =1{1 օրից}one{# օրից}other{# օրից}}</translation>
<translation id="2931838996092594335">սեղմել</translation>
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ներկառուցված էկրան</translation>
<translation id="335581015389089642">Speech</translation>
<translation id="3389286852084373014">Տեքստը չափազանց մեծ է</translation>
+<translation id="3406306243914553062">HTML բովանդակություն</translation>
<translation id="348799646910989694">Դարակն ավտոմատ թաքցվում է</translation>
<translation id="3554637740840164787">«<ph name="ITEM_TITLE" />» տարրն ամրացվեց</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Մնացել է 1 օր}one{Մնացել է # օր}other{Մնացել է # օր}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Քարտի համարը</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> ԳԲ/վ</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> ԳԲ</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />։ <ph name="TYPE_2" />։</translation>
<translation id="3842239759367498783">Շարունակեք կարդալ «<ph name="TITLE" />» շարժական սարքից</translation>
<translation id="385051799172605136">Հետ</translation>
<translation id="3889424535448813030">Աջ սլաք</translation>
@@ -115,9 +117,10 @@
<translation id="40579289237549812">{UNREAD_NOTIFICATIONS,plural, =1{1 չկարդացված ծանուցում}one{# չկարդացված ծանուցում}other{# չկարդացված ծանուցում}}</translation>
<translation id="4202807286478387388">անցնել</translation>
<translation id="4250229828105606438">Սքրինշոթ</translation>
-<translation id="4266252015790371705">{MONTHS,plural, =1{1 ամիս առաջ}one{# months ago}other{# ամիս առաջ}}</translation>
+<translation id="4266252015790371705">{MONTHS,plural, =1{1 ամիս առաջ}one{# ամիս առաջ}other{# ամիս առաջ}}</translation>
<translation id="4289300219472526559">Start Speaking</translation>
<translation id="430191667033048642">«<ph name="MOVED_APP_NAME" />» հավելվածը տեղափոխվեց «<ph name="FOLDER_NAME" />» պանակ։</translation>
+<translation id="4306392492252714209">Հեռացնել սեղմատախտակից։</translation>
<translation id="4316910396681052118">ԲՈԼՈՐ ՀԱՎԵԼՎԱԾՆԵՐԸ</translation>
<translation id="4491109536499578614">Պատկեր</translation>
<translation id="4588090240171750605">Ոլորել դեպի աջ</translation>
@@ -126,7 +129,7 @@
<translation id="4690510401873698237">Դարակը ներքևում է</translation>
<translation id="4724120544754982507">Ծանուցումների կենտրոն, <ph name="UNREAD_NOTIFICATION_COUNT" /> չկարդացված ծանուցում</translation>
<translation id="4730374152663651037">ՀԱՃԱԽ ՕԳՏԱԳՈՐԾՎՈՂ</translation>
-<translation id="4788285488841504513">{MONTHS,plural, =1{Մնացել է 1 ամիս}one{# months left}other{Մնացել է # ամիս}}</translation>
+<translation id="4788285488841504513">{MONTHS,plural, =1{Մնացել է 1 ամիս}one{Մնացել է # ամիս}other{Մնացել է # ամիս}}</translation>
<translation id="4888938634149558681">Զանգել</translation>
<translation id="4968171027979920686">{SECONDS,plural, =1{1 վայրկյան}one{# վայրկյան}other{# վայրկյան}}</translation>
<translation id="4971687151119236543">Նախորդ կատարումը</translation>
@@ -178,7 +181,7 @@
<translation id="6404817160109697034">{SECONDS,plural, =1{1 վրկ առաջ}one{# վրկ առաջ}other{# վրկ առաջ}}</translation>
<translation id="6417265370957905582">Google Օգնական</translation>
<translation id="6430678249303439055">Արգելափակել այս հավելվածի բոլոր ծանուցումները</translation>
-<translation id="6483402905448010557">{SECONDS,plural, =1{1 վայրկյան առաջ}one{# seconds ago}other{# վայրկյան առաջ}}</translation>
+<translation id="6483402905448010557">{SECONDS,plural, =1{1 վայրկյան առաջ}one{# վայրկյան առաջ}other{# վայրկյան առաջ}}</translation>
<translation id="6503257047630241175">RTF ձևաչափով բովանդակություն</translation>
<translation id="6539092367496845964">Սխալ առաջացավ: Փորձեք ավելի ուշ:</translation>
<translation id="654149438358937226">Արգելափակել բոլոր ծանուցումները</translation>
@@ -196,7 +199,7 @@
<translation id="688711909580084195">Անվերնագիր վեբէջ</translation>
<translation id="6902419395050653510">HTML բովանդակություն։</translation>
<translation id="6907759265145635167"><ph name="QUANTITY" /> ՊԲ/վ</translation>
-<translation id="6917971086528278418">{YEARS,plural, =1{Մնացել է 1 տարի}one{# years left}other{Մնացել է # տարի}}</translation>
+<translation id="6917971086528278418">{YEARS,plural, =1{Մնացել է 1 տարի}one{Մնացել է # տարի}other{Մնացել է # տարի}}</translation>
<translation id="6945221475159498467">Ընտրել</translation>
<translation id="6965382102122355670">Եղավ</translation>
<translation id="6974053822202609517">Աջից ձախ</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Ջնջե՞լ այս որոնման հարցումը պատմությունից</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ՏԲ</translation>
<translation id="7507604095951736240">Զմայլիկներ</translation>
+<translation id="7620655452534002301">Հեռացվեց։</translation>
<translation id="7658239707568436148">Չեղարկել</translation>
<translation id="7781829728241885113">Երեկ</translation>
<translation id="7814458197256864873">&amp;Պատճենել</translation>
@@ -227,17 +231,17 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 ժամ առաջ}one{# ժամ առաջ}other{# ժամ առաջ}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Մնացել է 1 վրկ}one{Մնացել է # վրկ}other{Մնացել է # վրկ}}</translation>
<translation id="8134065097954893699">Այս էջը վերաբեռնվում է</translation>
-<translation id="8144660977431427332">Որոնման ձեր հարցումներն իրականացվում են Google Օգնականի միջոցով: <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, ինքնալրացում</translation>
<translation id="815598010540052116">Ոլորել ներքև</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Էջը վար</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, հավելված</translation>
<translation id="8259556432390118667">Գույնի տասնվեցական կոդը</translation>
<translation id="8328145009876646418">Ձախ եզր</translation>
<translation id="8331626408530291785">Ոլորել վեր</translation>
-<translation id="8352146631962686268">{YEARS,plural, =1{1 տարի}one{# years}other{# տարի}}</translation>
+<translation id="8352146631962686268">{YEARS,plural, =1{1 տարի}one{# տարի}other{# տարի}}</translation>
<translation id="838869780401515933">նշել</translation>
<translation id="8393700583063109961">Ուղարկել հաղորդագրություն</translation>
<translation id="8394908167088220973">Մեդիայի նվագարկում/դադար</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_id.xtb b/chromium/ui/strings/translations/ui_strings_id.xtb
index 4db4bda847d..4bffe4899ed 100644
--- a/chromium/ui/strings/translations/ui_strings_id.xtb
+++ b/chromium/ui/strings/translations/ui_strings_id.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Tampilan built-in</translation>
<translation id="335581015389089642">Ucapan</translation>
<translation id="3389286852084373014">Teks terlalu besar</translation>
+<translation id="3406306243914553062">Konten HTML</translation>
<translation id="348799646910989694">Rak otomatis disembunyikan</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> telah dipasangi pin</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 hari lagi}other{# hari lagi}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Nomor</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/dtk</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Lanjutkan membaca dari perangkat seluler <ph name="TITLE" /></translation>
<translation id="385051799172605136">Kembali</translation>
<translation id="3889424535448813030">Panah Kanan</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 bulan yang lalu}other{# bulan yang lalu}}</translation>
<translation id="4289300219472526559">Mulai Berbicara</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> dipindahkan ke folder <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Hapus dari papan klip.</translation>
<translation id="4316910396681052118">SEMUA APLIKASI</translation>
<translation id="4491109536499578614">Gambar</translation>
<translation id="4588090240171750605">Gulir ke Kanan</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Hapus penelusuran ini dari histori Anda?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Dihapus.</translation>
<translation id="7658239707568436148">Batal</translation>
<translation id="7781829728241885113">Kemarin</translation>
<translation id="7814458197256864873">&amp;Salin</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Memuat ulang halaman ini</translation>
-<translation id="8144660977431427332">Penelusuran Anda difasilitasi oleh Asisten Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, Aplikasi</translation>
<translation id="8259556432390118667">Nilai warna hex</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_is.xtb b/chromium/ui/strings/translations/ui_strings_is.xtb
index 526d1ed1036..8bd418cfb4d 100644
--- a/chromium/ui/strings/translations/ui_strings_is.xtb
+++ b/chromium/ui/strings/translations/ui_strings_is.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Innbyggður skjár</translation>
<translation id="335581015389089642">Tal</translation>
<translation id="3389286852084373014">Textinn er of stór</translation>
+<translation id="3406306243914553062">HTML-efni</translation>
<translation id="348799646910989694">Hilla falin sjálfkrafa</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> var fest</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dagur eftir}one{# dagur eftir}other{# dagar eftir}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Númer</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/sek.</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Haltu áfram að lesa í fartækinu <ph name="TITLE" /></translation>
<translation id="385051799172605136">Til baka</translation>
<translation id="3889424535448813030">Ör til hægri</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Fyrir einum mánuði}one{Fyrir # mánuði}other{Fyrir # mánuðum}}</translation>
<translation id="4289300219472526559">Byrja að tala</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> var fært í möppuna <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Fjarlægja af klippiborði</translation>
<translation id="4316910396681052118">ÖLL FORRIT</translation>
<translation id="4491109536499578614">Mynd</translation>
<translation id="4588090240171750605">Fletta til hægri</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Eyða þessari leit úr ferlinum?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Fjarlægt.</translation>
<translation id="7658239707568436148">Hætta við</translation>
<translation id="7781829728241885113">Í gær</translation>
<translation id="7814458197256864873">Afrita</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{Fyrir 1 klukkustund}one{Fyrir # klukkustund}other{Fyrir # klukkustundum}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 sek. eftir}one{# sek. eftir}other{# sek. eftir}}</translation>
<translation id="8134065097954893699">Endurhleður þessari síðu</translation>
-<translation id="8144660977431427332">Leitir eru knúnar af Google hjálparanum. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, sjálfvirk útfylling</translation>
<translation id="815598010540052116">Fletta niður</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Niður um síðu</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Flipi</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, forrit</translation>
<translation id="8259556432390118667">Litagildi fyrir sextándakerfi</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_it.xtb b/chromium/ui/strings/translations/ui_strings_it.xtb
index 9054dbdc983..22e09dfe955 100644
--- a/chromium/ui/strings/translations/ui_strings_it.xtb
+++ b/chromium/ui/strings/translations/ui_strings_it.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Display incorporato</translation>
<translation id="335581015389089642">Voce</translation>
<translation id="3389286852084373014">Il testo è troppo grande</translation>
+<translation id="3406306243914553062">Contenuti HTML</translation>
<translation id="348799646910989694">Shelf nascosto in automatico</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> è stato bloccato</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 giorno rimanente}other{# giorni rimanenti}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Numero</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Continua a leggere dal tuo dispositivo mobile <ph name="TITLE" /></translation>
<translation id="385051799172605136">Indietro</translation>
<translation id="3889424535448813030">Freccia destra</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 mese fa}other{# mesi fa}}</translation>
<translation id="4289300219472526559">Avvia comandi vocali</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> spostata nella cartella <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Rimuovi dagli appunti.</translation>
<translation id="4316910396681052118">TUTTE LE APP</translation>
<translation id="4491109536499578614">Immagine</translation>
<translation id="4588090240171750605">Scorri a destra</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Eliminare questa ricerca dalla cronologia?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Voce rimossa.</translation>
<translation id="7658239707568436148">Annulla</translation>
<translation id="7781829728241885113">Ieri</translation>
<translation id="7814458197256864873">&amp;Copia</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Ricaricare questa pagina</translation>
-<translation id="8144660977431427332">Le tue ricerche sono basate sulla tecnologia dell'Assistente Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabulazione</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, app</translation>
<translation id="8259556432390118667">Valore del colore esadecimale</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_iw.xtb b/chromium/ui/strings/translations/ui_strings_iw.xtb
index bdcc3922399..738a8113442 100644
--- a/chromium/ui/strings/translations/ui_strings_iw.xtb
+++ b/chromium/ui/strings/translations/ui_strings_iw.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">מסך מובנה</translation>
<translation id="335581015389089642">דיבור</translation>
<translation id="3389286852084373014">הטקסט ארוך מדי</translation>
+<translation id="3406306243914553062">‏תוכן HTML</translation>
<translation id="348799646910989694">המדף יוסתר באופן אוטומטי</translation>
<translation id="3554637740840164787">הפריט <ph name="ITEM_TITLE" /> הוצמד</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{נותר יום אחד}two{נותרו יומיים}many{נותרו # ימים}other{נותרו # ימים}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">מספר</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" />GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">אפשר להמשיך לקרוא מהמכשיר הנייד <ph name="TITLE" /></translation>
<translation id="385051799172605136">חזרה</translation>
<translation id="3889424535448813030">חץ לימין</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{לפני חודש אחד}two{לפני חודשיים}many{לפני # חודשים}other{לפני # חודשים}}</translation>
<translation id="4289300219472526559">יש להתחיל לדבר</translation>
<translation id="430191667033048642">האפליקציה <ph name="MOVED_APP_NAME" /> הועברה אל התיקייה <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">הסרה מהלוח.</translation>
<translation id="4316910396681052118">כל האפליקציות</translation>
<translation id="4491109536499578614">תמונה</translation>
<translation id="4588090240171750605">גלילה ימינה</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">למחוק את החיפוש הזה מההיסטוריה?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">אמוג'י</translation>
+<translation id="7620655452534002301">הרשומה הוסר.</translation>
<translation id="7658239707568436148">ביטול</translation>
<translation id="7781829728241885113">אתמול</translation>
<translation id="7814458197256864873">&amp;העתקה</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{לפני שעה אחת}two{לפני שעתיים}many{לפני # שעות}other{לפני # שעות}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{נותרה שנ‘ אחת}two{נותרו # שנ‘}many{נותרו # שנ‘}other{נותרו # שנ‘}}</translation>
<translation id="8134065097954893699">טעינה מחדש של הדף הזה</translation>
-<translation id="8144660977431427332">‏החיפושים שלך מופעלים על ידי Google Assistant. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, השלמה אוטומטית</translation>
<translation id="815598010540052116">גלילה למטה</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">דף למטה</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">כרטיסייה</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, אפליקציה</translation>
<translation id="8259556432390118667">ערך צבע הקסדצימלי</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ja.xtb b/chromium/ui/strings/translations/ui_strings_ja.xtb
index 9d564b6a408..c06d807a265 100644
--- a/chromium/ui/strings/translations/ui_strings_ja.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ja.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">内蔵ディスプレイ</translation>
<translation id="335581015389089642">スピーチ</translation>
<translation id="3389286852084373014">テキストが大きすぎます</translation>
+<translation id="3406306243914553062">HTML コンテンツ</translation>
<translation id="348799646910989694">シェルフは自動的に非表示になります</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> を固定しました</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{残り 1 日}other{残り # 日}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">番号</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/秒</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />。<ph name="TYPE_2" />。</translation>
<translation id="3842239759367498783">モバイル デバイスで読む: <ph name="TITLE" /></translation>
<translation id="385051799172605136">戻る</translation>
<translation id="3889424535448813030">右矢印キー</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 か月前}other{# か月前}}</translation>
<translation id="4289300219472526559">読み上げを開始</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> をフォルダ <ph name="FOLDER_NAME" /> に移動しました。</translation>
+<translation id="4306392492252714209">クリップボードから削除します。</translation>
<translation id="4316910396681052118">すべてのアプリ</translation>
<translation id="4491109536499578614">画像</translation>
<translation id="4588090240171750605">右にスクロール</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">この検索キーワードを履歴から削除しますか?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">絵文字</translation>
+<translation id="7620655452534002301">削除しました。</translation>
<translation id="7658239707568436148">キャンセル</translation>
<translation id="7781829728241885113">昨日</translation>
<translation id="7814458197256864873">コピー(&amp;C)</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 時間前}other{# 時間前}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{残り 1 秒}other{残り # 秒}}</translation>
<translation id="8134065097954893699">ページを再読み込み</translation>
-<translation id="8144660977431427332">検索は Google アシスタントによって行われます。<ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />、オートコンプリート</translation>
<translation id="815598010540052116">下にスクロール</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">次のページへ</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />、<ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">タブ</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />、アプリ</translation>
<translation id="8259556432390118667">16 進数色コード</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ka.xtb b/chromium/ui/strings/translations/ui_strings_ka.xtb
index 19e61bd263c..99e1469a367 100644
--- a/chromium/ui/strings/translations/ui_strings_ka.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ka.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">ჩაშენებული ეკრანი</translation>
<translation id="335581015389089642">მეტყველება</translation>
<translation id="3389286852084373014">ტექსტი მეტისმეტად დიდია</translation>
+<translation id="3406306243914553062">HTML კონტენტი</translation>
<translation id="348799646910989694">თარო ავტომატურად დამალულია</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> ჩამაგრებულია</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{დარჩენილია 1 დღე}other{დარჩენილია # დღე}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">ნომერი</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> გიგაბაიტი/წ</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> გიგაბაიტი</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">კითხვის გაგრძელება თქვენი მობილური მოწყობილობიდან <ph name="TITLE" /></translation>
<translation id="385051799172605136">უკან</translation>
<translation id="3889424535448813030">მარჯვენა ისარი</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 თვის წინ}other{# თვის წინ}}</translation>
<translation id="4289300219472526559">დაიწყეთ ლაპარაკი</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> გადატანილია საქაღალდეში <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">გაცვლის ბუფერიდან ამოშლა.</translation>
<translation id="4316910396681052118">ყველა აპი</translation>
<translation id="4491109536499578614">გამოსახულება</translation>
<translation id="4588090240171750605">გადაადგილება მარჯვნივ</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">გსურთ ამ ძიების წაშლა თქვენი ისტორიიდან?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ტბაიტი</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">ამოიშალა.</translation>
<translation id="7658239707568436148">გაუქმება</translation>
<translation id="7781829728241885113">გუშინ</translation>
<translation id="7814458197256864873">&amp;კოპირება</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 საათის წინ}other{# საათის წინ}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{დარჩენილია 1 წმ}other{დარჩენილია # წმ}}</translation>
<translation id="8134065097954893699">ამ გვერდის ხელახლა ჩატვირთვა</translation>
-<translation id="8144660977431427332">თქვენს ძიებებს უზრუნველყოფს Google ასისტენტი. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, ავტომატური დასრულება</translation>
<translation id="815598010540052116">გადაადგილება ქვემოთ</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">ერთი გვერდით ქვემოთ</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ჩანართი</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, აპი</translation>
<translation id="8259556432390118667">ფერის თექვსმეტობითი მნიშვნელობა</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_kk.xtb b/chromium/ui/strings/translations/ui_strings_kk.xtb
index 37693179e83..c8aebdd05fb 100644
--- a/chromium/ui/strings/translations/ui_strings_kk.xtb
+++ b/chromium/ui/strings/translations/ui_strings_kk.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ендірілген дисплей</translation>
<translation id="335581015389089642">Сөйлеу</translation>
<translation id="3389286852084373014">Мәтін өте үлкен</translation>
+<translation id="3406306243914553062">HTML мазмұны</translation>
<translation id="348799646910989694">Сөре автоматты түрде жасырылған.</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> бекітілді</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 күн қалды}other{# күн қалды}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Нөмір</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> ГБ/с</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> ГБ</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783"><ph name="TITLE" /> мобильдік құрылғысынан оқи беру</translation>
<translation id="385051799172605136">Артқа</translation>
<translation id="3889424535448813030">Оң жақ көрсеткісі</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 ай бұрын}other{# ай бұрын}}</translation>
<translation id="4289300219472526559">Сөйлеуді бастау</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> қолданбасы <ph name="FOLDER_NAME" /> қалтасына ауысты.</translation>
+<translation id="4306392492252714209">Буферден өшіру.</translation>
<translation id="4316910396681052118">БАРЛЫҚ ҚОЛДАНБАЛАР</translation>
<translation id="4491109536499578614">Кескін</translation>
<translation id="4588090240171750605">Оңға айналдыру</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Бұл іздеу шартын тарихтан өшіру керек пе?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ТБ</translation>
<translation id="7507604095951736240">Эмоджи</translation>
+<translation id="7620655452534002301">Жойылды.</translation>
<translation id="7658239707568436148">Бас тарту</translation>
<translation id="7781829728241885113">Кеше</translation>
<translation id="7814458197256864873">&amp;Көшіру</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 сағат бұрын}other{# сағат бұрын}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 сек. қалды}other{# сек. қалды}}</translation>
<translation id="8134065097954893699">Осы бетті қайта жүктеу</translation>
-<translation id="8144660977431427332">Іздеу тапсырмалары Google Assistant қызметінде орындалады. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, Автоматты толтыру</translation>
<translation id="815598010540052116">Төменге айналдыру</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Төменгі бетке өту</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, қолданба</translation>
<translation id="8259556432390118667">Түстің он алтылық коды</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_km.xtb b/chromium/ui/strings/translations/ui_strings_km.xtb
index ac68855c17b..af93eb4f909 100644
--- a/chromium/ui/strings/translations/ui_strings_km.xtb
+++ b/chromium/ui/strings/translations/ui_strings_km.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">ផ្ទាំងអេក្រង់ដែលភ្ជាប់​មក​ស្រាប់</translation>
<translation id="335581015389089642">ការនិយាយ</translation>
<translation id="3389286852084373014">អត្ថបទធំពេក</translation>
+<translation id="3406306243914553062">ខ្លឹមសារ HTML</translation>
<translation id="348799646910989694">លាក់​ធ្នើដោយ​ស្វ័យប្រវត្តិ</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> ត្រូវបានដៅ</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{នៅសល់ 1 ថ្ងៃទៀត}other{នៅសល់ # ថ្ងៃទៀត}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">លេខ</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/វិនាទី</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />។ <ph name="TYPE_2" />។</translation>
<translation id="3842239759367498783">បន្ដ​អាន​ពី​ឧបករណ៍​ចល័ត​របស់អ្នក <ph name="TITLE" /></translation>
<translation id="385051799172605136">ថយក្រោយ</translation>
<translation id="3889424535448813030">សញ្ញាព្រួញទៅស្តាំ</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 ខែមុន}other{# ខែមុន}}</translation>
<translation id="4289300219472526559">ចាប់ផ្តើមនិយាយ</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> ត្រូវបាន​ផ្លាស់ទី​ទៅថត <ph name="FOLDER_NAME" />។</translation>
+<translation id="4306392492252714209">លុបចេញពី​ឃ្លីបបត។</translation>
<translation id="4316910396681052118">កម្មវិធី​ទាំងអស់</translation>
<translation id="4491109536499578614">រូបភាព</translation>
<translation id="4588090240171750605">ទាញចុះទៅខាងស្តាំ</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">លុប​ការស្វែងរក​នេះពីប្រវត្តិ​របស់អ្នក?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">រូប​អារម្មណ៍</translation>
+<translation id="7620655452534002301">បានលុបចេញ។</translation>
<translation id="7658239707568436148">បដិសេធ</translation>
<translation id="7781829728241885113">ម្សិលមិញ</translation>
<translation id="7814458197256864873">ចម្លង</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{ 1 ម៉ោងមុន}other{# ម៉ោងមុន}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{នៅសល់ 1 វិនាទីទៀត}other{នៅសល់ # វិនាទីទៀត}}</translation>
<translation id="8134065097954893699">កំពុង​ផ្ទុកទំព័រនេះ​ឡើងវិញ</translation>
-<translation id="8144660977431427332">ការស្វែងរក​របស់អ្នកទទួល​បាន​ជំនួយពី Google ជំនួយការ។ <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" /> បំពេញ​ស្វ័យ​ប្រវត្តិ</translation>
<translation id="815598010540052116">ទាញចុះក្រោម</translation>
<translation id="8179976553408161302">បញ្ចូល</translation>
<translation id="8210608804940886430">Page Down</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ផ្ទាំង</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, កម្មវិធី</translation>
<translation id="8259556432390118667">តម្លៃពណ៌ Hex</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_kn.xtb b/chromium/ui/strings/translations/ui_strings_kn.xtb
index 7c622893b90..519b9d4160d 100644
--- a/chromium/ui/strings/translations/ui_strings_kn.xtb
+++ b/chromium/ui/strings/translations/ui_strings_kn.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">ಅಂತರ್ನಿರ್ಮಿತ ಡಿಸ್‌ಪ್ಲೇ</translation>
<translation id="335581015389089642">ಧ್ವನಿ</translation>
<translation id="3389286852084373014">ಪಠ್ಯ ತುಂಬಾ ದೊಡ್ಡದಾಗಿದೆ</translation>
+<translation id="3406306243914553062">HTML ವಿಷಯ</translation>
<translation id="348799646910989694">ಶೆಲ್ಫ್ ಸ್ವಯಂ ಮರೆಯಾಗಿದೆ</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> ಅನ್ನು ಪಿನ್ ಮಾಡಲಾಗಿದೆ</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 ದಿನ ಬಾಕಿ ಉಳಿದಿದೆ}one{# ದಿನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}other{# ದಿನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">ಸಂಖ್ಯೆ</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">ನಿಮ್ಮ ಮೊಬೈಲ್ ಸಾಧನ <ph name="TITLE" /> ನಿಂದ ಓದುವುದನ್ನು ಮುಂದುವರಿಸಿ</translation>
<translation id="385051799172605136">ಹಿಂದೆ</translation>
<translation id="3889424535448813030">ಬಲ ಬಾಣದ ಗುರುತು</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 ತಿಂಗಳ ಹಿಂದೆ}one{# ತಿಂಗಳುಗಳ ಹಿಂದೆ}other{# ತಿಂಗಳುಗಳ ಹಿಂದೆ}}</translation>
<translation id="4289300219472526559">ಮಾತನಾಡುವುದನ್ನು ಪ್ರಾರಂಭಿಸಿ</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> ಆ್ಯಪ್ ಅನ್ನು <ph name="FOLDER_NAME" /> ಫೋಲ್ಡರ್‌ಗೆ ಸರಿಸಲಾಗಿದೆ.</translation>
+<translation id="4306392492252714209">ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ನಿಂದ ತೆಗೆದುಹಾಕಿ.</translation>
<translation id="4316910396681052118">ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು</translation>
<translation id="4491109536499578614">ಚಿತ್ರ</translation>
<translation id="4588090240171750605">ಬಲಕ್ಕೆ ಸ್ಕ್ರೋಲ್ ಮಾಡಿ</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">ನಿಮ್ಮ ಇತಿಹಾಸದಿಂದ ಈ ಹುಡುಕಾಟವನ್ನು ಅಳಿಸುವುದೇ?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">ಎಮೋಜಿ</translation>
+<translation id="7620655452534002301">ತೆಗೆದುಹಾಕಲಾಗಿದೆ.</translation>
<translation id="7658239707568436148">ರದ್ದುಮಾಡಿ</translation>
<translation id="7781829728241885113">ನಿನ್ನೆ</translation>
<translation id="7814458197256864873">&amp;ನಕಲಿಸಿ</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 ಗಂಟೆ ಹಿಂದೆ}one{# ಗಂಟೆಗಳ ಹಿಂದೆ}other{# ಗಂಟೆಗಳ ಹಿಂದೆ}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 ಸೆಕೆಂಡ್ ಬಾಕಿ ಉಳಿದಿದೆ}one{# ಸೆಕೆಂಡುಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}other{# ಸೆಕೆಂಡುಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}}</translation>
<translation id="8134065097954893699">ಈ ಪುಟ ಮರುಲೋಡ್ ಆಗುತ್ತಿದೆ</translation>
-<translation id="8144660977431427332">ನಿಮ್ಮ ಹುಡುಕಾಟಗಳು Google ಅಸಿಸ್ಟೆಂಟ್‌ನಿಂದ ಪ್ರಾಯೋಜಿತವಾಗಿವೆ. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, ಸ್ವಯಂಪೂರ್ಣಗೊಳಿಸುವಿಕೆ</translation>
<translation id="815598010540052116">ಕೆಳಗೆ ಸ್ಕ್ರೋಲ್ ಮಾಡು</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">ಪುಟ ಕೆಳಗೆ</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ಟ್ಯಾಬ್</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, ಆ್ಯಪ್</translation>
<translation id="8259556432390118667">ಹೆಕ್ಸ್ ಬಣ್ಣ ಮೌಲ್ಯ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ko.xtb b/chromium/ui/strings/translations/ui_strings_ko.xtb
index 9e2154f20a8..7ff19b1891f 100644
--- a/chromium/ui/strings/translations/ui_strings_ko.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ko.xtb
@@ -72,7 +72,7 @@
<translation id="2586657967955657006">클립보드</translation>
<translation id="2666092431469916601">맨 위</translation>
<translation id="2701330563083355633"><ph name="DEVICE_NAME" />에서 공유함</translation>
-<translation id="271033894570825754">새 파일</translation>
+<translation id="271033894570825754">New</translation>
<translation id="2743387203779672305">클립보드로 복사</translation>
<translation id="2749082172777216925"><ph name="APP_NAME_INFO" />, <ph name="PRICE" /></translation>
<translation id="2803313416453193357">폴더 열기</translation>
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">내장 디스플레이</translation>
<translation id="335581015389089642">음성</translation>
<translation id="3389286852084373014">텍스트가 너무 큼</translation>
+<translation id="3406306243914553062">HTML 콘텐츠</translation>
<translation id="348799646910989694">실행기 자동 숨김</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> 고정됨</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1일 남음}other{#일 남음}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">번호</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" />GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" />GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="3842239759367498783">휴대기기에서 <ph name="TITLE" /> 계속 읽기</translation>
<translation id="385051799172605136">뒤로</translation>
<translation id="3889424535448813030">오른쪽 화살표</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1개월 전}other{#개월 전}}</translation>
<translation id="4289300219472526559">말하기 시작</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> 앱이 <ph name="FOLDER_NAME" /> 폴더로 이동했습니다.</translation>
+<translation id="4306392492252714209">클립보드에서 삭제합니다.</translation>
<translation id="4316910396681052118">모든 앱</translation>
<translation id="4491109536499578614">이미지</translation>
<translation id="4588090240171750605">오른쪽 스크롤</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">기록에서 검색어를 삭제하시겠습니까?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" />TB</translation>
<translation id="7507604095951736240">그림 이모티콘</translation>
+<translation id="7620655452534002301">삭제되었습니다.</translation>
<translation id="7658239707568436148">취소</translation>
<translation id="7781829728241885113">어제</translation>
<translation id="7814458197256864873">복사(&amp;C)</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1시간 전}other{#시간 전}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1초 남음}other{#초 남음}}</translation>
<translation id="8134065097954893699">페이지 새로고침</translation>
-<translation id="8144660977431427332">Google 어시스턴트가 지원되는 검색입니다. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, 자동 완성</translation>
<translation id="815598010540052116">아래로 스크롤</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">페이지 아래로</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">탭</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, 앱</translation>
<translation id="8259556432390118667">16진수 색상 값</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ky.xtb b/chromium/ui/strings/translations/ui_strings_ky.xtb
index db44e01d6e5..58fd06d0af2 100644
--- a/chromium/ui/strings/translations/ui_strings_ky.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ky.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Кыстарылган дисплей</translation>
<translation id="335581015389089642">Кеп</translation>
<translation id="3389286852084373014">Тексттин көлөмү өтө чоң</translation>
+<translation id="3406306243914553062">HTML мазмуну</translation>
<translation id="348799646910989694">Текче автоматтык түрдө жашырылды</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> кадалды</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 күн калды}other{# күн калды}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Сан</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> Гб/сек.</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> Гб</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783"><ph name="TITLE" /> мобилдик түзмөгүңүздөн улантып окуңуз</translation>
<translation id="385051799172605136">Артка</translation>
<translation id="3889424535448813030">Оң жебе</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 ай мурун}other{# ай мурун}}</translation>
<translation id="4289300219472526559">Сүйлөп баштаңыз</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> <ph name="FOLDER_NAME" /> папкасына жылдырылды.</translation>
+<translation id="4306392492252714209">Алмашуу буферинен өчүрүү.</translation>
<translation id="4316910396681052118">БАРДЫК КОЛДОНМОЛОР</translation>
<translation id="4491109536499578614">Сүрөт</translation>
<translation id="4588090240171750605">Оңго сыдырып кароо</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Бул издөө таржымалыңыздан жок кылынсынбы?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> Тб</translation>
<translation id="7507604095951736240">Быйтыкча</translation>
+<translation id="7620655452534002301">Өчүрүлдү.</translation>
<translation id="7658239707568436148">Жокко чыгаруу</translation>
<translation id="7781829728241885113">Кечээ</translation>
<translation id="7814458197256864873">&amp;Көчүрүү</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 саат мурун}other{# саат мурун}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 сек. калды}other{# сек. калды}}</translation>
<translation id="8134065097954893699">Бул баракты кайрадан жүктөңүз</translation>
-<translation id="8144660977431427332">Издөөнү Google Жардамчы аткарат. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, автотолтуруу</translation>
<translation id="815598010540052116">Ылдый сыдыруу</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Ылдый барактоо</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Өтмөк</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, Колдонмо</translation>
<translation id="8259556432390118667">Он алты түстүү код</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_lo.xtb b/chromium/ui/strings/translations/ui_strings_lo.xtb
index 334bd1f9855..9a3ff27603e 100644
--- a/chromium/ui/strings/translations/ui_strings_lo.xtb
+++ b/chromium/ui/strings/translations/ui_strings_lo.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">ຈໍສະແດງຜົນໃນຕົວ</translation>
<translation id="335581015389089642">ການເວົ້າ</translation>
<translation id="3389286852084373014">ຂໍ້ຄວາມໃຫຍ່ເກີນໄປ</translation>
+<translation id="3406306243914553062">ເນື້ອຫາ HTML</translation>
<translation id="348799646910989694">ເຊື່ອງຊັ້ນວາງໂດຍອັດຕະໂນມັດແລ້ວ</translation>
<translation id="3554637740840164787">ປັກໝຸດ <ph name="ITEM_TITLE" /> ແລ້ວ</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{ຍັງ​ເຫຼືອ 1 ວັນ}other{ຍັງ​ເຫຼືອ # ວັນ}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">ໝາຍເລກ</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/ວິນາທີ</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">ສືບຕໍ່ອ່ານຈາກອຸປະກອນມືຖືຂອງທ່ານ <ph name="TITLE" /></translation>
<translation id="385051799172605136">ກັບ​ຄືນ​</translation>
<translation id="3889424535448813030">ລູກ​ສອນ​ເບື້ອງຂວາ</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 ເດືອນກ່ອນນີ້}other{# ເດືອນກ່ອນນີ້}}</translation>
<translation id="4289300219472526559">ເລີ່ມ​ຕົ້ນ​ເວົ້າ</translation>
<translation id="430191667033048642">ຍ້າຍ <ph name="MOVED_APP_NAME" /> ໄປຫາໂຟນເດີ <ph name="FOLDER_NAME" /> ແລ້ວ.</translation>
+<translation id="4306392492252714209">ລຶບອອກຈາກຄລິບບອດ.</translation>
<translation id="4316910396681052118">ທຸກແອັບ</translation>
<translation id="4491109536499578614">ຮູບ​</translation>
<translation id="4588090240171750605">ເລື່ອນໄປທາງຂວາ</translation>
@@ -190,7 +193,7 @@
<translation id="6710213216561001401">ຜ່ານມາ</translation>
<translation id="6786750046913594791">ປິດໂຟລເດີ</translation>
<translation id="6808150112686056157">ຢຸດມີເດຍ</translation>
-<translation id="6845383723252244143">ເລືອກໂຟລເດີ</translation>
+<translation id="6845383723252244143">ເລືອກໂຟນເດີ</translation>
<translation id="6845533974506654842">ກົດ</translation>
<translation id="6863590663815976734">{HOURS,plural, =1{ຍັງ​ເຫຼືອ 1 ຊົ່ວ​ໂມງ}other{ຍັງ​ເຫຼືອ # ຊົ່ວ​ໂມງ}}</translation>
<translation id="688711909580084195">ໜ້າເວັບບໍ່ມີຊື່</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">ລຶບການຊອກຫາອອກຈາກປະຫວັດຂອງທ່ານບໍ?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">ອີໂມຈິ</translation>
+<translation id="7620655452534002301">ລຶບອອກແລ້ວ.</translation>
<translation id="7658239707568436148">ຍົກ​ເລີກ​</translation>
<translation id="7781829728241885113">ມື້​ວານ​ນີ້</translation>
<translation id="7814458197256864873">ກັອບປີ້</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 ຊົ່ວໂມງກ່ອນນີ້}other{# ຊົ່ວ​ໂມງ​ກ່ອນ​ນີ້}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{ຍັງ​ເຫຼື 1 ວິ​ນາ​ທີ}other{ຍັງ​ເຫຼືອ # ວິ​ນາ​ທີ}}</translation>
<translation id="8134065097954893699">ກຳລັງໂຫຼດໜ້ານີ້ຄືນໃໝ່</translation>
-<translation id="8144660977431427332">ການຊອກຫາຂອງທ່ານຂັບເຄື່ອນໂດຍຜູ້ຊ່ວຍ Google. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, ຕື່ມອັດຕະໂນມັດ</translation>
<translation id="815598010540052116">ເລື່ອນລົງ</translation>
<translation id="8179976553408161302">ປ້ອນເຂົ້າ</translation>
<translation id="8210608804940886430">ຫນ້າ​ລົງ</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ແຖບ</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, ແອັບ</translation>
<translation id="8259556432390118667">ຄ່າສີແບບເລກຖານສິບຫົກ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_lt.xtb b/chromium/ui/strings/translations/ui_strings_lt.xtb
index 4a94db982ca..b2aa438e32c 100644
--- a/chromium/ui/strings/translations/ui_strings_lt.xtb
+++ b/chromium/ui/strings/translations/ui_strings_lt.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Įtaisytasis ekranas</translation>
<translation id="335581015389089642">Kalba</translation>
<translation id="3389286852084373014">Teksto pranešimas per didelis</translation>
+<translation id="3406306243914553062">HTML turinys</translation>
<translation id="348799646910989694">Lentyna automatiškai slepiama</translation>
<translation id="3554637740840164787">Prisegta: <ph name="ITEM_TITLE" /></translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Liko 1 diena}one{Liko # diena}few{Liko # dienos}many{Liko # dienos}other{Liko # dienų}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Numeris</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Toliau skaityti iš mobiliojo įrenginio „<ph name="TITLE" />“</translation>
<translation id="385051799172605136">Atgal</translation>
<translation id="3889424535448813030">Rodyklė į dešinę</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Prieš 1 mėnesį}one{Prieš # mėnesį}few{Prieš # mėnesius}many{Prieš # mėnesio}other{Prieš # mėnesių}}</translation>
<translation id="4289300219472526559">Pradėti kalbėti</translation>
<translation id="430191667033048642">„<ph name="MOVED_APP_NAME" />“ perkelta į aplanką „<ph name="FOLDER_NAME" />“.</translation>
+<translation id="4306392492252714209">Pašalinti iš iškarpinės.</translation>
<translation id="4316910396681052118">VISOS PROGRAMOS</translation>
<translation id="4491109536499578614">Vaizdas</translation>
<translation id="4588090240171750605">Slinkti į dešinę</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Ištrinti šią paiešką iš istorijos?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Jaustukai</translation>
+<translation id="7620655452534002301">Pašalinta.</translation>
<translation id="7658239707568436148">Atšaukti</translation>
<translation id="7781829728241885113">Vakar</translation>
<translation id="7814458197256864873">&amp;Kopijuoti</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Šis puslapis įkeliamas iš naujo</translation>
-<translation id="8144660977431427332">Jūsų paieškos veikia su „Google Assistant“. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Skirtukas</translation>
<translation id="8247998213073982446">„<ph name="APP_NAME" />“, programa</translation>
<translation id="8259556432390118667">Šešioliktainės spalvos vertė</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_lv.xtb b/chromium/ui/strings/translations/ui_strings_lv.xtb
index d93f65a7739..e3499e57351 100644
--- a/chromium/ui/strings/translations/ui_strings_lv.xtb
+++ b/chromium/ui/strings/translations/ui_strings_lv.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Iebūvēts displejs</translation>
<translation id="335581015389089642">Runa</translation>
<translation id="3389286852084373014">Teksts ir pārāk liels</translation>
+<translation id="3406306243914553062">HTML saturs</translation>
<translation id="348799646910989694">Plaukts tiek automātiski paslēpts</translation>
<translation id="3554637740840164787">Vienums <ph name="ITEM_TITLE" /> tika piesprausts</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Atlikusi 1 diena}zero{Atlikušas # dienas}one{Atlikusi # diena}other{Atlikušas # dienas}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Numurs</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Turpiniet lasīt no savas mobilās ierīces <ph name="TITLE" /></translation>
<translation id="385051799172605136">Atpakaļ</translation>
<translation id="3889424535448813030">Labā bulta</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Pirms 1 mēneša}zero{Pirms # mēnešiem}one{Pirms # mēneša}other{Pirms # mēnešiem}}</translation>
<translation id="4289300219472526559">Sākt runāt</translation>
<translation id="430191667033048642">Lietotne <ph name="MOVED_APP_NAME" /> pārvietota uz mapi <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Noņemt no starpliktuves.</translation>
<translation id="4316910396681052118">VISAS LIETOTNES</translation>
<translation id="4491109536499578614">Attēls</translation>
<translation id="4588090240171750605">Ritināt pa labi</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Vai dzēst šo meklēšanas vaicājumu no vēstures?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emocijzīmes</translation>
+<translation id="7620655452534002301">Noņemts.</translation>
<translation id="7658239707568436148">Atcelt</translation>
<translation id="7781829728241885113">Vakar</translation>
<translation id="7814458197256864873">Ko&amp;pēt</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Notiek atkārtota šīs lapas ielādēšana</translation>
-<translation id="8144660977431427332">Jūsu meklēšanas vaicājumus nodrošina Google asistents. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabulēšanas taustiņš</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, lietotne</translation>
<translation id="8259556432390118667">Heksadecimāla krāsas vērtība</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_mk.xtb b/chromium/ui/strings/translations/ui_strings_mk.xtb
index ede2edcc6f1..45916428b0b 100644
--- a/chromium/ui/strings/translations/ui_strings_mk.xtb
+++ b/chromium/ui/strings/translations/ui_strings_mk.xtb
@@ -29,7 +29,7 @@
<translation id="169515659049020177">Shift</translation>
<translation id="1710340000377843106">сега</translation>
<translation id="1752946267035950200">{MINUTES,plural, =1{1 минута}one{# минута}other{# минути}}</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY" /> Б</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY" /> B</translation>
<translation id="1801827354178857021">Точка</translation>
<translation id="1803208670097017349">{MONTHS,plural, =1{1 месец}one{# месец}other{# месеци}}</translation>
<translation id="1809410197924942083"><ph name="QUANTITY" /> MB/s</translation>
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Вграден екран</translation>
<translation id="335581015389089642">Говор</translation>
<translation id="3389286852084373014">Премногу е долго</translation>
+<translation id="3406306243914553062">HTML-содржини</translation>
<translation id="348799646910989694">Полицата е автоматски сокриена</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> е прикачена</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Преостана 1 ден}one{Преостана # ден}other{Преостанаа # дена}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Број</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/с</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Продолжете со читање од мобилниот уред <ph name="TITLE" /></translation>
<translation id="385051799172605136">Назад</translation>
<translation id="3889424535448813030">Стрелка надесно</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Пред 1 месец}one{Пред # месец}other{Пред # месеци}}</translation>
<translation id="4289300219472526559">Започни со говорење</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> е преместена во папката <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Отстранете од привремената меморија.</translation>
<translation id="4316910396681052118">СИТЕ АПЛИКАЦИИ</translation>
<translation id="4491109536499578614">Слика</translation>
<translation id="4588090240171750605">Лизгај надесно</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Да се избрише пребарувањево од историјата?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ТБ</translation>
<translation id="7507604095951736240">Емотикони</translation>
+<translation id="7620655452534002301">Отстрането.</translation>
<translation id="7658239707568436148">Откажи</translation>
<translation id="7781829728241885113">Вчера</translation>
<translation id="7814458197256864873">&amp;Копирај</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{Пред 1 час}one{Пред # час}other{Пред # часа}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Преостана 1 сек.}one{Преостана # сек.}other{Преостанаа # сек.}}</translation>
<translation id="8134065097954893699">Вчитајте ја страницава повторно</translation>
-<translation id="8144660977431427332">Пребарувањата се овозможени од „Помошникот на Google“. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, автоматско довршување</translation>
<translation id="815598010540052116">Лизгај надолу</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Страница подолу</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Копчето Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, апликација</translation>
<translation id="8259556432390118667">Вредност за хексадецимална боја</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ml.xtb b/chromium/ui/strings/translations/ui_strings_ml.xtb
index 40f0ce3de8f..ed60774d824 100644
--- a/chromium/ui/strings/translations/ui_strings_ml.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ml.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">ബിൽറ്റ് ഇൻ ഡിസ്‌പ്ലേ</translation>
<translation id="335581015389089642">സംഭാഷണം</translation>
<translation id="3389286852084373014">ടെക്‌സ്‌റ്റ് വളരെ വലുതാണ്</translation>
+<translation id="3406306243914553062">HTML ഉള്ളടക്കം</translation>
<translation id="348799646910989694">ഷെൽഫ് സ്വയമേവ മറച്ചു</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> പിൻ ചെയ്‌തു</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{ഒരു ദിവസം ശേഷിക്കുന്നു}other{# ദിവസം ശേഷിക്കുന്നു}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">നമ്പർ</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">നിങ്ങളുടെ <ph name="TITLE" /> എന്ന മൊബൈലിൽ നിന്ന് വായന തുടരുക</translation>
<translation id="385051799172605136">പിന്നോട്ട്</translation>
<translation id="3889424535448813030">വലതുഭാഗത്തെ അമ്പടയാളം</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{ഒരു മാസം മുമ്പ്}other{# മാസം മുമ്പ്}}</translation>
<translation id="4289300219472526559">സംഭാഷണം ആരംഭിക്കുക</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> എന്ന ആപ്പിനെ <ph name="FOLDER_NAME" /> എന്ന ഫോൾഡറിലേക്ക് നീക്കി.</translation>
+<translation id="4306392492252714209">ക്ലിപ്പ്ബോർഡിൽ നിന്ന് നീക്കം ചെയ്യുക.</translation>
<translation id="4316910396681052118">എല്ലാ ആപ്പുകളും</translation>
<translation id="4491109536499578614">ചിത്രം</translation>
<translation id="4588090240171750605">വലത്തോട്ട് സ്ക്രോള്‍ ചെയ്യുക</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">നിങ്ങളുടെ ചരിത്രത്തിൽ നിന്ന് ഈ തിരയൽ ഇല്ലാതാക്കണോ?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">ഇമോജി</translation>
+<translation id="7620655452534002301">നീക്കം ചെയ്തു.</translation>
<translation id="7658239707568436148">റദ്ദാക്കൂ</translation>
<translation id="7781829728241885113">ഇന്നലെ</translation>
<translation id="7814458197256864873">&amp;പകര്‍ത്തൂ</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{ഒരു മണിക്കൂര്‍ മുമ്പ്}other{# മണിക്കൂർ മുമ്പ്}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{ഒരു സെക്കൻഡ് ശേഷിക്കുന്നു}other{# സെക്കൻഡ് ശേഷിക്കുന്നു}}</translation>
<translation id="8134065097954893699">ഈ പേജ് റീലോഡ് ചെയ്യുന്നു</translation>
-<translation id="8144660977431427332">നിങ്ങളുടെ തിരയലുകൾ നൽകുന്നത് Google അസിസ്‌റ്റൻ്റ് ആണ്. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, സ്വയമേവ പൂർത്തിയാക്കുക</translation>
<translation id="815598010540052116">താഴേയ്‌ക്ക് സ്ക്രോൾ ചെയ്യുക</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">താഴെയുള്ള പേജുകള്‍</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ടാബ്</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, ആപ്പ്</translation>
<translation id="8259556432390118667">ഹെക്‌സ് വർണ മൂല്യം</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_mn.xtb b/chromium/ui/strings/translations/ui_strings_mn.xtb
index ce3d1c54b6d..ff036411c18 100644
--- a/chromium/ui/strings/translations/ui_strings_mn.xtb
+++ b/chromium/ui/strings/translations/ui_strings_mn.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Суурилагдсан дэлгэц</translation>
<translation id="335581015389089642">Хэлсэн үг</translation>
<translation id="3389286852084373014">Текст хэт том байна</translation>
+<translation id="3406306243914553062">HTML контент</translation>
<translation id="348799646910989694">Shelf-г автоматаар нууна</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" />-г бэхэллээ</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 өдөр үлдсэн}other{# өдөр үлдсэн}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Тоо</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/с</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783"><ph name="TITLE" /> гар утаснаасаа үргэлжлүүлэн унших</translation>
<translation id="385051799172605136">Буцах</translation>
<translation id="3889424535448813030">Баруун тийш заасан сум</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 сарын өмнө}other{# сарын өмнө}}</translation>
<translation id="4289300219472526559">Ярьж эхлэх</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" />-г <ph name="FOLDER_NAME" /> фолдерт зөөсөн.</translation>
+<translation id="4306392492252714209">Түр санах ойгоос хасна.</translation>
<translation id="4316910396681052118">БҮХ АПП</translation>
<translation id="4491109536499578614">Зураг</translation>
<translation id="4588090240171750605">Баруун тийш гүйлгэх</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Энэ хайлтыг түүхээсээ устгах уу?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ТБ</translation>
<translation id="7507604095951736240">Эможи</translation>
+<translation id="7620655452534002301">Хассан.</translation>
<translation id="7658239707568436148">Болих</translation>
<translation id="7781829728241885113">Өчигдөр</translation>
<translation id="7814458197256864873">Хуулах</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 цагийн өмнө}other{# цагийн өмнө}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 сек үлдсэн }other{# сек үлдсэн }}</translation>
<translation id="8134065097954893699">Энэ хуудсыг дахин ачаалж байна</translation>
-<translation id="8144660977431427332">Таны хайлтыг Google Туслах дэмждэг. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, Автоматаар гүйцээх</translation>
<translation id="815598010540052116">Доош нь гүйлгэж харах</translation>
<translation id="8179976553408161302">Нэвтрэх</translation>
<translation id="8210608804940886430">Хуудас доошлуулах</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Таб</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, апп</translation>
<translation id="8259556432390118667">Hex өнгөний утга</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_mr.xtb b/chromium/ui/strings/translations/ui_strings_mr.xtb
index ffa6cd8cceb..0ff9160f229 100644
--- a/chromium/ui/strings/translations/ui_strings_mr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_mr.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">बिल्ट-इन डिस्प्ले</translation>
<translation id="335581015389089642">भाषण</translation>
<translation id="3389286852084373014">मजकूर खूप मोठा आहे</translation>
+<translation id="3406306243914553062">HTML आशय</translation>
<translation id="348799646910989694">शेल्फ आपोआप लपवले</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> पिन केला गेला</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 दिवस शिल्लक}other{# दिवस शिल्लक}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">नंबर</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">तुमच्या मोबाइल डिव्हाइसवरून वाचणे सुरू ठेवा <ph name="TITLE" /></translation>
<translation id="385051799172605136">मागील</translation>
<translation id="3889424535448813030">Right Arrow</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 महिन्यापूर्वी}other{# महिन्यांपूर्वी}}</translation>
<translation id="4289300219472526559">बोलणे सुरू करा</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> फोल्डर <ph name="FOLDER_NAME" /> वर हलवले.</translation>
+<translation id="4306392492252714209">क्लिपबोर्डवरून काढून टाका.</translation>
<translation id="4316910396681052118">सर्व अ‍ॅप्स</translation>
<translation id="4491109536499578614">इमेज</translation>
<translation id="4588090240171750605">उजवे स्क्रोल करा</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">तुमच्या इतिहासातून हा शोध हटवायचा आहे का?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">इमोजी</translation>
+<translation id="7620655452534002301">काढला.</translation>
<translation id="7658239707568436148">रद्द करा</translation>
<translation id="7781829728241885113">काल</translation>
<translation id="7814458197256864873">&amp;कॉपी करा</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 तासापूर्वी}other{# तासांपूर्वी}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 सेकंद शिल्लक}other{# सेकंद शिल्लक}}</translation>
<translation id="8134065097954893699">हे पेज रीलोड करत आहे</translation>
-<translation id="8144660977431427332">तुमचे शोध Google असिस्टंट द्वारे प्रायोजित आहेत. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, ऑटोकंप्लीट</translation>
<translation id="815598010540052116">खाली स्क्रोल करा</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">पृष्ठ खाली</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">टॅब</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, ॲप</translation>
<translation id="8259556432390118667">हेक्स रंग मूल्य</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ms.xtb b/chromium/ui/strings/translations/ui_strings_ms.xtb
index 3db1a22485a..33f8152a8d3 100644
--- a/chromium/ui/strings/translations/ui_strings_ms.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ms.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Paparan terbina dalam</translation>
<translation id="335581015389089642">Pertuturan</translation>
<translation id="3389286852084373014">Teks terlalu besar</translation>
+<translation id="3406306243914553062">Kandungan HTML</translation>
<translation id="348799646910989694">Rak disembunyikan secara automatik</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> telah disemat</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 hari lagi}other{# hari lagi}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Nombor</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Teruskan membaca daripada peranti mudah alih anda <ph name="TITLE" /></translation>
<translation id="385051799172605136">Kembali</translation>
<translation id="3889424535448813030">Anak Panah Kanan</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 bulan yang lalu}other{# bulan yang lalu}}</translation>
<translation id="4289300219472526559">Mula Bercakap</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> dialihkan kepada folder <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Alih keluar daripada papan keratan.</translation>
<translation id="4316910396681052118">SEMUA APL</translation>
<translation id="4491109536499578614">Imej</translation>
<translation id="4588090240171750605">Tatal ke Kanan</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Padamkan carian ini daripada sejarah anda?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Dialih keluar.</translation>
<translation id="7658239707568436148">Batal</translation>
<translation id="7781829728241885113">Semalam</translation>
<translation id="7814458197256864873">&amp;Salin</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Memuatkan semula halaman ini</translation>
-<translation id="8144660977431427332">Carian anda dikuasakan oleh Google Assistant. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, Apl</translation>
<translation id="8259556432390118667">Nilai warna perenambelasan</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_my.xtb b/chromium/ui/strings/translations/ui_strings_my.xtb
index ede10fe7207..dc9abae7311 100644
--- a/chromium/ui/strings/translations/ui_strings_my.xtb
+++ b/chromium/ui/strings/translations/ui_strings_my.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">အသင့်ပါ ဖန်သားပြင်ပြသမှု</translation>
<translation id="335581015389089642">စကားပြောမှု</translation>
<translation id="3389286852084373014">စာသား အလွန်ကြီးနေသည်</translation>
+<translation id="3406306243914553062">HTML အကြောင်းအရာ</translation>
<translation id="348799646910989694">စင်ကို အလိုလိုဖျောက်ထားသည်</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> ကို ပင်ထိုးထားသည်</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{၁ ရက်ကျန်၏}other{# ရက်ကျန်၏}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">နံပါတ်</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />။ <ph name="TYPE_2" />။</translation>
<translation id="3842239759367498783">သင့်မိုဘိုင်းစက်ကိရိယာ <ph name="TITLE" /> မှ ဆက်ဖတ်ပါ</translation>
<translation id="385051799172605136">နောက်သို့</translation>
<translation id="3889424535448813030">ညာ မြား</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{ပြီးခံသည့် ၁ လ}other{ပြီးခဲ့သည့် # လ}}</translation>
<translation id="4289300219472526559">စတင် စကားပြော</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> ကို <ph name="FOLDER_NAME" /> ဖိုင်တွဲသို့ ရွှေ့လိုက်ပါပြီ။</translation>
+<translation id="4306392492252714209">ကလစ်ဘုတ်မှ ဖယ်ရှားလိုက်သည်။</translation>
<translation id="4316910396681052118">အက်ပ်များ အားလုံး</translation>
<translation id="4491109536499578614">ပုံ</translation>
<translation id="4588090240171750605">ညာဖက်သို့ ရွှေ့ရန်</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">ဤရှာဖွေမှုကို သင်၏မှတ်တမ်းမှ ဖျက်လိုပါသလား။</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">အီမိုဂျီ</translation>
+<translation id="7620655452534002301">ဖယ်ရှားလိုက်သည်။</translation>
<translation id="7658239707568436148">မလုပ်တော့</translation>
<translation id="7781829728241885113">မနေ့က</translation>
<translation id="7814458197256864873">&amp;ကူးယူ</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{၁ နာရီ အကြာက}other{# နာရီ အကြာက}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{၁ စက္ကန့်ကျန်၏}other{# စက္ကန့်ကျန်၏}}</translation>
<translation id="8134065097954893699">ဤစာမျက်နှာကို ပြန်လည် စတင်နေသည်</translation>
-<translation id="8144660977431427332">သင်၏ ရှာဖွေမှုများကို Google Assistant က ပံ့ပိုးပေးထားခြင်းဖြစ်သည်။ <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />၊ အလိုအလျောက်ဖြည့်သည်</translation>
<translation id="815598010540052116">အောက်ကို လှိမ့်ဆင်းရန်</translation>
<translation id="8179976553408161302">အင်တာ</translation>
<translation id="8210608804940886430">စာမျက်နှာ အောက်သို့</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />၊ <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab ကီးခလုတ်</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />၊ အက်ပ်</translation>
<translation id="8259556432390118667">Hex အရောင် အညွှန်းကိန်း</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ne.xtb b/chromium/ui/strings/translations/ui_strings_ne.xtb
index 468ae30eb0d..44331a47b77 100644
--- a/chromium/ui/strings/translations/ui_strings_ne.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ne.xtb
@@ -43,7 +43,7 @@
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">&amp;सबै चयन गर्नुहोस्</translation>
<translation id="19085484004813472">यो नयाँ सुविधा हो</translation>
-<translation id="2006524834898217237">यो यन्त्र इन्टरनेटमा जोडिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस्।</translation>
+<translation id="2006524834898217237">यो डिभाइस इन्टरनेटमा जोडिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस्।</translation>
<translation id="208586643495776849">कृपया फेरि प्रयास गर्नुहोस्</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{१ दिन}other{# दिन}}</translation>
<translation id="2148716181193084225">आज</translation>
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">अन्तर्निर्मित डिस्प्ले</translation>
<translation id="335581015389089642">बोली</translation>
<translation id="3389286852084373014">पाठ ज्यादै ठुलो छ</translation>
+<translation id="3406306243914553062">HTML सामग्री</translation>
<translation id="348799646910989694">सेल्फ स्वतः लुक्ने छ</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> पिन गरिएको थियो</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{ १ दिन बाँकी}other{ # दिन बाँकी}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">अङ्क</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> जीबी/से</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> जीबी</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />। <ph name="TYPE_2" />।</translation>
<translation id="3842239759367498783">आफ्नो मोबाइल यन्त्रमार्फत पढ्ने कार्य जारी राख्नुहोस् <ph name="TITLE" /></translation>
<translation id="385051799172605136">पछाडि जानुहोस्</translation>
<translation id="3889424535448813030">दाहिने तीर</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{१ महिना अघि}other{# महिना अघि}}</translation>
<translation id="4289300219472526559">बोल्न सुरु गर्नुहोस्</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> फोल्डर <ph name="FOLDER_NAME" /> मा सारियो।</translation>
+<translation id="4306392492252714209">क्लिपबोर्डबाट हटाउनुहोस्।</translation>
<translation id="4316910396681052118">सबै एपहरू</translation>
<translation id="4491109536499578614">छवि</translation>
<translation id="4588090240171750605">दायाँ तिर स्क्रोल गर्नुहोस्</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">आफ्नो इतिहासबाट यो खोज मेटाउने हो?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> टीबी</translation>
<translation id="7507604095951736240">इमोजी</translation>
+<translation id="7620655452534002301">हटाइयो।</translation>
<translation id="7658239707568436148">रद्द गर्नुहोस्</translation>
<translation id="7781829728241885113">हिजो</translation>
<translation id="7814458197256864873">&amp;प्रतिलिपि बनाउनुहोस्</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{ १ घन्टाअघि}other{ # घन्टाअघि}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{ १ सेकेन्ड बाँकी}other{ # सेकेन्ड बाँकी}}</translation>
<translation id="8134065097954893699">यो पृष्ठ पुन: लोड गरी हेर्नुहोस्</translation>
-<translation id="8144660977431427332">Google सहायकले तपाईंका खोजहरू सञ्चालन गर्छ। <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, स्वत: पूर्ण भयो</translation>
<translation id="815598010540052116">तलतिर स्क्रोल गर्नुहोस्</translation>
<translation id="8179976553408161302">प्रविष्टि गर्नुहोस्</translation>
<translation id="8210608804940886430">पृष्ठ तल</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ट्याब</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />,एप</translation>
<translation id="8259556432390118667">हेक्स रङको मान</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_nl.xtb b/chromium/ui/strings/translations/ui_strings_nl.xtb
index e7a2da4aaeb..35171363b4b 100644
--- a/chromium/ui/strings/translations/ui_strings_nl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_nl.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ingebouwd scherm</translation>
<translation id="335581015389089642">Spraak</translation>
<translation id="3389286852084373014">Tekst is te groot</translation>
+<translation id="3406306243914553062">Html-content</translation>
<translation id="348799646910989694">Plank automatisch verborgen</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> is vastgezet</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag resterend}other{# dagen resterend}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Nummer</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Verder lezen vanaf je mobiele apparaat <ph name="TITLE" /></translation>
<translation id="385051799172605136">Terug</translation>
<translation id="3889424535448813030">Pijl-rechts</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 maand geleden}other{# maanden geleden}}</translation>
<translation id="4289300219472526559">Inspreken starten</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> is verplaatst naar de map <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Verwijderen van het klembord.</translation>
<translation id="4316910396681052118">ALLE APPS</translation>
<translation id="4491109536499578614">Afbeelding</translation>
<translation id="4588090240171750605">Naar rechts bladeren</translation>
@@ -212,13 +215,14 @@
<translation id="7430878839542012341">Deze zoekopdracht uit je geschiedenis verwijderen?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji's</translation>
+<translation id="7620655452534002301">Verwijderd.</translation>
<translation id="7658239707568436148">Annuleren</translation>
<translation id="7781829728241885113">Gisteren</translation>
<translation id="7814458197256864873">&amp;Kopiëren</translation>
<translation id="7848989271541991537">Verplaatst naar pagina <ph name="PAGE_NUMBER" />, rij <ph name="ROW_NUMBER" />, kolom <ph name="COLUMN_NUMBER" />.</translation>
<translation id="7879499977785298635">Niet blokkeren</translation>
<translation id="7907591526440419938">Bestand openen</translation>
-<translation id="7952747673138230804">Chrome OS geeft suggesties weer voor nieuwe content die je kunt bekijken. Stuurt alleen statistieken om de kwaliteit te verbeteren als je ervoor hebt gekozen gebruiksgegevens te delen. <ph name="MANAGE_SETTINGS" /></translation>
+<translation id="7952747673138230804">Chrome OS toont suggesties voor nieuwe content die je kunt bekijken. Stuurt alleen statistieken om de kwaliteit te verbeteren als je ervoor hebt gekozen gebruiksgegevens te delen. <ph name="MANAGE_SETTINGS" /></translation>
<translation id="7969046989155602842">Command</translation>
<translation id="8074552109918343525">{MAX_UNREAD_NOTIFICATIONS,plural, =1{Meer dan één ongelezen melding}other{Meer dan # ongelezen meldingen}}</translation>
<translation id="8086866675552927481">{MINUTES,plural, =1{over 1 m}other{over # m}}</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Deze pagina wordt opnieuw geladen</translation>
-<translation id="8144660977431427332">Je zoekopdrachten worden mogelijk gemaakt door de Google Assistent. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, app</translation>
<translation id="8259556432390118667">Hex-kleurwaarde</translation>
@@ -243,7 +247,7 @@
<translation id="8394908167088220973">Media afspelen/onderbreken</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="8649597172973390955">Plank altijd weergegeven</translation>
+<translation id="8649597172973390955">Plank altijd zichtbaar</translation>
<translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation>
<translation id="8685326675965865247">Zoek op je apparaat, in apps en instellingen en op internet. Gebruik de pijltoetsen om te navigeren in je apps.</translation>
<translation id="8725488761726303204">+ nog <ph name="NUMBER" /></translation>
diff --git a/chromium/ui/strings/translations/ui_strings_no.xtb b/chromium/ui/strings/translations/ui_strings_no.xtb
index 432fe797c13..5f899d2beff 100644
--- a/chromium/ui/strings/translations/ui_strings_no.xtb
+++ b/chromium/ui/strings/translations/ui_strings_no.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Innebygd skjerm</translation>
<translation id="335581015389089642">Tale</translation>
<translation id="3389286852084373014">Teksten er for stor</translation>
+<translation id="3406306243914553062">HTML-innhold</translation>
<translation id="348799646910989694">Hyllen skjules automatisk</translation>
<translation id="3554637740840164787">Festet <ph name="ITEM_TITLE" /></translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag igjen}other{# dager igjen}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Nummer</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB per sek</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Fortsett lesingen på mobilenheten <ph name="TITLE" /></translation>
<translation id="385051799172605136">Tilbake</translation>
<translation id="3889424535448813030">Pil høyre</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{for 1 måned siden}other{for # måneder siden}}</translation>
<translation id="4289300219472526559">Begynn å snakke</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> er flyttet til mappen <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Fjern fra utklippstavlen.</translation>
<translation id="4316910396681052118">ALLE APPER</translation>
<translation id="4491109536499578614">Bilde</translation>
<translation id="4588090240171750605">Rull mot høyre</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Vil du slette dette søket fra loggen?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Fjernet.</translation>
<translation id="7658239707568436148">Avbryt</translation>
<translation id="7781829728241885113">I går</translation>
<translation id="7814458197256864873">&amp;Kopier</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Laster inn denne siden på nytt</translation>
-<translation id="8144660977431427332">Søkene er drevet av Google-assistenten. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" /> – app</translation>
<translation id="8259556432390118667">Heksadesimal fargekode</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_or.xtb b/chromium/ui/strings/translations/ui_strings_or.xtb
index 97720b6eba1..656d021aad6 100644
--- a/chromium/ui/strings/translations/ui_strings_or.xtb
+++ b/chromium/ui/strings/translations/ui_strings_or.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">ବିଲ୍ଟ-ଇନ୍ ଡିସପ୍ଲେ</translation>
<translation id="335581015389089642">ସ୍ପୀଚ୍‌</translation>
<translation id="3389286852084373014">ଟେକ୍ସଟ୍ ବହୁତ ଲମ୍ବା ଅଟେ</translation>
+<translation id="3406306243914553062">HTML ବିଷୟବସ୍ତୁ</translation>
<translation id="348799646910989694">ସେଲ୍ପ ସ୍ୱଚାଳିତ ରୂପେ ଲୁଚାଯାଇଛି</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> ପିନ୍ କରାଯାଇଥିଲା</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 ଦିନ ବାକି ଅଛି}other{# ଦିନ ବାକି ଅଛି}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">ନମ୍ବର</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">ଆପଣଙ୍କର ମୋବାଇଲ୍ ଡିଭାଇସ୍ <ph name="TITLE" />ରୁ ପଢ଼ିବା ଜାରି ରଖନ୍ତୁ</translation>
<translation id="385051799172605136">ପଛକୁ</translation>
<translation id="3889424535448813030">Right Arrow</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 ମାସ ପୂର୍ବେ}other{# ମାସ ପୂର୍ବେ}}</translation>
<translation id="4289300219472526559">କହିବା ଆରମ୍ଭ କରନ୍ତୁ</translation>
<translation id="430191667033048642"><ph name="FOLDER_NAME" /> ଫୋଲ୍ଡରକୁ <ph name="MOVED_APP_NAME" /> ନିଆଗଲା।</translation>
+<translation id="4306392492252714209">କ୍ଲିପବୋର୍ଡରୁ କାଢ଼ି ଦିଅନ୍ତୁ।</translation>
<translation id="4316910396681052118">ସମସ୍ତ ଆପ୍‌</translation>
<translation id="4491109536499578614">ଛବି</translation>
<translation id="4588090240171750605">ଦକ୍ଷିଣକୁ ସ୍କ୍ରୋଲ୍ କରନ୍ତୁ</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">ଆପଣଙ୍କର ଇତିହାସରୁ ଏହି ସନ୍ଧାନ ବିଲୋପ କରିବେ?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">ଇମୋଜି</translation>
+<translation id="7620655452534002301">କାଢ଼ି ଦିଆଯାଇଛି।</translation>
<translation id="7658239707568436148">ବାତିଲ୍</translation>
<translation id="7781829728241885113">ଗତକଲି</translation>
<translation id="7814458197256864873">&amp;କପି</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 ଘଣ୍ଟା ପୂର୍ବେ}other{# ଘଣ୍ଟା ପୂର୍ବେ}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 ସେକେଣ୍ଡ ବାକି ଅଛି}other{# ସେକେଣ୍ଡ ବାକି ଅଛି}}</translation>
<translation id="8134065097954893699">ଏହି ପୃଷ୍ଠା ପୁଣି ଲୋଡ୍ ହେଉଛି</translation>
-<translation id="8144660977431427332">ଆପଣଙ୍କର ସନ୍ଧାନଗୁଡ଼ିକ Google Assistant ଦ୍ୱାରା ପରିଚାଳିତ ହୁଏ। <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, ସ୍ଵତଃ ଶେଷ ହେଉଥିବା</translation>
<translation id="815598010540052116">ତଳକୁ ସ୍କ୍ରୋଲ କରନ୍ତୁ</translation>
<translation id="8179976553408161302">ପ୍ରବେଶ</translation>
<translation id="8210608804940886430">ତଳ ପୃଷ୍ଠା</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" /> <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ଟାବ୍</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, ଆପ୍</translation>
<translation id="8259556432390118667">ରଙ୍ଗର ହେକ୍ସ ମୂଲ୍ୟ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pa.xtb b/chromium/ui/strings/translations/ui_strings_pa.xtb
index 6f9e1629de1..9b7ec6107eb 100644
--- a/chromium/ui/strings/translations/ui_strings_pa.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pa.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">ਬਿਲਟ-ਇਨ ਡਿਸਪਲੇ</translation>
<translation id="335581015389089642">ਸਪੀਚ</translation>
<translation id="3389286852084373014">ਲਿਖਤ ਬਹੁਤ ਜ਼ਿਆਦਾ ਵੱਡੀ ਹੈ</translation>
+<translation id="3406306243914553062">HTML ਸਮੱਗਰੀ</translation>
<translation id="348799646910989694">ਸ਼ੈਲਫ਼ ਸਵੈਚਲਿਤ ਤੌਰ 'ਤੇ ਲੁਕ ਜਾਵੇਗੀ</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> ਨੂੰ ਪਿੰਨ ਕੀਤਾ ਗਿਆ</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 ਦਿਨ ਬਾਕੀ}one{# ਦਿਨ ਬਾਕੀ}other{# ਦਿਨ ਬਾਕੀ}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">ਨੰਬਰ</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />। <ph name="TYPE_2" />।</translation>
<translation id="3842239759367498783">ਆਪਣੇ ਮੋਬਾਈਲ ਡੀਵਾਈਸ <ph name="TITLE" /> ਤੋਂ ਪੜ੍ਹਨਾ ਜਾਰੀ ਰੱਖੋ</translation>
<translation id="385051799172605136">ਪਿੱਛੇ</translation>
<translation id="3889424535448813030">ਸੱਜਾ ਤੀਰ</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 ਮਹੀਨਾ ਪਹਿਲਾਂ}one{# ਮਹੀਨਾ ਪਹਿਲਾਂ}other{# ਮਹੀਨੇ ਪਹਿਲਾਂ}}</translation>
<translation id="4289300219472526559">ਬੋਲਣਾ ਸ਼ੁਰੂ ਕਰੋ</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> ਨੂੰ <ph name="FOLDER_NAME" /> ਫੋਲਡਰ ਵਿੱਚ ਲਿਜਾਇਆ ਗਿਆ।</translation>
+<translation id="4306392492252714209">ਕਲਿੱਪਬੋਰਡ ਵਿੱਚੋਂ ਹਟਾਓ।</translation>
<translation id="4316910396681052118">ਸਭ ਐਪਾਂ</translation>
<translation id="4491109536499578614">ਚਿੱਤਰ</translation>
<translation id="4588090240171750605">ਸੱਜੇ ਪਾਸੇ ਸਕ੍ਰੌਲ ਕਰੋ</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">ਕੀ ਇਸ ਖੋਜ ਨੂੰ ਤੁਹਾਡੇ ਇਤਿਹਾਸ ਵਿੱਚੋਂ ਮਿਟਾਉਣਾ ਹੈ?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">ਇਮੋਜੀ</translation>
+<translation id="7620655452534002301">ਹਟਾਇਆ ਗਿਆ।</translation>
<translation id="7658239707568436148">ਰੱਦ ਕਰੋ</translation>
<translation id="7781829728241885113">ਕੱਲ੍ਹ</translation>
<translation id="7814458197256864873">&amp;ਕਾਪੀ ਕਰੋ</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 ਘੰਟਾ ਪਹਿਲਾਂ}one{# ਘੰਟੇ ਪਹਿਲਾਂ}other{# ਘੰਟੇ ਪਹਿਲਾਂ}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 ਸਕਿੰਟ ਬਾਕੀ}one{# ਸਕਿੰਟ ਬਾਕੀ}other{# ਸਕਿੰਟ ਬਾਕੀ}}</translation>
<translation id="8134065097954893699">ਇਸ ਪੰਨੇ ਨੂੰ ਰੀਲੋਡ ਕਰਨਾ</translation>
-<translation id="8144660977431427332">ਤੁਹਾਡੀਆਂ ਖੋਜਾਂ ਨੂੰ 'Google ਅਸਿਸਟੈਂਟ' ਰਾਹੀਂ ਸੰਚਾਲਿਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, ਸਵੈ-ਮੁਕੰਮਲ</translation>
<translation id="815598010540052116">ਸਕ੍ਰੌਲ ਡਾਊਨ</translation>
<translation id="8179976553408161302">ਦਰਜ ਕਰੋ</translation>
<translation id="8210608804940886430">ਸਫ਼ਾ ਹੇਠਾਂ</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ਟੈਬ</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, ਐਪ</translation>
<translation id="8259556432390118667">ਹੈਕਸ ਰੰਗ ਮੁੱਲ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pl.xtb b/chromium/ui/strings/translations/ui_strings_pl.xtb
index 0691ee3dcf8..67db16707e1 100644
--- a/chromium/ui/strings/translations/ui_strings_pl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pl.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Wyświetlacz wbudowany</translation>
<translation id="335581015389089642">Mowa</translation>
<translation id="3389286852084373014">Tekst jest za długi</translation>
+<translation id="3406306243914553062">Treść HTML</translation>
<translation id="348799646910989694">Półka ukryta automatycznie</translation>
<translation id="3554637740840164787">Element <ph name="ITEM_TITLE" /> został przypięty</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Pozostał 1 dzień}few{Pozostały # dni}many{Pozostało # dni}other{Pozostało # dnia}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Numer</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Kontynuuj czytanie przerwane na urządzeniu mobilnym <ph name="TITLE" /></translation>
<translation id="385051799172605136">Wstecz</translation>
<translation id="3889424535448813030">Strzałka w prawo</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{miesiąc temu}few{# miesiące temu}many{# miesięcy temu}other{# miesiąca temu}}</translation>
<translation id="4289300219472526559">Zacznij mówić</translation>
<translation id="430191667033048642">Aplikacja <ph name="MOVED_APP_NAME" /> została przeniesiona do folderu <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Usuń ze schowka.</translation>
<translation id="4316910396681052118">WSZYSTKIE APLIKACJE</translation>
<translation id="4491109536499578614">Obraz</translation>
<translation id="4588090240171750605">Przewiń w prawo</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Usunąć to hasło z historii wyszukiwania?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emotikony</translation>
+<translation id="7620655452534002301">Usunięto.</translation>
<translation id="7658239707568436148">Anuluj</translation>
<translation id="7781829728241885113">Wczoraj</translation>
<translation id="7814458197256864873">&amp;Kopiuj</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Wczytaj ponownie tę stronę</translation>
-<translation id="8144660977431427332">Twoje wyszukiwania obsługuje Asystent Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplikacja</translation>
<translation id="8259556432390118667">Wartość szesnastkowego kodu koloru</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
index 6f9e314a08b..b7b817bbf08 100644
--- a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Tela integrada</translation>
<translation id="335581015389089642">Voz</translation>
<translation id="3389286852084373014">O texto está grande demais</translation>
+<translation id="3406306243914553062">Conteúdo HTML</translation>
<translation id="348799646910989694">Estante automaticamente oculta</translation>
<translation id="3554637740840164787">O item <ph name="ITEM_TITLE" /> foi fixado</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Um dia restante}one{# dias restantes}other{# dias restantes}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Número</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Continuar lendo no dispositivo móvel <ph name="TITLE" /></translation>
<translation id="385051799172605136">Voltar</translation>
<translation id="3889424535448813030">Seta para a direita</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 mês atrás}one{# mês atrás}other{# meses atrás}}</translation>
<translation id="4289300219472526559">Comece a falar</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> movido para a pasta <ph name="FOLDER_NAME" /></translation>
+<translation id="4306392492252714209">Remover da área de transferência.</translation>
<translation id="4316910396681052118">TODOS OS APPS</translation>
<translation id="4491109536499578614">Imagem</translation>
<translation id="4588090240171750605">Percorrer à direita</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Excluir essa pesquisa do seu histórico?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emojis</translation>
+<translation id="7620655452534002301">Removido.</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ontem</translation>
<translation id="7814458197256864873">Co&amp;piar</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Recarregando esta página</translation>
-<translation id="8144660977431427332">Suas pesquisas são executadas pelo Google Assistente. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Guia</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, app</translation>
<translation id="8259556432390118667">Valor de cor hexadecimal</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pt-PT.xtb b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
index 80f26ba74fe..3eddc08fc2b 100644
--- a/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ecrã integrado</translation>
<translation id="335581015389089642">Voz</translation>
<translation id="3389286852084373014">O texto é demasiado grande</translation>
+<translation id="3406306243914553062">Conteúdo HTML</translation>
<translation id="348799646910989694">Ocultação automática da prateleira</translation>
<translation id="3554637740840164787">O item <ph name="ITEM_TITLE" /> foi fixado.</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Falta 1 dia}other{Faltam # dias}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Número</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Continuar a ler no dispositivo móvel <ph name="TITLE" /></translation>
<translation id="385051799172605136">Anterior</translation>
<translation id="3889424535448813030">Seta para a direita</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Há 1 mês}other{Há # meses}}</translation>
<translation id="4289300219472526559">Comece a Falar</translation>
<translation id="430191667033048642">A aplicação <ph name="MOVED_APP_NAME" /> foi movida para a pasta <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Remover da área de transferência</translation>
<translation id="4316910396681052118">TODAS AS APLICAÇÕES</translation>
<translation id="4491109536499578614">Imagem</translation>
<translation id="4588090240171750605">Deslocar-se para a direita</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Pretende eliminar esta pesquisa do seu histórico?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Removida.</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ontem</translation>
<translation id="7814458197256864873">&amp;Copiar</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Atualizar esta página</translation>
-<translation id="8144660977431427332">As suas pesquisas são ativadas pelo Assistente Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabulação</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplicação</translation>
<translation id="8259556432390118667">Valor de cor hexadecimal</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ro.xtb b/chromium/ui/strings/translations/ui_strings_ro.xtb
index e1a8d0d3522..072e33be99c 100644
--- a/chromium/ui/strings/translations/ui_strings_ro.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ro.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ecran încorporat</translation>
<translation id="335581015389089642">Voce</translation>
<translation id="3389286852084373014">Textul este prea mare</translation>
+<translation id="3406306243914553062">Conținut HTML</translation>
<translation id="348799646910989694">Raft ascuns automat</translation>
<translation id="3554637740840164787">S-a fixat <ph name="ITEM_TITLE" /></translation>
<translation id="3600566671520689681">{DAYS,plural, =1{O zi rămasă}few{# zile rămase}other{# de zile rămase}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Număr</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Continuă să citești de pe dispozitivul mobil <ph name="TITLE" /></translation>
<translation id="385051799172605136">Înapoi</translation>
<translation id="3889424535448813030">Săgeată spre dreapta</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Acum 1 lună}few{Acum # luni}other{Acum # de luni}}</translation>
<translation id="4289300219472526559">Începeți să vorbiți</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> s-a mutat în dosarul <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Elimină din clipboard.</translation>
<translation id="4316910396681052118">TOATE APLICAȚIILE</translation>
<translation id="4491109536499578614">Imagine</translation>
<translation id="4588090240171750605">Derulează spre dreapta</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Ștergi această căutare din istoric?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">S-a eliminat.</translation>
<translation id="7658239707568436148">Anulează</translation>
<translation id="7781829728241885113">Ieri</translation>
<translation id="7814458197256864873">&amp;Copiază</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Se reîncarcă pagina</translation>
-<translation id="8144660977431427332">Căutările tale funcționează cu Asistentul Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplicație</translation>
<translation id="8259556432390118667">Valoarea culorii hexazecimale</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ru.xtb b/chromium/ui/strings/translations/ui_strings_ru.xtb
index ec04c7c524a..bd3547224ae 100644
--- a/chromium/ui/strings/translations/ui_strings_ru.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ru.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Встроенный дисплей</translation>
<translation id="335581015389089642">Озвучивание</translation>
<translation id="3389286852084373014">Сообщение слишком длинное</translation>
+<translation id="3406306243914553062">HTML-контент</translation>
<translation id="348799646910989694">Временное хранилище автоматически скрыто</translation>
<translation id="3554637740840164787">Объект "<ph name="ITEM_TITLE" />" закреплен</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Остался 1 день}one{Остался # день}few{Осталось # дня}many{Осталось # дней}other{Осталось # дня}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Номер</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> ГБ/с</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> ГБ</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Продолжить чтение с мобильного устройства "<ph name="TITLE" />"</translation>
<translation id="385051799172605136">Назад</translation>
<translation id="3889424535448813030">Стрелка вправо</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{месяц назад}one{# месяц назад}few{# месяца назад}many{# месяцев назад}other{# месяца назад}}</translation>
<translation id="4289300219472526559">Начать голосовой ввод</translation>
<translation id="430191667033048642">Приложение "<ph name="MOVED_APP_NAME" />" перемещено в папку "<ph name="FOLDER_NAME" />".</translation>
+<translation id="4306392492252714209">Удалить из буфера обмена.</translation>
<translation id="4316910396681052118">ВСЕ ПРИЛОЖЕНИЯ</translation>
<translation id="4491109536499578614">Изображение</translation>
<translation id="4588090240171750605">Прокрутка вправо</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Удалить этот запрос из истории поиска?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ТБ</translation>
<translation id="7507604095951736240">Эмодзи</translation>
+<translation id="7620655452534002301">Удалено.</translation>
<translation id="7658239707568436148">Отмена</translation>
<translation id="7781829728241885113">Вчера</translation>
<translation id="7814458197256864873">&amp;Копировать</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Обновить страницу</translation>
-<translation id="8144660977431427332">Ваши поисковые запросы обрабатывает Google Ассистент. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, автозаполнение</translation>
<translation id="815598010540052116">Прокрутка вниз</translation>
<translation id="8179976553408161302">ВВОД</translation>
<translation id="8210608804940886430">Прокрутка вниз</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" /> и <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, приложение</translation>
<translation id="8259556432390118667">Шестнадцатеричный код цвета</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_si.xtb b/chromium/ui/strings/translations/ui_strings_si.xtb
index 4bf1ff1c601..d93c497d983 100644
--- a/chromium/ui/strings/translations/ui_strings_si.xtb
+++ b/chromium/ui/strings/translations/ui_strings_si.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">තිළැලි සංදර්ශනය</translation>
<translation id="335581015389089642">කථනය</translation>
<translation id="3389286852084373014">පාඨය විශාල වැඩියි</translation>
+<translation id="3406306243914553062">HTML අන්තර්ගතය</translation>
<translation id="348799646910989694">රාක්කය ස්වයංක්‍රීයව සැඟවී ඇත</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> අමුණා ඇත</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{දින 1 ක් ඉතිරියි}one{දින # ක් ඉතිරියි}other{දින # ක් ඉතිරියි}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">අංකය</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">ඔබගේ <ph name="TITLE" /> ජංගම උපාංගයෙන් කියවීම දිගටම පවත්වාගෙන යන්න</translation>
<translation id="385051799172605136">ආපසු</translation>
<translation id="3889424535448813030">දකුණු ඊතලය</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{මාස 1කට පෙර}one{මාස #කට පෙර}other{මාස #කට පෙර}}</translation>
<translation id="4289300219472526559">කතා කිරීම අරඹන්න</translation>
<translation id="430191667033048642"><ph name="FOLDER_NAME" /> ෆෝල්ඩරයට <ph name="MOVED_APP_NAME" /> ගෙන යැවිණි.</translation>
+<translation id="4306392492252714209">පසුරු පුවරුවෙන් ඉවත් කරන්න.</translation>
<translation id="4316910396681052118">සියලු යෙදුම්</translation>
<translation id="4491109536499578614">රූපය</translation>
<translation id="4588090240171750605">දකුණට අනුචලනය කරන්න</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">ඔබේ ඉතිහාසයෙන් මෙම සෙවීම මකන්නද?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">ඉමොජි</translation>
+<translation id="7620655452534002301">ඉවත් කරන ලදි.</translation>
<translation id="7658239707568436148">අවලංගු කරන්න</translation>
<translation id="7781829728241885113">ඊයේ</translation>
<translation id="7814458197256864873">&amp;පිටපත් කරන්න</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{පැය 1 කට පෙර}one{පැය # කට පෙර}other{පැය # කට පෙර}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{තත්පර 1 ක් ඉතිරියි}one{තත්පර # ක් ඉතිරියි}other{තත්පර # ක් ඉතිරියි}}</translation>
<translation id="8134065097954893699">මෙම පිටුව යළි පූරණ කෙරේ</translation>
-<translation id="8144660977431427332">ඔබේ සෙවුම්වලට Google සහකරු විසින් බල ගන්වනු ලැබේ. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, ස්වයං සම්පූර්ණය</translation>
<translation id="815598010540052116">පහළට ස්ක්‍රෝල්</translation>
<translation id="8179976553408161302">ඇතුළු කරන්න</translation>
<translation id="8210608804940886430">පිටුව පහළට</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ටැබ යතුර</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, යෙදුම</translation>
<translation id="8259556432390118667">ෂඩ් වර්ණ අගය</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sk.xtb b/chromium/ui/strings/translations/ui_strings_sk.xtb
index 6305c4b3c70..c573e90f308 100644
--- a/chromium/ui/strings/translations/ui_strings_sk.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sk.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Vstavaná obrazovka</translation>
<translation id="335581015389089642">Reč</translation>
<translation id="3389286852084373014">Text je príliš veľký</translation>
+<translation id="3406306243914553062">Obsah HTML</translation>
<translation id="348799646910989694">Polička sa bude automaticky skrývať</translation>
<translation id="3554637740840164787">Položka <ph name="ITEM_TITLE" /> bola pripnutá</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>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Číslo</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Pokračujte v čítaní v mobilnom zariadení <ph name="TITLE" /></translation>
<translation id="385051799172605136">Späť</translation>
<translation id="3889424535448813030">Šípka doprava</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{pred mesiacom}few{pred # mesiacmi}many{pred # mesiacom}other{pred # mesiacmi}}</translation>
<translation id="4289300219472526559">Začať hovoriť</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> bola presunutá do priečinka <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Odstrániť zo schránky</translation>
<translation id="4316910396681052118">VŠETKY APLIKÁCIE</translation>
<translation id="4491109536499578614">Obrázok</translation>
<translation id="4588090240171750605">Rolovať doprava</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Chcete odstrániť toto vyhľadávanie z histórie?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emodži</translation>
+<translation id="7620655452534002301">Odstránené.</translation>
<translation id="7658239707568436148">Zrušiť</translation>
<translation id="7781829728241885113">Včera</translation>
<translation id="7814458197256864873">&amp;Kopírovať</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Táto stránka sa znova načítava</translation>
-<translation id="8144660977431427332">Vaše vyhľadávania využívajú technológiu Asistenta Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplikácia</translation>
<translation id="8259556432390118667">Hodnota farby v šestnástkovej sústave</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sl.xtb b/chromium/ui/strings/translations/ui_strings_sl.xtb
index c62e9cdbd0f..0c9e7f83ef4 100644
--- a/chromium/ui/strings/translations/ui_strings_sl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sl.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Vgrajeni zaslon</translation>
<translation id="335581015389089642">Speech</translation>
<translation id="3389286852084373014">Besedilo je preveliko</translation>
+<translation id="3406306243914553062">Vsebina HTML</translation>
<translation id="348799646910989694">Polica je samodejno skrita</translation>
<translation id="3554637740840164787">Element <ph name="ITEM_TITLE" /> je bil pripet</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Še 1 dan}one{Še # dan}two{Še # dneva}few{Še # dni}other{Še # dni}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Številka</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Nadaljevanje branja v mobilni napravi <ph name="TITLE" /></translation>
<translation id="385051799172605136">Nazaj</translation>
<translation id="3889424535448813030">Puščica desno</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Pred 1 mesecem}one{Pred # mesecem}two{Pred # mesecema}few{Pred # meseci}other{Pred # meseci}}</translation>
<translation id="4289300219472526559">Start Speaking</translation>
<translation id="430191667033048642">Aplikacija <ph name="MOVED_APP_NAME" /> premaknjena v mapo <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Odstrani iz odložišča.</translation>
<translation id="4316910396681052118">VSE APLIKACIJE</translation>
<translation id="4491109536499578614">Slika</translation>
<translation id="4588090240171750605">Pomik desno</translation>
@@ -211,6 +214,7 @@
<translation id="7430878839542012341">Želite izbrisati to iskanje iz zgodovine?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Odstranjeno.</translation>
<translation id="7658239707568436148">Prekliči</translation>
<translation id="7781829728241885113">Včeraj</translation>
<translation id="7814458197256864873">&amp;Kopiraj</translation>
@@ -226,11 +230,11 @@
<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="8134065097954893699">Vnovično nalaganje te strani</translation>
-<translation id="8144660977431427332">Pri iskanju se uporablja tehnologija Pomočnika Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Zavihek</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplikacija</translation>
<translation id="8259556432390118667">Vrednost barve v šestnajstiškem zapisu</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sq.xtb b/chromium/ui/strings/translations/ui_strings_sq.xtb
index 9a459364618..ef383455dc5 100644
--- a/chromium/ui/strings/translations/ui_strings_sq.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sq.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ekrani i integruar</translation>
<translation id="335581015389089642">Ligjërimi</translation>
<translation id="3389286852084373014">Teksti është tepër i madh</translation>
+<translation id="3406306243914553062">Përmbajtje HTML</translation>
<translation id="348799646910989694">Rafti i fshehur automatikisht</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> u gozhdua</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 ditë e mbetur}other{# ditë të mbetura}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Numri</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Vazhdo të lexosh nga pajisja jote celulare <ph name="TITLE" /></translation>
<translation id="385051799172605136">Prapa</translation>
<translation id="3889424535448813030">Shigjeta djathtas</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 muaj më parë}other{# muaj më parë}}</translation>
<translation id="4289300219472526559">Fillo të flasësh</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> u zhvendos te skedari <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Hiqe nga kujtesa e fragmenteve.</translation>
<translation id="4316910396681052118">TË GJITHA APLIKACIONET</translation>
<translation id="4491109536499578614">Imazh</translation>
<translation id="4588090240171750605">Lëvize djathtas</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Të fshihet ky kërkim nga historiku yt?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">U hoq.</translation>
<translation id="7658239707568436148">Anulo</translation>
<translation id="7781829728241885113">Dje</translation>
<translation id="7814458197256864873">&amp;Kopjo</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 orë më parë}other{# orë më parë}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 sek. e mbetur}other{# sek. të mbetura}}</translation>
<translation id="8134065097954893699">Po ringarkon këtë faqe</translation>
-<translation id="8144660977431427332">Kërkimet e tua mundësohen nga "Asistenti i Google". <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, plotësimi automatik</translation>
<translation id="815598010540052116">Lëviz poshtë</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Faqe poshtë</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Skeda</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplikacion</translation>
<translation id="8259556432390118667">Vlera heks e ngjyrës</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sr-Latn.xtb b/chromium/ui/strings/translations/ui_strings_sr-Latn.xtb
index 8b788dee362..e8a69647818 100644
--- a/chromium/ui/strings/translations/ui_strings_sr-Latn.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sr-Latn.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ugrađeni ekran</translation>
<translation id="335581015389089642">Govor</translation>
<translation id="3389286852084373014">Tekst je prevelik</translation>
+<translation id="3406306243914553062">HTML sadržaj</translation>
<translation id="348799646910989694">Polica je automatski sakrivena</translation>
<translation id="3554637740840164787">Stavka <ph name="ITEM_TITLE" /> je zakačena</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Još 1 dan}one{Još # dan}few{Još # dana}other{Još # dana}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Broj</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Nastavite da čitate na mobilnom uređaju <ph name="TITLE" /></translation>
<translation id="385051799172605136">Nazad</translation>
<translation id="3889424535448813030">Strelica nadesno</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Pre mesec dana}one{Pre # mesec}few{Pre # meseca}other{Pre # meseci}}</translation>
<translation id="4289300219472526559">Počnite da govorite</translation>
<translation id="430191667033048642">Aplikacija <ph name="MOVED_APP_NAME" /> je premeštena u direktorijum <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Uklonite iz privremene memorije.</translation>
<translation id="4316910396681052118">SVE APLIKACIJE</translation>
<translation id="4491109536499578614">Slika</translation>
<translation id="4588090240171750605">Pomeri nadesno</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Želite li da izbrišete ovu pretragu iz istorije?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emodži</translation>
+<translation id="7620655452534002301">Uklonjeno je.</translation>
<translation id="7658239707568436148">Otkaži</translation>
<translation id="7781829728241885113">Juče</translation>
<translation id="7814458197256864873">&amp;Kopiraj</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{Pre 1 sat}one{Pre # sat}few{Pre # sata}other{Pre # sati}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Još 1 sek}one{Još # sek}few{Još # sek}other{Još # sek}}</translation>
<translation id="8134065097954893699">Ponovo učitajte ovu stranicu</translation>
-<translation id="8144660977431427332">Pretrage omogućava Google pomoćnik. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, automatsko dovršavanje</translation>
<translation id="815598010540052116">Pomeri nadole</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Stranica nadole</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tabulator</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, aplikacija</translation>
<translation id="8259556432390118667">Heksadecimalna vrednost boje</translation>
@@ -250,7 +254,7 @@
<translation id="8730621377337864115">Gotovo</translation>
<translation id="8772073294905169192">{HOURS,plural, =1{1 s}one{# s}few{# s}other{# s}}</translation>
<translation id="8798099450830957504">Podrazumevano</translation>
-<translation id="8806053966018712535">Direktorijum <ph name="FOLDER_NAME" /></translation>
+<translation id="8806053966018712535">Folder <ph name="FOLDER_NAME" /></translation>
<translation id="883911313571074303">Dodaj napomenu u sliku</translation>
<translation id="8841375032071747811">Dugme Nazad</translation>
<translation id="8867568208303837180">Slanje...</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sr.xtb b/chromium/ui/strings/translations/ui_strings_sr.xtb
index 62d7954a305..03a94b536ab 100644
--- a/chromium/ui/strings/translations/ui_strings_sr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sr.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Уграђени екран</translation>
<translation id="335581015389089642">Говор</translation>
<translation id="3389286852084373014">Текст је превелик</translation>
+<translation id="3406306243914553062">HTML садржај</translation>
<translation id="348799646910989694">Полица је аутоматски сакривена</translation>
<translation id="3554637740840164787">Ставка <ph name="ITEM_TITLE" /> је закачена</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Још 1 дан}one{Још # дан}few{Још # дана}other{Још # дана}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Број</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Наставите да читате на мобилном уређају <ph name="TITLE" /></translation>
<translation id="385051799172605136">Назад</translation>
<translation id="3889424535448813030">Стрелица надесно</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Пре месец дана}one{Пре # месец}few{Пре # месеца}other{Пре # месеци}}</translation>
<translation id="4289300219472526559">Почните да говорите</translation>
<translation id="430191667033048642">Апликација <ph name="MOVED_APP_NAME" /> је премештена у директоријум <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Уклоните из привремене меморије.</translation>
<translation id="4316910396681052118">СВЕ АПЛИКАЦИЈЕ</translation>
<translation id="4491109536499578614">Слика</translation>
<translation id="4588090240171750605">Помери надесно</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Желите ли да избришете ову претрагу из историје?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Емоџи</translation>
+<translation id="7620655452534002301">Уклоњено је.</translation>
<translation id="7658239707568436148">Откажи</translation>
<translation id="7781829728241885113">Јуче</translation>
<translation id="7814458197256864873">&amp;Копирај</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{Пре 1 сат}one{Пре # сат}few{Пре # сата}other{Пре # сати}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{Још 1 сек}one{Још # сек}few{Још # сек}other{Још # сек}}</translation>
<translation id="8134065097954893699">Поново учитајте ову страницу</translation>
-<translation id="8144660977431427332">Претраге омогућава Google помоћник. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, аутоматско довршавање</translation>
<translation id="815598010540052116">Помери надоле</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Страница надоле</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Табулатор</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, апликација</translation>
<translation id="8259556432390118667">Хексадецимална вредност боје</translation>
@@ -250,7 +254,7 @@
<translation id="8730621377337864115">Готово</translation>
<translation id="8772073294905169192">{HOURS,plural, =1{1 с}one{# с}few{# с}other{# с}}</translation>
<translation id="8798099450830957504">Подразумевано</translation>
-<translation id="8806053966018712535">Директоријум <ph name="FOLDER_NAME" /></translation>
+<translation id="8806053966018712535">Фолдер <ph name="FOLDER_NAME" /></translation>
<translation id="883911313571074303">Додај напомену у слику</translation>
<translation id="8841375032071747811">Дугме Назад</translation>
<translation id="8867568208303837180">Слање...</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sv.xtb b/chromium/ui/strings/translations/ui_strings_sv.xtb
index 9e90303b45b..41618cf65a1 100644
--- a/chromium/ui/strings/translations/ui_strings_sv.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sv.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Inbyggd skärm</translation>
<translation id="335581015389089642">Tal</translation>
<translation id="3389286852084373014">Texten är för stor</translation>
+<translation id="3406306243914553062">HTML-innehåll</translation>
<translation id="348799646910989694">Hyllan döljs automatiskt</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> har fästs</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag kvar}other{# dagar kvar}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Nummer</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/sek</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Fortsätt att läsa på din mobila enhet <ph name="TITLE" /></translation>
<translation id="385051799172605136">Föregående</translation>
<translation id="3889424535448813030">Högerpil</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 månad sedan}other{# månader sedan}}</translation>
<translation id="4289300219472526559">Börja tala</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> har flyttats till mappen <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Ta bort från urklipp.</translation>
<translation id="4316910396681052118">ALLA APPAR</translation>
<translation id="4491109536499578614">Bild</translation>
<translation id="4588090240171750605">Rulla åt höger</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Vill du radera den här sökningen från historiken?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Borttagen.</translation>
<translation id="7658239707568436148">Avbryt</translation>
<translation id="7781829728241885113">Igår</translation>
<translation id="7814458197256864873">&amp;Kopiera</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Sidan läses in igen</translation>
-<translation id="8144660977431427332">Sökningarna görs med Google Assistent. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Flik</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, app</translation>
<translation id="8259556432390118667">Hexadecimalt färgvärde</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sw.xtb b/chromium/ui/strings/translations/ui_strings_sw.xtb
index e52aa11444b..1f375467a16 100644
--- a/chromium/ui/strings/translations/ui_strings_sw.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sw.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Skrini iliyo ndani ya mfumo</translation>
<translation id="335581015389089642">Usemi</translation>
<translation id="3389286852084373014">Maandishi ni makubwa mno</translation>
+<translation id="3406306243914553062">Maudhui ya HTML</translation>
<translation id="348799646910989694">Rafu itajificha kiotomatiki</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> imebandikwa</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Imesalia siku 1}other{Zimesalia siku #}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Nambari</translation>
<translation id="3740362395218339114">GB/s <ph name="QUANTITY" /></translation>
<translation id="3757388668994797779">GB <ph name="QUANTITY" /></translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Endelea kusoma kwenye kifaa chako cha mkononi <ph name="TITLE" /></translation>
<translation id="385051799172605136">Rudi nyuma</translation>
<translation id="3889424535448813030">Mshale Kulia</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{Mwezi 1 uliopita}other{Miezi # iliyopita}}</translation>
<translation id="4289300219472526559">Anza Kuzungumza</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> imehamishiwa kwenye folda ya <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Ondoa kwenye ubao wa kunakili.</translation>
<translation id="4316910396681052118">PROGRAMU ZOTE</translation>
<translation id="4491109536499578614">Picha</translation>
<translation id="4588090240171750605">Sogeza Kulia</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Ungependa kufuta utafutaji huu kwenye historia yako?</translation>
<translation id="7460907917090416791">TB <ph name="QUANTITY" /></translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Imeondolewa.</translation>
<translation id="7658239707568436148">Ghairi</translation>
<translation id="7781829728241885113">Jana</translation>
<translation id="7814458197256864873">&amp;Nakili</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Inapakia ukurasa huu upya</translation>
-<translation id="8144660977431427332">Utafutaji wako unatekelezwa na programu ya Mratibu wa Google. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Kichupo</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, Programu</translation>
<translation id="8259556432390118667">Thamani ya rangi ya hex</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ta.xtb b/chromium/ui/strings/translations/ui_strings_ta.xtb
index 7fb7de50bb2..ee55dfd7d61 100644
--- a/chromium/ui/strings/translations/ui_strings_ta.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ta.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">உள்ளமைந்த டிஸ்பிளே</translation>
<translation id="335581015389089642">பேச்சு</translation>
<translation id="3389286852084373014">உரையின் அளவு மிகப் பெரியதாக உள்ளது</translation>
+<translation id="3406306243914553062">HTML உள்ளடக்கம்</translation>
<translation id="348799646910989694">ஷெல்ஃப் தானாகவே மறைக்கப்படும்</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> ஷெல்ஃபில் நிலையாகப் பொருத்தப்பட்டது</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 நாள் உள்ளது}other{# நாட்கள் உள்ளன}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">எண்</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> ஜி.பை/வி</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">உங்கள் மொபைல் ஃபோனில் தொடர்ந்து <ph name="TITLE" />ஐப் படிக்கவும்</translation>
<translation id="385051799172605136">திரும்பு</translation>
<translation id="3889424535448813030">வலது அம்பு</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 மாதத்திற்கு முன்}other{# மாதங்களுக்கு முன்}}</translation>
<translation id="4289300219472526559">பேச்சைத் தொடங்கு</translation>
<translation id="430191667033048642"><ph name="FOLDER_NAME" /> கோப்புறைக்கு <ph name="MOVED_APP_NAME" /> ஆப்ஸ் நகர்த்தப்பட்டது.</translation>
+<translation id="4306392492252714209">கிளிப்போர்டிலிருந்து அகற்றும்.</translation>
<translation id="4316910396681052118">எல்லாப் பயன்பாடுகளும்</translation>
<translation id="4491109536499578614">படம்</translation>
<translation id="4588090240171750605">வலப்புறம் நகர்த்து</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">இதுவரை தேடியவற்றிலிருந்து இந்தத் தேடலை நீக்கவா?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> டெ.பை</translation>
<translation id="7507604095951736240">ஈமோஜி</translation>
+<translation id="7620655452534002301">அகற்றப்பட்டது.</translation>
<translation id="7658239707568436148">ரத்து செய்</translation>
<translation id="7781829728241885113">நேற்று</translation>
<translation id="7814458197256864873">&amp;நகலெடு</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 மணிநேரம் முன்பு}other{# மணிநேரம் முன்பு}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 நொடி உள்ளது}other{# நொடிகள் உள்ளன}}</translation>
<translation id="8134065097954893699">இந்தப் பக்கம் ரெஃப்ரெஷ் செய்யப்படுகிறது</translation>
-<translation id="8144660977431427332">உங்கள் தேடல்கள் Google அசிஸ்டண்ட்டைப் பயன்படுத்தி தேடப்படுகின்றன. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, தானே நிரப்பியது</translation>
<translation id="815598010540052116">கீழே நகர்த்து</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">பக்கத்தின் கீழே</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">தாவல்</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, ஆப்ஸ்</translation>
<translation id="8259556432390118667">ஹெக்ஸ் வண்ண மதிப்பு</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_te.xtb b/chromium/ui/strings/translations/ui_strings_te.xtb
index 0a3d076f943..2bd79e22036 100644
--- a/chromium/ui/strings/translations/ui_strings_te.xtb
+++ b/chromium/ui/strings/translations/ui_strings_te.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">బిల్ట్-ఇన్ డిస్‌ప్లే</translation>
<translation id="335581015389089642">ప్రసంగం</translation>
<translation id="3389286852084373014">వచనం చాలా పెద్దదిగా ఉంది</translation>
+<translation id="3406306243914553062">HTML కంటెంట్</translation>
<translation id="348799646910989694">అర ఆటోమేటిక్‌గా దాచి పెట్టబడుతుంది</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> పిన్ చేయబడింది</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 రోజు మిగిలి ఉంది}other{# రోజులు మిగిలి ఉన్నాయి}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">నంబర్</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">మీ మొబైల్ పరికరం <ph name="TITLE" /> నుండి చదవడం కొనసాగించండి</translation>
<translation id="385051799172605136">వెనుకకు</translation>
<translation id="3889424535448813030">కుడి బాణం</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 నెల క్రితం}other{# నెలల క్రితం}}</translation>
<translation id="4289300219472526559">మాట్లాడటాన్ని ప్రారంభించు</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> అనేది <ph name="FOLDER_NAME" /> ఫోల్డర్‌కు తరలించబడింది.</translation>
+<translation id="4306392492252714209">క్లిప్‌బోర్డ్ నుండి తీసివేయి.</translation>
<translation id="4316910396681052118">అన్ని యాప్‌లు</translation>
<translation id="4491109536499578614">చిత్రం</translation>
<translation id="4588090240171750605">కుడికి స్క్రోల్ చేయి</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">మీ చరిత్ర నుండి ఈ శోధనను తొలగించాలా?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">ఎమోజి</translation>
+<translation id="7620655452534002301">తీసివేయబడింది.</translation>
<translation id="7658239707568436148">రద్దు చేయి</translation>
<translation id="7781829728241885113">నిన్న</translation>
<translation id="7814458197256864873">&amp;కాపీ</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 గంట క్రితం}other{# గంటల క్రితం}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 సెక. మిగిలి ఉంది}other{# సెక. మిగిలి ఉన్నాయి}}</translation>
<translation id="8134065097954893699">ఈ పేజీని మళ్లీ లోడ్ చేస్తోంది</translation>
-<translation id="8144660977431427332">మీ శోధనలు Google అసిస్టెంట్ ఆధారితంగా ఉంటాయి. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, ఆటోఫిల్</translation>
<translation id="815598010540052116">కిందికి స్క్రోల్ చేయి</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">పేజీ క్రిందికి</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ట్యాబ్</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, యాప్</translation>
<translation id="8259556432390118667">హెక్స్ రంగు విలువ</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_th.xtb b/chromium/ui/strings/translations/ui_strings_th.xtb
index f93f5fd894f..ca543eb57c4 100644
--- a/chromium/ui/strings/translations/ui_strings_th.xtb
+++ b/chromium/ui/strings/translations/ui_strings_th.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">จอแสดงผลในตัว</translation>
<translation id="335581015389089642">คำพูด</translation>
<translation id="3389286852084373014">ข้อความมีขนาดใหญ่เกินไป</translation>
+<translation id="3406306243914553062">เนื้อหา HTML</translation>
<translation id="348799646910989694">ซ่อนชั้นวางโดยอัตโนมัติ</translation>
<translation id="3554637740840164787">ตรึง <ph name="ITEM_TITLE" /> แล้ว</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{เหลือ 1 วัน}other{เหลือ # วัน}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">หมายเลข</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/วินาที</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" /> <ph name="TYPE_2" /></translation>
<translation id="3842239759367498783">อ่านต่อจากอุปกรณ์เคลื่อนที่ <ph name="TITLE" /></translation>
<translation id="385051799172605136">กลับ</translation>
<translation id="3889424535448813030">ลูกศรขวา</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 เดือนที่ผ่านมา}other{# เดือนที่ผ่านมา}}</translation>
<translation id="4289300219472526559">เริ่มพูด</translation>
<translation id="430191667033048642">ย้าย <ph name="MOVED_APP_NAME" /> ไปยังโฟลเดอร์ <ph name="FOLDER_NAME" /> แล้ว</translation>
+<translation id="4306392492252714209">นำออกจากคลิปบอร์ด</translation>
<translation id="4316910396681052118">แอปทั้งหมด</translation>
<translation id="4491109536499578614">รูปภาพ</translation>
<translation id="4588090240171750605">เลื่อนทางขวา</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">ลบการค้นหานี้ออกจากประวัติการเข้าชมไหม</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">อีโมจิ</translation>
+<translation id="7620655452534002301">นำออกแล้ว</translation>
<translation id="7658239707568436148">ยกเลิก</translation>
<translation id="7781829728241885113">เมื่อวานนี้</translation>
<translation id="7814458197256864873">&amp;คัดลอก</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 ชั่วโมงที่ผ่านมา}other{# ชั่วโมงที่ผ่านมา}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{เหลือ 1 วินาที}other{เหลือ # วินาที}}</translation>
<translation id="8134065097954893699">กำลังโหลดหน้านี้ใหม่</translation>
-<translation id="8144660977431427332">การค้นหาของคุณขับเคลื่อนโดย Google Assistant <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" /> เติมข้อความอัตโนมัติ</translation>
<translation id="815598010540052116">เลื่อนลง</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">เลื่อนหน้าลง</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">แท็บ</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, แอป</translation>
<translation id="8259556432390118667">ค่าสีแบบเลขฐาน 16</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_tr.xtb b/chromium/ui/strings/translations/ui_strings_tr.xtb
index 29bd62f24f4..174f2ec0fe8 100644
--- a/chromium/ui/strings/translations/ui_strings_tr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_tr.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Yerleşik ekran</translation>
<translation id="335581015389089642">Konuşma</translation>
<translation id="3389286852084373014">Metin çok büyük</translation>
+<translation id="3406306243914553062">HTML İçeriği</translation>
<translation id="348799646910989694">Raf otomatik olarak gizlenecek</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> sabitlendi</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 gün kaldı}other{# gün kaldı}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Numara</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/sn</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783"><ph name="TITLE" /> adlı mobil cihazınızdan okumaya devam edin</translation>
<translation id="385051799172605136">Geri</translation>
<translation id="3889424535448813030">Sağ Ok</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 ay önce}other{# ay önce}}</translation>
<translation id="4289300219472526559">Konuşmaya Başla</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" />, <ph name="FOLDER_NAME" />klasörüne taşındı</translation>
+<translation id="4306392492252714209">Panodan kaldır.</translation>
<translation id="4316910396681052118">TÜM UYGULAMALAR</translation>
<translation id="4491109536499578614">Resim</translation>
<translation id="4588090240171750605">Sağa Kaydır</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Bu arama, geçmişinizden silinsin mi?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">Kaldırıldı.</translation>
<translation id="7658239707568436148">İptal</translation>
<translation id="7781829728241885113">Dün</translation>
<translation id="7814458197256864873">K&amp;opyala</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Bu sayfa yeniden yükleniyor</translation>
-<translation id="8144660977431427332">Aramalarınız Google Asistan tarafından desteklenmektedir. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Sekme</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, Uygulama</translation>
<translation id="8259556432390118667">Onaltılık renk değeri</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_uk.xtb b/chromium/ui/strings/translations/ui_strings_uk.xtb
index 4c73b3593d1..f9c8d7e748d 100644
--- a/chromium/ui/strings/translations/ui_strings_uk.xtb
+++ b/chromium/ui/strings/translations/ui_strings_uk.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Вбудований екран</translation>
<translation id="335581015389089642">Speech</translation>
<translation id="3389286852084373014">SMS-повідомлення завелике</translation>
+<translation id="3406306243914553062">Контент HTML</translation>
<translation id="348799646910989694">Автоматичне ховання полиці</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" />: закріплено</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Залишився 1 день}one{Залишився # день}few{Залишилося # дні}many{Залишилося # днів}other{Залишилося # дня}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Номер</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> ГБ/сек.</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> ГБ</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Продовжити читати з мобільного пристрою <ph name="TITLE" /></translation>
<translation id="385051799172605136">Назад</translation>
<translation id="3889424535448813030">Курсор праворуч</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 місяць тому}one{# місяць тому}few{# місяці тому}many{# місяців тому}other{# місяця тому}}</translation>
<translation id="4289300219472526559">Start Speaking</translation>
<translation id="430191667033048642">Додаток <ph name="MOVED_APP_NAME" /> переміщено в папку "<ph name="FOLDER_NAME" />".</translation>
+<translation id="4306392492252714209">Видалити з буфера обміну.</translation>
<translation id="4316910396681052118">УСІ ДОДАТКИ</translation>
<translation id="4491109536499578614">Зображення</translation>
<translation id="4588090240171750605">Прокрутка вправо</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Видалити цей пошуковий запит з історії?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> ТБ</translation>
<translation id="7507604095951736240">Смайли</translation>
+<translation id="7620655452534002301">Видалено.</translation>
<translation id="7658239707568436148">Скасувати</translation>
<translation id="7781829728241885113">Учора</translation>
<translation id="7814458197256864873">&amp;Копіювати</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Оновити цю сторінку</translation>
-<translation id="8144660977431427332">Ваші пошукові запити виконуються за технологією Google Асистента. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />: автозавершення</translation>
<translation id="815598010540052116">Прокрутка вниз</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Сторінка вниз</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, додаток</translation>
<translation id="8259556432390118667">Шістнадцятковий код кольору</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ur.xtb b/chromium/ui/strings/translations/ui_strings_ur.xtb
index 1de73732906..f7765af02d7 100644
--- a/chromium/ui/strings/translations/ui_strings_ur.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ur.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">پہلے سے شامل ڈسپلے</translation>
<translation id="335581015389089642">اسپیچ</translation>
<translation id="3389286852084373014">متن کافی بڑا ہے</translation>
+<translation id="3406306243914553062">‏HTML مواد</translation>
<translation id="348799646910989694">شیلف خودکار طور پر پوشیدہ</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> کو پن کر دیا گیا</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 دن باقی}other{# دن باقی}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">نمبر</translation>
<translation id="3740362395218339114">‎<ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />۔ <ph name="TYPE_2" />۔</translation>
<translation id="3842239759367498783">اپنے موبائل آلہ سے پڑھنا جاری رکھیں <ph name="TITLE" /></translation>
<translation id="385051799172605136">پیچھے</translation>
<translation id="3889424535448813030">دایاں تیر کا نشان</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 مہینہ پہلے}other{# مہینے پہلے}}</translation>
<translation id="4289300219472526559">بولنا شروع کریں</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> کو فولڈر<ph name="FOLDER_NAME" /> میں منتقل کر دیا گیا۔</translation>
+<translation id="4306392492252714209">کلپ بورڈ سے ہٹائیں۔</translation>
<translation id="4316910396681052118">سبھی ایپس</translation>
<translation id="4491109536499578614">تصویر</translation>
<translation id="4588090240171750605">دائیں سکرول کریں</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">آپ کی سرگزشت سے یہ تلاش حذف کریں؟</translation>
<translation id="7460907917090416791">‎<ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">ہٹا دیا گیا۔</translation>
<translation id="7658239707568436148">منسوخ کریں</translation>
<translation id="7781829728241885113">گزشتہ کل</translation>
<translation id="7814458197256864873">&amp;کاپی کریں</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 گھنٹہ پہلے}other{# گھنٹے پہلے}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 سیکنڈ باقی}other{# سیکنڈ باقی}}</translation>
<translation id="8134065097954893699">یہ صفحہ دوبارہ لوڈ کریں</translation>
-<translation id="8144660977431427332">‏آپ کی تلاشیں Google اسسٹنٹ کے ذریعہ تقویت یافتہ ہوتی ہیں۔ <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />، خود کار تکمیل</translation>
<translation id="815598010540052116">نیچے سکرول کریں</translation>
<translation id="8179976553408161302">انٹر</translation>
<translation id="8210608804940886430">صفحہ نیچے</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />، <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">ٹیب</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />، ایپ</translation>
<translation id="8259556432390118667">ہیکس رنگ کی قدر</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_uz.xtb b/chromium/ui/strings/translations/ui_strings_uz.xtb
index 1161de6d26f..d2bb2375fc5 100644
--- a/chromium/ui/strings/translations/ui_strings_uz.xtb
+++ b/chromium/ui/strings/translations/ui_strings_uz.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Ichki displey</translation>
<translation id="335581015389089642">Ovoz berish</translation>
<translation id="3389286852084373014">Matn juda katta</translation>
+<translation id="3406306243914553062">HTML kontent</translation>
<translation id="348799646910989694">Vaqtincha xotira avtomatik yopildi</translation>
<translation id="3554637740840164787">Mahkamlandi: <ph name="ITEM_TITLE" /></translation>
<translation id="3600566671520689681">{DAYS,plural, =1{ 1 kun qoldi}other{ # kun qoldi}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Raqam</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783"><ph name="TITLE" /> mobil qurilmangizdan o‘qishda davom etish</translation>
<translation id="385051799172605136">Orqaga</translation>
<translation id="3889424535448813030">O‘ngga tugmasi</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 oy oldin}other{# oy oldin}}</translation>
<translation id="4289300219472526559">Gapirishni boshlang</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> ilovasi <ph name="FOLDER_NAME" /> jildiga olindi.</translation>
+<translation id="4306392492252714209">Vaqtincha xotiradan olib tashlash</translation>
<translation id="4316910396681052118">BARCHA ILOVALAR</translation>
<translation id="4491109536499578614">Tasvir</translation>
<translation id="4588090240171750605">O‘ngga aylantirish</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Bu qidiruv qaydi tarixingizdan olib tashlansinmi?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Kulgichlar</translation>
+<translation id="7620655452534002301">Olib tashlandi.</translation>
<translation id="7658239707568436148">Bekor qilish</translation>
<translation id="7781829728241885113">Kecha</translation>
<translation id="7814458197256864873">&amp;Nuxsa olish</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 soat oldin}other{# soat oldin}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 soniya qoldi}other{# soniya qoldi}}</translation>
<translation id="8134065097954893699">Shu sahifani yangilang</translation>
-<translation id="8144660977431427332">Qidiruvlar Google Assistent tomonidan bajariladi. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, Avtomatik kiritish</translation>
<translation id="815598010540052116">Pastga o‘tkazish</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">Pastga o‘tkazish</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, Ilova</translation>
<translation id="8259556432390118667">Rangning 16 raqamli qiymati</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_vi.xtb b/chromium/ui/strings/translations/ui_strings_vi.xtb
index 863180788e8..72da5866c6e 100644
--- a/chromium/ui/strings/translations/ui_strings_vi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_vi.xtb
@@ -69,11 +69,11 @@
<translation id="2570734079541893434">Quản lý chế độ cài đặt</translation>
<translation id="2573731672208488250">{HOURS,plural, =1{trong 1 giờ}other{trong # giờ}}</translation>
<translation id="2583543531130364912">Hiệu chỉnh màn hình cảm ứng</translation>
-<translation id="2586657967955657006">Khay nhớ tạm</translation>
+<translation id="2586657967955657006">Bảng nhớ tạm</translation>
<translation id="2666092431469916601">Hàng đầu</translation>
<translation id="2701330563083355633">Chia sẻ từ <ph name="DEVICE_NAME" /></translation>
<translation id="271033894570825754">Mới</translation>
-<translation id="2743387203779672305">Sao chép vào khay nhớ tạm</translation>
+<translation id="2743387203779672305">Sao chép vào bảng nhớ tạm</translation>
<translation id="2749082172777216925"><ph name="APP_NAME_INFO" />, <ph name="PRICE" /></translation>
<translation id="2803313416453193357">Mở thư mục</translation>
<translation id="2824719307700604149">{YEARS,plural, =1{1 năm trước}other{# năm trước}}</translation>
@@ -94,18 +94,20 @@
<translation id="3306688585798492231">Màn hình tích hợp</translation>
<translation id="335581015389089642">Giọng nói</translation>
<translation id="3389286852084373014">Văn bản quá lớn</translation>
+<translation id="3406306243914553062">Nội dung HTML</translation>
<translation id="348799646910989694">Giá tự động ẩn</translation>
<translation id="3554637740840164787">Đã ghim <ph name="ITEM_TITLE" /></translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Còn 1 ngày}other{Còn # ngày}}</translation>
<translation id="3600969208114796418">Tệp <ph name="SAVEAS_EXTENSION_TYPE" /></translation>
<translation id="3608915363409716668"><ph name="MAXIMUM_VALUE" />+</translation>
<translation id="3618849550573277856">Tra cứu “<ph name="LOOKUP_STRING" />”</translation>
-<translation id="3622035490309591977">Lịch sử lưu dữ liệu vào khay nhớ tạm</translation>
+<translation id="3622035490309591977">Lịch sử lưu dữ liệu vào bảng nhớ tạm</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>
<translation id="3670030362669914947">Số</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/giây</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Tiếp tục đọc trên thiết bị di động <ph name="TITLE" /></translation>
<translation id="385051799172605136">Quay lại</translation>
<translation id="3889424535448813030">Mũi tên phải</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 tháng trước}other{# tháng trước}}</translation>
<translation id="4289300219472526559">Bắt đầu nói</translation>
<translation id="430191667033048642">Đã chuyển <ph name="MOVED_APP_NAME" /> vào thư mục <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Xóa khỏi bảng nhớ tạm.</translation>
<translation id="4316910396681052118">TẤT CẢ ỨNG DỤNG</translation>
<translation id="4491109536499578614">Hình ảnh</translation>
<translation id="4588090240171750605">Cuộn qua Phải</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Xóa nội dung tìm kiếm này khỏi lịch sử của bạn?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Biểu tượng cảm xúc</translation>
+<translation id="7620655452534002301">Đã xóa.</translation>
<translation id="7658239707568436148">Hủy</translation>
<translation id="7781829728241885113">Hôm qua</translation>
<translation id="7814458197256864873">Sao &amp;chép</translation>
@@ -227,11 +231,11 @@
<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="8134065097954893699">Tải lại trang này</translation>
-<translation id="8144660977431427332">Các nội dung tìm kiếm của bạn được Trợ lý Google hỗ trợ. <ph name="LEARN_MORE" /></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>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Thẻ</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, Ứng dụng</translation>
<translation id="8259556432390118667">Giá trị màu hex</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_zh-CN.xtb b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
index 3ea7094adfc..ec83a34116a 100644
--- a/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
+++ b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">内置显示屏</translation>
<translation id="335581015389089642">语音</translation>
<translation id="3389286852084373014">文本过长</translation>
+<translation id="3406306243914553062">HTML 内容</translation>
<translation id="348799646910989694">任务栏已自动隐藏</translation>
<translation id="3554637740840164787">“<ph name="ITEM_TITLE" />”已被固定</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{还剩 1 天}other{还剩 # 天}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">卡号</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />。<ph name="TYPE_2" />。</translation>
<translation id="3842239759367498783">继续在移动设备“<ph name="TITLE" />”上阅读</translation>
<translation id="385051799172605136">返回</translation>
<translation id="3889424535448813030">向右箭头</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 个月前}other{# 个月前}}</translation>
<translation id="4289300219472526559">开始讲话</translation>
<translation id="430191667033048642">“<ph name="MOVED_APP_NAME" />”已移至文件夹“<ph name="FOLDER_NAME" />”</translation>
+<translation id="4306392492252714209">从剪贴板中移除。</translation>
<translation id="4316910396681052118">所有应用</translation>
<translation id="4491109536499578614">图片</translation>
<translation id="4588090240171750605">向右滚动</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">要将这项搜索从您的历史记录中删除吗?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">表情符号</translation>
+<translation id="7620655452534002301">已移除。</translation>
<translation id="7658239707568436148">取消</translation>
<translation id="7781829728241885113">昨天</translation>
<translation id="7814458197256864873">复制(&amp;C)</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 小时前}other{# 小时前}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{还剩 1 秒}other{还剩 # 秒}}</translation>
<translation id="8134065097954893699">重新加载此页</translation>
-<translation id="8144660977431427332">您的搜索由 Google 助理提供支持。<ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />,自动填充</translation>
<translation id="815598010540052116">向下滚动</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">向下翻页</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />、<ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />,应用</translation>
<translation id="8259556432390118667">十六进制颜色值</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_zh-HK.xtb b/chromium/ui/strings/translations/ui_strings_zh-HK.xtb
index 8a168af0e0f..43db1c535a8 100644
--- a/chromium/ui/strings/translations/ui_strings_zh-HK.xtb
+++ b/chromium/ui/strings/translations/ui_strings_zh-HK.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">內置顯示屏</translation>
<translation id="335581015389089642">語音</translation>
<translation id="3389286852084373014">文字過多</translation>
+<translation id="3406306243914553062">HTML 內容</translation>
<translation id="348799646910989694">自動隱藏捷徑列</translation>
<translation id="3554637740840164787">已經將<ph name="ITEM_TITLE" />置頂</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{還有 1 天}other{還有 # 天}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">號碼</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/秒</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />。<ph name="TYPE_2" />。</translation>
<translation id="3842239759367498783">喺流動裝置上繼續閱讀「<ph name="TITLE" />」</translation>
<translation id="385051799172605136">返回</translation>
<translation id="3889424535448813030">向右鍵</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 個月前}other{# 個月前}}</translation>
<translation id="4289300219472526559">開始說</translation>
<translation id="430191667033048642">「<ph name="MOVED_APP_NAME" />」已經移咗去「<ph name="FOLDER_NAME" />」資料夾。</translation>
+<translation id="4306392492252714209">喺剪貼簿度移除。</translation>
<translation id="4316910396681052118">所有應用程式</translation>
<translation id="4491109536499578614">圖片</translation>
<translation id="4588090240171750605">向右捲動</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">要從記錄中刪除此搜尋嗎?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">Emoji</translation>
+<translation id="7620655452534002301">移除咗。</translation>
<translation id="7658239707568436148">取消</translation>
<translation id="7781829728241885113">昨天</translation>
<translation id="7814458197256864873">複製(&amp;C)</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 小時前}other{# 小時前}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{還有 1 秒}other{還有 # 秒}}</translation>
<translation id="8134065097954893699">重新載入此頁面</translation>
-<translation id="8144660977431427332">您的搜尋結果由「Google 助理」提供。<ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />,自動完成</translation>
<translation id="815598010540052116">向下捲動</translation>
<translation id="8179976553408161302">Enter 鍵</translation>
<translation id="8210608804940886430">下一頁</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />、<ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab 鍵</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />,應用程式</translation>
<translation id="8259556432390118667">十六進制顏色值</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_zh-TW.xtb b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
index b4f3afe82d8..bb54bd8a13d 100644
--- a/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
+++ b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">內建螢幕</translation>
<translation id="335581015389089642">語音</translation>
<translation id="3389286852084373014">文字過多</translation>
+<translation id="3406306243914553062">HTML 內容</translation>
<translation id="348799646910989694">自動隱藏檔案櫃</translation>
<translation id="3554637740840164787">已固定「<ph name="ITEM_TITLE" />」</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{還剩 1 天}other{還剩 # 天}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">號碼</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/秒</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />。<ph name="TYPE_2" />。</translation>
<translation id="3842239759367498783">你可以在行動裝置「<ph name="TITLE" />」上繼續閱讀</translation>
<translation id="385051799172605136">返回</translation>
<translation id="3889424535448813030">向右鍵</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 個月前}other{# 個月前}}</translation>
<translation id="4289300219472526559">Start Speaking</translation>
<translation id="430191667033048642">已將「<ph name="MOVED_APP_NAME" />」移至「<ph name="FOLDER_NAME" />」資料夾。</translation>
+<translation id="4306392492252714209">從剪貼簿中移除。</translation>
<translation id="4316910396681052118">所有應用程式</translation>
<translation id="4491109536499578614">圖片</translation>
<translation id="4588090240171750605">向右捲動</translation>
@@ -193,7 +196,7 @@
<translation id="6845383723252244143">選取資料夾</translation>
<translation id="6845533974506654842">按下</translation>
<translation id="6863590663815976734">{HOURS,plural, =1{還剩 1 小時}other{還剩 # 小時}}</translation>
-<translation id="688711909580084195">無標題網頁</translation>
+<translation id="688711909580084195">未命名網頁</translation>
<translation id="6902419395050653510">HTML 內容。</translation>
<translation id="6907759265145635167"><ph name="QUANTITY" /> PB/秒</translation>
<translation id="6917971086528278418">{YEARS,plural, =1{還剩 1 年}other{還剩 # 年}}</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">要將這個搜尋從你的記錄中刪除嗎?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">表情符號</translation>
+<translation id="7620655452534002301">已移除。</translation>
<translation id="7658239707568436148">取消</translation>
<translation id="7781829728241885113">昨天</translation>
<translation id="7814458197256864873">複製(&amp;C)</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 小時前}other{# 小時前}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{還剩 1 秒}other{還剩 # 秒}}</translation>
<translation id="8134065097954893699">重新載入這個頁面</translation>
-<translation id="8144660977431427332">你的搜尋結果由 Google 助理提供。<ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />,自動完成</translation>
<translation id="815598010540052116">向下捲動</translation>
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">向下翻頁</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />、<ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Tab 鍵</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />,應用程式</translation>
<translation id="8259556432390118667">十六進位顏色值</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_zu.xtb b/chromium/ui/strings/translations/ui_strings_zu.xtb
index 2664f99e949..4353dce8979 100644
--- a/chromium/ui/strings/translations/ui_strings_zu.xtb
+++ b/chromium/ui/strings/translations/ui_strings_zu.xtb
@@ -94,6 +94,7 @@
<translation id="3306688585798492231">Izibonisi ezakhelwe phakathi</translation>
<translation id="335581015389089642">Inkulumo</translation>
<translation id="3389286852084373014">Umbhalo mkhulu kakhulu</translation>
+<translation id="3406306243914553062">Okuqukethwe kwe-HTML</translation>
<translation id="348799646910989694">Ukufihla ngokuzenzakalelayo ishelufu</translation>
<translation id="3554637740840164787"><ph name="ITEM_TITLE" /> iphiniwe</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 usuku olusele}one{# izinsuku ezisele}other{# izinsuku ezisele}}</translation>
@@ -106,6 +107,7 @@
<translation id="3670030362669914947">Inombolo</translation>
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
+<translation id="3804247818991980532"><ph name="TYPE_1" />. <ph name="TYPE_2" />.</translation>
<translation id="3842239759367498783">Qhubeka nokufunda kusuka kudivayisi yakho yeselula <ph name="TITLE" /></translation>
<translation id="385051799172605136">Emuva</translation>
<translation id="3889424535448813030">Umcibisholo wangakwesokudla</translation>
@@ -118,6 +120,7 @@
<translation id="4266252015790371705">{MONTHS,plural, =1{1 inyanga edlule}one{# izinyanga ezedlule}other{# izinyanga ezedlule}}</translation>
<translation id="4289300219472526559">Qala ukukhuluma</translation>
<translation id="430191667033048642"><ph name="MOVED_APP_NAME" /> iyiswe kufolda <ph name="FOLDER_NAME" />.</translation>
+<translation id="4306392492252714209">Yisuse kwibhodi yokunamathisela.</translation>
<translation id="4316910396681052118">ZONKE IZINHLELO ZOKUSEBENZA</translation>
<translation id="4491109536499578614">Isithombe</translation>
<translation id="4588090240171750605">Skrolela ngakwesokudla</translation>
@@ -212,6 +215,7 @@
<translation id="7430878839542012341">Susa lolu sesho kusukela kumlando wakho?</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">I-emoji</translation>
+<translation id="7620655452534002301">Kususiwe.</translation>
<translation id="7658239707568436148">Khansela</translation>
<translation id="7781829728241885113">Izolo</translation>
<translation id="7814458197256864873">Kopisha</translation>
@@ -227,11 +231,11 @@
<translation id="8106081041558092062">{HOURS,plural, =1{1 ihora eledlule}one{# amahora adlule}other{# amahora adlule}}</translation>
<translation id="8131263257437993507">{SECONDS,plural, =1{1 isekhondi elisele}one{# amasekhondi asele}other{# amasekhondi asele}}</translation>
<translation id="8134065097954893699">Ilayisha kabusha leli khasi</translation>
-<translation id="8144660977431427332">Usesho lwakho lunikwe amandla umsizi we-Google. <ph name="LEARN_MORE" /></translation>
<translation id="8152264887680882389"><ph name="TEXT" />, Qedela ngokuzenzakalela</translation>
<translation id="815598010540052116">Skrolela phansi</translation>
<translation id="8179976553408161302">Faka</translation>
<translation id="8210608804940886430">Yehla nekhasi</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8245914219290430011">Ithebhu</translation>
<translation id="8247998213073982446"><ph name="APP_NAME" />, Uhlelo lokusebenza</translation>
<translation id="8259556432390118667">Ivelu lombala we-Hex</translation>
diff --git a/chromium/ui/strings/ui_strings.grd b/chromium/ui/strings/ui_strings.grd
index 3d2c31e349d..1613ffe6de3 100644
--- a/chromium/ui/strings/ui_strings.grd
+++ b/chromium/ui/strings/ui_strings.grd
@@ -46,6 +46,9 @@ need to be translated for each locale.-->
<output filename="ui_strings_zh-HK.pak" type="data_package" lang="zh-HK" />
<output filename="ui_strings_zu.pak" type="data_package" lang="zu" />
</if>
+ <if expr="chromeos or lacros">
+ <output filename="ui_strings_is.pak" type="data_package" lang="is" />
+ </if>
<output filename="ui_strings_am.pak" type="data_package" lang="am" />
<output filename="ui_strings_ar.pak" type="data_package" lang="ar" />
<output filename="ui_strings_bg.pak" type="data_package" lang="bg" />
@@ -67,7 +70,6 @@ need to be translated for each locale.-->
</if>
<output filename="ui_strings_et.pak" type="data_package" lang="et" />
<output filename="ui_strings_fa.pak" type="data_package" lang="fa" />
- <output filename="ui_strings_fake-bidi.pak" type="data_package" lang="fake-bidi" />
<output filename="ui_strings_fi.pak" type="data_package" lang="fi" />
<output filename="ui_strings_fil.pak" type="data_package" lang="fil" />
<output filename="ui_strings_fr.pak" type="data_package" lang="fr" />
@@ -114,6 +116,10 @@ need to be translated for each locale.-->
<output filename="ui_strings_vi.pak" type="data_package" lang="vi" />
<output filename="ui_strings_zh-CN.pak" type="data_package" lang="zh-CN" />
<output filename="ui_strings_zh-TW.pak" type="data_package" lang="zh-TW" />
+
+ <!-- Pseudolocales -->
+ <output filename="ui_strings_ar-XB.pak" type="data_package" lang="ar-XB" />
+ <output filename="ui_strings_en-XA.pak" type="data_package" lang="en-XA" />
</outputs>
<translations>
<file path="translations/ui_strings_af.xtb" lang="af" />
@@ -198,7 +204,7 @@ need to be translated for each locale.-->
<file path="translations/ui_strings_zh-TW.xtb" lang="zh-TW" />
<file path="translations/ui_strings_zu.xtb" lang="zu" />
</translations>
- <release seq="1" allow_pseudo="false">
+ <release seq="1">
<messages fallback_to_english="true">
<!-- time format -->
@@ -366,6 +372,9 @@ need to be translated for each locale.-->
<message name="IDS_APP_MENU_EMPTY_SUBMENU" desc="Used when a submenu has no entries">
(empty)
</message>
+ <message name="IDS_CLIPBOARD_MENU_HTML" desc="Used when HTML is stored in the clipboard history">
+ HTML Content
+ </message>
<message name="IDS_CLIPBOARD_MENU_IMAGE" desc="Used when an image is stored in the clipboard history">
Image
</message>
@@ -395,6 +404,12 @@ need to be translated for each locale.-->
<message name="IDS_SENTENCE_END" desc="The symbol that is used to end a sentence.">
.
</message>
+ <message name="IDS_CONCAT_TWO_STRINGS_WITH_COMMA" desc="This string concatenates two other strings. In the English language, this particular concatenation is done via a comma and a whitespace in between the other strings. For example: '1 compromised password, 2 weak passwords'">
+ <ph name="TYPE_1">$1<ex>2 compromised passwords</ex></ph>, <ph name="TYPE_2">$2<ex>7 weak passwords</ex></ph>
+ </message>
+ <message name="IDS_CONCAT_TWO_STRINGS_WITH_PERIODS" desc="This string concatenates two other strings. In the English language, this particular concatenation is done via a period and a whitespace after the first string, and a period after the second string. For example: '1 compromised password. 2 weak passwords.'">
+ <ph name="TYPE_1">$1<ex>2 compromised passwords</ex></ph>. <ph name="TYPE_2">$2<ex>7 weak passwords</ex></ph>.
+ </message>
<if expr="is_win or is_ios">
<message name="IDS_APP_UNTITLED_SHORTCUT_FILE_NAME" desc="The name of the Internet Shortcut file created for URLs dragged that have no title">
Untitled Webpage
@@ -611,6 +626,11 @@ need to be translated for each locale.-->
Emoji &amp;&amp; Symbols
</message>
</if>
+ <if expr="chromeos">
+ <message name="IDS_APP_SHOW_CLIPBOARD_HISTORY" desc="The context menu item to show the clipboard history menu.">
+ Clipboard
+ </message>
+ </if>
<!-- Generic terms -->
<message name="IDS_APP_OK" desc="Used for Ok on buttons">
@@ -1020,12 +1040,6 @@ need to be translated for each locale.-->
<message name="IDS_APP_LIST_MANAGE_SETTINGS" desc="Text of Manage settings links.">
Manage settings
</message>
- <message name="IDS_APP_LIST_ASSISTANT_PRIVACY_INFO" desc="Text shown in Launcher to imply Assistant search.">
- Your searches are powered by the Google Assistant. <ph name="LEARN_MORE">$1<ex>Learn more</ex></ph>
- </message>
- <message name="IDS_APP_LIST_ASSISTANT_PRIVACY_INFO_CLOSE" desc="Close button text.">
- Close
- </message>
<message name="IDS_APP_LIST_SUGGESTED_CONTENT_INFO" desc="Text shown in launcher to notify users about Suggested Content. Suggested Content includes app search recommendations and website recommendations which can show up in places such as launcher search and suggestion chips.">
Chrome OS shows suggestions for new content to explore. Sends statistics to improve quality only if you’ve chosen to share usage data. <ph name="MANAGE_SETTINGS">$1<ex>Manage settings</ex></ph>
</message>
@@ -1069,6 +1083,12 @@ need to be translated for each locale.-->
<message name="IDS_CLIPBOARD_HISTORY_MENU_TITLE" desc="The title of the clipboard history menu which shows the history of the clipboard data">
Clipboard history
</message>
+ <message name="IDS_CLIPBOARD_HISTORY_DELETE_BUTTON" desc="Accessibility name of the button which functions to delete a clipboard history menu entry">
+ Remove from clipboard.
+ </message>
+ <message name="IDS_CLIPBOARD_HISTORY_ITEM_DELETION" desc="Accessibility text when a clipboard history menu entry is deleted">
+ Removed.
+ </message>
<!-- Strings describing the touch calibration UX -->
<message name="IDS_DISPLAY_TOUCH_CALIBRATION_EXIT_LABEL" desc="A message to notify the user about using the escape key to exit the calibration mode.">
diff --git a/chromium/ui/strings/ui_strings_grd/IDS_APP_SHOW_CLIPBOARD_HISTORY.png.sha1 b/chromium/ui/strings/ui_strings_grd/IDS_APP_SHOW_CLIPBOARD_HISTORY.png.sha1
new file mode 100644
index 00000000000..edfc1853995
--- /dev/null
+++ b/chromium/ui/strings/ui_strings_grd/IDS_APP_SHOW_CLIPBOARD_HISTORY.png.sha1
@@ -0,0 +1 @@
+5ab94be1bbbebc839acf4bb0b07c6b5f8ce60b99 \ No newline at end of file
diff --git a/chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_HISTORY_DELETE_BUTTON.png.sha1 b/chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_HISTORY_DELETE_BUTTON.png.sha1
new file mode 100644
index 00000000000..32fdb2f8414
--- /dev/null
+++ b/chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_HISTORY_DELETE_BUTTON.png.sha1
@@ -0,0 +1 @@
+174cd4f4630ddd01a62b33f70cfbb2c2aecd2db6 \ No newline at end of file
diff --git a/chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_HISTORY_ITEM_DELETION.png.sha1 b/chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_HISTORY_ITEM_DELETION.png.sha1
new file mode 100644
index 00000000000..4952d7c709c
--- /dev/null
+++ b/chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_HISTORY_ITEM_DELETION.png.sha1
@@ -0,0 +1 @@
+6511dbca5c3b68f603ab47dcd6b3cc39b1f50604 \ No newline at end of file
diff --git a/chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_MENU_HTML.png.sha1 b/chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_MENU_HTML.png.sha1
new file mode 100644
index 00000000000..3c6ae74d923
--- /dev/null
+++ b/chromium/ui/strings/ui_strings_grd/IDS_CLIPBOARD_MENU_HTML.png.sha1
@@ -0,0 +1 @@
+f698a89ecc8fb5c568b804b90c4f6ae8d97c68ed \ No newline at end of file
diff --git a/chromium/ui/strings/ui_strings_grd/IDS_CONCAT_TWO_STRINGS_WITH_COMMA.png.sha1 b/chromium/ui/strings/ui_strings_grd/IDS_CONCAT_TWO_STRINGS_WITH_COMMA.png.sha1
new file mode 100644
index 00000000000..12749082e4e
--- /dev/null
+++ b/chromium/ui/strings/ui_strings_grd/IDS_CONCAT_TWO_STRINGS_WITH_COMMA.png.sha1
@@ -0,0 +1 @@
+6139bb64c11e0f921e8d5951367952b62ecb3fcc \ No newline at end of file
diff --git a/chromium/ui/strings/ui_strings_grd/IDS_CONCAT_TWO_STRINGS_WITH_PERIODS.png.sha1 b/chromium/ui/strings/ui_strings_grd/IDS_CONCAT_TWO_STRINGS_WITH_PERIODS.png.sha1
new file mode 100644
index 00000000000..a774d9481dc
--- /dev/null
+++ b/chromium/ui/strings/ui_strings_grd/IDS_CONCAT_TWO_STRINGS_WITH_PERIODS.png.sha1
@@ -0,0 +1 @@
+f39b3eea7e82b711a29c50f7cc12567bae2a80c3 \ No newline at end of file
diff --git a/chromium/ui/surface/DIR_METADATA b/chromium/ui/surface/DIR_METADATA
new file mode 100644
index 00000000000..f31293e3139
--- /dev/null
+++ b/chromium/ui/surface/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI"
+}
diff --git a/chromium/ui/surface/OWNERS b/chromium/ui/surface/OWNERS
index b5c1e741aef..66f16abf0d6 100644
--- a/chromium/ui/surface/OWNERS
+++ b/chromium/ui/surface/OWNERS
@@ -1,4 +1,2 @@
kbr@chromium.org
pinkerton@chromium.org
-
-# COMPONENT: UI
diff --git a/chromium/ui/touch_selection/BUILD.gn b/chromium/ui/touch_selection/BUILD.gn
index 64dbda0fd37..5e7fdbaf767 100644
--- a/chromium/ui/touch_selection/BUILD.gn
+++ b/chromium/ui/touch_selection/BUILD.gn
@@ -95,7 +95,10 @@ test("ui_touch_selection_unittests") {
if (is_android) {
java_cpp_enum("ui_touch_selection_enums_srcjar") {
- sources = [ "selection_event_type.h" ]
+ sources = [
+ "selection_event_type.h",
+ "touch_selection_draggable.h",
+ ]
}
java_cpp_enum("ui_touch_handle_orientation_srcjar") {
sources = [ "touch_handle_orientation.h" ]
diff --git a/chromium/ui/touch_selection/DIR_METADATA b/chromium/ui/touch_selection/DIR_METADATA
new file mode 100644
index 00000000000..64c023dfeb3
--- /dev/null
+++ b/chromium/ui/touch_selection/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+ component: "UI>Browser>Selection"
+}
+team_email: "input-dev@chromium.org"
diff --git a/chromium/ui/touch_selection/OWNERS b/chromium/ui/touch_selection/OWNERS
index 2fa76936c19..c65e542a90b 100644
--- a/chromium/ui/touch_selection/OWNERS
+++ b/chromium/ui/touch_selection/OWNERS
@@ -1,3 +1 @@
mohsen@chromium.org
-# COMPONENT: UI>Browser>Selection
-# TEAM: input-dev@chromium.org
diff --git a/chromium/ui/touch_selection/touch_selection_controller.cc b/chromium/ui/touch_selection/touch_selection_controller.cc
index ebbeacf3488..54a85202d21 100644
--- a/chromium/ui/touch_selection/touch_selection_controller.cc
+++ b/chromium/ui/touch_selection/touch_selection_controller.cc
@@ -116,6 +116,14 @@ void TouchSelectionController::OnSelectionBoundsChanged(
start_selection_handle_.swap(end_selection_handle_);
}
+ // Update |anchor_drag_to_selection_start_| for long press drag selector.
+ // Since selection can be updated with only one end at a time, if one end is
+ // equal to the previous value, the updated end is the other.
+ if (start_ == start)
+ anchor_drag_to_selection_start_ = false;
+ else if (end_ == end)
+ anchor_drag_to_selection_start_ = true;
+
start_ = start;
end_ = end;
start_orientation_ = ToTouchHandleOrientation(start_.type());
@@ -446,11 +454,20 @@ void TouchSelectionController::OnDragUpdate(
else
client_->MoveRangeSelectionExtent(line_position);
- // We use the bound middle point to restrict the ability to move up and down,
- // but let user move it more freely in horizontal direction.
- if (&draggable != &longpress_drag_selector_) {
- float y = GetActiveHandleMiddleY();
- client_->OnDragUpdate(gfx::PointF(drag_position.x(), y));
+ // We use the bound middle point to restrict the ability to move up and
+ // down, but let user move it more freely in horizontal direction.
+ if (&draggable == &longpress_drag_selector_) {
+ // Show magnifier at the selection edge.
+ const gfx::SelectionBound* bound =
+ anchor_drag_to_selection_start_ ? &start_ : &end_;
+ const float x = bound->edge_start().x();
+ const float y = (bound->edge_start().y() + bound->edge_end().y()) / 2.f;
+ client_->OnDragUpdate(TouchSelectionDraggable::Type::kLongpress,
+ gfx::PointF(x, y));
+ } else {
+ const float y = GetActiveHandleMiddleY();
+ client_->OnDragUpdate(TouchSelectionDraggable::Type::kTouchHandle,
+ gfx::PointF(drag_position.x(), y));
}
}
diff --git a/chromium/ui/touch_selection/touch_selection_controller.h b/chromium/ui/touch_selection/touch_selection_controller.h
index 56ae7ff02ee..4e203ab6dc2 100644
--- a/chromium/ui/touch_selection/touch_selection_controller.h
+++ b/chromium/ui/touch_selection/touch_selection_controller.h
@@ -34,7 +34,8 @@ class UI_TOUCH_SELECTION_EXPORT TouchSelectionControllerClient {
virtual void SelectBetweenCoordinates(const gfx::PointF& base,
const gfx::PointF& extent) = 0;
virtual void OnSelectionEvent(SelectionEventType event) = 0;
- virtual void OnDragUpdate(const gfx::PointF& position) = 0;
+ virtual void OnDragUpdate(const TouchSelectionDraggable::Type type,
+ const gfx::PointF& position) = 0;
virtual std::unique_ptr<TouchHandleDrawable> CreateDrawable() = 0;
virtual void DidScroll() = 0;
virtual void ShowTouchSelectionContextMenu(const gfx::Point& location) {}
diff --git a/chromium/ui/touch_selection/touch_selection_controller_unittest.cc b/chromium/ui/touch_selection/touch_selection_controller_unittest.cc
index a29c06e8edd..d9cc1c7ba22 100644
--- a/chromium/ui/touch_selection/touch_selection_controller_unittest.cc
+++ b/chromium/ui/touch_selection/touch_selection_controller_unittest.cc
@@ -105,7 +105,8 @@ class TouchSelectionControllerTest : public testing::Test,
last_event_bounds_rect_ = controller_->GetRectBetweenBounds();
}
- void OnDragUpdate(const gfx::PointF& position) override {
+ void OnDragUpdate(const TouchSelectionDraggable::Type type,
+ const gfx::PointF& position) override {
last_drag_update_position_ = position;
}
@@ -1514,6 +1515,56 @@ TEST_F(TouchSelectionControllerTest, SelectionUpdateDragPosition) {
EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED));
}
+TEST_F(TouchSelectionControllerTest, LongpressDragSelectorUpdageDragPosition) {
+ EnableLongPressDragSelection();
+ float line_height = 10.f;
+ gfx::RectF start_rect(-40, 0, 0, line_height);
+ gfx::RectF end_rect(50, 0, 0, line_height);
+ bool visible = true;
+
+ // Start a touch sequence.
+ MockMotionEvent event;
+ EXPECT_FALSE(controller().WillHandleTouchEvent(event.PressPoint(0, 0)));
+
+ // Activate a longpress-triggered selection
+ OnLongPressEvent();
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN));
+ EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
+
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event.MovePoint(0, 0, 0)));
+ EXPECT_THAT(GetAndResetEvents(), IsEmpty());
+
+ // Move within tap slop, move haven't started yet.
+ EXPECT_TRUE(
+ controller().WillHandleTouchEvent(event.MovePoint(0, 0, kDefaulTapSlop)));
+ EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED));
+ EXPECT_EQ(gfx::PointF(0.f, 0.f), GetLastDragUpdatePosition());
+
+ // Movement after the start of drag will be relative to the moved endpoint,
+ // the actual selection change offset is not necessary equal to the event
+ // moving distance.
+ end_rect.Offset(6, 0);
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event.MovePoint(0, 5, 0)));
+ EXPECT_TRUE(GetAndResetSelectionMoved());
+ EXPECT_EQ(gfx::PointF(56.f, 5.f), GetLastDragUpdatePosition());
+
+ // Vertical move
+ end_rect.Offset(0, 10);
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event.MovePoint(0, 5, 10)));
+ EXPECT_TRUE(GetAndResetSelectionMoved());
+ EXPECT_EQ(gfx::PointF(56.f, 15.f), GetLastDragUpdatePosition());
+
+ // Move start
+ start_rect.Offset(30, 0);
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event.MovePoint(0, 35, 10)));
+ EXPECT_TRUE(GetAndResetSelectionMoved());
+ EXPECT_EQ(gfx::PointF(-10.f, 5.f), GetLastDragUpdatePosition());
+}
+
TEST_F(TouchSelectionControllerTest, NoHideActiveInsertionHandle) {
SetHideActiveHandle(false);
TouchSelectionControllerTestApi test_controller(&controller());
diff --git a/chromium/ui/touch_selection/touch_selection_draggable.h b/chromium/ui/touch_selection/touch_selection_draggable.h
index 0bd9a70f884..2c7217415cd 100644
--- a/chromium/ui/touch_selection/touch_selection_draggable.h
+++ b/chromium/ui/touch_selection/touch_selection_draggable.h
@@ -27,6 +27,15 @@ class UI_TOUCH_SELECTION_EXPORT TouchSelectionDraggableClient {
// Generic interface for entities that manipulate the selection via dragging.
class UI_TOUCH_SELECTION_EXPORT TouchSelectionDraggable {
+ public:
+ // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.ui.touch_selection
+ // GENERATED_JAVA_CLASS_NAME_OVERRIDE: TouchSelectionDraggableType
+ enum class Type {
+ kNone,
+ kTouchHandle,
+ kLongpress,
+ };
+
protected:
virtual ~TouchSelectionDraggable() {}
diff --git a/chromium/ui/views/BUILD.gn b/chromium/ui/views/BUILD.gn
index 227cb94a203..07cbdc311c0 100644
--- a/chromium/ui/views/BUILD.gn
+++ b/chromium/ui/views/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/buildflag_header.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/features.gni")
import("//build/config/ozone.gni")
import("//build/config/ui.gni")
@@ -61,10 +62,13 @@ component("views") {
"accessibility/ax_virtual_view.h",
"accessibility/view_accessibility.h",
"accessibility/view_accessibility_utils.h",
+ "accessibility/views_ax_tree_manager.h",
+ "accessibility/widget_ax_tree_id_map.h",
"accessible_pane_view.h",
"animation/animation_delegate_views.h",
"animation/bounds_animator.h",
"animation/bounds_animator_observer.h",
+ "animation/bubble_slide_animator.h",
"animation/compositor_animation_runner.h",
"animation/flood_fill_ink_drop_ripple.h",
"animation/ink_drop.h",
@@ -90,6 +94,7 @@ component("views") {
"animation/slide_out_controller.h",
"animation/slide_out_controller_delegate.h",
"animation/square_ink_drop_ripple.h",
+ "animation/widget_fade_animator.h",
"background.h",
"border.h",
"bubble/bubble_border.h",
@@ -117,6 +122,7 @@ component("views") {
"controls/color_tracking_icon_view.h",
"controls/combobox/combobox.h",
"controls/combobox/combobox_util.h",
+ "controls/dot_indicator.h",
"controls/editable_combobox/editable_combobox.h",
"controls/focus_ring.h",
"controls/focusable_border.h",
@@ -169,14 +175,17 @@ component("views") {
"controls/table/table_utils.h",
"controls/table/table_view.h",
"controls/table/table_view_observer.h",
+ "controls/textarea/textarea.h",
"controls/textfield/textfield.h",
"controls/textfield/textfield_controller.h",
"controls/textfield/textfield_model.h",
+ "controls/theme_tracking_image_view.h",
"controls/throbber.h",
"controls/tree/tree_view.h",
"controls/tree/tree_view_controller.h",
"controls/tree/tree_view_drawing_provider.h",
"controls/views_text_services_context_menu.h",
+ "controls/views_text_services_context_menu_base.h",
"debug_utils.h",
"drag_controller.h",
"drag_utils.h",
@@ -273,7 +282,6 @@ component("views") {
"window/native_frame_view.h",
"window/non_client_view.h",
"window/window_button_order_provider.h",
- "window/window_resize_utils.h",
"window/window_resources.h",
"window/window_shape.h",
"word_lookup_client.h",
@@ -288,6 +296,7 @@ component("views") {
"accessible_pane_view.cc",
"animation/animation_delegate_views.cc",
"animation/bounds_animator.cc",
+ "animation/bubble_slide_animator.cc",
"animation/compositor_animation_runner.cc",
"animation/flood_fill_ink_drop_ripple.cc",
"animation/ink_drop.cc",
@@ -308,6 +317,7 @@ component("views") {
"animation/scroll_animator.cc",
"animation/slide_out_controller.cc",
"animation/square_ink_drop_ripple.cc",
+ "animation/widget_fade_animator.cc",
"background.cc",
"border.cc",
"bubble/bubble_border.cc",
@@ -336,6 +346,7 @@ component("views") {
"controls/combobox/combobox_util.cc",
"controls/combobox/empty_combobox_model.cc",
"controls/combobox/empty_combobox_model.h",
+ "controls/dot_indicator.cc",
"controls/editable_combobox/editable_combobox.cc",
"controls/focus_ring.cc",
"controls/focusable_border.cc",
@@ -376,15 +387,16 @@ component("views") {
"controls/table/table_header.cc",
"controls/table/table_utils.cc",
"controls/table/table_view.cc",
+ "controls/textarea/textarea.cc",
"controls/textfield/textfield.cc",
"controls/textfield/textfield_controller.cc",
"controls/textfield/textfield_model.cc",
+ "controls/theme_tracking_image_view.cc",
"controls/throbber.cc",
"controls/tree/tree_view.cc",
"controls/tree/tree_view_controller.cc",
"controls/tree/tree_view_drawing_provider.cc",
"controls/views_text_services_context_menu_base.cc",
- "controls/views_text_services_context_menu_base.h",
"debug_utils.cc",
"drag_utils.cc",
"focus/external_focus_tracker.cc",
@@ -432,6 +444,7 @@ component("views") {
"view_targeter.cc",
"view_targeter_delegate.cc",
"view_tracker.cc",
+ "view_utils.cc",
"views_delegate.cc",
"views_features.cc",
"views_switches.cc",
@@ -459,7 +472,6 @@ component("views") {
"window/native_frame_view.cc",
"window/non_client_view.cc",
"window/window_button_order_provider.cc",
- "window/window_resize_utils.cc",
"window/window_shape.cc",
]
@@ -486,18 +498,20 @@ component("views") {
"//base/third_party/dynamic_annotations",
"//build:chromeos_buildflags",
"//cc/paint",
+ "//components/url_formatter",
"//mojo/public/cpp/bindings",
"//skia",
"//third_party/icu",
"//ui/accessibility",
"//ui/base/clipboard",
- "//ui/base/dragdrop/mojom:mojom_shared",
+ "//ui/base/dragdrop/mojom",
"//ui/display",
"//ui/latency",
"//ui/native_theme",
"//ui/native_theme:native_theme_browser",
"//ui/resources",
"//ui/strings",
+ "//ui/views/debug:views_debug",
"//ui/views/resources",
"//url",
]
@@ -529,12 +543,16 @@ component("views") {
deps += [ "//ui/display/util" ]
}
+ if (is_chromeos_ash) {
+ deps += [ "//ui/base/ime/chromeos" ]
+ }
+
if (is_linux || is_chromeos) {
public += [ "color_chooser/color_chooser_view.h" ]
sources += [ "color_chooser/color_chooser_view.cc" ]
}
- if (is_linux && !is_chromeos) {
+ if (is_linux || is_chromeos_lacros) {
sources -= [ "window/window_button_order_provider.cc" ]
public_deps += [ "//ui/base/cursor:theme_manager" ]
deps += [
@@ -549,15 +567,22 @@ component("views") {
"linux_ui/window_button_order_observer.h",
]
sources += [
- "controls/menu/menu_config_linux.cc",
"linux_ui/linux_ui.cc",
"linux_ui/status_icon_linux.cc",
"linux_ui/window_button_order_provider.cc",
]
+
+ if (!is_chromeos_lacros) {
+ sources += [ "controls/menu/menu_config_linux.cc" ]
+ }
}
- if (is_chromeos) {
+ if (is_chromeos_ash || is_chromeos_lacros) {
sources += [ "controls/menu/menu_config_chromeos.cc" ]
+ if (!is_chromeos_lacros) {
+ public += [ "controls/views_text_services_context_menu_chromeos.h" ]
+ sources += [ "controls/views_text_services_context_menu_chromeos.cc" ]
+ }
}
if (is_mac) {
@@ -729,6 +754,12 @@ component("views") {
"corewm/tooltip_win.cc",
]
}
+ if (!is_chromeos_ash) {
+ sources += [
+ "accessibility/views_ax_tree_manager.cc",
+ "accessibility/widget_ax_tree_id_map.cc",
+ ]
+ }
deps += [
"//ui/aura",
"//ui/events",
@@ -808,6 +839,8 @@ component("views") {
"widget/desktop_aura/desktop_drag_drop_client_ozone.h",
"widget/desktop_aura/desktop_window_tree_host_platform.cc",
"widget/desktop_aura/window_move_client_platform.cc",
+ "widget/desktop_aura/window_shape_updater.cc",
+ "widget/desktop_aura/window_shape_updater.h",
]
}
if (use_atk) {
@@ -828,8 +861,6 @@ component("views") {
if (use_aura) {
sources += [
- "accessibility/views_ax_tree_manager.cc",
- "accessibility/views_ax_tree_manager.h",
"accessibility/views_utilities_aura.cc",
"accessibility/views_utilities_aura.h",
]
@@ -959,6 +990,7 @@ source_set("test_support") {
":views",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//gpu/ipc/service",
"//ipc:test_support",
"//mojo/core/embedder",
@@ -966,6 +998,7 @@ source_set("test_support") {
"//ui/base",
"//ui/base:test_support",
"//ui/base/clipboard:clipboard_test_support",
+ "//ui/base/dragdrop/mojom",
"//ui/base/ime/init",
"//ui/compositor",
"//ui/compositor:test_support",
@@ -1029,7 +1062,7 @@ source_set("test_support") {
deps += [ "//ui/ozone" ]
}
- if (use_ozone && is_linux && enable_desktop_aura) {
+ if (use_ozone && (is_linux || is_chromeos_lacros) && enable_desktop_aura) {
sources += [
"test/test_desktop_screen_ozone.cc",
"test/test_desktop_screen_ozone.h",
@@ -1046,6 +1079,7 @@ test("views_unittests") {
sources = [
"accessible_pane_view_unittest.cc",
"animation/bounds_animator_unittest.cc",
+ "animation/bubble_slide_animator_unittest.cc",
"animation/compositor_animation_runner_unittest.cc",
"animation/flood_fill_ink_drop_ripple_unittest.cc",
"animation/ink_drop_highlight_unittest.cc",
@@ -1059,6 +1093,7 @@ test("views_unittests") {
"animation/installable_ink_drop_unittest.cc",
"animation/slide_out_controller_unittest.cc",
"animation/square_ink_drop_ripple_unittest.cc",
+ "animation/widget_fade_animator_unittest.cc",
"border_unittest.cc",
"bubble/bubble_border_unittest.cc",
"bubble/bubble_dialog_delegate_view_unittest.cc",
@@ -1108,8 +1143,10 @@ test("views_unittests") {
"controls/table/table_view_unittest.cc",
"controls/table/test_table_model.cc",
"controls/table/test_table_model.h",
+ "controls/textarea/textarea_unittest.cc",
"controls/textfield/textfield_model_unittest.cc",
"controls/textfield/textfield_unittest.cc",
+ "controls/textfield/textfield_unittest.h",
"controls/tree/tree_view_unittest.cc",
"event_monitor_unittest.cc",
"focus/focus_manager_unittest.cc",
@@ -1151,7 +1188,6 @@ test("views_unittests") {
"window/frame_caption_button_unittest.cc",
"window/hit_test_utils_unittest.cc",
"window/non_client_view_unittest.cc",
- "window/window_resize_utils_unittest.cc",
]
configs += [ "//build/config:precompiled_headers" ]
@@ -1162,6 +1198,7 @@ test("views_unittests") {
"//base",
"//base:i18n",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//cc",
"//cc/paint",
"//components/vector_icons",
@@ -1176,7 +1213,7 @@ test("views_unittests") {
"//ui/base:test_support",
"//ui/base/clipboard",
"//ui/base/clipboard:clipboard_test_support",
- "//ui/base/dragdrop/mojom:mojom_shared",
+ "//ui/base/dragdrop/mojom",
"//ui/base/ime/init",
"//ui/compositor:test_support",
"//ui/display:test_support",
@@ -1222,7 +1259,7 @@ test("views_unittests") {
]
}
- if (is_linux && !is_chromeos) {
+ if (is_linux || is_chromeos_lacros) {
deps += [ "//ui/base/ime/linux" ]
}
@@ -1332,7 +1369,7 @@ test("views_unittests") {
}
}
- if (is_linux && use_ozone) {
+ if ((is_linux || is_chromeos_lacros) && use_ozone) {
data_deps +=
[ "//testing/buildbot/filters:linux_ozone_views_unittests_filters" ]
}
@@ -1364,6 +1401,7 @@ source_set("views_interactive_ui_tests") {
":views",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//mojo/core/embedder",
"//skia",
"//testing/gtest",
@@ -1402,7 +1440,7 @@ source_set("views_interactive_ui_tests") {
"//ui/wm/public",
]
- if (is_linux) {
+ if (is_linux || is_chromeos_lacros) {
sources += [ "widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc" ]
}
@@ -1430,7 +1468,7 @@ source_set("views_interactive_ui_tests") {
]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources -= [ "corewm/desktop_capture_controller_unittest.cc" ]
}
}
diff --git a/chromium/ui/views/DEPS b/chromium/ui/views/DEPS
index 3e681c16ffa..960c549ee4f 100644
--- a/chromium/ui/views/DEPS
+++ b/chromium/ui/views/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+cc/paint",
"+components/crash/core/common/crash_key.h",
"+components/remote_cocoa",
+ "+components/url_formatter",
"+components/vector_icons",
"+mojo/public/cpp/bindings",
"+skia/ext",
diff --git a/chromium/ui/views/DIR_METADATA b/chromium/ui/views/DIR_METADATA
new file mode 100644
index 00000000000..d1a66307bfa
--- /dev/null
+++ b/chromium/ui/views/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals>Views"
+}
diff --git a/chromium/ui/views/OWNERS b/chromium/ui/views/OWNERS
index f4d17a21bfa..20ee0495499 100644
--- a/chromium/ui/views/OWNERS
+++ b/chromium/ui/views/OWNERS
@@ -25,5 +25,3 @@ per-file *.mm=lgrey@chromium.org
# If you're doing structural changes get a review from one of the OWNERS.
per-file BUILD.gn=*
-
-# COMPONENT: Internals>Views
diff --git a/chromium/ui/views/accessibility/DIR_METADATA b/chromium/ui/views/accessibility/DIR_METADATA
new file mode 100644
index 00000000000..6849a4f840b
--- /dev/null
+++ b/chromium/ui/views/accessibility/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+ component: "UI>Accessibility"
+}
+team_email: "chromium-accessibility@chromium.org"
diff --git a/chromium/ui/views/accessibility/OWNERS b/chromium/ui/views/accessibility/OWNERS
index f067861ca6f..d9090fe1829 100644
--- a/chromium/ui/views/accessibility/OWNERS
+++ b/chromium/ui/views/accessibility/OWNERS
@@ -1,5 +1,2 @@
file://ui/accessibility/OWNERS
jamescook@chromium.org
-
-# TEAM: chromium-accessibility@chromium.org
-# COMPONENT: UI>Accessibility
diff --git a/chromium/ui/views/accessibility/accessibility_alert_window.cc b/chromium/ui/views/accessibility/accessibility_alert_window.cc
index 9afdb5263f9..c1b5b430484 100644
--- a/chromium/ui/views/accessibility/accessibility_alert_window.cc
+++ b/chromium/ui/views/accessibility/accessibility_alert_window.cc
@@ -23,7 +23,7 @@ AccessibilityAlertWindow::AccessibilityAlertWindow(aura::Window* parent,
alert_window_->Init(ui::LayerType::LAYER_NOT_DRAWN);
alert_window_->SetProperty(ui::kAXRoleOverride, ax::mojom::Role::kAlert);
parent->AddChild(alert_window_.get());
- observer_.Add(aura::Env::GetInstance());
+ observation_.Observe(aura::Env::GetInstance());
}
AccessibilityAlertWindow::~AccessibilityAlertWindow() = default;
@@ -38,7 +38,7 @@ void AccessibilityAlertWindow::HandleAlert(const std::string& alert_string) {
}
void AccessibilityAlertWindow::OnWillDestroyEnv() {
- observer_.RemoveAll();
+ observation_.Reset();
alert_window_.reset();
}
diff --git a/chromium/ui/views/accessibility/accessibility_alert_window.h b/chromium/ui/views/accessibility/accessibility_alert_window.h
index 5895a714ea8..d64082dfe86 100644
--- a/chromium/ui/views/accessibility/accessibility_alert_window.h
+++ b/chromium/ui/views/accessibility/accessibility_alert_window.h
@@ -9,7 +9,7 @@
#include <string>
#include "base/gtest_prod_util.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/aura/env.h"
#include "ui/aura/env_observer.h"
#include "ui/views/views_export.h"
@@ -48,7 +48,7 @@ class VIEWS_EXPORT AccessibilityAlertWindow : public aura::EnvObserver {
// The accessibility cache associated with |alert_window_|.
views::AXAuraObjCache* cache_;
- ScopedObserver<aura::Env, aura::EnvObserver> observer_{this};
+ base::ScopedObservation<aura::Env, aura::EnvObserver> observation_{this};
};
} // namespace views
diff --git a/chromium/ui/views/accessibility/accessibility_alert_window_unittest.cc b/chromium/ui/views/accessibility/accessibility_alert_window_unittest.cc
index 60af94effee..fe3c5e3bddc 100644
--- a/chromium/ui/views/accessibility/accessibility_alert_window_unittest.cc
+++ b/chromium/ui/views/accessibility/accessibility_alert_window_unittest.cc
@@ -76,7 +76,7 @@ TEST_F(AccessibilityAlertWindowTest, OnWillDestroyEnv) {
AccessibilityAlertWindow window(parent_.get(), &cache);
window.OnWillDestroyEnv();
- EXPECT_FALSE(window.observer_.IsObservingSources());
+ EXPECT_FALSE(window.observation_.IsObserving());
EXPECT_FALSE(window.alert_window_);
}
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
index b8f102137de..a7808998f70 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -13,6 +13,7 @@
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/accessibility/ax_view_obj_wrapper.h"
#include "ui/views/accessibility/ax_widget_obj_wrapper.h"
@@ -33,6 +34,40 @@ aura::client::FocusClient* GetFocusClient(aura::Window* root_window) {
} // namespace
+// A class which observes the destruction of the a11y override window. Done here
+// since adding Window and WindowObserver includes are not allowed in the
+// header.
+class AXAuraObjCache::A11yOverrideWindowObserver : public aura::WindowObserver {
+ public:
+ explicit A11yOverrideWindowObserver(AXAuraObjCache* cache) : cache_(cache) {}
+ A11yOverrideWindowObserver(const A11yOverrideWindowObserver&) = delete;
+ A11yOverrideWindowObserver& operator=(const A11yOverrideWindowObserver&) =
+ delete;
+ ~A11yOverrideWindowObserver() override = default;
+
+ void Observe() {
+ observer_.Reset();
+ aura::Window* a11y_override_window = cache_->a11y_override_window_;
+ if (a11y_override_window)
+ observer_.Observe(a11y_override_window);
+ }
+
+ private:
+ // aura::WindowObserver:
+ void OnWindowDestroying(aura::Window* window) override {
+ DCHECK(window);
+ DCHECK_EQ(cache_->a11y_override_window_, window);
+ cache_->a11y_override_window_ = nullptr;
+ observer_.Reset();
+ }
+
+ // Pointer to the AXAuraObjCache object that owns |this|. Guaranteed not to be
+ // null for the lifetime of this.
+ AXAuraObjCache* const cache_;
+
+ base::ScopedObservation<aura::Window, aura::WindowObserver> observer_{this};
+};
+
AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(View* view) {
// Avoid problems with transient focus events. https://crbug.com/729449
if (!view->GetWidget())
@@ -132,7 +167,9 @@ void AXAuraObjCache::FireEvent(AXAuraObjWrapper* aura_obj,
delegate_->OnEvent(aura_obj, event_type);
}
-AXAuraObjCache::AXAuraObjCache() = default;
+AXAuraObjCache::AXAuraObjCache()
+ : a11y_override_window_observer_(
+ std::make_unique<A11yOverrideWindowObserver>(this)) {}
// Never runs because object is leaked.
AXAuraObjCache::~AXAuraObjCache() {
@@ -151,7 +188,12 @@ View* AXAuraObjCache::GetFocusedView() {
if (!focus_client)
return nullptr;
- focused_window = focus_client->GetFocusedWindow();
+ // Uses the a11y override window for focus if it exists, otherwise gets the
+ // current focused window.
+ focused_window = a11y_override_window_;
+ if (!focused_window)
+ focused_window = focus_client->GetFocusedWindow();
+
if (!focused_window)
return nullptr;
@@ -209,6 +251,11 @@ void AXAuraObjCache::OnRootWindowObjDestroyed(aura::Window* window) {
GetFocusClient(window)->RemoveObserver(this);
}
+void AXAuraObjCache::SetA11yOverrideWindow(aura::Window* a11y_override_window) {
+ a11y_override_window_ = a11y_override_window;
+ a11y_override_window_observer_->Observe();
+}
+
template <typename AuraViewWrapper, typename AuraView>
AXAuraObjWrapper* AXAuraObjCache::CreateInternal(
AuraView* aura_view,
@@ -222,7 +269,7 @@ AXAuraObjWrapper* AXAuraObjCache::CreateInternal(
return Get(it->second);
auto wrapper = std::make_unique<AuraViewWrapper>(this, aura_view);
- int32_t id = wrapper->GetUniqueId();
+ ui::AXNodeID id = wrapper->GetUniqueId();
(*aura_view_to_id_map)[aura_view] = id;
cache_[id] = std::move(wrapper);
return cache_[id].get();
@@ -233,11 +280,10 @@ int32_t AXAuraObjCache::GetIDInternal(
AuraView* aura_view,
const std::map<AuraView*, int32_t>& aura_view_to_id_map) const {
if (!aura_view)
- return ui::AXNode::kInvalidAXID;
+ return ui::kInvalidAXNodeID;
auto it = aura_view_to_id_map.find(aura_view);
- return it != aura_view_to_id_map.end() ? it->second
- : ui::AXNode::kInvalidAXID;
+ return it != aura_view_to_id_map.end() ? it->second : ui::kInvalidAXNodeID;
}
template <typename AuraView>
@@ -245,7 +291,7 @@ void AXAuraObjCache::RemoveInternal(
AuraView* aura_view,
std::map<AuraView*, int32_t>* aura_view_to_id_map) {
int32_t id = GetID(aura_view);
- if (id == ui::AXNode::kInvalidAXID)
+ if (id == ui::kInvalidAXNodeID)
return;
aura_view_to_id_map->erase(aura_view);
cache_.erase(id);
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.h b/chromium/ui/views/accessibility/ax_aura_obj_cache.h
index 05d4a795bc2..d645a0859b1 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache.h
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.h
@@ -13,18 +13,19 @@
#include <vector>
#include "ui/accessibility/ax_enums.mojom-forward.h"
+#include "ui/accessibility/ax_node_data.h"
#include "ui/aura/client/focus_change_observer.h"
#include "ui/views/views_export.h"
+namespace aura {
+class Window;
+} // namespace aura
+
namespace base {
template <typename T>
class NoDestructor;
} // namespace base
-namespace aura {
-class Window;
-} // namespace aura
-
namespace views {
class AXAuraObjWrapper;
class View;
@@ -61,9 +62,9 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
void CreateOrReplace(std::unique_ptr<AXAuraObjWrapper> obj);
// Gets an id given an Aura view.
- int32_t GetID(View* view) const;
- int32_t GetID(Widget* widget) const;
- int32_t GetID(aura::Window* window) const;
+ ui::AXNodeID GetID(View* view) const;
+ ui::AXNodeID GetID(Widget* widget) const;
+ ui::AXNodeID GetID(aura::Window* window) const;
// Removes an entry from this cache based on an Aura view.
void Remove(View* view);
@@ -77,7 +78,7 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
void RemoveViewSubtree(View* view);
// Lookup a cached entry based on an id.
- AXAuraObjWrapper* Get(int32_t id);
+ AXAuraObjWrapper* Get(ui::AXNodeID id);
// Get all top level windows this cache knows about. Under classic ash and
// SingleProcessMash this is a list of per-display root windows.
@@ -98,6 +99,13 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
// Notifies this cache of a change in root window.
void OnRootWindowObjDestroyed(aura::Window* window);
+ // Sets a window to take a11y focus. This is for windows that need to work
+ // with accessibility clients that consume accessibility APIs, but cannot take
+ // real focus themselves. |a11y_override_window_| will be set to null when
+ // destroyed, or can be set back to null using this function.
+ // TODO(sammiequon): Merge this with set_focused_widget_for_testing().
+ void SetA11yOverrideWindow(aura::Window* a11y_override_window);
+
void SetDelegate(Delegate* delegate) { delegate_ = delegate; }
// Changes the behavior of GetFocusedView() so that it only considers
@@ -109,6 +117,7 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
private:
friend class base::NoDestructor<AXAuraObjCache>;
+ class A11yOverrideWindowObserver;
View* GetFocusedView();
@@ -119,22 +128,31 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
template <typename AuraViewWrapper, typename AuraView>
AXAuraObjWrapper* CreateInternal(
AuraView* aura_view,
- std::map<AuraView*, int32_t>* aura_view_to_id_map);
+ std::map<AuraView*, ui::AXNodeID>* aura_view_to_id_map);
template <typename AuraView>
- int32_t GetIDInternal(
+ ui::AXNodeID GetIDInternal(
AuraView* aura_view,
- const std::map<AuraView*, int32_t>& aura_view_to_id_map) const;
+ const std::map<AuraView*, ui::AXNodeID>& aura_view_to_id_map) const;
template <typename AuraView>
void RemoveInternal(AuraView* aura_view,
- std::map<AuraView*, int32_t>* aura_view_to_id_map);
+ std::map<AuraView*, ui::AXNodeID>* aura_view_to_id_map);
+
+ // The window that should take a11y focus. This is for a window that needs to
+ // work with accessiblity features, but cannot take real focus. Gets set to
+ // null if the window is destroyed.
+ aura::Window* a11y_override_window_ = nullptr;
+
+ // Observes |a11y_override_window_| for destruction and sets it to null in
+ // that case.
+ std::unique_ptr<A11yOverrideWindowObserver> a11y_override_window_observer_;
- std::map<views::View*, int32_t> view_to_id_map_;
- std::map<views::Widget*, int32_t> widget_to_id_map_;
- std::map<aura::Window*, int32_t> window_to_id_map_;
+ std::map<views::View*, ui::AXNodeID> view_to_id_map_;
+ std::map<views::Widget*, ui::AXNodeID> widget_to_id_map_;
+ std::map<aura::Window*, ui::AXNodeID> window_to_id_map_;
- std::map<int32_t, std::unique_ptr<AXAuraObjWrapper>> cache_;
+ std::map<ui::AXNodeID, std::unique_ptr<AXAuraObjWrapper>> cache_;
Delegate* delegate_ = nullptr;
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc b/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc
index 90f49f2ee05..41ca48dfe7b 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc
@@ -18,10 +18,13 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+#include "ui/views/accessibility/ax_event_manager.h"
+#include "ui/views/accessibility/ax_event_observer.h"
#include "ui/views/accessibility/ax_tree_source_views.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/test/widget_test.h"
+#include "ui/views/widget/widget_delegate.h"
namespace views {
namespace test {
@@ -85,8 +88,8 @@ TEST_F(AXAuraObjCacheTest, TestViewRemoval) {
// from the cache, but leave the widget.
widget->GetRootView()->RemoveChildView(parent);
ASSERT_GT(cache.GetID(widget.get()), 0);
- ASSERT_EQ(ui::AXNode::kInvalidAXID, cache.GetID(parent));
- ASSERT_EQ(ui::AXNode::kInvalidAXID, cache.GetID(child));
+ ASSERT_EQ(ui::kInvalidAXNodeID, cache.GetID(parent));
+ ASSERT_EQ(ui::kInvalidAXNodeID, cache.GetID(child));
// Explicitly delete |parent| to prevent a memory leak, since calling
// RemoveChildView() doesn't delete it.
@@ -126,14 +129,12 @@ TEST_F(AXAuraObjCacheTest, ValidTree) {
ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
AXTreeSourceViews tree_source(
cache.GetOrCreate(parent_widget->GetNativeWindow()), tree_id, &cache);
- ui::AXTreeSerializer<AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData>
- serializer(&tree_source);
+ ui::AXTreeSerializer<AXAuraObjWrapper*> serializer(&tree_source);
ui::AXTreeUpdate serialized_tree;
serializer.SerializeChanges(tree_source.GetRoot(), &serialized_tree);
// Verify tree is valid.
- ui::AXTreeSourceChecker<AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData>
- checker(&tree_source);
+ ui::AXTreeSourceChecker<AXAuraObjWrapper*> checker(&tree_source);
std::string error_string;
EXPECT_TRUE(checker.CheckAndGetErrorString(&error_string)) << error_string;
ui::AXTree ax_tree(serialized_tree);
@@ -204,6 +205,70 @@ TEST_F(AXAuraObjCacheTest, GetFocusIsUnignoredAncestor) {
cache.OnRootWindowObjDestroyed(widget->GetNativeWindow());
}
+class TestingWidgetDelegateView : public WidgetDelegateView {
+ public:
+ explicit TestingWidgetDelegateView(base::RunLoop* run_loop)
+ : run_loop_(run_loop) {}
+ ~TestingWidgetDelegateView() override {
+ NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, false);
+ run_loop_->QuitWhenIdle();
+ }
+ TestingWidgetDelegateView(const TestingWidgetDelegateView&) = delete;
+ TestingWidgetDelegateView& operator=(const TestingWidgetDelegateView&) =
+ delete;
+
+ private:
+ // WidgetDelegate:
+ void DeleteDelegate() override { delete this; }
+
+ base::RunLoop* run_loop_;
+};
+
+class TestingAXEventObserver : public AXEventObserver {
+ public:
+ explicit TestingAXEventObserver(AXAuraObjCache* cache) : cache_(cache) {
+ observation_.Observe(AXEventManager::Get());
+ }
+ ~TestingAXEventObserver() override = default;
+ TestingAXEventObserver(const TestingAXEventObserver&) = delete;
+ TestingAXEventObserver& operator=(const TestingAXEventObserver&) = delete;
+
+ private:
+ void OnViewEvent(View* view, ax::mojom::Event event_type) override {
+ auto* ax_view = cache_->GetOrCreate(view);
+ while (ax_view != nullptr) {
+ ax_view = ax_view->GetParent();
+ }
+ }
+
+ AXAuraObjCache* cache_;
+ base::ScopedObservation<AXEventManager, AXEventObserver> observation_{this};
+};
+
+TEST_F(AXAuraObjCacheTest, DoNotCreateWidgetWrapperOnDestroyed) {
+ AXAuraObjCache cache;
+ TestingAXEventObserver observer(&cache);
+ auto* widget = new Widget;
+
+ base::RunLoop run_loop;
+ auto* delegate = new TestingWidgetDelegateView(&run_loop);
+
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.bounds = gfx::Rect(0, 0, 200, 200);
+ params.activatable = views::Widget::InitParams::ACTIVATABLE_YES;
+ params.delegate = delegate;
+ widget->Init(std::move(params));
+ widget->Show();
+
+ EXPECT_NE(ui::kInvalidAXNodeID, cache.GetID(widget));
+
+ // Widget is closed asynchronously.
+ widget->Close();
+ run_loop.Run();
+
+ EXPECT_EQ(ui::kInvalidAXNodeID, cache.GetID(widget));
+}
+
} // namespace
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h b/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h
index 6410416ce2b..cbe5f701ed4 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h
@@ -7,15 +7,18 @@
#include <stdint.h>
+#include <string>
#include <vector>
#include "base/compiler_specific.h"
+#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/geometry/point.h"
#include "ui/views/views_export.h"
namespace ui {
+
struct AXActionData;
-struct AXNodeData;
+
} // namespace ui
namespace views {
@@ -29,19 +32,18 @@ class VIEWS_EXPORT AXAuraObjWrapper {
explicit AXAuraObjWrapper(AXAuraObjCache* cache);
virtual ~AXAuraObjWrapper() = default;
- // See ViewAccessibility for details.
- virtual bool IsIgnored() = 0;
-
// Traversal and serialization.
virtual AXAuraObjWrapper* GetParent() = 0;
virtual void GetChildren(std::vector<AXAuraObjWrapper*>* out_children) = 0;
virtual void Serialize(ui::AXNodeData* out_node_data) = 0;
- virtual int32_t GetUniqueId() const = 0;
+ virtual ui::AXNodeID GetUniqueId() const = 0;
virtual std::string ToString() const = 0;
// Actions.
virtual bool HandleAccessibleAction(const ui::AXActionData& action);
+ const AXAuraObjCache* cache() const { return aura_obj_cache_; }
+
protected:
// The cache associated with this wrapper. Subclasses should initialize this
// cache on construction.
diff --git a/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
index f79b6c0ec10..b3a7f26ce54 100644
--- a/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
@@ -35,10 +35,6 @@ bool AXRootObjWrapper::HasChild(views::AXAuraObjWrapper* child) {
return base::Contains(children, child);
}
-bool AXRootObjWrapper::IsIgnored() {
- return false;
-}
-
views::AXAuraObjWrapper* AXRootObjWrapper::GetParent() {
return nullptr;
}
@@ -71,7 +67,7 @@ void AXRootObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
out_node_data->AddState(ax::mojom::State::kVertical);
}
-int32_t AXRootObjWrapper::GetUniqueId() const {
+ui::AXNodeID AXRootObjWrapper::GetUniqueId() const {
return unique_id_.Get();
}
diff --git a/chromium/ui/views/accessibility/ax_root_obj_wrapper.h b/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
index 168138b9314..e77a545468b 100644
--- a/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
@@ -29,12 +29,11 @@ class VIEWS_EXPORT AXRootObjWrapper : public views::AXAuraObjWrapper,
bool HasChild(views::AXAuraObjWrapper* child);
// views::AXAuraObjWrapper overrides.
- bool IsIgnored() override;
views::AXAuraObjWrapper* GetParent() override;
void GetChildren(
std::vector<views::AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
- int32_t GetUniqueId() const override;
+ ui::AXNodeID GetUniqueId() const final;
std::string ToString() const override;
private:
diff --git a/chromium/ui/views/accessibility/ax_tree_source_views.cc b/chromium/ui/views/accessibility/ax_tree_source_views.cc
index 8733f5e1ebe..b0e3d46505e 100644
--- a/chromium/ui/views/accessibility/ax_tree_source_views.cc
+++ b/chromium/ui/views/accessibility/ax_tree_source_views.cc
@@ -101,7 +101,11 @@ AXAuraObjWrapper* AXTreeSourceViews::GetParent(AXAuraObjWrapper* node) const {
}
bool AXTreeSourceViews::IsIgnored(AXAuraObjWrapper* node) const {
- return node && node->IsIgnored();
+ if (!node)
+ return false;
+ ui::AXNodeData out_data;
+ node->Serialize(&out_data);
+ return out_data.IsIgnored();
}
bool AXTreeSourceViews::IsValid(AXAuraObjWrapper* node) const {
@@ -118,7 +122,7 @@ AXAuraObjWrapper* AXTreeSourceViews::GetNull() const {
}
std::string AXTreeSourceViews::GetDebugString(AXAuraObjWrapper* node) const {
- return node->ToString();
+ return node ? node->ToString() : "(null)";
}
void AXTreeSourceViews::SerializeNode(AXAuraObjWrapper* node,
diff --git a/chromium/ui/views/accessibility/ax_tree_source_views.h b/chromium/ui/views/accessibility/ax_tree_source_views.h
index a867cd971bc..f6c02549042 100644
--- a/chromium/ui/views/accessibility/ax_tree_source_views.h
+++ b/chromium/ui/views/accessibility/ax_tree_source_views.h
@@ -29,8 +29,7 @@ class AXAuraObjWrapper;
// (for example to create the "desktop" node for the extension API call
// chrome.automation.getDesktop()).
class VIEWS_EXPORT AXTreeSourceViews
- : public ui::
- AXTreeSource<AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData> {
+ : public ui::AXTreeSource<AXAuraObjWrapper*> {
public:
AXTreeSourceViews(AXAuraObjWrapper* root,
const ui::AXTreeID& tree_id,
diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
index 53845347297..a751656bf33 100644
--- a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -4,6 +4,7 @@
#include "ui/views/accessibility/ax_view_obj_wrapper.h"
+#include <string>
#include <vector>
#include "ui/accessibility/ax_action_data.h"
@@ -20,15 +21,11 @@ AXViewObjWrapper::AXViewObjWrapper(AXAuraObjCache* aura_obj_cache, View* view)
: AXAuraObjWrapper(aura_obj_cache), view_(view) {
if (view->GetWidget())
aura_obj_cache_->GetOrCreate(view->GetWidget());
- observer_.Add(view);
+ observation_.Observe(view);
}
AXViewObjWrapper::~AXViewObjWrapper() = default;
-bool AXViewObjWrapper::IsIgnored() {
- return !view_ || view_->GetViewAccessibility().IsIgnored();
-}
-
AXAuraObjWrapper* AXViewObjWrapper::GetParent() {
if (!view_)
return nullptr;
@@ -66,9 +63,7 @@ void AXViewObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
return;
ViewAccessibility& view_accessibility = view_->GetViewAccessibility();
-
view_accessibility.GetAccessibleNodeData(out_node_data);
- out_node_data->id = GetUniqueId();
if (view_accessibility.GetNextFocus()) {
out_node_data->AddIntAttribute(
@@ -83,9 +78,9 @@ void AXViewObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
}
}
-int32_t AXViewObjWrapper::GetUniqueId() const {
+ui::AXNodeID AXViewObjWrapper::GetUniqueId() const {
return view_ ? view_->GetViewAccessibility().GetUniqueId()
- : ui::AXNode::kInvalidAXID;
+ : ui::kInvalidAXNodeID;
}
bool AXViewObjWrapper::HandleAccessibleAction(const ui::AXActionData& action) {
@@ -97,7 +92,7 @@ std::string AXViewObjWrapper::ToString() const {
}
void AXViewObjWrapper::OnViewIsDeleting(View* observed_view) {
- observer_.RemoveAll();
+ observation_.Reset();
view_ = nullptr;
}
diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.h b/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
index 758381fbf49..801760a5758 100644
--- a/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
@@ -7,9 +7,10 @@
#include <stdint.h>
+#include <string>
#include <vector>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/view.h"
#include "ui/views/view_observer.h"
@@ -29,11 +30,10 @@ class AXViewObjWrapper : public AXAuraObjWrapper, public ViewObserver {
View* view() { return view_; }
// AXAuraObjWrapper overrides.
- bool IsIgnored() override;
AXAuraObjWrapper* GetParent() override;
void GetChildren(std::vector<AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
- int32_t GetUniqueId() const final;
+ ui::AXNodeID GetUniqueId() const final;
bool HandleAccessibleAction(const ui::AXActionData& action) override;
std::string ToString() const override;
@@ -43,7 +43,7 @@ class AXViewObjWrapper : public AXAuraObjWrapper, public ViewObserver {
private:
View* view_;
- ScopedObserver<View, ViewObserver> observer_{this};
+ base::ScopedObservation<View, ViewObserver> observation_{this};
};
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_virtual_view.cc b/chromium/ui/views/accessibility/ax_virtual_view.cc
index cc9f8aae5fe..5a6cdd44feb 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view.cc
+++ b/chromium/ui/views/accessibility/ax_virtual_view.cc
@@ -256,32 +256,34 @@ int AXVirtualView::GetChildCount() const {
for (const std::unique_ptr<AXVirtualView>& child : children_) {
if (child->IsIgnored()) {
count += child->GetChildCount();
- continue;
+ } else {
+ ++count;
}
- count++;
}
return count;
}
gfx::NativeViewAccessible AXVirtualView::ChildAtIndex(int index) {
- DCHECK_GE(index, 0) << "Child indices should be greater or equal to 0.";
+ DCHECK_GE(index, 0) << "|index| should be greater or equal to 0.";
DCHECK_LT(index, GetChildCount())
- << "Child indices should be less than the child count.";
- int i = 0;
+ << "|index| should be less than the child count.";
+
for (const std::unique_ptr<AXVirtualView>& child : children_) {
if (child->IsIgnored()) {
- if (index - i < child->GetChildCount()) {
- gfx::NativeViewAccessible result = child->ChildAtIndex(index - i);
- if (result)
- return result;
- }
- i += child->GetChildCount();
- continue;
+ int child_count = child->GetChildCount();
+ if (index < child_count)
+ return child->ChildAtIndex(index);
+ index -= child_count;
+ } else {
+ if (index == 0)
+ return child->GetNativeObject();
+ --index;
}
- if (i == index)
- return child->GetNativeObject();
- i++;
+
+ DCHECK_GE(index, 0) << "|index| should be less than the child count.";
}
+
+ NOTREACHED() << "|index| should be less than the child count.";
return nullptr;
}
@@ -297,8 +299,11 @@ gfx::NativeViewAccessible AXVirtualView::GetNativeViewAccessible() {
}
gfx::NativeViewAccessible AXVirtualView::GetParent() {
- if (parent_view_)
- return parent_view_->GetNativeObject();
+ if (parent_view_) {
+ if (!parent_view_->IsIgnored())
+ return parent_view_->GetNativeObject();
+ return GetDelegate()->GetParent();
+ }
if (virtual_parent_view_) {
if (virtual_parent_view_->IsIgnored())
@@ -373,7 +378,7 @@ gfx::NativeViewAccessible AXVirtualView::HitTestSync(
return nullptr;
}
-gfx::NativeViewAccessible AXVirtualView::GetFocus() {
+gfx::NativeViewAccessible AXVirtualView::GetFocus() const {
View* owner_view = GetOwnerView();
if (owner_view) {
if (!(owner_view->HasFocus())) {
@@ -417,8 +422,8 @@ const ui::AXUniqueId& AXVirtualView::GetUniqueId() const {
return unique_id_;
}
-// Virtual views need to implement this function in order for A11Y events
-// to be routed correctly.
+// Virtual views need to implement this function in order for accessibility
+// events to be routed correctly.
gfx::AcceleratedWidget AXVirtualView::GetTargetForNativeAccessibilityEvent() {
#if defined(OS_WIN)
if (GetOwnerView())
@@ -439,6 +444,11 @@ std::vector<int32_t> AXVirtualView::GetColHeaderNodeIds(int col_index) const {
return GetDelegate()->GetColHeaderNodeIds(col_index);
}
+base::Optional<int32_t> AXVirtualView::GetCellId(int row_index,
+ int col_index) const {
+ return GetDelegate()->GetCellId(row_index, col_index);
+}
+
bool AXVirtualView::IsIgnored() const {
return GetData().IsIgnored();
}
@@ -498,7 +508,8 @@ ViewAXPlatformNodeDelegate* AXVirtualView::GetDelegate() const {
AXVirtualViewWrapper* AXVirtualView::GetOrCreateWrapper(
views::AXAuraObjCache* cache) {
#if defined(USE_AURA)
- if (!wrapper_)
+ // cache might be recreated, and if cache is new, recreate the wrapper.
+ if (!wrapper_ || wrapper_->cache() != cache)
wrapper_ = std::make_unique<AXVirtualViewWrapper>(this, cache);
#endif
return wrapper_.get();
diff --git a/chromium/ui/views/accessibility/ax_virtual_view.h b/chromium/ui/views/accessibility/ax_virtual_view.h
index 299d106a01b..fdab3993dce 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view.h
+++ b/chromium/ui/views/accessibility/ax_virtual_view.h
@@ -149,7 +149,7 @@ class VIEWS_EXPORT AXVirtualView : public ui::AXPlatformNodeDelegateBase {
gfx::NativeViewAccessible HitTestSync(
int screen_physical_pixel_x,
int screen_physical_pixel_y) const override;
- gfx::NativeViewAccessible GetFocus() override;
+ gfx::NativeViewAccessible GetFocus() const override;
ui::AXPlatformNode* GetFromNodeID(int32_t id) override;
bool AccessibilityPerformAction(const ui::AXActionData& data) override;
bool ShouldIgnoreHoveredStateForTesting() override;
@@ -159,18 +159,25 @@ class VIEWS_EXPORT AXVirtualView : public ui::AXPlatformNodeDelegateBase {
base::Optional<bool> GetTableHasColumnOrRowHeaderNode() const override;
std::vector<int32_t> GetColHeaderNodeIds() const override;
std::vector<int32_t> GetColHeaderNodeIds(int col_index) const override;
+ base::Optional<int32_t> GetCellId(int row_index,
+ int col_index) const override;
// Gets the real View that owns our shallowest virtual ancestor,, if any.
View* GetOwnerView() const;
- // Gets the view platform delegate if exists, otherwise nullptr.
+ // Gets the delegate for our owning View; if we are on a platform that exposes
+ // Views directly to platform APIs instead of serializing them into an AXTree.
+ // Otherwise, returns nullptr.
ViewAXPlatformNodeDelegate* GetDelegate() const;
// Gets or creates a wrapper suitable for use with tree sources.
AXVirtualViewWrapper* GetOrCreateWrapper(views::AXAuraObjCache* cache);
// Returns true if this node is ignored and should be hidden from the
- // accessibility tree. This does not impact the node's descendants.
+ // accessibility tree. Methods that are used to navigate the accessibility
+ // tree, such as "ChildAtIndex", "GetParent", and "GetChildCount", among
+ // others, also skip ignored nodes. This does not impact the node's
+ // descendants.
bool IsIgnored() const;
// Handle a request from assistive technology to perform an action on this
diff --git a/chromium/ui/views/accessibility/ax_virtual_view_unittest.cc b/chromium/ui/views/accessibility/ax_virtual_view_unittest.cc
index ae13025849b..f370f5e6160 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view_unittest.cc
+++ b/chromium/ui/views/accessibility/ax_virtual_view_unittest.cc
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
@@ -98,19 +99,7 @@ class AXVirtualViewTest : public ViewsTestBase {
void ExpectReceivedAccessibilityEvents(
const std::vector<std::pair<const ui::AXPlatformNodeDelegate*,
const ax::mojom::Event>>& expected_events) {
- EXPECT_EQ(accessibility_events_.size(), expected_events.size());
-
- size_t i = 0;
- for (const auto& actual_event : accessibility_events_) {
- if (i >= expected_events.size())
- break;
-
- const auto& expected_event = expected_events[i];
- EXPECT_EQ(actual_event.first, expected_event.first);
- EXPECT_EQ(actual_event.second, expected_event.second);
- ++i;
- }
-
+ EXPECT_THAT(accessibility_events_, testing::ContainerEq(expected_events));
accessibility_events_.clear();
}
@@ -365,122 +354,6 @@ TEST_F(AXVirtualViewTest, InvisibleVirtualViews) {
button_->SetVisible(true);
}
-// Verify that ignored virtual views are removed from the accessible tree and
-// that their contents are intact.
-TEST_F(AXVirtualViewTest, IgnoredVirtualViews) {
- ASSERT_EQ(0, virtual_label_->GetChildCount());
-
- // An ignored node should not be exposed.
- AXVirtualView* virtual_child_1 = new AXVirtualView;
- virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
- virtual_child_1->GetCustomData().AddState(ax::mojom::State::kIgnored);
- ASSERT_EQ(0, virtual_label_->GetChildCount());
- ASSERT_EQ(0, virtual_child_1->GetChildCount());
-
- // The contents of ignored nodes should be exposed.
- AXVirtualView* virtual_child_2 = new AXVirtualView;
- virtual_child_1->AddChildView(base::WrapUnique(virtual_child_2));
- AXVirtualView* virtual_child_3 = new AXVirtualView;
- virtual_child_2->AddChildView(base::WrapUnique(virtual_child_3));
- AXVirtualView* virtual_child_4 = new AXVirtualView;
- virtual_child_2->AddChildView(base::WrapUnique(virtual_child_4));
- ASSERT_EQ(1, virtual_label_->GetChildCount());
- ASSERT_EQ(1, virtual_child_1->GetChildCount());
- ASSERT_EQ(2, virtual_child_2->GetChildCount());
- ASSERT_EQ(0, virtual_child_3->GetChildCount());
- ASSERT_EQ(0, virtual_child_4->GetChildCount());
- EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_1->GetParent());
- EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_2->GetParent());
- EXPECT_EQ(virtual_child_2->GetNativeObject(), virtual_child_3->GetParent());
- EXPECT_EQ(virtual_child_2->GetNativeObject(), virtual_child_4->GetParent());
- EXPECT_EQ(virtual_child_2->GetNativeObject(),
- virtual_label_->ChildAtIndex(0));
- EXPECT_EQ(virtual_child_2->GetNativeObject(),
- virtual_child_1->ChildAtIndex(0));
- EXPECT_EQ(virtual_child_3->GetNativeObject(),
- virtual_child_2->ChildAtIndex(0));
- EXPECT_EQ(virtual_child_4->GetNativeObject(),
- virtual_child_2->ChildAtIndex(1));
-
- // The contents of ignored nodes should be unignored accessibility subtrees.
- virtual_child_2->GetCustomData().role = ax::mojom::Role::kIgnored;
- ASSERT_EQ(2, virtual_label_->GetChildCount());
- ASSERT_EQ(2, virtual_child_1->GetChildCount());
- ASSERT_EQ(2, virtual_child_2->GetChildCount());
- ASSERT_EQ(0, virtual_child_3->GetChildCount());
- ASSERT_EQ(0, virtual_child_4->GetChildCount());
- EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_1->GetParent());
- EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_2->GetParent());
- EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_3->GetParent());
- EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_4->GetParent());
- EXPECT_EQ(virtual_child_3->GetNativeObject(),
- virtual_label_->ChildAtIndex(0));
- EXPECT_EQ(virtual_child_4->GetNativeObject(),
- virtual_label_->ChildAtIndex(1));
- EXPECT_EQ(virtual_child_3->GetNativeObject(),
- virtual_child_1->ChildAtIndex(0));
- EXPECT_EQ(virtual_child_4->GetNativeObject(),
- virtual_child_1->ChildAtIndex(1));
- EXPECT_EQ(virtual_child_3->GetNativeObject(),
- virtual_child_2->ChildAtIndex(0));
- EXPECT_EQ(virtual_child_4->GetNativeObject(),
- virtual_child_2->ChildAtIndex(1));
-
- // Test for mixed ignored and unignored virtual children.
- AXVirtualView* virtual_child_5 = new AXVirtualView;
- virtual_child_1->AddChildView(base::WrapUnique(virtual_child_5));
- ASSERT_EQ(3, virtual_label_->GetChildCount());
- ASSERT_EQ(3, virtual_child_1->GetChildCount());
- ASSERT_EQ(2, virtual_child_2->GetChildCount());
- ASSERT_EQ(0, virtual_child_5->GetChildCount());
- EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_1->GetParent());
- EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_2->GetParent());
- EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_5->GetParent());
- EXPECT_EQ(virtual_child_3->GetNativeObject(),
- virtual_label_->ChildAtIndex(0));
- EXPECT_EQ(virtual_child_4->GetNativeObject(),
- virtual_label_->ChildAtIndex(1));
- EXPECT_EQ(virtual_child_5->GetNativeObject(),
- virtual_label_->ChildAtIndex(2));
-
- // An ignored root node should not be exposed.
- virtual_label_->GetCustomData().AddState(ax::mojom::State::kIgnored);
- ASSERT_EQ(3, GetButtonAccessibility()->GetChildCount());
- EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_label_->GetParent());
- EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_child_1->GetParent());
- EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_child_2->GetParent());
- EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_child_3->GetParent());
- EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_child_4->GetParent());
- EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_child_5->GetParent());
- EXPECT_EQ(virtual_child_3->GetNativeObject(),
- GetButtonAccessibility()->ChildAtIndex(0));
- EXPECT_EQ(virtual_child_4->GetNativeObject(),
- GetButtonAccessibility()->ChildAtIndex(1));
- EXPECT_EQ(virtual_child_5->GetNativeObject(),
- GetButtonAccessibility()->ChildAtIndex(2));
-
- // Test for mixed ignored and unignored root nodes.
- AXVirtualView* virtual_label_2 = new AXVirtualView;
- virtual_label_2->GetCustomData().role = ax::mojom::Role::kStaticText;
- virtual_label_2->GetCustomData().SetName("Label");
- button_->GetViewAccessibility().AddVirtualChildView(
- base::WrapUnique(virtual_label_2));
- ASSERT_EQ(4, GetButtonAccessibility()->GetChildCount());
- ASSERT_EQ(0, virtual_label_2->GetChildCount());
- EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_label_2->GetParent());
- EXPECT_EQ(virtual_label_2->GetNativeObject(),
- GetButtonAccessibility()->ChildAtIndex(3));
-
- // A focusable node should not be ignored.
- virtual_child_1->GetCustomData().AddState(ax::mojom::State::kFocusable);
- ASSERT_EQ(2, GetButtonAccessibility()->GetChildCount());
- ASSERT_EQ(1, virtual_label_->GetChildCount());
- EXPECT_EQ(virtual_child_1->GetNativeObject(),
- GetButtonAccessibility()->ChildAtIndex(0));
- EXPECT_EQ(virtual_label_2->GetNativeObject(),
- GetButtonAccessibility()->ChildAtIndex(1));
-}
-
TEST_F(AXVirtualViewTest, OverrideFocus) {
ViewAccessibility& button_accessibility = button_->GetViewAccessibility();
ASSERT_NE(nullptr, button_accessibility.GetNativeObject());
@@ -490,9 +363,7 @@ TEST_F(AXVirtualViewTest, OverrideFocus) {
button_->SetFocusBehavior(View::FocusBehavior::ALWAYS);
button_->RequestFocus();
ExpectReceivedAccessibilityEvents(
- {std::make_pair(GetButtonAccessibility(), ax::mojom::Event::kFocus),
- std::make_pair(GetButtonAccessibility(),
- ax::mojom::Event::kChildrenChanged)});
+ {std::make_pair(GetButtonAccessibility(), ax::mojom::Event::kFocus)});
EXPECT_EQ(button_accessibility.GetNativeObject(),
button_accessibility.GetFocusedDescendant());
@@ -555,9 +426,7 @@ TEST_F(AXVirtualViewTest, OverrideFocus) {
button_->SetFocusBehavior(View::FocusBehavior::ALWAYS);
button_->RequestFocus();
ExpectReceivedAccessibilityEvents(
- {std::make_pair(virtual_child_3, ax::mojom::Event::kFocus),
- std::make_pair(GetButtonAccessibility(),
- ax::mojom::Event::kChildrenChanged)});
+ {std::make_pair(virtual_child_3, ax::mojom::Event::kFocus)});
// Test that calling GetFocus() from any object in the tree will return the
// same result.
@@ -595,16 +464,14 @@ TEST_F(AXVirtualViewTest, OverrideFocus) {
ax::mojom::Event::kChildrenChanged)});
}
-TEST_F(AXVirtualViewTest, Navigation) {
+TEST_F(AXVirtualViewTest, TreeNavigation) {
ASSERT_EQ(0, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_1 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
- EXPECT_EQ(1, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_2 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_2));
- EXPECT_EQ(2, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_3 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_3));
@@ -612,29 +479,225 @@ TEST_F(AXVirtualViewTest, Navigation) {
AXVirtualView* virtual_child_4 = new AXVirtualView;
virtual_child_2->AddChildView(base::WrapUnique(virtual_child_4));
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_label_->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_1->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_2->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_3->GetParent());
+ EXPECT_EQ(virtual_child_2->GetNativeObject(), virtual_child_4->GetParent());
+
+ EXPECT_EQ(0, virtual_label_->GetIndexInParent());
+ EXPECT_EQ(0, virtual_child_1->GetIndexInParent());
+ EXPECT_EQ(1, virtual_child_2->GetIndexInParent());
+ EXPECT_EQ(2, virtual_child_3->GetIndexInParent());
+ EXPECT_EQ(0, virtual_child_4->GetIndexInParent());
+
+ EXPECT_EQ(3, virtual_label_->GetChildCount());
+ EXPECT_EQ(0, virtual_child_1->GetChildCount());
+ EXPECT_EQ(1, virtual_child_2->GetChildCount());
+ EXPECT_EQ(0, virtual_child_3->GetChildCount());
+ EXPECT_EQ(0, virtual_child_4->GetChildCount());
+
+ EXPECT_EQ(virtual_child_1->GetNativeObject(),
+ virtual_label_->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_2->GetNativeObject(),
+ virtual_label_->ChildAtIndex(1));
+ EXPECT_EQ(virtual_child_3->GetNativeObject(),
+ virtual_label_->ChildAtIndex(2));
+ EXPECT_EQ(virtual_child_4->GetNativeObject(),
+ virtual_child_2->ChildAtIndex(0));
+
+ EXPECT_EQ(virtual_child_1->GetNativeObject(),
+ virtual_label_->GetFirstChild());
+ EXPECT_EQ(virtual_child_3->GetNativeObject(), virtual_label_->GetLastChild());
+ EXPECT_EQ(nullptr, virtual_child_1->GetFirstChild());
+ EXPECT_EQ(nullptr, virtual_child_1->GetLastChild());
+ EXPECT_EQ(virtual_child_4->GetNativeObject(),
+ virtual_child_2->GetFirstChild());
+ EXPECT_EQ(virtual_child_4->GetNativeObject(),
+ virtual_child_2->GetLastChild());
+ EXPECT_EQ(nullptr, virtual_child_4->GetFirstChild());
+ EXPECT_EQ(nullptr, virtual_child_4->GetLastChild());
+
EXPECT_EQ(nullptr, virtual_label_->GetNextSibling());
EXPECT_EQ(nullptr, virtual_label_->GetPreviousSibling());
- EXPECT_EQ(0, virtual_label_->GetIndexInParent());
EXPECT_EQ(virtual_child_2->GetNativeObject(),
virtual_child_1->GetNextSibling());
EXPECT_EQ(nullptr, virtual_child_1->GetPreviousSibling());
- EXPECT_EQ(0, virtual_child_1->GetIndexInParent());
EXPECT_EQ(virtual_child_3->GetNativeObject(),
virtual_child_2->GetNextSibling());
EXPECT_EQ(virtual_child_1->GetNativeObject(),
virtual_child_2->GetPreviousSibling());
- EXPECT_EQ(1, virtual_child_2->GetIndexInParent());
EXPECT_EQ(nullptr, virtual_child_3->GetNextSibling());
EXPECT_EQ(virtual_child_2->GetNativeObject(),
virtual_child_3->GetPreviousSibling());
- EXPECT_EQ(2, virtual_child_3->GetIndexInParent());
EXPECT_EQ(nullptr, virtual_child_4->GetNextSibling());
EXPECT_EQ(nullptr, virtual_child_4->GetPreviousSibling());
- EXPECT_EQ(0, virtual_child_4->GetIndexInParent());
+}
+
+TEST_F(AXVirtualViewTest, TreeNavigationWithIgnoredVirtualViews) {
+ ASSERT_EQ(0, virtual_label_->GetChildCount());
+
+ AXVirtualView* virtual_child_1 = new AXVirtualView;
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
+ virtual_child_1->GetCustomData().AddState(ax::mojom::State::kIgnored);
+
+ EXPECT_EQ(0, virtual_label_->GetChildCount());
+ EXPECT_EQ(0, virtual_child_1->GetChildCount());
+
+ AXVirtualView* virtual_child_2 = new AXVirtualView;
+ virtual_child_1->AddChildView(base::WrapUnique(virtual_child_2));
+ AXVirtualView* virtual_child_3 = new AXVirtualView;
+ virtual_child_2->AddChildView(base::WrapUnique(virtual_child_3));
+ AXVirtualView* virtual_child_4 = new AXVirtualView;
+ virtual_child_2->AddChildView(base::WrapUnique(virtual_child_4));
+
+ // While ignored nodes should not be accessible via any of the tree navigation
+ // methods, their descendants should be.
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_label_->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_1->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_2->GetParent());
+ EXPECT_EQ(virtual_child_2->GetNativeObject(), virtual_child_3->GetParent());
+ EXPECT_EQ(virtual_child_2->GetNativeObject(), virtual_child_4->GetParent());
+
+ EXPECT_EQ(0, virtual_label_->GetIndexInParent());
+ EXPECT_EQ(-1, virtual_child_1->GetIndexInParent());
+ EXPECT_EQ(0, virtual_child_2->GetIndexInParent());
+ EXPECT_EQ(0, virtual_child_3->GetIndexInParent());
+ EXPECT_EQ(1, virtual_child_4->GetIndexInParent());
+
+ EXPECT_EQ(1, virtual_label_->GetChildCount());
+ EXPECT_EQ(1, virtual_child_1->GetChildCount());
+ EXPECT_EQ(2, virtual_child_2->GetChildCount());
+ EXPECT_EQ(0, virtual_child_3->GetChildCount());
+ EXPECT_EQ(0, virtual_child_4->GetChildCount());
+
+ EXPECT_EQ(virtual_child_2->GetNativeObject(),
+ virtual_label_->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_2->GetNativeObject(),
+ virtual_child_1->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_3->GetNativeObject(),
+ virtual_child_2->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_4->GetNativeObject(),
+ virtual_child_2->ChildAtIndex(1));
+
+ // Try ignoring a node by changing its role, instead of its state.
+ virtual_child_2->GetCustomData().role = ax::mojom::Role::kIgnored;
+
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_label_->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_1->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_2->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_3->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_4->GetParent());
+
+ EXPECT_EQ(2, virtual_label_->GetChildCount());
+ EXPECT_EQ(2, virtual_child_1->GetChildCount());
+ EXPECT_EQ(2, virtual_child_2->GetChildCount());
+ EXPECT_EQ(0, virtual_child_3->GetChildCount());
+ EXPECT_EQ(0, virtual_child_4->GetChildCount());
+
+ EXPECT_EQ(0, virtual_label_->GetIndexInParent());
+ EXPECT_EQ(-1, virtual_child_1->GetIndexInParent());
+ EXPECT_EQ(-1, virtual_child_2->GetIndexInParent());
+ EXPECT_EQ(0, virtual_child_3->GetIndexInParent());
+ EXPECT_EQ(1, virtual_child_4->GetIndexInParent());
+
+ EXPECT_EQ(virtual_child_3->GetNativeObject(),
+ virtual_label_->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_4->GetNativeObject(),
+ virtual_label_->ChildAtIndex(1));
+ EXPECT_EQ(virtual_child_3->GetNativeObject(),
+ virtual_child_1->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_4->GetNativeObject(),
+ virtual_child_1->ChildAtIndex(1));
+ EXPECT_EQ(virtual_child_3->GetNativeObject(),
+ virtual_child_2->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_4->GetNativeObject(),
+ virtual_child_2->ChildAtIndex(1));
+
+ // Test for mixed ignored and unignored virtual children.
+ AXVirtualView* virtual_child_5 = new AXVirtualView;
+ virtual_child_1->AddChildView(base::WrapUnique(virtual_child_5));
+
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_label_->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_1->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_2->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_3->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_4->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_5->GetParent());
+
+ EXPECT_EQ(3, virtual_label_->GetChildCount());
+ EXPECT_EQ(3, virtual_child_1->GetChildCount());
+ EXPECT_EQ(2, virtual_child_2->GetChildCount());
+ EXPECT_EQ(0, virtual_child_3->GetChildCount());
+ EXPECT_EQ(0, virtual_child_4->GetChildCount());
+ EXPECT_EQ(0, virtual_child_5->GetChildCount());
+
+ EXPECT_EQ(0, virtual_label_->GetIndexInParent());
+ EXPECT_EQ(-1, virtual_child_1->GetIndexInParent());
+ EXPECT_EQ(-1, virtual_child_2->GetIndexInParent());
+ EXPECT_EQ(0, virtual_child_3->GetIndexInParent());
+ EXPECT_EQ(1, virtual_child_4->GetIndexInParent());
+ EXPECT_EQ(2, virtual_child_5->GetIndexInParent());
+
+ EXPECT_EQ(virtual_child_3->GetNativeObject(),
+ virtual_label_->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_4->GetNativeObject(),
+ virtual_label_->ChildAtIndex(1));
+ EXPECT_EQ(virtual_child_5->GetNativeObject(),
+ virtual_label_->ChildAtIndex(2));
+
+ // An ignored root node should not be exposed.
+ virtual_label_->GetCustomData().AddState(ax::mojom::State::kIgnored);
+
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_label_->GetParent());
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_child_1->GetParent());
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_child_2->GetParent());
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_child_3->GetParent());
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_child_4->GetParent());
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_child_5->GetParent());
+
+ EXPECT_EQ(3, GetButtonAccessibility()->GetChildCount());
+
+ EXPECT_EQ(0, virtual_child_3->GetIndexInParent());
+ EXPECT_EQ(1, virtual_child_4->GetIndexInParent());
+ EXPECT_EQ(2, virtual_child_5->GetIndexInParent());
+
+ EXPECT_EQ(virtual_child_3->GetNativeObject(),
+ GetButtonAccessibility()->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_4->GetNativeObject(),
+ GetButtonAccessibility()->ChildAtIndex(1));
+ EXPECT_EQ(virtual_child_5->GetNativeObject(),
+ GetButtonAccessibility()->ChildAtIndex(2));
+
+ // Test for mixed ignored and unignored root nodes.
+ AXVirtualView* virtual_label_2 = new AXVirtualView;
+ virtual_label_2->GetCustomData().role = ax::mojom::Role::kStaticText;
+ virtual_label_2->GetCustomData().SetName("Label");
+ button_->GetViewAccessibility().AddVirtualChildView(
+ base::WrapUnique(virtual_label_2));
+
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_label_2->GetParent());
+
+ EXPECT_EQ(4, GetButtonAccessibility()->GetChildCount());
+ EXPECT_EQ(0, virtual_label_2->GetChildCount());
+
+ EXPECT_EQ(virtual_label_2->GetNativeObject(),
+ GetButtonAccessibility()->ChildAtIndex(3));
+
+ // A focusable node should not be ignored.
+ virtual_child_1->GetCustomData().AddState(ax::mojom::State::kFocusable);
+
+ EXPECT_EQ(2, GetButtonAccessibility()->GetChildCount());
+ EXPECT_EQ(1, virtual_label_->GetChildCount());
+
+ EXPECT_EQ(virtual_child_1->GetNativeObject(),
+ GetButtonAccessibility()->ChildAtIndex(0));
+ EXPECT_EQ(virtual_label_2->GetNativeObject(),
+ GetButtonAccessibility()->ChildAtIndex(1));
}
TEST_F(AXVirtualViewTest, HitTesting) {
@@ -682,6 +745,15 @@ TEST_F(AXVirtualViewTest, HitTesting) {
virtual_label_->HitTestSync(point_3.x(), point_3.y()));
}
+#if defined(USE_AURA)
+TEST_F(AXVirtualViewTest, GetOrCreateWrapper) {
+ std::unique_ptr<AXAuraObjCache> cache;
+ auto* wrapper1 = virtual_label_->GetOrCreateWrapper(cache.get());
+ cache = std::make_unique<AXAuraObjCache>();
+ EXPECT_NE(wrapper1, virtual_label_->GetOrCreateWrapper(cache.get()));
+}
+#endif
+
// Test for GetTargetForNativeAccessibilityEvent().
#if defined(OS_WIN)
TEST_F(AXVirtualViewTest, GetTargetForEvents) {
@@ -690,7 +762,7 @@ TEST_F(AXVirtualViewTest, GetTargetForEvents) {
EXPECT_EQ(HWNDForView(button_),
virtual_label_->GetTargetForNativeAccessibilityEvent());
}
-#endif
+#endif // defined(OS_WIN)
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_virtual_view_wrapper.cc b/chromium/ui/views/accessibility/ax_virtual_view_wrapper.cc
index dffc373da1a..bfdc3d663e1 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_virtual_view_wrapper.cc
@@ -4,6 +4,8 @@
#include "ui/views/accessibility/ax_virtual_view_wrapper.h"
+#include <string>
+
#include "ui/views/accessibility/ax_view_obj_wrapper.h"
#include "ui/views/accessibility/ax_virtual_view.h"
#include "ui/views/accessibility/view_accessibility.h"
@@ -17,10 +19,6 @@ AXVirtualViewWrapper::AXVirtualViewWrapper(AXVirtualView* virtual_view,
AXVirtualViewWrapper::~AXVirtualViewWrapper() = default;
-bool AXVirtualViewWrapper::IsIgnored() {
- return false;
-}
-
AXAuraObjWrapper* AXVirtualViewWrapper::GetParent() {
if (virtual_view_->virtual_parent_view()) {
return const_cast<AXVirtualView*>(virtual_view_->virtual_parent_view())
@@ -42,7 +40,7 @@ void AXVirtualViewWrapper::Serialize(ui::AXNodeData* out_node_data) {
*out_node_data = virtual_view_->GetData();
}
-int32_t AXVirtualViewWrapper::GetUniqueId() const {
+ui::AXNodeID AXVirtualViewWrapper::GetUniqueId() const {
return virtual_view_->GetUniqueId().Get();
}
diff --git a/chromium/ui/views/accessibility/ax_virtual_view_wrapper.h b/chromium/ui/views/accessibility/ax_virtual_view_wrapper.h
index 7588a5ffbba..f2e95234471 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_virtual_view_wrapper.h
@@ -5,6 +5,7 @@
#ifndef UI_VIEWS_ACCESSIBILITY_AX_VIRTUAL_VIEW_WRAPPER_H_
#define UI_VIEWS_ACCESSIBILITY_AX_VIRTUAL_VIEW_WRAPPER_H_
+#include <string>
#include <vector>
#include "ui/views/accessibility/ax_aura_obj_cache.h"
@@ -25,11 +26,10 @@ class AXVirtualViewWrapper : public AXAuraObjWrapper {
~AXVirtualViewWrapper() override;
// AXAuraObjWrapper:
- bool IsIgnored() override;
AXAuraObjWrapper* GetParent() override;
void GetChildren(std::vector<AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
- int32_t GetUniqueId() const override;
+ ui::AXNodeID GetUniqueId() const override;
bool HandleAccessibleAction(const ui::AXActionData& action) override;
std::string ToString() const override;
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
index c58811c8b67..7aba1f32a1d 100644
--- a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
@@ -18,17 +18,12 @@ namespace views {
AXWidgetObjWrapper::AXWidgetObjWrapper(AXAuraObjCache* aura_obj_cache,
Widget* widget)
: AXAuraObjWrapper(aura_obj_cache), widget_(widget) {
- widget_observer_.Add(widget);
- widget->AddRemovalsObserver(this);
+ DCHECK(widget->GetNativeView());
+ widget_observation_.Observe(widget);
+ widget_removals_observation_.Observe(widget);
}
-AXWidgetObjWrapper::~AXWidgetObjWrapper() {
- widget_->RemoveRemovalsObserver(this);
-}
-
-bool AXWidgetObjWrapper::IsIgnored() {
- return false;
-}
+AXWidgetObjWrapper::~AXWidgetObjWrapper() = default;
AXAuraObjWrapper* AXWidgetObjWrapper::GetParent() {
return aura_obj_cache_->GetOrCreate(widget_->GetNativeView());
@@ -58,7 +53,7 @@ void AXWidgetObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
out_node_data->state = 0;
}
-int32_t AXWidgetObjWrapper::GetUniqueId() const {
+ui::AXNodeID AXWidgetObjWrapper::GetUniqueId() const {
return unique_id_.Get();
}
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
index 9d768b80b85..b2b14bb7cb1 100644
--- a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
@@ -7,9 +7,10 @@
#include <stdint.h>
+#include <string>
#include <vector>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/widget/widget.h"
@@ -31,11 +32,10 @@ class AXWidgetObjWrapper : public AXAuraObjWrapper,
~AXWidgetObjWrapper() override;
// AXAuraObjWrapper overrides.
- bool IsIgnored() override;
AXAuraObjWrapper* GetParent() override;
void GetChildren(std::vector<AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
- int32_t GetUniqueId() const final;
+ ui::AXNodeID GetUniqueId() const final;
std::string ToString() const override;
// WidgetObserver overrides.
@@ -52,7 +52,12 @@ class AXWidgetObjWrapper : public AXAuraObjWrapper,
const ui::AXUniqueId unique_id_;
- ScopedObserver<Widget, WidgetObserver> widget_observer_{this};
+ base::ScopedObservation<Widget, WidgetObserver> widget_observation_{this};
+ base::ScopedObservation<Widget,
+ WidgetRemovalsObserver,
+ &Widget::AddRemovalsObserver,
+ &Widget::RemoveRemovalsObserver>
+ widget_removals_observation_{this};
};
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
index bdbe0ec689a..cc34462e2f3 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -81,7 +81,7 @@ AXWindowObjWrapper::AXWindowObjWrapper(AXAuraObjCache* aura_obj_cache,
: AXAuraObjWrapper(aura_obj_cache),
window_(window),
is_root_window_(window->IsRootWindow()) {
- observer_.Add(window);
+ observation_.Observe(window);
if (is_root_window_)
aura_obj_cache_->OnRootWindowObjCreated(window);
@@ -98,10 +98,6 @@ bool AXWindowObjWrapper::HandleAccessibleAction(
return false;
}
-bool AXWindowObjWrapper::IsIgnored() {
- return false;
-}
-
AXAuraObjWrapper* AXWindowObjWrapper::GetParent() {
aura::Window* parent = window_->parent();
if (!parent)
@@ -161,7 +157,7 @@ void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
GetWindowName(window_));
}
-int32_t AXWindowObjWrapper::GetUniqueId() const {
+ui::AXNodeID AXWindowObjWrapper::GetUniqueId() const {
return unique_id_.Get();
}
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
index 7c5514b3b5e..dda56e3d565 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
@@ -7,9 +7,10 @@
#include <stdint.h>
+#include <string>
#include <vector>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/aura/window.h"
@@ -31,11 +32,10 @@ class AXWindowObjWrapper : public AXAuraObjWrapper,
// AXAuraObjWrapper overrides.
bool HandleAccessibleAction(const ui::AXActionData& action) override;
- bool IsIgnored() override;
AXAuraObjWrapper* GetParent() override;
void GetChildren(std::vector<AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
- int32_t GetUniqueId() const final;
+ ui::AXNodeID GetUniqueId() const final;
std::string ToString() const override;
// WindowObserver overrides.
@@ -69,7 +69,8 @@ class AXWindowObjWrapper : public AXAuraObjWrapper,
// pointer could be left in |aura_obj_cache_|. See https://crbug.com/1091545
bool window_destroying_ = false;
- ScopedObserver<aura::Window, aura::WindowObserver> observer_{this};
+ base::ScopedObservation<aura::Window, aura::WindowObserver> observation_{
+ this};
};
} // namespace views
diff --git a/chromium/ui/views/accessibility/view_accessibility.cc b/chromium/ui/views/accessibility/view_accessibility.cc
index 3bbe3767096..a2914dbb74e 100644
--- a/chromium/ui/views/accessibility/view_accessibility.cc
+++ b/chromium/ui/views/accessibility/view_accessibility.cc
@@ -10,10 +10,15 @@
#include "base/callback.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
+#include "ui/accessibility/accessibility_features.h"
#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_tree_manager_map.h"
#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
#include "ui/base/buildflags.h"
+#include "ui/views/accessibility/views_ax_tree_manager.h"
+#include "ui/views/accessibility/widget_ax_tree_id_map.h"
#include "ui/views/view.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
@@ -27,11 +32,15 @@ bool IsValidRoleForViews(ax::mojom::Role role) {
// These roles all have special meaning and shouldn't ever be
// set on a View.
case ax::mojom::Role::kDesktop:
+ case ax::mojom::Role::kDocument: // Used for ARIA role="document".
+ case ax::mojom::Role::kIframe:
+ case ax::mojom::Role::kIframePresentational:
case ax::mojom::Role::kNone:
+ case ax::mojom::Role::kPdfRoot:
+ case ax::mojom::Role::kPortal:
case ax::mojom::Role::kRootWebArea:
case ax::mojom::Role::kSvgRoot:
case ax::mojom::Role::kUnknown:
- case ax::mojom::Role::kWebArea:
return false;
default:
@@ -53,7 +62,20 @@ ViewAccessibility::ViewAccessibility(View* view)
: view_(view),
focused_virtual_child_(nullptr),
is_leaf_(false),
- is_ignored_(false) {}
+ is_ignored_(false) {
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
+ if (features::IsAccessibilityTreeForViewsEnabled()) {
+ Widget* widget = view_->GetWidget();
+ if (widget && widget->is_top_level() &&
+ !WidgetAXTreeIDMap::GetInstance().HasWidget(widget)) {
+ View* root_view = static_cast<View*>(widget->GetRootView());
+ if (root_view && root_view == view) {
+ ax_tree_manager_ = std::make_unique<views::ViewsAXTreeManager>(widget);
+ }
+ }
+ }
+#endif
+}
ViewAccessibility::~ViewAccessibility() = default;
@@ -127,16 +149,10 @@ int ViewAccessibility::GetIndexOf(const AXVirtualView* virtual_view) const {
: -1;
}
-const ui::AXUniqueId& ViewAccessibility::GetUniqueId() const {
- return unique_id_;
-}
-
-bool ViewAccessibility::IsLeaf() const {
- return is_leaf_;
-}
-
void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
data->id = GetUniqueId().Get();
+ data->AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ view_->GetClassName());
// Views may misbehave if their widget is closed; return an unknown role
// rather than possibly crashing.
@@ -144,6 +160,17 @@ void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
if (!widget || !widget->widget_delegate() || widget->IsClosed()) {
data->role = ax::mojom::Role::kUnknown;
data->SetRestriction(ax::mojom::Restriction::kDisabled);
+
+ // Ordinarily, a view cannot be focusable if its widget has already closed.
+ // So, it would have been appropriate to set the focusable state to false in
+ // this particular case. However, the `FocusManager` may sometimes try to
+ // retrieve the focusable state of this view via
+ // `View::IsAccessibilityFocusable()`, even after this view's widget has
+ // been closed. Returning the wrong result might cause a crash, because the
+ // focus manager might be expecting the result to be the same regardless of
+ // the state of the view's widget.
+ if (ViewAccessibility::IsAccessibilityFocusable())
+ data->AddState(ax::mojom::State::kFocusable);
return;
}
@@ -174,7 +201,7 @@ void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
if (custom_data_.GetHasPopup() != ax::mojom::HasPopup::kFalse)
data->SetHasPopup(custom_data_.GetHasPopup());
- static const ax::mojom::IntAttribute kOverridableIntAttributes[]{
+ static constexpr ax::mojom::IntAttribute kOverridableIntAttributes[]{
ax::mojom::IntAttribute::kPosInSet,
ax::mojom::IntAttribute::kSetSize,
};
@@ -183,7 +210,7 @@ void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
data->AddIntAttribute(attribute, custom_data_.GetIntAttribute(attribute));
}
- static const ax::mojom::IntListAttribute kOverridableIntListAttributes[]{
+ static constexpr ax::mojom::IntListAttribute kOverridableIntListAttributes[]{
ax::mojom::IntListAttribute::kDescribedbyIds,
};
for (auto attribute : kOverridableIntListAttributes) {
@@ -200,8 +227,7 @@ void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
// their screen reader is announcing the same thing twice.
if (tooltip !=
data->GetString16Attribute(ax::mojom::StringAttribute::kName)) {
- data->AddStringAttribute(ax::mojom::StringAttribute::kDescription,
- base::UTF16ToUTF8(tooltip));
+ data->SetDescription(base::UTF16ToUTF8(tooltip));
}
}
@@ -209,22 +235,35 @@ void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
if (!custom_data_.relative_bounds.bounds.IsEmpty())
data->relative_bounds.bounds = custom_data_.relative_bounds.bounds;
- data->AddStringAttribute(ax::mojom::StringAttribute::kClassName,
- view_->GetClassName());
-
- if (IsIgnored()) {
- // Prevent screen readers from navigating to or speaking ignored nodes.
- data->AddState(ax::mojom::State::kInvisible);
+ // We need to add the ignored state to all ignored Views, similar to how Blink
+ // exposes ignored DOM nodes. Calling AXNodeData::IsIgnored() would also check
+ // if the role is in the list of roles that are inherently ignored.
+ // Furthermore, we add the ignored state if this View is a descendant of a
+ // leaf View. We call this class's "IsChildOfLeaf" method instead of the one
+ // in our platform specific subclass because subclasses determine if a node is
+ // a leaf by (among other things) counting the number of unignored children,
+ // which would create a circular definition of the ignored state.
+ if (is_ignored_ || data->IsIgnored() || ViewAccessibility::IsChildOfLeaf())
data->AddState(ax::mojom::State::kIgnored);
- data->role = ax::mojom::Role::kIgnored;
- return;
- }
- if (view_->IsAccessibilityFocusable() && !focused_virtual_child_)
+ if (ViewAccessibility::IsAccessibilityFocusable())
data->AddState(ax::mojom::State::kFocusable);
- if (!view_->GetEnabled())
+ if (is_enabled_) {
+ if (*is_enabled_) {
+ // Take into account the possibility that the View is marked as readonly
+ // but enabled. In other words, we can't just remove all restrictions,
+ // unless the View is explicitly marked as disabled. Note that readonly is
+ // another restriction state in addition to enabled and disabled, (see
+ // ax::mojom::Restriction).
+ if (data->GetRestriction() == ax::mojom::Restriction::kDisabled)
+ data->SetRestriction(ax::mojom::Restriction::kNone);
+ } else {
+ data->SetRestriction(ax::mojom::Restriction::kDisabled);
+ }
+ } else if (!view_->GetEnabled()) {
data->SetRestriction(ax::mojom::Restriction::kDisabled);
+ }
if (!view_->GetVisible() && data->role != ax::mojom::Role::kAlert)
data->AddState(ax::mojom::State::kInvisible);
@@ -248,14 +287,37 @@ void ViewAccessibility::OverrideFocus(AXVirtualView* virtual_view) {
}
}
-void ViewAccessibility::SetPopupFocusOverride() {}
-
-void ViewAccessibility::EndPopupFocusOverride() {}
+bool ViewAccessibility::IsAccessibilityFocusable() const {
+ // Descendants of leaf nodes should not be reported as focusable, because all
+ // such descendants are not exposed to the accessibility APIs of any platform.
+ // (See `AXNode::IsLeaf()` for more information.) We avoid calling
+ // `IsChildOfLeaf()` for performance reasons, because `FocusManager` makes use
+ // of this method, which means that it would be called frequently. However,
+ // since all descendants of leaf nodes are ignored by default, and since our
+ // testing framework enforces the condition that all ignored nodes should not
+ // be focusable, if there is test coverage, such a situation will cause a test
+ // failure.
+ return view_->GetFocusBehavior() != View::FocusBehavior::NEVER &&
+ ViewAccessibility::IsAccessibilityEnabled() && view_->IsDrawn() &&
+ !is_ignored_;
+}
-bool ViewAccessibility::IsFocusedForTesting() {
+bool ViewAccessibility::IsFocusedForTesting() const {
return view_->HasFocus() && !focused_virtual_child_;
}
+void ViewAccessibility::SetPopupFocusOverride() {
+ NOTIMPLEMENTED();
+}
+
+void ViewAccessibility::EndPopupFocusOverride() {
+ NOTIMPLEMENTED();
+}
+
+void ViewAccessibility::FireFocusAfterMenuClose() {
+ NotifyAccessibilityEvent(ax::mojom::Event::kFocusAfterMenuClose);
+}
+
void ViewAccessibility::OverrideRole(const ax::mojom::Role role) {
DCHECK(IsValidRoleForViews(role)) << "Invalid role for Views.";
custom_data_.role = role;
@@ -281,10 +343,54 @@ void ViewAccessibility::OverrideIsLeaf(bool value) {
is_leaf_ = value;
}
+bool ViewAccessibility::IsLeaf() const {
+ return is_leaf_;
+}
+
+bool ViewAccessibility::IsChildOfLeaf() const {
+ // Note to future developers: This method is called from
+ // "GetAccessibleNodeData". We should avoid calling any methods in any of our
+ // subclasses that might try and retrieve our AXNodeData, because this will
+ // cause an infinite loop.
+ // TODO(crbug.com/1100047): Make this method non-virtual and delete it from
+ // all subclasses.
+ if (const View* parent_view = view_->parent()) {
+ const ViewAccessibility& view_accessibility =
+ parent_view->GetViewAccessibility();
+ if (view_accessibility.ViewAccessibility::IsLeaf())
+ return true;
+ return view_accessibility.ViewAccessibility::IsChildOfLeaf();
+ }
+ return false;
+}
+
void ViewAccessibility::OverrideIsIgnored(bool value) {
is_ignored_ = value;
}
+bool ViewAccessibility::IsIgnored() const {
+ // TODO(nektar): Make this method non-virtual and implement as follows:
+ // ui::AXNodeData out_data;
+ // GetAccessibleNodeData(&out_data);
+ // return out_data.IsIgnored();
+ return is_ignored_;
+}
+
+void ViewAccessibility::OverrideIsEnabled(bool enabled) {
+ // Cannot store this value in `custom_data_` because
+ // `AXNodeData::AddIntAttribute` will DCHECK if you add an IntAttribute that
+ // is equal to kNone. Adding an IntAttribute that is equal to kNone is
+ // ambiguous, since it is unclear what would be the difference between doing
+ // this and not adding the attribute at all.
+ is_enabled_ = enabled;
+}
+
+bool ViewAccessibility::IsAccessibilityEnabled() const {
+ if (is_enabled_)
+ return *is_enabled_;
+ return view_->GetEnabled();
+}
+
void ViewAccessibility::OverrideBounds(const gfx::RectF& bounds) {
custom_data_.relative_bounds.bounds = bounds;
}
@@ -313,11 +419,11 @@ void ViewAccessibility::OverridePreviousFocus(Widget* widget) {
previous_focus_ = widget;
}
-Widget* ViewAccessibility::GetNextFocus() {
+Widget* ViewAccessibility::GetNextFocus() const {
return next_focus_;
}
-Widget* ViewAccessibility::GetPreviousFocus() {
+Widget* ViewAccessibility::GetPreviousFocus() const {
return previous_focus_;
}
@@ -343,16 +449,40 @@ void ViewAccessibility::AnnounceText(const base::string16& text) {
root_view->AnnounceText(text);
}
+const ui::AXUniqueId& ViewAccessibility::GetUniqueId() const {
+ return unique_id_;
+}
+
+ViewsAXTreeManager* ViewAccessibility::AXTreeManager() const {
+ ViewsAXTreeManager* manager = nullptr;
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
+ Widget* widget = view_->GetWidget();
+
+ // Don't return managers for closing Widgets.
+ if (!widget || !widget->widget_delegate() || widget->IsClosed())
+ return nullptr;
+
+ manager = ax_tree_manager_.get();
+
+ // ViewsAXTreeManagers are only created for top-level windows (Widgets). For
+ // non top-level Views, look up the Widget's tree ID to retrieve the manager.
+ if (!manager) {
+ ui::AXTreeID tree_id =
+ WidgetAXTreeIDMap::GetInstance().GetWidgetTreeID(widget);
+ DCHECK_NE(tree_id, ui::AXTreeIDUnknown());
+ manager = static_cast<views::ViewsAXTreeManager*>(
+ ui::AXTreeManagerMap::GetInstance().GetManager(tree_id));
+ }
+#endif
+ return manager;
+}
+
gfx::NativeViewAccessible ViewAccessibility::GetFocusedDescendant() {
if (focused_virtual_child_)
return focused_virtual_child_->GetNativeObject();
return view_->GetNativeViewAccessible();
}
-void ViewAccessibility::FireFocusAfterMenuClose() {
- NotifyAccessibilityEvent(ax::mojom::Event::kFocusAfterMenuClose);
-}
-
const ViewAccessibility::AccessibilityEventsCallback&
ViewAccessibility::accessibility_events_callback() const {
return accessibility_events_callback_;
diff --git a/chromium/ui/views/accessibility/view_accessibility.h b/chromium/ui/views/accessibility/view_accessibility.h
index 38cda9c6363..7c8004b2c6b 100644
--- a/chromium/ui/views/accessibility/view_accessibility.h
+++ b/chromium/ui/views/accessibility/view_accessibility.h
@@ -10,8 +10,10 @@
#include <vector>
#include "base/callback_forward.h"
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/platform/ax_unique_id.h"
@@ -28,6 +30,7 @@ class AXPlatformNodeDelegate;
namespace views {
class View;
+class ViewsAXTreeManager;
class Widget;
// An object that manages the accessibility interface for a View.
@@ -54,14 +57,16 @@ class VIEWS_EXPORT ViewAccessibility {
// Modifies |node_data| to reflect the current accessible state of the
// associated View, taking any custom overrides into account
- // (see OverrideRole, etc. below).
+ // (see OverrideFocus, OverrideRole, etc. below).
virtual void GetAccessibleNodeData(ui::AXNodeData* node_data) const;
//
- // These override accessibility information, including properties returned
- // from View::GetAccessibleNodeData().
- // Note that string attributes are only used if non-empty, so you can't
- // override a string with the empty string.
+ // The following methods get or set accessibility attributes (in the owning
+ // View's AXNodeData), overrideing any identical attributes which might have
+ // been set by the owning View in its View::GetAccessibleNodeData() method.
+ //
+ // Note that accessibility string attributes are only used if non-empty, so
+ // you can't override a string with the empty string.
//
// Sets one of our virtual descendants as having the accessibility focus. This
@@ -71,33 +76,92 @@ class VIEWS_EXPORT ViewAccessibility {
// is illegal to set this to any virtual view that is currently not one of our
// descendants and this is enforced by a DCHECK.
void OverrideFocus(AXVirtualView* virtual_view);
+
+ // Returns whether this view is focusable when the user uses an accessibility
+ // aid or the keyboard, even though it may not be normally focusable. Note
+ // that if using the keyboard, on macOS the preference "Full Keyboard Access"
+ // needs to be turned on.
+ virtual bool IsAccessibilityFocusable() const;
+
+ // Used for testing. Returns true if this view is considered focused.
+ virtual bool IsFocusedForTesting() const;
+
+ // Call when this is the active descendant of a popup view that temporarily
+ // takes over focus. It is only necessary to use this for menus like autofill,
+ // where the actual focus is in content.
+ // When the popup closes, call EndPopupFocusOverride().
+ virtual void SetPopupFocusOverride();
+
+ // Call when popup closes, if it used SetPopupFocusOverride().
+ virtual void EndPopupFocusOverride();
+
+ // Call when a menu closes, to restore focus to where it was previously.
+ virtual void FireFocusAfterMenuClose();
+
void OverrideRole(const ax::mojom::Role role);
void OverrideName(const std::string& name);
void OverrideName(const base::string16& name);
void OverrideDescription(const std::string& description);
void OverrideDescription(const base::string16& description);
+
+ // Sets whether this View hides all its descendants from the accessibility
+ // tree that is exposed to platform APIs. This is similar, but not exactly
+ // identical to aria-hidden="true".
+ //
+ // Note that this attribute does not cross widget boundaries, i.e. if a sub
+ // widget is a descendant of this View, it will not be marked hidden. This
+ // should not happen in practice as widgets are not children of Views.
void OverrideIsLeaf(bool value);
+ virtual bool IsLeaf() const;
+
+ // Returns true if an ancestor of this node (not including itself) is a
+ // leaf node, meaning that this node is not actually exposed to any
+ // platform's accessibility layer.
+ virtual bool IsChildOfLeaf() const;
+
+ // Hides this View from the accessibility tree that is exposed to platform
+ // APIs.
void OverrideIsIgnored(bool value);
+ virtual bool IsIgnored() const;
+
+ // Marks this View either as enabled or disabled (grayed out) in the
+ // accessibility tree and ignores the View's real enabled state. Does not
+ // affect the View's focusable state (see "IsAccessibilityFocusable()").
+ // Screen readers make a special announcement when an item is disabled.
+ //
+ // It might not be advisable to mark a View as enabled in the accessibility
+ // tree, whilst the real View is actually disabled, because such a View will
+ // not respond to user actions.
+ void OverrideIsEnabled(bool enabled);
+ virtual bool IsAccessibilityEnabled() const;
+
void OverrideBounds(const gfx::RectF& bounds);
void OverrideDescribedBy(View* described_by_view);
void OverrideHasPopup(const ax::mojom::HasPopup has_popup);
- // Override indexes used by some screen readers when describing elements in a
- // menu, list, etc. If not specified, a view's index in its parent and its
- // parent's number of children provide the values for these.
+ // Override information provided to users by screen readers when describing
+ // elements in a menu, listbox, or another set-like item. For example, "New
+ // tab, menu item 1 of 5". If not specified, a view's index in its parent and
+ // its parent's number of children provide the values for |pos_in_set| and
+ // |set_size| respectively.
//
- // Note: |pos_in_set| is 1-indexed.
+ // Note that |pos_in_set| is one-based, i.e. it starts from 1 not 0.
void OverridePosInSet(int pos_in_set, int set_size);
- // Override the next or previous focused widget. Some screen readers may
- // utilize this information to transition focus from the beginning or end of
- // one window to another when navigating by its default navigation method.
+ // Override the next or previous focused widget. Some assistive technologies,
+ // such as screen readers, may utilize this information to transition focus
+ // from the beginning or end of one widget to another when navigating by its
+ // default navigation method.
void OverrideNextFocus(Widget* widget);
void OverridePreviousFocus(Widget* widget);
- Widget* GetNextFocus();
- Widget* GetPreviousFocus();
+ Widget* GetNextFocus() const;
+ Widget* GetPreviousFocus() const;
+ // Returns the accessibility object that represents the View whose
+ // accessibility is managed by this instance. This may be an AXPlatformNode or
+ // it may be a native accessible object implemented by another class.
virtual gfx::NativeViewAccessible GetNativeObject() const;
+
virtual void NotifyAccessibilityEvent(ax::mojom::Event event_type);
// Causes the screen reader to announce |text|. If the current user is not
@@ -108,8 +172,7 @@ class VIEWS_EXPORT ViewAccessibility {
View* view() const { return view_; }
AXVirtualView* FocusedVirtualChild() const { return focused_virtual_child_; }
- virtual bool IsLeaf() const;
- bool IsIgnored() const { return is_ignored_; }
+ ViewsAXTreeManager* AXTreeManager() const;
//
// Methods for managing virtual views.
@@ -149,21 +212,6 @@ class VIEWS_EXPORT ViewAccessibility {
// native accessibility object associated with this view.
gfx::NativeViewAccessible GetFocusedDescendant();
- // Call when this is the active descendant of a popup view that temporarily
- // takes over focus. It is only necessary to use this for menus like autofill,
- // where the actual focus is in content.
- // When the popup closes, call EndPopupFocusOverride().
- virtual void SetPopupFocusOverride();
-
- // Call when popup closes, if it used SetPopupFocusOverride().
- virtual void EndPopupFocusOverride();
-
- // Return true if this view is considered focused.
- virtual bool IsFocusedForTesting();
-
- // Call when a menu closes, to restore focus to where it was previously.
- virtual void FireFocusAfterMenuClose();
-
// Used for testing. Allows a test to watch accessibility events.
const AccessibilityEventsCallback& accessibility_events_callback() const;
void set_accessibility_events_callback(AccessibilityEventsCallback callback);
@@ -207,8 +255,20 @@ class VIEWS_EXPORT ViewAccessibility {
// "presentational".
bool is_ignored_;
+ // Used to override the View's enabled state in case we need to mark the View
+ // as enabled or disabled only in the accessibility tree.
+ base::Optional<bool> is_enabled_ = base::nullopt;
+
+ // Used by the Views system to help some assistive technologies, such as
+ // screen readers, transition focus from one widget to another.
Widget* next_focus_ = nullptr;
Widget* previous_focus_ = nullptr;
+
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
+ // Each instance of ViewAccessibility that's associated with a root View
+ // owns an ViewsAXTreeManager. For other Views, this should be nullptr.
+ std::unique_ptr<views::ViewsAXTreeManager> ax_tree_manager_;
+#endif
};
} // namespace views
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 00b72e939ed..3c427e8e606 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -113,17 +113,26 @@ void PostFlushEventQueueTaskIfNecessary() {
} // namespace
-struct ViewAXPlatformNodeDelegate::ChildWidgetsResult {
- std::vector<Widget*> child_widgets;
+ViewAXPlatformNodeDelegate::ChildWidgetsResult::ChildWidgetsResult() = default;
- // Set to true if, instead of populating |child_widgets| normally, a single
- // child widget was returned (e.g. a dialog that should be read instead of
- // the rest of the page contents).
- bool is_tab_modal_showing;
-};
+ViewAXPlatformNodeDelegate::ChildWidgetsResult::ChildWidgetsResult(
+ std::vector<Widget*> child_widgets,
+ bool is_tab_modal_showing)
+ : child_widgets(child_widgets),
+ is_tab_modal_showing(is_tab_modal_showing) {}
+ViewAXPlatformNodeDelegate::ChildWidgetsResult::ChildWidgetsResult(
+ const ViewAXPlatformNodeDelegate::ChildWidgetsResult& other) = default;
+
+ViewAXPlatformNodeDelegate::ChildWidgetsResult::~ChildWidgetsResult() = default;
+
+ViewAXPlatformNodeDelegate::ChildWidgetsResult&
+ViewAXPlatformNodeDelegate::ChildWidgetsResult::operator=(
+ const ViewAXPlatformNodeDelegate::ChildWidgetsResult& other) = default;
ViewAXPlatformNodeDelegate::ViewAXPlatformNodeDelegate(View* view)
- : ViewAccessibility(view) {
+ : ViewAccessibility(view) {}
+
+void ViewAXPlatformNodeDelegate::Init() {
ax_platform_node_ = ui::AXPlatformNode::Create(this);
DCHECK(ax_platform_node_);
@@ -136,29 +145,69 @@ ViewAXPlatformNodeDelegate::ViewAXPlatformNodeDelegate(View* view)
}
ViewAXPlatformNodeDelegate::~ViewAXPlatformNodeDelegate() {
- if (ui::AXPlatformNode::GetPopupFocusOverride() == GetNativeObject())
- EndPopupFocusOverride();
+ if (ui::AXPlatformNode::GetPopupFocusOverride() ==
+ ax_platform_node_->GetNativeViewAccessible()) {
+ ui::AXPlatformNode::SetPopupFocusOverride(nullptr);
+ }
ax_platform_node_->Destroy();
}
-gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetNativeObject() const {
- DCHECK(ax_platform_node_);
- return ax_platform_node_->GetNativeViewAccessible();
+bool ViewAXPlatformNodeDelegate::IsAccessibilityFocusable() const {
+ return GetData().HasState(ax::mojom::State::kFocusable);
+}
+
+bool ViewAXPlatformNodeDelegate::IsFocusedForTesting() const {
+ if (ui::AXPlatformNode::GetPopupFocusOverride()) {
+ return ui::AXPlatformNode::GetPopupFocusOverride() ==
+ GetNativeViewAccessible();
+ }
+
+ return ViewAccessibility::IsFocusedForTesting();
}
void ViewAXPlatformNodeDelegate::SetPopupFocusOverride() {
- ui::AXPlatformNode::SetPopupFocusOverride(GetNativeObject());
+ ui::AXPlatformNode::SetPopupFocusOverride(GetNativeViewAccessible());
}
void ViewAXPlatformNodeDelegate::EndPopupFocusOverride() {
ui::AXPlatformNode::SetPopupFocusOverride(nullptr);
}
-bool ViewAXPlatformNodeDelegate::IsFocusedForTesting() {
- if (ui::AXPlatformNode::GetPopupFocusOverride())
- return ui::AXPlatformNode::GetPopupFocusOverride() == GetNativeObject();
+void ViewAXPlatformNodeDelegate::FireFocusAfterMenuClose() {
+ ui::AXPlatformNodeBase* focused_node =
+ static_cast<ui::AXPlatformNodeBase*>(ax_platform_node_);
+ // Continue to drill down focused nodes to get to the "deepest" node that is
+ // focused. This is not necessarily a view. It could be web content.
+ while (focused_node) {
+ ui::AXPlatformNodeBase* deeper_focus = static_cast<ui::AXPlatformNodeBase*>(
+ ui::AXPlatformNode::FromNativeViewAccessible(focused_node->GetFocus()));
+ if (!deeper_focus || deeper_focus == focused_node)
+ break;
+ focused_node = deeper_focus;
+ }
+ if (focused_node) {
+ // Callback used for testing.
+ if (accessibility_events_callback_) {
+ accessibility_events_callback_.Run(
+ this, ax::mojom::Event::kFocusAfterMenuClose);
+ }
+
+ focused_node->NotifyAccessibilityEvent(
+ ax::mojom::Event::kFocusAfterMenuClose);
+ }
+}
+
+bool ViewAXPlatformNodeDelegate::IsIgnored() const {
+ // TODO(nektar): Make `ViewAccessibility::IsIgnored()` non-virtual and delete
+ // this method. For this to happen
+ // `IsViewUnfocusableDescendantOfFocusableAncestor()` needs to be moved to
+ // `ViewAccessibility`.
+ return GetData().IsIgnored();
+}
- return ViewAccessibility::IsFocusedForTesting();
+gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetNativeObject() const {
+ DCHECK(ax_platform_node_);
+ return ax_platform_node_->GetNativeViewAccessible();
}
void ViewAXPlatformNodeDelegate::NotifyAccessibilityEvent(
@@ -182,7 +231,7 @@ void ViewAXPlatformNodeDelegate::NotifyAccessibilityEvent(
case ax::mojom::Event::kFocus: {
if (ui::AXPlatformNode::GetPopupFocusOverride()) {
DCHECK_EQ(ui::AXPlatformNode::GetPopupFocusOverride(),
- GetNativeObject())
+ GetNativeViewAccessible())
<< "If the popup focus override is on, then the kFocus event must "
"match it. Most likely the popup has closed, but did not call "
"ViewAccessibility::EndPopupFocusOverride(), and focus has "
@@ -217,32 +266,7 @@ void ViewAXPlatformNodeDelegate::NotifyAccessibilityEvent(
void ViewAXPlatformNodeDelegate::AnnounceText(const base::string16& text) {
ax_platform_node_->AnnounceText(text);
}
-#endif
-
-void ViewAXPlatformNodeDelegate::FireFocusAfterMenuClose() {
- ui::AXPlatformNodeBase* focused_node =
- static_cast<ui::AXPlatformNodeBase*>(ax_platform_node_);
- // Continue to drill down focused nodes to get to the "deepest" node that is
- // focused, this is not necessarily a view. (It could be web content.)
- while (focused_node) {
- ui::AXPlatformNodeBase* deeper_focus = static_cast<ui::AXPlatformNodeBase*>(
- ui::AXPlatformNode::FromNativeViewAccessible(focused_node->GetFocus()));
- if (!deeper_focus || deeper_focus == focused_node)
- break;
- focused_node = deeper_focus;
- }
- if (focused_node) {
- // callback used for testing
- if (accessibility_events_callback_)
- accessibility_events_callback_.Run(
- this, ax::mojom::Event::kFocusAfterMenuClose);
-
- focused_node->NotifyAccessibilityEvent(
- ax::mojom::Event::kFocusAfterMenuClose);
- }
-}
-
-// ui::AXPlatformNodeDelegate
+#endif // defined(OS_APPLE)
const ui::AXNodeData& ViewAXPlatformNodeDelegate::GetData() const {
// Clear the data, then populate it.
@@ -267,81 +291,137 @@ const ui::AXNodeData& ViewAXPlatformNodeDelegate::GetData() const {
// accessibility tree. We need to replace this with a cross-platform
// solution that works for ChromeVox, too, and move it to ViewAccessibility.
if (IsViewUnfocusableDescendantOfFocusableAncestor(view()))
- data_.role = ax::mojom::Role::kIgnored;
+ data_.AddState(ax::mojom::State::kIgnored);
return data_;
}
int ViewAXPlatformNodeDelegate::GetChildCount() const {
+ // We call `ViewAccessibility::IsLeaf` here instead of our own override
+ // because our class has an expanded definition of what a leaf node is, which
+ // includes all nodes with zero unignored children. Calling our own override
+ // would create a circular definition of what a "leaf node" is.
if (ViewAccessibility::IsLeaf())
return 0;
+ // If present, virtual view children override any real children.
if (!virtual_children().empty()) {
- int count = 0;
- for (const std::unique_ptr<AXVirtualView>& child : virtual_children()) {
- if (child->IsIgnored()) {
- count += child->GetChildCount();
- continue;
+ // Ignored virtual views are not exposed in any accessibility platform APIs.
+ // Remove all ignored virtual view children and recursively replace them
+ // with their unignored children count.
+ int virtual_child_count = 0;
+ for (const std::unique_ptr<AXVirtualView>& virtual_child :
+ virtual_children()) {
+ if (virtual_child->IsIgnored()) {
+ virtual_child_count += virtual_child->GetChildCount();
+ } else {
+ ++virtual_child_count;
}
- count++;
}
- return count;
+
+ // A virtual views subtree hides any real view children.
+ return virtual_child_count;
}
- const auto child_widgets_result = GetChildWidgets();
+ const ChildWidgetsResult child_widgets_result = GetChildWidgets();
if (child_widgets_result.is_tab_modal_showing) {
+ // In order to support the "read title (NVDAKey+T)" and "read window
+ // (NVDAKey+B)" commands in the NVDA screen reader, hide the rest of the UI
+ // from the accessibility tree when a modal dialog is showing.
DCHECK_EQ(child_widgets_result.child_widgets.size(), 1U);
return 1;
}
- return static_cast<int>(view()->children().size() +
- child_widgets_result.child_widgets.size());
+
+ // Ignored views are not exposed in any accessibility platform APIs. Remove
+ // all ignored view children and recursively replace them with their unignored
+ // children count. This matches how AXPlatformNodeDelegate::GetChildCount()
+ // behaves for Web content.
+ int view_child_count = 0;
+ for (View* child : view()->children()) {
+ const ViewAccessibility& view_accessibility = child->GetViewAccessibility();
+ if (view_accessibility.IsIgnored()) {
+ const auto* child_view_delegate =
+ static_cast<const ViewAXPlatformNodeDelegate*>(&view_accessibility);
+ DCHECK(child_view_delegate);
+ view_child_count += child_view_delegate->GetChildCount();
+ } else {
+ ++view_child_count;
+ }
+ }
+
+ return view_child_count + int{child_widgets_result.child_widgets.size()};
}
gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::ChildAtIndex(int index) {
- DCHECK_GE(index, 0) << "Child indices should be greater or equal to 0.";
+ DCHECK_GE(index, 0) << "|index| should be greater or equal to 0.";
DCHECK_LT(index, GetChildCount())
- << "Child indices should be less than the child count.";
+ << "|index| should be less than the unignored child count.";
if (IsLeaf())
return nullptr;
- size_t child_index = size_t{index};
if (!virtual_children().empty()) {
- int i = 0;
- for (const std::unique_ptr<AXVirtualView>& child : virtual_children()) {
- if (child->IsIgnored()) {
- if (index - i < child->GetChildCount()) {
- gfx::NativeViewAccessible result = child->ChildAtIndex(index - i);
- if (result)
- return result;
- }
- i += child->GetChildCount();
- continue;
+ // A virtual views subtree hides all the real view children.
+ for (const std::unique_ptr<AXVirtualView>& virtual_child :
+ virtual_children()) {
+ if (virtual_child->IsIgnored()) {
+ int virtual_child_count = virtual_child->GetChildCount();
+ if (index < virtual_child_count)
+ return virtual_child->ChildAtIndex(index);
+ index -= virtual_child_count;
+ } else {
+ if (index == 0)
+ return virtual_child->GetNativeObject();
+ --index;
}
- if (i == index)
- return child->GetNativeObject();
- i++;
+
+ DCHECK_GE(index, 0);
}
+
+ NOTREACHED() << "|index| should be less than the unignored child count.";
return nullptr;
}
- // If this is a root view, our widget might have child widgets. Include
- const auto child_widgets_result = GetChildWidgets();
- const auto& child_widgets = child_widgets_result.child_widgets;
+ // Our widget might have child widgets. If this is a root view, include those
+ // widgets in the list of the root view's children because this is the most
+ // opportune location in the accessibility tree to expose them.
+ const ChildWidgetsResult child_widgets_result = GetChildWidgets();
+ const std::vector<Widget*>& child_widgets =
+ child_widgets_result.child_widgets;
- // If a visible tab modal dialog is present, ignore |index| and return the
- // dialog.
+ // If a visible tab modal dialog is present, return the dialog's root view.
+ //
+ // This is in order to support the "read title (NVDAKey+T)" and "read window
+ // (NVDAKey+B)" commands in the NVDA screen reader. We need to hide the rest
+ // of the UI, other than the dialog, from the screen reader.
if (child_widgets_result.is_tab_modal_showing) {
+ DCHECK_EQ(index, 0);
DCHECK_EQ(child_widgets.size(), 1U);
return child_widgets[0]->GetRootView()->GetNativeViewAccessible();
}
- if (child_index < view()->children().size())
- return view()->children()[child_index]->GetNativeViewAccessible();
+ for (View* child : view()->children()) {
+ ViewAccessibility& view_accessibility = child->GetViewAccessibility();
+ if (view_accessibility.IsIgnored()) {
+ auto* child_view_delegate =
+ static_cast<ViewAXPlatformNodeDelegate*>(&view_accessibility);
+ DCHECK(child_view_delegate);
+ int child_count = child_view_delegate->GetChildCount();
+ if (index < child_count)
+ return child_view_delegate->ChildAtIndex(index);
+ index -= child_count;
+ } else {
+ if (index == 0)
+ return view_accessibility.view()->GetNativeViewAccessible();
+ --index;
+ }
+
+ DCHECK_GE(index, 0);
+ }
- child_index -= view()->children().size();
- if (child_index < child_widgets_result.child_widgets.size())
- return child_widgets[child_index]->GetRootView()->GetNativeViewAccessible();
+ if (index < int{child_widgets_result.child_widgets.size()})
+ return child_widgets[index]->GetRootView()->GetNativeViewAccessible();
+ NOTREACHED() << "|index| should be less than the unignored child count.";
return nullptr;
}
@@ -349,19 +429,41 @@ bool ViewAXPlatformNodeDelegate::HasModalDialog() const {
return GetChildWidgets().is_tab_modal_showing;
}
+bool ViewAXPlatformNodeDelegate::IsChildOfLeaf() const {
+ return AXPlatformNodeDelegateBase::IsChildOfLeaf();
+}
+
gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetNSWindow() {
- NOTREACHED();
+ NOTIMPLEMENTED() << "Should only be called on Mac.";
return nullptr;
}
+gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetNativeViewAccessible()
+ const {
+ // TODO(nektar): Make "GetNativeViewAccessible" const throughout the codebase.
+ return const_cast<ViewAXPlatformNodeDelegate*>(this)
+ ->GetNativeViewAccessible();
+}
+
gfx::NativeViewAccessible
ViewAXPlatformNodeDelegate::GetNativeViewAccessible() {
- return GetNativeObject();
+ // The WebView class returns the BrowserAccessibility instance exposed by its
+ // WebContents child, not its own AXPlatformNode. This is done by overriding
+ // "GetNativeViewAccessible", so we can't simply call "GetNativeObject" here.
+ return view()->GetNativeViewAccessible();
}
gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetParent() {
- if (view()->parent())
- return view()->parent()->GetNativeViewAccessible();
+ if (View* parent_view = view()->parent()) {
+ ViewAccessibility& view_accessibility = parent_view->GetViewAccessibility();
+ if (!view_accessibility.IsIgnored())
+ return parent_view->GetNativeViewAccessible();
+
+ auto* parent_view_delegate =
+ static_cast<ViewAXPlatformNodeDelegate*>(&view_accessibility);
+ DCHECK(parent_view_delegate);
+ return parent_view_delegate->GetParent();
+ }
if (Widget* widget = view()->GetWidget()) {
Widget* top_widget = widget->GetTopLevelWidget();
@@ -372,15 +474,22 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetParent() {
return nullptr;
}
-bool ViewAXPlatformNodeDelegate::IsChildOfLeaf() const {
- // Needed to prevent endless loops, see: http://crbug.com/1100047
- return false;
-}
-
bool ViewAXPlatformNodeDelegate::IsLeaf() const {
return ViewAccessibility::IsLeaf() || AXPlatformNodeDelegateBase::IsLeaf();
}
+bool ViewAXPlatformNodeDelegate::IsInvisibleOrIgnored() const {
+ return IsIgnored() || !view()->GetVisible();
+}
+
+bool ViewAXPlatformNodeDelegate::IsAccessibilityEnabled() const {
+ return GetData().GetRestriction() != ax::mojom::Restriction::kDisabled;
+}
+
+bool ViewAXPlatformNodeDelegate::IsFocused() const {
+ return GetFocus() == GetNativeObject();
+}
+
bool ViewAXPlatformNodeDelegate::IsToplevelBrowserWindow() {
// Note: only used on Desktop Linux. Other platforms don't have an application
// node so this would never return true.
@@ -415,7 +524,7 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::HitTestSync(
return nullptr;
if (IsLeaf())
- return GetNativeObject();
+ return GetNativeViewAccessible();
gfx::NativeView native_view = view()->GetWidget()->GetNativeView();
float scale_factor = 1.0;
@@ -453,7 +562,7 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::HitTestSync(
return result;
}
// If it's not inside any of our virtual children, it's inside this view.
- return GetNativeObject();
+ return GetNativeViewAccessible();
}
// Check if the point is within any of the immediate children of this
@@ -474,11 +583,11 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::HitTestSync(
const auto i = std::find_if(v->children().rbegin(), v->children().rend(),
is_point_in_child);
// If it's not inside any of our children, it's inside this view.
- return (i == v->children().rend()) ? GetNativeObject()
+ return (i == v->children().rend()) ? GetNativeViewAccessible()
: (*i)->GetNativeViewAccessible();
}
-gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetFocus() {
+gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetFocus() const {
gfx::NativeViewAccessible focus_override =
ui::AXPlatformNode::GetPopupFocusOverride();
if (focus_override)
@@ -570,6 +679,24 @@ std::vector<int32_t> ViewAXPlatformNodeDelegate::GetColHeaderNodeIds(
return {columns[col_index]};
}
+base::Optional<int32_t> ViewAXPlatformNodeDelegate::GetCellId(
+ int row_index,
+ int col_index) const {
+ if (virtual_children().empty() || !GetAncestorTableView())
+ return base::nullopt;
+
+ AXVirtualView* ax_cell =
+ GetAncestorTableView()->GetVirtualAccessibilityCell(row_index, col_index);
+ if (!ax_cell)
+ return base::nullopt;
+
+ const ui::AXNodeData& cell_data = ax_cell->GetData();
+ if (cell_data.role == ax::mojom::Role::kCell)
+ return cell_data.id;
+
+ return base::nullopt;
+}
+
TableView* ViewAXPlatformNodeDelegate::GetAncestorTableView() const {
ui::AXNodeData data;
view()->GetViewAccessibility().GetAccessibleNodeData(&data);
@@ -652,27 +779,22 @@ void ViewAXPlatformNodeDelegate::GetViewsInGroupForSet(
[](View* view) {
ViewAccessibility& view_accessibility =
view->GetViewAccessibility();
- bool is_ignored = view_accessibility.IsIgnored();
- // TODO(dmazzoni): Remove the remainder of this lambda once the
- // temporary code in GetData() setting the role to kIgnored is moved
- // to ViewAccessibility.
- ViewAXPlatformNodeDelegate* ax_delegate =
- static_cast<ViewAXPlatformNodeDelegate*>(&view_accessibility);
- if (ax_delegate)
- is_ignored = is_ignored || ax_delegate->IsIgnored();
- return is_ignored;
+ return view_accessibility.IsIgnored();
}),
views_in_group->end());
}
ViewAXPlatformNodeDelegate::ChildWidgetsResult
ViewAXPlatformNodeDelegate::GetChildWidgets() const {
- // Only attach child widgets to the root view.
+ // This method is used to create a parent / child relationship between the
+ // root view and any child widgets. Child widgets should only be exposed as
+ // the direct children of the root view. A root view should appear as the only
+ // child of a widget.
Widget* widget = view()->GetWidget();
// Note that during window close, a Widget may exist in a state where it has
// no NativeView, but hasn't yet torn down its view hierarchy.
if (!widget || !widget->GetNativeView() || widget->GetRootView() != view())
- return {{}, false};
+ return ChildWidgetsResult();
std::set<Widget*> owned_widgets;
Widget::GetAllOwnedWidgets(widget->GetNativeView(), &owned_widgets);
@@ -687,15 +809,19 @@ ViewAXPlatformNodeDelegate::GetChildWidgets() const {
const FocusManager* focus_manager = view()->GetFocusManager();
const View* focused_view =
focus_manager ? focus_manager->GetFocusedView() : nullptr;
- const auto is_focused_child = [focused_view](Widget* child) {
- return ViewAccessibilityUtils::IsFocusedChildWidget(child, focused_view);
+ const auto is_focused_child = [focused_view](Widget* child_widget) {
+ return ViewAccessibilityUtils::IsFocusedChildWidget(child_widget,
+ focused_view);
};
const auto i = std::find_if(visible_widgets.cbegin(), visible_widgets.cend(),
is_focused_child);
+ // In order to support the "read title (NVDAKey+T)" and "read window
+ // (NVDAKey+B)" commands in the NVDA screen reader, hide the rest of the UI
+ // from the accessibility tree when a modal dialog is showing.
if (i != visible_widgets.cend())
- return {{*i}, true};
+ return ChildWidgetsResult({*i}, true /* is_tab_modal_showing */);
- return {visible_widgets, false};
+ return ChildWidgetsResult(visible_widgets, false /* is_tab_modal_showing */);
}
} // namespace views
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h
index f4ba9a4787b..cc0297fd1f2 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h
@@ -9,6 +9,7 @@
#include <vector>
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
@@ -44,27 +45,35 @@ class ViewAXPlatformNodeDelegate : public ViewAccessibility,
~ViewAXPlatformNodeDelegate() override;
// ViewAccessibility:
+ bool IsAccessibilityFocusable() const override;
+ bool IsFocusedForTesting() const override;
+ void SetPopupFocusOverride() override;
+ void EndPopupFocusOverride() override;
+ void FireFocusAfterMenuClose() override;
+ bool IsIgnored() const override;
+ bool IsAccessibilityEnabled() const override;
gfx::NativeViewAccessible GetNativeObject() const override;
void NotifyAccessibilityEvent(ax::mojom::Event event_type) override;
#if defined(OS_APPLE)
void AnnounceText(const base::string16& text) override;
#endif
- void FireFocusAfterMenuClose() override;
- // ui::AXPlatformNodeDelegate
- // Note that, for parents of virtual views, GetChildCount() and ChildAtIndex()
- // present to assistive technologies the unignored accessibility subtree,
- // which doesn't necessarily reflect the internal descendant tree. (An ignored
- // node means that the node should not be exposed to the platform.)
+ // ui::AXPlatformNodeDelegate.
const ui::AXNodeData& GetData() const override;
int GetChildCount() const override;
gfx::NativeViewAccessible ChildAtIndex(int index) override;
bool HasModalDialog() const override;
+ // Also in |ViewAccessibility|.
+ bool IsChildOfLeaf() const override;
gfx::NativeViewAccessible GetNSWindow() override;
+ // TODO(nektar): Make "GetNativeViewAccessible" a const method throughout the
+ // codebase.
+ gfx::NativeViewAccessible GetNativeViewAccessible() const;
gfx::NativeViewAccessible GetNativeViewAccessible() override;
gfx::NativeViewAccessible GetParent() override;
- bool IsChildOfLeaf() const override;
bool IsLeaf() const override;
+ bool IsInvisibleOrIgnored() const override;
+ bool IsFocused() const override;
bool IsToplevelBrowserWindow() override;
gfx::Rect GetBoundsRect(
const ui::AXCoordinateSystem coordinate_system,
@@ -73,7 +82,7 @@ class ViewAXPlatformNodeDelegate : public ViewAccessibility,
gfx::NativeViewAccessible HitTestSync(
int screen_physical_pixel_x,
int screen_physical_pixel_y) const override;
- gfx::NativeViewAccessible GetFocus() override;
+ gfx::NativeViewAccessible GetFocus() const override;
ui::AXPlatformNode* GetFromNodeID(int32_t id) override;
ui::AXPlatformNode* GetFromTreeIDAndNodeID(const ui::AXTreeID& ax_tree_id,
int32_t id) override;
@@ -87,34 +96,59 @@ class ViewAXPlatformNodeDelegate : public ViewAccessibility,
base::Optional<bool> GetTableHasColumnOrRowHeaderNode() const override;
std::vector<int32_t> GetColHeaderNodeIds() const override;
std::vector<int32_t> GetColHeaderNodeIds(int col_index) const override;
+ base::Optional<int32_t> GetCellId(int row_index,
+ int col_index) const override;
bool IsOrderedSetItem() const override;
bool IsOrderedSet() const override;
base::Optional<int> GetPosInSet() const override;
base::Optional<int> GetSetSize() const override;
- void SetPopupFocusOverride() override;
- void EndPopupFocusOverride() override;
- bool IsFocusedForTesting() override;
protected:
explicit ViewAXPlatformNodeDelegate(View* view);
+ friend class ViewAccessibility;
+ // Called by ViewAccessibility::Create immediately after
+ // construction. Used to avoid issues with calling virtual functions
+ // during the constructor.
+ virtual void Init();
+
ui::AXPlatformNode* ax_platform_node() { return ax_platform_node_; }
private:
+ struct ChildWidgetsResult final {
+ ChildWidgetsResult();
+ ChildWidgetsResult(std::vector<Widget*> child_widgets,
+ bool is_tab_modal_showing);
+ ChildWidgetsResult(const ChildWidgetsResult& other);
+ virtual ~ChildWidgetsResult();
+ ChildWidgetsResult& operator=(const ChildWidgetsResult& other);
+
+ std::vector<Widget*> child_widgets;
+
+ // When the focus is within a child widget, |child_widgets| contains only
+ // that widget. Otherwise, |child_widgets| contains all child widgets.
+ //
+ // The former arises when a modal dialog is showing. In order to support the
+ // "read title (NVDAKey+T)" and "read window (NVDAKey+B)" commands in the
+ // NVDA screen reader, we need to hide the rest of the UI from the
+ // accessibility tree for these commands to work properly.
+ bool is_tab_modal_showing = false;
+ };
+
// Uses Views::GetViewsInGroup to find nearby Views in the same group.
// Searches from the View's parent to include siblings within that group.
void GetViewsInGroupForSet(std::vector<View*>* views_in_group) const;
- struct ChildWidgetsResult;
-
+ // If this delegate is attached to the root view, returns all the child
+ // widgets of this view's owning widget.
ChildWidgetsResult GetChildWidgets() const;
- // Gets the real TableView, otherwise nullptr.
+ // Gets the real (non-virtual) TableView, otherwise nullptr.
TableView* GetAncestorTableView() const;
// We own this, but it is reference-counted on some platforms so we can't use
// a unique_ptr. It is destroyed in the destructor.
- ui::AXPlatformNode* ax_platform_node_;
+ ui::AXPlatformNode* ax_platform_node_ = nullptr;
mutable ui::AXNodeData data_;
};
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc
index 3d2fcb72b75..5a240858f12 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc
@@ -8,9 +8,9 @@
#include <memory>
#include <vector>
-#include "base/memory/singleton.h"
-#include "base/scoped_observer.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
+#include "base/no_destructor.h"
+#include "base/scoped_multi_source_observation.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
@@ -51,7 +51,7 @@ Widget* GetWidgetOfParentWindowIncludingTransient(Widget* widget) {
// Return the toplevel widget ancestor of |widget|, including widgets of
// parents of transient windows.
Widget* GetToplevelWidgetIncludingTransientWindows(Widget* widget) {
- widget = widget = widget->GetTopLevelWidget();
+ widget = widget->GetTopLevelWidget();
if (Widget* parent_widget = GetWidgetOfParentWindowIncludingTransient(widget))
return GetToplevelWidgetIncludingTransientWindows(parent_widget);
return widget;
@@ -71,8 +71,9 @@ class AuraLinuxApplication : public ui::AXPlatformNodeDelegateBase,
AuraLinuxApplication& operator=(const AuraLinuxApplication&) = delete;
// Get the single instance of this class.
- static AuraLinuxApplication* GetInstance() {
- return base::Singleton<AuraLinuxApplication>::get();
+ static AuraLinuxApplication& GetInstance() {
+ static base::NoDestructor<AuraLinuxApplication> instance;
+ return *instance;
}
// Called every time we create a new accessibility on a View.
@@ -83,19 +84,19 @@ class AuraLinuxApplication : public ui::AXPlatformNodeDelegateBase,
return;
widget = GetToplevelWidgetIncludingTransientWindows(widget);
- if (base::Contains(widgets_, widget))
+ if (!widget || base::Contains(widgets_, widget))
return;
widgets_.push_back(widget);
- widget_observer_.Add(widget);
+ widget_observations_.AddObservation(widget);
aura::Window* window = widget->GetNativeWindow();
if (window)
- window_observer_.Add(window);
+ window_observations_.AddObservation(window);
}
gfx::NativeViewAccessible GetNativeViewAccessible() override {
- return platform_node_->GetNativeViewAccessible();
+ return ax_platform_node_->GetNativeViewAccessible();
}
const ui::AXUniqueId& GetUniqueId() const override { return unique_id_; }
@@ -103,11 +104,11 @@ class AuraLinuxApplication : public ui::AXPlatformNodeDelegateBase,
// WidgetObserver:
void OnWidgetDestroying(Widget* widget) override {
- widget_observer_.Remove(widget);
+ widget_observations_.RemoveObservation(widget);
aura::Window* window = widget->GetNativeWindow();
- if (window && window_observer_.IsObserving(window))
- window_observer_.Remove(window);
+ if (window && window_observations_.IsObservingSource(window))
+ window_observations_.RemoveObservation(window);
auto iter = std::find(widgets_.begin(), widgets_.end(), widget);
if (iter != widgets_.end())
@@ -130,7 +131,20 @@ class AuraLinuxApplication : public ui::AXPlatformNodeDelegateBase,
// ui::AXPlatformNodeDelegate:
- const ui::AXNodeData& GetData() const override { return data_; }
+ const ui::AXNodeData& GetData() const override {
+ // Despite the fact that the comment above
+ // `views::ViewsDelegate::GetInstance()` says that a nullptr check is not
+ // needed, we discovered that the delegate instance may be nullptr during
+ // test setup. Since the application name does not change, we can set it
+ // only once and avoid setting it every time our accessibility data is
+ // retrieved.
+ if (data_.GetStringAttribute(ax::mojom::StringAttribute::kName).empty() &&
+ ViewsDelegate::GetInstance()) {
+ data_.SetName(ViewsDelegate::GetInstance()->GetApplicationName());
+ }
+
+ return data_;
+ }
int GetChildCount() const override {
return static_cast<int>(widgets_.size());
@@ -145,62 +159,89 @@ class AuraLinuxApplication : public ui::AXPlatformNodeDelegateBase,
return widget->GetRootView()->GetNativeViewAccessible();
}
+ bool IsChildOfLeaf() const override {
+ // TODO(crbug.com/1100047): Needed to prevent endless loops only on Linux
+ // ATK.
+ return false;
+ }
+
private:
- friend struct base::DefaultSingletonTraits<AuraLinuxApplication>;
+ friend class base::NoDestructor<AuraLinuxApplication>;
AuraLinuxApplication() {
+ data_.id = unique_id_.Get();
data_.role = ax::mojom::Role::kApplication;
- platform_node_ = ui::AXPlatformNode::Create(this);
- data_.AddStringAttribute(
- ax::mojom::StringAttribute::kName,
- ViewsDelegate::GetInstance()->GetApplicationName());
- ui::AXPlatformNodeAuraLinux::SetApplication(platform_node_);
+ data_.AddState(ax::mojom::State::kFocusable);
+ ax_platform_node_ = ui::AXPlatformNode::Create(this);
+ DCHECK(ax_platform_node_);
+ ui::AXPlatformNodeAuraLinux::SetApplication(ax_platform_node_);
ui::AXPlatformNodeAuraLinux::StaticInitialize();
}
~AuraLinuxApplication() override {
- platform_node_->Destroy();
- platform_node_ = nullptr;
+ ax_platform_node_->Destroy();
+ ax_platform_node_ = nullptr;
}
- ui::AXPlatformNode* platform_node_;
- ui::AXNodeData data_;
+ // TODO(nektar): Make this into a const pointer so that it can't be set
+ // outside the class's constructor.
+ ui::AXPlatformNode* ax_platform_node_;
ui::AXUniqueId unique_id_;
+ mutable ui::AXNodeData data_;
std::vector<Widget*> widgets_;
- ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this};
- ScopedObserver<aura::Window, aura::WindowObserver> window_observer_{this};
+ base::ScopedMultiSourceObservation<Widget, WidgetObserver>
+ widget_observations_{this};
+ base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
+ window_observations_{this};
};
} // namespace
// static
std::unique_ptr<ViewAccessibility> ViewAccessibility::Create(View* view) {
- AuraLinuxApplication::GetInstance()->RegisterWidget(view->GetWidget());
- return std::make_unique<ViewAXPlatformNodeDelegateAuraLinux>(view);
+ AuraLinuxApplication::GetInstance().RegisterWidget(view->GetWidget());
+
+ auto result = std::make_unique<ViewAXPlatformNodeDelegateAuraLinux>(view);
+ result->Init();
+ return result;
}
ViewAXPlatformNodeDelegateAuraLinux::ViewAXPlatformNodeDelegateAuraLinux(
View* view)
- : ViewAXPlatformNodeDelegate(view) {
- view->AddObserver(this);
+ : ViewAXPlatformNodeDelegate(view) {}
+
+void ViewAXPlatformNodeDelegateAuraLinux::Init() {
+ ViewAXPlatformNodeDelegate::Init();
+
+ view_observation_.Observe(view());
+}
+
+ViewAXPlatformNodeDelegateAuraLinux::~ViewAXPlatformNodeDelegateAuraLinux() {
+ view_observation_.Reset();
}
gfx::NativeViewAccessible ViewAXPlatformNodeDelegateAuraLinux::GetParent() {
if (gfx::NativeViewAccessible parent =
- ViewAXPlatformNodeDelegate::GetParent())
+ ViewAXPlatformNodeDelegate::GetParent()) {
return parent;
+ }
Widget* parent_widget =
GetWidgetOfParentWindowIncludingTransient(view()->GetWidget());
if (parent_widget)
return parent_widget->GetRootView()->GetNativeViewAccessible();
- return AuraLinuxApplication::GetInstance()->GetNativeViewAccessible();
+ return AuraLinuxApplication::GetInstance().GetNativeViewAccessible();
+}
+
+bool ViewAXPlatformNodeDelegateAuraLinux::IsChildOfLeaf() const {
+ // TODO(crbug.com/1100047): Needed to prevent endless loops only on Linux ATK.
+ return false;
}
void ViewAXPlatformNodeDelegateAuraLinux::OnViewHierarchyChanged(
- views::View* observed_view,
- const views::ViewHierarchyChangedDetails& details) {
+ View* observed_view,
+ const ViewHierarchyChangedDetails& details) {
if (view() != details.child || !details.is_add)
return;
static_cast<ui::AXPlatformNodeAuraLinux*>(ax_platform_node())
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.h b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.h
index cc5cbf179ed..efa378af743 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.h
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.h
@@ -5,6 +5,7 @@
#ifndef UI_VIEWS_ACCESSIBILITY_VIEW_AX_PLATFORM_NODE_DELEGATE_AURALINUX_H_
#define UI_VIEWS_ACCESSIBILITY_VIEW_AX_PLATFORM_NODE_DELEGATE_AURALINUX_H_
+#include "base/scoped_observation.h"
#include "ui/views/accessibility/view_ax_platform_node_delegate.h"
#include "ui/views/view_observer.h"
@@ -13,21 +14,27 @@ namespace views {
class View;
class ViewAXPlatformNodeDelegateAuraLinux : public ViewAXPlatformNodeDelegate,
- public views::ViewObserver {
+ public ViewObserver {
public:
explicit ViewAXPlatformNodeDelegateAuraLinux(View* view);
ViewAXPlatformNodeDelegateAuraLinux(
const ViewAXPlatformNodeDelegateAuraLinux&) = delete;
ViewAXPlatformNodeDelegateAuraLinux& operator=(
const ViewAXPlatformNodeDelegateAuraLinux&) = delete;
+ ~ViewAXPlatformNodeDelegateAuraLinux() override;
+
+ void Init() override;
// |ViewAXPlatformNodeDelegate| overrides:
gfx::NativeViewAccessible GetParent() override;
+ bool IsChildOfLeaf() const override;
private:
void OnViewHierarchyChanged(
- views::View* observed_view,
- const views::ViewHierarchyChangedDetails& details) override;
+ View* observed_view,
+ const ViewHierarchyChangedDetails& details) override;
+
+ base::ScopedObservation<View, ViewObserver> view_observation_{this};
};
} // namespace views
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm
index 75e00918bc6..6e6cb3b3e64 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm
@@ -6,6 +6,7 @@
#include <memory>
+#include "ui/accessibility/platform/ax_platform_node_mac.h"
#include "ui/views/cocoa/native_widget_mac_ns_window_host.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -14,7 +15,9 @@ namespace views {
// static
std::unique_ptr<ViewAccessibility> ViewAccessibility::Create(View* view) {
- return std::make_unique<ViewAXPlatformNodeDelegateMac>(view);
+ auto result = std::make_unique<ViewAXPlatformNodeDelegateMac>(view);
+ result->Init();
+ return result;
}
ViewAXPlatformNodeDelegateMac::ViewAXPlatformNodeDelegateMac(View* view)
@@ -37,7 +40,7 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegateMac::GetNSWindow() {
gfx::NativeViewAccessible ViewAXPlatformNodeDelegateMac::GetParent() {
if (view()->parent())
- return view()->parent()->GetNativeViewAccessible();
+ return ViewAXPlatformNodeDelegate::GetParent();
auto* widget = view()->GetWidget();
if (!widget)
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
index 454a41aa8f2..7c0f11eea2f 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
@@ -5,15 +5,19 @@
#include "ui/views/accessibility/view_ax_platform_node_delegate.h"
#include <memory>
+#include <string>
#include <utility>
#include <vector>
#include "base/strings/utf_string_conversions.h"
+#include "base/test/gtest_util.h"
+#include "build/build_config.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/accessibility/platform/ax_platform_node_base.h"
+#include "ui/base/models/table_model.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size.h"
@@ -24,6 +28,11 @@
#include "ui/views/accessibility/ax_widget_obj_wrapper.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/label.h"
+#include "ui/views/controls/menu/submenu_view.h"
+#include "ui/views/controls/menu/test_menu_item_view.h"
+#include "ui/views/controls/scroll_view.h"
+#include "ui/views/controls/table/table_view.h"
+#include "ui/views/test/menu_test_utils.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
@@ -64,6 +73,34 @@ class TestAXEventObserver : public AXEventObserver {
} // namespace
+class TestTableModel : public ui::TableModel {
+ public:
+ TestTableModel() = default;
+
+ // ui::TableModel:
+ int RowCount() override { return 10; }
+
+ base::string16 GetText(int row, int column_id) override {
+ if (row == -1)
+ return base::string16();
+
+ const char* const cells[5][4] = {
+ {"Orange", "Orange", "South america", "$5"},
+ {"Apple", "Green", "Canada", "$3"},
+ {"Blue berries", "Blue", "Mexico", "$10.3"},
+ {"Strawberries", "Red", "California", "$7"},
+ {"Cantaloupe", "Orange", "South america", "$5"},
+ };
+
+ return base::ASCIIToUTF16(cells[row % 5][column_id]);
+ }
+
+ void SetObserver(ui::TableModelObserver* observer) override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestTableModel);
+};
+
class ViewAXPlatformNodeDelegateTest : public ViewsTestBase {
public:
ViewAXPlatformNodeDelegateTest() = default;
@@ -170,18 +207,133 @@ class ViewAXPlatformNodeDelegateTest : public ViewsTestBase {
Label* label_ = nullptr;
};
-TEST_F(ViewAXPlatformNodeDelegateTest, RoleShouldMatch) {
+class ViewAXPlatformNodeDelegateTableTest
+ : public ViewAXPlatformNodeDelegateTest {
+ public:
+ void SetUp() override {
+ ViewAXPlatformNodeDelegateTest::SetUp();
+
+ std::vector<ui::TableColumn> columns;
+ columns.push_back(TestTableColumn(0, "Fruit"));
+ columns.push_back(TestTableColumn(1, "Color"));
+ columns.push_back(TestTableColumn(2, "Origin"));
+ columns.push_back(TestTableColumn(3, "Price"));
+
+ model_ = std::make_unique<TestTableModel>();
+ auto table =
+ std::make_unique<TableView>(model_.get(), columns, TEXT_ONLY, true);
+ table_ = table.get();
+ widget_->GetContentsView()->AddChildView(
+ TableView::CreateScrollViewWithTable(std::move(table)));
+ }
+
+ ui::TableColumn TestTableColumn(int id, const std::string& title) {
+ ui::TableColumn column;
+ column.id = id;
+ column.title = base::ASCIIToUTF16(title.c_str());
+ column.sortable = true;
+ return column;
+ }
+
+ ViewAXPlatformNodeDelegate* table_accessibility() {
+ return view_accessibility(table_);
+ }
+
+ private:
+ std::unique_ptr<TestTableModel> model_;
+ TableView* table_ = nullptr; // Owned by parent.
+};
+
+class ViewAXPlatformNodeDelegateMenuTest
+ : public ViewAXPlatformNodeDelegateTest {
+ public:
+ void SetUp() override {
+ ViewAXPlatformNodeDelegateTest::SetUp();
+
+ owner_ = std::make_unique<Widget>();
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ owner_->Init(std::move(params));
+ owner_->Show();
+
+ menu_delegate_ = std::make_unique<TestMenuDelegate>();
+ menu_ = new views::TestMenuItemView(menu_delegate_.get());
+ runner_ = std::make_unique<MenuRunner>(menu_, 0);
+
+ menu_->AppendMenuItemImpl(0, base::ASCIIToUTF16("normal"), gfx::ImageSkia(),
+ MenuItemView::Type::kNormal);
+ menu_->AppendMenuItemImpl(1, base::ASCIIToUTF16("submenu"),
+ gfx::ImageSkia(), MenuItemView::Type::kSubMenu);
+ menu_->AppendMenuItemImpl(2, base::ASCIIToUTF16("actionable"),
+ gfx::ImageSkia(),
+ MenuItemView::Type::kActionableSubMenu);
+ menu_->AppendMenuItemImpl(3, base::ASCIIToUTF16("checkbox"),
+ gfx::ImageSkia(), MenuItemView::Type::kCheckbox);
+ menu_->AppendMenuItemImpl(4, base::ASCIIToUTF16("radio"), gfx::ImageSkia(),
+ MenuItemView::Type::kRadio);
+ menu_->AppendMenuItemImpl(5, base::ASCIIToUTF16("separator"),
+ gfx::ImageSkia(), MenuItemView::Type::kSeparator);
+ menu_->AppendMenuItemImpl(6, base::ASCIIToUTF16("highlighted"),
+ gfx::ImageSkia(),
+ MenuItemView::Type::kHighlighted);
+ menu_->AppendMenuItemImpl(7, base::ASCIIToUTF16("title"), gfx::ImageSkia(),
+ MenuItemView::Type::kTitle);
+
+ submenu_ = menu_->GetSubmenu();
+ submenu_->GetMenuItemAt(3)->SetSelected(true);
+ }
+
+ void TearDown() override {
+ if (owner_)
+ owner_->CloseNow();
+ ViewAXPlatformNodeDelegateTest::TearDown();
+ }
+
+ void RunMenu() {
+ runner_.get()->RunMenuAt(owner_.get(), nullptr, gfx::Rect(),
+ MenuAnchorPosition::kTopLeft,
+ ui::MENU_SOURCE_NONE);
+ }
+
+ ViewAXPlatformNodeDelegate* submenu_accessibility() {
+ return view_accessibility(submenu_);
+ }
+
+ private:
+ // Owned by runner_.
+ views::TestMenuItemView* menu_ = nullptr;
+
+ SubmenuView* submenu_ = nullptr;
+ std::unique_ptr<TestMenuDelegate> menu_delegate_;
+ std::unique_ptr<MenuRunner> runner_;
+ std::unique_ptr<Widget> owner_;
+};
+
+TEST_F(ViewAXPlatformNodeDelegateTest, FocusBehaviorShouldAffectIgnoredState) {
EXPECT_EQ(ax::mojom::Role::kButton, button_accessibility()->GetData().role);
+ EXPECT_FALSE(
+ button_accessibility()->GetData().HasState(ax::mojom::State::kIgnored));
+
// Since the label is a subview of |button_|, and the button is keyboard
- // focusable, the label is assumed to form part of the button and not have a
- // role of its own.
- EXPECT_EQ(ax::mojom::Role::kIgnored, label_accessibility()->GetData().role);
+ // focusable, the label is assumed to form part of the button and should be
+ // ignored.
+ EXPECT_EQ(ax::mojom::Role::kStaticText,
+ label_accessibility()->GetData().role);
+ EXPECT_TRUE(
+ label_accessibility()->GetData().HasState(ax::mojom::State::kIgnored));
+
// This will happen for all potentially keyboard-focusable Views with
// non-keyboard-focusable children, so if we make the button unfocusable, the
- // label will be allowed to have its own role again.
+ // label will not be ignored any more.
button_->SetFocusBehavior(View::FocusBehavior::NEVER);
+
+ EXPECT_EQ(ax::mojom::Role::kButton, button_accessibility()->GetData().role);
+ EXPECT_FALSE(
+ button_accessibility()->GetData().HasState(ax::mojom::State::kIgnored));
EXPECT_EQ(ax::mojom::Role::kStaticText,
label_accessibility()->GetData().role);
+ EXPECT_FALSE(
+ label_accessibility()->GetData().HasState(ax::mojom::State::kIgnored));
}
TEST_F(ViewAXPlatformNodeDelegateTest, BoundsShouldMatch) {
@@ -199,21 +351,25 @@ TEST_F(ViewAXPlatformNodeDelegateTest, LabelIsChildOfButton) {
// be either before or after the label, which complicates correctness testing.
button_->SetInstallFocusRingOnFocus(false);
- // |button_| is focusable, so |label_| (as its child) should be ignored.
+ // Since the label is a subview of |button_|, and the button is keyboard
+ // focusable, the label is assumed to form part of the button and should be
+ // ignored, i.e. not visible in the accessibility tree that is available to
+ // platform APIs.
EXPECT_NE(View::FocusBehavior::NEVER, button_->GetFocusBehavior());
- EXPECT_EQ(1, button_accessibility()->GetChildCount());
- EXPECT_EQ(button_->GetNativeViewAccessible(),
- label_accessibility()->GetParent());
- EXPECT_EQ(ax::mojom::Role::kIgnored, label_accessibility()->GetData().role);
+ EXPECT_EQ(0, button_accessibility()->GetChildCount());
+ EXPECT_EQ(ax::mojom::Role::kStaticText,
+ label_accessibility()->GetData().role);
- // If |button_| is no longer focusable, |label_| should show up again.
+ // Modify the focus behavior to make the button unfocusable, and verify that
+ // the label is now a child of the button.
button_->SetFocusBehavior(View::FocusBehavior::NEVER);
EXPECT_EQ(1, button_accessibility()->GetChildCount());
EXPECT_EQ(label_->GetNativeViewAccessible(),
button_accessibility()->ChildAtIndex(0));
EXPECT_EQ(button_->GetNativeViewAccessible(),
label_accessibility()->GetParent());
- EXPECT_NE(ax::mojom::Role::kIgnored, label_accessibility()->GetData().role);
+ EXPECT_EQ(ax::mojom::Role::kStaticText,
+ label_accessibility()->GetData().role);
}
// Verify Views with invisible ancestors have ax::mojom::State::kInvisible.
@@ -230,7 +386,7 @@ TEST_F(ViewAXPlatformNodeDelegateTest, InvisibleViews) {
label_accessibility()->GetData().HasState(ax::mojom::State::kInvisible));
}
-TEST_F(ViewAXPlatformNodeDelegateTest, WritableFocus) {
+TEST_F(ViewAXPlatformNodeDelegateTest, SetFocus) {
// Make |button_| focusable, and focus/unfocus it via
// ViewAXPlatformNodeDelegate.
button_->SetFocusBehavior(View::FocusBehavior::ALWAYS);
@@ -244,9 +400,18 @@ TEST_F(ViewAXPlatformNodeDelegateTest, WritableFocus) {
EXPECT_EQ(nullptr, button_->GetFocusManager()->GetFocusedView());
EXPECT_EQ(nullptr, button_accessibility()->GetFocus());
- // If not focusable at all, SetFocused() should return false.
+ // If the button is not focusable at all, or if it is disabled for
+ // accessibility, SetFocused() should return false.
button_->SetEnabled(false);
EXPECT_FALSE(SetFocused(button_accessibility(), true));
+ button_->SetEnabled(true);
+
+ button_accessibility()->OverrideIsEnabled(false);
+ EXPECT_FALSE(SetFocused(button_accessibility(), true));
+
+ EXPECT_FALSE(button_accessibility()->IsAccessibilityFocusable());
+ button_accessibility()->OverrideIsEnabled(true);
+ EXPECT_TRUE(button_accessibility()->IsAccessibilityFocusable());
}
TEST_F(ViewAXPlatformNodeDelegateTest, GetAuthorUniqueIdDefault) {
@@ -353,35 +518,293 @@ TEST_F(ViewAXPlatformNodeDelegateTest, SetSizeAndPosition) {
EXPECT_EQ(view_accessibility(group_ids[4])->GetPosInSet(), 1);
}
-TEST_F(ViewAXPlatformNodeDelegateTest, Navigation) {
- View::Views view_ids = SetUpExtraViews();
+TEST_F(ViewAXPlatformNodeDelegateTest, TreeNavigation) {
+ // Adds one extra parent view with four child views to our widget. The parent
+ // view is added as the next sibling of the already present button view.
+ //
+ // Widget
+ // ++NonClientView
+ // ++NonClientFrameView
+ // ++Button
+ // ++++Label
+ // 0 = ++ParentView
+ // 1 = ++++ChildView1
+ // 2 = ++++ChildView2
+ // 3 = ++++ChildView3
+ // 4 = ++++ChildView4
+ View::Views extra_views = SetUpExtraViews();
+ ViewAXPlatformNodeDelegate* parent_view = view_accessibility(extra_views[0]);
+ ViewAXPlatformNodeDelegate* child_view_1 = view_accessibility(extra_views[1]);
+ ViewAXPlatformNodeDelegate* child_view_2 = view_accessibility(extra_views[2]);
+ ViewAXPlatformNodeDelegate* child_view_3 = view_accessibility(extra_views[3]);
+ ViewAXPlatformNodeDelegate* child_view_4 = view_accessibility(extra_views[4]);
+
+ EXPECT_EQ(view_accessibility(widget_->GetContentsView())->GetNativeObject(),
+ parent_view->GetParent());
+ EXPECT_EQ(4, parent_view->GetChildCount());
+
+ EXPECT_EQ(2, button_accessibility()->GetIndexInParent());
+ EXPECT_EQ(3, parent_view->GetIndexInParent());
+
+ EXPECT_EQ(child_view_1->GetNativeObject(), parent_view->ChildAtIndex(0));
+ EXPECT_EQ(child_view_2->GetNativeObject(), parent_view->ChildAtIndex(1));
+ EXPECT_EQ(child_view_3->GetNativeObject(), parent_view->ChildAtIndex(2));
+ EXPECT_EQ(child_view_4->GetNativeObject(), parent_view->ChildAtIndex(3));
+
+ EXPECT_EQ(nullptr, parent_view->GetNextSibling());
+ EXPECT_EQ(button_accessibility()->GetNativeObject(),
+ parent_view->GetPreviousSibling());
+
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_1->GetParent());
+ EXPECT_EQ(0, child_view_1->GetChildCount());
+ EXPECT_EQ(0, child_view_1->GetIndexInParent());
+ EXPECT_EQ(child_view_2->GetNativeObject(), child_view_1->GetNextSibling());
+ EXPECT_EQ(nullptr, child_view_1->GetPreviousSibling());
+
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_2->GetParent());
+ EXPECT_EQ(0, child_view_2->GetChildCount());
+ EXPECT_EQ(1, child_view_2->GetIndexInParent());
+ EXPECT_EQ(child_view_3->GetNativeObject(), child_view_2->GetNextSibling());
+ EXPECT_EQ(child_view_1->GetNativeObject(),
+ child_view_2->GetPreviousSibling());
+
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_3->GetParent());
+ EXPECT_EQ(0, child_view_3->GetChildCount());
+ EXPECT_EQ(2, child_view_3->GetIndexInParent());
+ EXPECT_EQ(child_view_4->GetNativeObject(), child_view_3->GetNextSibling());
+ EXPECT_EQ(child_view_2->GetNativeObject(),
+ child_view_3->GetPreviousSibling());
+
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_4->GetParent());
+ EXPECT_EQ(0, child_view_4->GetChildCount());
+ EXPECT_EQ(3, child_view_4->GetIndexInParent());
+ EXPECT_EQ(nullptr, child_view_4->GetNextSibling());
+ EXPECT_EQ(child_view_3->GetNativeObject(),
+ child_view_4->GetPreviousSibling());
+}
+
+TEST_F(ViewAXPlatformNodeDelegateTest, TreeNavigationWithLeafViews) {
+ // Adds one extra parent view with four child views to our widget. The parent
+ // view is added as the next sibling of the already present button view.
+ //
+ // Widget
+ // ++NonClientView
+ // ++NonClientFrameView
+ // ++Button
+ // ++++Label
+ // 0 = ++ParentView
+ // 1 = ++++ChildView1
+ // 2 = ++++ChildView2
+ // 3 = ++++ChildView3
+ // 4 = ++++ChildView4
+ View::Views extra_views = SetUpExtraViews();
+ ViewAXPlatformNodeDelegate* contents_view =
+ view_accessibility(widget_->GetContentsView());
+ ViewAXPlatformNodeDelegate* parent_view = view_accessibility(extra_views[0]);
+ ViewAXPlatformNodeDelegate* child_view_1 = view_accessibility(extra_views[1]);
+ ViewAXPlatformNodeDelegate* child_view_2 = view_accessibility(extra_views[2]);
+ ViewAXPlatformNodeDelegate* child_view_3 = view_accessibility(extra_views[3]);
+ ViewAXPlatformNodeDelegate* child_view_4 = view_accessibility(extra_views[4]);
+
+ // Mark the parent view and the second child view as leafs. This should hide
+ // all four children, not only the second child. It should not hide the parent
+ // view. In this context, "hide" means that these views will be ignored (be
+ // invisible) by platform accessibility APIs.
+ parent_view->OverrideIsLeaf(true);
+ child_view_2->OverrideIsLeaf(true);
+
+ EXPECT_EQ(4, contents_view->GetChildCount());
+ EXPECT_EQ(contents_view->GetNativeObject(), parent_view->GetParent());
+ EXPECT_EQ(0, parent_view->GetChildCount());
+
+ EXPECT_EQ(2, button_accessibility()->GetIndexInParent());
+ EXPECT_EQ(3, parent_view->GetIndexInParent());
+
+ EXPECT_FALSE(contents_view->IsIgnored());
+ EXPECT_FALSE(parent_view->IsIgnored());
+ EXPECT_TRUE(child_view_1->IsIgnored());
+ EXPECT_TRUE(child_view_2->IsIgnored());
+ EXPECT_TRUE(child_view_3->IsIgnored());
+ EXPECT_TRUE(child_view_4->IsIgnored());
+
+ EXPECT_FALSE(contents_view->IsLeaf());
+ EXPECT_TRUE(parent_view->IsLeaf());
+
+ EXPECT_FALSE(contents_view->IsChildOfLeaf());
+ EXPECT_FALSE(parent_view->IsChildOfLeaf());
+#if !BUILDFLAG(USE_ATK)
+ // TODO(crbug.com/1100047): IsChildOfLeaf always returns false on Linux.
+ EXPECT_TRUE(child_view_1->IsChildOfLeaf());
+ EXPECT_TRUE(child_view_2->IsChildOfLeaf());
+ EXPECT_TRUE(child_view_3->IsChildOfLeaf());
+ EXPECT_TRUE(child_view_4->IsChildOfLeaf());
+#endif // !BUILDFLAG(USE_ATK)
+
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_1->GetParent());
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_2->GetParent());
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_3->GetParent());
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_4->GetParent());
+
+ // Try unhiding the parent view's descendants. Nothing should be hidden any
+ // more. The second child has no descendants so marking it as a leaf should
+ // have no effect.
+ parent_view->OverrideIsLeaf(false);
+
+ EXPECT_EQ(4, contents_view->GetChildCount());
+ EXPECT_EQ(contents_view->GetNativeObject(), parent_view->GetParent());
+ EXPECT_EQ(4, parent_view->GetChildCount());
+
+ EXPECT_EQ(2, button_accessibility()->GetIndexInParent());
+ EXPECT_EQ(3, parent_view->GetIndexInParent());
+
+ EXPECT_FALSE(contents_view->IsIgnored());
+ EXPECT_FALSE(parent_view->IsIgnored());
+ EXPECT_FALSE(child_view_1->IsIgnored());
+ EXPECT_FALSE(child_view_2->IsIgnored());
+ EXPECT_FALSE(child_view_3->IsIgnored());
+ EXPECT_FALSE(child_view_4->IsIgnored());
+
+ EXPECT_FALSE(contents_view->IsLeaf());
+ EXPECT_FALSE(parent_view->IsLeaf());
+ EXPECT_TRUE(child_view_1->IsLeaf());
+ EXPECT_TRUE(child_view_2->IsLeaf());
+ EXPECT_TRUE(child_view_3->IsLeaf());
+ EXPECT_TRUE(child_view_4->IsLeaf());
+
+ EXPECT_FALSE(contents_view->IsChildOfLeaf());
+ EXPECT_FALSE(parent_view->IsChildOfLeaf());
+ EXPECT_FALSE(child_view_1->IsChildOfLeaf());
+ EXPECT_FALSE(child_view_2->IsChildOfLeaf());
+ EXPECT_FALSE(child_view_3->IsChildOfLeaf());
+ EXPECT_FALSE(child_view_4->IsChildOfLeaf());
+
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_1->GetParent());
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_2->GetParent());
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_3->GetParent());
+ EXPECT_EQ(parent_view->GetNativeObject(), child_view_4->GetParent());
+
+ EXPECT_EQ(child_view_1->GetNativeObject(), parent_view->ChildAtIndex(0));
+ EXPECT_EQ(child_view_2->GetNativeObject(), parent_view->ChildAtIndex(1));
+ EXPECT_EQ(child_view_3->GetNativeObject(), parent_view->ChildAtIndex(2));
+ EXPECT_EQ(child_view_4->GetNativeObject(), parent_view->ChildAtIndex(3));
+}
- EXPECT_EQ(view_accessibility(view_ids[0])->GetNextSibling(), nullptr);
- EXPECT_EQ(view_accessibility(view_ids[0])->GetPreviousSibling(),
- view_accessibility(button_)->GetNativeObject());
- EXPECT_EQ(view_accessibility(view_ids[0])->GetIndexInParent(), 3);
-
- EXPECT_EQ(view_accessibility(view_ids[1])->GetNextSibling(),
- view_accessibility(view_ids[2])->GetNativeObject());
- EXPECT_EQ(view_accessibility(view_ids[1])->GetPreviousSibling(), nullptr);
- EXPECT_EQ(view_accessibility(view_ids[1])->GetIndexInParent(), 0);
-
- EXPECT_EQ(view_accessibility(view_ids[2])->GetNextSibling(),
- view_accessibility(view_ids[3])->GetNativeObject());
- EXPECT_EQ(view_accessibility(view_ids[2])->GetPreviousSibling(),
- view_accessibility(view_ids[1])->GetNativeObject());
- EXPECT_EQ(view_accessibility(view_ids[2])->GetIndexInParent(), 1);
-
- EXPECT_EQ(view_accessibility(view_ids[3])->GetNextSibling(),
- view_accessibility(view_ids[4])->GetNativeObject());
- EXPECT_EQ(view_accessibility(view_ids[3])->GetPreviousSibling(),
- view_accessibility(view_ids[2])->GetNativeObject());
- EXPECT_EQ(view_accessibility(view_ids[3])->GetIndexInParent(), 2);
-
- EXPECT_EQ(view_accessibility(view_ids[4])->GetNextSibling(), nullptr);
- EXPECT_EQ(view_accessibility(view_ids[4])->GetPreviousSibling(),
- view_accessibility(view_ids[3])->GetNativeObject());
- EXPECT_EQ(view_accessibility(view_ids[4])->GetIndexInParent(), 3);
+TEST_F(ViewAXPlatformNodeDelegateTest, TreeNavigationWithIgnoredViews) {
+ // Adds one extra parent view with four child views to our widget. The parent
+ // view is added as the next sibling of the already present button view.
+ //
+ // Widget
+ // ++NonClientView
+ // ++NonClientFrameView
+ // ++Button
+ // ++++Label
+ // 0 = ++ParentView
+ // 1 = ++++ChildView1
+ // 2 = ++++ChildView2
+ // 3 = ++++ChildView3
+ // 4 = ++++ChildView4
+ View::Views extra_views = SetUpExtraViews();
+ ViewAXPlatformNodeDelegate* contents_view =
+ view_accessibility(widget_->GetContentsView());
+ ViewAXPlatformNodeDelegate* parent_view = view_accessibility(extra_views[0]);
+ ViewAXPlatformNodeDelegate* child_view_1 = view_accessibility(extra_views[1]);
+ ViewAXPlatformNodeDelegate* child_view_2 = view_accessibility(extra_views[2]);
+ ViewAXPlatformNodeDelegate* child_view_3 = view_accessibility(extra_views[3]);
+ ViewAXPlatformNodeDelegate* child_view_4 = view_accessibility(extra_views[4]);
+
+ // Mark the parent view and the second child view as ignored.
+ parent_view->OverrideIsIgnored(true);
+ child_view_2->OverrideIsIgnored(true);
+
+ EXPECT_EQ(contents_view->GetNativeObject(), parent_view->GetParent());
+ EXPECT_EQ(3, parent_view->GetChildCount());
+
+ EXPECT_EQ(2, button_accessibility()->GetIndexInParent());
+ EXPECT_EQ(-1, parent_view->GetIndexInParent());
+
+ EXPECT_EQ(child_view_1->GetNativeObject(), parent_view->ChildAtIndex(0));
+ EXPECT_EQ(child_view_3->GetNativeObject(), parent_view->ChildAtIndex(1));
+ EXPECT_EQ(child_view_4->GetNativeObject(), parent_view->ChildAtIndex(2));
+
+ EXPECT_EQ(button_accessibility()->GetNativeObject(),
+ contents_view->ChildAtIndex(2));
+ EXPECT_EQ(child_view_1->GetNativeObject(), contents_view->ChildAtIndex(3));
+ EXPECT_EQ(child_view_3->GetNativeObject(), contents_view->ChildAtIndex(4));
+ EXPECT_EQ(child_view_4->GetNativeObject(), contents_view->ChildAtIndex(5));
+
+ EXPECT_EQ(nullptr, parent_view->GetNextSibling());
+ EXPECT_EQ(nullptr, parent_view->GetPreviousSibling());
+
+ EXPECT_EQ(contents_view->GetNativeObject(), child_view_1->GetParent());
+ EXPECT_EQ(0, child_view_1->GetChildCount());
+ EXPECT_EQ(3, child_view_1->GetIndexInParent());
+ EXPECT_EQ(child_view_3->GetNativeObject(), child_view_1->GetNextSibling());
+ EXPECT_EQ(button_accessibility()->GetNativeObject(),
+ child_view_1->GetPreviousSibling());
+
+ EXPECT_EQ(contents_view->GetNativeObject(), child_view_2->GetParent());
+ EXPECT_EQ(0, child_view_2->GetChildCount());
+ EXPECT_EQ(-1, child_view_2->GetIndexInParent());
+ EXPECT_EQ(nullptr, child_view_2->GetNextSibling());
+ EXPECT_EQ(nullptr, child_view_2->GetPreviousSibling());
+
+ EXPECT_EQ(contents_view->GetNativeObject(), child_view_3->GetParent());
+ EXPECT_EQ(0, child_view_3->GetChildCount());
+ EXPECT_EQ(4, child_view_3->GetIndexInParent());
+ EXPECT_EQ(child_view_4->GetNativeObject(), child_view_3->GetNextSibling());
+ EXPECT_EQ(child_view_1->GetNativeObject(),
+ child_view_3->GetPreviousSibling());
+
+ EXPECT_EQ(contents_view->GetNativeObject(), child_view_4->GetParent());
+ EXPECT_EQ(0, child_view_4->GetChildCount());
+ EXPECT_EQ(5, child_view_4->GetIndexInParent());
+ EXPECT_EQ(nullptr, child_view_4->GetNextSibling());
+ EXPECT_EQ(child_view_3->GetNativeObject(),
+ child_view_4->GetPreviousSibling());
+}
+
+TEST_F(ViewAXPlatformNodeDelegateTest, OverrideIsEnabled) {
+ // Initially, the button should be enabled.
+ EXPECT_TRUE(button_accessibility()->IsAccessibilityEnabled());
+ EXPECT_TRUE(button_accessibility()->IsAccessibilityFocusable());
+
+ button_->SetEnabled(false);
+ EXPECT_FALSE(button_accessibility()->IsAccessibilityEnabled());
+ EXPECT_FALSE(button_accessibility()->IsAccessibilityFocusable());
+
+ button_->SetEnabled(true);
+ EXPECT_TRUE(button_accessibility()->IsAccessibilityEnabled());
+ EXPECT_TRUE(button_accessibility()->IsAccessibilityFocusable());
+
+ // `ViewAccessibility::OverrideIsEnabled` should have priority over
+ // `View::SetEnabled`.
+ button_accessibility()->OverrideIsEnabled(false);
+ EXPECT_FALSE(button_accessibility()->IsAccessibilityEnabled());
+ EXPECT_FALSE(button_accessibility()->IsAccessibilityFocusable());
+
+ button_->SetEnabled(false);
+ EXPECT_FALSE(button_accessibility()->IsAccessibilityEnabled());
+ EXPECT_FALSE(button_accessibility()->IsAccessibilityFocusable());
+ button_accessibility()->OverrideIsEnabled(true);
+ EXPECT_TRUE(button_accessibility()->IsAccessibilityEnabled());
+ EXPECT_TRUE(button_accessibility()->IsAccessibilityFocusable());
+
+ // Initially, the label should be enabled. It should never be focusable
+ // because it is not an interactive control like the button.
+ EXPECT_TRUE(label_accessibility()->IsAccessibilityEnabled());
+ EXPECT_FALSE(label_accessibility()->IsAccessibilityFocusable());
+
+ label_->SetEnabled(false);
+ EXPECT_FALSE(label_accessibility()->IsAccessibilityEnabled());
+ EXPECT_FALSE(label_accessibility()->IsAccessibilityFocusable());
+
+ label_accessibility()->OverrideIsEnabled(true);
+ EXPECT_TRUE(label_accessibility()->IsAccessibilityEnabled());
+ EXPECT_FALSE(label_accessibility()->IsAccessibilityFocusable());
+
+ label_accessibility()->OverrideIsEnabled(false);
+ EXPECT_FALSE(label_accessibility()->IsAccessibilityEnabled());
+ EXPECT_FALSE(label_accessibility()->IsAccessibilityFocusable());
}
TEST_F(ViewAXPlatformNodeDelegateTest, OverrideHasPopup) {
@@ -425,6 +848,177 @@ TEST_F(ViewAXPlatformNodeDelegateTest, FocusOnMenuClose) {
button_accessibility()->GetFocus());
}
+TEST_F(ViewAXPlatformNodeDelegateTableTest, TableHasHeader) {
+ EXPECT_TRUE(table_accessibility()->GetTableHasColumnOrRowHeaderNode());
+ EXPECT_EQ(size_t{4}, table_accessibility()->GetColHeaderNodeIds().size());
+ EXPECT_TRUE(table_accessibility()->GetColHeaderNodeIds(5).empty());
+}
+
+TEST_F(ViewAXPlatformNodeDelegateTableTest, TableHasCell) {
+ EXPECT_NE(base::nullopt, table_accessibility()->GetCellId(0, 0));
+ EXPECT_NE(base::nullopt, table_accessibility()->GetCellId(0, 3));
+ EXPECT_NE(base::nullopt, table_accessibility()->GetCellId(9, 3));
+ EXPECT_DCHECK_DEATH(table_accessibility()->GetCellId(-1, 0));
+ EXPECT_DCHECK_DEATH(table_accessibility()->GetCellId(0, -1));
+ EXPECT_DCHECK_DEATH(table_accessibility()->GetCellId(10, 0));
+ EXPECT_DCHECK_DEATH(table_accessibility()->GetCellId(0, 4));
+}
+
+TEST_F(ViewAXPlatformNodeDelegateMenuTest, MenuTest) {
+ RunMenu();
+
+ ViewAXPlatformNodeDelegate* submenu = submenu_accessibility();
+ EXPECT_FALSE(submenu->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_EQ(submenu->GetChildCount(), 8);
+ EXPECT_EQ(submenu->GetData().role, ax::mojom::Role::kMenu);
+ EXPECT_EQ(submenu->GetData().GetHasPopup(), ax::mojom::HasPopup::kMenu);
+
+ auto items = submenu->view()->children();
+
+ // MenuItemView::Type::kNormal
+ ViewAXPlatformNodeDelegate* normal_item = view_accessibility(items[0]);
+ EXPECT_TRUE(normal_item->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_TRUE(normal_item->GetData().IsSelectable());
+ EXPECT_FALSE(normal_item->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected));
+ EXPECT_FALSE(normal_item->IsInvisibleOrIgnored());
+ EXPECT_FALSE(normal_item->GetData().IsInvisibleOrIgnored());
+ EXPECT_EQ(normal_item->GetData().role, ax::mojom::Role::kMenuItem);
+ EXPECT_EQ(normal_item->GetData().GetHasPopup(), ax::mojom::HasPopup::kFalse);
+ EXPECT_EQ(normal_item->GetPosInSet(), 1);
+ EXPECT_EQ(normal_item->GetSetSize(), 7);
+ EXPECT_EQ(normal_item->GetChildCount(), 0);
+ EXPECT_EQ(normal_item->GetIndexInParent(), 0);
+
+ // MenuItemView::Type::kSubMenu
+ ViewAXPlatformNodeDelegate* submenu_item = view_accessibility(items[1]);
+ EXPECT_TRUE(submenu_item->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_TRUE(submenu_item->GetData().IsSelectable());
+ EXPECT_FALSE(submenu_item->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected));
+ EXPECT_FALSE(submenu_item->IsInvisibleOrIgnored());
+ EXPECT_FALSE(submenu_item->GetData().IsInvisibleOrIgnored());
+ EXPECT_EQ(submenu_item->GetData().role, ax::mojom::Role::kMenuItem);
+ EXPECT_EQ(submenu_item->GetData().GetHasPopup(), ax::mojom::HasPopup::kMenu);
+ EXPECT_EQ(submenu_item->GetPosInSet(), 2);
+ EXPECT_EQ(submenu_item->GetSetSize(), 7);
+#if defined(OS_APPLE)
+ // A virtual child with role menu is exposed so that VoiceOver treats a
+ // MenuItemView of type kSubMenu as a submenu rather than an item.
+ EXPECT_EQ(submenu_item->GetChildCount(), 1);
+#else
+ EXPECT_EQ(submenu_item->GetChildCount(), 0);
+#endif // defined(OS_APPLE)
+ EXPECT_EQ(submenu_item->GetIndexInParent(), 1);
+
+ // MenuItemView::Type::kActionableSubMenu
+ ViewAXPlatformNodeDelegate* actionable_submenu_item =
+ view_accessibility(items[2]);
+ EXPECT_TRUE(actionable_submenu_item->GetData().HasState(
+ ax::mojom::State::kFocusable));
+ EXPECT_TRUE(actionable_submenu_item->GetData().IsSelectable());
+ EXPECT_FALSE(actionable_submenu_item->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected));
+ EXPECT_FALSE(actionable_submenu_item->IsInvisibleOrIgnored());
+ EXPECT_FALSE(actionable_submenu_item->GetData().IsInvisibleOrIgnored());
+ EXPECT_EQ(actionable_submenu_item->GetData().role,
+ ax::mojom::Role::kMenuItem);
+ EXPECT_EQ(actionable_submenu_item->GetData().GetHasPopup(),
+ ax::mojom::HasPopup::kMenu);
+ EXPECT_EQ(actionable_submenu_item->GetPosInSet(), 3);
+ EXPECT_EQ(actionable_submenu_item->GetSetSize(), 7);
+#if defined(OS_APPLE)
+ // A virtual child with role menu is exposed so that VoiceOver treats a
+ // MenuItemView of type kActionableSubMenu as a submenu rather than an item.
+ EXPECT_EQ(actionable_submenu_item->GetChildCount(), 1);
+#else
+ EXPECT_EQ(actionable_submenu_item->GetChildCount(), 0);
+#endif // defined(OS_APPLE)
+ EXPECT_EQ(actionable_submenu_item->GetIndexInParent(), 2);
+
+ // MenuItemView::Type::kCheckbox
+ ViewAXPlatformNodeDelegate* checkbox_item = view_accessibility(items[3]);
+ EXPECT_TRUE(checkbox_item->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_TRUE(checkbox_item->GetData().IsSelectable());
+ EXPECT_TRUE(checkbox_item->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected));
+ EXPECT_FALSE(checkbox_item->IsInvisibleOrIgnored());
+ EXPECT_FALSE(checkbox_item->GetData().IsInvisibleOrIgnored());
+ EXPECT_EQ(checkbox_item->GetData().role, ax::mojom::Role::kMenuItemCheckBox);
+ EXPECT_EQ(checkbox_item->GetData().GetHasPopup(),
+ ax::mojom::HasPopup::kFalse);
+ EXPECT_EQ(checkbox_item->GetPosInSet(), 4);
+ EXPECT_EQ(checkbox_item->GetSetSize(), 7);
+ EXPECT_EQ(checkbox_item->GetChildCount(), 0);
+ EXPECT_EQ(checkbox_item->GetIndexInParent(), 3);
+
+ // MenuItemView::Type::kRadio
+ ViewAXPlatformNodeDelegate* radio_item = view_accessibility(items[4]);
+ EXPECT_TRUE(radio_item->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_TRUE(radio_item->GetData().IsSelectable());
+ EXPECT_FALSE(radio_item->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected));
+ EXPECT_FALSE(radio_item->IsInvisibleOrIgnored());
+ EXPECT_FALSE(radio_item->GetData().IsInvisibleOrIgnored());
+ EXPECT_EQ(radio_item->GetData().role, ax::mojom::Role::kMenuItemRadio);
+ EXPECT_EQ(radio_item->GetData().GetHasPopup(), ax::mojom::HasPopup::kFalse);
+ EXPECT_EQ(radio_item->GetPosInSet(), 5);
+ EXPECT_EQ(radio_item->GetSetSize(), 7);
+ EXPECT_EQ(radio_item->GetChildCount(), 0);
+ EXPECT_EQ(radio_item->GetIndexInParent(), 4);
+
+ // MenuItemView::Type::kSeparator
+ ViewAXPlatformNodeDelegate* separator_item = view_accessibility(items[5]);
+ EXPECT_FALSE(
+ separator_item->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_FALSE(separator_item->GetData().IsSelectable());
+ EXPECT_FALSE(separator_item->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected));
+ EXPECT_FALSE(separator_item->IsInvisibleOrIgnored());
+ EXPECT_FALSE(separator_item->GetData().IsInvisibleOrIgnored());
+ EXPECT_EQ(separator_item->GetData().role, ax::mojom::Role::kSplitter);
+ EXPECT_EQ(separator_item->GetData().GetHasPopup(),
+ ax::mojom::HasPopup::kFalse);
+ EXPECT_FALSE(separator_item->GetData().HasIntAttribute(
+ ax::mojom::IntAttribute::kPosInSet));
+ EXPECT_FALSE(separator_item->GetData().HasIntAttribute(
+ ax::mojom::IntAttribute::kSetSize));
+ EXPECT_EQ(separator_item->GetChildCount(), 0);
+ EXPECT_EQ(separator_item->GetIndexInParent(), 5);
+
+ // MenuItemView::Type::kHighlighted
+ ViewAXPlatformNodeDelegate* highlighted_item = view_accessibility(items[6]);
+ EXPECT_TRUE(
+ highlighted_item->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_TRUE(highlighted_item->GetData().IsSelectable());
+ EXPECT_FALSE(highlighted_item->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected));
+ EXPECT_FALSE(highlighted_item->IsInvisibleOrIgnored());
+ EXPECT_FALSE(highlighted_item->GetData().IsInvisibleOrIgnored());
+ EXPECT_EQ(highlighted_item->GetData().role, ax::mojom::Role::kMenuItem);
+ EXPECT_EQ(highlighted_item->GetData().GetHasPopup(),
+ ax::mojom::HasPopup::kFalse);
+ EXPECT_EQ(highlighted_item->GetPosInSet(), 6);
+ EXPECT_EQ(highlighted_item->GetSetSize(), 7);
+ EXPECT_EQ(highlighted_item->GetChildCount(), 0);
+ EXPECT_EQ(highlighted_item->GetIndexInParent(), 6);
+
+ // MenuItemView::Type::kTitle
+ ViewAXPlatformNodeDelegate* title_item = view_accessibility(items[7]);
+ EXPECT_TRUE(title_item->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_TRUE(title_item->GetData().IsSelectable());
+ EXPECT_FALSE(title_item->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected));
+ EXPECT_FALSE(title_item->IsInvisibleOrIgnored());
+ EXPECT_FALSE(title_item->GetData().IsInvisibleOrIgnored());
+ EXPECT_EQ(title_item->GetData().role, ax::mojom::Role::kMenuItem);
+ EXPECT_EQ(title_item->GetData().GetHasPopup(), ax::mojom::HasPopup::kFalse);
+ EXPECT_EQ(title_item->GetPosInSet(), 7);
+ EXPECT_EQ(title_item->GetSetSize(), 7);
+ EXPECT_EQ(title_item->GetChildCount(), 0);
+ EXPECT_EQ(title_item->GetIndexInParent(), 7);
+}
+
#if defined(USE_AURA)
class DerivedTestView : public View {
public:
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win.cc
index 041d532c58b..af845a0cc28 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win.cc
@@ -19,6 +19,7 @@
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_text_utils.h"
#include "ui/accessibility/platform/ax_fragment_root_win.h"
+#include "ui/accessibility/platform/ax_platform_node_win.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/layout.h"
@@ -35,7 +36,9 @@ namespace views {
// static
std::unique_ptr<ViewAccessibility> ViewAccessibility::Create(View* view) {
- return std::make_unique<ViewAXPlatformNodeDelegateWin>(view);
+ auto result = std::make_unique<ViewAXPlatformNodeDelegateWin>(view);
+ result->Init();
+ return result;
}
ViewAXPlatformNodeDelegateWin::ViewAXPlatformNodeDelegateWin(View* view)
@@ -46,7 +49,7 @@ ViewAXPlatformNodeDelegateWin::~ViewAXPlatformNodeDelegateWin() = default;
gfx::NativeViewAccessible ViewAXPlatformNodeDelegateWin::GetParent() {
// If the View has a parent View, return that View's IAccessible.
if (view()->parent())
- return view()->parent()->GetNativeViewAccessible();
+ return ViewAXPlatformNodeDelegate::GetParent();
// Otherwise we must be the RootView, get the corresponding Widget
// and Window.
@@ -105,4 +108,5 @@ gfx::Rect ViewAXPlatformNodeDelegateWin::GetBoundsRect(
return gfx::Rect();
}
}
+
} // namespace views
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc
index 9cea15b6858..ab3d076e524 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc
@@ -8,7 +8,9 @@
#include <wrl/client.h>
#include <memory>
+#include <string>
#include <utility>
+#include <vector>
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_variant.h"
@@ -79,6 +81,16 @@ class ViewAXPlatformNodeDelegateWinTest : public ViewsTestBase {
__uuidof(IRawElementProviderSimple), &result));
return result;
}
+
+ ComPtr<IAccessible2> ToIAccessible2(ComPtr<IAccessible> accessible) {
+ CHECK(accessible);
+ ComPtr<IServiceProvider> service_provider;
+ accessible.As(&service_provider);
+ ComPtr<IAccessible2> result;
+ CHECK(SUCCEEDED(service_provider->QueryService(IID_IAccessible2,
+ IID_PPV_ARGS(&result))));
+ return result;
+ }
};
TEST_F(ViewAXPlatformNodeDelegateWinTest, TextfieldAccessibility) {
@@ -90,8 +102,8 @@ TEST_F(ViewAXPlatformNodeDelegateWinTest, TextfieldAccessibility) {
View* content = widget.SetContentsView(std::make_unique<View>());
Textfield* textfield = new Textfield;
- textfield->SetAccessibleName(L"Name");
- textfield->SetText(L"Value");
+ textfield->SetAccessibleName(STRING16_LITERAL("Name"));
+ textfield->SetText(STRING16_LITERAL("Value"));
content->AddChildView(textfield);
ComPtr<IAccessible> content_accessible(content->GetNativeViewAccessible());
@@ -125,7 +137,7 @@ TEST_F(ViewAXPlatformNodeDelegateWinTest, TextfieldAccessibility) {
ScopedBstr new_value(L"New value");
ASSERT_EQ(S_OK,
textfield_accessible->put_accValue(childid_self, new_value.Get()));
- EXPECT_STREQ(L"New value", textfield->GetText().c_str());
+ EXPECT_EQ(STRING16_LITERAL("New value"), textfield->GetText());
}
TEST_F(ViewAXPlatformNodeDelegateWinTest, TextfieldAssociatedLabel) {
@@ -136,7 +148,7 @@ TEST_F(ViewAXPlatformNodeDelegateWinTest, TextfieldAssociatedLabel) {
View* content = widget.SetContentsView(std::make_unique<View>());
- Label* label = new Label(L"Label");
+ Label* label = new Label(STRING16_LITERAL("Label"));
content->AddChildView(label);
Textfield* textfield = new Textfield;
textfield->SetAssociatedLabel(label);
@@ -382,7 +394,7 @@ TEST_F(ViewAXPlatformNodeDelegateWinTest, Overrides) {
View* alert_view = new ScrollView;
alert_view->GetViewAccessibility().OverrideRole(ax::mojom::Role::kAlert);
- alert_view->GetViewAccessibility().OverrideName(L"Name");
+ alert_view->GetViewAccessibility().OverrideName(STRING16_LITERAL("Name"));
alert_view->GetViewAccessibility().OverrideDescription("Description");
alert_view->GetViewAccessibility().OverrideIsLeaf(true);
contents_view->AddChildView(alert_view);
@@ -530,5 +542,123 @@ TEST_F(ViewAXPlatformNodeDelegateWinTest, IsUIAControlIsTrueEvenWhenReadonly) {
GetIRawElementProviderSimple(text_field);
EXPECT_UIA_BOOL_EQ(textfield_provider, UIA_IsControlElementPropertyId, true);
}
+
+//
+// TableView tests.
+//
+
+namespace {
+class TestTableModel : public ui::TableModel {
+ public:
+ TestTableModel() = default;
+
+ // ui::TableModel:
+ int RowCount() override { return 3; }
+
+ base::string16 GetText(int row, int column_id) override {
+ if (row == -1)
+ return base::string16();
+
+ const char* const cells[5][3] = {
+ {"Australia", "24,584,620", "1,323,421,072,479"},
+ {"Spain", "46,647,428", "1,314,314,164,402"},
+ {"Nigeria", "190.873,244", "375,745,486,521"},
+ };
+
+ return base::ASCIIToUTF16(cells[row % 5][column_id]);
+ }
+
+ void SetObserver(ui::TableModelObserver* observer) override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestTableModel);
+};
+} // namespace
+
+class ViewAXPlatformNodeDelegateWinTableTest
+ : public ViewAXPlatformNodeDelegateWinTest {
+ void SetUp() override {
+ ViewAXPlatformNodeDelegateWinTest::SetUp();
+
+ std::vector<ui::TableColumn> columns;
+ columns.push_back(TestTableColumn(0, "Country"));
+ columns.push_back(TestTableColumn(1, "Population"));
+ columns.push_back(TestTableColumn(2, "GDP"));
+
+ model_ = std::make_unique<TestTableModel>();
+ auto table =
+ std::make_unique<TableView>(model_.get(), columns, TEXT_ONLY, true);
+ table_ = table.get();
+
+ widget_ = new Widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_POPUP);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.bounds = gfx::Rect(0, 0, 400, 400);
+ widget_->Init(std::move(init_params));
+
+ View* content = widget_->SetContentsView(std::make_unique<View>());
+ content->AddChildView(
+ TableView::CreateScrollViewWithTable(std::move(table)));
+ widget_->Show();
+ }
+
+ void TearDown() override {
+ if (!widget_->IsClosed())
+ widget_->Close();
+ ViewAXPlatformNodeDelegateWinTest::TearDown();
+ }
+
+ ui::TableColumn TestTableColumn(int id, const std::string& title) {
+ ui::TableColumn column;
+ column.id = id;
+ column.title = base::ASCIIToUTF16(title.c_str());
+ column.sortable = true;
+ return column;
+ }
+
+ protected:
+ std::unique_ptr<TestTableModel> model_;
+ Widget* widget_ = nullptr;
+ TableView* table_ = nullptr; // Owned by parent.
+};
+
+TEST_F(ViewAXPlatformNodeDelegateWinTableTest, TableCellAttributes) {
+ ComPtr<IAccessible2_2> table_accessible;
+ GetIAccessible2InterfaceForView(table_, &table_accessible);
+
+ auto get_attributes = [&](int row_child, int cell_child) -> std::wstring {
+ ComPtr<IDispatch> row_dispatch;
+ CHECK_EQ(S_OK, table_accessible->get_accChild(ScopedVariant(row_child),
+ &row_dispatch));
+ ComPtr<IAccessible> row;
+ CHECK_EQ(S_OK, row_dispatch.As(&row));
+ ComPtr<IAccessible2> ia2_row = ToIAccessible2(row);
+
+ ComPtr<IDispatch> cell_dispatch;
+ CHECK_EQ(S_OK,
+ row->get_accChild(ScopedVariant(cell_child), &cell_dispatch));
+ ComPtr<IAccessible> cell;
+ CHECK_EQ(S_OK, cell_dispatch.As(&cell));
+ ComPtr<IAccessible2> ia2_cell = ToIAccessible2(cell);
+
+ ScopedBstr attributes_bstr;
+ CHECK_EQ(S_OK, ia2_cell->get_attributes(attributes_bstr.Receive()));
+ std::wstring attributes(attributes_bstr.Get());
+ return attributes;
+ };
+
+ // These strings should NOT contain rowindex or colindex, since those
+ // imply an ARIA override.
+ EXPECT_EQ(get_attributes(1, 1),
+ L"explicit-name:true;sort:none;class:AXVirtualView;");
+ EXPECT_EQ(get_attributes(1, 2),
+ L"explicit-name:true;sort:none;class:AXVirtualView;");
+ EXPECT_EQ(get_attributes(2, 1),
+ L"hidden:true;explicit-name:true;class:AXVirtualView;");
+ EXPECT_EQ(get_attributes(2, 2),
+ L"hidden:true;explicit-name:true;class:AXVirtualView;");
+}
+
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/accessibility/views_ax_tree_manager.cc b/chromium/ui/views/accessibility/views_ax_tree_manager.cc
index 2b30e23ceef..861009afe4f 100644
--- a/chromium/ui/views/accessibility/views_ax_tree_manager.cc
+++ b/chromium/ui/views/accessibility/views_ax_tree_manager.cc
@@ -12,12 +12,14 @@
#include "base/location.h"
#include "base/notreached.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "ui/accessibility/accessibility_features.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_tree_manager_map.h"
#include "ui/accessibility/ax_tree_source_checker.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+#include "ui/views/accessibility/widget_ax_tree_id_map.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -25,14 +27,15 @@ namespace views {
ViewsAXTreeManager::ViewsAXTreeManager(Widget* widget)
: widget_(widget),
- tree_source_(cache_.GetOrCreate(widget),
- ui::AXTreeID::CreateNewAXTreeID(),
- &cache_),
+ tree_id_(ui::AXTreeID::CreateNewAXTreeID()),
+ tree_source_(cache_.GetOrCreate(widget), tree_id_, &cache_),
tree_serializer_(&tree_source_),
event_generator_(&ax_tree_) {
DCHECK(widget);
- ui::AXTreeManagerMap::GetInstance().AddTreeManager(GetTreeID(), this);
- views_event_observer_.Add(AXEventManager::Get());
+ ui::AXTreeManagerMap::GetInstance().AddTreeManager(tree_id_, this);
+ views::WidgetAXTreeIDMap::GetInstance().AddWidget(tree_id_, widget);
+ views_event_observer_.Observe(AXEventManager::Get());
+ widget_observer_.Observe(widget);
View* root_view = widget->GetRootView();
if (root_view)
root_view->NotifyAccessibilityEvent(ax::mojom::Event::kLoadComplete, true);
@@ -40,8 +43,9 @@ ViewsAXTreeManager::ViewsAXTreeManager(Widget* widget)
ViewsAXTreeManager::~ViewsAXTreeManager() {
event_generator_.ReleaseTree();
- views_event_observer_.RemoveAll();
- ui::AXTreeManagerMap::GetInstance().RemoveTreeManager(GetTreeID());
+ views_event_observer_.Reset();
+ widget_observer_.Reset();
+ ui::AXTreeManagerMap::GetInstance().RemoveTreeManager(tree_id_);
}
void ViewsAXTreeManager::SetGeneratedEventCallbackForTesting(
@@ -55,19 +59,25 @@ void ViewsAXTreeManager::UnsetGeneratedEventCallbackForTesting() {
ui::AXNode* ViewsAXTreeManager::GetNodeFromTree(
const ui::AXTreeID tree_id,
- const ui::AXNode::AXID node_id) const {
+ const ui::AXNodeID node_id) const {
+ if (!widget_)
+ return nullptr;
+
const ui::AXTreeManager* manager =
ui::AXTreeManagerMap::GetInstance().GetManager(tree_id);
return manager ? manager->GetNodeFromTree(node_id) : nullptr;
}
ui::AXNode* ViewsAXTreeManager::GetNodeFromTree(
- const ui::AXNode::AXID node_id) const {
+ const ui::AXNodeID node_id) const {
+ if (!widget_)
+ return nullptr;
+
return ax_tree_.GetFromId(node_id);
}
ui::AXTreeID ViewsAXTreeManager::GetTreeID() const {
- return ax_tree_.GetAXTreeID();
+ return tree_id_;
}
ui::AXTreeID ViewsAXTreeManager::GetParentTreeID() const {
@@ -77,6 +87,9 @@ ui::AXTreeID ViewsAXTreeManager::GetParentTreeID() const {
}
ui::AXNode* ViewsAXTreeManager::GetRootAsAXNode() const {
+ if (!widget_)
+ return nullptr;
+
return ax_tree_.root();
}
@@ -101,11 +114,31 @@ void ViewsAXTreeManager::OnViewEvent(View* view, ax::mojom::Event event) {
weak_factory_.GetWeakPtr()));
}
+void ViewsAXTreeManager::OnWidgetDestroyed(Widget* widget) {
+ if (widget->is_top_level())
+ views::WidgetAXTreeIDMap::GetInstance().RemoveWidget(widget);
+
+ widget_ = nullptr;
+}
+
+void ViewsAXTreeManager::OnWidgetClosing(Widget* widget) {
+ if (widget->is_top_level())
+ views::WidgetAXTreeIDMap::GetInstance().RemoveWidget(widget);
+
+ widget_ = nullptr;
+}
+
void ViewsAXTreeManager::PerformAction(const ui::AXActionData& data) {
+ if (!widget_)
+ return;
+
tree_source_.HandleAccessibleAction(data);
}
void ViewsAXTreeManager::SerializeTreeUpdates() {
+ if (!widget_)
+ return;
+
// Better to set this flag to false early in case this method, or any method
// it calls, causes an event to get fired.
waiting_to_serialize_ = false;
@@ -116,7 +149,7 @@ void ViewsAXTreeManager::SerializeTreeUpdates() {
modified_nodes_.insert(focused_wrapper->GetUniqueId());
std::vector<ui::AXTreeUpdate> updates;
- for (const ui::AXNode::AXID node_id : modified_nodes_) {
+ for (const ui::AXNodeID node_id : modified_nodes_) {
AXAuraObjWrapper* wrapper = cache_.Get(node_id);
if (!wrapper)
continue;
@@ -124,8 +157,7 @@ void ViewsAXTreeManager::SerializeTreeUpdates() {
ui::AXTreeUpdate update;
if (!tree_serializer_.SerializeChanges(wrapper, &update)) {
std::string error;
- ui::AXTreeSourceChecker<AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData>
- checker(&tree_source_);
+ ui::AXTreeSourceChecker<AXAuraObjWrapper*> checker(&tree_source_);
checker.CheckAndGetErrorString(&error);
NOTREACHED() << error << '\n' << update.ToString();
return;
@@ -139,6 +171,9 @@ void ViewsAXTreeManager::SerializeTreeUpdates() {
void ViewsAXTreeManager::UnserializeTreeUpdates(
const std::vector<ui::AXTreeUpdate>& updates) {
+ if (!widget_)
+ return;
+
for (const ui::AXTreeUpdate& update : updates) {
if (!ax_tree_.Unserialize(update)) {
NOTREACHED() << ax_tree_.error();
diff --git a/chromium/ui/views/accessibility/views_ax_tree_manager.h b/chromium/ui/views/accessibility/views_ax_tree_manager.h
index 324af2d35b5..ab7313ce3cf 100644
--- a/chromium/ui/views/accessibility/views_ax_tree_manager.h
+++ b/chromium/ui/views/accessibility/views_ax_tree_manager.h
@@ -11,7 +11,7 @@
#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/accessibility/ax_action_handler.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
#include "ui/accessibility/ax_event_generator.h"
@@ -27,6 +27,8 @@
#include "ui/views/accessibility/ax_event_observer.h"
#include "ui/views/accessibility/ax_tree_source_views.h"
#include "ui/views/views_export.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_observer.h"
namespace ui {
@@ -38,7 +40,6 @@ namespace views {
class AXAuraObjWrapper;
class View;
-class Widget;
// Manages an accessibility tree that mirrors the Views tree for a particular
// widget.
@@ -51,10 +52,11 @@ class Widget;
// deserialized into an AXTree, both in the same process.
class VIEWS_EXPORT ViewsAXTreeManager : public ui::AXTreeManager,
public ui::AXActionHandler,
- public AXEventObserver {
+ public AXEventObserver,
+ public views::WidgetObserver {
public:
using GeneratedEventCallbackForTesting = base::RepeatingCallback<
- void(Widget*, ui::AXEventGenerator::Event, ui::AXNode::AXID)>;
+ void(Widget*, ui::AXEventGenerator::Event, ui::AXNodeID)>;
// Creates an instance of this class that manages an AXTree mirroring the
// Views tree rooted at a given Widget.
@@ -80,8 +82,8 @@ class VIEWS_EXPORT ViewsAXTreeManager : public ui::AXTreeManager,
// AXTreeManager implementation.
ui::AXNode* GetNodeFromTree(const ui::AXTreeID tree_id,
- const ui::AXNode::AXID node_id) const override;
- ui::AXNode* GetNodeFromTree(const ui::AXNode::AXID node_id) const override;
+ const ui::AXNodeID node_id) const override;
+ ui::AXNode* GetNodeFromTree(const ui::AXNodeID node_id) const override;
ui::AXTreeID GetTreeID() const override;
ui::AXTreeID GetParentTreeID() const override;
ui::AXNode* GetRootAsAXNode() const override;
@@ -93,9 +95,12 @@ class VIEWS_EXPORT ViewsAXTreeManager : public ui::AXTreeManager,
// AXEventObserver implementation.
void OnViewEvent(views::View* view, ax::mojom::Event event) override;
+ // WidgetObserver implementation.
+ void OnWidgetDestroyed(Widget* widget) override;
+ void OnWidgetClosing(Widget* widget) override;
+
private:
- using ViewsAXTreeSerializer =
- ui::AXTreeSerializer<AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData>;
+ using ViewsAXTreeSerializer = ui::AXTreeSerializer<AXAuraObjWrapper*>;
void SerializeTreeUpdates();
void UnserializeTreeUpdates(const std::vector<ui::AXTreeUpdate>& updates);
@@ -110,7 +115,7 @@ class VIEWS_EXPORT ViewsAXTreeManager : public ui::AXTreeManager,
// The Widget for which this class manages an AXTree.
//
// Weak, a Widget doesn't own this class.
- Widget* const widget_;
+ Widget* widget_;
// Set to true if we are still waiting for a task to serialize all previously
// modified nodes.
@@ -118,12 +123,19 @@ class VIEWS_EXPORT ViewsAXTreeManager : public ui::AXTreeManager,
// The set of nodes in the source tree that might have been modified after an
// event has been fired on them.
- std::set<ui::AXNode::AXID> modified_nodes_;
+ std::set<ui::AXNodeID> modified_nodes_;
// The cache that maps objects in the Views tree to AXAuraObjWrapper objects
// that are used to serialize the Views tree.
AXAuraObjCache cache_;
+ // The ID for this AXTree.
+ ui::AXTreeID tree_id_;
+
+ // The AXTree that mirrors the Views tree and which is created by
+ // deserializing the updates from |tree_source_|.
+ ui::AXTree ax_tree_;
+
// The tree source that enables us to serialize the Views tree.
AXTreeSourceViews tree_source_;
@@ -131,10 +143,6 @@ class VIEWS_EXPORT ViewsAXTreeManager : public ui::AXTreeManager,
// AXTreeUpdate.
ViewsAXTreeSerializer tree_serializer_;
- // The AXTree that mirrors the Views tree and which is created by
- // deserializing the updates from |tree_source_|.
- ui::AXTree ax_tree_;
-
// For automatically generating events based on changes to |tree_|.
ui::AXEventGenerator event_generator_;
@@ -143,7 +151,9 @@ class VIEWS_EXPORT ViewsAXTreeManager : public ui::AXTreeManager,
// To prevent any use-after-free, members below this line should be declared
// last.
- ScopedObserver<AXEventManager, AXEventObserver> views_event_observer_{this};
+ base::ScopedObservation<AXEventManager, AXEventObserver>
+ views_event_observer_{this};
+ base::ScopedObservation<Widget, views::WidgetObserver> widget_observer_{this};
base::WeakPtrFactory<ViewsAXTreeManager> weak_factory_{this};
};
diff --git a/chromium/ui/views/accessibility/views_ax_tree_manager_unittest.cc b/chromium/ui/views/accessibility/views_ax_tree_manager_unittest.cc
index d2f4d0b1acb..80670848945 100644
--- a/chromium/ui/views/accessibility/views_ax_tree_manager_unittest.cc
+++ b/chromium/ui/views/accessibility/views_ax_tree_manager_unittest.cc
@@ -13,6 +13,8 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "ui/accessibility/accessibility_features.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_event_generator.h"
#include "ui/accessibility/ax_node.h"
@@ -41,7 +43,8 @@ class TestButton : public Button {
~TestButton() override = default;
};
-class ViewsAXTreeManagerTest : public ViewsTestBase {
+class ViewsAXTreeManagerTest : public ViewsTestBase,
+ public ::testing::WithParamInterface<bool> {
public:
ViewsAXTreeManagerTest() = default;
~ViewsAXTreeManagerTest() override = default;
@@ -51,6 +54,7 @@ class ViewsAXTreeManagerTest : public ViewsTestBase {
protected:
void SetUp() override;
void TearDown() override;
+ void CloseWidget();
ui::AXNode* FindNode(const ax::mojom::Role role,
const std::string& name_or_value) const;
void WaitFor(const ui::AXEventGenerator::Event event);
@@ -58,7 +62,7 @@ class ViewsAXTreeManagerTest : public ViewsTestBase {
Widget* widget() const { return widget_; }
Button* button() const { return button_; }
Label* label() const { return label_; }
- const ViewsAXTreeManager& manager() const { return *manager_; }
+ ViewsAXTreeManager* manager() const { return manager_.get(); }
private:
ui::AXNode* FindNodeInSubtree(ui::AXNode* root,
@@ -66,7 +70,7 @@ class ViewsAXTreeManagerTest : public ViewsTestBase {
const std::string& name_or_value) const;
void OnGeneratedEvent(Widget* widget,
ui::AXEventGenerator::Event event,
- ui::AXNode::AXID node_id);
+ ui::AXNodeID node_id);
Widget* widget_ = nullptr;
Button* button_ = nullptr;
@@ -74,13 +78,20 @@ class ViewsAXTreeManagerTest : public ViewsTestBase {
std::unique_ptr<ViewsAXTreeManager> manager_;
ui::AXEventGenerator::Event event_to_wait_for_;
std::unique_ptr<base::RunLoop> loop_runner_;
+ base::test::ScopedFeatureList scoped_feature_list_;
};
void ViewsAXTreeManagerTest::SetUp() {
ViewsTestBase::SetUp();
+ if (GetParam()) {
+ scoped_feature_list_.InitWithFeatures(
+ {features::kEnableAccessibilityTreeForViews}, {});
+ }
+
widget_ = new Widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = gfx::Rect(0, 0, 200, 200);
widget_->Init(std::move(params));
@@ -93,26 +104,45 @@ void ViewsAXTreeManagerTest::SetUp() {
widget_->GetContentsView()->AddChildView(button_);
widget_->Show();
- manager_ = std::make_unique<ViewsAXTreeManager>(widget_);
- ASSERT_NE(nullptr, manager_.get());
- manager_->SetGeneratedEventCallbackForTesting(base::BindRepeating(
+ // AccessibilityTreeForViewsEnabled will create and manage its own
+ // ViewsAXTreeManager, so we don't need to create one for testing.
+ if (features::IsAccessibilityTreeForViewsEnabled()) {
+ manager_.reset(
+ widget_->GetRootView()->GetViewAccessibility().AXTreeManager());
+ } else {
+ manager_ = std::make_unique<ViewsAXTreeManager>(widget_);
+ }
+
+ ASSERT_NE(nullptr, manager_);
+ manager()->SetGeneratedEventCallbackForTesting(base::BindRepeating(
&ViewsAXTreeManagerTest::OnGeneratedEvent, base::Unretained(this)));
WaitFor(ui::AXEventGenerator::Event::LOAD_COMPLETE);
}
void ViewsAXTreeManagerTest::TearDown() {
- manager_->UnsetGeneratedEventCallbackForTesting();
+ if (manager())
+ manager()->UnsetGeneratedEventCallbackForTesting();
manager_.reset();
- if (!widget_->IsClosed())
- widget_->Close();
+ CloseWidget();
ViewsTestBase::TearDown();
}
+void ViewsAXTreeManagerTest::CloseWidget() {
+ if (!widget_->IsClosed())
+ widget_->CloseNow();
+
+ RunPendingMessages();
+}
+
ui::AXNode* ViewsAXTreeManagerTest::FindNode(
const ax::mojom::Role role,
const std::string& name_or_value) const {
- ui::AXNode* root = manager_->GetRootAsAXNode();
- EXPECT_NE(nullptr, root);
+ ui::AXNode* root = manager()->GetRootAsAXNode();
+
+ // If the manager has been closed, it will return nullptr as root.
+ if (!root)
+ return nullptr;
+
return FindNodeInSubtree(root, role, name_or_value);
}
@@ -148,16 +178,17 @@ ui::AXNode* ViewsAXTreeManagerTest::FindNodeInSubtree(
void ViewsAXTreeManagerTest::OnGeneratedEvent(Widget* widget,
ui::AXEventGenerator::Event event,
- ui::AXNode::AXID node_id) {
- ASSERT_NE(nullptr, manager_.get())
- << "Should not be called after TearDown().";
+ ui::AXNodeID node_id) {
+ ASSERT_NE(nullptr, manager()) << "Should not be called after TearDown().";
if (loop_runner_ && event == event_to_wait_for_)
loop_runner_->Quit();
}
} // namespace
-TEST_F(ViewsAXTreeManagerTest, MirrorInitialTree) {
+INSTANTIATE_TEST_SUITE_P(All, ViewsAXTreeManagerTest, testing::Bool());
+
+TEST_P(ViewsAXTreeManagerTest, MirrorInitialTree) {
ui::AXNodeData button_data;
button()->GetViewAccessibility().GetAccessibleNodeData(&button_data);
ui::AXNode* ax_button = FindNode(ax::mojom::Role::kButton, "");
@@ -174,7 +205,7 @@ TEST_F(ViewsAXTreeManagerTest, MirrorInitialTree) {
EXPECT_TRUE(ax_button->data().HasState(ax::mojom::State::kFocusable));
}
-TEST_F(ViewsAXTreeManagerTest, PerformAction) {
+TEST_P(ViewsAXTreeManagerTest, PerformAction) {
ui::AXNode* ax_button = FindNode(ax::mojom::Role::kButton, "");
ASSERT_NE(nullptr, ax_button);
ASSERT_FALSE(ax_button->data().HasIntAttribute(
@@ -185,5 +216,22 @@ TEST_F(ViewsAXTreeManagerTest, PerformAction) {
WaitFor(ui::AXEventGenerator::Event::CHECKED_STATE_CHANGED);
}
+TEST_P(ViewsAXTreeManagerTest, CloseWidget) {
+ // This test is only relevant when IsAccessibilityTreeForViewsEnabled is set,
+ // as it tests the lifetime management of ViewsAXTreeManager when a Widget is
+ // closed.
+ if (!features::IsAccessibilityTreeForViewsEnabled())
+ return;
+
+ ui::AXNode* ax_button = FindNode(ax::mojom::Role::kButton, "");
+ ASSERT_NE(nullptr, ax_button);
+
+ CloseWidget();
+
+ // Looking up a node after its Widget has been closed should return nullptr.
+ ax_button = FindNode(ax::mojom::Role::kButton, "");
+ EXPECT_EQ(nullptr, ax_button);
+}
+
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/accessibility/widget_ax_tree_id_map.cc b/chromium/ui/views/accessibility/widget_ax_tree_id_map.cc
new file mode 100644
index 00000000000..7892d204af2
--- /dev/null
+++ b/chromium/ui/views/accessibility/widget_ax_tree_id_map.cc
@@ -0,0 +1,55 @@
+// Copyright 2020 The Chromium 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/widget_ax_tree_id_map.h"
+
+#include "base/stl_util.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+
+namespace views {
+
+WidgetAXTreeIDMap::WidgetAXTreeIDMap() {}
+
+WidgetAXTreeIDMap::~WidgetAXTreeIDMap() {}
+
+// static
+WidgetAXTreeIDMap& WidgetAXTreeIDMap::GetInstance() {
+ static base::NoDestructor<WidgetAXTreeIDMap> instance;
+ return *instance;
+}
+
+bool WidgetAXTreeIDMap::HasWidget(Widget* widget) {
+ return base::Contains(widget_map_, widget);
+}
+
+void WidgetAXTreeIDMap::AddWidget(ui::AXTreeID tree_id, Widget* widget) {
+ DCHECK_NE(tree_id, ui::AXTreeIDUnknown());
+ DCHECK(widget);
+ DCHECK(!HasWidget(widget));
+ widget_map_[widget] = tree_id;
+}
+
+void WidgetAXTreeIDMap::RemoveWidget(Widget* widget) {
+ widget_map_.erase(widget);
+}
+
+ui::AXTreeID WidgetAXTreeIDMap::GetWidgetTreeID(Widget* widget) {
+ DCHECK(widget);
+ if (!base::Contains(widget_map_, widget))
+ return ui::AXTreeIDUnknown();
+
+ return widget_map_.at(widget);
+}
+
+const std::vector<Widget*> WidgetAXTreeIDMap::GetWidgets() const {
+ std::vector<Widget*> widgets;
+ widgets.reserve(widget_map_.size());
+
+ for (auto iter : widget_map_)
+ widgets.push_back(iter.first);
+
+ return widgets;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/accessibility/widget_ax_tree_id_map.h b/chromium/ui/views/accessibility/widget_ax_tree_id_map.h
new file mode 100644
index 00000000000..cdb6e004ed1
--- /dev/null
+++ b/chromium/ui/views/accessibility/widget_ax_tree_id_map.h
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium 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_WIDGET_AX_TREE_ID_MAP_H_
+#define UI_VIEWS_ACCESSIBILITY_WIDGET_AX_TREE_ID_MAP_H_
+
+#include <map>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/no_destructor.h"
+#include "ui/accessibility/ax_tree_id.h"
+#include "ui/accessibility/ax_tree_manager.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+class Widget;
+
+// This class manages mapping between Widgets and their associated AXTreeIDs.
+// It is a singleton wrapper around a std::map. Widget pointers are used as the
+// key for the map and AXTreeID's are used as the value returned.
+class VIEWS_EXPORT WidgetAXTreeIDMap {
+ public:
+ WidgetAXTreeIDMap();
+ ~WidgetAXTreeIDMap();
+ static WidgetAXTreeIDMap& GetInstance();
+
+ bool HasWidget(Widget* widget);
+ void AddWidget(ui::AXTreeID tree_id, Widget* widget);
+ void RemoveWidget(Widget* widget);
+ ui::AXTreeID GetWidgetTreeID(views::Widget* widget);
+ const std::vector<Widget*> GetWidgets() const;
+
+ private:
+ std::map<Widget*, ui::AXTreeID> widget_map_;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_WIDGET_AX_TREE_ID_MAP_H_
diff --git a/chromium/ui/views/accessible_pane_view_unittest.cc b/chromium/ui/views/accessible_pane_view_unittest.cc
index 3e0628206be..9408c37ef13 100644
--- a/chromium/ui/views/accessible_pane_view_unittest.cc
+++ b/chromium/ui/views/accessible_pane_view_unittest.cc
@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/layout/fill_layout.h"
@@ -134,7 +135,7 @@ TEST_F(AccessiblePaneViewTest, SetPaneFocusAndRestore) {
// 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_APPLE) || defined(OS_CHROMEOS)
+#if !defined(OS_APPLE) || BUILDFLAG(IS_CHROMEOS_ASH)
// Esc should deactivate the widget.
test_view_bar->AcceleratorPressed(test_view_bar->escape_key());
EXPECT_TRUE(widget_main->IsActive());
diff --git a/chromium/ui/views/animation/animation_delegate_views.cc b/chromium/ui/views/animation/animation_delegate_views.cc
index f379e561000..f114d727486 100644
--- a/chromium/ui/views/animation/animation_delegate_views.cc
+++ b/chromium/ui/views/animation/animation_delegate_views.cc
@@ -14,7 +14,7 @@ namespace views {
AnimationDelegateViews::AnimationDelegateViews(View* view) : view_(view) {
if (view)
- scoped_observer_.Add(view);
+ scoped_observation_.Observe(view);
}
AnimationDelegateViews::~AnimationDelegateViews() {
@@ -46,7 +46,8 @@ void AnimationDelegateViews::OnViewRemovedFromWidget(View* observed_view) {
}
void AnimationDelegateViews::OnViewIsDeleting(View* observed_view) {
- scoped_observer_.Remove(view_);
+ DCHECK(scoped_observation_.IsObservingSource(view_));
+ scoped_observation_.Reset();
view_ = nullptr;
UpdateAnimationRunner();
}
diff --git a/chromium/ui/views/animation/animation_delegate_views.h b/chromium/ui/views/animation/animation_delegate_views.h
index c8aed3937e6..7edc84d9cf1 100644
--- a/chromium/ui/views/animation/animation_delegate_views.h
+++ b/chromium/ui/views/animation/animation_delegate_views.h
@@ -7,7 +7,7 @@
#include <memory>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/gfx/animation/animation_container_observer.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/views/view.h"
@@ -61,7 +61,7 @@ class VIEWS_EXPORT AnimationDelegateViews
// The animation runner that |container_| uses.
CompositorAnimationRunner* compositor_animation_runner_ = nullptr;
- ScopedObserver<View, ViewObserver> scoped_observer_{this};
+ base::ScopedObservation<View, ViewObserver> scoped_observation_{this};
};
} // namespace views
diff --git a/chromium/ui/views/animation/bubble_slide_animator.cc b/chromium/ui/views/animation/bubble_slide_animator.cc
new file mode 100644
index 00000000000..4ba8149c2df
--- /dev/null
+++ b/chromium/ui/views/animation/bubble_slide_animator.cc
@@ -0,0 +1,101 @@
+// Copyright 2021 The Chromium 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/animation/bubble_slide_animator.h"
+
+#include "base/time/time.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+
+namespace views {
+
+BubbleSlideAnimator::BubbleSlideAnimator(
+ BubbleDialogDelegateView* bubble_delegate)
+ : AnimationDelegateViews(bubble_delegate),
+ bubble_delegate_(bubble_delegate) {
+ Widget* widget = bubble_delegate->GetWidget();
+ DCHECK(widget);
+ widget_observation_.Observe(widget);
+
+ constexpr base::TimeDelta kDefaultBubbleSlideAnimationTime =
+ base::TimeDelta::FromMilliseconds(200);
+ slide_animation_.SetDuration(kDefaultBubbleSlideAnimationTime);
+}
+
+BubbleSlideAnimator::~BubbleSlideAnimator() = default;
+
+void BubbleSlideAnimator::SetSlideDuration(base::TimeDelta duration) {
+ slide_animation_.SetDuration(duration);
+}
+
+void BubbleSlideAnimator::AnimateToAnchorView(View* desired_anchor_view) {
+ desired_anchor_view_ = desired_anchor_view;
+ starting_bubble_bounds_ =
+ bubble_delegate_->GetWidget()->GetWindowBoundsInScreen();
+ target_bubble_bounds_ = CalculateTargetBounds(desired_anchor_view);
+ slide_animation_.SetCurrentValue(0);
+ slide_animation_.Start();
+}
+
+void BubbleSlideAnimator::SnapToAnchorView(View* desired_anchor_view) {
+ StopAnimation();
+ target_bubble_bounds_ = CalculateTargetBounds(desired_anchor_view);
+ starting_bubble_bounds_ = target_bubble_bounds_;
+ bubble_delegate_->GetWidget()->SetBounds(target_bubble_bounds_);
+ bubble_delegate_->SetAnchorView(desired_anchor_view);
+ slide_progressed_callbacks_.Notify(this, 1.0);
+ slide_complete_callbacks_.Notify(this);
+}
+
+void BubbleSlideAnimator::StopAnimation() {
+ slide_animation_.Stop();
+ desired_anchor_view_ = nullptr;
+}
+
+base::CallbackListSubscription BubbleSlideAnimator::AddSlideProgressedCallback(
+ SlideProgressedCallback callback) {
+ return slide_progressed_callbacks_.Add(callback);
+}
+
+base::CallbackListSubscription BubbleSlideAnimator::AddSlideCompleteCallback(
+ SlideCompleteCallback callback) {
+ return slide_complete_callbacks_.Add(callback);
+}
+
+void BubbleSlideAnimator::AnimationProgressed(const gfx::Animation* animation) {
+ double value = gfx::Tween::CalculateValue(tween_type_,
+ slide_animation_.GetCurrentValue());
+
+ const gfx::Rect current_bounds = gfx::Tween::RectValueBetween(
+ value, starting_bubble_bounds_, target_bubble_bounds_);
+ if (current_bounds == target_bubble_bounds_ && desired_anchor_view_)
+ bubble_delegate_->SetAnchorView(desired_anchor_view_);
+
+ bubble_delegate_->GetWidget()->SetBounds(current_bounds);
+ slide_progressed_callbacks_.Notify(this, value);
+}
+
+void BubbleSlideAnimator::AnimationEnded(const gfx::Animation* animation) {
+ desired_anchor_view_ = nullptr;
+ slide_complete_callbacks_.Notify(this);
+}
+
+void BubbleSlideAnimator::AnimationCanceled(const gfx::Animation* animation) {
+ desired_anchor_view_ = nullptr;
+}
+
+void BubbleSlideAnimator::OnWidgetDestroying(Widget* widget) {
+ widget_observation_.Reset();
+ slide_animation_.Stop();
+}
+
+gfx::Rect BubbleSlideAnimator::CalculateTargetBounds(
+ const View* desired_anchor_view) const {
+ gfx::Rect anchor_bounds = desired_anchor_view->GetAnchorBoundsInScreen();
+ anchor_bounds.Inset(bubble_delegate_->anchor_view_insets());
+ return bubble_delegate_->GetBubbleFrameView()->GetUpdatedWindowBounds(
+ anchor_bounds, bubble_delegate_->arrow(),
+ bubble_delegate_->GetWidget()->client_view()->GetPreferredSize(), true);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/animation/bubble_slide_animator.h b/chromium/ui/views/animation/bubble_slide_animator.h
new file mode 100644
index 00000000000..7bb92fdc535
--- /dev/null
+++ b/chromium/ui/views/animation/bubble_slide_animator.h
@@ -0,0 +1,116 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_ANIMATION_BUBBLE_SLIDE_ANIMATOR_H_
+#define UI_VIEWS_ANIMATION_BUBBLE_SLIDE_ANIMATOR_H_
+
+#include "base/callback_forward.h"
+#include "base/callback_list.h"
+#include "base/time/time.h"
+#include "ui/gfx/animation/linear_animation.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/animation/animation_delegate_views.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_observer.h"
+
+namespace views {
+
+class BubbleDialogDelegateView;
+class View;
+
+// Animates a bubble between anchor views on demand. Must be used with
+// BubbleDialogDelegateView because of its reliance on the anchoring system.
+class VIEWS_EXPORT BubbleSlideAnimator : public AnimationDelegateViews,
+ public WidgetObserver {
+ public:
+ // Slide complete callback is called when a slide completes and the bubble is
+ // safely anchored to the new view.
+ using SlideCompleteCallbackSignature = void(BubbleSlideAnimator*);
+ using SlideCompleteCallback =
+ base::RepeatingCallback<SlideCompleteCallbackSignature>;
+
+ // Slide progressed callback is called for each animation frame,
+ // |animation_value| will be between 0 and 1 and will scale according to the
+ // |tween_type| parameter.
+ using SlideProgressedCallbackSignature = void(BubbleSlideAnimator*,
+ double animation_value);
+ using SlideProgressedCallback =
+ base::RepeatingCallback<SlideProgressedCallbackSignature>;
+
+ // Constructs a new BubbleSlideAnimator associated with the specified
+ // |bubble_view|, which must already have a widget. If the bubble's widget is
+ // destroyed, any animations will be canceled and this animator will no longer
+ // be able to be used.
+ explicit BubbleSlideAnimator(BubbleDialogDelegateView* bubble_view);
+ BubbleSlideAnimator(const BubbleSlideAnimator&) = delete;
+ BubbleSlideAnimator& operator=(const BubbleSlideAnimator&) = delete;
+ ~BubbleSlideAnimator() override;
+
+ bool is_animating() const { return slide_animation_.is_animating(); }
+
+ // Sets the animation duration (a default is used if not set).
+ void SetSlideDuration(base::TimeDelta duration);
+
+ View* desired_anchor_view() { return desired_anchor_view_; }
+ const View* desired_anchor_view() const { return desired_anchor_view_; }
+
+ gfx::Tween::Type tween_type() const { return tween_type_; }
+ void set_tween_type(gfx::Tween::Type tween_type) { tween_type_ = tween_type; }
+
+ // Animates to a new anchor view.
+ void AnimateToAnchorView(View* desired_anchor_view);
+
+ // Ends any ongoing animation and immediately snaps the bubble to its target
+ // bounds.
+ void SnapToAnchorView(View* desired_anchor_view);
+
+ // Stops the animation without snapping the widget to a particular anchor
+ // view.
+ void StopAnimation();
+
+ // Adds a listener for slide progressed events.
+ base::CallbackListSubscription AddSlideProgressedCallback(
+ SlideProgressedCallback callback);
+
+ // Adds a listener for slide complete events.
+ base::CallbackListSubscription AddSlideCompleteCallback(
+ SlideCompleteCallback callback);
+
+ private:
+ // AnimationDelegateViews:
+ void AnimationProgressed(const gfx::Animation* animation) override;
+ void AnimationEnded(const gfx::Animation* animation) override;
+ void AnimationCanceled(const gfx::Animation* animation) override;
+
+ // WidgetObserver:
+ void OnWidgetDestroying(Widget* widget) override;
+
+ // Determines where to animate the bubble to during an animation.
+ gfx::Rect CalculateTargetBounds(const View* desired_anchor_view) const;
+
+ BubbleDialogDelegateView* const bubble_delegate_;
+ base::ScopedObservation<Widget, WidgetObserver> widget_observation_{this};
+ gfx::LinearAnimation slide_animation_{this};
+
+ // The desired anchor view, which is valid during a slide animation. When not
+ // animating, this value is null.
+ View* desired_anchor_view_ = nullptr;
+
+ // The tween type to use when animating. The default should be aesthetically
+ // pleasing for most applications.
+ gfx::Tween::Type tween_type_ = gfx::Tween::FAST_OUT_SLOW_IN;
+
+ gfx::Rect starting_bubble_bounds_;
+ gfx::Rect target_bubble_bounds_;
+ base::RepeatingCallbackList<SlideProgressedCallbackSignature>
+ slide_progressed_callbacks_;
+ base::RepeatingCallbackList<SlideCompleteCallbackSignature>
+ slide_complete_callbacks_;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ANIMATION_BUBBLE_SLIDE_ANIMATOR_H_
diff --git a/chromium/ui/views/animation/bubble_slide_animator_unittest.cc b/chromium/ui/views/animation/bubble_slide_animator_unittest.cc
new file mode 100644
index 00000000000..2744c412dbb
--- /dev/null
+++ b/chromium/ui/views/animation/bubble_slide_animator_unittest.cc
@@ -0,0 +1,376 @@
+// Copyright 2021 The Chromium 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/animation/bubble_slide_animator.h"
+
+#include <memory>
+
+#include "base/test/bind.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/gfx/animation/animation_test_api.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/flex_layout_view.h"
+#include "ui/views/test/widget_test.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+namespace {
+
+constexpr base::TimeDelta kSlideDuration =
+ base::TimeDelta::FromMilliseconds(1000);
+constexpr base::TimeDelta kHalfSlideDuration = kSlideDuration / 2;
+
+// This will be the size of the three horizontally-oriented anchor views as well
+// as the target size for the floating view.
+constexpr gfx::Size kTestViewSize(100, 100);
+// Make this big enough that even if we anchor to a third view horizontally, no
+// mirroring should happen.
+constexpr gfx::Rect kAnchorWidgetRect(50, 50, 400, 250);
+
+class TestBubbleView : public BubbleDialogDelegateView {
+ public:
+ explicit TestBubbleView(View* anchor_view)
+ : BubbleDialogDelegateView(anchor_view, BubbleBorder::TOP_LEFT) {
+ SetButtons(ui::DIALOG_BUTTON_NONE);
+ SetLayoutManager(std::make_unique<FillLayout>());
+ AddChildView(std::make_unique<View>())->SetPreferredSize(kTestViewSize);
+ }
+
+ protected:
+ void AddedToWidget() override {
+ BubbleDialogDelegateView::AddedToWidget();
+ SizeToContents();
+ }
+};
+
+class TestBubbleSlideAnimator : public BubbleSlideAnimator {
+ public:
+ using BubbleSlideAnimator::BubbleSlideAnimator;
+ ~TestBubbleSlideAnimator() override = default;
+
+ void AnimationContainerWasSet(gfx::AnimationContainer* container) override {
+ BubbleSlideAnimator::AnimationContainerWasSet(container);
+ container_test_api_.reset();
+ if (container) {
+ container_test_api_ =
+ std::make_unique<gfx::AnimationContainerTestApi>(container);
+ }
+ }
+
+ gfx::AnimationContainerTestApi* test_api() {
+ return container_test_api_.get();
+ }
+
+ private:
+ std::unique_ptr<gfx::AnimationContainerTestApi> container_test_api_;
+};
+
+} // namespace
+
+class BubbleSlideAnimatorTest : public test::WidgetTest {
+ public:
+ void SetUp() override {
+ test::WidgetTest::SetUp();
+ anchor_widget_ = CreateTestWidget(Widget::InitParams::Type::TYPE_WINDOW);
+ auto* const contents_view = anchor_widget_->GetRootView()->AddChildView(
+ std::make_unique<FlexLayoutView>());
+ contents_view->SetOrientation(LayoutOrientation::kHorizontal);
+ contents_view->SetMainAxisAlignment(LayoutAlignment::kStart);
+ contents_view->SetCrossAxisAlignment(LayoutAlignment::kStart);
+ view1_ = contents_view->AddChildView(std::make_unique<View>());
+ view2_ = contents_view->AddChildView(std::make_unique<View>());
+ view3_ = contents_view->AddChildView(std::make_unique<View>());
+ view1_->SetPreferredSize(kTestViewSize);
+ view2_->SetPreferredSize(kTestViewSize);
+ view3_->SetPreferredSize(kTestViewSize);
+ anchor_widget_->Show();
+ anchor_widget_->SetBounds(kAnchorWidgetRect);
+ bubble_ = new TestBubbleView(view1_);
+ widget_ = BubbleDialogDelegateView::CreateBubble(bubble_);
+ delegate_ = std::make_unique<TestBubbleSlideAnimator>(bubble_);
+ delegate_->SetSlideDuration(kSlideDuration);
+ }
+
+ void TearDown() override {
+ CloseWidget();
+ if (anchor_widget_ && !anchor_widget_->IsClosed())
+ anchor_widget_->CloseNow();
+ test::WidgetTest::TearDown();
+ }
+
+ void CloseWidget() {
+ if (widget_ && !widget_->IsClosed())
+ widget_->CloseNow();
+ widget_ = nullptr;
+ bubble_ = nullptr;
+ }
+
+ protected:
+ std::unique_ptr<Widget> anchor_widget_;
+ BubbleDialogDelegateView* bubble_ = nullptr;
+ Widget* widget_ = nullptr;
+ View* view1_;
+ View* view2_;
+ View* view3_;
+ std::unique_ptr<TestBubbleSlideAnimator> delegate_;
+};
+
+TEST_F(BubbleSlideAnimatorTest, InitiateSlide) {
+ const auto bounds = widget_->GetWindowBoundsInScreen();
+ delegate_->AnimateToAnchorView(view2_);
+ // Shouldn't animate from here yet.
+ EXPECT_EQ(bounds, widget_->GetWindowBoundsInScreen());
+ EXPECT_TRUE(delegate_->is_animating());
+}
+
+TEST_F(BubbleSlideAnimatorTest, SlideProgresses) {
+ const auto starting_bounds = widget_->GetWindowBoundsInScreen();
+ delegate_->AnimateToAnchorView(view2_);
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+ const auto intermediate_bounds = widget_->GetWindowBoundsInScreen();
+ EXPECT_TRUE(delegate_->is_animating());
+ EXPECT_EQ(intermediate_bounds.y(), starting_bounds.y());
+ EXPECT_GT(intermediate_bounds.x(), starting_bounds.x());
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+ const auto final_bounds = widget_->GetWindowBoundsInScreen();
+ EXPECT_FALSE(delegate_->is_animating());
+ EXPECT_EQ(final_bounds.y(), starting_bounds.y());
+ EXPECT_GT(final_bounds.x(), intermediate_bounds.x());
+ EXPECT_EQ(final_bounds.x(), starting_bounds.x() + view2_->x() - view1_->x());
+}
+
+TEST_F(BubbleSlideAnimatorTest, SnapToAnchorView) {
+ const auto starting_bounds = widget_->GetWindowBoundsInScreen();
+ delegate_->SnapToAnchorView(view2_);
+ const auto final_bounds = widget_->GetWindowBoundsInScreen();
+ EXPECT_FALSE(delegate_->is_animating());
+ EXPECT_EQ(final_bounds.y(), starting_bounds.y());
+ EXPECT_EQ(final_bounds.x(), starting_bounds.x() + view2_->x() - view1_->x());
+}
+
+TEST_F(BubbleSlideAnimatorTest, SlideCallbacksCalled) {
+ int progress_count = 0;
+ int complete_count = 0;
+ double last_progress = 0.0;
+ auto progress_sub = delegate_->AddSlideProgressedCallback(
+ base::BindLambdaForTesting([&](BubbleSlideAnimator*, double progress) {
+ last_progress = progress;
+ ++progress_count;
+ }));
+ auto completed_sub =
+ delegate_->AddSlideCompleteCallback(base::BindLambdaForTesting(
+ [&](BubbleSlideAnimator*) { ++complete_count; }));
+ delegate_->AnimateToAnchorView(view2_);
+ EXPECT_EQ(0, progress_count);
+ EXPECT_EQ(0, complete_count);
+ EXPECT_EQ(0.0, last_progress);
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+ EXPECT_EQ(1, progress_count);
+ EXPECT_EQ(0, complete_count);
+ EXPECT_GT(last_progress, 0.0);
+ EXPECT_LT(last_progress, 1.0);
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+ EXPECT_EQ(2, progress_count);
+ EXPECT_EQ(1, complete_count);
+ EXPECT_EQ(1.0, last_progress);
+}
+
+TEST_F(BubbleSlideAnimatorTest, SnapCallbacksCalled) {
+ int progress_count = 0;
+ int complete_count = 0;
+ double last_progress = 0.0;
+ auto progress_sub = delegate_->AddSlideProgressedCallback(
+ base::BindLambdaForTesting([&](BubbleSlideAnimator*, double progress) {
+ last_progress = progress;
+ ++progress_count;
+ }));
+ auto completed_sub =
+ delegate_->AddSlideCompleteCallback(base::BindLambdaForTesting(
+ [&](BubbleSlideAnimator*) { ++complete_count; }));
+ delegate_->SnapToAnchorView(view2_);
+ EXPECT_EQ(1, progress_count);
+ EXPECT_EQ(1, complete_count);
+ EXPECT_EQ(1.0, last_progress);
+}
+
+TEST_F(BubbleSlideAnimatorTest, InterruptingWithSlideCallsCorrectCallbacks) {
+ int progress_count = 0;
+ int complete_count = 0;
+ double last_progress = 0.0;
+ auto progress_sub = delegate_->AddSlideProgressedCallback(
+ base::BindLambdaForTesting([&](BubbleSlideAnimator*, double progress) {
+ last_progress = progress;
+ ++progress_count;
+ }));
+ auto completed_sub =
+ delegate_->AddSlideCompleteCallback(base::BindLambdaForTesting(
+ [&](BubbleSlideAnimator*) { ++complete_count; }));
+ delegate_->AnimateToAnchorView(view2_);
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+ EXPECT_EQ(1, progress_count);
+ EXPECT_EQ(0, complete_count);
+ delegate_->AnimateToAnchorView(view3_);
+ EXPECT_EQ(1, progress_count);
+ EXPECT_EQ(0, complete_count);
+ delegate_->test_api()->IncrementTime(kSlideDuration);
+ EXPECT_EQ(2, progress_count);
+ EXPECT_EQ(1, complete_count);
+}
+
+TEST_F(BubbleSlideAnimatorTest, InterruptingWithSnapCallsCorrectCallbacks) {
+ int progress_count = 0;
+ int complete_count = 0;
+ double last_progress = 0.0;
+ auto progress_sub = delegate_->AddSlideProgressedCallback(
+ base::BindLambdaForTesting([&](BubbleSlideAnimator*, double progress) {
+ last_progress = progress;
+ ++progress_count;
+ }));
+ auto completed_sub =
+ delegate_->AddSlideCompleteCallback(base::BindLambdaForTesting(
+ [&](BubbleSlideAnimator*) { ++complete_count; }));
+ delegate_->AnimateToAnchorView(view2_);
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+ EXPECT_EQ(1, progress_count);
+ EXPECT_EQ(0, complete_count);
+ delegate_->SnapToAnchorView(view3_);
+ EXPECT_EQ(2, progress_count);
+ EXPECT_EQ(1, complete_count);
+ EXPECT_EQ(1.0, last_progress);
+}
+
+TEST_F(BubbleSlideAnimatorTest, CancelAnimation) {
+ int progress_count = 0;
+ int complete_count = 0;
+ double last_progress = 0.0;
+ auto progress_sub = delegate_->AddSlideProgressedCallback(
+ base::BindLambdaForTesting([&](BubbleSlideAnimator*, double progress) {
+ last_progress = progress;
+ ++progress_count;
+ }));
+ auto completed_sub =
+ delegate_->AddSlideCompleteCallback(base::BindLambdaForTesting(
+ [&](BubbleSlideAnimator*) { ++complete_count; }));
+
+ const auto initial_bounds = widget_->GetWindowBoundsInScreen();
+ delegate_->AnimateToAnchorView(view2_);
+ delegate_->test_api()->IncrementTime(kSlideDuration);
+ const auto second_bounds = widget_->GetWindowBoundsInScreen();
+ delegate_->AnimateToAnchorView(view1_);
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+ const auto final_bounds = widget_->GetWindowBoundsInScreen();
+ delegate_->StopAnimation();
+ EXPECT_FALSE(delegate_->is_animating());
+ EXPECT_EQ(2, progress_count);
+ EXPECT_EQ(1, complete_count);
+ EXPECT_GT(last_progress, 0.0);
+ EXPECT_LT(last_progress, 1.0);
+ EXPECT_GT(final_bounds.x(), initial_bounds.x());
+ EXPECT_LT(final_bounds.x(), second_bounds.x());
+}
+
+TEST_F(BubbleSlideAnimatorTest, MultipleSlidesInSequence) {
+ // First slide.
+ delegate_->AnimateToAnchorView(view2_);
+ delegate_->test_api()->IncrementTime(kSlideDuration);
+ const auto first_bounds = widget_->GetWindowBoundsInScreen();
+ EXPECT_FALSE(delegate_->is_animating());
+
+ // Second slide.
+ delegate_->AnimateToAnchorView(view3_);
+ EXPECT_TRUE(delegate_->is_animating());
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+
+ // Ensure we are sliding.
+ const auto intermediate_bounds = widget_->GetWindowBoundsInScreen();
+ EXPECT_TRUE(delegate_->is_animating());
+ EXPECT_EQ(intermediate_bounds.y(), first_bounds.y());
+ EXPECT_GT(intermediate_bounds.x(), first_bounds.x());
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+
+ // Ensure we're done.
+ const auto final_bounds = widget_->GetWindowBoundsInScreen();
+ EXPECT_FALSE(delegate_->is_animating());
+ EXPECT_EQ(final_bounds.y(), first_bounds.y());
+ EXPECT_EQ(final_bounds.x(), first_bounds.x() + view3_->x() - view2_->x());
+}
+
+TEST_F(BubbleSlideAnimatorTest, SlideBackToStartingPosition) {
+ const auto first_bounds = widget_->GetWindowBoundsInScreen();
+ delegate_->AnimateToAnchorView(view3_);
+ delegate_->test_api()->IncrementTime(kSlideDuration);
+ delegate_->AnimateToAnchorView(view1_);
+ delegate_->test_api()->IncrementTime(kSlideDuration);
+ const auto final_bounds = widget_->GetWindowBoundsInScreen();
+ EXPECT_FALSE(delegate_->is_animating());
+ EXPECT_EQ(final_bounds, first_bounds);
+}
+
+TEST_F(BubbleSlideAnimatorTest, InterruptingSlide) {
+ const auto starting_bounds = widget_->GetWindowBoundsInScreen();
+
+ // Start the first slide.
+ delegate_->AnimateToAnchorView(view2_);
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+ const auto intermediate_bounds1 = widget_->GetWindowBoundsInScreen();
+ EXPECT_TRUE(delegate_->is_animating());
+
+ // Interrupt mid-slide with another slide.
+ delegate_->AnimateToAnchorView(view3_);
+ EXPECT_TRUE(delegate_->is_animating());
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+
+ // Ensure we are sliding.
+ const auto intermediate_bounds2 = widget_->GetWindowBoundsInScreen();
+ EXPECT_TRUE(delegate_->is_animating());
+ EXPECT_EQ(intermediate_bounds2.y(), intermediate_bounds1.y());
+ EXPECT_GT(intermediate_bounds2.x(), intermediate_bounds1.x());
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+
+ // Ensure we are done.
+ const auto final_bounds = widget_->GetWindowBoundsInScreen();
+ EXPECT_FALSE(delegate_->is_animating());
+ EXPECT_EQ(final_bounds.y(), starting_bounds.y());
+ EXPECT_EQ(final_bounds.x(), starting_bounds.x() + view3_->x() - view1_->x());
+}
+
+TEST_F(BubbleSlideAnimatorTest, WidgetClosedDuringSlide) {
+ delegate_->AnimateToAnchorView(view2_);
+ CloseWidget();
+ EXPECT_FALSE(delegate_->is_animating());
+}
+
+TEST_F(BubbleSlideAnimatorTest, AnimatorDestroyedDuringSlide) {
+ delegate_->AnimateToAnchorView(view2_);
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+ delegate_.reset();
+}
+
+TEST_F(BubbleSlideAnimatorTest, AnimationSetsAnchorView) {
+ delegate_->AnimateToAnchorView(view2_);
+ delegate_->test_api()->IncrementTime(kSlideDuration);
+ EXPECT_EQ(view2_, bubble_->GetAnchorView());
+ delegate_->AnimateToAnchorView(view3_);
+ delegate_->test_api()->IncrementTime(kSlideDuration);
+ EXPECT_EQ(view3_, bubble_->GetAnchorView());
+}
+
+TEST_F(BubbleSlideAnimatorTest, SnapSetsAnchorView) {
+ delegate_->SnapToAnchorView(view2_);
+ EXPECT_EQ(view2_, bubble_->GetAnchorView());
+ delegate_->SnapToAnchorView(view3_);
+ EXPECT_EQ(view3_, bubble_->GetAnchorView());
+}
+
+TEST_F(BubbleSlideAnimatorTest, CancelDoesntSetAnchorView) {
+ delegate_->AnimateToAnchorView(view2_);
+ delegate_->test_api()->IncrementTime(kHalfSlideDuration);
+ delegate_->StopAnimation();
+ EXPECT_EQ(view1_, bubble_->GetAnchorView());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/animation/compositor_animation_runner.h b/chromium/ui/views/animation/compositor_animation_runner.h
index 2f26f8d2948..b2e543eb643 100644
--- a/chromium/ui/views/animation/compositor_animation_runner.h
+++ b/chromium/ui/views/animation/compositor_animation_runner.h
@@ -7,7 +7,6 @@
#include <memory>
-#include "base/scoped_observer.h"
#include "base/time/time.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_animation_observer.h"
diff --git a/chromium/ui/views/animation/ink_drop.cc b/chromium/ui/views/animation/ink_drop.cc
index 98a62557a72..9eb25dfdcb6 100644
--- a/chromium/ui/views/animation/ink_drop.cc
+++ b/chromium/ui/views/animation/ink_drop.cc
@@ -5,6 +5,7 @@
#include "ui/views/animation/ink_drop.h"
#include "ui/views/animation/ink_drop_observer.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
namespace views {
@@ -52,4 +53,7 @@ bool InkDropContainerView::GetCanProcessEventsWithinSubtree() const {
return false;
}
+BEGIN_METADATA(InkDropContainerView, views::View)
+END_METADATA
+
} // namespace views
diff --git a/chromium/ui/views/animation/ink_drop.h b/chromium/ui/views/animation/ink_drop.h
index 287fd1e25ef..5260dab3cbc 100644
--- a/chromium/ui/views/animation/ink_drop.h
+++ b/chromium/ui/views/animation/ink_drop.h
@@ -7,13 +7,13 @@
#include <memory>
-#include "base/macros.h"
#include "base/time/time.h"
#include "ui/compositor/layer_tree_owner.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/animation/ink_drop_state.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/view.h"
#include "ui/views/views_export.h"
@@ -25,6 +25,8 @@ class InkDropObserver;
// well as visual hover state feedback.
class VIEWS_EXPORT InkDrop {
public:
+ InkDrop(const InkDrop&) = delete;
+ InkDrop& operator=(const InkDrop&) = delete;
virtual ~InkDrop();
// Called by ink drop hosts when their size is changed.
@@ -84,8 +86,6 @@ class VIEWS_EXPORT InkDrop {
private:
base::ObserverList<InkDropObserver>::Unchecked observers_;
-
- DISALLOW_COPY_AND_ASSIGN(InkDrop);
};
// A View which can be used to parent ink drop layers. Typically this is used
@@ -94,16 +94,16 @@ class VIEWS_EXPORT InkDrop {
// rendering enabled are painted onto a non-opaque canvas.
class VIEWS_EXPORT InkDropContainerView : public views::View {
public:
+ METADATA_HEADER(InkDropContainerView);
InkDropContainerView();
+ InkDropContainerView(const InkDropContainerView&) = delete;
+ InkDropContainerView& operator=(const InkDropContainerView&) = delete;
void AddInkDropLayer(ui::Layer* ink_drop_layer);
void RemoveInkDropLayer(ui::Layer* ink_drop_layer);
// View:
bool GetCanProcessEventsWithinSubtree() const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InkDropContainerView);
};
} // namespace views
diff --git a/chromium/ui/views/animation/ink_drop_event_handler.cc b/chromium/ui/views/animation/ink_drop_event_handler.cc
index 3b9b3aa2a2a..d0771c26ccd 100644
--- a/chromium/ui/views/animation/ink_drop_event_handler.cc
+++ b/chromium/ui/views/animation/ink_drop_event_handler.cc
@@ -18,7 +18,7 @@ InkDropEventHandler::InkDropEventHandler(View* host_view, Delegate* delegate)
std::make_unique<ui::ScopedTargetHandler>(host_view, this)),
host_view_(host_view),
delegate_(delegate) {
- observer_.Add(host_view_);
+ observation_.Observe(host_view_);
}
InkDropEventHandler::~InkDropEventHandler() = default;
@@ -113,6 +113,10 @@ void InkDropEventHandler::OnMouseEvent(ui::MouseEvent* event) {
}
}
+base::StringPiece InkDropEventHandler::GetLogContext() const {
+ return "InkDropEventHandler";
+}
+
void InkDropEventHandler::OnViewVisibilityChanged(View* observed_view,
View* starting_view) {
DCHECK_EQ(host_view_, observed_view);
diff --git a/chromium/ui/views/animation/ink_drop_event_handler.h b/chromium/ui/views/animation/ink_drop_event_handler.h
index 7b402b1303f..ebc957908aa 100644
--- a/chromium/ui/views/animation/ink_drop_event_handler.h
+++ b/chromium/ui/views/animation/ink_drop_event_handler.h
@@ -7,7 +7,8 @@
#include <memory>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
+#include "base/strings/string_piece.h"
#include "ui/events/event_handler.h"
#include "ui/views/view.h"
#include "ui/views/view_observer.h"
@@ -50,6 +51,7 @@ class VIEWS_EXPORT InkDropEventHandler : public ui::EventHandler,
// ui::EventHandler:
void OnGestureEvent(ui::GestureEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
+ base::StringPiece GetLogContext() const override;
// ViewObserver:
void OnViewVisibilityChanged(View* observed_view,
@@ -73,7 +75,7 @@ class VIEWS_EXPORT InkDropEventHandler : public ui::EventHandler,
// The last user Event to trigger an InkDrop-ripple animation.
std::unique_ptr<ui::LocatedEvent> last_ripple_triggering_event_;
- ScopedObserver<View, ViewObserver> observer_{this};
+ base::ScopedObservation<View, ViewObserver> observation_{this};
DISALLOW_COPY_AND_ASSIGN(InkDropEventHandler);
};
diff --git a/chromium/ui/views/animation/ink_drop_host_view.cc b/chromium/ui/views/animation/ink_drop_host_view.cc
index 6b66522cda6..23d77f89c96 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.cc
+++ b/chromium/ui/views/animation/ink_drop_host_view.cc
@@ -182,7 +182,7 @@ bool InkDropHostView::GetHighlighted() const {
return ink_drop_ && ink_drop_->IsHighlightFadingInOrVisible();
}
-PropertyChangedSubscription InkDropHostView::AddHighlightedChangedCallback(
+base::CallbackListSubscription InkDropHostView::AddHighlightedChangedCallback(
PropertyChangedCallback callback) {
// Since the highlight state is not directly represented by a member, use the
// applicable member (|ink_drop_|) as the property key. Note that this won't
diff --git a/chromium/ui/views/animation/ink_drop_host_view.h b/chromium/ui/views/animation/ink_drop_host_view.h
index ce6581cbc3c..8c8f77fc26d 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.h
+++ b/chromium/ui/views/animation/ink_drop_host_view.h
@@ -135,7 +135,7 @@ class VIEWS_EXPORT InkDropHostView : public View {
// animating into "highlight visible" steady state).
bool GetHighlighted() const;
- PropertyChangedSubscription AddHighlightedChangedCallback(
+ base::CallbackListSubscription AddHighlightedChangedCallback(
PropertyChangedCallback callback);
// Should be called by InkDrop implementations when their highlight state
diff --git a/chromium/ui/views/animation/ink_drop_painted_layer_delegates.h b/chromium/ui/views/animation/ink_drop_painted_layer_delegates.h
index c2090df5fe6..82b6763e2a8 100644
--- a/chromium/ui/views/animation/ink_drop_painted_layer_delegates.h
+++ b/chromium/ui/views/animation/ink_drop_painted_layer_delegates.h
@@ -35,11 +35,12 @@ class VIEWS_EXPORT BasePaintedLayerDelegate : public ui::LayerDelegate {
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) override;
+ SkColor color() const { return color_; }
+ void set_color(SkColor color) { color_ = color; }
+
protected:
explicit BasePaintedLayerDelegate(SkColor color);
- SkColor color() const { return color_; }
-
private:
// The color to paint.
SkColor color_;
diff --git a/chromium/ui/views/animation/installable_ink_drop.cc b/chromium/ui/views/animation/installable_ink_drop.cc
index 2701886375c..dd71277ce49 100644
--- a/chromium/ui/views/animation/installable_ink_drop.cc
+++ b/chromium/ui/views/animation/installable_ink_drop.cc
@@ -109,7 +109,7 @@ void InstallableInkDrop::SetConfig(InstallableInkDropConfig config) {
SchedulePaint();
}
-std::unique_ptr<base::RepeatingClosureList::Subscription>
+base::CallbackListSubscription
InstallableInkDrop::RegisterHighlightedChangedCallback(
base::RepeatingClosure callback) {
return highlighted_changed_list_.Add(std::move(callback));
diff --git a/chromium/ui/views/animation/installable_ink_drop.h b/chromium/ui/views/animation/installable_ink_drop.h
index c46a3929cc2..1b91ea19e0f 100644
--- a/chromium/ui/views/animation/installable_ink_drop.h
+++ b/chromium/ui/views/animation/installable_ink_drop.h
@@ -63,8 +63,8 @@ class VIEWS_EXPORT InstallableInkDrop : public InkDrop,
InstallableInkDropConfig config() const { return config_; }
// Registers |callback| to be called whenever the highlighted state changes.
- std::unique_ptr<base::RepeatingClosureList::Subscription>
- RegisterHighlightedChangedCallback(base::RepeatingClosure callback);
+ base::CallbackListSubscription RegisterHighlightedChangedCallback(
+ base::RepeatingClosure callback);
// Should only be used for inspecting properties of the layer in tests.
const ui::Layer* layer_for_testing() const { return layer_.get(); }
diff --git a/chromium/ui/views/animation/widget_fade_animator.cc b/chromium/ui/views/animation/widget_fade_animator.cc
new file mode 100644
index 00000000000..5a4b69c2e0b
--- /dev/null
+++ b/chromium/ui/views/animation/widget_fade_animator.cc
@@ -0,0 +1,104 @@
+// Copyright 2021 The Chromium 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/animation/widget_fade_animator.h"
+
+#include "ui/gfx/animation/linear_animation.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+WidgetFadeAnimator::WidgetFadeAnimator(Widget* widget)
+ : AnimationDelegateViews(widget->GetRootView()), widget_(widget) {
+ widget_observation_.Observe(widget);
+}
+
+WidgetFadeAnimator::~WidgetFadeAnimator() = default;
+
+void WidgetFadeAnimator::FadeIn() {
+ if (IsFadingIn())
+ return;
+
+ DCHECK(widget_);
+
+ animation_type_ = FadeType::kFadeIn;
+ fade_animation_.SetDuration(fade_in_duration_);
+
+ // Widgets cannot be shown when visible and fully transparent.
+ widget_->SetOpacity(0.01f);
+ widget_->Show();
+ fade_animation_.Start();
+}
+
+void WidgetFadeAnimator::FadeOut() {
+ if (IsFadingOut())
+ return;
+
+ DCHECK(widget_);
+
+ // If the widget is already hidden, then there is no current animation and
+ // nothing to do. If the animation is close-on-hide, however, we should still
+ // close the widget.
+ if (!widget_->IsVisible()) {
+ DCHECK(!IsFadingIn());
+ if (close_on_hide_)
+ widget_->Close();
+ fade_complete_callbacks_.Notify(this, FadeType::kFadeOut);
+ return;
+ }
+
+ animation_type_ = FadeType::kFadeOut;
+ fade_animation_.SetDuration(fade_out_duration_);
+ fade_animation_.Start();
+}
+
+void WidgetFadeAnimator::CancelFadeOut() {
+ if (!IsFadingOut())
+ return;
+
+ fade_animation_.Stop();
+ animation_type_ = FadeType::kNone;
+ widget_->SetOpacity(1.0f);
+}
+
+base::CallbackListSubscription WidgetFadeAnimator::AddFadeCompleteCallback(
+ FadeCompleteCallback callback) {
+ return fade_complete_callbacks_.Add(callback);
+}
+
+void WidgetFadeAnimator::AnimationProgressed(const gfx::Animation* animation) {
+ // Get the value of the animation with a material ease applied.
+ double value =
+ gfx::Tween::CalculateValue(tween_type_, animation->GetCurrentValue());
+ float opacity = 0.0f;
+ if (IsFadingOut())
+ opacity = gfx::Tween::FloatValueBetween(value, 1.0f, 0.0f);
+ else if (IsFadingIn())
+ opacity = gfx::Tween::FloatValueBetween(value, 0.0f, 1.0f);
+
+ if (IsFadingOut() && opacity == 0.0f) {
+ if (close_on_hide_)
+ widget_->Close();
+ else
+ widget_->Hide();
+ } else {
+ widget_->SetOpacity(opacity);
+ }
+}
+
+void WidgetFadeAnimator::AnimationEnded(const gfx::Animation* animation) {
+ const FadeType animation_type = animation_type_;
+ AnimationProgressed(animation);
+ animation_type_ = FadeType::kNone;
+ fade_complete_callbacks_.Notify(this, animation_type);
+}
+
+void WidgetFadeAnimator::OnWidgetClosing(Widget* widget) {
+ widget_observation_.Reset();
+ fade_animation_.End();
+ animation_type_ = FadeType::kNone;
+ widget_ = nullptr;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/animation/widget_fade_animator.h b/chromium/ui/views/animation/widget_fade_animator.h
new file mode 100644
index 00000000000..e0a20b1b94f
--- /dev/null
+++ b/chromium/ui/views/animation/widget_fade_animator.h
@@ -0,0 +1,125 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_ANIMATION_WIDGET_FADE_ANIMATOR_H_
+#define UI_VIEWS_ANIMATION_WIDGET_FADE_ANIMATOR_H_
+
+#include "base/callback_forward.h"
+#include "base/callback_list.h"
+#include "base/scoped_observation.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
+#include "ui/gfx/animation/linear_animation.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/views/animation/animation_delegate_views.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_observer.h"
+
+namespace views {
+
+class Widget;
+
+// Animates a widget's opacity between fully hidden and fully shown, providing
+// a fade-in/fade-out effect.
+class VIEWS_EXPORT WidgetFadeAnimator : public AnimationDelegateViews,
+ public WidgetObserver {
+ public:
+ // Describes the current fade animation.
+ enum class FadeType {
+ kNone,
+ kFadeIn,
+ kFadeOut,
+ };
+
+ // Defines a callback for when a fade completes. Not called on cancel. The
+ // |animation_type| of the completed animation is specified (it will never be
+ // kNone).
+ using FadeCompleteCallbackSignature = void(WidgetFadeAnimator*,
+ FadeType animation_type);
+ using FadeCompleteCallback =
+ base::RepeatingCallback<FadeCompleteCallbackSignature>;
+
+ // Creates a new fade animator for the specified widget. If the widget closes
+ // the animator will no longer be valid and should not be used.
+ explicit WidgetFadeAnimator(Widget* widget);
+ WidgetFadeAnimator(const WidgetFadeAnimator&) = delete;
+ WidgetFadeAnimator& operator=(const WidgetFadeAnimator&) = delete;
+ ~WidgetFadeAnimator() override;
+
+ void set_fade_in_duration(base::TimeDelta fade_in_duration) {
+ fade_in_duration_ = fade_in_duration;
+ }
+ base::TimeDelta fade_in_duration() const { return fade_in_duration_; }
+
+ void set_fade_out_duration(base::TimeDelta fade_out_duration) {
+ fade_out_duration_ = fade_out_duration;
+ }
+ base::TimeDelta fade_out_duration() const { return fade_out_duration_; }
+
+ void set_tween_type(gfx::Tween::Type tween_type) { tween_type_ = tween_type; }
+ gfx::Tween::Type tween_type() const { return tween_type_; }
+
+ void set_close_on_hide(bool close_on_hide) { close_on_hide_ = close_on_hide; }
+ bool close_on_hide() const { return close_on_hide_; }
+
+ Widget* widget() { return widget_; }
+
+ bool IsFadingIn() const { return animation_type_ == FadeType::kFadeIn; }
+
+ bool IsFadingOut() const { return animation_type_ == FadeType::kFadeOut; }
+
+ // Plays the fade-in animation. If the widget is not currently visible, it
+ // will be made visible.
+ void FadeIn();
+
+ // Plays the fade-out animation. At the end of the fade, the widget will be
+ // hidden or closed, as per |close_on_hide|. If the widget is already hidden
+ // or closed, completes immediately.
+ void FadeOut();
+
+ // Cancels any pending fade-out, returning the widget to 100% opacity. Has no
+ // effect if the widget is not fading out.
+ void CancelFadeOut();
+
+ // Adds a listener for fade complete events.
+ base::CallbackListSubscription AddFadeCompleteCallback(
+ FadeCompleteCallback callback);
+
+ private:
+ // AnimationDelegateViews:
+ void AnimationProgressed(const gfx::Animation* animation) override;
+ void AnimationEnded(const gfx::Animation* animation) override;
+
+ // WidgetObserver:
+ void OnWidgetClosing(Widget* widget) override;
+
+ Widget* widget_;
+ base::ScopedObservation<Widget, WidgetObserver> widget_observation_{this};
+ gfx::LinearAnimation fade_animation_{this};
+ FadeType animation_type_ = FadeType::kNone;
+
+ // Duration for fade-in animations. The default should be visually pleasing
+ // for most applications.
+ base::TimeDelta fade_in_duration_ = base::TimeDelta::FromMilliseconds(200);
+
+ // Duration for fade-out animations. The default should be visually pleasing
+ // for most applications.
+ base::TimeDelta fade_out_duration_ = base::TimeDelta::FromMilliseconds(150);
+
+ // The tween type to use. The default value should be pleasing for most
+ // applications.
+ gfx::Tween::Type tween_type_ = gfx::Tween::FAST_OUT_SLOW_IN;
+
+ // Whether the widget should be closed at the end of a fade-out animation.
+ bool close_on_hide_ = false;
+
+ base::RepeatingCallbackList<FadeCompleteCallbackSignature>
+ fade_complete_callbacks_;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ANIMATION_WIDGET_FADE_ANIMATOR_H_
diff --git a/chromium/ui/views/animation/widget_fade_animator_unittest.cc b/chromium/ui/views/animation/widget_fade_animator_unittest.cc
new file mode 100644
index 00000000000..bc5e1787e2b
--- /dev/null
+++ b/chromium/ui/views/animation/widget_fade_animator_unittest.cc
@@ -0,0 +1,276 @@
+// Copyright 2021 The Chromium 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/animation/widget_fade_animator.h"
+
+#include <memory>
+
+#include "base/test/bind.h"
+#include "base/time/time.h"
+#include "ui/gfx/animation/animation_test_api.h"
+#include "ui/views/test/widget_test.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+namespace {
+
+constexpr base::TimeDelta kFadeDuration =
+ base::TimeDelta::FromMilliseconds(1000);
+constexpr base::TimeDelta kHalfFadeDuration = kFadeDuration / 2;
+
+class TestWidgetFadeAnimator : public WidgetFadeAnimator {
+ public:
+ using WidgetFadeAnimator::WidgetFadeAnimator;
+ ~TestWidgetFadeAnimator() override = default;
+
+ void AnimationContainerWasSet(gfx::AnimationContainer* container) override {
+ WidgetFadeAnimator::AnimationContainerWasSet(container);
+ container_test_api_.reset();
+ if (container) {
+ container_test_api_ =
+ std::make_unique<gfx::AnimationContainerTestApi>(container);
+ }
+ }
+
+ gfx::AnimationContainerTestApi* test_api() {
+ return container_test_api_.get();
+ }
+
+ private:
+ std::unique_ptr<gfx::AnimationContainerTestApi> container_test_api_;
+};
+
+} // namespace
+
+class WidgetFadeAnimatorTest : public test::WidgetTest {
+ public:
+ void SetUp() override {
+ test::WidgetTest::SetUp();
+ widget_ = CreateTestWidget(Widget::InitParams::Type::TYPE_WINDOW);
+ delegate_ = std::make_unique<TestWidgetFadeAnimator>(widget_.get());
+ delegate_->set_fade_in_duration(kFadeDuration);
+ delegate_->set_fade_out_duration(kFadeDuration);
+ }
+
+ void TearDown() override {
+ if (widget_ && !widget_->IsClosed())
+ widget_->CloseNow();
+ test::WidgetTest::TearDown();
+ }
+
+ protected:
+ std::unique_ptr<Widget> widget_;
+ std::unique_ptr<TestWidgetFadeAnimator> delegate_;
+};
+
+TEST_F(WidgetFadeAnimatorTest, FadeIn) {
+ EXPECT_FALSE(widget_->IsVisible());
+ delegate_->FadeIn();
+ // Fade in should set visibility and opacity to some small value.
+ EXPECT_TRUE(widget_->IsVisible());
+ EXPECT_TRUE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+}
+
+TEST_F(WidgetFadeAnimatorTest, FadeInAnimationProgressesToEnd) {
+ delegate_->FadeIn();
+ // Note that there is currently no way to *read* a widget's opacity, so we can
+ // only verify that the widget's visibility changes appropriately at the
+ // beginning and end of each animation.
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_TRUE(widget_->IsVisible());
+ EXPECT_TRUE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_TRUE(widget_->IsVisible());
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+}
+
+TEST_F(WidgetFadeAnimatorTest, FadeOut) {
+ widget_->Show();
+ EXPECT_TRUE(widget_->IsVisible());
+ delegate_->FadeOut();
+ // Fade in should set visibility and opacity to some small value.
+ EXPECT_TRUE(widget_->IsVisible());
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_TRUE(delegate_->IsFadingOut());
+}
+
+TEST_F(WidgetFadeAnimatorTest, FadeOutAnimationProgressesToEnd) {
+ widget_->Show();
+ delegate_->FadeOut();
+ // Note that there is currently no way to *read* a widget's opacity, so we can
+ // only verify that the widget's visibility changes appropriately at the
+ // beginning and end of each animation.
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_TRUE(widget_->IsVisible());
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_TRUE(delegate_->IsFadingOut());
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_FALSE(widget_->IsVisible());
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+}
+
+TEST_F(WidgetFadeAnimatorTest, CancelFadeOutAtStart) {
+ widget_->Show();
+ delegate_->FadeOut();
+ delegate_->CancelFadeOut();
+ EXPECT_TRUE(widget_->IsVisible());
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+}
+
+TEST_F(WidgetFadeAnimatorTest, CancelFadeOutInMiddle) {
+ widget_->Show();
+ delegate_->FadeOut();
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ delegate_->CancelFadeOut();
+ EXPECT_TRUE(widget_->IsVisible());
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+}
+
+TEST_F(WidgetFadeAnimatorTest, CancelFadeOutAtEndHasNoEffect) {
+ widget_->Show();
+ delegate_->FadeOut();
+ delegate_->test_api()->IncrementTime(kFadeDuration);
+ delegate_->CancelFadeOut();
+ EXPECT_FALSE(widget_->IsVisible());
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+}
+
+TEST_F(WidgetFadeAnimatorTest, CancelFadeOutHasNoEffectIfFadingIn) {
+ delegate_->FadeIn();
+ delegate_->CancelFadeOut();
+ EXPECT_TRUE(widget_->IsVisible());
+ EXPECT_TRUE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ delegate_->CancelFadeOut();
+ EXPECT_TRUE(widget_->IsVisible());
+ EXPECT_TRUE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ delegate_->CancelFadeOut();
+ EXPECT_TRUE(widget_->IsVisible());
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+}
+
+TEST_F(WidgetFadeAnimatorTest, FadeOutClosesWidget) {
+ delegate_->set_close_on_hide(true);
+ widget_->Show();
+ delegate_->FadeOut();
+ delegate_->test_api()->IncrementTime(kFadeDuration);
+ EXPECT_TRUE(widget_->IsClosed());
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+}
+
+TEST_F(WidgetFadeAnimatorTest, WidgetClosedDuringFade) {
+ widget_->Show();
+ delegate_->FadeOut();
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ widget_->CloseNow();
+ EXPECT_FALSE(delegate_->IsFadingOut());
+}
+
+TEST_F(WidgetFadeAnimatorTest, WidgetDestroyedDuringFade) {
+ widget_->Show();
+ delegate_->FadeOut();
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ widget_->Close();
+ widget_.reset();
+ EXPECT_FALSE(delegate_->IsFadingOut());
+}
+
+TEST_F(WidgetFadeAnimatorTest, AnimatorDestroyedDuringFade) {
+ delegate_->FadeIn();
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ delegate_.reset();
+}
+
+TEST_F(WidgetFadeAnimatorTest, FadeOutInterruptsFadeIn) {
+ delegate_->FadeIn();
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ delegate_->FadeOut();
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_TRUE(delegate_->IsFadingOut());
+ EXPECT_TRUE(widget_->IsVisible());
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_TRUE(delegate_->IsFadingOut());
+ EXPECT_TRUE(widget_->IsVisible());
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+ EXPECT_FALSE(widget_->IsVisible());
+}
+
+TEST_F(WidgetFadeAnimatorTest, FadeInInterruptsFadeOut) {
+ widget_->Show();
+ delegate_->FadeOut();
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ delegate_->FadeIn();
+ EXPECT_TRUE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+ EXPECT_TRUE(widget_->IsVisible());
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_TRUE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+ EXPECT_TRUE(widget_->IsVisible());
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_FALSE(delegate_->IsFadingIn());
+ EXPECT_FALSE(delegate_->IsFadingOut());
+ EXPECT_TRUE(widget_->IsVisible());
+}
+
+TEST_F(WidgetFadeAnimatorTest, FadeInCallback) {
+ int called_count = 0;
+ WidgetFadeAnimator::FadeType anim_type = WidgetFadeAnimator::FadeType::kNone;
+
+ auto subscription =
+ delegate_->AddFadeCompleteCallback(base::BindLambdaForTesting(
+ [&](WidgetFadeAnimator*,
+ WidgetFadeAnimator::FadeType animation_type) {
+ ++called_count;
+ anim_type = animation_type;
+ }));
+
+ delegate_->FadeIn();
+ EXPECT_EQ(0, called_count);
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_EQ(0, called_count);
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_EQ(1, called_count);
+ EXPECT_EQ(WidgetFadeAnimator::FadeType::kFadeIn, anim_type);
+}
+
+TEST_F(WidgetFadeAnimatorTest, FadeOutCallback) {
+ int called_count = 0;
+ WidgetFadeAnimator::FadeType anim_type = WidgetFadeAnimator::FadeType::kNone;
+
+ auto subscription =
+ delegate_->AddFadeCompleteCallback(base::BindLambdaForTesting(
+ [&](WidgetFadeAnimator*,
+ WidgetFadeAnimator::FadeType animation_type) {
+ ++called_count;
+ anim_type = animation_type;
+ }));
+
+ widget_->Show();
+ delegate_->FadeOut();
+ EXPECT_EQ(0, called_count);
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_EQ(0, called_count);
+ delegate_->test_api()->IncrementTime(kHalfFadeDuration);
+ EXPECT_EQ(1, called_count);
+ EXPECT_EQ(WidgetFadeAnimator::FadeType::kFadeOut, anim_type);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/background.cc b/chromium/ui/views/background.cc
index 7ab9015b129..3cf74b720ad 100644
--- a/chromium/ui/views/background.cc
+++ b/chromium/ui/views/background.cc
@@ -8,7 +8,7 @@
#include "base/check.h"
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "build/build_config.h"
#include "cc/paint/paint_flags.h"
#include "ui/gfx/canvas.h"
@@ -67,15 +67,18 @@ class ThemedVectorIconBackground : public Background, public ViewObserver {
public:
explicit ThemedVectorIconBackground(View* view,
const ui::ThemedVectorIcon& icon)
- : icon_(icon), observer_(this) {
+ : icon_(icon) {
DCHECK(!icon_.empty());
- observer_.Add(view);
+ observation_.Observe(view);
OnViewThemeChanged(view);
}
// ViewObserver:
void OnViewThemeChanged(View* view) override { view->SchedulePaint(); }
- void OnViewIsDeleting(View* view) override { observer_.Remove(view); }
+ void OnViewIsDeleting(View* view) override {
+ DCHECK(observation_.IsObservingSource(view));
+ observation_.Reset();
+ }
void Paint(gfx::Canvas* canvas, View* view) const override {
canvas->DrawImageInt(icon_.GetImageSkia(view->GetNativeTheme()), 0, 0);
@@ -83,7 +86,7 @@ class ThemedVectorIconBackground : public Background, public ViewObserver {
private:
const ui::ThemedVectorIcon icon_;
- ScopedObserver<View, ViewObserver> observer_;
+ base::ScopedObservation<View, ViewObserver> observation_{this};
DISALLOW_COPY_AND_ASSIGN(ThemedVectorIconBackground);
};
@@ -94,9 +97,8 @@ class ThemedSolidBackground : public SolidBackground, public ViewObserver {
public:
explicit ThemedSolidBackground(View* view, ui::NativeTheme::ColorId color_id)
: SolidBackground(gfx::kPlaceholderColor),
- observer_(this),
color_id_(color_id) {
- observer_.Add(view);
+ observation_.Observe(view);
OnViewThemeChanged(view);
}
~ThemedSolidBackground() override = default;
@@ -106,10 +108,13 @@ class ThemedSolidBackground : public SolidBackground, public ViewObserver {
SetNativeControlColor(view->GetNativeTheme()->GetSystemColor(color_id_));
view->SchedulePaint();
}
- void OnViewIsDeleting(View* view) override { observer_.Remove(view); }
+ void OnViewIsDeleting(View* view) override {
+ DCHECK(observation_.IsObservingSource(view));
+ observation_.Reset();
+ }
private:
- ScopedObserver<View, ViewObserver> observer_;
+ base::ScopedObservation<View, ViewObserver> observation_{this};
ui::NativeTheme::ColorId color_id_;
DISALLOW_COPY_AND_ASSIGN(ThemedSolidBackground);
diff --git a/chromium/ui/views/bubble/DIR_METADATA b/chromium/ui/views/bubble/DIR_METADATA
new file mode 100644
index 00000000000..960749c7e7a
--- /dev/null
+++ b/chromium/ui/views/bubble/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI>Browser>Bubbles"
+}
diff --git a/chromium/ui/views/bubble/OWNERS b/chromium/ui/views/bubble/OWNERS
index 36fab0b26e1..3de6061df6e 100644
--- a/chromium/ui/views/bubble/OWNERS
+++ b/chromium/ui/views/bubble/OWNERS
@@ -1,5 +1,3 @@
msw@chromium.org
dfried@chromium.org
bsep@chromium.org
-
-# COMPONENT: UI>Browser>Bubbles
diff --git a/chromium/ui/views/bubble/bubble_border.cc b/chromium/ui/views/bubble/bubble_border.cc
index 22b609a91c5..7fb5850a438 100644
--- a/chromium/ui/views/bubble/bubble_border.cc
+++ b/chromium/ui/views/bubble/bubble_border.cc
@@ -97,7 +97,7 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
// 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()
+ shadow_ == NO_SHADOW || md_shadow_elevation_.has_value()
? gfx::Insets()
: gfx::Insets(kBorderThicknessDip);
const gfx::Insets shadow_insets = GetInsets() - border_insets;
@@ -154,9 +154,9 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
default:
NOTREACHED();
}
- // With NO_ASSETS, there should be further insets, but the same logic is
+ // With NO_SHADOW, 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) ||
+ DCHECK((shadow_ != NO_SHADOW && shadow_ != NO_SHADOW_LEGACY) ||
insets_.has_value() || shadow_insets.IsEmpty());
if (!avoid_shadow_overlap_)
contents_bounds.Inset(-shadow_insets);
@@ -174,7 +174,7 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
int w = anchor_rect.width();
int h = anchor_rect.height();
const gfx::Size size(GetSizeForContentsSize(contents_size));
- const int stroke_width = shadow_ == NO_ASSETS ? 0 : kStroke;
+ const int stroke_width = shadow_ == NO_SHADOW ? 0 : kStroke;
// Calculate the bubble coordinates based on the border and arrow settings.
if (is_arrow_on_horizontal(arrow_)) {
@@ -204,12 +204,12 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
}
void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
- if (shadow_ == NO_ASSETS)
- return PaintNoAssets(view, canvas);
-
if (shadow_ == NO_SHADOW)
return PaintNoShadow(view, canvas);
+ if (shadow_ == NO_SHADOW_LEGACY)
+ return PaintNoShadowLegacy(view, canvas);
+
gfx::ScopedCanvas scoped(canvas);
SkRRect r_rect = GetClientRect(view);
@@ -223,9 +223,9 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
gfx::Insets BubbleBorder::GetInsets() const {
if (insets_.has_value())
return insets_.value();
- if (shadow_ == NO_ASSETS)
- return gfx::Insets();
if (shadow_ == NO_SHADOW)
+ return gfx::Insets();
+ if (shadow_ == NO_SHADOW_LEGACY)
return gfx::Insets(kBorderThicknessDip);
return GetBorderAndShadowInsets(md_shadow_elevation_);
}
@@ -310,14 +310,14 @@ SkRRect BubbleBorder::GetClientRect(const View& view) const {
corner_radius());
}
-void BubbleBorder::PaintNoAssets(const View& view, gfx::Canvas* canvas) {
+void BubbleBorder::PaintNoShadow(const View& view, gfx::Canvas* canvas) {
gfx::ScopedCanvas scoped(canvas);
canvas->sk_canvas()->clipRRect(GetClientRect(view), SkClipOp::kDifference,
true /*doAntiAlias*/);
canvas->sk_canvas()->drawColor(SK_ColorTRANSPARENT, SkBlendMode::kSrc);
}
-void BubbleBorder::PaintNoShadow(const View& view, gfx::Canvas* canvas) {
+void BubbleBorder::PaintNoShadowLegacy(const View& view, gfx::Canvas* canvas) {
gfx::RectF bounds(view.GetLocalBounds());
bounds.Inset(gfx::InsetsF(kBorderThicknessDip / 2.0f));
cc::PaintFlags flags;
@@ -331,9 +331,6 @@ void BubbleBorder::PaintNoShadow(const View& view, gfx::Canvas* canvas) {
}
void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
- if (border_->shadow() == BubbleBorder::NO_SHADOW_OPAQUE_BORDER)
- canvas->DrawColor(border_->background_color());
-
// Fill the contents with a round-rect region to match the border images.
cc::PaintFlags flags;
flags.setAntiAlias(true);
diff --git a/chromium/ui/views/bubble/bubble_border.h b/chromium/ui/views/bubble/bubble_border.h
index 2aca6e2353a..6622b5b978c 100644
--- a/chromium/ui/views/bubble/bubble_border.h
+++ b/chromium/ui/views/bubble/bubble_border.h
@@ -60,21 +60,21 @@ class VIEWS_EXPORT BubbleBorder : public Border {
};
enum Shadow {
- NO_SHADOW = 0,
- NO_SHADOW_OPAQUE_BORDER,
- BIG_SHADOW,
- SMALL_SHADOW,
- // NO_ASSETS borders don't draw a stroke or a shadow. This is used for
- // platforms that provide their own shadows.
- NO_ASSETS,
+ // NO_SHADOW_LEGACY is obsolete. Used only for Win7 where custom shadows are
+ // not supported.
+ NO_SHADOW_LEGACY = 0,
+ STANDARD_SHADOW,
+ // NO_SHADOW don't draw a stroke or a shadow. This is used for platforms
+ // that provide their own shadows or UIs that doesn't need shadows.
+ NO_SHADOW,
SHADOW_COUNT,
#if defined(OS_APPLE)
// On Mac, the native window server should provide its own shadow for
// windows that could overlap the browser window.
- DIALOG_SHADOW = NO_ASSETS,
+ DIALOG_SHADOW = NO_SHADOW,
#else
- DIALOG_SHADOW = SMALL_SHADOW,
+ DIALOG_SHADOW = STANDARD_SHADOW,
#endif
};
@@ -238,13 +238,14 @@ class VIEWS_EXPORT BubbleBorder : public Border {
// draw over the contents of the bubble.
SkRRect GetClientRect(const View& view) const;
- // Paint for the NO_ASSETS shadow type. This just paints transparent pixels
+ // Paint for the NO_SHADOW shadow type. This just paints transparent pixels
// to make the window shape based on insets and GetBorderCornerRadius().
- void PaintNoAssets(const View& view, gfx::Canvas* canvas);
-
- // Paint for the NO_SHADOW shadow type. This paints a simple line border.
void PaintNoShadow(const View& view, gfx::Canvas* canvas);
+ // Paint for the NO_SHADOW_LEGACY shadow type. This paints a simple line
+ // border.
+ void PaintNoShadowLegacy(const View& view, gfx::Canvas* canvas);
+
Arrow arrow_;
int arrow_offset_;
// Corner radius for the bubble border. If supplied the border will use
diff --git a/chromium/ui/views/bubble/bubble_border_unittest.cc b/chromium/ui/views/bubble/bubble_border_unittest.cc
index b8ecfaf81e5..c7f6b16e18a 100644
--- a/chromium/ui/views/bubble/bubble_border_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_border_unittest.cc
@@ -211,7 +211,7 @@ TEST_F(BubbleBorderTest, IsArrowAtCenter) {
}
TEST_F(BubbleBorderTest, GetSizeForContentsSizeTest) {
- views::BubbleBorder border(BubbleBorder::NONE, BubbleBorder::NO_SHADOW,
+ views::BubbleBorder border(BubbleBorder::NONE, BubbleBorder::NO_SHADOW_LEGACY,
SK_ColorWHITE);
const gfx::Insets kInsets = border.GetInsets();
@@ -310,7 +310,7 @@ TEST_F(BubbleBorderTest, GetBoundsOriginTest) {
EXPECT_EQ(kTotalSize, border.GetSizeForContentsSize(kContentSize));
const int kStrokeWidth =
- shadow == BubbleBorder::NO_ASSETS ? 0 : BubbleBorder::kStroke;
+ shadow == BubbleBorder::NO_SHADOW ? 0 : BubbleBorder::kStroke;
const int kBorderedContentHeight =
kContentSize.height() + (2 * kStrokeWidth);
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
index 7c4fb6a5a4d..25e492a5c66 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -44,9 +44,6 @@
namespace views {
-// static
-bool BubbleDialogDelegate::devtools_dismiss_override_ = false;
-
namespace {
// A BubbleFrameView will apply a masking path to its ClientView to ensure
@@ -116,7 +113,7 @@ Widget* CreateBubbleWidget(BubbleDialogDelegate* bubble) {
bubble_params.layer_type = bubble->GetLayerType();
// Use a window default shadow if the bubble doesn't provides its own.
- if (bubble->GetShadow() == BubbleBorder::NO_ASSETS)
+ if (bubble->GetShadow() == BubbleBorder::NO_SHADOW)
bubble_params.shadow_type = Widget::InitParams::ShadowType::kDefault;
else if (CustomShadowsSupported())
bubble_params.shadow_type = Widget::InitParams::ShadowType::kNone;
@@ -195,9 +192,9 @@ class BubbleDialogDelegate::AnchorWidgetObserver : public WidgetObserver,
public:
AnchorWidgetObserver(BubbleDialogDelegate* owner, Widget* widget)
: owner_(owner) {
- widget_observer_.Add(widget);
+ widget_observation_.Observe(widget);
#if !defined(OS_APPLE)
- window_observer_.Add(widget->GetNativeWindow());
+ window_observation_.Observe(widget->GetNativeWindow());
#endif
}
~AnchorWidgetObserver() override = default;
@@ -205,9 +202,11 @@ class BubbleDialogDelegate::AnchorWidgetObserver : public WidgetObserver,
// WidgetObserver:
void OnWidgetDestroying(Widget* widget) override {
#if !defined(OS_APPLE)
- window_observer_.Remove(widget->GetNativeWindow());
+ DCHECK(window_observation_.IsObservingSource(widget->GetNativeWindow()));
+ window_observation_.Reset();
#endif
- widget_observer_.Remove(widget);
+ DCHECK(widget_observation_.IsObservingSource(widget));
+ widget_observation_.Reset();
owner_->OnAnchorWidgetDestroying();
// |this| may be destroyed here!
}
@@ -238,9 +237,11 @@ class BubbleDialogDelegate::AnchorWidgetObserver : public WidgetObserver,
private:
BubbleDialogDelegate* owner_;
- ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this};
+ base::ScopedObservation<views::Widget, views::WidgetObserver>
+ widget_observation_{this};
#if !defined(OS_APPLE)
- ScopedObserver<aura::Window, aura::WindowObserver> window_observer_{this};
+ base::ScopedObservation<aura::Window, aura::WindowObserver>
+ window_observation_{this};
#endif
};
@@ -250,7 +251,7 @@ class BubbleDialogDelegate::BubbleWidgetObserver : public WidgetObserver {
public:
BubbleWidgetObserver(BubbleDialogDelegate* owner, Widget* widget)
: owner_(owner) {
- observer_.Add(widget);
+ observation_.Observe(widget);
}
~BubbleWidgetObserver() override = default;
@@ -264,7 +265,8 @@ class BubbleDialogDelegate::BubbleWidgetObserver : public WidgetObserver {
}
void OnWidgetDestroyed(Widget* widget) override {
- observer_.Remove(widget);
+ DCHECK(observation_.IsObservingSource(widget));
+ observation_.Reset();
owner_->OnWidgetDestroyed(widget);
}
@@ -295,7 +297,8 @@ class BubbleDialogDelegate::BubbleWidgetObserver : public WidgetObserver {
private:
BubbleDialogDelegate* owner_;
- ScopedObserver<views::Widget, views::WidgetObserver> observer_{this};
+ base::ScopedObservation<views::Widget, views::WidgetObserver> observation_{
+ this};
};
BubbleDialogDelegate::BubbleDialogDelegate() = default;
@@ -380,7 +383,7 @@ BubbleDialogDelegate::CreateNonClientFrameView(Widget* widget) {
auto frame = std::make_unique<BubbleDialogFrameView>(title_margins_);
LayoutProvider* provider = LayoutProvider::Get();
- frame->set_footnote_margins(
+ frame->SetFootnoteMargins(
provider->GetInsetsMetric(INSETS_DIALOG_SUBSECTION));
frame->SetFootnoteView(DisownFootnoteView());
@@ -409,17 +412,6 @@ ClientView* BubbleDialogDelegate::CreateClientView(Widget* widget) {
return client_view_;
}
-bool BubbleDialogDelegateView::AcceleratorPressed(
- const ui::Accelerator& accelerator) {
- if (accelerator.key_code() == ui::VKEY_DOWN ||
- accelerator.key_code() == ui::VKEY_UP) {
- // Move the focus up or down.
- GetFocusManager()->AdvanceFocus(accelerator.key_code() != ui::VKEY_DOWN);
- return true;
- }
- return View::AcceleratorPressed(accelerator);
-}
-
Widget* BubbleDialogDelegateView::GetWidget() {
return View::GetWidget();
}
@@ -459,9 +451,6 @@ void BubbleDialogDelegate::OnAnchorWidgetDestroying() {
}
void BubbleDialogDelegate::OnBubbleWidgetActivationChanged(bool active) {
- if (devtools_dismiss_override_)
- return;
-
#if defined(OS_APPLE)
// Install |mac_bubble_closer_| the first time the widget becomes active.
if (active && !mac_bubble_closer_) {
@@ -504,9 +493,9 @@ void BubbleDialogDelegate::OnBubbleWidgetPaintAsActiveChanged() {
}
BubbleBorder::Shadow BubbleDialogDelegate::GetShadow() const {
- if (CustomShadowsSupported() || shadow_ == BubbleBorder::NO_ASSETS)
+ if (CustomShadowsSupported() || shadow_ == BubbleBorder::NO_SHADOW)
return shadow_;
- return BubbleBorder::NO_SHADOW;
+ return BubbleBorder::NO_SHADOW_LEGACY;
}
View* BubbleDialogDelegate::GetAnchorView() const {
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_view.h b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
index b588fdb446e..922e14c6ae2 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -9,10 +9,8 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "base/scoped_observer.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
-#include "ui/base/accelerators/accelerator.h"
#include "ui/base/class_property.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/bubble/bubble_frame_view.h"
@@ -31,14 +29,6 @@ namespace gfx {
class Rect;
}
-namespace ui {
-class Accelerator;
-} // namespace ui
-
-namespace ui_devtools {
-class PageAgentViews;
-}
-
namespace views {
class Button;
@@ -317,7 +307,6 @@ class VIEWS_EXPORT BubbleDialogDelegate : public DialogDelegate,
friend class BubbleBorderDelegate;
friend class BubbleWindowTargeter;
- friend class ui_devtools::PageAgentViews;
// Notify the BubbleDialogDelegate about changes in the anchor Widget. You do
// not need to call these yourself.
@@ -333,10 +322,6 @@ class VIEWS_EXPORT BubbleDialogDelegate : public DialogDelegate,
void OnDeactivate();
- // Set from UI DevTools to prevent bubbles from closing in
- // OnWidgetActivationChanged().
- static bool devtools_dismiss_override_;
-
gfx::Insets title_margins_;
BubbleBorder::Arrow arrow_ = BubbleBorder::NONE;
BubbleBorder::Shadow shadow_;
@@ -346,8 +331,7 @@ class VIEWS_EXPORT BubbleDialogDelegate : public DialogDelegate,
std::unique_ptr<AnchorViewObserver> anchor_view_observer_;
std::unique_ptr<AnchorWidgetObserver> anchor_widget_observer_;
std::unique_ptr<BubbleWidgetObserver> bubble_widget_observer_;
- std::unique_ptr<Widget::PaintAsActiveCallbackList::Subscription>
- paint_as_active_subscription_;
+ base::CallbackListSubscription paint_as_active_subscription_;
std::unique_ptr<Widget::PaintAsActiveLock> paint_as_active_lock_;
bool adjust_if_offscreen_ = true;
bool focus_traversable_from_anchor_view_ = true;
@@ -411,7 +395,6 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public BubbleDialogDelegate,
Widget* GetWidget() override;
const Widget* GetWidget() const override;
void AddedToWidget() override;
- bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
protected:
// Disallow overrides of GetMinimumSize and GetMaximumSize(). These would only
diff --git a/chromium/ui/views/bubble/bubble_dialog_model_host.cc b/chromium/ui/views/bubble/bubble_dialog_model_host.cc
index 3f2df684cd8..cee4c6b6ac6 100644
--- a/chromium/ui/views/bubble/bubble_dialog_model_host.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_model_host.cc
@@ -21,6 +21,7 @@
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/layout_provider.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/view_class_properties.h"
@@ -50,6 +51,7 @@ DialogContentType FieldTypeToContentType(ui::DialogModelField::Type type) {
// StyledLabel.
class CheckboxControl : public Checkbox {
public:
+ METADATA_HEADER(CheckboxControl);
CheckboxControl(std::unique_ptr<View> label, int label_line_height)
: label_line_height_(label_line_height) {
auto* layout = SetLayoutManager(std::make_unique<BoxLayout>());
@@ -90,10 +92,14 @@ class CheckboxControl : public Checkbox {
const int label_line_height_;
};
+BEGIN_METADATA(CheckboxControl, Checkbox)
+END_METADATA
+
} // namespace
class BubbleDialogModelHost::LayoutConsensusView : public View {
public:
+ METADATA_HEADER(LayoutConsensusView);
LayoutConsensusView(LayoutConsensusGroup* group, std::unique_ptr<View> view)
: group_(group) {
group->AddView(this);
@@ -126,6 +132,9 @@ class BubbleDialogModelHost::LayoutConsensusView : public View {
LayoutConsensusGroup* const group_;
};
+BEGIN_METADATA(BubbleDialogModelHost, LayoutConsensusView, View)
+END_METADATA
+
BubbleDialogModelHost::LayoutConsensusGroup::LayoutConsensusGroup() = default;
BubbleDialogModelHost::LayoutConsensusGroup::~LayoutConsensusGroup() {
DCHECK(children_.empty());
@@ -321,15 +330,6 @@ void BubbleDialogModelHost::Close() {
model_.reset();
}
-void BubbleDialogModelHost::SelectAllText(int unique_id) {
- const DialogModelHostField& field_view_info =
- FindDialogModelHostField(model_->GetFieldByUniqueId(unique_id));
-
- DCHECK(field_view_info.focusable_view);
- static_cast<views::Textfield*>(field_view_info.focusable_view)
- ->SelectAll(false);
-}
-
void BubbleDialogModelHost::OnFieldAdded(ui::DialogModelField* field) {
switch (field->type(GetPassKey())) {
case ui::DialogModelField::kButton:
@@ -439,10 +439,11 @@ void BubbleDialogModelHost::AddOrUpdateCheckbox(
const int line_height = label->GetLineHeight();
checkbox = std::make_unique<CheckboxControl>(std::move(label), line_height);
}
+ checkbox->SetChecked(model_field->is_checked());
checkbox->SetCallback(base::BindRepeating(
[](ui::DialogModelCheckbox* model_field,
- util::PassKey<DialogModelHost> pass_key, Checkbox* checkbox,
+ base::PassKey<DialogModelHost> pass_key, Checkbox* checkbox,
const ui::Event& event) {
model_field->OnChecked(pass_key, checkbox->GetChecked());
},
@@ -462,7 +463,7 @@ void BubbleDialogModelHost::AddOrUpdateCombobox(
: model_field->accessible_name(GetPassKey()));
combobox->SetCallback(base::BindRepeating(
[](ui::DialogModelCombobox* model_field,
- util::PassKey<DialogModelHost> pass_key, Combobox* combobox) {
+ base::PassKey<DialogModelHost> pass_key, Combobox* combobox) {
// TODO(pbos): This should be a subscription through the Combobox
// directly, but Combobox right now doesn't support listening to
// selected-index changes.
@@ -490,10 +491,19 @@ void BubbleDialogModelHost::AddOrUpdateTextfield(
: model_field->accessible_name(GetPassKey()));
textfield->SetText(model_field->text());
+ // If this textfield is initially focused the text should be initially
+ // selected as well.
+ base::Optional<int> initially_focused_field_id =
+ model_->initially_focused_field(GetPassKey());
+ if (initially_focused_field_id &&
+ model_field->unique_id(GetPassKey()) == initially_focused_field_id) {
+ textfield->SelectAll(true);
+ }
+
property_changed_subscriptions_.push_back(
textfield->AddTextChangedCallback(base::BindRepeating(
[](ui::DialogModelTextfield* model_field,
- util::PassKey<DialogModelHost> pass_key, Textfield* textfield) {
+ base::PassKey<DialogModelHost> pass_key, Textfield* textfield) {
model_field->OnTextChanged(pass_key, textfield->GetText());
},
model_field, GetPassKey(), textfield.get())));
diff --git a/chromium/ui/views/bubble/bubble_dialog_model_host.h b/chromium/ui/views/bubble/bubble_dialog_model_host.h
index 5dd3e942a63..9f05a03c38b 100644
--- a/chromium/ui/views/bubble/bubble_dialog_model_host.h
+++ b/chromium/ui/views/bubble/bubble_dialog_model_host.h
@@ -51,7 +51,6 @@ class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView,
// ui::DialogModelHost:
void Close() override;
- void SelectAllText(int unique_id) override;
void OnFieldAdded(ui::DialogModelField* field) override;
private:
@@ -132,7 +131,7 @@ class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView,
std::unique_ptr<ui::DialogModel> model_;
std::vector<DialogModelHostField> fields_;
- std::vector<PropertyChangedSubscription> property_changed_subscriptions_;
+ std::vector<base::CallbackListSubscription> property_changed_subscriptions_;
LayoutConsensusGroup textfield_first_column_group_;
LayoutConsensusGroup textfield_second_column_group_;
diff --git a/chromium/ui/views/bubble/bubble_frame_view.cc b/chromium/ui/views/bubble/bubble_frame_view.cc
index a2c8fc5745b..f29e4ce60ec 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view.cc
@@ -32,6 +32,7 @@
#include "ui/views/controls/image_view.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/layout_provider.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/paint_info.h"
#include "ui/views/resources/grit/views_resources.h"
#include "ui/views/view_class_properties.h"
@@ -74,9 +75,6 @@ constexpr int kProgressIndicatorHeight = 4;
} // namespace
-// static
-const char BubbleFrameView::kViewClassName[] = "BubbleFrameView";
-
BubbleFrameView::BubbleFrameView(const gfx::Insets& title_margins,
const gfx::Insets& content_margins)
: title_margins_(title_margins),
@@ -232,7 +230,7 @@ int BubbleFrameView::NonClientHitTest(const gfx::Point& point) {
// dialog and allow events to pass through the shadows.
gfx::RRectF round_contents_bounds(gfx::RectF(GetContentsBounds()),
bubble_border_->corner_radius());
- if (bubble_border_->shadow() != BubbleBorder::NO_ASSETS)
+ if (bubble_border_->shadow() != BubbleBorder::NO_SHADOW)
round_contents_bounds.Outset(BubbleBorder::kBorderThicknessDip);
gfx::RectF rectf_point(point.x(), point.y(), 1, 1);
if (!round_contents_bounds.Contains(rectf_point))
@@ -250,21 +248,20 @@ int BubbleFrameView::NonClientHitTest(const gfx::Point& point) {
void BubbleFrameView::GetWindowMask(const gfx::Size& size,
SkPath* window_mask) {
- if (bubble_border_->shadow() != BubbleBorder::SMALL_SHADOW &&
- bubble_border_->shadow() != BubbleBorder::NO_SHADOW_OPAQUE_BORDER &&
- bubble_border_->shadow() != BubbleBorder::NO_ASSETS)
+ if (bubble_border_->shadow() != BubbleBorder::STANDARD_SHADOW &&
+ bubble_border_->shadow() != BubbleBorder::NO_SHADOW)
return;
// We don't return a mask for windows with arrows unless they use
- // BubbleBorder::NO_ASSETS.
- if (bubble_border_->shadow() != BubbleBorder::NO_ASSETS &&
+ // BubbleBorder::NO_SHADOW.
+ if (bubble_border_->shadow() != BubbleBorder::NO_SHADOW &&
bubble_border_->arrow() != BubbleBorder::NONE &&
bubble_border_->arrow() != BubbleBorder::FLOAT)
return;
// Use a window mask roughly matching the border in the image assets.
const int kBorderStrokeSize =
- bubble_border_->shadow() == BubbleBorder::NO_ASSETS ? 0 : 1;
+ bubble_border_->shadow() == BubbleBorder::NO_SHADOW ? 0 : 1;
const SkScalar kCornerRadius = SkIntToScalar(bubble_border_->corner_radius());
const gfx::Insets border_insets = bubble_border_->GetInsets();
SkRect rect = {
@@ -274,8 +271,7 @@ void BubbleFrameView::GetWindowMask(const gfx::Size& size,
SkIntToScalar(size.height() - border_insets.bottom() +
kBorderStrokeSize)};
- if (bubble_border_->shadow() == BubbleBorder::NO_SHADOW_OPAQUE_BORDER ||
- bubble_border_->shadow() == BubbleBorder::NO_ASSETS) {
+ if (bubble_border_->shadow() == BubbleBorder::NO_SHADOW) {
window_mask->addRoundRect(rect, kCornerRadius, kCornerRadius);
} else {
static const int kBottomBorderShadowSize = 2;
@@ -324,8 +320,10 @@ void BubbleFrameView::SetProgress(base::Optional<double> progress) {
progress_indicator_->SetValue(progress.value());
}
-const char* BubbleFrameView::GetClassName() const {
- return kViewClassName;
+base::Optional<double> BubbleFrameView::GetProgress() const {
+ if (progress_indicator_->GetVisible())
+ return progress_indicator_->GetValue();
+ return base::nullopt;
}
gfx::Size BubbleFrameView::CalculatePreferredSize() const {
@@ -521,6 +519,14 @@ void BubbleFrameView::SetBubbleBorder(std::unique_ptr<BubbleBorder> border) {
// Update the background, which relies on the border.
SetBackground(std::make_unique<views::BubbleBackground>(bubble_border_));
}
+void BubbleFrameView::SetContentMargins(const gfx::Insets& content_margins) {
+ content_margins_ = content_margins;
+ OnPropertyChanged(&content_margins_, kPropertyEffectsPreferredSizeChanged);
+}
+
+gfx::Insets BubbleFrameView::GetContentMargins() const {
+ return content_margins_;
+}
void BubbleFrameView::SetHeaderView(std::unique_ptr<View> view) {
if (header_view_) {
@@ -558,15 +564,45 @@ View* BubbleFrameView::GetFootnoteView() const {
return footnote_container_->children()[0];
}
+void BubbleFrameView::SetFootnoteMargins(const gfx::Insets& footnote_margins) {
+ footnote_margins_ = footnote_margins;
+ OnPropertyChanged(&footnote_margins_, kPropertyEffectsLayout);
+}
+
+gfx::Insets BubbleFrameView::GetFootnoteMargins() const {
+ return footnote_margins_;
+}
+
+void BubbleFrameView::SetPreferredArrowAdjustment(
+ BubbleFrameView::PreferredArrowAdjustment adjustment) {
+ preferred_arrow_adjustment_ = adjustment;
+ // Changing |preferred_arrow_adjustment| will affect window bounds. Therefore
+ // this effect is handled during window resizing.
+ OnPropertyChanged(&preferred_arrow_adjustment_, kPropertyEffectsNone);
+}
+
+BubbleFrameView::PreferredArrowAdjustment
+BubbleFrameView::GetPreferredArrowAdjustment() const {
+ return preferred_arrow_adjustment_;
+}
+
void BubbleFrameView::SetCornerRadius(int radius) {
bubble_border_->SetCornerRadius(radius);
UpdateClientLayerCornerRadius();
}
+int BubbleFrameView::GetCornerRadius() const {
+ return bubble_border_ ? bubble_border_->corner_radius() : 0;
+}
+
void BubbleFrameView::SetArrow(BubbleBorder::Arrow arrow) {
bubble_border_->set_arrow(arrow);
}
+BubbleBorder::Arrow BubbleFrameView::GetArrow() const {
+ return bubble_border_->arrow();
+}
+
void BubbleFrameView::SetBackgroundColor(SkColor color) {
bubble_border_->set_background_color(color);
UpdateClientViewBackground();
@@ -886,4 +922,17 @@ void BubbleFrameView::UpdateClientLayerCornerRadius() {
}
}
+BEGIN_METADATA(BubbleFrameView, NonClientFrameView)
+ADD_PROPERTY_METADATA(base::Optional<double>, Progress)
+ADD_PROPERTY_METADATA(gfx::Insets, ContentMargins)
+ADD_PROPERTY_METADATA(gfx::Insets, FootnoteMargins)
+ADD_PROPERTY_METADATA(BubbleFrameView::PreferredArrowAdjustment,
+ PreferredArrowAdjustment)
+ADD_PROPERTY_METADATA(int, CornerRadius)
+ADD_PROPERTY_METADATA(BubbleBorder::Arrow, Arrow)
+ADD_PROPERTY_METADATA(SkColor,
+ BackgroundColor,
+ views::metadata::SkColorConverter)
+END_METADATA
+
} // namespace views
diff --git a/chromium/ui/views/bubble/bubble_frame_view.h b/chromium/ui/views/bubble/bubble_frame_view.h
index f4c770331d9..09f3d769193 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.h
+++ b/chromium/ui/views/bubble/bubble_frame_view.h
@@ -18,6 +18,7 @@
#include "ui/views/controls/label.h"
#include "ui/views/controls/progress_bar.h"
#include "ui/views/input_event_activation_protector.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/window/non_client_view.h"
namespace gfx {
@@ -32,13 +33,14 @@ class ImageView;
// The non-client frame view of bubble-styled widgets.
class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView {
public:
- enum class PreferredArrowAdjustment { kMirror, kOffset };
+ METADATA_HEADER(BubbleFrameView);
- // Internal class name.
- static const char kViewClassName[];
+ enum class PreferredArrowAdjustment { kMirror, kOffset };
BubbleFrameView(const gfx::Insets& title_margins,
const gfx::Insets& content_margins);
+ BubbleFrameView(const BubbleFrameView&) = delete;
+ BubbleFrameView& operator=(BubbleFrameView&) = delete;
~BubbleFrameView() override;
static std::unique_ptr<Label> CreateDefaultTitleLabel(
@@ -71,9 +73,11 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView {
// Updates the current progress value of |progress_indicator_|. If progress is
// absent, hides |the progress_indicator|.
void SetProgress(base::Optional<double> progress);
+ // Returns the current progress value of |progress_indicator_| if
+ // |progress_indicator_| is visible.
+ base::Optional<double> GetProgress() const;
// View:
- const char* GetClassName() const override;
gfx::Size CalculatePreferredSize() const override;
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
@@ -96,7 +100,8 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView {
static_cast<const BubbleFrameView*>(this)->title());
}
- gfx::Insets content_margins() const { return content_margins_; }
+ void SetContentMargins(const gfx::Insets& content_margins);
+ gfx::Insets GetContentMargins() const;
// Sets a custom header view for the dialog. If there is an existing header
// view it will be deleted. The header view will be inserted above the title,
@@ -113,16 +118,11 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView {
// FootnoteContainerView. An example footnote would be some help text.
void SetFootnoteView(std::unique_ptr<View> view);
View* GetFootnoteView() const;
- void set_footnote_margins(const gfx::Insets& footnote_margins) {
- footnote_margins_ = footnote_margins;
- }
+ void SetFootnoteMargins(const gfx::Insets& footnote_margins);
+ gfx::Insets GetFootnoteMargins() const;
- PreferredArrowAdjustment preferred_arrow_adjustment() const {
- return preferred_arrow_adjustment_;
- }
- void set_preferred_arrow_adjustment(PreferredArrowAdjustment adjustment) {
- preferred_arrow_adjustment_ = adjustment;
- }
+ void SetPreferredArrowAdjustment(PreferredArrowAdjustment adjustment);
+ PreferredArrowAdjustment GetPreferredArrowAdjustment() const;
// TODO(crbug.com/1007604): remove this in favor of using
// Widget::InitParams::accept_events. In the mean time, don't add new uses of
@@ -132,14 +132,13 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView {
hit_test_transparent_ = hit_test_transparent;
}
- // Get/set the corner radius of the bubble border.
- int corner_radius() const {
- return bubble_border_ ? bubble_border_->corner_radius() : 0;
- }
+ // Set the corner radius of the bubble border.
void SetCornerRadius(int radius);
+ int GetCornerRadius() const;
// Set the arrow of the bubble border.
void SetArrow(BubbleBorder::Arrow arrow);
+ BubbleBorder::Arrow GetArrow() const;
// Set the background color of the bubble border.
void SetBackgroundColor(SkColor color);
@@ -295,8 +294,6 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView {
bool hit_test_transparent_ = false;
InputEventActivationProtector input_protector_;
-
- DISALLOW_COPY_AND_ASSIGN(BubbleFrameView);
};
} // namespace views
diff --git a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
index 91ada18f5e3..9ac1741c00a 100644
--- a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
@@ -26,6 +26,7 @@
#include "ui/views/test/button_test_api.h"
#include "ui/views/test/test_layout_provider.h"
#include "ui/views/test/test_views.h"
+#include "ui/views/test/view_metadata_test_utils.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -87,7 +88,7 @@ class TestBubbleFrameView : public BubbleFrameView {
explicit TestBubbleFrameView(ViewsTestBase* test_base)
: BubbleFrameView(gfx::Insets(), gfx::Insets(kMargin)) {
SetBubbleBorder(std::make_unique<BubbleBorder>(
- kArrow, BubbleBorder::BIG_SHADOW, kColor));
+ kArrow, BubbleBorder::STANDARD_SHADOW, kColor));
widget_ = std::make_unique<Widget>();
widget_delegate_ =
std::make_unique<TestBubbleFrameViewWidgetDelegate>(widget_.get());
@@ -149,7 +150,7 @@ TEST_F(BubbleFrameViewTest, GetBoundsForClientView) {
EXPECT_EQ(kArrow, frame.GetBorderArrow());
EXPECT_EQ(kColor, frame.GetBorderBackgroundColor());
- const gfx::Insets content_margins = frame.content_margins();
+ const gfx::Insets content_margins = frame.GetContentMargins();
const gfx::Insets insets = frame.GetBorderInsets();
const gfx::Rect client_view_bounds = frame.GetBoundsForClientView();
EXPECT_EQ(insets.left() + content_margins.left(), client_view_bounds.x());
@@ -163,7 +164,7 @@ TEST_F(BubbleFrameViewTest, GetBoundsForClientViewWithClose) {
EXPECT_EQ(kArrow, frame.GetBorderArrow());
EXPECT_EQ(kColor, frame.GetBorderBackgroundColor());
- const gfx::Insets content_margins = frame.content_margins();
+ const gfx::Insets content_margins = frame.GetContentMargins();
const gfx::Insets insets = frame.GetBorderInsets();
const int close_margin =
frame.GetCloseButtonForTesting()->height() +
@@ -206,8 +207,8 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) {
TestBubbleFrameView frame(this);
gfx::Rect window_bounds;
- frame.SetBubbleBorder(
- std::make_unique<BubbleBorder>(kArrow, BubbleBorder::NO_SHADOW, kColor));
+ frame.SetBubbleBorder(std::make_unique<BubbleBorder>(
+ kArrow, BubbleBorder::NO_SHADOW_LEGACY, kColor));
// Test that the info bubble displays normally when it fits.
frame.SetArrow(BubbleBorder::TOP_LEFT);
@@ -369,7 +370,7 @@ TEST_F(BubbleFrameViewTest, TestMirroringForCenteredArrow) {
TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsDontTryMirror) {
TestBubbleFrameView frame(this);
frame.SetBubbleBorder(std::make_unique<BubbleBorder>(
- BubbleBorder::TOP_RIGHT, BubbleBorder::NO_SHADOW, kColor));
+ BubbleBorder::TOP_RIGHT, BubbleBorder::NO_SHADOW_LEGACY, kColor));
gfx::Rect window_bounds = frame.GetUpdatedWindowBounds(
gfx::Rect(100, 900, 0, 0), // |anchor_rect|
BubbleBorder::Arrow::TOP_RIGHT, // |delegate_arrow|
@@ -386,8 +387,8 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsCenterArrows) {
TestBubbleFrameView frame(this);
gfx::Rect window_bounds;
- frame.SetBubbleBorder(
- std::make_unique<BubbleBorder>(kArrow, BubbleBorder::NO_SHADOW, kColor));
+ frame.SetBubbleBorder(std::make_unique<BubbleBorder>(
+ kArrow, BubbleBorder::NO_SHADOW_LEGACY, kColor));
// Some of these tests may go away once --secondary-ui-md becomes the
// default. Under Material Design mode, the BubbleBorder doesn't support all
@@ -450,8 +451,8 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsForBubbleWithAnchorWindow) {
frame.SetAvailableAnchorWindowBounds(gfx::Rect(100, 100, 500, 500));
gfx::Rect window_bounds;
- frame.SetBubbleBorder(
- std::make_unique<BubbleBorder>(kArrow, BubbleBorder::NO_SHADOW, kColor));
+ frame.SetBubbleBorder(std::make_unique<BubbleBorder>(
+ kArrow, BubbleBorder::NO_SHADOW_LEGACY, kColor));
// Test that the bubble displays normally when it fits.
frame.SetArrow(BubbleBorder::TOP_LEFT);
@@ -568,8 +569,8 @@ TEST_F(BubbleFrameViewTest,
TestBubbleFrameView frame(this);
gfx::Rect window_bounds;
- frame.SetBubbleBorder(
- std::make_unique<BubbleBorder>(kArrow, BubbleBorder::NO_SHADOW, kColor));
+ frame.SetBubbleBorder(std::make_unique<BubbleBorder>(
+ kArrow, BubbleBorder::NO_SHADOW_LEGACY, kColor));
// Test bubble fitting anchor window and not fitting screen on right.
// ________________________
@@ -640,8 +641,8 @@ TEST_F(BubbleFrameViewTest, MirroringNotStickyForGetUpdatedWindowBounds) {
TestBubbleFrameView frame(this);
gfx::Rect window_bounds;
- frame.SetBubbleBorder(
- std::make_unique<BubbleBorder>(kArrow, BubbleBorder::NO_SHADOW, kColor));
+ frame.SetBubbleBorder(std::make_unique<BubbleBorder>(
+ kArrow, BubbleBorder::NO_SHADOW_LEGACY, kColor));
// Test bubble fitting anchor window and not fitting screen on right.
frame.SetAvailableAnchorWindowBounds(gfx::Rect(700, 200, 400, 400));
@@ -673,12 +674,12 @@ TEST_F(BubbleFrameViewTest, MirroringNotStickyForGetUpdatedWindowBounds) {
TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsForBubbleSetToOffset) {
TestBubbleFrameView frame(this);
frame.SetAvailableAnchorWindowBounds(gfx::Rect(100, 100, 500, 500));
- frame.set_preferred_arrow_adjustment(
+ frame.SetPreferredArrowAdjustment(
BubbleFrameView::PreferredArrowAdjustment::kOffset);
gfx::Rect window_bounds;
- frame.SetBubbleBorder(
- std::make_unique<BubbleBorder>(kArrow, BubbleBorder::NO_SHADOW, kColor));
+ frame.SetBubbleBorder(std::make_unique<BubbleBorder>(
+ kArrow, BubbleBorder::NO_SHADOW_LEGACY, kColor));
// Test that the bubble displays normally when it fits.
frame.SetArrow(BubbleBorder::TOP_LEFT);
@@ -731,12 +732,12 @@ TEST_F(BubbleFrameViewTest,
GetUpdatedWindowBoundsForBubbleSetToOffsetLargerThanAvailableBounds) {
TestBubbleFrameView frame(this);
frame.SetAvailableAnchorWindowBounds(gfx::Rect(200, 200, 500, 500));
- frame.set_preferred_arrow_adjustment(
+ frame.SetPreferredArrowAdjustment(
BubbleFrameView::PreferredArrowAdjustment::kOffset);
gfx::Rect window_bounds;
- frame.SetBubbleBorder(
- std::make_unique<BubbleBorder>(kArrow, BubbleBorder::NO_SHADOW, kColor));
+ frame.SetBubbleBorder(std::make_unique<BubbleBorder>(
+ kArrow, BubbleBorder::NO_SHADOW_LEGACY, kColor));
// Test that the bubble exiting right side of anchor window displays against
// left edge of anchor window bounds if larger than anchor window.
@@ -814,7 +815,7 @@ TEST_F(BubbleFrameViewTest, GetPreferredSizeWithFootnote) {
gfx::Size with_footnote_size = no_footnote_size;
constexpr int kFootnoteTopBorderThickness = 1;
with_footnote_size.Enlarge(0, kFootnoteHeight + kFootnoteTopBorderThickness +
- frame.content_margins().height());
+ frame.GetContentMargins().height());
EXPECT_EQ(with_footnote_size, frame.GetPreferredSize());
footnote_dummy_view->SetVisible(false);
@@ -879,7 +880,7 @@ TEST_F(BubbleFrameViewTest, LayoutWithHeaderAndCloseButton) {
const int close_margin =
frame.GetCloseButtonForTesting()->height() +
LayoutProvider::Get()->GetDistanceMetric(DISTANCE_CLOSE_BUTTON_MARGIN);
- const gfx::Insets content_margins = frame.content_margins();
+ const gfx::Insets content_margins = frame.GetContentMargins();
const gfx::Insets insets = frame.GetBorderInsets();
// Header is smaller than close button + margin, expect bounds to be below the
@@ -901,13 +902,19 @@ TEST_F(BubbleFrameViewTest, LayoutWithHeaderAndCloseButton) {
client_view_bounds.y());
}
+TEST_F(BubbleFrameViewTest, MetadataTest) {
+ TestBubbleFrameView frame(this);
+ TestBubbleFrameView* frame_pointer = &frame;
+ test::TestViewMetadata(frame_pointer);
+}
+
namespace {
class TestBubbleDialogDelegateView : public BubbleDialogDelegateView {
public:
TestBubbleDialogDelegateView()
: BubbleDialogDelegateView(nullptr, BubbleBorder::NONE) {
- set_shadow(BubbleBorder::NO_ASSETS);
+ set_shadow(BubbleBorder::NO_SHADOW);
SetAnchorRect(gfx::Rect());
DialogDelegate::SetButtons(ui::DIALOG_BUTTON_OK);
}
diff --git a/chromium/ui/views/bubble/tooltip_icon.cc b/chromium/ui/views/bubble/tooltip_icon.cc
index fa42d321126..4a24284a2b2 100644
--- a/chromium/ui/views/bubble/tooltip_icon.cc
+++ b/chromium/ui/views/bubble/tooltip_icon.cc
@@ -98,7 +98,7 @@ void TooltipIcon::ShowBubble() {
bubble_->SetCanActivate(!mouse_inside_);
bubble_->Show();
- observer_.Add(bubble_->GetWidget());
+ observation_.Observe(bubble_->GetWidget());
if (mouse_inside_) {
View* frame = bubble_->GetWidget()->non_client_view()->frame_view();
@@ -117,7 +117,8 @@ void TooltipIcon::HideBubble() {
}
void TooltipIcon::OnWidgetDestroyed(Widget* widget) {
- observer_.Remove(widget);
+ DCHECK(observation_.IsObservingSource(widget));
+ observation_.Reset();
SetDrawAsHovered(false);
mouse_watcher_.reset();
diff --git a/chromium/ui/views/bubble/tooltip_icon.h b/chromium/ui/views/bubble/tooltip_icon.h
index 80436bd84c8..7fd90f18c4f 100644
--- a/chromium/ui/views/bubble/tooltip_icon.h
+++ b/chromium/ui/views/bubble/tooltip_icon.h
@@ -8,7 +8,7 @@
#include <memory>
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/strings/string16.h"
#include "base/timer/timer.h"
#include "ui/views/bubble/bubble_border.h"
@@ -102,7 +102,7 @@ class VIEWS_EXPORT TooltipIcon : public ImageView,
// A watcher that keeps |bubble_| open if the user's mouse enters it.
std::unique_ptr<MouseWatcher> mouse_watcher_;
- ScopedObserver<Widget, WidgetObserver> observer_{this};
+ base::ScopedObservation<Widget, WidgetObserver> observation_{this};
base::ObserverList<Observer, /*check_empty=*/true> observers_;
diff --git a/chromium/ui/views/button_drag_utils.cc b/chromium/ui/views/button_drag_utils.cc
index ca50afc36f4..23997eeb9f1 100644
--- a/chromium/ui/views/button_drag_utils.cc
+++ b/chromium/ui/views/button_drag_utils.cc
@@ -91,7 +91,7 @@ void SetDragImage(const GURL& url,
widget.GetCompositor()->is_pixel_canvas())
.context(),
size));
- gfx::ImageSkia image(gfx::ImageSkiaRep(bitmap, raster_scale));
+ gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(bitmap, raster_scale);
data->provider().SetDragImage(image, press_point);
}
diff --git a/chromium/ui/views/cocoa/drag_drop_client_mac.mm b/chromium/ui/views/cocoa/drag_drop_client_mac.mm
index eb361a94c65..94a7e1d91d3 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac.mm
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac.mm
@@ -10,6 +10,7 @@
#import "components/remote_cocoa/app_shim/bridged_content_view.h"
#import "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#import "ui/base/dragdrop/os_exchange_data_provider_mac.h"
#include "ui/gfx/image/image_skia_util_mac.h"
#include "ui/views/drag_utils.h"
@@ -103,10 +104,11 @@ NSDragOperation DragDropClientMac::Drop(id<NSDraggingInfo> sender) {
// OnDrop may delete |this|, so clear |exchange_data_| first.
std::unique_ptr<ui::OSExchangeData> exchange_data = std::move(exchange_data_);
- int drag_operation = drop_helper_.OnDrop(
+ ui::mojom::DragOperation drag_operation = drop_helper_.OnDrop(
*exchange_data, LocationInView([sender draggingLocation]),
last_operation_);
- return ui::DragDropTypes::DragOperationToNSDragOperation(drag_operation);
+ return ui::DragDropTypes::DragOperationToNSDragOperation(
+ static_cast<int>(drag_operation));
}
void DragDropClientMac::EndDrag() {
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 8fb1b382134..35af65f054f 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -13,7 +13,7 @@
#import "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
#import "ui/base/clipboard/clipboard_util_mac.h"
#import "ui/base/dragdrop/drag_drop_types.h"
-#import "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
+#import "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/gfx/image/image_unittest_util.h"
#import "ui/views/cocoa/native_widget_mac_ns_window_host.h"
#include "ui/views/test/widget_test.h"
@@ -21,8 +21,6 @@
#include "ui/views/widget/native_widget_mac.h"
#include "ui/views/widget/widget.h"
-using base::ASCIIToUTF16;
-
@interface NSView (DragSessionTestingDonor)
@end
@@ -45,8 +43,7 @@ using base::ASCIIToUTF16;
@property BOOL animatesToDestination;
@property NSInteger numberOfValidItemsForDrop;
@property NSDraggingFormation draggingFormation;
-@property(readonly)
- NSSpringLoadingHighlight springLoadingHighlight API_AVAILABLE(macos(10.11));
+@property(readonly) NSSpringLoadingHighlight springLoadingHighlight;
@end
@@ -121,6 +118,9 @@ enumerateDraggingItemsWithOptions:(NSDraggingItemEnumerationOptions)enumOpts
namespace views {
namespace test {
+using ::base::ASCIIToUTF16;
+using ::ui::mojom::DragOperation;
+
// View object that will receive and process dropped data from the test.
class DragDropView : public View {
public:
@@ -142,8 +142,8 @@ class DragDropView : public View {
return ui::DragDropTypes::DRAG_COPY;
}
- int OnPerformDrop(const ui::DropTargetEvent& event) override {
- return ui::DragDropTypes::DRAG_MOVE;
+ DragOperation OnPerformDrop(const ui::DropTargetEvent& event) override {
+ return DragOperation::kMove;
}
private:
@@ -312,9 +312,9 @@ class DragDropCloseView : public DragDropView {
DragDropCloseView() {}
// View:
- int OnPerformDrop(const ui::DropTargetEvent& event) override {
+ DragOperation OnPerformDrop(const ui::DropTargetEvent& event) override {
GetWidget()->CloseNow();
- return ui::DragDropTypes::DRAG_MOVE;
+ return DragOperation::kMove;
}
private:
diff --git a/chromium/ui/views/cocoa/native_widget_mac_ns_window_host.h b/chromium/ui/views/cocoa/native_widget_mac_ns_window_host.h
index 492386c61ac..6d218f9e38f 100644
--- a/chromium/ui/views/cocoa/native_widget_mac_ns_window_host.h
+++ b/chromium/ui/views/cocoa/native_widget_mac_ns_window_host.h
@@ -15,6 +15,7 @@
#include "components/remote_cocoa/app_shim/native_widget_ns_window_host_helper.h"
#include "components/remote_cocoa/app_shim/ns_view_ids.h"
#include "components/remote_cocoa/browser/application_host.h"
+#include "components/remote_cocoa/browser/scoped_cg_window_id.h"
#include "components/remote_cocoa/common/native_widget_ns_window.mojom.h"
#include "components/remote_cocoa/common/native_widget_ns_window_host.mojom.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
@@ -456,6 +457,7 @@ class VIEWS_EXPORT NativeWidgetMacNSWindowHost
gfx::Rect window_bounds_before_fullscreen_;
std::unique_ptr<ui::RecyclableCompositorMac> compositor_;
+ std::unique_ptr<remote_cocoa::ScopedCGWindowID> scoped_cg_window_id_;
// Properties used by Set/GetNativeWindowProperty.
std::map<std::string, void*> native_window_properties_;
diff --git a/chromium/ui/views/cocoa/native_widget_mac_ns_window_host.mm b/chromium/ui/views/cocoa/native_widget_mac_ns_window_host.mm
index d0be0e2ff2d..c2a1dc7a9ff 100644
--- a/chromium/ui/views/cocoa/native_widget_mac_ns_window_host.mm
+++ b/chromium/ui/views/cocoa/native_widget_mac_ns_window_host.mm
@@ -519,7 +519,19 @@ void NativeWidgetMacNSWindowHost::CreateCompositor(
if (is_visible_)
compositor_->Unsuspend();
- GetNSWindowMojo()->InitCompositorView();
+ // Register the CGWindowID (used to identify this window for video capture)
+ // when it is received. Note that this is done at this moment (as opposed to
+ // as a callback to CreateWindow) so that we can associate the CGWindowID with
+ // the (now existing) compositor.
+ auto lambda = [](NativeWidgetMacNSWindowHost* host, uint32_t cg_window_id) {
+ if (!host->compositor_)
+ return;
+ host->scoped_cg_window_id_ =
+ std::make_unique<remote_cocoa::ScopedCGWindowID>(
+ cg_window_id, host->compositor_->compositor()->frame_sink_id());
+ };
+ GetNSWindowMojo()->InitCompositorView(
+ base::BindOnce(lambda, base::Unretained(this)));
}
void NativeWidgetMacNSWindowHost::UpdateCompositorProperties() {
diff --git a/chromium/ui/views/cocoa/text_input_host.mm b/chromium/ui/views/cocoa/text_input_host.mm
index f9592c0b75f..c7cc10abc6a 100644
--- a/chromium/ui/views/cocoa/text_input_host.mm
+++ b/chromium/ui/views/cocoa/text_input_host.mm
@@ -265,7 +265,9 @@ void TextInputHost::InsertText(const base::string16& text, bool as_character) {
text_input_client_->InsertChar(ui::KeyEvent(
text[0], ui::VKEY_UNKNOWN, ui::DomCode::NONE, ui::EF_NONE));
} else {
- text_input_client_->InsertText(text);
+ text_input_client_->InsertText(
+ text,
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
}
}
diff --git a/chromium/ui/views/color_chooser/color_chooser_unittest.cc b/chromium/ui/views/color_chooser/color_chooser_unittest.cc
index e20ed343a43..a54f79a8e9c 100644
--- a/chromium/ui/views/color_chooser/color_chooser_unittest.cc
+++ b/chromium/ui/views/color_chooser/color_chooser_unittest.cc
@@ -22,6 +22,7 @@
#include "ui/views/color_chooser/color_chooser_view.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget_delegate.h"
#include "ui/views/widget/widget_utils.h"
namespace {
@@ -42,11 +43,18 @@ class ColorChooserTest : public views::ViewsTestBase {
void SetUp() override {
ViewsTestBase::SetUp();
- chooser_ =
- std::make_unique<views::ColorChooserView>(&listener_, SK_ColorGREEN);
- chooser_->SetBounds(0, 0, 400, 300);
+ chooser_ = std::make_unique<views::ColorChooser>(&listener_, SK_ColorGREEN);
+
+ // Icky: we can't use our own WidgetDelegate for CreateTestWidget, but we
+ // want to follow the production code path here regardless, so we create our
+ // own delegate, pull the contents view out of it, and stick it into the
+ // test widget. In production Views would handle that step itself.
+ auto delegate = chooser_->MakeWidgetDelegate();
+ auto* view = delegate->TransferOwnershipOfContentsView();
+
+ view->SetBounds(0, 0, 400, 300);
widget_ = CreateTestWidget(views::Widget::InitParams::TYPE_WINDOW);
- widget_->GetContentsView()->AddChildView(chooser());
+ widget_->GetContentsView()->AddChildView(std::move(view));
generator_ = std::make_unique<ui::test::EventGenerator>(
views::GetRootWindow(widget_.get()), widget_->GetNativeWindow());
generator_->set_assume_window_at_origin(false);
@@ -58,7 +66,7 @@ class ColorChooserTest : public views::ViewsTestBase {
ViewsTestBase::TearDown();
}
- views::ColorChooserView* chooser() { return chooser_.get(); }
+ views::ColorChooser* chooser() { return chooser_.get(); }
ui::test::EventGenerator* generator() { return generator_.get(); }
void ExpectExactHSV(float h, float s, float v) const {
@@ -115,7 +123,7 @@ class ColorChooserTest : public views::ViewsTestBase {
private:
TestChooserListener listener_;
- std::unique_ptr<views::ColorChooserView> chooser_;
+ std::unique_ptr<views::ColorChooser> chooser_;
std::unique_ptr<views::Widget> widget_;
std::unique_ptr<ui::test::EventGenerator> generator_;
};
diff --git a/chromium/ui/views/color_chooser/color_chooser_view.cc b/chromium/ui/views/color_chooser/color_chooser_view.cc
index 8470a676208..6fe11178383 100644
--- a/chromium/ui/views/color_chooser/color_chooser_view.cc
+++ b/chromium/ui/views/color_chooser/color_chooser_view.cc
@@ -12,7 +12,6 @@
#include <utility>
#include "base/check.h"
-#include "base/macros.h"
#include "base/numerics/ranges.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
@@ -34,7 +33,10 @@
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/grid_layout.h"
+#include "ui/views/metadata/metadata_header_macros.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
namespace {
@@ -70,6 +72,9 @@ bool GetColorFromText(const base::string16& text, SkColor* result) {
// interface.
class LocatedEventHandlerView : public views::View {
public:
+ METADATA_HEADER(LocatedEventHandlerView);
+ LocatedEventHandlerView(const LocatedEventHandlerView&) = delete;
+ LocatedEventHandlerView& operator=(const LocatedEventHandlerView&) = delete;
~LocatedEventHandlerView() override = default;
protected:
@@ -97,10 +102,11 @@ class LocatedEventHandlerView : public views::View {
event->SetHandled();
}
}
-
- DISALLOW_COPY_AND_ASSIGN(LocatedEventHandlerView);
};
+BEGIN_METADATA(LocatedEventHandlerView, views::View)
+END_METADATA
+
void DrawGradientRect(const gfx::Rect& rect,
SkColor start_color,
SkColor end_color,
@@ -124,13 +130,18 @@ void DrawGradientRect(const gfx::Rect& rect,
namespace views {
////////////////////////////////////////////////////////////////////////////////
-// ColorChooserView::HueView
+// HueView
//
// The class to choose the hue of the color. It draws a vertical bar and
// the indicator for the currently selected hue.
-class ColorChooserView::HueView : public LocatedEventHandlerView {
+class HueView : public LocatedEventHandlerView {
public:
- explicit HueView(ColorChooserView* chooser_view);
+ METADATA_HEADER(HueView);
+
+ using HueChangedCallback = base::RepeatingCallback<void(SkScalar)>;
+ explicit HueView(const HueChangedCallback& changed_callback);
+ HueView(const HueView&) = delete;
+ HueView& operator=(const HueView&) = delete;
void OnHueChanged(SkScalar hue);
@@ -142,16 +153,14 @@ class ColorChooserView::HueView : public LocatedEventHandlerView {
gfx::Size CalculatePreferredSize() const override;
void OnPaint(gfx::Canvas* canvas) override;
- ColorChooserView* chooser_view_;
+ HueChangedCallback changed_callback_;
int level_;
-
- DISALLOW_COPY_AND_ASSIGN(HueView);
};
-ColorChooserView::HueView::HueView(ColorChooserView* chooser_view)
- : chooser_view_(chooser_view), level_(0) {}
+HueView::HueView(const HueChangedCallback& changed_callback)
+ : changed_callback_(changed_callback), level_(0) {}
-void ColorChooserView::HueView::OnHueChanged(SkScalar hue) {
+void HueView::OnHueChanged(SkScalar hue) {
SkScalar height = SkIntToScalar(kSaturationValueSize - 1);
SkScalar hue_max = SkIntToScalar(360);
int level = (hue_max - hue) * height / hue_max;
@@ -162,23 +171,22 @@ void ColorChooserView::HueView::OnHueChanged(SkScalar hue) {
}
}
-void ColorChooserView::HueView::ProcessEventAtLocation(
- const gfx::Point& point) {
+void HueView::ProcessEventAtLocation(const gfx::Point& point) {
level_ =
std::max(kBorderWidth, std::min(height() - 1 - kBorderWidth, point.y()));
int base_height = kSaturationValueSize - 1;
- chooser_view_->OnHueChosen(360.f * (base_height - (level_ - kBorderWidth)) /
- base_height);
+ changed_callback_.Run(360.f * (base_height - (level_ - kBorderWidth)) /
+ base_height);
SchedulePaint();
}
-gfx::Size ColorChooserView::HueView::CalculatePreferredSize() const {
+gfx::Size HueView::CalculatePreferredSize() const {
// We put indicators on the both sides of the hue bar.
return gfx::Size(kHueBarWidth + kHueIndicatorSize * 2 + kBorderWidth * 2,
kSaturationValueSize + kBorderWidth * 2);
}
-void ColorChooserView::HueView::OnPaint(gfx::Canvas* canvas) {
+void HueView::OnPaint(gfx::Canvas* canvas) {
SkScalar hsv[3];
// In the hue bar, saturation and value for the color should be always 100%.
hsv[1] = SK_Scalar1;
@@ -222,15 +230,25 @@ void ColorChooserView::HueView::OnPaint(gfx::Canvas* canvas) {
canvas->DrawPath(right_indicator_path, indicator_flags);
}
+BEGIN_METADATA(HueView, LocatedEventHandlerView)
+END_METADATA
+
////////////////////////////////////////////////////////////////////////////////
-// ColorChooserView::SaturationValueView
+// SaturationValueView
//
// The class to choose the saturation and the value of the color. It draws
// a square area and the indicator for the currently selected saturation and
// value.
-class ColorChooserView::SaturationValueView : public LocatedEventHandlerView {
+class SaturationValueView : public LocatedEventHandlerView {
public:
- explicit SaturationValueView(ColorChooserView* chooser_view);
+ METADATA_HEADER(SaturationValueView);
+
+ using SaturationValueChangedCallback =
+ base::RepeatingCallback<void(SkScalar, SkScalar)>;
+ explicit SaturationValueView(
+ const SaturationValueChangedCallback& changed_callback);
+ SaturationValueView(const SaturationValueView&) = delete;
+ SaturationValueView& operator=(const SaturationValueView&) = delete;
void OnHueChanged(SkScalar hue);
void OnSaturationValueChanged(SkScalar saturation, SkScalar value);
@@ -243,29 +261,26 @@ class ColorChooserView::SaturationValueView : public LocatedEventHandlerView {
gfx::Size CalculatePreferredSize() const override;
void OnPaint(gfx::Canvas* canvas) override;
- ColorChooserView* chooser_view_;
+ SaturationValueChangedCallback changed_callback_;
SkScalar hue_;
gfx::Point marker_position_;
-
- DISALLOW_COPY_AND_ASSIGN(SaturationValueView);
};
-ColorChooserView::SaturationValueView::SaturationValueView(
- ColorChooserView* chooser_view)
- : chooser_view_(chooser_view), hue_(0) {
+SaturationValueView::SaturationValueView(
+ const SaturationValueChangedCallback& changed_callback)
+ : changed_callback_(changed_callback), hue_(0) {
SetBorder(CreateSolidBorder(kBorderWidth, SK_ColorGRAY));
}
-void ColorChooserView::SaturationValueView::OnHueChanged(SkScalar hue) {
+void SaturationValueView::OnHueChanged(SkScalar hue) {
if (hue_ != hue) {
hue_ = hue;
SchedulePaint();
}
}
-void ColorChooserView::SaturationValueView::OnSaturationValueChanged(
- SkScalar saturation,
- SkScalar value) {
+void SaturationValueView::OnSaturationValueChanged(SkScalar saturation,
+ SkScalar value) {
SkScalar scalar_size = SkIntToScalar(kSaturationValueSize - 1);
int x = SkScalarFloorToInt(saturation * scalar_size) + kBorderWidth;
int y = SkScalarFloorToInt((SK_Scalar1 - value) * scalar_size) + kBorderWidth;
@@ -277,24 +292,22 @@ void ColorChooserView::SaturationValueView::OnSaturationValueChanged(
SchedulePaint();
}
-void ColorChooserView::SaturationValueView::ProcessEventAtLocation(
- const gfx::Point& point) {
+void SaturationValueView::ProcessEventAtLocation(const gfx::Point& point) {
SkScalar scalar_size = SkIntToScalar(kSaturationValueSize - 1);
SkScalar saturation = (point.x() - kBorderWidth) / scalar_size;
SkScalar value = SK_Scalar1 - (point.y() - kBorderWidth) / scalar_size;
saturation = base::ClampToRange(saturation, 0.0f, SK_Scalar1);
value = base::ClampToRange(value, 0.0f, SK_Scalar1);
OnSaturationValueChanged(saturation, value);
- chooser_view_->OnSaturationValueChosen(saturation, value);
+ changed_callback_.Run(saturation, value);
}
-gfx::Size ColorChooserView::SaturationValueView::CalculatePreferredSize()
- const {
+gfx::Size SaturationValueView::CalculatePreferredSize() const {
return gfx::Size(kSaturationValueSize + kBorderWidth * 2,
kSaturationValueSize + kBorderWidth * 2);
}
-void ColorChooserView::SaturationValueView::OnPaint(gfx::Canvas* canvas) {
+void SaturationValueView::OnPaint(gfx::Canvas* canvas) {
gfx::Rect color_bounds = bounds();
color_bounds.Inset(GetInsets());
@@ -328,26 +341,29 @@ void ColorChooserView::SaturationValueView::OnPaint(gfx::Canvas* canvas) {
OnPaintBorder(canvas);
}
+BEGIN_METADATA(SaturationValueView, LocatedEventHandlerView)
+END_METADATA
+
////////////////////////////////////////////////////////////////////////////////
-// ColorChooserView::SelectedColorPatchView
+// SelectedColorPatchView
//
// A view to simply show the selected color in a rectangle.
-class ColorChooserView::SelectedColorPatchView : public views::View {
+class SelectedColorPatchView : public views::View {
public:
+ METADATA_HEADER(SelectedColorPatchView);
SelectedColorPatchView();
+ SelectedColorPatchView(const SelectedColorPatchView&) = delete;
+ SelectedColorPatchView& operator=(const SelectedColorPatchView&) = delete;
void SetColor(SkColor color);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SelectedColorPatchView);
};
-ColorChooserView::SelectedColorPatchView::SelectedColorPatchView() {
+SelectedColorPatchView::SelectedColorPatchView() {
SetVisible(true);
SetBorder(CreateSolidBorder(kBorderWidth, SK_ColorGRAY));
}
-void ColorChooserView::SelectedColorPatchView::SetColor(SkColor color) {
+void SelectedColorPatchView::SetColor(SkColor color) {
if (!background())
SetBackground(CreateSolidBackground(color));
else
@@ -355,29 +371,26 @@ void ColorChooserView::SelectedColorPatchView::SetColor(SkColor color) {
SchedulePaint();
}
-////////////////////////////////////////////////////////////////////////////////
-// ColorChooserView
-//
-
-ColorChooserView::ColorChooserView(ColorChooserListener* listener,
- SkColor initial_color)
- : listener_(listener) {
- DCHECK(listener_);
-
- SetModalType(ui::MODAL_TYPE_WINDOW);
+BEGIN_METADATA(SelectedColorPatchView, views::View)
+END_METADATA
- SetBackground(CreateSolidBackground(SK_ColorLTGRAY));
- SetLayoutManager(
+std::unique_ptr<View> ColorChooser::BuildView() {
+ auto view = std::make_unique<View>();
+ tracker_.SetView(view.get());
+ view->SetBackground(CreateSolidBackground(SK_ColorLTGRAY));
+ view->SetLayoutManager(
std::make_unique<BoxLayout>(BoxLayout::Orientation::kVertical,
gfx::Insets(kMarginWidth), kMarginWidth));
auto container = std::make_unique<View>();
container->SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::Orientation::kHorizontal, gfx::Insets(), kMarginWidth));
- saturation_value_ =
- container->AddChildView(std::make_unique<SaturationValueView>(this));
- hue_ = container->AddChildView(std::make_unique<HueView>(this));
- AddChildView(std::move(container));
+ saturation_value_ = container->AddChildView(
+ std::make_unique<SaturationValueView>(base::BindRepeating(
+ &ColorChooser::OnSaturationValueChosen, this->AsWeakPtr())));
+ hue_ = container->AddChildView(std::make_unique<HueView>(
+ base::BindRepeating(&ColorChooser::OnHueChosen, this->AsWeakPtr())));
+ view->AddChildView(std::move(container));
auto container2 = std::make_unique<View>();
GridLayout* layout =
@@ -397,95 +410,128 @@ ColorChooserView::ColorChooserView(ColorChooserListener* listener,
textfield_ = layout->AddView(std::move(textfield));
selected_color_patch_ =
layout->AddView(std::make_unique<SelectedColorPatchView>());
- AddChildView(std::move(container2));
+ view->AddChildView(std::move(container2));
- OnColorChanged(initial_color);
+ OnColorChanged(initial_color_);
+
+ return view;
}
-ColorChooserView::~ColorChooserView() = default;
+bool ColorChooser::IsViewAttached() const {
+ return tracker_.view();
+}
-void ColorChooserView::OnColorChanged(SkColor color) {
- SkColorToHSV(color, hsv_);
- hue_->OnHueChanged(hsv_[0]);
- saturation_value_->OnHueChanged(hsv_[0]);
- saturation_value_->OnSaturationValueChanged(hsv_[1], hsv_[2]);
- selected_color_patch_->SetColor(color);
- textfield_->SetText(GetColorText(color));
+void ColorChooser::OnColorChanged(SkColor color) {
+ SetColor(color);
+ if (IsViewAttached()) {
+ hue_->OnHueChanged(hue());
+ saturation_value_->OnHueChanged(hue());
+ saturation_value_->OnSaturationValueChanged(saturation(), value());
+ selected_color_patch_->SetColor(color);
+ textfield_->SetText(GetColorText(color));
+ }
}
-void ColorChooserView::OnHueChosen(SkScalar hue) {
- hsv_[0] = hue;
- SkColor color = SkHSVToColor(255, hsv_);
- if (listener_)
- listener_->OnColorChosen(color);
+void ColorChooser::OnHueChosen(SkScalar hue) {
+ SetHue(hue);
+ SkColor color = GetColor();
saturation_value_->OnHueChanged(hue);
selected_color_patch_->SetColor(color);
textfield_->SetText(GetColorText(color));
}
-void ColorChooserView::OnSaturationValueChosen(SkScalar saturation,
- SkScalar value) {
- hsv_[1] = saturation;
- hsv_[2] = value;
- SkColor color = SkHSVToColor(255, hsv_);
- if (listener_)
- listener_->OnColorChosen(color);
+void ColorChooser::OnSaturationValueChosen(SkScalar saturation,
+ SkScalar value) {
+ SetSaturationValue(saturation, value);
+ SkColor color = GetColor();
selected_color_patch_->SetColor(color);
textfield_->SetText(GetColorText(color));
}
-View* ColorChooserView::hue_view_for_testing() {
+View* ColorChooser::hue_view_for_testing() {
return hue_;
}
-View* ColorChooserView::saturation_value_view_for_testing() {
+View* ColorChooser::saturation_value_view_for_testing() {
return saturation_value_;
}
-Textfield* ColorChooserView::textfield_for_testing() {
+Textfield* ColorChooser::textfield_for_testing() {
return textfield_;
}
-View* ColorChooserView::selected_color_patch_for_testing() {
+View* ColorChooser::selected_color_patch_for_testing() {
return selected_color_patch_;
}
-void ColorChooserView::ContentsChanged(Textfield* sender,
- const base::string16& new_contents) {
+void ColorChooser::ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) {
+ DCHECK(IsViewAttached());
+
SkColor color = SK_ColorBLACK;
if (GetColorFromText(new_contents, &color)) {
- SkColorToHSV(color, hsv_);
- if (listener_)
- listener_->OnColorChosen(color);
- hue_->OnHueChanged(hsv_[0]);
- saturation_value_->OnHueChanged(hsv_[0]);
- saturation_value_->OnSaturationValueChanged(hsv_[1], hsv_[2]);
+ SetColor(color);
+ hue_->OnHueChanged(hue());
+ saturation_value_->OnHueChanged(hue());
+ saturation_value_->OnSaturationValueChanged(saturation(), value());
selected_color_patch_->SetColor(color);
}
}
-bool ColorChooserView::HandleKeyEvent(Textfield* sender,
- const ui::KeyEvent& key_event) {
+bool ColorChooser::HandleKeyEvent(Textfield* sender,
+ const ui::KeyEvent& key_event) {
+ DCHECK(IsViewAttached());
+
if (key_event.type() != ui::ET_KEY_PRESSED ||
(key_event.key_code() != ui::VKEY_RETURN &&
key_event.key_code() != ui::VKEY_ESCAPE))
return false;
- GetWidget()->Close();
+ tracker_.view()->GetWidget()->Close();
return true;
}
-bool ColorChooserView::CanMinimize() const {
- return false;
+std::unique_ptr<WidgetDelegate> ColorChooser::MakeWidgetDelegate() {
+ DCHECK(!IsViewAttached());
+
+ auto delegate = std::make_unique<WidgetDelegate>();
+ delegate->SetCanMinimize(false);
+ delegate->SetContentsView(BuildView());
+ delegate->SetInitiallyFocusedView(textfield_);
+ delegate->SetModalType(ui::MODAL_TYPE_WINDOW);
+ delegate->RegisterWindowClosingCallback(
+ base::BindOnce(&ColorChooser::OnViewClosing, this->AsWeakPtr()));
+
+ return delegate;
}
-View* ColorChooserView::GetInitiallyFocusedView() {
- return textfield_;
+ColorChooser::ColorChooser(ColorChooserListener* listener, SkColor initial)
+ : listener_(listener), initial_color_(initial) {}
+
+ColorChooser::~ColorChooser() = default;
+
+void ColorChooser::SetColor(SkColor color) {
+ SkColorToHSV(color, hsv_);
+ listener_->OnColorChosen(GetColor());
+}
+
+void ColorChooser::SetHue(SkScalar hue) {
+ hsv_[0] = hue;
+ listener_->OnColorChosen(GetColor());
+}
+
+void ColorChooser::SetSaturationValue(SkScalar saturation, SkScalar value) {
+ hsv_[1] = saturation;
+ hsv_[2] = value;
+ listener_->OnColorChosen(GetColor());
+}
+
+SkColor ColorChooser::GetColor() const {
+ return SkHSVToColor(255, hsv_);
}
-void ColorChooserView::WindowClosing() {
- if (listener_)
- listener_->OnColorChooserDialogClosed();
+void ColorChooser::OnViewClosing() {
+ listener_->OnColorChooserDialogClosed();
}
} // namespace views
diff --git a/chromium/ui/views/color_chooser/color_chooser_view.h b/chromium/ui/views/color_chooser/color_chooser_view.h
index 60bf2ac9b7f..8ff12948052 100644
--- a/chromium/ui/views/color_chooser/color_chooser_view.h
+++ b/chromium/ui/views/color_chooser/color_chooser_view.h
@@ -5,86 +5,102 @@
#ifndef UI_VIEWS_COLOR_CHOOSER_COLOR_CHOOSER_VIEW_H_
#define UI_VIEWS_COLOR_CHOOSER_COLOR_CHOOSER_VIEW_H_
+#include <memory>
+
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkScalar.h"
#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/view.h"
+#include "ui/views/view_tracker.h"
#include "ui/views/views_export.h"
-#include "ui/views/widget/widget_delegate.h"
namespace views {
class ColorChooserListener;
class Textfield;
+class WidgetDelegate;
+
+class HueView;
+class SaturationValueView;
+class SelectedColorPatchView;
-// ColorChooserView provides the UI to choose a color by mouse and/or keyboard.
+// ColorChooser provides the UI to choose a color by mouse and/or keyboard.
// It is typically used for <input type="color">. Currently the user can
// choose a color by dragging over the bar for hue and the area for saturation
// and value.
-class VIEWS_EXPORT ColorChooserView : public WidgetDelegateView,
- public TextfieldController {
+//
+// All public methods on ColorChooser are safe to call before, during, or after
+// the existence of the corresponding Widget/Views/etc.
+class VIEWS_EXPORT ColorChooser : public TextfieldController,
+ public base::SupportsWeakPtr<ColorChooser> {
public:
- ColorChooserView(ColorChooserListener* listener, SkColor initial_color);
- ~ColorChooserView() override;
-
- // Called when its color value is changed in the web contents.
- void OnColorChanged(SkColor color);
+ ColorChooser(ColorChooserListener* listener, SkColor initial_color);
+ ~ColorChooser() override;
- // Called when the user chooses a hue from the UI.
- void OnHueChosen(SkScalar hue);
+ // Construct the WidgetDelegate that should be used to show the actual dialog
+ // for this ColorChooser. It is only safe to call this once per ColorChooser
+ // instance.
+ std::unique_ptr<WidgetDelegate> MakeWidgetDelegate();
- // Called when the user chooses saturation/value from the UI.
- void OnSaturationValueChosen(SkScalar saturation, SkScalar value);
+ SkColor GetColor() const;
+ SkScalar hue() const { return hsv_[0]; }
+ SkScalar saturation() const { return hsv_[1]; }
+ SkScalar value() const { return hsv_[2]; }
- float hue() const { return hsv_[0]; }
- float saturation() const { return hsv_[1]; }
- float value() const { return hsv_[2]; }
- void set_listener(ColorChooserListener* listener) { listener_ = listener; }
+ bool IsViewAttached() const;
- View* hue_view_for_testing();
- View* saturation_value_view_for_testing();
- Textfield* textfield_for_testing();
- View* selected_color_patch_for_testing();
+ // Called when its color value is changed in the web contents.
+ void OnColorChanged(SkColor color);
- // TextfieldController overrides:
+ // TextfieldController overrides, public for testing:
void ContentsChanged(Textfield* sender,
const base::string16& new_contents) override;
bool HandleKeyEvent(Textfield* sender,
const ui::KeyEvent& key_event) override;
+ View* hue_view_for_testing();
+ View* saturation_value_view_for_testing();
+ Textfield* textfield_for_testing();
+ View* selected_color_patch_for_testing();
+
private:
- class HueView;
- class SaturationValueView;
- class SelectedColorPatchView;
+ std::unique_ptr<View> BuildView();
- // WidgetDelegate overrides:
- bool CanMinimize() const override;
- View* GetInitiallyFocusedView() override;
- void WindowClosing() override;
+ void SetColor(SkColor color);
+ void SetHue(SkScalar hue);
+ void SetSaturationValue(SkScalar saturation, SkScalar value);
+
+ void OnViewClosing();
+
+ // Called when the user chooses a hue from the UI.
+ void OnHueChosen(SkScalar hue);
+
+ // Called when the user chooses saturation/value from the UI.
+ void OnSaturationValueChosen(SkScalar saturation, SkScalar value);
// The current color in HSV coordinate.
SkScalar hsv_[3];
- // The pointer to the current color chooser for callbacks. It doesn't take
- // ownership on |listener_| so the user of this class should take care of
- // its lifetime. See chrome/browser/ui/browser.cc for example.
ColorChooserListener* listener_;
+ ViewTracker tracker_;
// Child views. These are owned as part of the normal views hierarchy.
// The view of hue chooser.
- HueView* hue_;
+ HueView* hue_ = nullptr;
// The view of saturation/value choosing area.
- SaturationValueView* saturation_value_;
-
- // The textfield to write the color explicitly.
- Textfield* textfield_;
+ SaturationValueView* saturation_value_ = nullptr;
// The rectangle to denote the selected color.
- SelectedColorPatchView* selected_color_patch_;
+ SelectedColorPatchView* selected_color_patch_ = nullptr;
+
+ // The textfield to write the color explicitly.
+ Textfield* textfield_ = nullptr;
- DISALLOW_COPY_AND_ASSIGN(ColorChooserView);
+ SkColor initial_color_;
};
} // namespace views
diff --git a/chromium/ui/views/controls/button/button.cc b/chromium/ui/views/controls/button/button.cc
index e1f389d6e1c..506241b8e2c 100644
--- a/chromium/ui/views/controls/button/button.cc
+++ b/chromium/ui/views/controls/button/button.cc
@@ -347,7 +347,7 @@ void Button::SetHighlighted(bool bubble_visible) {
nullptr);
}
-PropertyChangedSubscription Button::AddStateChangedCallback(
+base::CallbackListSubscription Button::AddStateChangedCallback(
PropertyChangedCallback callback) {
return AddPropertyChangedCallback(&state_, std::move(callback));
}
@@ -591,7 +591,7 @@ Button::Button(PressedCallback callback)
: AnimationDelegateViews(this),
callback_(std::move(callback)),
ink_drop_base_color_(gfx::kPlaceholderColor) {
- SetFocusBehavior(PlatformStyle::DefaultFocusBehavior());
+ SetFocusBehavior(PlatformStyle::kDefaultFocusBehavior);
SetProperty(kIsButtonProperty, true);
hover_animation_.SetSlideDuration(base::TimeDelta::FromMilliseconds(150));
SetInstallFocusRingOnFocus(true);
@@ -695,7 +695,7 @@ ADD_PROPERTY_METADATA(PressedCallback, Callback)
ADD_PROPERTY_METADATA(bool, AnimateOnStateChange)
ADD_PROPERTY_METADATA(bool, HasInkDropActionOnClick)
ADD_PROPERTY_METADATA(bool, HideInkDropWhenShowingContextMenu)
-ADD_PROPERTY_METADATA(SkColor, InkDropBaseColor)
+ADD_PROPERTY_METADATA(SkColor, InkDropBaseColor, metadata::SkColorConverter)
ADD_PROPERTY_METADATA(bool, InstallFocusRingOnFocus)
ADD_PROPERTY_METADATA(bool, RequestFocusOnPress)
ADD_PROPERTY_METADATA(ButtonState, State)
diff --git a/chromium/ui/views/controls/button/button.h b/chromium/ui/views/controls/button/button.h
index d2ae90642d6..6e059dcb12c 100644
--- a/chromium/ui/views/controls/button/button.h
+++ b/chromium/ui/views/controls/button/button.h
@@ -182,7 +182,7 @@ class VIEWS_EXPORT Button : public InkDropHostView,
// Highlights the ink drop for the button.
void SetHighlighted(bool bubble_visible);
- PropertyChangedSubscription AddStateChangedCallback(
+ base::CallbackListSubscription AddStateChangedCallback(
PropertyChangedCallback callback);
// Overridden from View:
@@ -355,7 +355,7 @@ class VIEWS_EXPORT Button : public InkDropHostView,
// ButtonController.
std::unique_ptr<ButtonController> button_controller_;
- PropertyChangedSubscription enabled_changed_subscription_{
+ base::CallbackListSubscription enabled_changed_subscription_{
AddEnabledChangedCallback(base::BindRepeating(&Button::OnEnabledChanged,
base::Unretained(this)))};
diff --git a/chromium/ui/views/controls/button/button_unittest.cc b/chromium/ui/views/controls/button/button_unittest.cc
index 8955695509f..74cce33fc2b 100644
--- a/chromium/ui/views/controls/button/button_unittest.cc
+++ b/chromium/ui/views/controls/button/button_unittest.cc
@@ -155,8 +155,8 @@ class TestButtonObserver {
bool highlighted_changed_ = false;
bool state_changed_ = false;
- PropertyChangedSubscription highlighted_changed_subscription_;
- PropertyChangedSubscription state_changed_subscription_;
+ base::CallbackListSubscription highlighted_changed_subscription_;
+ base::CallbackListSubscription state_changed_subscription_;
DISALLOW_COPY_AND_ASSIGN(TestButtonObserver);
};
diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc
index a0c317ab848..3b67a434853 100644
--- a/chromium/ui/views/controls/button/checkbox.cc
+++ b/chromium/ui/views/controls/button/checkbox.cc
@@ -83,7 +83,7 @@ bool Checkbox::GetChecked() const {
return checked_;
}
-PropertyChangedSubscription Checkbox::AddCheckedChangedCallback(
+base::CallbackListSubscription Checkbox::AddCheckedChangedCallback(
PropertyChangedCallback callback) {
return AddPropertyChangedCallback(&checked_, callback);
}
diff --git a/chromium/ui/views/controls/button/checkbox.h b/chromium/ui/views/controls/button/checkbox.h
index 86cc2f134db..57fcacdc1ab 100644
--- a/chromium/ui/views/controls/button/checkbox.h
+++ b/chromium/ui/views/controls/button/checkbox.h
@@ -36,7 +36,7 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
virtual void SetChecked(bool checked);
bool GetChecked() const;
- PropertyChangedSubscription AddCheckedChangedCallback(
+ base::CallbackListSubscription AddCheckedChangedCallback(
PropertyChangedCallback callback) WARN_UNUSED_RESULT;
void SetMultiLine(bool multi_line);
diff --git a/chromium/ui/views/controls/button/image_button.cc b/chromium/ui/views/controls/button/image_button.cc
index 0762225e0ba..98c22e003c2 100644
--- a/chromium/ui/views/controls/button/image_button.cc
+++ b/chromium/ui/views/controls/button/image_button.cc
@@ -13,6 +13,7 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/scoped_canvas.h"
+#include "ui/views/background.h"
#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/painter.h"
#include "ui/views/widget/widget.h"
@@ -246,6 +247,11 @@ void ToggleImageButton::SetToggledImage(ButtonState image_state,
}
}
+void ToggleImageButton::SetToggledBackground(std::unique_ptr<Background> b) {
+ toggled_background_ = std::move(b);
+ SchedulePaint();
+}
+
base::string16 ToggleImageButton::GetToggledTooltipText() const {
return toggled_tooltip_text_;
}
@@ -290,6 +296,15 @@ void ToggleImageButton::SetImage(ButtonState image_state,
PreferredSizeChanged();
}
+void ToggleImageButton::OnPaintBackground(gfx::Canvas* canvas) {
+ if (toggled_ && toggled_background_) {
+ TRACE_EVENT0("views", "View::OnPaintBackground");
+ toggled_background_->Paint(canvas, this);
+ } else {
+ ImageButton::OnPaintBackground(canvas);
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// ToggleImageButton, View overrides:
@@ -342,6 +357,7 @@ END_METADATA
BEGIN_METADATA(ToggleImageButton, ImageButton)
ADD_PROPERTY_METADATA(bool, Toggled)
+ADD_PROPERTY_METADATA(std::unique_ptr<Background>, ToggledBackground)
ADD_PROPERTY_METADATA(base::string16, ToggledTooltipText)
ADD_PROPERTY_METADATA(base::string16, ToggledAccessibleName)
END_METADATA
diff --git a/chromium/ui/views/controls/button/image_button.h b/chromium/ui/views/controls/button/image_button.h
index 6ea3fdfb46e..6bf0541e6bc 100644
--- a/chromium/ui/views/controls/button/image_button.h
+++ b/chromium/ui/views/controls/button/image_button.h
@@ -138,6 +138,11 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
// before the button is toggled.
void SetToggledImage(ButtonState state, const gfx::ImageSkia* image);
+ // Like Views::SetBackground(), but to set the background color used for the
+ // "has been toggled" state.
+ void SetToggledBackground(std::unique_ptr<Background> b);
+ Background* GetToggledBackground() const { return toggled_background_.get(); }
+
// Get/Set the tooltip text displayed when the button is toggled.
base::string16 GetToggledTooltipText() const;
void SetToggledTooltipText(const base::string16& tooltip);
@@ -153,6 +158,7 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
// Overridden from View:
base::string16 GetTooltipText(const gfx::Point& p) const override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+ void OnPaintBackground(gfx::Canvas* canvas) override;
private:
// The parent class's images_ member is used for the current images,
@@ -163,6 +169,8 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
// True if the button is currently toggled.
bool toggled_ = false;
+ std::unique_ptr<Background> toggled_background_;
+
// The parent class's tooltip_text_ is displayed when not toggled, and
// this one is shown when toggled.
base::string16 toggled_tooltip_text_;
@@ -176,6 +184,7 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
BEGIN_VIEW_BUILDER(VIEWS_EXPORT, ToggleImageButton, ImageButton)
VIEW_BUILDER_PROPERTY(bool, Toggled)
+VIEW_BUILDER_PROPERTY(std::unique_ptr<Background>, ToggledBackground)
VIEW_BUILDER_PROPERTY(base::string16, ToggledTooltipText)
VIEW_BUILDER_PROPERTY(base::string16, ToggledAccessibleName)
END_VIEW_BUILDER
diff --git a/chromium/ui/views/controls/button/image_button_unittest.cc b/chromium/ui/views/controls/button/image_button_unittest.cc
index c5830643357..cf3c9310c3d 100644
--- a/chromium/ui/views/controls/button/image_button_unittest.cc
+++ b/chromium/ui/views/controls/button/image_button_unittest.cc
@@ -43,7 +43,7 @@ using ImageButtonTest = ViewsTestBase;
TEST_F(ImageButtonTest, FocusBehavior) {
ImageButton button;
- EXPECT_EQ(PlatformStyle::DefaultFocusBehavior(), button.GetFocusBehavior());
+ EXPECT_EQ(PlatformStyle::kDefaultFocusBehavior, button.GetFocusBehavior());
}
TEST_F(ImageButtonTest, Basics) {
diff --git a/chromium/ui/views/controls/button/label_button.cc b/chromium/ui/views/controls/button/label_button.cc
index 563bc70f496..e8b6cd6b290 100644
--- a/chromium/ui/views/controls/button/label_button.cc
+++ b/chromium/ui/views/controls/button/label_button.cc
@@ -246,6 +246,9 @@ gfx::Size LabelButton::CalculatePreferredSize() const {
// Account for the label only when the button is not shrinking down to hide
// the label entirely.
if (!shrinking_down_label_) {
+ if (!label_->GetMultiLine() && max_size_.width() > 0)
+ label_->SetMaximumWidthSingleLine(max_size_.width() - size.width());
+
const gfx::Size preferred_label_size = label_->GetPreferredSize();
size.Enlarge(preferred_label_size.width(), 0);
size.SetToMax(
@@ -476,7 +479,7 @@ void LabelButton::AddedToWidget() {
}
void LabelButton::RemovedFromWidget() {
- paint_as_active_subscription_.reset();
+ paint_as_active_subscription_ = {};
}
void LabelButton::OnFocus() {
diff --git a/chromium/ui/views/controls/button/label_button.h b/chromium/ui/views/controls/button/label_button.h
index 5dbf8e3e9c8..39887eb2625 100644
--- a/chromium/ui/views/controls/button/label_button.h
+++ b/chromium/ui/views/controls/button/label_button.h
@@ -263,10 +263,9 @@ class VIEWS_EXPORT LabelButton : public Button, public NativeThemeDelegate {
// UI direction).
gfx::HorizontalAlignment horizontal_alignment_ = gfx::ALIGN_LEFT;
- std::unique_ptr<Widget::PaintAsActiveCallbackList::Subscription>
- paint_as_active_subscription_;
+ base::CallbackListSubscription paint_as_active_subscription_;
- PropertyChangedSubscription flip_canvas_on_paint_subscription_ =
+ base::CallbackListSubscription flip_canvas_on_paint_subscription_ =
AddFlipCanvasOnPaintForRTLUIChangedCallback(
base::BindRepeating(&LabelButton::FlipCanvasOnPaintForRTLUIChanged,
base::Unretained(this)));
diff --git a/chromium/ui/views/controls/button/label_button_label.cc b/chromium/ui/views/controls/button/label_button_label.cc
index a1ec3993631..7bb2053e0e3 100644
--- a/chromium/ui/views/controls/button/label_button_label.cc
+++ b/chromium/ui/views/controls/button/label_button_label.cc
@@ -4,6 +4,8 @@
#include "ui/views/controls/button/label_button_label.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
+
namespace views {
namespace internal {
@@ -35,15 +37,19 @@ void LabelButtonLabel::OnEnabledChanged() {
}
void LabelButtonLabel::SetColorForEnableState() {
- if (GetEnabled() ? requested_enabled_color_ : requested_disabled_color_) {
- Label::SetEnabledColor(GetEnabled() ? *requested_enabled_color_
- : *requested_disabled_color_);
+ const base::Optional<SkColor>& color =
+ GetEnabled() ? requested_enabled_color_ : requested_disabled_color_;
+ if (color) {
+ Label::SetEnabledColor(*color);
} else {
int style = GetEnabled() ? style::STYLE_PRIMARY : style::STYLE_DISABLED;
Label::SetEnabledColor(style::GetColor(*this, GetTextContext(), style));
}
}
+BEGIN_METADATA(LabelButtonLabel, Label)
+END_METADATA
+
} // namespace internal
} // namespace views
diff --git a/chromium/ui/views/controls/button/label_button_label.h b/chromium/ui/views/controls/button/label_button_label.h
index 88ab37127f1..0c7d0c0291f 100644
--- a/chromium/ui/views/controls/button/label_button_label.h
+++ b/chromium/ui/views/controls/button/label_button_label.h
@@ -6,12 +6,12 @@
#define UI_VIEWS_CONTROLS_BUTTON_LABEL_BUTTON_LABEL_H_
#include "base/bind.h"
-#include "base/macros.h"
#include "base/optional.h"
#include "base/strings/string16.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/color_palette.h"
#include "ui/views/controls/label.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/views_export.h"
namespace views {
@@ -22,7 +22,10 @@ namespace internal {
// views::LabelButton.
class VIEWS_EXPORT LabelButtonLabel : public Label {
public:
+ METADATA_HEADER(LabelButtonLabel);
LabelButtonLabel(const base::string16& text, int text_context);
+ LabelButtonLabel(const LabelButtonLabel&) = delete;
+ LabelButtonLabel& operator=(const LabelButtonLabel&) = delete;
~LabelButtonLabel() override;
// Set an explicit disabled color. This will stop the Label responding to
@@ -42,12 +45,10 @@ class VIEWS_EXPORT LabelButtonLabel : public Label {
base::Optional<SkColor> requested_disabled_color_;
base::Optional<SkColor> requested_enabled_color_;
- PropertyChangedSubscription enabled_changed_subscription_ =
+ base::CallbackListSubscription enabled_changed_subscription_ =
AddEnabledChangedCallback(
base::BindRepeating(&LabelButtonLabel::OnEnabledChanged,
base::Unretained(this)));
-
- DISALLOW_COPY_AND_ASSIGN(LabelButtonLabel);
};
} // namespace internal
diff --git a/chromium/ui/views/controls/button/label_button_unittest.cc b/chromium/ui/views/controls/button/label_button_unittest.cc
index 0f55418d4ba..5b50d07d5c1 100644
--- a/chromium/ui/views/controls/button/label_button_unittest.cc
+++ b/chromium/ui/views/controls/button/label_button_unittest.cc
@@ -5,6 +5,7 @@
#include "ui/views/controls/button/label_button.h"
#include <algorithm>
+#include <string>
#include <utility>
#include "base/command_line.h"
@@ -143,7 +144,7 @@ class LabelButtonTest : public test::WidgetTest {
};
TEST_F(LabelButtonTest, FocusBehavior) {
- EXPECT_EQ(PlatformStyle::DefaultFocusBehavior(), button_->GetFocusBehavior());
+ EXPECT_EQ(PlatformStyle::kDefaultFocusBehavior, button_->GetFocusBehavior());
}
TEST_F(LabelButtonTest, Init) {
@@ -193,7 +194,9 @@ TEST_F(LabelButtonTest, Label) {
// Clamp the size to a maximum value.
button_->SetText(long_text);
button_->SetMaxSize(gfx::Size(short_text_width, 1));
- EXPECT_EQ(button_->GetPreferredSize(), gfx::Size(short_text_width, 1));
+ const gfx::Size preferred_size = button_->GetPreferredSize();
+ EXPECT_LE(preferred_size.width(), short_text_width);
+ EXPECT_EQ(1, preferred_size.height());
// Clamp the size to a minimum value.
button_->SetText(short_text);
@@ -203,6 +206,48 @@ TEST_F(LabelButtonTest, Label) {
gfx::Size(long_text_width, font_list.GetHeight() * 2));
}
+// Tests LabelButton's usage of SetMaximumWidthSingleLine.
+TEST_F(LabelButtonTest, LabelPreferredSizeWithMaxWidth) {
+ const std::string text_cases[] = {
+ {"The"},
+ {"The quick"},
+ {"The quick brown"},
+ {"The quick brown fox"},
+ {"The quick brown fox jumps"},
+ {"The quick brown fox jumps over"},
+ {"The quick brown fox jumps over the"},
+ {"The quick brown fox jumps over the lazy"},
+ {"The quick brown fox jumps over the lazy dog"},
+ };
+
+ const int width_cases[] = {
+ 10, 30, 50, 70, 90, 110, 130, 170, 200, 500,
+ };
+
+ for (bool set_image = false; button_->GetImage(Button::STATE_NORMAL).isNull();
+ set_image = true) {
+ if (set_image)
+ button_->SetImage(Button::STATE_NORMAL, CreateTestImage(16, 16));
+
+ bool preferred_size_is_sometimes_narrower_than_max = false;
+
+ for (size_t i = 0; i < base::size(text_cases); ++i) {
+ for (size_t j = 0; j < base::size(width_cases); ++j) {
+ button_->SetText(ASCIIToUTF16(text_cases[i]));
+ button_->SetMaxSize(gfx::Size(width_cases[j], 30));
+
+ const gfx::Size preferred_size = button_->GetPreferredSize();
+ EXPECT_LE(preferred_size.width(), width_cases[j]);
+
+ if (preferred_size.width() < width_cases[j])
+ preferred_size_is_sometimes_narrower_than_max = true;
+ }
+ }
+
+ EXPECT_TRUE(preferred_size_is_sometimes_narrower_than_max);
+ }
+}
+
TEST_F(LabelButtonTest, LabelShrinkDown) {
ASSERT_TRUE(button_->GetText().empty());
diff --git a/chromium/ui/views/controls/button/menu_button.h b/chromium/ui/views/controls/button/menu_button.h
index 44a66ee24fd..a05b763a36a 100644
--- a/chromium/ui/views/controls/button/menu_button.h
+++ b/chromium/ui/views/controls/button/menu_button.h
@@ -5,9 +5,10 @@
#ifndef UI_VIEWS_CONTROLS_BUTTON_MENU_BUTTON_H_
#define UI_VIEWS_CONTROLS_BUTTON_MENU_BUTTON_H_
-#include "base/macros.h"
#include "base/strings/string16.h"
#include "ui/views/controls/button/label_button.h"
+#include "ui/views/metadata/metadata_header_macros.h"
+#include "ui/views/metadata/view_factory.h"
namespace views {
@@ -23,10 +24,11 @@ class MenuButtonController;
class VIEWS_EXPORT MenuButton : public LabelButton {
public:
METADATA_HEADER(MenuButton);
-
explicit MenuButton(PressedCallback callback = PressedCallback(),
const base::string16& text = base::string16(),
int button_context = style::CONTEXT_BUTTON);
+ MenuButton(const MenuButton&) = delete;
+ MenuButton& operator=(const MenuButton&) = delete;
~MenuButton() override;
MenuButtonController* button_controller() const {
@@ -41,10 +43,13 @@ class VIEWS_EXPORT MenuButton : public LabelButton {
private:
MenuButtonController* menu_button_controller_;
-
- DISALLOW_COPY_AND_ASSIGN(MenuButton);
};
+BEGIN_VIEW_BUILDER(VIEWS_EXPORT, MenuButton, LabelButton)
+END_VIEW_BUILDER
+
} // namespace views
+DEFINE_VIEW_BUILDER(VIEWS_EXPORT, MenuButton)
+
#endif // UI_VIEWS_CONTROLS_BUTTON_MENU_BUTTON_H_
diff --git a/chromium/ui/views/controls/button/menu_button_controller.cc b/chromium/ui/views/controls/button/menu_button_controller.cc
index f621f8b1620..ee45a1bf1c3 100644
--- a/chromium/ui/views/controls/button/menu_button_controller.cc
+++ b/chromium/ui/views/controls/button/menu_button_controller.cc
@@ -223,7 +223,7 @@ bool MenuButtonController::Activate(const ui::Event* event) {
// mouse target during the mouse press we explicitly set the mouse handler
// to NULL.
static_cast<internal::RootView*>(button()->GetWidget()->GetRootView())
- ->SetMouseHandler(nullptr);
+ ->SetMouseAndGestureHandler(nullptr);
DCHECK(increment_pressed_lock_called_ == nullptr);
// Observe if IncrementPressedLocked() was called so we can trigger the
@@ -319,7 +319,7 @@ void MenuButtonController::DecrementPressedLocked() {
// If this was the last lock, manually reset state to the desired state.
if (pressed_lock_count_ == 0) {
menu_closed_time_ = TimeTicks::Now();
- state_changed_subscription_.reset();
+ state_changed_subscription_ = {};
LabelButton::ButtonState desired_state = Button::STATE_NORMAL;
if (should_disable_after_press_) {
desired_state = Button::STATE_DISABLED;
diff --git a/chromium/ui/views/controls/button/menu_button_controller.h b/chromium/ui/views/controls/button/menu_button_controller.h
index a7129e6ceea..6c0afacf5a7 100644
--- a/chromium/ui/views/controls/button/menu_button_controller.h
+++ b/chromium/ui/views/controls/button/menu_button_controller.h
@@ -115,7 +115,7 @@ class VIEWS_EXPORT MenuButtonController : public ButtonController {
bool should_disable_after_press_ = false;
// Subscribes to state changes on the button while pressed lock is engaged.
- views::PropertyChangedSubscription state_changed_subscription_;
+ base::CallbackListSubscription state_changed_subscription_;
base::WeakPtrFactory<MenuButtonController> weak_factory_{this};
diff --git a/chromium/ui/views/controls/combobox/combobox.cc b/chromium/ui/views/controls/combobox/combobox.cc
index f911fa3aeb0..8a1bd561de0 100644
--- a/chromium/ui/views/controls/combobox/combobox.cc
+++ b/chromium/ui/views/controls/combobox/combobox.cc
@@ -309,14 +309,16 @@ void Combobox::SetOwnedModel(std::unique_ptr<ui::ComboboxModel> model) {
void Combobox::SetModel(ui::ComboboxModel* model) {
DCHECK(model) << "After construction, the model must not be null.";
- if (model_)
- observer_.Remove(model_);
+ if (model_) {
+ DCHECK(observation_.IsObservingSource(model_));
+ observation_.Reset();
+ }
model_ = model;
if (model_) {
menu_model_ = std::make_unique<ComboboxMenuModel>(this, model_);
- observer_.Add(model_);
+ observation_.Observe(model_);
SetSelectedIndex(model_->GetDefaultIndex());
OnComboboxModelChanged(model_);
}
diff --git a/chromium/ui/views/controls/combobox/combobox.h b/chromium/ui/views/controls/combobox/combobox.h
index 812810cc3b3..fa781688732 100644
--- a/chromium/ui/views/controls/combobox/combobox.h
+++ b/chromium/ui/views/controls/combobox/combobox.h
@@ -9,7 +9,7 @@
#include <utility>
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "ui/base/models/combobox_model.h"
@@ -224,7 +224,8 @@ class VIEWS_EXPORT Combobox : public View,
// The focus ring for this Combobox.
FocusRing* focus_ring_ = nullptr;
- ScopedObserver<ui::ComboboxModel, ui::ComboboxModelObserver> observer_{this};
+ base::ScopedObservation<ui::ComboboxModel, ui::ComboboxModelObserver>
+ observation_{this};
DISALLOW_COPY_AND_ASSIGN(Combobox);
};
diff --git a/chromium/ui/views/controls/dot_indicator.cc b/chromium/ui/views/controls/dot_indicator.cc
new file mode 100644
index 00000000000..d1b3e4410d8
--- /dev/null
+++ b/chromium/ui/views/controls/dot_indicator.cc
@@ -0,0 +1,75 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/dot_indicator.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
+
+namespace views {
+
+DotIndicator::~DotIndicator() = default;
+
+// static
+DotIndicator* DotIndicator::Install(View* parent) {
+ auto dot = base::WrapUnique<DotIndicator>(new DotIndicator());
+ dot->SetPaintToLayer();
+ dot->layer()->SetFillsBoundsOpaquely(false);
+ dot->SetVisible(false);
+ return parent->AddChildView(std::move(dot));
+}
+
+void DotIndicator::SetColor(SkColor dot_color, SkColor border_color) {
+ dot_color_ = dot_color;
+ border_color_ = border_color;
+ SchedulePaint();
+}
+
+void DotIndicator::Show() {
+ SetVisible(true);
+}
+
+void DotIndicator::Hide() {
+ SetVisible(false);
+}
+
+DotIndicator::DotIndicator() {
+ // Don't allow the view to process events.
+ SetCanProcessEventsWithinSubtree(false);
+}
+
+void DotIndicator::OnPaint(gfx::Canvas* canvas) {
+ canvas->SaveLayerAlpha(SK_AlphaOPAQUE);
+
+ DCHECK_EQ(width(), height());
+ float radius = width() / 2.0f;
+ const float scale = canvas->UndoDeviceScaleFactor();
+ const int kStrokeWidthPx = 1;
+ gfx::PointF center = gfx::RectF(GetLocalBounds()).CenterPoint();
+ center.Scale(scale);
+
+ // Fill the center.
+ cc::PaintFlags flags;
+ flags.setColor(dot_color_);
+ flags.setAntiAlias(true);
+ canvas->DrawCircle(center, scale * radius - kStrokeWidthPx, flags);
+
+ // Draw the border.
+ flags.setColor(border_color_);
+ flags.setStyle(cc::PaintFlags::kStroke_Style);
+ flags.setStrokeWidth(kStrokeWidthPx * scale);
+ canvas->DrawCircle(center, scale * radius - kStrokeWidthPx / 2.0f, flags);
+}
+
+BEGIN_METADATA(DotIndicator, View)
+END_METADATA
+
+} // namespace views
diff --git a/chromium/ui/views/controls/dot_indicator.h b/chromium/ui/views/controls/dot_indicator.h
new file mode 100644
index 00000000000..f3473de642b
--- /dev/null
+++ b/chromium/ui/views/controls/dot_indicator.h
@@ -0,0 +1,43 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_DOT_INDICATOR_H_
+#define UI_VIEWS_CONTROLS_DOT_INDICATOR_H_
+
+#include "base/macros.h"
+#include "ui/views/view.h"
+
+namespace views {
+
+// Dot indicator that can be added to a view, usually used as a status
+// indicator.
+class VIEWS_EXPORT DotIndicator : public View {
+ public:
+ METADATA_HEADER(DotIndicator);
+ DotIndicator(DotIndicator&) = delete;
+ DotIndicator& operator=(const DotIndicator&) = delete;
+ ~DotIndicator() override;
+
+ // Create a DotIndicator and adds it to |parent|. The returned dot indicator
+ // is owned by the |parent|.
+ static DotIndicator* Install(View* parent);
+
+ void SetColor(SkColor dot_color, SkColor border_color);
+
+ void Show();
+ void Hide();
+
+ private:
+ DotIndicator();
+
+ // View:
+ void OnPaint(gfx::Canvas* canvas) override;
+
+ SkColor dot_color_ = SK_ColorRED;
+ SkColor border_color_ = SK_ColorWHITE;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_DOT_INDICATOR_H_
diff --git a/chromium/ui/views/controls/editable_combobox/editable_combobox.cc b/chromium/ui/views/controls/editable_combobox/editable_combobox.cc
index b9203707279..696e8ae29c5 100644
--- a/chromium/ui/views/controls/editable_combobox/editable_combobox.cc
+++ b/chromium/ui/views/controls/editable_combobox/editable_combobox.cc
@@ -52,6 +52,7 @@
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/layout_manager.h"
#include "ui/views/layout/layout_provider.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/style/typography.h"
@@ -64,6 +65,8 @@ namespace {
class Arrow : public Button {
public:
+ METADATA_HEADER(Arrow);
+
explicit Arrow(PressedCallback callback) : Button(std::move(callback)) {
// Similar to Combobox's TransparentButton.
SetFocusBehavior(FocusBehavior::NEVER);
@@ -73,6 +76,8 @@ class Arrow : public Button {
SetInkDropMode(InkDropMode::ON);
SetHasInkDropActionOnClick(true);
}
+ Arrow(const Arrow&) = delete;
+ Arrow& operator=(const Arrow&) = delete;
~Arrow() override = default;
double GetAnimationValue() const {
@@ -115,10 +120,11 @@ class Arrow : public Button {
if (GetEnabled())
node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kOpen);
}
-
- DISALLOW_COPY_AND_ASSIGN(Arrow);
};
+BEGIN_METADATA(Arrow, Button)
+END_METADATA
+
} // namespace
// Adapts a ui::ComboboxModel to a ui::MenuModel to be used by EditableCombobox.
@@ -136,7 +142,7 @@ class EditableCombobox::EditableComboboxMenuModel
filter_on_edit_(filter_on_edit),
show_on_empty_(show_on_empty) {
UpdateItemsShown();
- observer_.Add(combobox_model_);
+ observation_.Observe(combobox_model_);
}
~EditableComboboxMenuModel() override = default;
@@ -252,7 +258,8 @@ class EditableCombobox::EditableComboboxMenuModel
// When false, UpdateItemsShown doesn't do anything.
bool update_items_shown_enabled_ = true;
- ScopedObserver<ui::ComboboxModel, ui::ComboboxModelObserver> observer_{this};
+ base::ScopedObservation<ui::ComboboxModel, ui::ComboboxModelObserver>
+ observation_{this};
DISALLOW_COPY_AND_ASSIGN(EditableComboboxMenuModel);
};
@@ -322,7 +329,7 @@ EditableCombobox::EditableCombobox(
show_on_empty_(show_on_empty),
showing_password_text_(type != Type::kPassword) {
SetModel(std::move(combobox_model));
- observer_.Add(textfield_);
+ observation_.Observe(textfield_);
textfield_->set_controller(this);
textfield_->SetFontList(GetFontList());
textfield_->SetTextInputType((type == Type::kPassword)
diff --git a/chromium/ui/views/controls/editable_combobox/editable_combobox.h b/chromium/ui/views/controls/editable_combobox/editable_combobox.h
index a87863dd9cc..d2e68f3e257 100644
--- a/chromium/ui/views/controls/editable_combobox/editable_combobox.h
+++ b/chromium/ui/views/controls/editable_combobox/editable_combobox.h
@@ -10,12 +10,13 @@
#include "base/callback.h"
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/layout/animating_layout_manager.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/style/typography.h"
#include "ui/views/view.h"
#include "ui/views/view_observer.h"
@@ -187,7 +188,7 @@ class VIEWS_EXPORT EditableCombobox
bool dropdown_blocked_for_animation_ = false;
- ScopedObserver<View, ViewObserver> observer_{this};
+ base::ScopedObservation<View, ViewObserver> observation_{this};
DISALLOW_COPY_AND_ASSIGN(EditableCombobox);
};
diff --git a/chromium/ui/views/controls/focus_ring.cc b/chromium/ui/views/controls/focus_ring.cc
index e34713127b3..95d55d5347a 100644
--- a/chromium/ui/views/controls/focus_ring.cc
+++ b/chromium/ui/views/controls/focus_ring.cc
@@ -113,13 +113,13 @@ void FocusRing::ViewHierarchyChanged(
if (details.is_add) {
// Need to start observing the parent.
- view_observer_.Add(details.parent);
+ view_observation_.Observe(details.parent);
RefreshLayer();
- } else if (view_observer_.IsObserving(details.parent)) {
+ } else if (view_observation_.IsObservingSource(details.parent)) {
// This view is being removed from its parent. It needs to remove itself
// from its parent's observer list in the case where the FocusView is
// removed from its parent but not deleted.
- view_observer_.Remove(details.parent);
+ view_observation_.Reset();
}
}
diff --git a/chromium/ui/views/controls/focus_ring.h b/chromium/ui/views/controls/focus_ring.h
index c3e42b6a4da..7882505d6ec 100644
--- a/chromium/ui/views/controls/focus_ring.h
+++ b/chromium/ui/views/controls/focus_ring.h
@@ -7,7 +7,7 @@
#include <memory>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/controls/focusable_border.h"
#include "ui/views/view.h"
@@ -96,7 +96,7 @@ class VIEWS_EXPORT FocusRing : public View, public ViewObserver {
// The predicate used to determine whether the parent has focus.
base::Optional<ViewPredicate> has_focus_predicate_;
- ScopedObserver<View, ViewObserver> view_observer_{this};
+ base::ScopedObservation<View, ViewObserver> view_observation_{this};
DISALLOW_COPY_AND_ASSIGN(FocusRing);
};
diff --git a/chromium/ui/views/controls/image_view.h b/chromium/ui/views/controls/image_view.h
index c39d116b6a6..1eebb3f4252 100644
--- a/chromium/ui/views/controls/image_view.h
+++ b/chromium/ui/views/controls/image_view.h
@@ -91,7 +91,9 @@ class VIEWS_EXPORT ImageView : public View {
void OnPaintImage(gfx::Canvas* canvas);
- // Gets an ImageSkia to paint that has proper rep for |scale|.
+ // Gets an ImageSkia to paint that has proper rep for |scale|. Note that if
+ // there is no existing rep of `scale`, we will utilize the image resize
+ // operation to create one. The resize may be time consuming for a big image.
gfx::ImageSkia GetPaintImage(float scale);
// Returns true if |img| is the same as the last image we painted. This is
diff --git a/chromium/ui/views/controls/label.cc b/chromium/ui/views/controls/label.cc
index 70370d27c47..d7f4226a37f 100644
--- a/chromium/ui/views/controls/label.cc
+++ b/chromium/ui/views/controls/label.cc
@@ -108,6 +108,19 @@ void Label::SetText(const base::string16& new_text) {
stored_selection_range_ = gfx::Range::InvalidRange();
}
+void Label::SetAccessibleName(const base::string16& name) {
+ if (name == accessible_name_)
+ return;
+ accessible_name_ = name;
+ OnPropertyChanged(&accessible_name_, kPropertyEffectsNone);
+ NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true);
+}
+
+const base::string16& Label::GetAccessibleName() const {
+ return accessible_name_.empty() ? full_text_->GetDisplayText()
+ : accessible_name_;
+}
+
int Label::GetTextContext() const {
return text_context_;
}
@@ -116,8 +129,11 @@ void Label::SetTextContext(int text_context) {
if (text_context == text_context_)
return;
text_context_ = text_context;
+ full_text_->SetFontList(style::GetFont(text_context_, text_style_));
+ full_text_->SetMinLineHeight(GetLineHeight());
+ ClearDisplayText();
UpdateColorsFromTheme();
- OnPropertyChanged(&text_context_, views::kPropertyEffectsPaint);
+ OnPropertyChanged(&text_context_, kPropertyEffectsPreferredSizeChanged);
}
int Label::GetTextStyle() const {
@@ -129,12 +145,30 @@ void Label::SetTextStyle(int style) {
return;
text_style_ = style;
- // TODO(pkasting): Seems like potentially |full_text_|'s font list and line
- // height should be updated here?
+ full_text_->SetFontList(style::GetFont(text_context_, text_style_));
+ full_text_->SetMinLineHeight(GetLineHeight());
+ ClearDisplayText();
UpdateColorsFromTheme();
OnPropertyChanged(&text_style_, kPropertyEffectsPreferredSizeChanged);
}
+void Label::SetTextStyleRange(int style, const gfx::Range& range) {
+ if (style == text_style_ || !range.IsValid() || range.is_empty() ||
+ !gfx::Range(0, GetText().size()).Contains(range))
+ return;
+
+ const auto details = style::GetFontDetails(text_context_, style);
+ // This function is not prepared to handle style requests that vary by
+ // anything other than weight.
+ DCHECK_EQ(details.typeface,
+ style::GetFontDetails(text_context_, text_style_).typeface);
+ DCHECK_EQ(details.size_delta,
+ style::GetFontDetails(text_context_, text_style_).size_delta);
+ full_text_->ApplyWeight(details.weight, range);
+ ClearDisplayText();
+ PreferredSizeChanged();
+}
+
bool Label::GetAutoColorReadabilityEnabled() const {
return auto_color_readability_enabled_;
}
@@ -370,6 +404,7 @@ void Label::SetElideBehavior(gfx::ElideBehavior elide_behavior) {
if (elide_behavior_ == elide_behavior)
return;
elide_behavior_ = elide_behavior;
+ UpdateFullTextElideBehavior();
ClearDisplayText();
OnPropertyChanged(&elide_behavior_, kPropertyEffectsPreferredSizeChanged);
}
@@ -417,6 +452,16 @@ void Label::SetMaximumWidth(int max_width) {
OnPropertyChanged(&max_width_, kPropertyEffectsPreferredSizeChanged);
}
+void Label::SetMaximumWidthSingleLine(int max_width) {
+ DCHECK(!GetMultiLine());
+ if (max_width_single_line_ == max_width)
+ return;
+ max_width_single_line_ = max_width;
+ UpdateFullTextElideBehavior();
+ OnPropertyChanged(&max_width_single_line_,
+ kPropertyEffectsPreferredSizeChanged);
+}
+
bool Label::GetCollapseWhenHidden() const {
return collapse_when_hidden_;
}
@@ -504,7 +549,7 @@ std::vector<gfx::Rect> Label::GetSubstringBounds(const gfx::Range& range) {
return substring_bounds;
}
-views::PropertyChangedSubscription Label::AddTextChangedCallback(
+base::CallbackListSubscription Label::AddTextChangedCallback(
views::PropertyChangedCallback callback) {
return AddPropertyChangedCallback(&full_text_ + kLabelText,
std::move(callback));
@@ -619,7 +664,7 @@ void Label::GetAccessibleNodeData(ui::AXNodeData* node_data) {
else
node_data->role = ax::mojom::Role::kStaticText;
- node_data->SetName(full_text_->GetDisplayText());
+ node_data->SetName(GetAccessibleName());
}
base::string16 Label::GetTooltipText(const gfx::Point& p) const {
@@ -642,17 +687,13 @@ std::unique_ptr<gfx::RenderText> Label::CreateRenderText() const {
: elide_behavior_;
std::unique_ptr<gfx::RenderText> render_text =
- gfx::RenderText::CreateRenderText();
+ full_text_->CreateInstanceOfSameStyle(GetText());
render_text->SetHorizontalAlignment(GetHorizontalAlignment());
render_text->SetVerticalAlignment(GetVerticalAlignment());
- render_text->SetDirectionalityMode(full_text_->directionality_mode());
render_text->SetElideBehavior(elide_behavior);
render_text->SetObscured(GetObscured());
render_text->SetMinLineHeight(GetLineHeight());
- render_text->SetFontList(font_list());
render_text->set_shadows(GetShadows());
- render_text->SetCursorEnabled(false);
- render_text->SetText(GetText());
const bool multiline = GetMultiLine();
render_text->SetMultiline(multiline);
render_text->SetMaxLines(multiline ? GetMaxLines() : 0);
@@ -684,7 +725,8 @@ void Label::PaintText(gfx::Canvas* canvas) {
if (display_text_)
display_text_->Draw(canvas);
-#if DCHECK_IS_ON() && !defined(OS_CHROMEOS) && !BUILDFLAG(IS_LACROS)
+#if DCHECK_IS_ON() && !BUILDFLAG(IS_CHROMEOS_ASH) && \
+ !BUILDFLAG(IS_CHROMEOS_LACROS)
// TODO(crbug.com/1139395): Enable this DCHECK on ChromeOS and LaCrOS by
// fixing either this check (to correctly idenfify more paints-on-opaque
// cases), refactoring parents to use background() or by fixing
@@ -773,7 +815,9 @@ bool Label::OnMousePressed(const ui::MouseEvent& event) {
GetFocusManager()->SetFocusedView(this);
}
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
if (event.IsOnlyMiddleMouseButton() && GetFocusManager() && !had_focus)
GetFocusManager()->SetFocusedView(this);
#endif
@@ -960,7 +1004,9 @@ bool Label::PasteSelectionClipboard() {
}
void Label::UpdateSelectionClipboard() {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
if (!GetObscured()) {
ui::ScopedClipboardWriter(ui::ClipboardBuffer::kSelection)
.WriteText(GetSelectedText());
@@ -1031,9 +1077,7 @@ void Label::Init(const base::string16& text,
full_text_->SetCursorEnabled(false);
full_text_->SetWordWrapBehavior(gfx::TRUNCATE_LONG_WORDS);
full_text_->SetMinLineHeight(GetLineHeight());
- // NOTE: |full_text_| should not be elided at all. This is used to keep
- // some properties and to compute the size of the string.
- full_text_->SetElideBehavior(gfx::NO_ELIDE);
+ UpdateFullTextElideBehavior();
full_text_->SetDirectionalityMode(directionality_mode);
SetText(text);
@@ -1067,6 +1111,15 @@ gfx::Size Label::GetTextSize() const {
gfx::Size size;
if (GetText().empty()) {
size = gfx::Size(0, GetLineHeight());
+ } else if (max_width_single_line_ > 0) {
+ DCHECK(!GetMultiLine());
+ // Enable eliding during text width calculation. This allows the RenderText
+ // to report an accurate width given the constraints and how it determines
+ // to elide the text. If we simply clamp the width to the max after the
+ // fact, then there may be some empty space left over *after* an ellipsis.
+ full_text_->SetDisplayRect(
+ gfx::Rect(0, 0, max_width_single_line_ - GetInsets().width(), 0));
+ size = full_text_->GetStringSize();
} else {
// Cancel the display rect of |full_text_|. The display rect may be
// specified in GetHeightForWidth(), and specifying empty Rect cancels
@@ -1181,16 +1234,25 @@ void Label::BuildContextMenuContents() {
IDS_APP_SELECT_ALL);
}
+void Label::UpdateFullTextElideBehavior() {
+ // In single line mode when a max width has been set, |full_text_| uses
+ // elision to properly calculate the text size. Otherwise, it is not elided.
+ full_text_->SetElideBehavior(max_width_single_line_ > 0 ? elide_behavior_
+ : gfx::NO_ELIDE);
+}
+
BEGIN_METADATA(Label, View)
ADD_PROPERTY_METADATA(base::string16, Text)
ADD_PROPERTY_METADATA(int, TextContext)
ADD_PROPERTY_METADATA(int, TextStyle)
ADD_PROPERTY_METADATA(bool, AutoColorReadabilityEnabled)
-ADD_PROPERTY_METADATA(SkColor, EnabledColor)
+ADD_PROPERTY_METADATA(SkColor, EnabledColor, metadata::SkColorConverter)
ADD_PROPERTY_METADATA(gfx::ElideBehavior, ElideBehavior)
-ADD_PROPERTY_METADATA(SkColor, BackgroundColor)
-ADD_PROPERTY_METADATA(SkColor, SelectionTextColor)
-ADD_PROPERTY_METADATA(SkColor, SelectionBackgroundColor)
+ADD_PROPERTY_METADATA(SkColor, BackgroundColor, metadata::SkColorConverter)
+ADD_PROPERTY_METADATA(SkColor, SelectionTextColor, metadata::SkColorConverter)
+ADD_PROPERTY_METADATA(SkColor,
+ SelectionBackgroundColor,
+ metadata::SkColorConverter)
ADD_PROPERTY_METADATA(bool, SubpixelRenderingEnabled)
ADD_PROPERTY_METADATA(bool, SkipSubpixelRenderingOpacityCheck)
ADD_PROPERTY_METADATA(gfx::ShadowValues, Shadows)
@@ -1205,6 +1267,7 @@ ADD_PROPERTY_METADATA(base::string16, TooltipText)
ADD_PROPERTY_METADATA(bool, HandlesTooltips)
ADD_PROPERTY_METADATA(bool, CollapseWhenHidden)
ADD_PROPERTY_METADATA(int, MaximumWidth)
+ADD_PROPERTY_METADATA(base::string16, AccessibleName)
END_METADATA
} // namespace views
diff --git a/chromium/ui/views/controls/label.h b/chromium/ui/views/controls/label.h
index 0a6bac23a2f..793189681a6 100644
--- a/chromium/ui/views/controls/label.h
+++ b/chromium/ui/views/controls/label.h
@@ -90,6 +90,12 @@ class VIEWS_EXPORT Label : public View,
const base::string16& GetText() const;
virtual void SetText(const base::string16& text);
+ // Set the accessibility name that will be announced by the screen reader.
+ // If this function is not called, the screen reader defaults to verbalizing
+ // the text value.
+ void SetAccessibleName(const base::string16& name);
+ const base::string16& GetAccessibleName() const;
+
// Where the label appears in the UI. Passed in from the constructor. This is
// a value from views::style::TextContext or an enum that extends it.
int GetTextContext() const;
@@ -100,6 +106,10 @@ class VIEWS_EXPORT Label : public View,
int GetTextStyle() const;
void SetTextStyle(int style);
+ // Applies |style| to a specific |range|. This is unimplemented for styles
+ // that vary from the global text style by anything besides weight.
+ void SetTextStyleRange(int style, const gfx::Range& range);
+
// 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::BlendForMinContrast()
@@ -177,6 +187,10 @@ class VIEWS_EXPORT Label : public View,
int GetMaxLines() const;
void SetMaxLines(int max_lines);
+ // If single-line, a non-zero value will help determine the amount of space
+ // needed *after* elision, which may be less than the passed |max_width|.
+ void SetMaximumWidthSingleLine(int max_width);
+
// Returns the number of lines required to render all text. The actual number
// of rendered lines might be limited by |max_lines_| which elides the rest.
size_t GetRequiredLines() const;
@@ -280,7 +294,7 @@ class VIEWS_EXPORT Label : public View,
// within the |range|. See gfx::RenderText.
std::vector<gfx::Rect> GetSubstringBounds(const gfx::Range& range);
- views::PropertyChangedSubscription AddTextChangedCallback(
+ base::CallbackListSubscription AddTextChangedCallback(
views::PropertyChangedCallback callback) WARN_UNUSED_RESULT;
// View:
@@ -409,6 +423,9 @@ class VIEWS_EXPORT Label : public View,
// Builds |context_menu_contents_|.
void BuildContextMenuContents();
+ // Updates the elide behavior used by |full_text_|.
+ void UpdateFullTextElideBehavior();
+
int text_context_;
int text_style_;
base::Optional<int> line_height_;
@@ -450,10 +467,16 @@ class VIEWS_EXPORT Label : public View,
// Whether to collapse the label when it's not visible.
bool collapse_when_hidden_ = false;
int fixed_width_ = 0;
+ // This is used only for multi-line mode.
int max_width_ = 0;
+ // This is used in single-line mode.
+ int max_width_single_line_ = 0;
std::unique_ptr<SelectionController> selection_controller_;
+ // Accessibility data.
+ base::string16 accessible_name_;
+
// Context menu related members.
ui::SimpleMenuModel context_menu_contents_;
std::unique_ptr<views::MenuRunner> context_menu_runner_;
diff --git a/chromium/ui/views/controls/label_unittest.cc b/chromium/ui/views/controls/label_unittest.cc
index 740d4cd7c59..4e58e3bdee7 100644
--- a/chromium/ui/views/controls/label_unittest.cc
+++ b/chromium/ui/views/controls/label_unittest.cc
@@ -16,6 +16,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/gtest_util.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
@@ -604,7 +605,9 @@ TEST_F(LabelTest, TooltipProperty) {
}
TEST_F(LabelTest, Accessibility) {
- label()->SetText(ASCIIToUTF16("My special text."));
+ const base::string16 accessible_name = ASCIIToUTF16("A11y text.");
+
+ label()->SetText(ASCIIToUTF16("Displayed text."));
ui::AXNodeData node_data;
label()->GetAccessibleNodeData(&node_data);
@@ -613,6 +616,33 @@ TEST_F(LabelTest, Accessibility) {
node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
EXPECT_FALSE(
node_data.HasIntAttribute(ax::mojom::IntAttribute::kRestriction));
+
+ // Setting a custom accessible name overrides the displayed text in
+ // screen reader announcements.
+ label()->SetAccessibleName(accessible_name);
+
+ label()->GetAccessibleNodeData(&node_data);
+ EXPECT_EQ(accessible_name,
+ node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
+ EXPECT_NE(label()->GetText(),
+ node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
+
+ // Changing the displayed text will not impact the non-empty accessible name.
+ label()->SetText(ASCIIToUTF16("Different displayed Text."));
+
+ label()->GetAccessibleNodeData(&node_data);
+ EXPECT_EQ(accessible_name,
+ node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
+ EXPECT_NE(label()->GetText(),
+ node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
+
+ // Clearing the accessible name will cause the screen reader to default to
+ // verbalizing the displayed text.
+ label()->SetAccessibleName(ASCIIToUTF16(""));
+
+ label()->GetAccessibleNodeData(&node_data);
+ EXPECT_EQ(label()->GetText(),
+ node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
}
TEST_F(LabelTest, TextChangeWithoutLayout) {
@@ -1083,7 +1113,7 @@ TEST_F(LabelTest, GetSubstringBounds) {
}
// TODO(crbug.com/1139395): Enable on ChromeOS along with the DCHECK in Label.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
// Ensures DCHECK for subpixel rendering on transparent layer is working.
TEST_F(LabelTest, ChecksSubpixelRenderingOntoOpaqueSurface) {
View view;
@@ -1115,7 +1145,7 @@ TEST_F(LabelTest, ChecksSubpixelRenderingOntoOpaqueSurface) {
view.SetBackground(CreateSolidBackground(SK_ColorWHITE));
label->OnPaint(&canvas);
}
-#endif // !defined(OS_CHROMEOS)
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(LabelSelectionTest, Selectable) {
// By default, labels don't support text selection.
@@ -1413,7 +1443,9 @@ TEST_F(LabelSelectionTest, MouseDragWord) {
EXPECT_STR_EQ("drag word", GetSelectedText());
}
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Verify selection clipboard behavior on text selection.
TEST_F(LabelSelectionTest, SelectionClipboard) {
label()->SetText(ASCIIToUTF16("Label selection clipboard"));
diff --git a/chromium/ui/views/controls/link.cc b/chromium/ui/views/controls/link.cc
index 0ef69a5d335..d11926195e6 100644
--- a/chromium/ui/views/controls/link.cc
+++ b/chromium/ui/views/controls/link.cc
@@ -230,7 +230,9 @@ void Link::ConfigureFocus() {
}
BEGIN_METADATA(Link, Label)
-ADD_READONLY_PROPERTY_METADATA(SkColor, Color)
+ADD_READONLY_PROPERTY_METADATA(SkColor,
+ Color,
+ views::metadata::SkColorConverter)
END_METADATA
} // namespace views
diff --git a/chromium/ui/views/controls/link.h b/chromium/ui/views/controls/link.h
index 6db2cd4a3b4..056489620af 100644
--- a/chromium/ui/views/controls/link.h
+++ b/chromium/ui/views/controls/link.h
@@ -96,7 +96,7 @@ class VIEWS_EXPORT Link : public Label {
// The color when the link is neither pressed nor disabled.
base::Optional<SkColor> requested_enabled_color_;
- PropertyChangedSubscription enabled_changed_subscription_;
+ base::CallbackListSubscription enabled_changed_subscription_;
// Whether the link text should use underline style regardless of enabled or
// focused state.
diff --git a/chromium/ui/views/controls/menu/README.md b/chromium/ui/views/controls/menu/README.md
new file mode 100644
index 00000000000..588641c7a58
--- /dev/null
+++ b/chromium/ui/views/controls/menu/README.md
@@ -0,0 +1,198 @@
+# Views Menus
+
+This document outlines how menus are implemented in Views. You should probably
+read the [Views overview] if you haven't yet.
+
+[TOC]
+
+## Key Classes in //ui/views/controls/menu
+
+ * [MenuController]
+ * [SubmenuView]
+ * [MenuRunner]
+ * [MenuHost]
+ * [MenuItemView]
+
+## Key Classes Elsewhere
+
+ * [ui::MenuModel]
+
+## Creating & Showing A Menu
+
+Conceptually, client code uses Views menus like so:
+
+ MenuRunner runner(model, ...);
+ runner.RunMenuAt(...);
+
+The constructor of MenuRunner does little actual work; it is primarily concerned
+with choosing an appropriate [MenuRunnerImplInterface] depending on the platform
+and the requested type of menu. This document will mostly focus on
+MenuRunnerImpl, which runs a Views menu; the only other MenuRunnerImplInterface
+implementation, named [MenuRunnerImplCocoa], runs a native Mac menu instead
+which has extremely different behavior.
+
+The call to `MenuRunnerImpl::RunMenuAt` is responsible for determining which
+MenuController will control this menu invocation, which may involve either
+nesting the menu off an existing parent menu or cancelling an existing menu
+first. In this context, "nesting" specifically means a fully separate menu that
+runs while another menu is still running. Here's an example menu:
+
+ Item 1
+ Item 1.1
+ Item 1.2
+ Item 2
+ Item 3
+
+Mousing over Item 1 would open the submenu containing Items 1.1 and 1.2, but
+that submenu is controlled by the same MenuController instance as the original
+menu containing Item 1. However, if the user right-clicked on Item 2 to open its
+context menu, that would create a nested MenuController to run the context menu.
+At any given time, only one MenuController can be active, since menus are
+conceptually modal.
+
+Once that's done, `MenuController::Run` takes over.
+
+That method has many responsibilities, but explaining them will require a brief
+detour into the structure of MenuController itself.
+
+## MenuController
+
+MenuController is the "uber class" of the Views menu system. It has a large
+amount of state and nearly all interesting logic is delegated to it, but the most important things it stores are:
+
+ * The current and pending [MenuController::State]
+ * A stack of prior states for parent MenuControllers, if the current
+ MenuController is nested
+ * The active mouse view, which is the view (if there is one) that the mouse is
+ over; this is only used for dragging
+ * The "hot tracked button" - this is a button which is a descendant view of
+ the selected MenuItemView, used to deliver mouse events to both that subview
+ and the MenuItemView itself, which can be useful for (eg) drawing hover
+ effects
+ * Various timers and locations used for animation & display
+ * The "pre-target handler", which listens for any mouse click anywhere and
+ closes the menu if they are outside the menu
+
+The MenuController also contains the logic to allow dragging within menus, which
+is used in bookmark menus to support reordering items.
+
+## Menu Running & Selection
+
+Back to `MenuController::Run`: after setting up some state, this method invokes
+`MenuController::SetSelection`. That method is responsible for changing the
+selection from the current selected MenuItemView (which may be nullptr) to a
+provided new MenuItemView (which again may be nullptr), which involves closing
+and opening submenus as needed and notifying accessibility events up and down
+the menu tree. For example, if the current menu is:
+
+ A [open]
+ A1
+ A2 [open]
+ A2.1
+ A2.2 [selected]
+ A3
+ A3.1
+
+and the new selected node is A3.1, `MenuController::SetSelection` would be
+responsible for:
+
+ * Unselecting A2.2
+ * Closing A2
+ * Opening A3
+ * Selecting A3.1
+
+Note that, if the selection is not immediate, this fills the pending selection
+but not the actual selection until later, to allow for menus to animate out and
+in a bit; if this isn't done, menus flicker in and out as the mouse moves over
+multiple items with submenus.
+
+When the selection *is* immediate, as it is when invoked by
+`MenuController::Run`, SetSelection will end up opening the root menu for this
+MenuController (via `MenuController::CommitPendingSelection`). This method
+handles actually closing and opening menus as needed to make the pending
+selection visible. Since there is no existing open menu during the initial call,
+practically this calls `MenuController::OpenMenu` on the first selectable item
+in the menu.
+
+That method, in turn, ultimately calls `SubmenuView::ShowAt` on the root
+MenuItemView's submenu, which is the root submenu. That method constructs a
+MenuHost, which is a special kind of [Widget] that contains a SubmenuView. The
+MenuHost is responsible for:
+
+ * Detecting touch events anywhere (not just in the menu) and forwarding them
+ to the MenuController to maybe cancel the menu if they are out of bounds
+ * Managing mouse capture if the menu has capture (some but not all menus do
+ this)
+
+Once `MenuHost::InitMenuHost` and `MenuHost::ShowMenuHost` are done, the menu is
+on screen!
+
+## Painting
+
+Once a menu is on screen, its view tree looks like this:
+
+ MenuHost (Widget)
+ MenuHostRootView
+ MenuItemView (root)
+ MenuScrollViewContainer
+ SubmenuView
+ MenuItemView
+ MenuItemView
+ ...
+
+None of these have any visuals except the MenuItemView, which contains:
+
+ * A title, a secondary title, and an icon
+ * A checkmark/radio marker
+ * "Minor" text and icon
+ * Arbitrary other child views
+
+None of these things are separate Views - instead they are drawn directly by
+`MenuItemView::OnPaint`, so the painting step for MenuItemView is also the
+layout step.
+
+## Event Handling
+
+MenuController centralizes input event handling for menus. Key events enter
+MenuController from multiple sources:
+
+ * SubmenuView, via the normal Views event path
+ * MenuHostRootView, which overrides Views hit-testing to ensure that mouse
+ events within the MenuHost always go to the controller
+ * Widget, which will dispatch incoming key events to a running MenuController
+ if there is one - this allows the Widget to retain activation while the menu handles events
+
+MenuController::OnWillDispatchKeyEvent is one of the entry points to this logic,
+but MenuController::OnKeyPressed handles all of the navigation and functional
+keys, and MenuController::SelectByChar implements incremental searching and menu
+accelerators.
+
+Mouse events are mostly handled via the normal Views flow, except that
+pre-target handlers can deliver mouse events to MenuController that did not
+actually target the menu's widget, which MenuController uses to close itself in
+response to those events.
+
+Events can also be "reposted", where the menu decides to dismiss itself in
+response to them and then propagate them up to the menu's parent widget. This
+behavior is platform-specific and tricky, so it's best to read the code to
+understand it.
+
+## Positioning
+
+TODO(ellyjones): How does this work?
+
+## Drag & Drop
+
+TODO(ellyjones): How does this work?
+
+[Views overview]: ../../../../docs/ui/views/overview.md
+[MenuController]: menu_controller.h
+[MenuController::State]: https://source.chromium.org/chromium/chromium/src/+/master:ui/views/controls/menu/menu_controller.h;drc=ce8d17ff494cf684f35c8ff64cb6bd0947adcf46;bpv=0;bpt=1;l=289
+[MenuHost]: menu_host.h
+[MenuItemView]: menu_item_view.h
+[MenuRunner]: menu_runner.h
+[MenuRunnerImplCocoa]: menu_runner_impl_cocoa.h
+[MenuRunnerImplInterface]: menu_runner_impl_interface.h
+[SubmenuView]: submenu_view.h
+[ui::MenuModel]: ../../base/models/menu_model.h
+[Widget]: ../widget/widget.h
diff --git a/chromium/ui/views/controls/menu/menu_config.h b/chromium/ui/views/controls/menu/menu_config.h
index c84d1377c94..ade60b9aa37 100644
--- a/chromium/ui/views/controls/menu/menu_config.h
+++ b/chromium/ui/views/controls/menu/menu_config.h
@@ -184,8 +184,11 @@ struct VIEWS_EXPORT MenuConfig {
// Height of child MenuItemViews for touchable menus.
int touchable_menu_height = 36;
- // Width of touchable menus.
- int touchable_menu_width = 256;
+ // Minimum width of touchable menus.
+ int touchable_menu_min_width = 256;
+
+ // Maximum width of touchable menus.
+ int touchable_menu_max_width = 352;
// Shadow elevation of touchable menus.
int touchable_menu_shadow_elevation = 12;
diff --git a/chromium/ui/views/controls/menu/menu_config_chromeos.cc b/chromium/ui/views/controls/menu/menu_config_chromeos.cc
index 085c1adb937..fd19d1223c7 100644
--- a/chromium/ui/views/controls/menu/menu_config_chromeos.cc
+++ b/chromium/ui/views/controls/menu/menu_config_chromeos.cc
@@ -4,6 +4,7 @@
#include "ui/views/controls/menu/menu_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/views/controls/menu/menu_image_util.h"
namespace views {
@@ -22,8 +23,13 @@ void MenuConfig::Init() {
offset_context_menus = true;
corner_radius = 2;
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ // TODO(crbug/1129012): Change to false once pop-up menus have shadows.
+ use_outer_border = true;
+#else
// In Ash, the border is provided by the shadow.
use_outer_border = false;
+#endif
}
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc
index ca6146dd053..3beb5516e12 100644
--- a/chromium/ui/views/controls/menu/menu_controller.cc
+++ b/chromium/ui/views/controls/menu/menu_controller.cc
@@ -17,7 +17,8 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "build/build_config.h"
-#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
+#include "build/chromeos_buildflags.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
@@ -361,7 +362,7 @@ class MenuController::MenuScrollTask {
}
DCHECK(part.submenu);
SubmenuView* new_menu = part.submenu;
- bool new_is_up = (part.type == MenuController::MenuPart::SCROLL_UP);
+ bool new_is_up = (part.type == MenuController::MenuPart::Type::kScrollUp);
if (new_menu == submenu_ && is_scrolling_up_ == new_is_up)
return;
@@ -707,7 +708,7 @@ bool MenuController::OnMouseDragged(SubmenuView* source,
return true;
}
MenuItemView* mouse_menu = nullptr;
- if (part.type == MenuPart::MENU_ITEM) {
+ if (part.type == MenuPart::Type::kMenuItem) {
// If there is no menu target, but a submenu target, then we are interacting
// with an empty menu item within a submenu. These cannot become selection
// targets for mouse interaction, so do not attempt to update selection.
@@ -718,7 +719,7 @@ bool MenuController::OnMouseDragged(SubmenuView* source,
mouse_menu = part.menu;
SetSelection(part.menu ? part.menu : state_.item, SELECTION_OPEN_SUBMENU);
}
- } else if (part.type == MenuPart::NONE) {
+ } else if (part.type == MenuPart::Type::kNone) {
// If there is a sibling menu, show it. Otherwise, if the user has selected
// a menu item with no accompanying sibling menu or submenu, move selection
// back to the parent menu item.
@@ -761,7 +762,7 @@ void MenuController::OnMouseReleased(SubmenuView* source,
DCHECK(state_.item);
possible_drag_ = false;
MenuPart part = GetMenuPart(source, event.location());
- if (event.IsRightMouseButton() && part.type == MenuPart::MENU_ITEM) {
+ if (event.IsRightMouseButton() && part.type == MenuPart::Type::kMenuItem) {
MenuItemView* menu = part.menu;
// |menu| is null means this event is from an empty menu or a separator.
// If it is from an empty menu, use parent context menu instead of that.
@@ -817,7 +818,7 @@ void MenuController::OnMouseReleased(SubmenuView* source,
Accept(part.menu, event.flags());
return;
}
- } else if (part.type == MenuPart::MENU_ITEM) {
+ } else if (part.type == MenuPart::Type::kMenuItem) {
// User either clicked on empty space, or a menu that has children.
SetSelection(part.menu ? part.menu : state_.item,
SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
@@ -913,7 +914,7 @@ void MenuController::OnGestureEvent(SubmenuView* source,
SetSelectionOnPointerDown(source, event);
event->StopPropagation();
} else if (event->type() == ui::ET_GESTURE_LONG_PRESS) {
- if (part.type == MenuPart::MENU_ITEM && part.menu) {
+ if (part.type == MenuPart::Type::kMenuItem && part.menu) {
gfx::Point screen_location(event->location());
View::ConvertPointToScreen(source->GetScrollViewContainer(),
&screen_location);
@@ -928,14 +929,14 @@ void MenuController::OnGestureEvent(SubmenuView* source,
Accept(part.menu, event->flags());
}
event->StopPropagation();
- } else if (part.type == MenuPart::MENU_ITEM) {
+ } else if (part.type == MenuPart::Type::kMenuItem) {
// User either tapped on empty space, or a menu that has children.
SetSelection(part.menu ? part.menu : state_.item,
SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
event->StopPropagation();
}
} else if (event->type() == ui::ET_GESTURE_TAP_CANCEL && part.menu &&
- part.type == MenuPart::MENU_ITEM) {
+ part.type == MenuPart::Type::kMenuItem) {
// Move the selection to the parent menu so that the selection in the
// current menu is unset. Make sure the submenu remains open by sending the
// appropriate SetSelectionTypes flags.
@@ -959,7 +960,7 @@ void MenuController::OnTouchEvent(SubmenuView* source, ui::TouchEvent* event) {
if (event->type() == ui::ET_TOUCH_PRESSED) {
MenuPart part = GetMenuPart(source, event->location());
- if (part.type == MenuPart::NONE) {
+ if (part.type == MenuPart::Type::kNone) {
RepostEventAndCancel(source, event);
event->SetHandled();
}
@@ -1059,8 +1060,9 @@ int MenuController::OnDragUpdated(SubmenuView* source,
query_menu_item = menu_item->GetParentMenuItem();
drop_position = MenuDelegate::DropPosition::kOn;
}
- drop_operation = menu_item->GetDelegate()->GetDropOperation(
- query_menu_item, event, &drop_position);
+ drop_operation =
+ static_cast<int>(menu_item->GetDelegate()->GetDropOperation(
+ query_menu_item, event, &drop_position));
// If the menu has a submenu, schedule the submenu to open.
SetSelection(menu_item, menu_item->HasSubmenu() ? SELECTION_OPEN_SUBMENU
@@ -1086,8 +1088,9 @@ void MenuController::OnDragExited(SubmenuView* source) {
}
}
-int MenuController::OnPerformDrop(SubmenuView* source,
- const ui::DropTargetEvent& event) {
+ui::mojom::DragOperation MenuController::OnPerformDrop(
+ SubmenuView* source,
+ const ui::DropTargetEvent& event) {
DCHECK(drop_target_);
// NOTE: the delegate may delete us after invoking OnPerformDrop, as such
// we don't call cancel here.
@@ -1125,7 +1128,7 @@ int MenuController::OnPerformDrop(SubmenuView* source,
void MenuController::OnDragEnteredScrollButton(SubmenuView* source,
bool is_up) {
MenuPart part;
- part.type = is_up ? MenuPart::SCROLL_UP : MenuPart::SCROLL_DOWN;
+ part.type = is_up ? MenuPart::Type::kScrollUp : MenuPart::Type::kScrollDown;
part.submenu = source;
UpdateScrolling(part);
@@ -1431,8 +1434,8 @@ void MenuController::SetSelectionOnPointerDown(SubmenuView* source,
(event->flags() & ui::EF_FROM_TOUCH))
return;
- if (part.type == MenuPart::NONE ||
- (part.type == MenuPart::MENU_ITEM && part.menu &&
+ if (part.type == MenuPart::Type::kNone ||
+ (part.type == MenuPart::Type::kMenuItem && part.menu &&
part.menu->GetRootMenuItem() != state_.item->GetRootMenuItem())) {
// Remember the time stamp of the current (press down) event. The owner can
// then use this to figure out if this menu was finished with the same click
@@ -1478,7 +1481,8 @@ void MenuController::StartDrag(SubmenuView* source,
float raster_scale = ScaleFactorForDragFromWidget(source->GetWidget());
gfx::Canvas canvas(item->size(), raster_scale, false /* opaque */);
item->PaintButton(&canvas, MenuItemView::PaintButtonMode::kForDrag);
- gfx::ImageSkia image(gfx::ImageSkiaRep(canvas.GetBitmap(), raster_scale));
+ gfx::ImageSkia image =
+ gfx::ImageSkia::CreateFromBitmap(canvas.GetBitmap(), raster_scale);
std::unique_ptr<OSExchangeData> data(std::make_unique<OSExchangeData>());
item->GetDelegate()->WriteDragData(item, data.get());
@@ -1869,11 +1873,11 @@ bool MenuController::IsScrollButtonAt(SubmenuView* source,
scroll_view->GetEventHandlerForPoint(gfx::Point(x, y));
if (child_under_mouse && child_under_mouse->GetEnabled()) {
if (child_under_mouse == scroll_view->scroll_up_button()) {
- *part = MenuPart::SCROLL_UP;
+ *part = MenuPart::Type::kScrollUp;
return true;
}
if (child_under_mouse == scroll_view->scroll_down_button()) {
- *part = MenuPart::SCROLL_DOWN;
+ *part = MenuPart::Type::kScrollDown;
return true;
}
}
@@ -1928,7 +1932,7 @@ bool MenuController::GetMenuPartByScreenCoordinateImpl(
gfx::Point menu_loc = screen_loc;
View::ConvertPointFromScreen(menu, &menu_loc);
part->menu = GetMenuItemAt(menu, menu_loc.x(), menu_loc.y());
- part->type = MenuPart::MENU_ITEM;
+ part->type = MenuPart::Type::kMenuItem;
part->submenu = menu;
part->should_submenu_show =
part->submenu && part->menu &&
@@ -2124,7 +2128,7 @@ void MenuController::OpenMenuImpl(MenuItemView* item, bool show) {
View::ConvertPointFromScreen(item->submenu_->GetWidget()->GetRootView(),
&mouse_pos);
MenuPart part_under_mouse = GetMenuPart(item->submenu_, mouse_pos);
- if (part_under_mouse.type != MenuPart::NONE)
+ if (part_under_mouse.type != MenuPart::Type::kNone)
menu_open_mouse_loc_ = mouse_pos;
}
@@ -2378,7 +2382,7 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
bool* is_leading) {
DCHECK(item);
- // Assume we can honor prefer_leading.
+ // Assume we can honor `prefer_leading`.
*is_leading = prefer_leading;
SubmenuView* submenu = item->GetSubmenu();
@@ -2427,26 +2431,58 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
menu_size.set_width(std::min(
menu_size.width(), item->GetDelegate()->GetMaxWidthForMenu(item)));
- if (state_.anchor == MenuAnchorPosition::kBubbleAbove) {
- // Align the left edges of the menu and anchor, and the bottom of the menu
- // with the top of the anchor.
+ if (state_.anchor == MenuAnchorPosition::kBubbleAbove ||
+ state_.anchor == MenuAnchorPosition::kBubbleBelow) {
+ // Align the left edges of the menu and anchor.
x = std::max(monitor_bounds.x(),
anchor_bounds.x() - border_and_shadow_insets.left());
- y = anchor_bounds.y() - menu_size.height() +
- border_and_shadow_insets.bottom() -
- menu_config.touchable_anchor_offset;
-
- // Align the right of the menu with the right of the anchor.
if (x + menu_size.width() > monitor_bounds.right()) {
+ // Align the right of the menu with the right of the anchor.
x = anchor_bounds.right() - menu_size.width() +
border_and_shadow_insets.right();
}
- // Align the top of the menu with the bottom of the anchor.
- if (y < monitor_bounds.y()) {
- y = anchor_bounds.bottom() - border_and_shadow_insets.top() +
- menu_config.touchable_anchor_offset;
+
+ const int y_for_menu_below = anchor_bounds.bottom() -
+ border_and_shadow_insets.top() +
+ menu_config.touchable_anchor_offset;
+ const int y_for_menu_above = anchor_bounds.y() - menu_size.height() +
+ border_and_shadow_insets.bottom() -
+ menu_config.touchable_anchor_offset;
+ if (state_.anchor == MenuAnchorPosition::kBubbleAbove) {
+ y = y_for_menu_above;
+ item->set_actual_menu_position(MenuPosition::kAboveBounds);
+ if (y < monitor_bounds.y()) {
+ y = y_for_menu_below;
+ item->set_actual_menu_position(MenuPosition::kBelowBounds);
+ }
+ } else if (state_.anchor == MenuAnchorPosition::kBubbleBelow) {
+ // Respect the previous MenuPosition. The menu contents could change
+ // while the menu is shown, the menu position should not change.
+ const bool able_to_show_menu_below =
+ (y_for_menu_below + menu_size.height() <= monitor_bounds.bottom());
+ const bool able_to_show_menu_above =
+ y_for_menu_above >= monitor_bounds.y();
+ if (item->actual_menu_position() == MenuPosition::kBelowBounds &&
+ able_to_show_menu_below) {
+ y = y_for_menu_below;
+ } else if (item->actual_menu_position() == MenuPosition::kAboveBounds &&
+ able_to_show_menu_above) {
+ y = y_for_menu_above;
+ } else if (able_to_show_menu_below) {
+ y = y_for_menu_below;
+ item->set_actual_menu_position(MenuPosition::kBelowBounds);
+ } else if (able_to_show_menu_above) {
+ // No room below, but there is room above. Show above the anchor.
+ // Align the bottom of the menu with the bottom of the anchor.
+ y = y_for_menu_above;
+ item->set_actual_menu_position(MenuPosition::kAboveBounds);
+ } else {
+ // No room above or below. Show as low as possible. Align the bottom
+ // of the menu with the bottom of the screen.
+ y = monitor_bounds.bottom() - menu_size.height();
+ item->set_actual_menu_position(MenuPosition::kBestFit);
+ }
}
- item->set_actual_menu_position(MenuPosition::kAboveBounds);
} else if (state_.anchor == MenuAnchorPosition::kBubbleLeft ||
state_.anchor == MenuAnchorPosition::kBubbleRight) {
if (state_.anchor == MenuAnchorPosition::kBubbleLeft) {
@@ -2473,32 +2509,34 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
}
}
- const int y_below = anchor_bounds.y() - border_and_shadow_insets.top();
- const int y_above = anchor_bounds.bottom() - menu_size.height() +
- border_and_shadow_insets.bottom();
+ const int y_for_menu_below =
+ anchor_bounds.y() - border_and_shadow_insets.top();
+ const int y_for_menu_above = anchor_bounds.bottom() - menu_size.height() +
+ border_and_shadow_insets.bottom();
- const bool able_to_show_below =
- (y_below + menu_size.height() <= monitor_bounds.bottom());
- const bool able_to_show_above = (y_above >= monitor_bounds.y());
+ const bool able_to_show_menu_below =
+ (y_for_menu_below + menu_size.height() <= monitor_bounds.bottom());
+ const bool able_to_show_menu_above =
+ (y_for_menu_above >= monitor_bounds.y());
// Respect the actual menu position calculated earlier if possible, to
// prevent changing positions during menu size updates.
if (item->actual_menu_position() == MenuPosition::kBelowBounds &&
- able_to_show_below) {
- y = y_below;
+ able_to_show_menu_below) {
+ y = y_for_menu_below;
} else if (item->actual_menu_position() == MenuPosition::kAboveBounds &&
- able_to_show_above) {
- y = y_above;
- } else if (able_to_show_below) {
+ able_to_show_menu_above) {
+ y = y_for_menu_above;
+ } else if (able_to_show_menu_below) {
// Show below the anchor. Align the top of the menu with the top of the
// anchor.
- y = y_below;
+ y = y_for_menu_below;
item->set_actual_menu_position(MenuPosition::kBelowBounds);
- } else if (able_to_show_above) {
+ } else if (able_to_show_menu_above) {
// No room below, but there is room above. Show above the anchor. Align
// the bottom of the menu with the bottom of the anchor.
- y = y_above;
+ y = y_for_menu_above;
item->set_actual_menu_position(MenuPosition::kAboveBounds);
} else {
// No room above or below. Show as low as possible. Align the bottom of
@@ -2533,7 +2571,7 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
const bool create_on_right = prefer_leading != layout_is_rtl;
const int width_with_right_inset =
- menu_config.touchable_menu_width + border_and_shadow_insets.right();
+ menu_config.touchable_menu_min_width + border_and_shadow_insets.right();
const int x_max = monitor_bounds.right() - width_with_right_inset;
const int x_left = item_bounds.x() - width_with_right_inset;
const int x_right = item_bounds.right() - border_and_shadow_insets.left();
@@ -2692,7 +2730,7 @@ MenuItemView* MenuController::FindNextSelectableMenuItem(
if (index == stop_index && !include_all_items)
return nullptr;
MenuItemView* child = parent->GetSubmenu()->GetMenuItemAt(index);
- if (child->GetVisible() && child->GetEnabled())
+ if (child->IsTraversableByKeyboard())
return child;
} while (index != stop_index);
return nullptr;
@@ -2807,7 +2845,9 @@ void MenuController::SelectByChar(base::char16 character) {
if (IsReadonlyCombobox() ||
MenuConfig::instance().all_menus_use_prefix_selection) {
- item->GetSubmenu()->GetPrefixSelector()->InsertText(char_array);
+ item->GetSubmenu()->GetPrefixSelector()->InsertText(
+ char_array,
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
} else {
// If no mnemonics found, look at first character of titles.
details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic);
@@ -2823,7 +2863,7 @@ void MenuController::RepostEventAndCancel(SubmenuView* source,
gfx::Point screen_loc(event->location());
View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc);
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
gfx::NativeView native_view = source->GetWidget()->GetNativeView();
gfx::NativeWindow window = nullptr;
if (native_view) {
@@ -2862,7 +2902,7 @@ void MenuController::RepostEventAndCancel(SubmenuView* source,
// of the menus from the last run.
MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu(
menu_stack_.back().first.item, screen_loc);
- if (last_part.type != MenuPart::NONE)
+ if (last_part.type != MenuPart::Type::kNone)
exit_type = ExitType::kOutermost;
}
#if defined(OS_APPLE)
@@ -3109,10 +3149,11 @@ void MenuController::HandleMouseLocation(SubmenuView* source,
if (for_drop_)
return;
- if (part.type == MenuPart::NONE && ShowSiblingMenu(source, mouse_location))
+ if (part.type == MenuPart::Type::kNone &&
+ ShowSiblingMenu(source, mouse_location))
return;
- if (part.type == MenuPart::MENU_ITEM && part.menu) {
+ if (part.type == MenuPart::Type::kMenuItem && part.menu) {
SetSelection(part.menu, part.should_submenu_show ? SELECTION_OPEN_SUBMENU
: SELECTION_DEFAULT);
} else if (!part.is_scroll() && pending_state_.item &&
diff --git a/chromium/ui/views/controls/menu/menu_controller.h b/chromium/ui/views/controls/menu/menu_controller.h
index 6908150ccc5..1e835dcc7d9 100644
--- a/chromium/ui/views/controls/menu/menu_controller.h
+++ b/chromium/ui/views/controls/menu/menu_controller.h
@@ -18,6 +18,7 @@
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/platform/platform_event_dispatcher.h"
@@ -186,7 +187,8 @@ class VIEWS_EXPORT MenuController
void OnDragEntered(SubmenuView* source, const ui::DropTargetEvent& event);
int OnDragUpdated(SubmenuView* source, const ui::DropTargetEvent& event);
void OnDragExited(SubmenuView* source);
- int OnPerformDrop(SubmenuView* source, const ui::DropTargetEvent& event);
+ ui::mojom::DragOperation OnPerformDrop(SubmenuView* source,
+ const ui::DropTargetEvent& event);
// Invoked from the scroll buttons of the MenuScrollViewContainer.
void OnDragEnteredScrollButton(SubmenuView* source, bool is_up);
@@ -313,24 +315,26 @@ class VIEWS_EXPORT MenuController
// Used by GetMenuPart to indicate the menu part at a particular location.
struct MenuPart {
// Type of part.
- enum Type { NONE, MENU_ITEM, SCROLL_UP, SCROLL_DOWN };
+ enum class Type { kNone, kMenuItem, kScrollUp, kScrollDown };
- // Convenience for testing type == SCROLL_DOWN or type == SCROLL_UP.
- bool is_scroll() const { return type == SCROLL_DOWN || type == SCROLL_UP; }
+ // Convenience for testing type == kScrollDown or type == kScrollUp.
+ bool is_scroll() const {
+ return type == Type::kScrollDown || type == Type::kScrollUp;
+ }
// Type of part.
- Type type = NONE;
+ Type type = Type::kNone;
- // If type is MENU_ITEM, this is the menu item the mouse is over, otherwise
- // this is NULL.
- // NOTE: if type is MENU_ITEM and the mouse is not over a valid menu item
+ // If type is kMenuItem, this is the menu item the mouse is over, otherwise
+ // this is null.
+ // NOTE: if type is kMenuItem and the mouse is not over a valid menu item
// but is over a menu (for example, the mouse is over a separator or
- // empty menu), this is NULL and parent is the menu the mouse was
+ // empty menu), this is null and parent is the menu the mouse was
// clicked on.
MenuItemView* menu = nullptr;
- // If type is MENU_ITEM but the mouse is not over a menu item this is the
- // parent of the menu item the user clicked on. Otherwise this is NULL.
+ // If type is kMenuItem but the mouse is not over a menu item this is the
+ // parent of the menu item the user clicked on. Otherwise this is null.
MenuItemView* parent = nullptr;
// This is the submenu the mouse is over.
diff --git a/chromium/ui/views/controls/menu/menu_controller_unittest.cc b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
index c58a57017a2..383452eca46 100644
--- a/chromium/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
@@ -892,7 +892,7 @@ TEST_F(MenuControllerTest, EventTargeter) {
TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) {
// Run this test only for X11 (either Ozone or non-Ozone).
if (features::IsUsingOzonePlatform() &&
- std::strcmp(ui::OzonePlatform::GetPlatformName(), "x11") != 0) {
+ ui::OzonePlatform::GetPlatformNameForTest() != "x11") {
GTEST_SKIP();
}
@@ -1063,6 +1063,70 @@ TEST_F(MenuControllerTest, VerifyMenuBubblePositionAfterSizeChanges) {
}
}
+// Verifies that the context menu bubble position, MenuPosition::kBubbleBelow,
+// does not shift as items are removed. The menu position will shift it items
+// are added and the menu no longer fits in its previous position.
+TEST_F(MenuControllerTest, VerifyMenuBubbleBelowPositionAfterSizeChanges) {
+ constexpr gfx::Rect kMonitorBounds(0, 0, 500, 500);
+ constexpr gfx::Size kMenuSize(100, 200);
+ const gfx::Insets border_and_shadow_insets =
+ BubbleBorder::GetBorderAndShadowInsets(
+ MenuConfig::instance().touchable_menu_shadow_elevation);
+
+ // Calculate the suitable anchor point to ensure that if the menu shows below
+ // the anchor point, the bottom of the menu should be one pixel off the
+ // bottom of the display. It means that there is insufficient space for the
+ // menu below the anchor.
+ const gfx::Point anchor_point(kMonitorBounds.width() / 2,
+ kMonitorBounds.bottom() + 1 -
+ kMenuSize.height() +
+ border_and_shadow_insets.top());
+
+ MenuBoundsOptions options;
+ options.menu_anchor = MenuAnchorPosition::kBubbleBelow;
+ options.monitor_bounds = kMonitorBounds;
+ options.anchor_bounds = gfx::Rect(anchor_point, gfx::Size());
+
+ // Case 1: There is insufficient space for the menu below `anchor_point` and
+ // there is no cached menu position. The menu should show above the anchor.
+ {
+ options.menu_size = kMenuSize;
+ ASSERT_GT(options.anchor_bounds.y() - border_and_shadow_insets.top() +
+ kMenuSize.height(),
+ kMonitorBounds.bottom());
+ CalculateBubbleMenuBounds(options);
+ EXPECT_EQ(MenuItemView::MenuPosition::kAboveBounds,
+ menu_item()->ActualMenuPosition());
+ }
+
+ // Case 2: There is insufficient space for the menu below `anchor_point`. The
+ // cached position is below the anchor. The menu should show above the anchor
+ // point.
+ {
+ options.menu_position = MenuItemView::MenuPosition::kBelowBounds;
+ CalculateBubbleMenuBounds(options);
+ EXPECT_EQ(MenuItemView::MenuPosition::kAboveBounds,
+ menu_item()->ActualMenuPosition());
+ }
+
+ // Case 3: There is enough space for the menu below `anchor_point`. The cached
+ // menu position is above the anchor. The menu should show above the anchor.
+ {
+ // Shrink the menu size. Verify that there is enough space below the anchor
+ // point now.
+ constexpr gfx::Size kUpdatedSize(kMenuSize.width(), kMenuSize.height() / 2);
+ options.menu_size = kUpdatedSize;
+ EXPECT_LE(options.anchor_bounds.y() - border_and_shadow_insets.top() +
+ kUpdatedSize.height(),
+ kMonitorBounds.bottom());
+
+ options.menu_position = MenuItemView::MenuPosition::kAboveBounds;
+ CalculateBubbleMenuBounds(options);
+ EXPECT_EQ(MenuItemView::MenuPosition::kAboveBounds,
+ menu_item()->ActualMenuPosition());
+ }
+}
+
// Tests that opening the menu and pressing 'Home' selects the first menu item.
TEST_F(MenuControllerTest, FirstSelectedItem) {
SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(0));
@@ -2100,7 +2164,7 @@ TEST_P(MenuControllerTest, TestSubmenuFitsOnScreen) {
MenuItemView* sub_item = menu_item()->GetSubmenu()->GetMenuItemAt(0);
sub_item->AppendMenuItem(11, base::ASCIIToUTF16("Subitem.One"));
- const int menu_width = MenuConfig::instance().touchable_menu_width;
+ const int menu_width = MenuConfig::instance().touchable_menu_min_width;
const gfx::Size parent_size(menu_width, menu_width);
const gfx::Size parent_size_wide(menu_width * 2, menu_width);
diff --git a/chromium/ui/views/controls/menu/menu_delegate.cc b/chromium/ui/views/controls/menu/menu_delegate.cc
index 9bc2a66b339..f9dad0e796c 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.cc
+++ b/chromium/ui/views/controls/menu/menu_delegate.cc
@@ -4,6 +4,7 @@
#include "ui/views/controls/menu/menu_delegate.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/events/event.h"
#include "ui/views/controls/menu/menu_config.h"
@@ -90,18 +91,20 @@ bool MenuDelegate::AreDropTypesRequired(MenuItemView* menu) {
return false;
}
-int MenuDelegate::GetDropOperation(MenuItemView* item,
- const ui::DropTargetEvent& event,
- DropPosition* position) {
+ui::mojom::DragOperation MenuDelegate::GetDropOperation(
+ MenuItemView* item,
+ const ui::DropTargetEvent& event,
+ DropPosition* position) {
NOTREACHED() << "If you override CanDrop, you need to override this too";
- return ui::DragDropTypes::DRAG_NONE;
+ return ui::mojom::DragOperation::kNone;
}
-int MenuDelegate::OnPerformDrop(MenuItemView* menu,
- DropPosition position,
- const ui::DropTargetEvent& event) {
+ui::mojom::DragOperation MenuDelegate::OnPerformDrop(
+ MenuItemView* menu,
+ DropPosition position,
+ const ui::DropTargetEvent& event) {
NOTREACHED() << "If you override CanDrop, you need to override this too";
- return ui::DragDropTypes::DRAG_NONE;
+ return ui::mojom::DragOperation::kNone;
}
bool MenuDelegate::CanDrag(MenuItemView* menu) {
diff --git a/chromium/ui/views/controls/menu/menu_delegate.h b/chromium/ui/views/controls/menu/menu_delegate.h
index 158724b4752..d863d6f874a 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.h
+++ b/chromium/ui/views/controls/menu/menu_delegate.h
@@ -11,6 +11,7 @@
#include "base/strings/string16.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/font_list.h"
@@ -160,19 +161,21 @@ class VIEWS_EXPORT MenuDelegate {
// is set based on the location of the mouse, reset to specify a different
// position.
//
- // If a drop should not be allowed, returned ui::DragDropTypes::DRAG_NONE.
- virtual int GetDropOperation(MenuItemView* item,
- const ui::DropTargetEvent& event,
- DropPosition* position);
+ // If a drop should not be allowed, returns DragOperation::kNone.
+ virtual ui::mojom::DragOperation GetDropOperation(
+ MenuItemView* item,
+ const ui::DropTargetEvent& event,
+ DropPosition* position);
// Invoked to perform the drop operation. This is ONLY invoked if CanDrop()
// returned true for the parent menu item, and GetDropOperation() returned an
- // operation other than ui::DragDropTypes::DRAG_NONE.
+ // operation other than DragOperation::kNone.
//
// |menu| is the menu the drop occurred on.
- virtual int OnPerformDrop(MenuItemView* menu,
- DropPosition position,
- const ui::DropTargetEvent& event);
+ virtual ui::mojom::DragOperation OnPerformDrop(
+ MenuItemView* menu,
+ DropPosition position,
+ const ui::DropTargetEvent& event);
// Invoked to determine if it is possible for the user to drag the specified
// menu item.
diff --git a/chromium/ui/views/controls/menu/menu_host.cc b/chromium/ui/views/controls/menu/menu_host.cc
index 9b3cc9c5f21..865b7dac0b8 100644
--- a/chromium/ui/views/controls/menu/menu_host.cc
+++ b/chromium/ui/views/controls/menu/menu_host.cc
@@ -20,6 +20,7 @@
#include "ui/views/controls/menu/menu_scroll_view_container.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/round_rect_painter.h"
+#include "ui/views/views_delegate.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
@@ -223,6 +224,10 @@ internal::RootView* MenuHost::CreateRootView() {
void MenuHost::OnMouseCaptureLost() {
if (destroying_ || ignore_capture_lost_)
return;
+
+ if (!ViewsDelegate::GetInstance()->ShouldCloseMenuIfMouseCaptureLost())
+ return;
+
MenuController* menu_controller =
submenu_->GetMenuItem()->GetMenuController();
if (menu_controller && !menu_controller->drag_in_progress())
diff --git a/chromium/ui/views/controls/menu/menu_item_view.cc b/chromium/ui/views/controls/menu/menu_item_view.cc
index 38bb7252ab7..89f6c657d0a 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view.cc
@@ -19,6 +19,7 @@
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/menu_model.h"
#include "ui/base/ui_base_features.h"
@@ -51,6 +52,10 @@
#include "ui/views/views_features.h"
#include "ui/views/widget/widget.h"
+#if defined(OS_APPLE)
+#include "ui/views/accessibility/view_accessibility.h"
+#endif // defined(OS_APPLE)
+
namespace views {
namespace {
@@ -181,6 +186,8 @@ void MenuItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
switch (type_) {
case Type::kSubMenu:
case Type::kActionableSubMenu:
+ // Note: This is neither necessary nor sufficient for macOS. See
+ // CreateSubmenu() for virtual child creation and explanation.
node_data->SetHasPopup(ax::mojom::HasPopup::kMenu);
break;
case Type::kCheckbox:
@@ -205,6 +212,11 @@ void MenuItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
ax::mojom::StringAttribute::kKeyShortcuts,
base::UTF16ToUTF8(base::string16(1, mnemonic)));
}
+
+ if (IsTraversableByKeyboard()) {
+ node_data->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
+ IsSelected());
+ }
}
bool MenuItemView::HandleAccessibleAction(const ui::AXActionData& action_data) {
@@ -223,9 +235,33 @@ bool MenuItemView::HandleAccessibleAction(const ui::AXActionData& action_data) {
return true;
}
+View::FocusBehavior MenuItemView::GetFocusBehavior() const {
+ // If the creator/owner of the MenuItemView has explicitly set the focus
+ // behavior to something other than the default NEVER, don't override it.
+ View::FocusBehavior focus_behavior = View::GetFocusBehavior();
+ if (focus_behavior != FocusBehavior::NEVER)
+ return focus_behavior;
+
+ // Some MenuItemView types are presumably never focusable, even by assistive
+ // technologies.
+ if (type_ == Type::kEmpty || type_ == Type::kSeparator)
+ return FocusBehavior::NEVER;
+
+ // The rest of the MenuItemView types are presumably focusable, at least by
+ // assistive technologies. But if they lack presentable information, then
+ // there won't be anything for ATs to convey to the user. Filter those out.
+ if (title_.empty() && secondary_title_.empty() && minor_text_.empty() &&
+ vector_icon_.empty()) {
+ return FocusBehavior::NEVER;
+ }
+
+ return FocusBehavior::ACCESSIBLE_ONLY;
+}
+
// static
bool MenuItemView::IsBubble(MenuAnchorPosition anchor) {
return anchor == MenuAnchorPosition::kBubbleAbove ||
+ anchor == MenuAnchorPosition::kBubbleBelow ||
anchor == MenuAnchorPosition::kBubbleLeft ||
anchor == MenuAnchorPosition::kBubbleRight;
}
@@ -376,6 +412,18 @@ SubmenuView* MenuItemView::CreateSubmenu() {
if (!submenu_) {
submenu_ = new SubmenuView(this);
+#if defined(OS_APPLE)
+ // All MenuItemViews of Type kSubMenu have a respective SubmenuView.
+ // However, in the Views hierarchy, this SubmenuView is not a child of the
+ // MenuItemView. This confuses VoiceOver, because it expects the submenu
+ // itself to be a child of the menu item. To allow VoiceOver to recognize
+ // submenu items, we create a virtual child of type Menu.
+ std::unique_ptr<AXVirtualView> virtual_child =
+ std::make_unique<AXVirtualView>();
+ virtual_child->GetCustomData().role = ax::mojom::Role::kMenu;
+ GetViewAccessibility().AddVirtualChildView(std::move(virtual_child));
+#endif // defined(OS_APPLE)
+
// Initialize the submenu indicator icon (arrow).
submenu_arrow_image_view_ = AddChildView(std::make_unique<ImageView>());
}
@@ -420,7 +468,7 @@ void MenuItemView::SetSelected(bool selected) {
OnPropertyChanged(&selected_, kPropertyEffectsPaint);
}
-PropertyChangedSubscription MenuItemView::AddSelectedChangedCallback(
+base::CallbackListSubscription MenuItemView::AddSelectedChangedCallback(
PropertyChangedCallback callback) {
return AddPropertyChangedCallback(&selected_, std::move(callback));
}
@@ -565,7 +613,7 @@ const MenuItemView* MenuItemView::GetRootMenuItem() const {
base::char16 MenuItemView::GetMnemonic() {
if (!GetRootMenuItem()->has_mnemonics_ ||
- !MenuConfig::instance().use_mnemonics) {
+ !MenuConfig::instance().use_mnemonics || !may_have_mnemonics()) {
return 0;
}
@@ -736,6 +784,12 @@ bool MenuItemView::ShouldShowNewBadge() const {
return feature_enabled && is_new_;
}
+bool MenuItemView::IsTraversableByKeyboard() const {
+ bool ignore_enabled = ui::AXPlatformNode::GetAccessibilityMode().has_mode(
+ ui::AXMode::kNativeAPIs);
+ return GetVisible() && (ignore_enabled || GetEnabled());
+}
+
MenuItemView::MenuItemView(MenuItemView* parent,
int command,
MenuItemView::Type type) {
@@ -863,7 +917,7 @@ int MenuItemView::GetDrawStringFlags() {
else
flags |= gfx::Canvas::TEXT_ALIGN_LEFT;
- if (GetRootMenuItem()->has_mnemonics_) {
+ if (GetRootMenuItem()->has_mnemonics_ && may_have_mnemonics()) {
if (MenuConfig::instance().show_mnemonics ||
GetRootMenuItem()->show_mnemonics_) {
flags |= gfx::Canvas::SHOW_PREFIX;
@@ -1195,6 +1249,9 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() const {
dimensions.children_width = child_size.width();
const MenuConfig& menu_config = MenuConfig::instance();
+ MenuDelegate::LabelStyle style;
+ GetLabelStyle(&style);
+
if (GetMenuController() && GetMenuController()->use_touchable_layout()) {
dimensions.height = menu_config.touchable_menu_height;
@@ -1205,7 +1262,15 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() const {
if (IsContainer())
return dimensions;
- dimensions.standard_width = menu_config.touchable_menu_width;
+ // Calculate total item width to make sure the current |title_|
+ // has enough room within the context menu.
+ int label_start = GetLabelStartForThisItem();
+ int string_width = gfx::GetStringWidth(title_, style.font_list);
+ int item_width = string_width + label_start + item_right_margin_;
+
+ item_width = std::max(item_width, menu_config.touchable_menu_min_width);
+ item_width = std::min(item_width, menu_config.touchable_menu_max_width);
+ dimensions.standard_width = item_width;
if (icon_view_) {
dimensions.height = icon_view_->GetPreferredSize().height() +
@@ -1214,8 +1279,6 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() const {
return dimensions;
}
- MenuDelegate::LabelStyle style;
- GetLabelStyle(&style);
base::string16 minor_text = GetMinorText();
dimensions.height = child_size.height();
@@ -1304,7 +1367,8 @@ int MenuItemView::GetLabelStartForThisItem() const {
// Touchable items with icons do not respect |label_start_|.
if (GetMenuController() && GetMenuController()->use_touchable_layout() &&
icon_view_) {
- return 2 * config.touchable_item_horizontal_padding + icon_view_->width();
+ return 2 * config.touchable_item_horizontal_padding +
+ icon_view_->GetPreferredSize().width();
}
int label_start = label_start_ + left_icon_margin_ + right_icon_margin_;
diff --git a/chromium/ui/views/controls/menu/menu_item_view.h b/chromium/ui/views/controls/menu/menu_item_view.h
index e0c41896c70..b614f1a2d1d 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.h
+++ b/chromium/ui/views/controls/menu/menu_item_view.h
@@ -123,6 +123,7 @@ class VIEWS_EXPORT MenuItemView : public View {
base::string16 GetTooltipText(const gfx::Point& p) const override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
bool HandleAccessibleAction(const ui::AXActionData& action_data) override;
+ FocusBehavior GetFocusBehavior() const override;
// Returns the preferred height of menu items. This is only valid when the
// menu is about to be shown.
@@ -239,7 +240,7 @@ class VIEWS_EXPORT MenuItemView : public View {
// Adds a callback subscription associated with the above selected property.
// The callback will be invoked whenever the selected property changes.
- PropertyChangedSubscription AddSelectedChangedCallback(
+ base::CallbackListSubscription AddSelectedChangedCallback(
PropertyChangedCallback callback) WARN_UNUSED_RESULT;
// Sets whether the submenu area of an ACTIONABLE_SUBMENU is selected.
@@ -279,6 +280,11 @@ class VIEWS_EXPORT MenuItemView : public View {
void set_is_new(bool is_new) { is_new_ = is_new; }
bool is_new() const { return is_new_; }
+ void set_may_have_mnemonics(bool may_have_mnemonics) {
+ may_have_mnemonics_ = may_have_mnemonics;
+ }
+ bool may_have_mnemonics() const { return may_have_mnemonics_; }
+
// Paints the menu item.
void OnPaint(gfx::Canvas* canvas) override;
@@ -363,6 +369,10 @@ class VIEWS_EXPORT MenuItemView : public View {
// Takes into account whether the badging feature is enabled.
bool ShouldShowNewBadge() const;
+ // Returns whether keyboard navigation through the menu should stop on this
+ // item.
+ bool IsTraversableByKeyboard() const;
+
protected:
// Creates a MenuItemView. This is used by the various AddXXX methods.
MenuItemView(MenuItemView* parent, int command, Type type);
@@ -528,6 +538,9 @@ class VIEWS_EXPORT MenuItemView : public View {
// a way to highlight a new feature for users.
bool is_new_ = false;
+ // Whether the menu item contains user-created text.
+ bool may_have_mnemonics_ = true;
+
// Submenu, created via CreateSubmenu.
SubmenuView* submenu_ = nullptr;
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 b942a3d978e..cff5dcf02a4 100644
--- a/chromium/ui/views/controls/menu/menu_item_view_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view_unittest.cc
@@ -16,6 +16,7 @@
#include "ui/gfx/geometry/insets.h"
#include "ui/native_theme/themed_vector_icon.h"
#include "ui/strings/grit/ui_strings.h"
+#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/controls/menu/test_menu_item_view.h"
#include "ui/views/test/menu_test_utils.h"
@@ -205,6 +206,67 @@ TEST_F(MenuItemViewUnitTest, NotifiesSelectedChanged) {
EXPECT_FALSE(is_selected);
}
+class TouchableMenuItemViewTest : public ViewsTestBase {
+ public:
+ TouchableMenuItemViewTest() = default;
+ ~TouchableMenuItemViewTest() override = default;
+
+ void SetUp() override {
+ ViewsTestBase::SetUp();
+ widget_ = CreateTestWidget();
+ widget_->Show();
+
+ menu_delegate_ = std::make_unique<test::TestMenuDelegate>();
+ menu_item_view_ = new TestMenuItemView(menu_delegate_.get());
+ menu_runner_ = std::make_unique<MenuRunner>(
+ menu_item_view_, MenuRunner::USE_TOUCHABLE_LAYOUT);
+ menu_runner_->RunMenuAt(widget_.get(), nullptr, gfx::Rect(),
+ MenuAnchorPosition::kTopLeft,
+ ui::MENU_SOURCE_KEYBOARD);
+ }
+
+ void TearDown() override {
+ widget_->CloseNow();
+ ViewsTestBase::TearDown();
+ }
+
+ gfx::Size AppendItemAndGetSize(int i, const base::string16& title) {
+ return menu_item_view_->AppendMenuItem(i, title)->GetPreferredSize();
+ }
+
+ private:
+ std::unique_ptr<test::TestMenuDelegate> menu_delegate_;
+ std::unique_ptr<MenuRunner> menu_runner_;
+ std::unique_ptr<Widget> widget_;
+
+ // Owned by MenuRunner.
+ TestMenuItemView* menu_item_view_ = nullptr;
+};
+
+// Test that touchable menu items are sized to fit the menu item titles within
+// the allowed minimum and maximum width.
+TEST_F(TouchableMenuItemViewTest, MinAndMaxWidth) {
+ const int min_menu_width = MenuConfig::instance().touchable_menu_min_width;
+ const int max_menu_width = MenuConfig::instance().touchable_menu_max_width;
+
+ // Test a title shorter than the minimum width.
+ gfx::Size item1_size =
+ AppendItemAndGetSize(1, base::ASCIIToUTF16("Item1 Short title"));
+ EXPECT_EQ(item1_size.width(), min_menu_width);
+
+ // Test a title which is between the min and max allowed widths.
+ gfx::Size item2_size = AppendItemAndGetSize(
+ 2, base::ASCIIToUTF16("Item2 bigger than min less than max"));
+ EXPECT_GT(item2_size.width(), min_menu_width);
+ EXPECT_LT(item2_size.width(), max_menu_width);
+
+ // Test a title which is longer than the max touchable menu width.
+ gfx::Size item3_size = AppendItemAndGetSize(
+ 3, base::ASCIIToUTF16("Item3 Title that is longer than the maximum "
+ "allowed context menu width"));
+ EXPECT_EQ(item3_size.width(), max_menu_width);
+}
+
class MenuItemViewLayoutTest : public ViewsTestBase {
public:
MenuItemViewLayoutTest() : test_item_(root_menu_.AppendMenuItem(1)) {}
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.cc b/chromium/ui/views/controls/menu/menu_model_adapter.cc
index b0b1cf9a7a7..5dd4a9bbb8c 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.cc
@@ -122,6 +122,8 @@ MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model,
if (model->IsAlertedAt(model_index))
menu_item_view->SetAlerted();
menu_item_view->set_is_new(model->IsNewFeatureAt(model_index));
+ menu_item_view->set_may_have_mnemonics(
+ model->MayHaveMnemonicsAt(model_index));
return menu_item_view;
}
diff --git a/chromium/ui/views/controls/menu/menu_runner.cc b/chromium/ui/views/controls/menu/menu_runner.cc
index b13f9fbf7cb..30b3ac414f9 100644
--- a/chromium/ui/views/controls/menu/menu_runner.cc
+++ b/chromium/ui/views/controls/menu/menu_runner.cc
@@ -45,7 +45,7 @@ void MenuRunner::RunMenuAt(Widget* parent,
// 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.
if (parent && parent->GetRootView())
- parent->GetRootView()->SetMouseHandler(nullptr);
+ parent->GetRootView()->SetMouseAndGestureHandler(nullptr);
if (runner_handler_.get()) {
runner_handler_->RunMenuAt(parent, button_controller, bounds, anchor,
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 214011f187c..9aa4d512daa 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ b/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -26,90 +26,138 @@
namespace {
+constexpr CGFloat kNativeCheckmarkWidth = 18;
+constexpr CGFloat kNativeMenuItemHeight = 18;
+constexpr CGFloat kIPHDotSize = 6;
+
NSImage* NewTagImage() {
- static NSImage* new_tag = []() {
- // 1. Make the attributed string.
-
- NSString* badge_text = l10n_util::GetNSString(IDS_NEW_BADGE);
-
- // The preferred font is slightly smaller and slightly more bold than the
- // menu font. The size change is required to make it look correct in the
- // badge; we add a small degree of bold to prevent color smearing/blurring
- // due to font smoothing. This ensures readability on all platforms and in
- // both light and dark modes.
- gfx::Font badge_font = gfx::Font(
- new gfx::PlatformFontMac(gfx::PlatformFontMac::SystemFontType::kMenu));
- badge_font =
- badge_font.Derive(views::NewBadge::kNewBadgeFontSizeAdjustment,
- gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM);
-
- NSColor* badge_text_color = skia::SkColorToSRGBNSColor(
- ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
- ui::NativeTheme::kColorId_TextOnProminentButtonColor));
-
- NSDictionary* badge_attrs = @{
- NSFontAttributeName : badge_font.GetNativeFont(),
- NSForegroundColorAttributeName : badge_text_color,
- };
-
- NSMutableAttributedString* badge_attr_string =
- [[NSMutableAttributedString alloc] initWithString:badge_text
- attributes:badge_attrs];
-
- if (base::mac::IsOS10_10()) {
- // The system font for 10.10 is Helvetica Neue, and when used for this
- // "new tag" the letters look cramped. Track it out so that there's some
- // breathing room. There is no tracking attribute, so instead add kerning
- // to all but the last character.
- [badge_attr_string
- addAttribute:NSKernAttributeName
- value:@0.4
- range:NSMakeRange(0, [badge_attr_string length] - 1)];
- }
+ // 1. Make the attributed string.
+
+ NSString* badge_text = l10n_util::GetNSString(IDS_NEW_BADGE);
+
+ // The preferred font is slightly smaller and slightly more bold than the
+ // menu font. The size change is required to make it look correct in the
+ // badge; we add a small degree of bold to prevent color smearing/blurring
+ // due to font smoothing. This ensures readability on all platforms and in
+ // both light and dark modes.
+ gfx::Font badge_font = gfx::Font(
+ new gfx::PlatformFontMac(gfx::PlatformFontMac::SystemFontType::kMenu));
+ badge_font = badge_font.Derive(views::NewBadge::kNewBadgeFontSizeAdjustment,
+ gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM);
+
+ NSColor* badge_text_color = skia::SkColorToSRGBNSColor(
+ ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
+ ui::NativeTheme::kColorId_TextOnProminentButtonColor));
+
+ NSDictionary* badge_attrs = @{
+ NSFontAttributeName : badge_font.GetNativeFont(),
+ NSForegroundColorAttributeName : badge_text_color,
+ };
+
+ NSMutableAttributedString* badge_attr_string =
+ [[NSMutableAttributedString alloc] initWithString:badge_text
+ attributes:badge_attrs];
+
+ // 2. Calculate the size required.
+
+ NSSize badge_size = [badge_attr_string size];
+ badge_size.width = trunc(badge_size.width);
+ badge_size.height = trunc(badge_size.height);
+
+ badge_size.width += 2 * views::NewBadge::kNewBadgeInternalPadding +
+ 2 * views::NewBadge::kNewBadgeHorizontalMargin;
+ badge_size.height += views::NewBadge::kNewBadgeInternalPaddingTopMac;
+
+ // 3. Craft the image.
+
+ return [NSImage
+ imageWithSize:badge_size
+ flipped:NO
+ drawingHandler:^(NSRect dest_rect) {
+ NSRect badge_frame = NSInsetRect(
+ dest_rect, views::NewBadge::kNewBadgeHorizontalMargin, 0);
+ NSBezierPath* rounded_badge_rect = [NSBezierPath
+ bezierPathWithRoundedRect:badge_frame
+ xRadius:views::NewBadge::kNewBadgeCornerRadius
+ yRadius:views::NewBadge::kNewBadgeCornerRadius];
+ NSColor* badge_color = skia::SkColorToSRGBNSColor(
+ ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
+ ui::NativeTheme::kColorId_ProminentButtonColor));
+ [badge_color set];
+ [rounded_badge_rect fill];
+
+ NSPoint badge_text_location = NSMakePoint(
+ NSMinX(badge_frame) + views::NewBadge::kNewBadgeInternalPadding,
+ NSMinY(badge_frame) +
+ views::NewBadge::kNewBadgeInternalPaddingTopMac);
+ [badge_attr_string drawAtPoint:badge_text_location];
+
+ return YES;
+ }];
+}
- // 2. Calculate the size required.
-
- NSSize badge_size = [badge_attr_string size];
- badge_size.width = trunc(badge_size.width);
- badge_size.height = trunc(badge_size.height);
-
- badge_size.width += 2 * views::NewBadge::kNewBadgeInternalPadding +
- 2 * views::NewBadge::kNewBadgeHorizontalMargin;
- badge_size.height += views::NewBadge::kNewBadgeInternalPaddingTopMac;
-
- // 3. Craft the image.
-
- return [[NSImage
- imageWithSize:badge_size
- flipped:NO
- drawingHandler:^(NSRect dest_rect) {
- NSRect badge_frame = NSInsetRect(
- dest_rect, views::NewBadge::kNewBadgeHorizontalMargin, 0);
- NSBezierPath* rounded_badge_rect = [NSBezierPath
- bezierPathWithRoundedRect:badge_frame
- xRadius:views::NewBadge::kNewBadgeCornerRadius
- yRadius:views::NewBadge::kNewBadgeCornerRadius];
- NSColor* badge_color = skia::SkColorToSRGBNSColor(
- ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
- ui::NativeTheme::kColorId_ProminentButtonColor));
- [badge_color set];
- [rounded_badge_rect fill];
-
- NSPoint badge_text_location = NSMakePoint(
- NSMinX(badge_frame) + views::NewBadge::kNewBadgeInternalPadding,
- NSMinY(badge_frame) +
- views::NewBadge::kNewBadgeInternalPaddingTopMac);
- [badge_attr_string drawAtPoint:badge_text_location];
-
- return YES;
- }] retain];
- }();
-
- return new_tag;
+NSImage* IPHDotImage() {
+ // Embed horizontal centering space as NSMenuItem will otherwise left-align
+ // it.
+ return [NSImage
+ imageWithSize:NSMakeSize(2 * kIPHDotSize, kIPHDotSize)
+ flipped:NO
+ drawingHandler:^(NSRect dest_rect) {
+ NSBezierPath* dot_path = [NSBezierPath
+ bezierPathWithOvalInRect:NSMakeRect(kIPHDotSize / 2, 0, kIPHDotSize,
+ kIPHDotSize)];
+ NSColor* dot_color = skia::SkColorToSRGBNSColor(
+ ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
+ ui::NativeTheme::kColorId_ProminentButtonColor));
+ [dot_color set];
+ [dot_path fill];
+
+ return YES;
+ }];
+}
+
+NSMutableAttributedString* MutableAttributedStringForMenuItemTitleString(
+ NSString* string) {
+ // Starting in 10.13, if an attributed string is set as a menu item title,
+ // and NSFontAttributeName is not specified for it, it is automatically
+ // rendered in a font matching other menu items. Prior to then, a menu item
+ // with no specified font is rendered in Helvetica. In addition, while the
+ // documentation says that -[NSFont menuFontOfSize:0] gives the standard
+ // menu font, that doesn't actually match up. Therefore, specify a font that
+ // visually matches.
+ NSDictionary* attrs = nil;
+ if (base::mac::IsAtMostOS10_12())
+ attrs = @{NSFontAttributeName : [NSFont menuFontOfSize:14]};
+
+ return [[[NSMutableAttributedString alloc] initWithString:string
+ attributes:attrs] autorelease];
}
} // namespace
+// --- Private API begin ---
+
+@interface NSCarbonMenuImpl : NSObject
+- (void)highlightItemAtIndex:(NSInteger)index;
+@end
+
+@interface NSMenu ()
+- (NSCarbonMenuImpl*)_menuImpl;
+@end
+
+// --- Private API end ---
+
+// An NSTextAttachmentCell to show the [New] tag on a menu item.
+//
+// /!\ WARNING /!\
+//
+// Do NOT update to the "new in macOS 10.11" API of NSTextAttachment.image until
+// macOS 10.15 is the minimum required macOS for Chromium. Because menus are
+// Carbon-based, the new NSTextAttachment.image API did not function correctly
+// until then. Specifically, in macOS 10.11-10.12, images that use the new API
+// do not appear. In macOS 10.13-10.14, the flipped flag of -[NSImage
+// imageWithSize:flipped:drawingHandler:] is not respected. Only when 10.15 is
+// the minimum required OS can https://crrev.com/c/2572937 be relanded.
@interface NewTagAttachmentCell : NSTextAttachmentCell
@end
@@ -123,7 +171,7 @@ NSImage* NewTagImage() {
}
- (NSPoint)cellBaselineOffset {
- return NSMakePoint(0, views::NewBadge::kNewBadgeBaslineOffsetMac);
+ return NSMakePoint(0, views::NewBadge::kNewBadgeBaselineOffsetMac);
}
- (NSSize)cellSize {
@@ -132,46 +180,65 @@ NSImage* NewTagImage() {
@end
-@interface MenuControllerDelegate : NSObject <MenuControllerCocoaDelegate>
+@interface MenuControllerDelegate : NSObject <MenuControllerCocoaDelegate> {
+ id<NSObject> _menuOpenObserver;
+}
@end
@implementation MenuControllerDelegate
+- (void)dealloc {
+ if (_menuOpenObserver)
+ [[NSNotificationCenter defaultCenter] removeObserver:_menuOpenObserver];
+
+ [super dealloc];
+}
+
- (void)controllerWillAddItem:(NSMenuItem*)menuItem
fromModel:(ui::MenuModel*)model
atIndex:(NSInteger)index {
- static const bool feature_enabled =
+ static const bool newBadgeFeatureEnabled =
base::FeatureList::IsEnabled(views::features::kEnableNewBadgeOnMenuItems);
- if (!feature_enabled || !model->IsNewFeatureAt(index))
- return;
-
- // TODO(avi): When moving to 10.11 as the minimum macOS, switch to using
- // NSTextAttachment's |image| and |bounds| properties and avoid the whole
- // NSTextAttachmentCell subclassing mishegas.
- base::scoped_nsobject<NSTextAttachment> attachment(
- [[NSTextAttachment alloc] init]);
- attachment.get().attachmentCell =
- [[[NewTagAttachmentCell alloc] init] autorelease];
-
- // Starting in 10.13, if an attributed string is set as a menu item title, and
- // NSFontAttributeName is not specified for it, it is automatically rendered
- // in a font matching other menu items. Prior to then, a menu item with no
- // specified font is rendered in Helvetica. In addition, while the
- // documentation says that -[NSFont menuFontOfSize:0] gives the standard menu
- // font, that doesn't actually match up. Therefore, specify a font that
- // visually matches.
- NSDictionary* attrs = nil;
- if (base::mac::IsAtMostOS10_12())
- attrs = @{NSFontAttributeName : [NSFont menuFontOfSize:14]};
-
- base::scoped_nsobject<NSMutableAttributedString> attrTitle(
- [[NSMutableAttributedString alloc] initWithString:menuItem.title
- attributes:attrs]);
- [attrTitle
- appendAttributedString:[NSAttributedString
- attributedStringWithAttachment:attachment]];
+ if (newBadgeFeatureEnabled && model->IsNewFeatureAt(index)) {
+ // /!\ WARNING /!\ Do not update this to use NSTextAttachment.image until
+ // macOS 10.15 is the minimum required OS. See the details on the class
+ // comment above.
+ NSTextAttachment* attachment =
+ [[[NSTextAttachment alloc] init] autorelease];
+ attachment.attachmentCell =
+ [[[NewTagAttachmentCell alloc] init] autorelease];
+
+ NSMutableAttributedString* attrTitle =
+ MutableAttributedStringForMenuItemTitleString(menuItem.title);
+ [attrTitle
+ appendAttributedString:[NSAttributedString
+ attributedStringWithAttachment:attachment]];
+
+ menuItem.attributedTitle = attrTitle;
+ }
- menuItem.attributedTitle = attrTitle;
+ if (model->IsAlertedAt(index)) {
+ NSImage* iphDotImage = IPHDotImage();
+ menuItem.onStateImage = iphDotImage;
+ menuItem.offStateImage = iphDotImage;
+ menuItem.mixedStateImage = iphDotImage;
+
+ DCHECK(!_menuOpenObserver);
+ _menuOpenObserver = [[NSNotificationCenter defaultCenter]
+ addObserverForName:NSMenuDidBeginTrackingNotification
+ object:menuItem.menu
+ queue:nil
+ usingBlock:^(NSNotification* note) {
+ NSMenu* menu = note.object;
+ if ([menu respondsToSelector:@selector(_menuImpl)]) {
+ NSCarbonMenuImpl* menuImpl = [menu _menuImpl];
+ if ([menuImpl respondsToSelector:@selector
+ (highlightItemAtIndex:)]) {
+ [menuImpl highlightItemAtIndex:index];
+ }
+ }
+ }];
+ }
}
@end
@@ -180,9 +247,6 @@ namespace views {
namespace internal {
namespace {
-constexpr CGFloat kNativeCheckmarkWidth = 18;
-constexpr CGFloat kNativeMenuItemHeight = 18;
-
// Returns the first item in |menu_controller|'s menu that will be checked.
NSMenuItem* FirstCheckedItem(MenuControllerCocoa* menu_controller) {
for (NSMenuItem* item in [[menu_controller menu] itemArray]) {
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 4771d1d6e85..8e21f427f6a 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -13,6 +13,7 @@
#include "third_party/skia/include/core/SkPath.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
#include "ui/views/border.h"
@@ -22,6 +23,7 @@
#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/layout/flex_layout.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/round_rect_painter.h"
#include "ui/views/view.h"
@@ -43,11 +45,14 @@ static constexpr int kBorderPaddingDueToRoundedCorners = 1;
class MenuScrollButton : public View {
public:
+ METADATA_HEADER(MenuScrollButton);
MenuScrollButton(SubmenuView* host, bool is_up)
: host_(host),
is_up_(is_up),
// Make our height the same as that of other MenuItemViews.
pref_height_(MenuItemView::pref_menu_height()) {}
+ MenuScrollButton(const MenuScrollButton&) = delete;
+ MenuScrollButton& operator=(const MenuScrollButton&) = delete;
gfx::Size CalculatePreferredSize() const override {
return gfx::Size(MenuConfig::instance().scroll_arrow_height * 2 - 1,
@@ -80,8 +85,9 @@ class MenuScrollButton : public View {
host_->GetMenuItem()->GetMenuController()->OnDragExitedScrollButton(host_);
}
- int OnPerformDrop(const ui::DropTargetEvent& event) override {
- return ui::DragDropTypes::DRAG_NONE;
+ ui::mojom::DragOperation OnPerformDrop(
+ const ui::DropTargetEvent& event) override {
+ return ui::mojom::DragOperation::kNone;
}
void OnPaint(gfx::Canvas* canvas) override {
@@ -133,10 +139,11 @@ class MenuScrollButton : public View {
// Color for the arrow to scroll.
SkColor arrow_color_;
-
- DISALLOW_COPY_AND_ASSIGN(MenuScrollButton);
};
+BEGIN_METADATA(MenuScrollButton, View)
+END_METADATA
+
} // namespace
// MenuScrollView --------------------------------------------------------------
@@ -151,7 +158,10 @@ class MenuScrollButton : public View {
class MenuScrollViewContainer::MenuScrollView : public View {
public:
+ METADATA_HEADER(MenuScrollView);
explicit MenuScrollView(View* child) { AddChildView(child); }
+ MenuScrollView(const MenuScrollView&) = delete;
+ MenuScrollView& operator=(const MenuScrollView&) = delete;
void ScrollRectToVisible(const gfx::Rect& rect) override {
// NOTE: this assumes we only want to scroll in the y direction.
@@ -177,11 +187,11 @@ class MenuScrollViewContainer::MenuScrollView : public View {
// Returns the contents, which is the SubmenuView.
View* GetContents() { return children().front(); }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MenuScrollView);
};
+BEGIN_METADATA(MenuScrollViewContainer, MenuScrollView, View)
+END_METADATA
+
// MenuScrollViewContainer ----------------------------------------------------
MenuScrollViewContainer::MenuScrollViewContainer(SubmenuView* content_view)
@@ -293,7 +303,7 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
const ui::NativeTheme* native_theme = GetNativeTheme();
bool use_outer_border =
menu_config.use_outer_border ||
- (native_theme && native_theme->UsesHighContrastColors());
+ (native_theme && native_theme->UserHasContrastPreference());
corner_radius_ = menu_config.CornerRadiusForMenu(
content_view_->GetMenuItem()->GetMenuController());
int padding = use_outer_border && corner_radius_ > 0
@@ -327,7 +337,8 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
void MenuScrollViewContainer::CreateBubbleBorder() {
const SkColor color = GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_MenuBackgroundColor);
- bubble_border_ = new BubbleBorder(arrow_, BubbleBorder::SMALL_SHADOW, color);
+ bubble_border_ =
+ new BubbleBorder(arrow_, BubbleBorder::STANDARD_SHADOW, color);
if (content_view_->GetMenuItem()
->GetMenuController()
->use_touchable_layout()) {
@@ -351,6 +362,7 @@ BubbleBorder::Arrow MenuScrollViewContainer::BubbleBorderTypeFromAnchor(
MenuAnchorPosition anchor) {
switch (anchor) {
case MenuAnchorPosition::kBubbleAbove:
+ case MenuAnchorPosition::kBubbleBelow:
case MenuAnchorPosition::kBubbleLeft:
case MenuAnchorPosition::kBubbleRight:
return BubbleBorder::FLOAT;
diff --git a/chromium/ui/views/controls/menu/menu_separator.cc b/chromium/ui/views/controls/menu/menu_separator.cc
index 539e79934fe..98343f884a3 100644
--- a/chromium/ui/views/controls/menu/menu_separator.cc
+++ b/chromium/ui/views/controls/menu/menu_separator.cc
@@ -6,6 +6,8 @@
#include "build/build_config.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/canvas.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/controls/menu/menu_config.h"
@@ -101,6 +103,10 @@ void MenuSeparator::SetType(ui::MenuSeparatorType type) {
OnPropertyChanged(&type_, kPropertyEffectsPreferredSizeChanged);
}
+void MenuSeparator::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+ node_data->role = ax::mojom::Role::kSplitter;
+}
+
BEGIN_METADATA(MenuSeparator, View)
ADD_PROPERTY_METADATA(ui::MenuSeparatorType, Type)
END_METADATA
diff --git a/chromium/ui/views/controls/menu/menu_separator.h b/chromium/ui/views/controls/menu/menu_separator.h
index 18566efae79..edf5c249212 100644
--- a/chromium/ui/views/controls/menu/menu_separator.h
+++ b/chromium/ui/views/controls/menu/menu_separator.h
@@ -29,6 +29,8 @@ class VIEWS_EXPORT MenuSeparator : public View {
ui::MenuSeparatorType GetType() const;
void SetType(ui::MenuSeparatorType type);
+ void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+
private:
// The type of the separator.
ui::MenuSeparatorType type_;
diff --git a/chromium/ui/views/controls/menu/menu_types.h b/chromium/ui/views/controls/menu/menu_types.h
index 3554c3fb84b..d00ccf44bcb 100644
--- a/chromium/ui/views/controls/menu/menu_types.h
+++ b/chromium/ui/views/controls/menu/menu_types.h
@@ -18,6 +18,7 @@ enum class MenuAnchorPosition {
kBubbleAbove,
kBubbleLeft,
kBubbleRight,
+ kBubbleBelow,
};
} // namespace views
diff --git a/chromium/ui/views/controls/menu/native_menu_win.cc b/chromium/ui/views/controls/menu/native_menu_win.cc
index 042ecddda20..a28e24a532a 100644
--- a/chromium/ui/views/controls/menu/native_menu_win.cc
+++ b/chromium/ui/views/controls/menu/native_menu_win.cc
@@ -8,6 +8,7 @@
#include "base/check.h"
#include "base/strings/string_util.h"
+#include "base/strings/string_util_win.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_win.h"
@@ -51,12 +52,9 @@ NativeMenuWin::NativeMenuWin(ui::MenuModel* model, HWND system_menu_for)
!system_menu_for),
system_menu_for_(system_menu_for),
first_item_index_(0),
- parent_(nullptr),
- destroyed_flag_(nullptr) {}
+ parent_(nullptr) {}
NativeMenuWin::~NativeMenuWin() {
- if (destroyed_flag_)
- *destroyed_flag_ = true;
items_.clear();
DestroyMenu(menu_);
}
@@ -193,12 +191,13 @@ void NativeMenuWin::UpdateMenuItemInfoForString(MENUITEMINFO* mii,
ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
// Strip out any tabs, otherwise they get interpreted as accelerators and can
// lead to weird behavior.
- base::ReplaceSubstringsAfterOffset(&formatted, 0, L"\t", L" ");
+ base::ReplaceSubstringsAfterOffset(&formatted, 0, STRING16_LITERAL("\t"),
+ STRING16_LITERAL(" "));
if (type != ui::MenuModel::TYPE_SUBMENU) {
// Add accelerator details to the label if provided.
ui::Accelerator accelerator(ui::VKEY_UNKNOWN, ui::EF_NONE);
if (model_->GetAcceleratorAt(model_index, &accelerator)) {
- formatted += L"\t";
+ formatted += STRING16_LITERAL("\t");
formatted += accelerator.GetShortcutText();
}
}
@@ -209,7 +208,7 @@ void NativeMenuWin::UpdateMenuItemInfoForString(MENUITEMINFO* mii,
// Give Windows a pointer to the label string.
mii->fMask |= MIIM_STRING;
- mii->dwTypeData = const_cast<wchar_t*>(items_[model_index]->label.c_str());
+ mii->dwTypeData = base::as_writable_wcstr(items_[model_index]->label);
}
void NativeMenuWin::ResetNativeMenu() {
diff --git a/chromium/ui/views/controls/menu/native_menu_win.h b/chromium/ui/views/controls/menu/native_menu_win.h
index 03f00a84ead..01db841cd96 100644
--- a/chromium/ui/views/controls/menu/native_menu_win.h
+++ b/chromium/ui/views/controls/menu/native_menu_win.h
@@ -100,11 +100,6 @@ class VIEWS_EXPORT NativeMenuWin {
// If we're a submenu, this is our parent.
NativeMenuWin* parent_;
- // If non-null the destructor sets this to true. This is set to non-null while
- // the menu is showing. It is used to detect if the menu was deleted while
- // running.
- bool* destroyed_flag_;
-
DISALLOW_COPY_AND_ASSIGN(NativeMenuWin);
};
diff --git a/chromium/ui/views/controls/menu/new_badge.h b/chromium/ui/views/controls/menu/new_badge.h
index 89c0602e703..478c67fb1d0 100644
--- a/chromium/ui/views/controls/menu/new_badge.h
+++ b/chromium/ui/views/controls/menu/new_badge.h
@@ -67,7 +67,7 @@ class VIEWS_EXPORT NewBadge {
static constexpr int kNewBadgeInternalPaddingTopMac = 1;
// The baseline offset of the "new" badge image to the menu text baseline.
- static constexpr int kNewBadgeBaslineOffsetMac = -4;
+ static constexpr int kNewBadgeBaselineOffsetMac = -4;
// The corner radius of the rounded rect for the "new" badge.
static constexpr int kNewBadgeCornerRadius = 3;
diff --git a/chromium/ui/views/controls/menu/submenu_view.cc b/chromium/ui/views/controls/menu/submenu_view.cc
index 253c795739f..548986ec100 100644
--- a/chromium/ui/views/controls/menu/submenu_view.cc
+++ b/chromium/ui/views/controls/menu/submenu_view.cc
@@ -267,7 +267,8 @@ void SubmenuView::OnDragExited() {
parent_menu_item_->GetMenuController()->OnDragExited(this);
}
-int SubmenuView::OnPerformDrop(const ui::DropTargetEvent& event) {
+ui::mojom::DragOperation SubmenuView::OnPerformDrop(
+ const ui::DropTargetEvent& event) {
DCHECK(parent_menu_item_->GetMenuController());
return parent_menu_item_->GetMenuController()->OnPerformDrop(this, event);
}
diff --git a/chromium/ui/views/controls/menu/submenu_view.h b/chromium/ui/views/controls/menu/submenu_view.h
index 5dd7dee536d..d03e5bbbefe 100644
--- a/chromium/ui/views/controls/menu/submenu_view.h
+++ b/chromium/ui/views/controls/menu/submenu_view.h
@@ -88,7 +88,8 @@ class VIEWS_EXPORT SubmenuView : public View,
void OnDragEntered(const ui::DropTargetEvent& event) override;
int OnDragUpdated(const ui::DropTargetEvent& event) override;
void OnDragExited() override;
- int OnPerformDrop(const ui::DropTargetEvent& event) override;
+ ui::mojom::DragOperation OnPerformDrop(
+ const ui::DropTargetEvent& event) override;
// Scrolls on menu item boundaries.
bool OnMouseWheel(const ui::MouseWheelEvent& e) override;
diff --git a/chromium/ui/views/controls/message_box_view.cc b/chromium/ui/views/controls/message_box_view.cc
index ba85f6f7fa2..1c699affa71 100644
--- a/chromium/ui/views/controls/message_box_view.cc
+++ b/chromium/ui/views/controls/message_box_view.cc
@@ -183,10 +183,6 @@ void MessageBoxView::SetLink(const base::string16& text,
ResetLayoutManager();
}
-void MessageBoxView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
- node_data->role = ax::mojom::Role::kAlertDialog;
-}
-
void MessageBoxView::SetInterRowVerticalSpacing(int spacing) {
if (inter_row_vertical_spacing_ == spacing)
return;
@@ -220,8 +216,6 @@ void MessageBoxView::ViewHierarchyChanged(
if (details.child == this && details.is_add) {
if (prompt_field_ && prompt_field_->GetVisible())
prompt_field_->SelectAll(true);
-
- NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
}
}
diff --git a/chromium/ui/views/controls/message_box_view.h b/chromium/ui/views/controls/message_box_view.h
index 8d790f6b389..79ac063b557 100644
--- a/chromium/ui/views/controls/message_box_view.h
+++ b/chromium/ui/views/controls/message_box_view.h
@@ -71,9 +71,6 @@ class VIEWS_EXPORT MessageBoxView : public View {
// Sets the text and the callback of the link. |text| must be non-empty.
void SetLink(const base::string16& text, Link::ClickedCallback callback);
- // View:
- void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
-
void SetInterRowVerticalSpacing(int spacing);
void SetMessageWidth(int width);
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 bf60b86ae20..ec20dd5e820 100644
--- a/chromium/ui/views/controls/native/native_view_host_mac.mm
+++ b/chromium/ui/views/controls/native/native_view_host_mac.mm
@@ -155,8 +155,11 @@ void NativeViewHostMac::RemovedFromWidget() {
bool NativeViewHostMac::SetCornerRadii(
const gfx::RoundedCornersF& corner_radii) {
- NOTIMPLEMENTED();
- return false;
+ ui::Layer* layer = GetUiLayer();
+ DCHECK(layer);
+ layer->SetRoundedCornerRadius(corner_radii);
+ layer->SetIsFastRoundedCorner(true);
+ return true;
}
bool NativeViewHostMac::SetCustomMask(std::unique_ptr<ui::LayerOwner> mask) {
diff --git a/chromium/ui/views/controls/prefix_selector.cc b/chromium/ui/views/controls/prefix_selector.cc
index c0cc92ea180..f553d805f14 100644
--- a/chromium/ui/views/controls/prefix_selector.cc
+++ b/chromium/ui/views/controls/prefix_selector.cc
@@ -13,6 +13,7 @@
#include "base/i18n/case_conversion.h"
#include "base/time/default_tick_clock.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/gfx/range/range.h"
@@ -48,7 +49,9 @@ uint32_t PrefixSelector::ConfirmCompositionText(bool keep_selection) {
void PrefixSelector::ClearCompositionText() {}
-void PrefixSelector::InsertText(const base::string16& text) {
+void PrefixSelector::InsertText(const base::string16& text,
+ InsertTextCursorBehavior cursor_behavior) {
+ // TODO(crbug.com/1155331): Handle |cursor_behavior| correctly.
OnTextInput(text);
}
@@ -163,7 +166,7 @@ bool PrefixSelector::ShouldDoLearning() {
return false;
}
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
bool PrefixSelector::SetCompositionFromExistingText(
const gfx::Range& range,
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) {
@@ -173,7 +176,7 @@ bool PrefixSelector::SetCompositionFromExistingText(
}
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
gfx::Range PrefixSelector::GetAutocorrectRange() const {
NOTIMPLEMENTED_LOG_ONCE();
return gfx::Range();
@@ -184,16 +187,11 @@ gfx::Rect PrefixSelector::GetAutocorrectCharacterBounds() const {
return gfx::Rect();
}
-bool PrefixSelector::SetAutocorrectRange(const base::string16& autocorrect_text,
- const gfx::Range& range) {
- // TODO(crbug.com/1091088) Implement setAutocorrectRange.
+bool PrefixSelector::SetAutocorrectRange(const gfx::Range& range) {
+ // TODO(crbug.com/1091088): Implement SetAutocorrectRange.
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
-
-void PrefixSelector::ClearAutocorrectRange() {
- // TODO(crbug.com/1091088) Implement ClearAutocorrectRange.
-}
#endif
#if defined(OS_WIN)
diff --git a/chromium/ui/views/controls/prefix_selector.h b/chromium/ui/views/controls/prefix_selector.h
index 9df6de750fb..a3df03f5c0f 100644
--- a/chromium/ui/views/controls/prefix_selector.h
+++ b/chromium/ui/views/controls/prefix_selector.h
@@ -16,6 +16,7 @@
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/views/views_export.h"
@@ -46,7 +47,8 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
void SetCompositionText(const ui::CompositionText& composition) override;
uint32_t ConfirmCompositionText(bool keep_selection) override;
void ClearCompositionText() override;
- void InsertText(const base::string16& text) override;
+ void InsertText(const base::string16& text,
+ InsertTextCursorBehavior cursor_behavior) override;
void InsertChar(const ui::KeyEvent& event) override;
ui::TextInputType GetTextInputType() const override;
ui::TextInputMode GetTextInputMode() const override;
@@ -76,18 +78,16 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
ukm::SourceId GetClientSourceForMetrics() const override;
bool ShouldDoLearning() override;
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
bool SetCompositionFromExistingText(
const gfx::Range& range,
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
gfx::Range GetAutocorrectRange() const override;
gfx::Rect GetAutocorrectCharacterBounds() const override;
- bool SetAutocorrectRange(const base::string16& autocorrect_text,
- const gfx::Range& range) override;
- void ClearAutocorrectRange() override;
+ bool SetAutocorrectRange(const gfx::Range& range) override;
#endif
#if defined(OS_WIN)
diff --git a/chromium/ui/views/controls/prefix_selector_unittest.cc b/chromium/ui/views/controls/prefix_selector_unittest.cc
index 567d2209b08..ac40d186c43 100644
--- a/chromium/ui/views/controls/prefix_selector_unittest.cc
+++ b/chromium/ui/views/controls/prefix_selector_unittest.cc
@@ -63,27 +63,43 @@ class PrefixSelectorTest : public ViewsTestBase {
};
TEST_F(PrefixSelectorTest, PrefixSelect) {
- selector_->InsertText(ASCIIToUTF16("an"));
+ selector_->InsertText(
+ ASCIIToUTF16("an"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_EQ(1, delegate_.GetSelectedRow());
// Invoke OnViewBlur() to reset time.
selector_->OnViewBlur();
- selector_->InsertText(ASCIIToUTF16("a"));
+ selector_->InsertText(
+ ASCIIToUTF16("a"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_EQ(0, delegate_.GetSelectedRow());
selector_->OnViewBlur();
- selector_->InsertText(ASCIIToUTF16("g"));
+ selector_->InsertText(
+ ASCIIToUTF16("g"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_EQ(3, delegate_.GetSelectedRow());
selector_->OnViewBlur();
- selector_->InsertText(ASCIIToUTF16("b"));
- selector_->InsertText(ASCIIToUTF16("a"));
+ selector_->InsertText(
+ ASCIIToUTF16("b"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+ selector_->InsertText(
+ ASCIIToUTF16("a"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_EQ(2, delegate_.GetSelectedRow());
selector_->OnViewBlur();
- selector_->InsertText(ASCIIToUTF16("\t"));
- selector_->InsertText(ASCIIToUTF16("b"));
- selector_->InsertText(ASCIIToUTF16("a"));
+ selector_->InsertText(
+ ASCIIToUTF16("\t"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+ selector_->InsertText(
+ ASCIIToUTF16("b"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+ selector_->InsertText(
+ ASCIIToUTF16("a"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_EQ(2, delegate_.GetSelectedRow());
}
diff --git a/chromium/ui/views/controls/progress_bar.cc b/chromium/ui/views/controls/progress_bar.cc
index 09e80a9c335..00b38aa71de 100644
--- a/chromium/ui/views/controls/progress_bar.cc
+++ b/chromium/ui/views/controls/progress_bar.cc
@@ -31,13 +31,20 @@ namespace {
// In DP, the amount to round the corners of the progress bar (both bg and
// fg, aka slice).
constexpr int kCornerRadius = 3;
+constexpr int kSmallCornerRadius = 1;
-// Adds a rectangle to the path. The corners will be rounded if there is room.
+// Adds a rectangle to the path. The corners will be rounded with regular corner
+// radius if the progress bar height is larger than the regular corner radius.
+// Otherwise the corners will be rounded with the small corner radius if there
+// is room for it.
void AddPossiblyRoundRectToPath(const gfx::Rect& rectangle,
bool allow_round_corner,
SkPath* path) {
- if (!allow_round_corner || rectangle.height() < kCornerRadius) {
+ if (!allow_round_corner || rectangle.height() < kSmallCornerRadius) {
path->addRect(gfx::RectToSkRect(rectangle));
+ } else if (rectangle.height() < kCornerRadius) {
+ path->addRoundRect(gfx::RectToSkRect(rectangle), kSmallCornerRadius,
+ kSmallCornerRadius);
} else {
path->addRoundRect(gfx::RectToSkRect(rectangle), kCornerRadius,
kCornerRadius);
@@ -257,8 +264,8 @@ void ProgressBar::MaybeNotifyAccessibilityValueChanged() {
}
BEGIN_METADATA(ProgressBar, View)
-ADD_PROPERTY_METADATA(SkColor, ForegroundColor)
-ADD_PROPERTY_METADATA(SkColor, BackgroundColor)
+ADD_PROPERTY_METADATA(SkColor, ForegroundColor, metadata::SkColorConverter)
+ADD_PROPERTY_METADATA(SkColor, BackgroundColor, metadata::SkColorConverter)
END_METADATA
} // namespace views
diff --git a/chromium/ui/views/controls/scroll_view.cc b/chromium/ui/views/controls/scroll_view.cc
index 1911f194535..dd9827ffe0e 100644
--- a/chromium/ui/views/controls/scroll_view.cc
+++ b/chromium/ui/views/controls/scroll_view.cc
@@ -23,6 +23,7 @@
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/focus_ring.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/view.h"
@@ -49,7 +50,10 @@ T CombineScrollOffsets(T x, T y) {
class ScrollCornerView : public View {
public:
+ METADATA_HEADER(ScrollCornerView);
ScrollCornerView() = default;
+ ScrollCornerView(const ScrollCornerView&) = delete;
+ ScrollCornerView& operator=(const ScrollCornerView&) = delete;
void OnPaint(gfx::Canvas* canvas) override {
ui::NativeTheme::ExtraParams ignored;
@@ -57,11 +61,11 @@ class ScrollCornerView : public View {
canvas->sk_canvas(), ui::NativeTheme::kScrollbarCorner,
ui::NativeTheme::kNormal, GetLocalBounds(), ignored);
}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ScrollCornerView);
};
+BEGIN_METADATA(ScrollCornerView, View)
+END_METADATA
+
// Returns true if any descendants of |view| have a layer (not including
// |view|).
bool DoesDescendantHaveLayer(View* view) {
@@ -128,7 +132,10 @@ int AdjustPosition(int current_position,
// Viewport contains the contents View of the ScrollView.
class ScrollView::Viewport : public View {
public:
+ METADATA_HEADER(Viewport);
explicit Viewport(ScrollView* scroll_view) : scroll_view_(scroll_view) {}
+ Viewport(const Viewport&) = delete;
+ Viewport& operator=(const Viewport&) = delete;
~Viewport() override = default;
void ScrollRectToVisible(const gfx::Rect& rect) override {
@@ -159,25 +166,27 @@ class ScrollView::Viewport : public View {
void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) override {
- if (details.is_add && IsContentsViewport() && Contains(details.parent))
+ if (details.is_add && GetIsContentsViewport() && Contains(details.parent))
scroll_view_->UpdateViewportLayerForClipping();
}
void OnChildLayerChanged(View* child) override {
- if (IsContentsViewport())
+ if (GetIsContentsViewport())
scroll_view_->UpdateViewportLayerForClipping();
}
private:
- bool IsContentsViewport() const {
+ bool GetIsContentsViewport() const {
return parent() && scroll_view_->contents_viewport_ == this;
}
ScrollView* scroll_view_;
-
- DISALLOW_COPY_AND_ASSIGN(Viewport);
};
+BEGIN_METADATA(ScrollView, Viewport, View)
+ADD_READONLY_PROPERTY_METADATA(bool, IsContentsViewport)
+END_METADATA
+
ScrollView::ScrollView()
: ScrollView(base::FeatureList::IsEnabled(
::features::kUiCompositorScrollWithLayers)
@@ -365,6 +374,47 @@ void ScrollView::SetDrawOverflowIndicator(bool draw_overflow_indicator) {
OnPropertyChanged(&draw_overflow_indicator_, kPropertyEffectsPaint);
}
+View* ScrollView::SetCustomOverflowIndicator(OverflowIndicatorAlignment side,
+ std::unique_ptr<View> indicator,
+ int thickness,
+ bool fills_opaquely) {
+ if (thickness < 0)
+ thickness = 0;
+
+ if (ScrollsWithLayers()) {
+ indicator->SetPaintToLayer();
+ indicator->layer()->SetFillsBoundsOpaquely(fills_opaquely);
+ }
+
+ View* indicator_ptr = indicator.get();
+ switch (side) {
+ case OverflowIndicatorAlignment::kLeft:
+ more_content_left_ = std::move(indicator);
+ more_content_left_thickness_ = thickness;
+ break;
+ case OverflowIndicatorAlignment::kTop:
+ more_content_top_ = std::move(indicator);
+ more_content_top_thickness_ = thickness;
+ break;
+ case OverflowIndicatorAlignment::kRight:
+ more_content_right_ = std::move(indicator);
+ more_content_right_thickness_ = thickness;
+ break;
+ case OverflowIndicatorAlignment::kBottom:
+ more_content_bottom_ = std::move(indicator);
+ more_content_bottom_thickness_ = thickness;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ UpdateOverflowIndicatorVisibility(CurrentOffset());
+ PositionOverflowIndicators();
+
+ return indicator_ptr;
+}
+
void ScrollView::ClipHeightTo(int min_height, int max_height) {
min_height_ = min_height;
max_height_ = max_height;
@@ -408,6 +458,14 @@ void ScrollView::SetHasFocusIndicator(bool has_focus_indicator) {
OnPropertyChanged(&draw_focus_indicator_, kPropertyEffectsPaint);
}
+void ScrollView::AddScrollViewObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ScrollView::RemoveScrollViewObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
gfx::Size ScrollView::CalculatePreferredSize() const {
if (!is_bounded())
return View::CalculatePreferredSize();
@@ -994,18 +1052,10 @@ gfx::ScrollOffset ScrollView::CurrentOffset() const {
void ScrollView::ScrollToOffset(const gfx::ScrollOffset& offset) {
if (ScrollsWithLayers()) {
contents_->layer()->SetScrollOffset(offset);
-
- // TODO(tapted): Remove this call to OnLayerScrolled(). It's unnecessary,
- // but will only be invoked (asynchronously) when a Compositor is present
- // and commits a frame, which isn't true in some tests.
- // See http://crbug.com/637521.
- OnLayerScrolled(offset, contents_->layer()->element_id());
} else {
contents_->SetPosition(gfx::Point(-offset.x(), -offset.y()));
- ScrollHeader();
}
- UpdateOverflowIndicatorVisibility(offset);
- UpdateScrollBarPositions();
+ OnScrolled(offset);
}
bool ScrollView::ScrollsWithLayers() const {
@@ -1051,10 +1101,18 @@ void ScrollView::EnableViewportLayer() {
UpdateBackground();
}
-void ScrollView::OnLayerScrolled(const gfx::ScrollOffset&,
+void ScrollView::OnLayerScrolled(const gfx::ScrollOffset& current_offset,
const cc::ElementId&) {
+ OnScrolled(current_offset);
+}
+
+void ScrollView::OnScrolled(const gfx::ScrollOffset& offset) {
+ UpdateOverflowIndicatorVisibility(offset);
UpdateScrollBarPositions();
ScrollHeader();
+
+ for (auto& observer : observers_)
+ observer.OnContentsScrolled();
}
void ScrollView::ScrollHeader() {
@@ -1117,16 +1175,23 @@ base::Optional<ui::NativeTheme::ColorId> ScrollView::GetBackgroundThemeColorId()
}
void ScrollView::PositionOverflowIndicators() {
- const gfx::Rect bounds = GetContentsBounds();
- const int x = bounds.x();
- const int y = bounds.y();
- const int w = bounds.width();
- const int h = bounds.height();
- const int t = Separator::kThickness;
- more_content_left_->SetBounds(x, y, t, h);
- more_content_top_->SetBounds(x, y, w, t);
- more_content_right_->SetBounds(bounds.right() - t, y, t, h);
- more_content_bottom_->SetBounds(x, bounds.bottom() - t, w, t);
+ // TODO(https://crbug.com/1166949): Use a layout manager to position these.
+ const gfx::Rect contents_bounds = GetContentsBounds();
+ const int x = contents_bounds.x();
+ const int y = contents_bounds.y();
+ const int w = contents_bounds.width();
+ const int h = contents_bounds.height();
+
+ more_content_left_->SetBoundsRect(
+ gfx::Rect(x, y, more_content_left_thickness_, h));
+ more_content_top_->SetBoundsRect(
+ gfx::Rect(x, y, w, more_content_top_thickness_));
+ more_content_right_->SetBoundsRect(
+ gfx::Rect(contents_bounds.right() - more_content_right_thickness_, y,
+ more_content_right_thickness_, h));
+ more_content_bottom_->SetBoundsRect(
+ gfx::Rect(x, contents_bounds.bottom() - more_content_bottom_thickness_, w,
+ more_content_bottom_thickness_));
}
void ScrollView::UpdateOverflowIndicatorVisibility(
@@ -1137,7 +1202,7 @@ void ScrollView::UpdateOverflowIndicatorVisibility(
draw_overflow_indicator_);
SetControlVisibility(
more_content_bottom_.get(),
- !draw_border_ && vert_sb_->GetVisible() && !horiz_sb_->GetVisible() &&
+ !draw_border_ && IsVerticalScrollEnabled() && !horiz_sb_->GetVisible() &&
offset.y() < vert_sb_->GetMaxPosition() && draw_overflow_indicator_);
SetControlVisibility(more_content_left_.get(),
diff --git a/chromium/ui/views/controls/scroll_view.h b/chromium/ui/views/controls/scroll_view.h
index ec20b217e4a..c7227c266b7 100644
--- a/chromium/ui/views/controls/scroll_view.h
+++ b/chromium/ui/views/controls/scroll_view.h
@@ -27,7 +27,7 @@ namespace test {
class ScrollViewTestApi;
}
-class Separator;
+enum class OverflowIndicatorAlignment { kLeft, kTop, kRight, kBottom };
/////////////////////////////////////////////////////////////////////////////
//
@@ -63,6 +63,12 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
kEnabled
};
+ class Observer {
+ public:
+ // Called when |contents_| scrolled.
+ virtual void OnContentsScrolled() {}
+ };
+
ScrollView();
// Additional constructor for overriding scrolling as defined by
@@ -140,6 +146,11 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
bool GetDrawOverflowIndicator() const { return draw_overflow_indicator_; }
void SetDrawOverflowIndicator(bool draw_overflow_indicator);
+ View* SetCustomOverflowIndicator(OverflowIndicatorAlignment side,
+ std::unique_ptr<View> indicator,
+ int thickness,
+ bool fills_opaquely);
+
// Turns this scroll view into a bounded scroll view, with a fixed height.
// By default, a ScrollView will stretch to fill its outer container.
void ClipHeightTo(int min_height, int max_height);
@@ -166,6 +177,9 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
bool GetHasFocusIndicator() const { return draw_focus_indicator_; }
void SetHasFocusIndicator(bool has_focus_indicator);
+ void AddScrollViewObserver(Observer* observer);
+ void RemoveScrollViewObserver(Observer* observer);
+
// View overrides:
gfx::Size CalculatePreferredSize() const override;
int GetHeightForWidth(int width) const override;
@@ -244,6 +258,9 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
// Callback entrypoint when hosted Layers are scrolled by the Compositor.
void OnLayerScrolled(const gfx::ScrollOffset&, const cc::ElementId&);
+ // Updates accessory elements when |contents_| is scrolled.
+ void OnScrolled(const gfx::ScrollOffset& offset);
+
// Horizontally scrolls the header (if any) to match the contents.
void ScrollHeader();
@@ -279,12 +296,16 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
std::unique_ptr<View> corner_view_;
// Hidden content indicators
- std::unique_ptr<Separator> more_content_left_ = std::make_unique<Separator>();
- std::unique_ptr<Separator> more_content_top_ = std::make_unique<Separator>();
- std::unique_ptr<Separator> more_content_right_ =
- std::make_unique<Separator>();
- std::unique_ptr<Separator> more_content_bottom_ =
- std::make_unique<Separator>();
+ // TODO(https://crbug.com/1166949): Use preferred width/height instead of
+ // thickness members.
+ std::unique_ptr<View> more_content_left_ = std::make_unique<Separator>();
+ int more_content_left_thickness_ = Separator::kThickness;
+ std::unique_ptr<View> more_content_top_ = std::make_unique<Separator>();
+ int more_content_top_thickness_ = Separator::kThickness;
+ std::unique_ptr<View> more_content_right_ = std::make_unique<Separator>();
+ int more_content_right_thickness_ = Separator::kThickness;
+ std::unique_ptr<View> more_content_bottom_ = std::make_unique<Separator>();
+ int more_content_bottom_thickness_ = Separator::kThickness;
// The min and max height for the bounded scroll view. These are negative
// values if the view is not bounded.
@@ -322,6 +343,8 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
// The focus ring for this ScrollView.
FocusRing* focus_ring_ = nullptr;
+ base::ObserverList<Observer>::Unchecked observers_;
+
DISALLOW_COPY_AND_ASSIGN(ScrollView);
};
diff --git a/chromium/ui/views/controls/scroll_view_unittest.cc b/chromium/ui/views/controls/scroll_view_unittest.cc
index 3eb0d5202c9..2e6aa82878c 100644
--- a/chromium/ui/views/controls/scroll_view_unittest.cc
+++ b/chromium/ui/views/controls/scroll_view_unittest.cc
@@ -25,7 +25,6 @@
#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
#include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
#include "ui/views/controls/scrollbar/scroll_bar_views.h"
-#include "ui/views/controls/separator.h"
#include "ui/views/test/test_views.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/test/widget_test.h"
@@ -77,16 +76,10 @@ class ScrollViewTestApi {
View* corner_view() { return scroll_view_->corner_view_.get(); }
View* contents_viewport() { return scroll_view_->contents_viewport_; }
- Separator* more_content_left() {
- return scroll_view_->more_content_left_.get();
- }
- Separator* more_content_top() {
- return scroll_view_->more_content_top_.get();
- }
- Separator* more_content_right() {
- return scroll_view_->more_content_right_.get();
- }
- Separator* more_content_bottom() {
+ View* more_content_left() { return scroll_view_->more_content_left_.get(); }
+ View* more_content_top() { return scroll_view_->more_content_top_.get(); }
+ View* more_content_right() { return scroll_view_->more_content_right_.get(); }
+ View* more_content_bottom() {
return scroll_view_->more_content_bottom_.get();
}
@@ -1740,6 +1733,73 @@ TEST_F(ScrollViewTest, VerticalWithHeaderOverflowIndicators) {
EXPECT_FALSE(test_api.more_content_right()->GetVisible());
}
+TEST_F(ScrollViewTest, CustomOverflowIndicator) {
+ const int kWidth = 100;
+ const int kHeight = 100;
+
+ ScrollViewTestApi test_api(scroll_view_.get());
+
+ // Set up with both horizontal and vertical scrolling.
+ auto contents = std::make_unique<FixedView>();
+ contents->SetPreferredSize(gfx::Size(kWidth * 5, kHeight * 5));
+ scroll_view_->SetContents(std::move(contents));
+
+ // Hide both scrollbars so they don't interfere with indicator visibility.
+ scroll_view_->SetHorizontalScrollBarMode(
+ views::ScrollView::ScrollBarMode::kHiddenButEnabled);
+ scroll_view_->SetVerticalScrollBarMode(
+ views::ScrollView::ScrollBarMode::kHiddenButEnabled);
+
+ // Make sure the size is set so the ScrollView is smaller than its contents
+ // in both directions.
+ scroll_view_->SetSize(gfx::Size(kWidth, kHeight));
+
+ // The horizontal and vertical scroll bars should not be visible.
+ CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, false);
+ CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, false);
+
+ // Make sure the initial origin is 0,0
+ EXPECT_EQ(gfx::ScrollOffset(0, 0), test_api.CurrentOffset());
+
+ // Now scroll the view to someplace in the middle of the scrollable region.
+ int offset_x = kWidth * 2;
+ scroll_view_->ScrollToPosition(test_api.GetScrollBar(HORIZONTAL), offset_x);
+ int offset_y = kHeight * 2;
+ scroll_view_->ScrollToPosition(test_api.GetScrollBar(VERTICAL), offset_y);
+ EXPECT_EQ(gfx::ScrollOffset(offset_x, offset_y), test_api.CurrentOffset());
+
+ // All overflow indicators should be visible.
+ ASSERT_TRUE(test_api.more_content_right()->GetVisible());
+ ASSERT_TRUE(test_api.more_content_bottom()->GetVisible());
+ ASSERT_TRUE(test_api.more_content_left()->GetVisible());
+ ASSERT_TRUE(test_api.more_content_top()->GetVisible());
+
+ // This should be similar to the default separator.
+ View* left_indicator = scroll_view_->SetCustomOverflowIndicator(
+ OverflowIndicatorAlignment::kLeft, std::make_unique<View>(), 1, true);
+ EXPECT_EQ(gfx::Rect(0, 0, 1, 100), left_indicator->bounds());
+ if (left_indicator->layer())
+ EXPECT_TRUE(left_indicator->layer()->fills_bounds_opaquely());
+
+ // A larger, but still reasonable, indicator that is not opaque.
+ View* top_indicator = scroll_view_->SetCustomOverflowIndicator(
+ OverflowIndicatorAlignment::kTop, std::make_unique<View>(), 20, false);
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 20), top_indicator->bounds());
+ if (top_indicator->layer())
+ EXPECT_FALSE(top_indicator->layer()->fills_bounds_opaquely());
+
+ // Negative thickness doesn't make sense. It should be treated like zero.
+ View* right_indicator = scroll_view_->SetCustomOverflowIndicator(
+ OverflowIndicatorAlignment::kRight, std::make_unique<View>(), -1, true);
+ EXPECT_EQ(gfx::Rect(100, 0, 0, 100), right_indicator->bounds());
+
+ // Thicker than the scrollview is strange, but works as you'd expect.
+ View* bottom_indicator = scroll_view_->SetCustomOverflowIndicator(
+ OverflowIndicatorAlignment::kBottom, std::make_unique<View>(), 1000,
+ true);
+ EXPECT_EQ(gfx::Rect(0, -900, 100, 1000), bottom_indicator->bounds());
+}
+
// Ensure ScrollView::Layout succeeds if a disabled scrollbar's overlap style
// does not match the other scrollbar.
TEST_F(ScrollViewTest, IgnoreOverlapWithDisabledHorizontalScroll) {
diff --git a/chromium/ui/views/controls/separator.cc b/chromium/ui/views/controls/separator.cc
index dc2e4e43918..d3d985bb758 100644
--- a/chromium/ui/views/controls/separator.cc
+++ b/chromium/ui/views/controls/separator.cc
@@ -15,6 +15,8 @@
namespace views {
+constexpr int Separator::kThickness;
+
Separator::Separator() = default;
Separator::~Separator() = default;
@@ -95,7 +97,7 @@ void Separator::OnPaint(gfx::Canvas* canvas) {
}
BEGIN_METADATA(Separator, View)
-ADD_PROPERTY_METADATA(SkColor, Color)
+ADD_PROPERTY_METADATA(SkColor, Color, metadata::SkColorConverter)
ADD_PROPERTY_METADATA(int, PreferredHeight)
END_METADATA
diff --git a/chromium/ui/views/controls/styled_label_unittest.cc b/chromium/ui/views/controls/styled_label_unittest.cc
index e36544f90bd..d96abc32f8e 100644
--- a/chromium/ui/views/controls/styled_label_unittest.cc
+++ b/chromium/ui/views/controls/styled_label_unittest.cc
@@ -346,9 +346,11 @@ TEST_F(StyledLabelTest, StyledRangeTextStyleBold) {
InitStyledLabel(bold_text + text);
// Pretend disabled text becomes bold for testing.
- bold_provider.SetFont(
- style::CONTEXT_LABEL, style::STYLE_DISABLED,
- styled()->GetFontList().DeriveWithWeight(gfx::Font::Weight::BOLD));
+ auto details =
+ bold_provider.GetFontDetails(style::CONTEXT_LABEL, style::STYLE_DISABLED);
+ details.weight = gfx::Font::Weight::BOLD;
+ bold_provider.SetFontDetails(style::CONTEXT_LABEL, style::STYLE_DISABLED,
+ details);
StyledLabel::RangeStyleInfo style_info;
style_info.text_style = style::STYLE_DISABLED;
diff --git a/chromium/ui/views/controls/tabbed_pane/DIR_METADATA b/chromium/ui/views/controls/tabbed_pane/DIR_METADATA
new file mode 100644
index 00000000000..d1a66307bfa
--- /dev/null
+++ b/chromium/ui/views/controls/tabbed_pane/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals>Views"
+}
diff --git a/chromium/ui/views/controls/tabbed_pane/OWNERS b/chromium/ui/views/controls/tabbed_pane/OWNERS
index dba3e5032df..80d20216a72 100644
--- a/chromium/ui/views/controls/tabbed_pane/OWNERS
+++ b/chromium/ui/views/controls/tabbed_pane/OWNERS
@@ -1,4 +1,2 @@
ellyjones@chromium.org
msw@chromium.org
-
-# COMPONENT: Internals>Views
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 4e43dde3360..9fbfeab4516 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -5,6 +5,7 @@
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include <algorithm>
+#include <string>
#include <utility>
#include "base/check_op.h"
@@ -229,8 +230,8 @@ void Tab::OnStateChanged() {
}
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- title_->SetFontList(
- rb.GetFontListWithDelta(font_size_delta, gfx::Font::NORMAL, font_weight));
+ title_->SetFontList(rb.GetFontListForDetails(ui::ResourceBundle::FontDetails(
+ std::string(), font_size_delta, font_weight)));
}
void Tab::OnPaint(gfx::Canvas* canvas) {
diff --git a/chromium/ui/views/controls/table/table_header.cc b/chromium/ui/views/controls/table/table_header.cc
index 0933088aa47..113ed48a5e2 100644
--- a/chromium/ui/views/controls/table/table_header.cc
+++ b/chromium/ui/views/controls/table/table_header.cc
@@ -20,6 +20,7 @@
#include "ui/views/background.h"
#include "ui/views/controls/table/table_utils.h"
#include "ui/views/controls/table/table_view.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/native_cursor.h"
namespace views {
@@ -46,8 +47,6 @@ constexpr int kSortIndicatorSize = 8;
} // namespace
// static
-const char TableHeader::kViewClassName[] = "TableHeader";
-// static
const int TableHeader::kHorizontalPadding = 7;
// static
const int TableHeader::kSortIndicatorWidth =
@@ -164,10 +163,6 @@ void TableHeader::OnPaint(gfx::Canvas* canvas) {
}
}
-const char* TableHeader::GetClassName() const {
- return kViewClassName;
-}
-
gfx::Size TableHeader::CalculatePreferredSize() const {
return gfx::Size(1, kVerticalPadding * 2 + font_list_.GetHeight());
}
@@ -335,5 +330,7 @@ int TableHeader::GetResizeColumn(int x) const {
return (x >= max_x - kResizePadding && x <= max_x + kResizePadding) ? index
: -1;
}
+BEGIN_METADATA(TableHeader, View)
+END_METADATA
} // namespace views
diff --git a/chromium/ui/views/controls/table/table_header.h b/chromium/ui/views/controls/table/table_header.h
index 66516b1eee2..a79cd242a1e 100644
--- a/chromium/ui/views/controls/table/table_header.h
+++ b/chromium/ui/views/controls/table/table_header.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "ui/gfx/font_list.h"
#include "ui/views/controls/table/table_view.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/view.h"
#include "ui/views/views_export.h"
@@ -18,8 +19,7 @@ namespace views {
// Views used to render the header for the table.
class VIEWS_EXPORT TableHeader : public views::View {
public:
- // Internal class name.
- static const char kViewClassName[];
+ METADATA_HEADER(TableHeader);
// Amount the text is padded on the left/right side.
static const int kHorizontalPadding;
@@ -28,6 +28,8 @@ class VIEWS_EXPORT TableHeader : public views::View {
static const int kSortIndicatorWidth;
explicit TableHeader(TableView* table);
+ TableHeader(const TableHeader&) = delete;
+ TableHeader& operator=(const TableHeader&) = delete;
~TableHeader() override;
const gfx::FontList& font_list() const { return font_list_; }
@@ -37,7 +39,6 @@ class VIEWS_EXPORT TableHeader : public views::View {
// views::View overrides.
void OnPaint(gfx::Canvas* canvas) override;
- const char* GetClassName() const override;
gfx::Size CalculatePreferredSize() const override;
bool GetNeedsNotificationWhenVisibleBoundsChange() const override;
void OnVisibleBoundsChanged() override;
@@ -88,8 +89,6 @@ class VIEWS_EXPORT TableHeader : public views::View {
// If non-null a resize is in progress.
std::unique_ptr<ColumnResizeDetails> resize_details_;
-
- DISALLOW_COPY_AND_ASSIGN(TableHeader);
};
} // namespace views
diff --git a/chromium/ui/views/controls/table/table_view.cc b/chromium/ui/views/controls/table/table_view.cc
index 1b254a0b416..b9bac9d0965 100644
--- a/chromium/ui/views/controls/table/table_view.cc
+++ b/chromium/ui/views/controls/table/table_view.cc
@@ -251,8 +251,25 @@ void TableView::Select(int model_row) {
SelectByViewIndex(model_row == -1 ? -1 : ModelToView(model_row));
}
+void TableView::SetSelectionAll(bool select) {
+ if (!GetRowCount())
+ return;
+
+ ui::ListSelectionModel selection_model;
+
+ if (select)
+ selection_model.AddIndexRangeToSelection(0, GetRowCount() - 1);
+
+ selection_model.set_anchor(selection_model_.anchor());
+ selection_model.set_active(selection_model_.active());
+
+ SetSelectionModel(std::move(selection_model));
+}
+
int TableView::GetFirstSelectedRow() const {
- return selection_model_.empty() ? -1 : selection_model_.selected_indices()[0];
+ return selection_model_.empty()
+ ? -1
+ : *selection_model_.selected_indices().begin();
}
void TableView::SetColumnVisibility(int id, bool is_visible) {
@@ -470,11 +487,7 @@ bool TableView::OnKeyPressed(const ui::KeyEvent& event) {
case ui::VKEY_A:
// control-a selects all.
if (IsCmdOrCtrl(event) && !single_selection_ && GetRowCount()) {
- ui::ListSelectionModel selection_model;
- selection_model.SetSelectedIndex(selection_model_.active());
- for (int i = 0; i < GetRowCount(); ++i)
- selection_model.AddIndexToSelection(i);
- SetSelectionModel(std::move(selection_model));
+ SetSelectionAll(/*select=*/true);
return true;
}
break;
@@ -747,14 +760,18 @@ void TableView::OnItemsRemoved(int start, int length) {
for (int i = 0; i < length; ++i)
selection_model_.DecrementFrom(start);
- // Remove the virtual views that are no longer needed.
- auto& virtual_children = GetViewAccessibility().virtual_children();
- for (int i = start; i < start + length; i++)
- virtual_children[virtual_children.size() - 1]->RemoveFromParentView();
-
+ // Update the `view_to_model_` and `model_to_view_` mappings prior to updating
+ // TableView's virtual children below. We do this because at this point the
+ // table model has changed but the model-view mappings have not yet been
+ // updated to reflect this. `RemoveFromParentView()` below may trigger calls
+ // back into TableView and this would happen before the model-view mappings
+ // have been updated. This can result in memory overflow errors.
+ // See (https://crbug.com/1173373).
SortItemsAndUpdateMapping(/*schedule_paint=*/true);
- PreferredSizeChanged();
- NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, true);
+ if (GetIsSorted()) {
+ DCHECK_EQ(GetRowCount(), int{view_to_model_.size()});
+ DCHECK_EQ(GetRowCount(), int{model_to_view_.size()});
+ }
// If the selection was empty and is no longer empty select the same visual
// index.
@@ -768,6 +785,15 @@ void TableView::OnItemsRemoved(int start, int length) {
if (!selection_model_.empty() && selection_model_.anchor() == -1)
selection_model_.set_anchor(GetFirstSelectedRow());
NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true);
+
+ // Remove the virtual views that are no longer needed.
+ auto& virtual_children = GetViewAccessibility().virtual_children();
+ for (int i = start; i < start + length; i++)
+ virtual_children[virtual_children.size() - 1]->RemoveFromParentView();
+
+ UpdateVirtualAccessibilityChildrenBounds();
+ PreferredSizeChanged();
+ NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, true);
if (observer_)
observer_->OnSelectionChanged();
}
@@ -1092,8 +1118,10 @@ void TableView::SchedulePaintForSelection() {
if (selection_model_.size() == 1) {
const int first_model_row = GetFirstSelectedRow();
SchedulePaintInRect(GetRowBounds(ModelToView(first_model_row)));
- if (first_model_row != selection_model_.active())
- SchedulePaintInRect(GetRowBounds(ModelToView(selection_model_.active())));
+
+ const int active_row = selection_model_.active();
+ if (active_row >= 0 && first_model_row != active_row)
+ SchedulePaintInRect(GetRowBounds(ModelToView(active_row)));
} else if (selection_model_.size() > 1) {
SchedulePaint();
}
diff --git a/chromium/ui/views/controls/table/table_view.h b/chromium/ui/views/controls/table/table_view.h
index e20f57b2b34..962cc76169f 100644
--- a/chromium/ui/views/controls/table/table_view.h
+++ b/chromium/ui/views/controls/table/table_view.h
@@ -138,6 +138,9 @@ class VIEWS_EXPORT TableView : public views::View,
// Selects the specified item, making sure it's visible.
void Select(int model_row);
+ // Selects all items.
+ void SetSelectionAll(bool select);
+
// Returns the first selected row in terms of the model.
int GetFirstSelectedRow() const;
@@ -218,6 +221,11 @@ class VIEWS_EXPORT TableView : public views::View,
// table's virtual accessibility children.
void UpdateVirtualAccessibilityChildrenBounds();
+ // 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);
+
// View overrides:
void Layout() override;
gfx::Size CalculatePreferredSize() const override;
@@ -381,11 +389,6 @@ class VIEWS_EXPORT TableView : public views::View,
// |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);
-
// Creates a virtual accessibility view that is used to expose information
// about the row at |view_index| to assistive software.
std::unique_ptr<AXVirtualView> CreateRowAccessibilityView(int view_index);
diff --git a/chromium/ui/views/controls/table/table_view_unittest.cc b/chromium/ui/views/controls/table/table_view_unittest.cc
index dfa2affc493..ff2060e1b41 100644
--- a/chromium/ui/views/controls/table/table_view_unittest.cc
+++ b/chromium/ui/views/controls/table/table_view_unittest.cc
@@ -172,6 +172,9 @@ class TestTableModel2 : public ui::TableModel {
// Reorders rows in the model.
void MoveRows(int row_from, int length, int row_to);
+ // Allows overriding the tooltip for testing.
+ void SetTooltip(const base::string16& tooltip);
+
// ui::TableModel:
int RowCount() override;
base::string16 GetText(int row, int column_id) override;
@@ -182,6 +185,8 @@ class TestTableModel2 : public ui::TableModel {
private:
ui::TableModelObserver* observer_ = nullptr;
+ base::Optional<base::string16> tooltip_;
+
// The data.
std::vector<std::vector<int>> rows_;
@@ -264,6 +269,10 @@ void TestTableModel2::MoveRows(int row_from, int length, int row_to) {
observer_->OnItemsMoved(row_from, length, row_to);
}
+void TestTableModel2::SetTooltip(const base::string16& tooltip) {
+ tooltip_ = tooltip;
+}
+
int TestTableModel2::RowCount() {
return static_cast<int>(rows_.size());
}
@@ -273,7 +282,8 @@ base::string16 TestTableModel2::GetText(int row, int column_id) {
}
base::string16 TestTableModel2::GetTooltip(int row) {
- return base::ASCIIToUTF16("Tooltip") + base::NumberToString16(row);
+ return tooltip_ ? *tooltip_
+ : base::ASCIIToUTF16("Tooltip") + base::NumberToString16(row);
}
void TestTableModel2::SetObserver(ui::TableModelObserver* observer) {
@@ -471,10 +481,14 @@ class TableViewTest : public ViewsTestBase,
" selection=";
const ui::ListSelectionModel::SelectedIndices& selection(
model.selected_indices());
- for (size_t i = 0; i < selection.size(); ++i) {
- if (i != 0)
+ bool first = true;
+ for (int index : selection) {
+ if (first) {
+ first = false;
+ } else {
result += " ";
- result += base::NumberToString(selection[i]);
+ }
+ result += base::NumberToString(index);
}
return result;
}
@@ -1295,6 +1309,29 @@ TEST_P(TableViewTest, Selection) {
table_->set_observer(nullptr);
}
+TEST_P(TableViewTest, SelectAll) {
+ TableViewObserverImpl observer;
+ table_->set_observer(&observer);
+
+ // Initially no selection.
+ EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
+
+ table_->SetSelectionAll(/*select=*/true);
+ EXPECT_EQ(1, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=-1 anchor=-1 selection=0 1 2 3", SelectionStateAsString());
+
+ table_->Select(2);
+ EXPECT_EQ(1, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=2 anchor=2 selection=2", SelectionStateAsString());
+
+ table_->SetSelectionAll(/*select=*/true);
+ EXPECT_EQ(1, observer.GetChangedCountAndClear());
+ EXPECT_EQ("active=2 anchor=2 selection=0 1 2 3", SelectionStateAsString());
+
+ table_->SetSelectionAll(/*select=*/false);
+ EXPECT_EQ("active=2 anchor=2 selection=", SelectionStateAsString());
+}
+
TEST_P(TableViewTest, RemoveUnselectedRows) {
TableViewObserverImpl observer;
table_->set_observer(&observer);
@@ -1897,6 +1934,34 @@ TEST_P(TableViewTest, FocusAfterRemovingAnchor) {
table_->RequestFocus();
}
+// OnItemsRemoved() should ensure view-model mappings are updated in response to
+// the table model change before these view-model mappings are used.
+// Test for (https://crbug.com/1173373).
+TEST_P(TableViewTest, RemovingSortedRowsDoesNotCauseOverflow) {
+ // Ensure the table has a sort descriptor set so that `view_to_model_` and
+ // `model_to_view_` mappings are established and are in descending order. Do
+ // this so the first view row maps to the last model row.
+ table_->ToggleSortOrder(0);
+ table_->ToggleSortOrder(0);
+ ASSERT_TRUE(table_->GetIsSorted());
+ ASSERT_EQ(1u, table_->sort_descriptors().size());
+ EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
+ EXPECT_FALSE(table_->sort_descriptors()[0].ascending);
+ EXPECT_EQ("3 2 1 0", GetViewToModelAsString(table_));
+ EXPECT_EQ("3 2 1 0", GetModelToViewAsString(table_));
+
+ // Removing rows can result in callbacks to GetTooltipText(). Above mappings
+ // will cause TableView to try to access the text for the first view row and
+ // consequently attempt to access the last element in the model via the
+ // `view_to_model_` mapping. This will result in a crash if the view-model
+ // mappings have not been appropriately updated.
+ model_->SetTooltip(base::ASCIIToUTF16(""));
+ model_->RemoveRow(0);
+ model_->RemoveRow(0);
+ model_->RemoveRow(0);
+ model_->RemoveRow(0);
+}
+
namespace {
class RemoveFocusChangeListenerDelegate : public WidgetDelegate {
diff --git a/chromium/ui/views/controls/textarea/textarea.cc b/chromium/ui/views/controls/textarea/textarea.cc
new file mode 100644
index 00000000000..de01539052c
--- /dev/null
+++ b/chromium/ui/views/controls/textarea/textarea.cc
@@ -0,0 +1,114 @@
+// 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/controls/textarea/textarea.h"
+
+#include "base/logging.h"
+#include "ui/base/ime/text_edit_commands.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
+
+namespace views {
+
+Textarea::Textarea() {
+ GetRenderText()->SetMultiline(true);
+ GetRenderText()->SetVerticalAlignment(gfx::ALIGN_TOP);
+ GetRenderText()->SetWordWrapBehavior(gfx::WRAP_LONG_WORDS);
+}
+
+size_t Textarea::GetNumLines() {
+ return GetRenderText()->GetNumLines();
+}
+
+bool Textarea::OnMouseWheel(const ui::MouseWheelEvent& event) {
+ GetRenderText()->SetDisplayOffset(GetRenderText()->GetUpdatedDisplayOffset() +
+ gfx::Vector2d(0, event.y_offset()));
+ UpdateCursorViewPosition();
+ SchedulePaint();
+ return true;
+}
+
+Textfield::EditCommandResult Textarea::DoExecuteTextEditCommand(
+ ui::TextEditCommand command) {
+ bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
+ gfx::VisualCursorDirection begin = rtl ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT;
+ gfx::VisualCursorDirection end = rtl ? gfx::CURSOR_LEFT : gfx::CURSOR_RIGHT;
+
+ switch (command) {
+ case ui::TextEditCommand::MOVE_UP:
+ textfield_model()->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_UP,
+ gfx::SELECTION_NONE);
+ break;
+ case ui::TextEditCommand::MOVE_DOWN:
+ textfield_model()->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_DOWN,
+ gfx::SELECTION_NONE);
+ break;
+ case ui::TextEditCommand::MOVE_UP_AND_MODIFY_SELECTION:
+ textfield_model()->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_UP,
+ gfx::SELECTION_RETAIN);
+ break;
+ case ui::TextEditCommand::MOVE_DOWN_AND_MODIFY_SELECTION:
+ textfield_model()->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_DOWN,
+ gfx::SELECTION_RETAIN);
+ break;
+ case ui::TextEditCommand::
+ MOVE_TO_BEGINNING_OF_DOCUMENT_AND_MODIFY_SELECTION:
+ case ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION:
+ textfield_model()->MoveCursor(gfx::FIELD_BREAK, begin,
+ kPageSelectionBehavior);
+ break;
+ case ui::TextEditCommand::
+ MOVE_TO_BEGINNING_OF_PARAGRAPH_AND_MODIFY_SELECTION:
+ textfield_model()->MoveCursor(gfx::FIELD_BREAK, begin,
+ kMoveParagraphSelectionBehavior);
+ break;
+ case ui::TextEditCommand::MOVE_TO_END_OF_DOCUMENT_AND_MODIFY_SELECTION:
+ case ui::TextEditCommand::MOVE_PAGE_DOWN_AND_MODIFY_SELECTION:
+ textfield_model()->MoveCursor(gfx::FIELD_BREAK, end,
+ kPageSelectionBehavior);
+ break;
+ case ui::TextEditCommand::MOVE_TO_END_OF_PARAGRAPH_AND_MODIFY_SELECTION:
+ textfield_model()->MoveCursor(gfx::FIELD_BREAK, end,
+ kMoveParagraphSelectionBehavior);
+ break;
+ default:
+ return Textfield::DoExecuteTextEditCommand(command);
+ }
+
+ // TODO(jongkwon.lee): Return |cursor_changed| with actual value. It's okay
+ // for now because |cursor_changed| is detected afterward in
+ // |Textfield::ExecuteTextEditCommand|.
+ return {false, false};
+}
+
+bool Textarea::PreHandleKeyPressed(const ui::KeyEvent& event) {
+ if (event.key_code() == ui::VKEY_RETURN) {
+ DoInsertChar('\n');
+ return true;
+ }
+ return false;
+}
+
+ui::TextEditCommand Textarea::GetCommandForKeyEvent(const ui::KeyEvent& event) {
+ if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode())
+ return Textfield::GetCommandForKeyEvent(event);
+
+ const bool shift = event.IsShiftDown();
+ switch (event.key_code()) {
+ case ui::VKEY_UP:
+ return shift ? ui::TextEditCommand::MOVE_UP_AND_MODIFY_SELECTION
+ : ui::TextEditCommand::MOVE_UP;
+ case ui::VKEY_DOWN:
+ return shift ? ui::TextEditCommand::MOVE_DOWN_AND_MODIFY_SELECTION
+ : ui::TextEditCommand::MOVE_DOWN;
+ default:
+ return Textfield::GetCommandForKeyEvent(event);
+ }
+}
+
+BEGIN_METADATA(Textarea, Textfield)
+END_METADATA
+
+} // namespace views
diff --git a/chromium/ui/views/controls/textarea/textarea.h b/chromium/ui/views/controls/textarea/textarea.h
new file mode 100644
index 00000000000..9e0699c12fb
--- /dev/null
+++ b/chromium/ui/views/controls/textarea/textarea.h
@@ -0,0 +1,36 @@
+// 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_CONTROLS_TEXTAREA_TEXTAREA_H_
+#define UI_VIEWS_CONTROLS_TEXTAREA_TEXTAREA_H_
+
+#include "ui/views/controls/textfield/textfield.h"
+
+namespace views {
+
+// A multiline textfield implementation.
+class VIEWS_EXPORT Textarea : public Textfield {
+ public:
+ METADATA_HEADER(Textarea);
+
+ Textarea();
+ ~Textarea() override = default;
+
+ // Returns the number of lines of the text.
+ size_t GetNumLines();
+
+ // Textfield:
+ bool OnMouseWheel(const ui::MouseWheelEvent& event) override;
+
+ protected:
+ // Textfield:
+ Textfield::EditCommandResult DoExecuteTextEditCommand(
+ ui::TextEditCommand command) override;
+ bool PreHandleKeyPressed(const ui::KeyEvent& event) override;
+ ui::TextEditCommand GetCommandForKeyEvent(const ui::KeyEvent& event) override;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_TEXTAREA_TEXTAREA_H_
diff --git a/chromium/ui/views/controls/textarea/textarea_unittest.cc b/chromium/ui/views/controls/textarea/textarea_unittest.cc
new file mode 100644
index 00000000000..a75ccf7c333
--- /dev/null
+++ b/chromium/ui/views/controls/textarea/textarea_unittest.cc
@@ -0,0 +1,299 @@
+// 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/controls/textarea/textarea.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "ui/events/event.h"
+#include "ui/gfx/render_text.h"
+#include "ui/strings/grit/ui_strings.h"
+#include "ui/views/controls/textfield/textfield_test_api.h"
+#include "ui/views/controls/textfield/textfield_unittest.h"
+#include "ui/views/style/platform_style.h"
+#include "ui/views/widget/widget.h"
+
+namespace {
+
+const base::char16 kHebrewLetterSamekh = 0x05E1;
+
+} // namespace
+
+namespace views {
+namespace {
+
+class TextareaTest : public test::TextfieldTest {
+ public:
+ TextareaTest() = default;
+ ~TextareaTest() override = default;
+
+ // TextfieldTest:
+ void SetUp() override {
+ TextfieldTest::SetUp();
+
+ ASSERT_FALSE(textarea_);
+ textarea_ = PrepareTextfields(0, std::make_unique<Textarea>(),
+ gfx::Rect(100, 100, 800, 100));
+ }
+
+ protected:
+ void RunMoveUpDownTest(int start_index,
+ ui::KeyboardCode key_code,
+ std::vector<int> expected) {
+ DCHECK(key_code == ui::VKEY_UP || key_code == ui::VKEY_DOWN);
+ textarea_->SetSelectedRange(gfx::Range(start_index));
+ for (size_t i = 0; i < expected.size(); ++i) {
+ SCOPED_TRACE(testing::Message()
+ << (key_code == ui::VKEY_UP ? "MOVE UP " : "MOVE DOWN ")
+ << i + 1 << " times from Range " << start_index);
+ SendKeyEvent(key_code);
+ EXPECT_EQ(gfx::Range(expected[i]), textarea_->GetSelectedRange());
+ }
+ }
+
+ size_t GetCursorLine() const {
+ return test_api_->GetRenderText()->GetLineContainingCaret(
+ textarea_->GetSelectionModel());
+ }
+
+ // TextfieldTest:
+ void SendHomeEvent(bool shift) override {
+ SendKeyEvent(ui::VKEY_HOME, shift, TestingNativeMac());
+ }
+
+ // TextfieldTest:
+ void SendEndEvent(bool shift) override {
+ SendKeyEvent(ui::VKEY_END, shift, TestingNativeMac());
+ }
+
+ Textarea* textarea_ = nullptr;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextareaTest);
+};
+
+} // namespace
+
+// Disabled when using XKB for crbug.com/1171828.
+#if BUILDFLAG(USE_XKBCOMMON)
+#define MAYBE_InsertNewlineTest DISABLED_InsertNewlineTest
+#else
+#define MAYBE_InsertNewlineTest InsertNewlineTest
+#endif // BUILDFLAG(USE_XKBCOMMON)
+TEST_F(TextareaTest, MAYBE_InsertNewlineTest) {
+ for (size_t i = 0; i < 5; i++) {
+ SendKeyEvent(static_cast<ui::KeyboardCode>(ui::VKEY_A + i));
+ SendKeyEvent(ui::VKEY_RETURN);
+ }
+ EXPECT_STR_EQ("a\nb\nc\nd\ne\n", textarea_->GetText());
+}
+
+TEST_F(TextareaTest, PasteNewlineTest) {
+ const std::string& kText = "abc\n \n";
+ textarea_->SetText(base::ASCIIToUTF16(kText));
+ textarea_->SelectAll(false);
+ textarea_->ExecuteCommand(Textfield::kCopy, 0);
+ textarea_->SetText(base::string16());
+ textarea_->ExecuteCommand(Textfield::kPaste, 0);
+ EXPECT_STR_EQ(kText, textarea_->GetText());
+}
+
+// Re-enable when crbug.com/1163587 is fixed.
+TEST_F(TextareaTest, DISABLED_CursorMovement) {
+ textarea_->SetText(base::ASCIIToUTF16("one\n\ntwo three"));
+
+ // Move Up/Down at the front of the line.
+ RunMoveUpDownTest(0, ui::VKEY_DOWN, {4, 5, 14});
+ RunMoveUpDownTest(5, ui::VKEY_UP, {4, 0, 0});
+
+ // Move Up/Down at the end of the line.
+ RunMoveUpDownTest(3, ui::VKEY_DOWN, {4, 8, 14});
+ RunMoveUpDownTest(14, ui::VKEY_UP, {4, 3, 0});
+
+ // Move Up/Down at the middle position.
+ RunMoveUpDownTest(2, ui::VKEY_DOWN, {4, 7, 14});
+ RunMoveUpDownTest(7, ui::VKEY_UP, {4, 2, 0});
+
+ // Test Home/End key on each lines.
+ textarea_->SetSelectedRange(gfx::Range(2)); // First line.
+ SendHomeEvent(false);
+ EXPECT_EQ(gfx::Range(0), textarea_->GetSelectedRange());
+ SendEndEvent(false);
+ EXPECT_EQ(gfx::Range(3), textarea_->GetSelectedRange());
+ textarea_->SetSelectedRange(gfx::Range(4)); // 2nd line.
+ SendHomeEvent(false);
+ EXPECT_EQ(gfx::Range(4), textarea_->GetSelectedRange());
+ SendEndEvent(false);
+ EXPECT_EQ(gfx::Range(4), textarea_->GetSelectedRange());
+ textarea_->SetSelectedRange(gfx::Range(7)); // 3rd line.
+ SendHomeEvent(false);
+ EXPECT_EQ(gfx::Range(5), textarea_->GetSelectedRange());
+ SendEndEvent(false);
+ EXPECT_EQ(gfx::Range(14), textarea_->GetSelectedRange());
+}
+
+// Ensure cursor view is always inside display rect.
+TEST_F(TextareaTest, CursorViewBounds) {
+ textarea_->SetBounds(0, 0, 100, 31);
+ for (size_t i = 0; i < 10; ++i) {
+ SCOPED_TRACE(base::StringPrintf("VKEY_RETURN %" PRIuS " times", i + 1));
+ SendKeyEvent(ui::VKEY_RETURN);
+ ASSERT_TRUE(textarea_->GetVisibleBounds().Contains(GetCursorViewRect()));
+ ASSERT_FALSE(GetCursorViewRect().size().IsEmpty());
+ }
+
+ for (size_t i = 0; i < 10; ++i) {
+ SCOPED_TRACE(base::StringPrintf("VKEY_UP %" PRIuS " times", i + 1));
+ SendKeyEvent(ui::VKEY_UP);
+ ASSERT_TRUE(textarea_->GetVisibleBounds().Contains(GetCursorViewRect()));
+ ASSERT_FALSE(GetCursorViewRect().size().IsEmpty());
+ }
+}
+
+TEST_F(TextareaTest, LineSelection) {
+ textarea_->SetText(base::ASCIIToUTF16("12\n34567 89"));
+
+ // Place the cursor after "5".
+ textarea_->SetEditableSelectionRange(gfx::Range(6));
+
+ // Select line towards right.
+ SendEndEvent(true);
+ EXPECT_STR_EQ("67 89", textarea_->GetSelectedText());
+
+ // Select line towards left. On Mac, the existing selection should be extended
+ // to cover the whole line.
+ SendHomeEvent(true);
+
+ if (Textarea::kLineSelectionBehavior == gfx::SELECTION_EXTEND)
+ EXPECT_STR_EQ("34567 89", textarea_->GetSelectedText());
+ else
+ EXPECT_STR_EQ("345", textarea_->GetSelectedText());
+
+ EXPECT_TRUE(textarea_->GetSelectedRange().is_reversed());
+
+ // Select line towards right.
+ SendEndEvent(true);
+
+ if (Textarea::kLineSelectionBehavior == gfx::SELECTION_EXTEND)
+ EXPECT_STR_EQ("34567 89", textarea_->GetSelectedText());
+ else
+ EXPECT_STR_EQ("67 89", textarea_->GetSelectedText());
+
+ EXPECT_FALSE(textarea_->GetSelectedRange().is_reversed());
+}
+
+// Disabled on Mac for crbug.com/1171826.
+#if defined(OS_MAC)
+#define MAYBE_MoveUpDownAndModifySelection DISABLED_MoveUpDownAndModifySelection
+#else
+#define MAYBE_MoveUpDownAndModifySelection MoveUpDownAndModifySelection
+#endif // defined(OS_MAC)
+TEST_F(TextareaTest, MAYBE_MoveUpDownAndModifySelection) {
+ textarea_->SetText(base::ASCIIToUTF16("12\n34567 89"));
+ textarea_->SetEditableSelectionRange(gfx::Range(6));
+ EXPECT_EQ(1U, GetCursorLine());
+
+ // Up key should place the cursor after "2" not after newline to place the
+ // cursor on the first line.
+ SendKeyEvent(ui::VKEY_UP);
+ EXPECT_EQ(0U, GetCursorLine());
+ EXPECT_EQ(gfx::Range(2), textarea_->GetSelectedRange());
+
+ // Down key after Up key should select the same range as the previous one.
+ SendKeyEvent(ui::VKEY_DOWN);
+ EXPECT_EQ(1U, GetCursorLine());
+ EXPECT_EQ(gfx::Range(6), textarea_->GetSelectedRange());
+
+ // Shift+Up should select the text to the upper line position including
+ // the newline character.
+ SendKeyEvent(ui::VKEY_UP, true /* shift */, false /* command */);
+ EXPECT_EQ(gfx::Range(6, 2), textarea_->GetSelectedRange());
+
+ // Shift+Down should collapse the selection.
+ SendKeyEvent(ui::VKEY_DOWN, true /* shift */, false /* command */);
+ EXPECT_EQ(gfx::Range(6), textarea_->GetSelectedRange());
+
+ // Shift+Down again should select the text to the end of the last line.
+ SendKeyEvent(ui::VKEY_DOWN, true /* shift */, false /* command */);
+ EXPECT_EQ(gfx::Range(6, 11), textarea_->GetSelectedRange());
+}
+
+TEST_F(TextareaTest, MovePageUpDownAndModifySelection) {
+ textarea_->SetText(base::ASCIIToUTF16("12\n34567 89"));
+ textarea_->SetEditableSelectionRange(gfx::Range(6));
+
+ EXPECT_TRUE(
+ textarea_->IsTextEditCommandEnabled(ui::TextEditCommand::MOVE_PAGE_UP));
+ EXPECT_TRUE(
+ textarea_->IsTextEditCommandEnabled(ui::TextEditCommand::MOVE_PAGE_DOWN));
+ EXPECT_TRUE(textarea_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION));
+ EXPECT_TRUE(textarea_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::MOVE_PAGE_DOWN_AND_MODIFY_SELECTION));
+
+ test_api_->ExecuteTextEditCommand(ui::TextEditCommand::MOVE_PAGE_UP);
+ EXPECT_EQ(gfx::Range(0), textarea_->GetSelectedRange());
+
+ test_api_->ExecuteTextEditCommand(ui::TextEditCommand::MOVE_PAGE_DOWN);
+ EXPECT_EQ(gfx::Range(11), textarea_->GetSelectedRange());
+
+ textarea_->SetEditableSelectionRange(gfx::Range(6));
+ test_api_->ExecuteTextEditCommand(
+ ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION);
+ EXPECT_EQ(gfx::Range(6, 0), textarea_->GetSelectedRange());
+
+ test_api_->ExecuteTextEditCommand(
+ ui::TextEditCommand::MOVE_PAGE_DOWN_AND_MODIFY_SELECTION);
+
+ if (Textarea::kLineSelectionBehavior == gfx::SELECTION_EXTEND)
+ EXPECT_EQ(gfx::Range(0, 11), textarea_->GetSelectedRange());
+ else
+ EXPECT_EQ(gfx::Range(6, 11), textarea_->GetSelectedRange());
+}
+
+// Ensure the textarea breaks the long word and scrolls on overflow.
+TEST_F(TextareaTest, OverflowTest) {
+ const size_t count = 50U;
+ textarea_->SetBounds(0, 0, 60, 40);
+
+ textarea_->SetText(base::string16(count, 'a'));
+ EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
+
+ textarea_->SetText(base::string16(count, kHebrewLetterSamekh));
+ EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
+}
+
+TEST_F(TextareaTest, OverflowInRTLTest) {
+ const size_t count = 50U;
+ textarea_->SetBounds(0, 0, 60, 40);
+ std::string locale = base::i18n::GetConfiguredLocale();
+ base::i18n::SetICUDefaultLocale("he");
+
+ textarea_->SetText(base::string16(count, 'a'));
+ EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
+
+ textarea_->SetText(base::string16(count, kHebrewLetterSamekh));
+ EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
+
+ // Reset locale.
+ base::i18n::SetICUDefaultLocale(locale);
+}
+
+TEST_F(TextareaTest, OnBlurTest) {
+ const std::string& kText = "abcdef";
+ textarea_->SetText(base::ASCIIToUTF16(kText));
+
+ SendEndEvent(false);
+ EXPECT_EQ(kText.size(), textarea_->GetCursorPosition());
+
+ // A focus loss should not change the cursor position.
+ textarea_->OnBlur();
+ EXPECT_EQ(kText.size(), textarea_->GetCursorPosition());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/textfield/DIR_METADATA b/chromium/ui/views/controls/textfield/DIR_METADATA
new file mode 100644
index 00000000000..d1a66307bfa
--- /dev/null
+++ b/chromium/ui/views/controls/textfield/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals>Views"
+}
diff --git a/chromium/ui/views/controls/textfield/OWNERS b/chromium/ui/views/controls/textfield/OWNERS
index d0cc058381a..b1b0e2d4660 100644
--- a/chromium/ui/views/controls/textfield/OWNERS
+++ b/chromium/ui/views/controls/textfield/OWNERS
@@ -1,5 +1,3 @@
msw@chromium.org
oshima@chromium.org
pkasting@chromium.org
-
-# COMPONENT: Internals>Views
diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc
index 432332a7fad..246ab8040a8 100644
--- a/chromium/ui/views/controls/textfield/textfield.cc
+++ b/chromium/ui/views/controls/textfield/textfield.cc
@@ -21,12 +21,14 @@
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/default_style.h"
#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/base/ime/constants.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/resource/resource_bundle.h"
@@ -68,7 +70,9 @@
#include "base/win/win_util.h"
#endif
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
#include "ui/base/ime/linux/text_edit_command_auralinux.h"
#include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
#endif
@@ -77,7 +81,7 @@
#include "ui/base/x/x11_util.h" // nogncheck
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/aura/window.h"
#include "ui/wm/core/ime_util_chromeos.h"
#endif
@@ -93,10 +97,16 @@
#include "ui/ozone/public/platform_gl_egl_utility.h"
#endif
-namespace views {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ui/base/ime/chromeos/extension_ime_util.h"
+#include "ui/base/ime/chromeos/input_method_manager.h"
+#endif
+namespace views {
namespace {
+using ::ui::mojom::DragOperation;
+
// An enum giving different model properties unique keys for the
// OnPropertyChanged call.
enum TextfieldPropertyKey {
@@ -110,117 +120,6 @@ enum TextfieldPropertyKey {
kTextfieldSelectedRange,
};
-#if defined(OS_APPLE)
-constexpr gfx::SelectionBehavior kLineSelectionBehavior = gfx::SELECTION_EXTEND;
-constexpr gfx::SelectionBehavior kWordSelectionBehavior = gfx::SELECTION_CARET;
-constexpr gfx::SelectionBehavior kMoveParagraphSelectionBehavior =
- gfx::SELECTION_CARET;
-#else
-constexpr gfx::SelectionBehavior kLineSelectionBehavior = gfx::SELECTION_RETAIN;
-constexpr gfx::SelectionBehavior kWordSelectionBehavior = gfx::SELECTION_RETAIN;
-constexpr gfx::SelectionBehavior kMoveParagraphSelectionBehavior =
- gfx::SELECTION_RETAIN;
-#endif
-
-// Get the default command for a given key |event|.
-ui::TextEditCommand GetCommandForKeyEvent(const ui::KeyEvent& event) {
- if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode())
- return ui::TextEditCommand::INVALID_COMMAND;
-
- const bool shift = event.IsShiftDown();
- const bool control = event.IsControlDown() || event.IsCommandDown();
- const bool alt = event.IsAltDown() || event.IsAltGrDown();
- switch (event.key_code()) {
- case ui::VKEY_Z:
- if (control && !shift && !alt)
- return ui::TextEditCommand::UNDO;
- return (control && shift && !alt) ? ui::TextEditCommand::REDO
- : ui::TextEditCommand::INVALID_COMMAND;
- case ui::VKEY_Y:
- return (control && !alt) ? ui::TextEditCommand::REDO
- : ui::TextEditCommand::INVALID_COMMAND;
- case ui::VKEY_A:
- return (control && !alt) ? ui::TextEditCommand::SELECT_ALL
- : ui::TextEditCommand::INVALID_COMMAND;
- case ui::VKEY_X:
- return (control && !alt) ? ui::TextEditCommand::CUT
- : ui::TextEditCommand::INVALID_COMMAND;
- case ui::VKEY_C:
- return (control && !alt) ? ui::TextEditCommand::COPY
- : ui::TextEditCommand::INVALID_COMMAND;
- case ui::VKEY_V:
- return (control && !alt) ? ui::TextEditCommand::PASTE
- : ui::TextEditCommand::INVALID_COMMAND;
- case ui::VKEY_RIGHT:
- // Ignore alt+right, which may be a browser navigation shortcut.
- if (alt)
- return ui::TextEditCommand::INVALID_COMMAND;
- if (!shift) {
- return control ? ui::TextEditCommand::MOVE_WORD_RIGHT
- : ui::TextEditCommand::MOVE_RIGHT;
- }
- return control ? ui::TextEditCommand::MOVE_WORD_RIGHT_AND_MODIFY_SELECTION
- : ui::TextEditCommand::MOVE_RIGHT_AND_MODIFY_SELECTION;
- case ui::VKEY_LEFT:
- // Ignore alt+left, which may be a browser navigation shortcut.
- if (alt)
- return ui::TextEditCommand::INVALID_COMMAND;
- if (!shift) {
- return control ? ui::TextEditCommand::MOVE_WORD_LEFT
- : ui::TextEditCommand::MOVE_LEFT;
- }
- return control ? ui::TextEditCommand::MOVE_WORD_LEFT_AND_MODIFY_SELECTION
- : ui::TextEditCommand::MOVE_LEFT_AND_MODIFY_SELECTION;
- case ui::VKEY_HOME:
- return shift ? ui::TextEditCommand::
- MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION
- : ui::TextEditCommand::MOVE_TO_BEGINNING_OF_LINE;
- case ui::VKEY_END:
- return shift
- ? ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
- : ui::TextEditCommand::MOVE_TO_END_OF_LINE;
- case ui::VKEY_UP:
- return shift ? ui::TextEditCommand::
- MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION
- : ui::TextEditCommand::INVALID_COMMAND;
- case ui::VKEY_DOWN:
- return shift
- ? ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
- : ui::TextEditCommand::INVALID_COMMAND;
- case ui::VKEY_BACK:
- if (!control) {
-#if defined(OS_WIN)
- if (alt)
- return shift ? ui::TextEditCommand::REDO : ui::TextEditCommand::UNDO;
-#endif
- return ui::TextEditCommand::DELETE_BACKWARD;
- }
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
- // Only erase by line break on Linux and ChromeOS.
- if (shift)
- return ui::TextEditCommand::DELETE_TO_BEGINNING_OF_LINE;
-#endif
- return ui::TextEditCommand::DELETE_WORD_BACKWARD;
- case ui::VKEY_DELETE:
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
- // Only erase by line break on Linux and ChromeOS.
- if (shift && control)
- return ui::TextEditCommand::DELETE_TO_END_OF_LINE;
-#endif
- if (control)
- return ui::TextEditCommand::DELETE_WORD_FORWARD;
- return shift ? ui::TextEditCommand::CUT
- : ui::TextEditCommand::DELETE_FORWARD;
- case ui::VKEY_INSERT:
- if (control && !shift)
- return ui::TextEditCommand::COPY;
- return (shift && !control) ? ui::TextEditCommand::PASTE
- : ui::TextEditCommand::INVALID_COMMAND;
- default:
- return ui::TextEditCommand::INVALID_COMMAND;
- }
-}
-
// Returns the ui::TextEditCommand corresponding to the |command_id| menu
// action. |has_selection| is true if the textfield has an active selection.
// Keep in sync with UpdateContextMenu.
@@ -585,6 +484,7 @@ gfx::HorizontalAlignment Textfield::GetHorizontalAlignment() const {
void Textfield::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
GetRenderText()->SetHorizontalAlignment(alignment);
+
OnPropertyChanged(&model_ + kTextfieldHorizontalAlignment,
kPropertyEffectsNone);
}
@@ -698,9 +598,15 @@ void Textfield::FitToLocalBounds() {
// beyond their legibility, or enlarging controls dynamically with content.
gfx::Rect bounds = GetLocalBounds();
const gfx::Insets insets = GetInsets();
- // The text will draw with the correct vertical alignment if we don't apply
- // the vertical insets.
- bounds.Inset(insets.left(), 0, insets.right(), 0);
+
+ if (GetRenderText()->multiline()) {
+ bounds.Inset(insets);
+ } else {
+ // The text will draw with the correct vertical alignment if we don't apply
+ // the vertical insets.
+ bounds.Inset(insets.left(), 0, insets.right(), 0);
+ }
+
bounds.set_x(GetMirroredXForRect(bounds));
GetRenderText()->SetDisplayRect(bounds);
UpdateAfterChange(TextChangeType::kNone, true);
@@ -765,7 +671,9 @@ bool Textfield::OnMousePressed(const ui::MouseEvent& event) {
#endif
}
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
if (!handled && !had_focus && event.IsOnlyMiddleMouseButton())
RequestFocusWithPointer(ui::EventPointerType::kMouse);
#endif
@@ -800,6 +708,9 @@ WordLookupClient* Textfield::GetWordLookupClient() {
}
bool Textfield::OnKeyPressed(const ui::KeyEvent& event) {
+ if (PreHandleKeyPressed(event))
+ return true;
+
ui::TextEditCommand edit_command = scheduled_text_edit_command_;
scheduled_text_edit_command_ = ui::TextEditCommand::INVALID_COMMAND;
@@ -812,7 +723,9 @@ bool Textfield::OnKeyPressed(const ui::KeyEvent& event) {
if (!textfield)
return handled;
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
ui::TextEditKeyBindingsDelegateAuraLinux* delegate =
ui::GetTextEditKeyBindingsDelegate();
std::vector<ui::TextEditCommandAuraLinux> commands;
@@ -966,7 +879,9 @@ void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) {
}
bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Skip any accelerator handling that conflicts with custom keybindings.
ui::TextEditKeyBindingsDelegateAuraLinux* delegate =
ui::GetTextEditKeyBindingsDelegate();
@@ -1037,13 +952,13 @@ void Textfield::OnDragExited() {
SchedulePaint();
}
-int Textfield::OnPerformDrop(const ui::DropTargetEvent& event) {
+DragOperation Textfield::OnPerformDrop(const ui::DropTargetEvent& event) {
DCHECK(CanDrop(event.data()));
drop_cursor_visible_ = false;
if (controller_) {
- int drag_operation = controller_->OnDrop(event.data());
- if (drag_operation != ui::DragDropTypes::DRAG_NONE)
+ DragOperation drag_operation = controller_->OnDrop(event.data());
+ if (drag_operation != DragOperation::kNone)
return drag_operation;
}
@@ -1074,7 +989,7 @@ int Textfield::OnPerformDrop(const ui::DropTargetEvent& event) {
skip_input_method_cancel_composition_ = false;
UpdateAfterChange(TextChangeType::kUserTriggered, true);
OnAfterUserAction();
- return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY;
+ return move ? DragOperation::kMove : DragOperation::kCopy;
}
void Textfield::OnDragDone() {
@@ -1184,15 +1099,16 @@ void Textfield::OnBlur() {
render_text->set_focused(false);
// If necessary, yank the cursor to the logical start of the textfield.
- if (PlatformStyle::kTextfieldScrollsToStartOnFocusChange)
+ if (PlatformStyle::kTextfieldScrollsToStartOnFocusChange &&
+ !render_text->multiline())
model_->MoveCursorTo(gfx::SelectionModel(0, gfx::CURSOR_FORWARD));
if (GetInputMethod()) {
GetInputMethod()->DetachTextInputClient(this);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
wm::RestoreWindowBoundsOnClientFocusLost(
GetNativeView()->GetToplevelWindow());
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
StopBlinkingCursor();
cursor_view_->SetVisible(false);
@@ -1276,7 +1192,7 @@ void Textfield::WriteDragDataForView(View* sender,
.context(),
label.size()));
constexpr gfx::Vector2d kOffset(-15, 0);
- gfx::ImageSkia image(gfx::ImageSkiaRep(bitmap, raster_scale));
+ gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(bitmap, raster_scale);
data->provider().SetDragImage(image, kOffset);
if (controller_)
controller_->OnWriteDragData(data);
@@ -1515,7 +1431,8 @@ void Textfield::ClearCompositionText() {
OnAfterUserAction();
}
-void Textfield::InsertText(const base::string16& new_text) {
+void Textfield::InsertText(const base::string16& new_text,
+ InsertTextCursorBehavior cursor_behavior) {
base::string16 filtered_new_text;
std::copy_if(new_text.begin(), new_text.end(),
std::back_inserter(filtered_new_text), IsValidCharToInsert);
@@ -1524,6 +1441,7 @@ void Textfield::InsertText(const base::string16& new_text) {
filtered_new_text.empty())
return;
+ // TODO(crbug.com/1155331): Handle |cursor_behavior| correctly.
OnBeforeUserAction();
skip_input_method_cancel_composition_ = true;
model_->InsertText(filtered_new_text);
@@ -1686,6 +1604,7 @@ void Textfield::OnInputMethodChanged() {}
bool Textfield::ChangeTextDirectionAndLayoutAlignment(
base::i18n::TextDirection direction) {
+ DCHECK_NE(direction, base::i18n::UNKNOWN_DIRECTION);
// Restore text directionality mode when the indicated direction matches the
// current forced mode; otherwise, force the mode indicated. This helps users
// manage BiDi text layout without getting stuck in forced LTR or RTL modes.
@@ -1696,7 +1615,13 @@ bool Textfield::ChangeTextDirectionAndLayoutAlignment(
const bool modes_match = new_mode == render_text->directionality_mode();
render_text->SetDirectionalityMode(modes_match ? gfx::DIRECTIONALITY_FROM_TEXT
: new_mode);
- SetHorizontalAlignment(default_rtl ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT);
+ // Do not reset horizontal alignment to left/right if it has been set to
+ // center, or if it depends on the text direction and that direction has not
+ // been modified.
+ bool dir_from_text =
+ modes_match && GetHorizontalAlignment() == gfx::ALIGN_TO_HEAD;
+ if (!dir_from_text && GetHorizontalAlignment() != gfx::ALIGN_CENTER)
+ SetHorizontalAlignment(default_rtl ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT);
SchedulePaint();
return true;
}
@@ -1713,10 +1638,10 @@ void Textfield::ExtendSelectionAndDelete(size_t before, size_t after) {
}
void Textfield::EnsureCaretNotInRect(const gfx::Rect& rect_in_screen) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
aura::Window* top_level_window = GetNativeView()->GetToplevelWindow();
wm::EnsureWindowNotInRect(top_level_window, rect_in_screen);
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
bool Textfield::IsTextEditCommandEnabled(ui::TextEditCommand command) const {
@@ -1796,12 +1721,16 @@ bool Textfield::IsTextEditCommandEnabled(ui::TextEditCommand command) const {
case ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION:
case ui::TextEditCommand::MOVE_UP:
case ui::TextEditCommand::MOVE_UP_AND_MODIFY_SELECTION:
+ case ui::TextEditCommand::SCROLL_TO_BEGINNING_OF_DOCUMENT:
+ case ui::TextEditCommand::SCROLL_TO_END_OF_DOCUMENT:
+ case ui::TextEditCommand::SCROLL_PAGE_DOWN:
+ case ui::TextEditCommand::SCROLL_PAGE_UP:
// On Mac, the textfield should respond to Up/Down arrows keys and
// PageUp/PageDown.
#if defined(OS_APPLE)
return true;
#else
- return false;
+ return GetRenderText()->multiline();
#endif
case ui::TextEditCommand::INSERT_TEXT:
case ui::TextEditCommand::SET_MARK:
@@ -1833,7 +1762,7 @@ bool Textfield::ShouldDoLearning() {
return false;
}
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(https://crbug.com/952355): Implement this method to support Korean IME
// reconversion feature on native text fields (e.g. find bar).
bool Textfield::SetCompositionFromExistingText(
@@ -1849,7 +1778,7 @@ bool Textfield::SetCompositionFromExistingText(
}
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
gfx::Range Textfield::GetAutocorrectRange() const {
return model_->autocorrect_range();
}
@@ -1868,22 +1797,37 @@ gfx::Rect Textfield::GetAutocorrectCharacterBounds() const {
return rect;
}
-bool Textfield::SetAutocorrectRange(const base::string16& autocorrect_text,
- const gfx::Range& range) {
- base::UmaHistogramEnumeration("InputMethod.Assistive.Autocorrect.Count",
- TextInputClient::SubClass::kTextField);
- return model_->SetAutocorrectRange(autocorrect_text, range);
-}
-
-void Textfield::ClearAutocorrectRange() {
- model_->SetAutocorrectRange(base::string16(), gfx::Range());
+bool Textfield::SetAutocorrectRange(const gfx::Range& range) {
+ if (!range.is_empty()) {
+ base::UmaHistogramEnumeration("InputMethod.Assistive.Autocorrect.Count",
+ TextInputClient::SubClass::kTextField);
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ auto* input_method_manager =
+ chromeos::input_method::InputMethodManager::Get();
+ if (input_method_manager &&
+ chromeos::extension_ime_util::IsExperimentalMultilingual(
+ input_method_manager->GetActiveIMEState()
+ ->GetCurrentInputMethod()
+ .id())) {
+ base::UmaHistogramEnumeration(
+ "InputMethod.MultilingualExperiment.Autocorrect.Count",
+ TextInputClient::SubClass::kTextField);
+ }
+#endif
+ }
+ return model_->SetAutocorrectRange(range);
}
#endif
#if defined(OS_WIN)
void Textfield::GetActiveTextInputControlLayoutBounds(
base::Optional<gfx::Rect>* control_bounds,
- base::Optional<gfx::Rect>* selection_bounds) {}
+ base::Optional<gfx::Rect>* selection_bounds) {
+ gfx::Rect origin = GetContentsBounds();
+ ConvertRectToScreen(this, &origin);
+ *control_bounds = origin;
+}
// TODO(https://crbug.com/952355): Implement this method once TSF supports
// reconversion features on native text fields.
@@ -1925,6 +1869,30 @@ base::string16 Textfield::GetSelectionClipboardText() const {
void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) {
DestroyTouchSelection();
+ // We only execute the commands enabled in Textfield::IsTextEditCommandEnabled
+ // below. Hence don't do a virtual IsTextEditCommandEnabled call.
+ if (!IsTextEditCommandEnabled(command))
+ return;
+
+ OnBeforeUserAction();
+
+ gfx::SelectionModel selection_model = GetSelectionModel();
+ bool text_changed, cursor_changed;
+ std::tie(text_changed, cursor_changed) = DoExecuteTextEditCommand(command);
+
+ cursor_changed |= (GetSelectionModel() != selection_model);
+ if (cursor_changed && HasSelection())
+ UpdateSelectionClipboard();
+ UpdateAfterChange(
+ text_changed ? TextChangeType::kUserTriggered : TextChangeType::kNone,
+ cursor_changed);
+ OnAfterUserAction();
+}
+
+Textfield::EditCommandResult Textfield::DoExecuteTextEditCommand(
+ ui::TextEditCommand command) {
+ bool changed = false;
+ bool cursor_changed = false;
bool add_to_kill_buffer = false;
base::AutoReset<bool> show_rejection_ui(&show_rejection_ui_if_any_, true);
@@ -1947,48 +1915,40 @@ void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) {
break;
}
- // We only execute the commands enabled in Textfield::IsTextEditCommandEnabled
- // below. Hence don't do a virtual IsTextEditCommandEnabled call.
- if (!IsTextEditCommandEnabled(command))
- return;
-
- bool changed = false;
bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
gfx::VisualCursorDirection begin = rtl ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT;
gfx::VisualCursorDirection end = rtl ? gfx::CURSOR_LEFT : gfx::CURSOR_RIGHT;
- gfx::SelectionModel selection_model = GetSelectionModel();
- OnBeforeUserAction();
switch (command) {
case ui::TextEditCommand::DELETE_BACKWARD:
- changed = model_->Backspace(add_to_kill_buffer);
+ changed = cursor_changed = model_->Backspace(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_FORWARD:
- changed = model_->Delete(add_to_kill_buffer);
+ changed = cursor_changed = model_->Delete(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_TO_BEGINNING_OF_LINE:
model_->MoveCursor(gfx::LINE_BREAK, begin, gfx::SELECTION_RETAIN);
- changed = model_->Backspace(add_to_kill_buffer);
+ changed = cursor_changed = model_->Backspace(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_TO_BEGINNING_OF_PARAGRAPH:
model_->MoveCursor(gfx::FIELD_BREAK, begin, gfx::SELECTION_RETAIN);
- changed = model_->Backspace(add_to_kill_buffer);
+ changed = cursor_changed = model_->Backspace(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_TO_END_OF_LINE:
model_->MoveCursor(gfx::LINE_BREAK, end, gfx::SELECTION_RETAIN);
- changed = model_->Delete(add_to_kill_buffer);
+ changed = cursor_changed = model_->Delete(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_TO_END_OF_PARAGRAPH:
model_->MoveCursor(gfx::FIELD_BREAK, end, gfx::SELECTION_RETAIN);
- changed = model_->Delete(add_to_kill_buffer);
+ changed = cursor_changed = model_->Delete(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_WORD_BACKWARD:
model_->MoveCursor(gfx::WORD_BREAK, begin, gfx::SELECTION_RETAIN);
- changed = model_->Backspace(add_to_kill_buffer);
+ changed = cursor_changed = model_->Backspace(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_WORD_FORWARD:
model_->MoveCursor(gfx::WORD_BREAK, end, gfx::SELECTION_RETAIN);
- changed = model_->Delete(add_to_kill_buffer);
+ changed = cursor_changed = model_->Delete(add_to_kill_buffer);
break;
case ui::TextEditCommand::MOVE_BACKWARD:
model_->MoveCursor(gfx::CHARACTER_BREAK, begin, gfx::SELECTION_NONE);
@@ -2025,6 +1985,8 @@ void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) {
case ui::TextEditCommand::MOVE_TO_BEGINNING_OF_PARAGRAPH:
case ui::TextEditCommand::MOVE_UP:
case ui::TextEditCommand::MOVE_PAGE_UP:
+ case ui::TextEditCommand::SCROLL_TO_BEGINNING_OF_DOCUMENT:
+ case ui::TextEditCommand::SCROLL_PAGE_UP:
model_->MoveCursor(gfx::FIELD_BREAK, begin, gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION:
@@ -2047,6 +2009,8 @@ void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) {
case ui::TextEditCommand::MOVE_TO_END_OF_PARAGRAPH:
case ui::TextEditCommand::MOVE_DOWN:
case ui::TextEditCommand::MOVE_PAGE_DOWN:
+ case ui::TextEditCommand::SCROLL_TO_END_OF_DOCUMENT:
+ case ui::TextEditCommand::SCROLL_PAGE_DOWN:
model_->MoveCursor(gfx::FIELD_BREAK, end, gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION:
@@ -2097,28 +2061,28 @@ void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) {
kWordSelectionBehavior);
break;
case ui::TextEditCommand::UNDO:
- changed = model_->Undo();
+ changed = cursor_changed = model_->Undo();
break;
case ui::TextEditCommand::REDO:
- changed = model_->Redo();
+ changed = cursor_changed = model_->Redo();
break;
case ui::TextEditCommand::CUT:
- changed = Cut();
+ changed = cursor_changed = Cut();
break;
case ui::TextEditCommand::COPY:
Copy();
break;
case ui::TextEditCommand::PASTE:
- changed = Paste();
+ changed = cursor_changed = Paste();
break;
case ui::TextEditCommand::SELECT_ALL:
SelectAll(false);
break;
case ui::TextEditCommand::TRANSPOSE:
- changed = model_->Transpose();
+ changed = cursor_changed = model_->Transpose();
break;
case ui::TextEditCommand::YANK:
- changed = model_->Yank();
+ changed = cursor_changed = model_->Yank();
break;
case ui::TextEditCommand::INSERT_TEXT:
case ui::TextEditCommand::SET_MARK:
@@ -2128,14 +2092,7 @@ void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) {
break;
}
- const auto text_change_type =
- changed ? TextChangeType::kUserTriggered : TextChangeType::kNone;
- const bool cursor_changed =
- changed || (GetSelectionModel() != selection_model);
- if (cursor_changed && HasSelection())
- UpdateSelectionClipboard();
- UpdateAfterChange(text_change_type, cursor_changed);
- OnAfterUserAction();
+ return {changed, cursor_changed};
}
void Textfield::OffsetDoubleClickWord(int offset) {
@@ -2185,12 +2142,157 @@ void Textfield::RequestFocusForGesture(const ui::GestureEventDetails& details) {
ShowVirtualKeyboardIfEnabled();
}
-views::PropertyChangedSubscription Textfield::AddTextChangedCallback(
+base::CallbackListSubscription Textfield::AddTextChangedCallback(
views::PropertyChangedCallback callback) {
return AddPropertyChangedCallback(&model_ + kTextfieldText,
std::move(callback));
}
+bool Textfield::PreHandleKeyPressed(const ui::KeyEvent& event) {
+ return false;
+}
+
+ui::TextEditCommand Textfield::GetCommandForKeyEvent(
+ const ui::KeyEvent& event) {
+ if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode())
+ return ui::TextEditCommand::INVALID_COMMAND;
+
+ const bool shift = event.IsShiftDown();
+#if defined(OS_APPLE)
+ const bool command = event.IsCommandDown();
+#endif
+ const bool control = event.IsControlDown() || event.IsCommandDown();
+ const bool alt = event.IsAltDown() || event.IsAltGrDown();
+ switch (event.key_code()) {
+ case ui::VKEY_Z:
+ if (control && !shift && !alt)
+ return ui::TextEditCommand::UNDO;
+ return (control && shift && !alt) ? ui::TextEditCommand::REDO
+ : ui::TextEditCommand::INVALID_COMMAND;
+ case ui::VKEY_Y:
+ return (control && !alt) ? ui::TextEditCommand::REDO
+ : ui::TextEditCommand::INVALID_COMMAND;
+ case ui::VKEY_A:
+ return (control && !alt) ? ui::TextEditCommand::SELECT_ALL
+ : ui::TextEditCommand::INVALID_COMMAND;
+ case ui::VKEY_X:
+ return (control && !alt) ? ui::TextEditCommand::CUT
+ : ui::TextEditCommand::INVALID_COMMAND;
+ case ui::VKEY_C:
+ return (control && !alt) ? ui::TextEditCommand::COPY
+ : ui::TextEditCommand::INVALID_COMMAND;
+ case ui::VKEY_V:
+ return (control && !alt) ? ui::TextEditCommand::PASTE
+ : ui::TextEditCommand::INVALID_COMMAND;
+ case ui::VKEY_RIGHT:
+ // Ignore alt+right, which may be a browser navigation shortcut.
+ if (alt)
+ return ui::TextEditCommand::INVALID_COMMAND;
+ if (!shift) {
+ return control ? ui::TextEditCommand::MOVE_WORD_RIGHT
+ : ui::TextEditCommand::MOVE_RIGHT;
+ }
+ return control ? ui::TextEditCommand::MOVE_WORD_RIGHT_AND_MODIFY_SELECTION
+ : ui::TextEditCommand::MOVE_RIGHT_AND_MODIFY_SELECTION;
+ case ui::VKEY_LEFT:
+ // Ignore alt+left, which may be a browser navigation shortcut.
+ if (alt)
+ return ui::TextEditCommand::INVALID_COMMAND;
+ if (!shift) {
+ return control ? ui::TextEditCommand::MOVE_WORD_LEFT
+ : ui::TextEditCommand::MOVE_LEFT;
+ }
+ return control ? ui::TextEditCommand::MOVE_WORD_LEFT_AND_MODIFY_SELECTION
+ : ui::TextEditCommand::MOVE_LEFT_AND_MODIFY_SELECTION;
+ case ui::VKEY_HOME:
+ if (shift) {
+ return ui::TextEditCommand::
+ MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION;
+ }
+#if defined(OS_APPLE)
+ return ui::TextEditCommand::SCROLL_TO_BEGINNING_OF_DOCUMENT;
+#else
+ return ui::TextEditCommand::MOVE_TO_BEGINNING_OF_LINE;
+#endif
+ case ui::VKEY_END:
+ if (shift)
+ return ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION;
+#if defined(OS_APPLE)
+ return ui::TextEditCommand::SCROLL_TO_END_OF_DOCUMENT;
+#else
+ return ui::TextEditCommand::MOVE_TO_END_OF_LINE;
+#endif
+ case ui::VKEY_UP:
+#if defined(OS_APPLE)
+ if (control && shift) {
+ return ui::TextEditCommand::
+ MOVE_PARAGRAPH_BACKWARD_AND_MODIFY_SELECTION;
+ }
+ if (command)
+ return ui::TextEditCommand::MOVE_TO_BEGINNING_OF_DOCUMENT;
+ return shift ? ui::TextEditCommand::
+ MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION
+ : ui::TextEditCommand::MOVE_UP;
+#else
+ return shift ? ui::TextEditCommand::
+ MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION
+ : ui::TextEditCommand::INVALID_COMMAND;
+#endif
+ case ui::VKEY_DOWN:
+#if defined(OS_APPLE)
+ if (control && shift) {
+ return ui::TextEditCommand::MOVE_PARAGRAPH_FORWARD_AND_MODIFY_SELECTION;
+ }
+ if (command)
+ return ui::TextEditCommand::MOVE_TO_END_OF_DOCUMENT;
+ return shift
+ ? ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
+ : ui::TextEditCommand::MOVE_DOWN;
+#else
+ return shift
+ ? ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
+ : ui::TextEditCommand::INVALID_COMMAND;
+#endif
+ case ui::VKEY_BACK:
+ if (!control) {
+#if defined(OS_WIN)
+ if (alt)
+ return shift ? ui::TextEditCommand::REDO : ui::TextEditCommand::UNDO;
+#endif
+ return ui::TextEditCommand::DELETE_BACKWARD;
+ }
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+ // Only erase by line break on Linux and ChromeOS.
+ if (shift)
+ return ui::TextEditCommand::DELETE_TO_BEGINNING_OF_LINE;
+#endif
+ return ui::TextEditCommand::DELETE_WORD_BACKWARD;
+ case ui::VKEY_DELETE:
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+ // Only erase by line break on Linux and ChromeOS.
+ if (shift && control)
+ return ui::TextEditCommand::DELETE_TO_END_OF_LINE;
+#endif
+ if (control)
+ return ui::TextEditCommand::DELETE_WORD_FORWARD;
+ return shift ? ui::TextEditCommand::CUT
+ : ui::TextEditCommand::DELETE_FORWARD;
+ case ui::VKEY_INSERT:
+ if (control && !shift)
+ return ui::TextEditCommand::COPY;
+ return (shift && !control) ? ui::TextEditCommand::PASTE
+ : ui::TextEditCommand::INVALID_COMMAND;
+ case ui::VKEY_PRIOR:
+ return control ? ui::TextEditCommand::SCROLL_PAGE_UP
+ : ui::TextEditCommand::INVALID_COMMAND;
+ case ui::VKEY_NEXT:
+ return control ? ui::TextEditCommand::SCROLL_PAGE_DOWN
+ : ui::TextEditCommand::INVALID_COMMAND;
+ default:
+ return ui::TextEditCommand::INVALID_COMMAND;
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// Textfield, private:
@@ -2256,7 +2358,9 @@ bool Textfield::PasteSelectionClipboard() {
}
void Textfield::UpdateSelectionClipboard() {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
if (text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD) {
ui::ScopedClipboardWriter(ui::ClipboardBuffer::kSelection)
.WriteText(GetSelectedText());
@@ -2558,10 +2662,12 @@ ADD_PROPERTY_METADATA(bool, ReadOnly)
ADD_PROPERTY_METADATA(base::string16, Text)
ADD_PROPERTY_METADATA(ui::TextInputType, TextInputType)
ADD_PROPERTY_METADATA(int, TextInputFlags)
-ADD_PROPERTY_METADATA(SkColor, TextColor)
-ADD_PROPERTY_METADATA(SkColor, SelectionTextColor)
-ADD_PROPERTY_METADATA(SkColor, BackgroundColor)
-ADD_PROPERTY_METADATA(SkColor, SelectionBackgroundColor)
+ADD_PROPERTY_METADATA(SkColor, TextColor, metadata::SkColorConverter)
+ADD_PROPERTY_METADATA(SkColor, SelectionTextColor, metadata::SkColorConverter)
+ADD_PROPERTY_METADATA(SkColor, BackgroundColor, metadata::SkColorConverter)
+ADD_PROPERTY_METADATA(SkColor,
+ SelectionBackgroundColor,
+ metadata::SkColorConverter)
ADD_PROPERTY_METADATA(bool, CursorEnabled)
ADD_PROPERTY_METADATA(base::string16, PlaceholderText)
ADD_PROPERTY_METADATA(bool, Invalid)
diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h
index 3e3b731dbb4..fe833a15e8e 100644
--- a/chromium/ui/views/controls/textfield/textfield.h
+++ b/chromium/ui/views/controls/textfield/textfield.h
@@ -11,6 +11,7 @@
#include <memory>
#include <set>
#include <string>
+#include <utility>
#if defined(OS_WIN)
#include <vector>
@@ -25,6 +26,7 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/ime/text_edit_commands.h"
#include "ui/base/ime/text_input_client.h"
@@ -84,6 +86,29 @@ class VIEWS_EXPORT Textfield : public View,
kLastCommandId = kSelectAll,
};
+#if defined(OS_APPLE)
+ static constexpr gfx::SelectionBehavior kLineSelectionBehavior =
+ gfx::SELECTION_EXTEND;
+ static constexpr gfx::SelectionBehavior kWordSelectionBehavior =
+ gfx::SELECTION_CARET;
+ static constexpr gfx::SelectionBehavior kMoveParagraphSelectionBehavior =
+ gfx::SELECTION_CARET;
+ static constexpr gfx::SelectionBehavior kPageSelectionBehavior =
+ gfx::SELECTION_EXTEND;
+#else
+ static constexpr gfx::SelectionBehavior kLineSelectionBehavior =
+ gfx::SELECTION_RETAIN;
+ static constexpr gfx::SelectionBehavior kWordSelectionBehavior =
+ gfx::SELECTION_RETAIN;
+ static constexpr gfx::SelectionBehavior kMoveParagraphSelectionBehavior =
+ gfx::SELECTION_RETAIN;
+ static constexpr gfx::SelectionBehavior kPageSelectionBehavior =
+ gfx::SELECTION_RETAIN;
+#endif
+
+ // Pair of |text_changed|, |cursor_changed|.
+ using EditCommandResult = std::pair<bool, bool>;
+
// Returns the text cursor blink time, or 0 for no blinking.
static base::TimeDelta GetCaretBlinkInterval();
@@ -312,7 +337,8 @@ class VIEWS_EXPORT Textfield : public View,
bool CanDrop(const ui::OSExchangeData& data) override;
int OnDragUpdated(const ui::DropTargetEvent& event) override;
void OnDragExited() override;
- int OnPerformDrop(const ui::DropTargetEvent& event) override;
+ ui::mojom::DragOperation OnPerformDrop(
+ const ui::DropTargetEvent& event) override;
void OnDragDone() override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
bool HandleAccessibleAction(const ui::AXActionData& action_data) override;
@@ -377,7 +403,8 @@ class VIEWS_EXPORT Textfield : public View,
void SetCompositionText(const ui::CompositionText& composition) override;
uint32_t ConfirmCompositionText(bool keep_selection) override;
void ClearCompositionText() override;
- void InsertText(const base::string16& text) override;
+ void InsertText(const base::string16& text,
+ InsertTextCursorBehavior cursor_behavior) override;
void InsertChar(const ui::KeyEvent& event) override;
ui::TextInputType GetTextInputType() const override;
ui::TextInputMode GetTextInputMode() const override;
@@ -409,18 +436,16 @@ class VIEWS_EXPORT Textfield : public View,
// Set whether the text should be used to improve typing suggestions.
void SetShouldDoLearning(bool value) { should_do_learning_ = value; }
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
bool SetCompositionFromExistingText(
const gfx::Range& range,
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
gfx::Range GetAutocorrectRange() const override;
gfx::Rect GetAutocorrectCharacterBounds() const override;
- bool SetAutocorrectRange(const base::string16& autocorrect_text,
- const gfx::Range& range) override;
- void ClearAutocorrectRange() override;
+ bool SetAutocorrectRange(const gfx::Range& range) override;
#endif
#if defined(OS_WIN)
@@ -433,10 +458,12 @@ class VIEWS_EXPORT Textfield : public View,
bool is_composition_committed) override;
#endif
- views::PropertyChangedSubscription AddTextChangedCallback(
+ base::CallbackListSubscription AddTextChangedCallback(
views::PropertyChangedCallback callback) WARN_UNUSED_RESULT;
protected:
+ TextfieldModel* textfield_model() { return model_.get(); }
+
// Inserts or appends a character in response to an IME operation.
virtual void DoInsertChar(base::char16 ch);
@@ -474,6 +501,20 @@ class VIEWS_EXPORT Textfield : public View,
// gesture event.
void RequestFocusForGesture(const ui::GestureEventDetails& details);
+ virtual Textfield::EditCommandResult DoExecuteTextEditCommand(
+ ui::TextEditCommand command);
+
+ // Handles key press event ahead of OnKeyPressed(). This is used for Textarea
+ // to handle the return key. Use TextfieldController::HandleKeyEvent to
+ // intercept the key event in other cases.
+ virtual bool PreHandleKeyPressed(const ui::KeyEvent& event);
+
+ // Get the default command for a given key |event|.
+ virtual ui::TextEditCommand GetCommandForKeyEvent(const ui::KeyEvent& event);
+
+ // Update the cursor position in the text field.
+ void UpdateCursorViewPosition();
+
private:
friend class TextfieldTestApi;
@@ -527,9 +568,6 @@ class VIEWS_EXPORT Textfield : public View,
// A callback function to periodically update the cursor node_data.
void UpdateCursorVisibility();
- // Update the cursor position in the text field.
- void UpdateCursorViewPosition();
-
// Gets the style::TextStyle that should be used.
int GetTextStyle() const;
@@ -735,7 +773,7 @@ class VIEWS_EXPORT Textfield : public View,
gfx::Insets extra_insets_ = gfx::Insets();
// Holds the subscription object for the enabled changed callback.
- PropertyChangedSubscription enabled_changed_subscription_ =
+ base::CallbackListSubscription enabled_changed_subscription_ =
AddEnabledChangedCallback(
base::BindRepeating(&Textfield::OnEnabledChanged,
base::Unretained(this)));
diff --git a/chromium/ui/views/controls/textfield/textfield_controller.cc b/chromium/ui/views/controls/textfield/textfield_controller.cc
index bf5f964c3e0..da6260083cb 100644
--- a/chromium/ui/views/controls/textfield/textfield_controller.cc
+++ b/chromium/ui/views/controls/textfield/textfield_controller.cc
@@ -4,7 +4,7 @@
#include "ui/views/controls/textfield/textfield_controller.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/events/event.h"
namespace views {
@@ -25,8 +25,9 @@ bool TextfieldController::HandleGestureEvent(
return false;
}
-int TextfieldController::OnDrop(const ui::OSExchangeData& data) {
- return ui::DragDropTypes::DRAG_NONE;
+ui::mojom::DragOperation TextfieldController::OnDrop(
+ const ui::OSExchangeData& data) {
+ return ui::mojom::DragOperation::kNone;
}
} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_controller.h b/chromium/ui/views/controls/textfield/textfield_controller.h
index 3010b3fe9dd..5ad5b589299 100644
--- a/chromium/ui/views/controls/textfield/textfield_controller.h
+++ b/chromium/ui/views/controls/textfield/textfield_controller.h
@@ -10,6 +10,7 @@
#include "base/strings/string16.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/views/views_export.h"
@@ -81,9 +82,9 @@ class VIEWS_EXPORT TextfieldController {
// 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
- // operation other than |ui::DragDropTypes::DRAG_NONE|, regular handling is
+ // operation other than `ui::mojom::DragOperation::kNone`, regular handling is
// skipped.
- virtual int OnDrop(const ui::OSExchangeData& data);
+ virtual ui::mojom::DragOperation OnDrop(const ui::OSExchangeData& data);
// Gives the controller a chance to modify the context menu contents.
virtual void UpdateContextMenu(ui::SimpleMenuModel* menu_contents) {}
diff --git a/chromium/ui/views/controls/textfield/textfield_model.cc b/chromium/ui/views/controls/textfield/textfield_model.cc
index 24514cb8e02..ba182dde811 100644
--- a/chromium/ui/views/controls/textfield/textfield_model.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model.cc
@@ -13,6 +13,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/current_thread.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/gfx/range/range.h"
@@ -362,7 +363,7 @@ void SelectRangeInCompositionText(gfx::RenderText* render_text,
DCHECK(range.IsValid());
uint32_t start = range.GetMin();
uint32_t end = range.GetMax();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Swap |start| and |end| so that GetCaretBounds() can always return the same
// value during conversion.
// TODO(yusukes): Check if this works for other platforms. If it is, use this
@@ -625,6 +626,11 @@ bool TextfieldModel::Paste() {
if (text.empty())
return false;
+ if (render_text()->multiline()) {
+ InsertTextInternal(text, false);
+ return true;
+ }
+
// Leading/trailing whitespace is often selected accidentally, and is rarely
// critical to include (e.g. when pasting into a find bar). Trim it. By
// contrast, whitespace in the middle of the string may need exact
@@ -753,41 +759,13 @@ void TextfieldModel::SetCompositionText(
}
}
-#if defined(OS_CHROMEOS)
-bool TextfieldModel::SetAutocorrectRange(const base::string16& autocorrect_text,
- const gfx::Range& autocorrect_range) {
- // Clears autocorrect range if text is empty.
- if (autocorrect_text.empty() || autocorrect_range == gfx::Range()) {
- autocorrect_range_ = gfx::Range();
- original_text_ = base::EmptyString16();
- } else {
- // TODO(crbug.com/1108170): Use original text to create the Undo window.
- base::string16 current_text =
- render_text_->GetTextFromRange(autocorrect_range);
- // current text should always be valid.
- if (current_text.empty())
- return false;
-
- original_text_ = std::move(current_text);
- uint32_t autocorrect_range_start = autocorrect_range.start();
-
- // TODO(crbug.com/1108170): Update the autocorrect range when the
- // composition changes for ChromeOS. The current autocorrect_range_ does not
- // get updated when composition changes or more text is committed.
- autocorrect_range_ =
- gfx::Range(autocorrect_range_start,
- autocorrect_text.length() + autocorrect_range_start);
-
- base::string16 before_text = render_text_->GetTextFromRange(
- gfx::Range(0, autocorrect_range.start()));
- base::string16 after_text = render_text_->GetTextFromRange(gfx::Range(
- autocorrect_range.end(),
- std::max(autocorrect_range.end(),
- static_cast<uint32_t>(render_text_->text().length()))));
- base::string16 new_text =
- before_text.append(autocorrect_text).append(after_text);
- SetRenderTextText(new_text);
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+bool TextfieldModel::SetAutocorrectRange(const gfx::Range& range) {
+ // TODO(crbug.com/1108170): Add an underline to |range|.
+ if (range.GetMax() > render_text()->text().length()) {
+ return false;
}
+ autocorrect_range_ = range;
return true;
}
#endif
diff --git a/chromium/ui/views/controls/textfield/textfield_model.h b/chromium/ui/views/controls/textfield/textfield_model.h
index 2d581a86104..77700891f91 100644
--- a/chromium/ui/views/controls/textfield/textfield_model.h
+++ b/chromium/ui/views/controls/textfield/textfield_model.h
@@ -14,6 +14,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/strings/string16.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/ime/composition_text.h"
#include "ui/gfx/render_text.h"
#include "ui/gfx/text_constants.h"
@@ -39,6 +40,7 @@ enum class MergeType {
namespace test {
class BridgedNativeWidgetTest;
+class TextfieldTest;
} // namespace test
// A model that represents text content for a views::Textfield.
@@ -233,15 +235,14 @@ class VIEWS_EXPORT TextfieldModel {
// composition text.
void SetCompositionText(const ui::CompositionText& composition);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Return the text range corresponding to the autocorrected text.
const gfx::Range& autocorrect_range() const { return autocorrect_range_; }
- // Replace the text in the specified range with the autocorrect text and
- // store necessary metadata (The size of the new text + the original text)
- // to be able to undo this change if needed.
- bool SetAutocorrectRange(const base::string16& autocorrect_text,
- const gfx::Range& range);
+ // Sets the autocorrect range to |range|. If |range| is empty, then the
+ // autocorrect range is cleared. Returns true if the range was set or cleared
+ // successfully.
+ bool SetAutocorrectRange(const gfx::Range& range);
#endif
// Puts the text in the specified range into composition mode.
@@ -270,7 +271,7 @@ class VIEWS_EXPORT TextfieldModel {
friend class internal::Edit;
friend class test::BridgedNativeWidgetTest;
friend class TextfieldModelTest;
- friend class TextfieldTest;
+ friend class test::TextfieldTest;
FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_BasicTest);
FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_CutCopyPasteTest);
@@ -335,12 +336,8 @@ class VIEWS_EXPORT TextfieldModel {
gfx::Range composition_range_;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
gfx::Range autocorrect_range_;
- // Original text is the text that was replaced by the autocorrect feature.
- // This should be restored if the Undo button corresponding to the Autocorrect
- // window is pressed.
- base::string16 original_text_;
#endif
// The list of Edits. The oldest Edits are at the front of the list, and the
diff --git a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
index f3919eece4a..2e22fa6f7d1 100644
--- a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
@@ -15,6 +15,7 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
@@ -1299,7 +1300,7 @@ TEST_F(TextfieldModelTest, CompositionTextTest) {
model.SetCompositionText(composition);
EXPECT_TRUE(model.HasCompositionText());
EXPECT_TRUE(model.HasSelection());
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
// |composition.selection| is ignored because SetCompositionText checks
// if a thick underline exists first.
EXPECT_EQ(gfx::Range(5, 7), model.render_text()->selection());
@@ -1340,7 +1341,7 @@ TEST_F(TextfieldModelTest, CompositionTextTest) {
model.SetCompositionText(composition);
EXPECT_STR_EQ("1234567890678", model.text());
EXPECT_TRUE(model.HasSelection());
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
EXPECT_EQ(gfx::Range(10, 11), model.render_text()->selection());
EXPECT_EQ(11U, model.render_text()->cursor_position());
#else
diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc
index 42d1f0f7cad..aa8e109a607 100644
--- a/chromium/ui/views/controls/textfield/textfield_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc
@@ -2,30 +2,31 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_unittest.h"
#include <stddef.h>
#include <stdint.h>
#include <set>
#include <string>
-#include <utility>
#include <vector>
#include "base/command_line.h"
-#include "base/feature_list.h"
#include "base/format_macros.h"
#include "base/i18n/rtl.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 "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
-#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/clipboard/test/test_clipboard.h"
#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/base/emoji/emoji_panel_helper.h"
#include "ui/base/ime/constants.h"
#include "ui/base/ime/init/input_method_factory.h"
@@ -40,20 +41,17 @@
#include "ui/events/event_processor.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
-#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/event_generator.h"
#include "ui/events/test/keyboard_layout.h"
#include "ui/gfx/render_text.h"
#include "ui/gfx/render_text_test_api.h"
#include "ui/strings/grit/ui_strings.h"
-#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/controls/textfield/textfield_model.h"
#include "ui/views/controls/textfield/textfield_test_api.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/test/ax_event_counter.h"
#include "ui/views/test/test_views_delegate.h"
-#include "ui/views/test/views_test_base.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/views_features.h"
#include "ui/views/widget/widget.h"
@@ -64,11 +62,13 @@
#include "base/win/windows_version.h"
#endif
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
#include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/aura/window.h"
#include "ui/wm/core/ime_util_chromeos.h"
#endif
@@ -82,18 +82,79 @@ using base::ASCIIToUTF16;
using base::UTF8ToUTF16;
using base::WideToUTF16;
-#define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16)
+namespace views {
+namespace test {
-namespace {
+const ui::EventType kFocusEvent =
+ base::FeatureList::IsEnabled(features::kTextfieldFocusOnTapUp)
+ ? ui::ET_GESTURE_TAP
+ : ui::ET_GESTURE_TAP_DOWN;
const base::char16 kHebrewLetterSamekh = 0x05E1;
+// Convenience to make constructing a GestureEvent simpler.
+class GestureEventForTest : public ui::GestureEvent {
+ public:
+ GestureEventForTest(int x, int y, ui::GestureEventDetails details)
+ : GestureEvent(x, y, ui::EF_NONE, base::TimeTicks(), details) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GestureEventForTest);
+};
+
+// This controller will happily destroy the target field passed on
+// construction when a key event is triggered.
+class TextfieldDestroyerController : public TextfieldController {
+ public:
+ explicit TextfieldDestroyerController(Textfield* target) : target_(target) {
+ target_->set_controller(this);
+ }
+
+ Textfield* target() { return target_.get(); }
+
+ // TextfieldController:
+ bool HandleKeyEvent(Textfield* sender,
+ const ui::KeyEvent& key_event) override {
+ if (target_)
+ target_->OnBlur();
+ target_.reset();
+ return false;
+ }
+
+ private:
+ std::unique_ptr<Textfield> target_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextfieldDestroyerController);
+};
+
+// Class that focuses a textfield when it sees a KeyDown event.
+class TextfieldFocuser : public View {
+ public:
+ explicit TextfieldFocuser(Textfield* textfield) : textfield_(textfield) {
+ SetFocusBehavior(FocusBehavior::ALWAYS);
+ }
+
+ void set_consume(bool consume) { consume_ = consume; }
+
+ // View:
+ bool OnKeyPressed(const ui::KeyEvent& event) override {
+ textfield_->RequestFocus();
+ return consume_;
+ }
+
+ private:
+ bool consume_ = true;
+ Textfield* textfield_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextfieldFocuser);
+};
+
class MockInputMethod : public ui::InputMethodBase {
public:
MockInputMethod();
~MockInputMethod() override;
- // Overridden from InputMethod:
+ // InputMethod:
ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* key) override;
void OnTextInputTypeChanged(const ui::TextInputClient* client) override;
void OnCaretBoundsChanged(const ui::TextInputClient* client) override {}
@@ -117,7 +178,6 @@ class MockInputMethod : public ui::InputMethodBase {
void SetCompositionTextForNextKey(const ui::CompositionText& composition);
void SetResultTextForNextKey(const base::string16& result);
- int count_show_virtual_keyboard_ = 0;
private:
// Overridden from InputMethodBase.
@@ -147,6 +207,8 @@ class MockInputMethod : public ui::InputMethodBase {
bool text_input_type_changed_ = false;
bool cancel_composition_called_ = false;
+ int count_show_virtual_keyboard_ = 0;
+
DISALLOW_COPY_AND_ASSIGN(MockInputMethod);
};
@@ -191,7 +253,9 @@ ui::EventDispatchDetails MockInputMethod::DispatchKeyEvent(ui::KeyEvent* key) {
if (client) {
if (handled) {
if (result_text_.length())
- client->InsertText(result_text_);
+ client->InsertText(result_text_,
+ ui::TextInputClient::InsertTextCursorBehavior::
+ kMoveCursorAfterText);
if (composition_.text.length())
client->SetCompositionText(composition_);
else
@@ -268,8 +332,9 @@ void MockInputMethod::ClearComposition() {
class TestTextfield : public views::Textfield {
public:
TestTextfield() = default;
+ ~TestTextfield() override = default;
- // ui::TextInputClient overrides:
+ // ui::TextInputClient:
void InsertChar(const ui::KeyEvent& e) override {
views::Textfield::InsertChar(e);
#if defined(OS_APPLE)
@@ -298,7 +363,7 @@ class TestTextfield : public views::Textfield {
}
private:
- // views::View override:
+ // views::View:
void OnKeyEvent(ui::KeyEvent* event) override {
key_received_ = true;
event_flags_ = event->flags();
@@ -328,256 +393,198 @@ class TestTextfield : public views::Textfield {
DISALLOW_COPY_AND_ASSIGN(TestTextfield);
};
-// Convenience to make constructing a GestureEvent simpler.
-class GestureEventForTest : public ui::GestureEvent {
- public:
- GestureEventForTest(int x, int y, ui::GestureEventDetails details)
- : GestureEvent(x, y, 0, base::TimeTicks(), details) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GestureEventForTest);
-};
-
-// This controller will happily destroy the target textfield passed on
-// construction when a key event is triggered.
-class TextfieldDestroyerController : public views::TextfieldController {
- public:
- explicit TextfieldDestroyerController(views::Textfield* target)
- : target_(target) {
- target_->set_controller(this);
- }
-
- views::Textfield* target() { return target_.get(); }
-
- // views::TextfieldController:
- bool HandleKeyEvent(views::Textfield* sender,
- const ui::KeyEvent& key_event) override {
- if (target_)
- target_->OnBlur();
- target_.reset();
- return false;
- }
-
- private:
- std::unique_ptr<views::Textfield> target_;
-};
-
-// Class that focuses a textfield when it sees a KeyDown event.
-class TextfieldFocuser : public views::View {
- public:
- explicit TextfieldFocuser(views::Textfield* textfield)
- : textfield_(textfield) {
- SetFocusBehavior(FocusBehavior::ALWAYS);
- }
+TextfieldTest::TextfieldTest() {
+ input_method_ = new MockInputMethod();
+ ui::SetUpInputMethodForTesting(input_method_);
+}
- void set_consume(bool consume) { consume_ = consume; }
+TextfieldTest::~TextfieldTest() = default;
- // View:
- bool OnKeyPressed(const ui::KeyEvent& event) override {
- textfield_->RequestFocus();
- return consume_;
- }
+void TextfieldTest::SetUp() {
+ // OS clipboard is a global resource, which causes flakiness when unit tests
+ // run in parallel. So, use a per-instance test clipboard.
+ ui::Clipboard::SetClipboardForCurrentThread(
+ std::make_unique<ui::TestClipboard>());
+ ViewsTestBase::SetUp();
+}
- private:
- bool consume_ = true;
- views::Textfield* textfield_;
+void TextfieldTest::TearDown() {
+ if (widget_)
+ widget_->Close();
+ // Clear kill buffer used for "Yank" text editing command so that no state
+ // persists between tests.
+ TextfieldModel::ClearKillBuffer();
+ ViewsTestBase::TearDown();
+}
- DISALLOW_COPY_AND_ASSIGN(TextfieldFocuser);
-};
+ui::ClipboardBuffer TextfieldTest::GetAndResetCopiedToClipboard() {
+ return std::exchange(copied_to_clipboard_, ui::ClipboardBuffer::kMaxValue);
+}
-base::string16 GetClipboardText(ui::ClipboardBuffer clipboard_buffer) {
+base::string16 TextfieldTest::GetClipboardText(
+ ui::ClipboardBuffer clipboard_buffer) {
base::string16 text;
ui::Clipboard::GetForCurrentThread()->ReadText(
clipboard_buffer, /* data_dst = */ nullptr, &text);
return text;
}
-void SetClipboardText(ui::ClipboardBuffer clipboard_buffer,
- const std::string& text) {
+void TextfieldTest::SetClipboardText(ui::ClipboardBuffer clipboard_buffer,
+ const std::string& text) {
ui::ScopedClipboardWriter(clipboard_buffer).WriteText(ASCIIToUTF16(text));
}
-} // namespace
-
-namespace views {
-
-class TextfieldTest : public ViewsTestBase, public TextfieldController {
- public:
- TextfieldTest() {
- input_method_ = new MockInputMethod();
- ui::SetUpInputMethodForTesting(input_method_);
- }
-
- // ::testing::Test:
- void TearDown() override {
- if (widget_)
- widget_->Close();
- // Clear kill buffer used for "Yank" text editing command so that no state
- // persists between tests.
- TextfieldModel::ClearKillBuffer();
- ViewsTestBase::TearDown();
- }
+void TextfieldTest::ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) {
+ // Paste calls TextfieldController::ContentsChanged() explicitly even if the
+ // paste action did not change the content. So |new_contents| may match
+ // |last_contents_|. For more info, see http://crbug.com/79002
+ last_contents_ = new_contents;
+}
- ui::ClipboardBuffer GetAndResetCopiedToClipboard() {
- ui::ClipboardBuffer clipboard_buffer = copied_to_clipboard_;
- copied_to_clipboard_ = ui::ClipboardBuffer::kMaxValue;
- return clipboard_buffer;
- }
+void TextfieldTest::OnBeforeUserAction(Textfield* sender) {
+ ++on_before_user_action_;
+}
- // TextfieldController:
- void ContentsChanged(Textfield* sender,
- const base::string16& new_contents) override {
- // Paste calls TextfieldController::ContentsChanged() explicitly even if the
- // paste action did not change the content. So |new_contents| may match
- // |last_contents_|. For more info, see http://crbug.com/79002
- last_contents_ = new_contents;
- }
+void TextfieldTest::OnAfterUserAction(Textfield* sender) {
+ ++on_after_user_action_;
+}
- void OnBeforeUserAction(Textfield* sender) override {
- ++on_before_user_action_;
- }
+void TextfieldTest::OnAfterCutOrCopy(ui::ClipboardBuffer clipboard_type) {
+ copied_to_clipboard_ = clipboard_type;
+}
- void OnAfterUserAction(Textfield* sender) override {
- ++on_after_user_action_;
- }
+void TextfieldTest::InitTextfield(int count) {
+ ASSERT_FALSE(textfield_);
+ textfield_ = PrepareTextfields(count, std::make_unique<TestTextfield>(),
+ gfx::Rect(100, 100, 100, 100));
+}
- void OnAfterCutOrCopy(ui::ClipboardBuffer clipboard_buffer) override {
- copied_to_clipboard_ = clipboard_buffer;
+void TextfieldTest::PrepareTextfieldsInternal(int count,
+ Textfield* textfield,
+ View* container,
+ gfx::Rect bounds) {
+ input_method_->SetDelegate(
+ test::WidgetTest::GetInputMethodDelegateForWidget(widget_.get()));
+
+ textfield->set_controller(this);
+ textfield->SetBoundsRect(bounds);
+ textfield->SetID(1);
+ test_api_ = std::make_unique<TextfieldTestApi>(textfield);
+
+ for (int i = 1; i < count; ++i) {
+ Textfield* textfield =
+ container->AddChildView(std::make_unique<Textfield>());
+ textfield->SetID(i + 1);
}
- void InitTextfield() { InitTextfields(1); }
-
- void InitTextfields(int count) {
- ASSERT_FALSE(textfield_);
- textfield_ = new TestTextfield();
- textfield_->set_controller(this);
- widget_ = new Widget();
-
- // The widget type must be an activatable type, and we don't want to worry
- // about the non-client view, which leaves just TYPE_WINDOW_FRAMELESS.
- Widget::InitParams params =
- CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
-
- params.bounds = gfx::Rect(100, 100, 100, 100);
- widget_->Init(std::move(params));
- input_method_->SetDelegate(
- test::WidgetTest::GetInputMethodDelegateForWidget(widget_));
- View* container = widget_->SetContentsView(std::make_unique<View>());
- container->AddChildView(textfield_);
- textfield_->SetBoundsRect(params.bounds);
- textfield_->SetID(1);
- test_api_ = std::make_unique<TextfieldTestApi>(textfield_);
-
- for (int i = 1; i < count; i++) {
- Textfield* textfield = new Textfield();
- container->AddChildView(textfield);
- textfield->SetID(i + 1);
- }
+ model_ = test_api_->model();
+ model_->ClearEditHistory();
- model_ = test_api_->model();
- model_->ClearEditHistory();
+ // Since the window type is activatable, showing the widget will also
+ // activate it. Calling Activate directly is insufficient, since that does
+ // not also _focus_ an aura::Window (i.e. using the FocusClient). Both the
+ // widget and the textfield must have focus to properly handle input.
+ widget_->Show();
+ textfield->RequestFocus();
- // Since the window type is activatable, showing the widget will also
- // activate it. Calling Activate directly is insufficient, since that does
- // not also _focus_ an aura::Window (i.e. using the FocusClient). Both the
- // widget and the textfield must have focus to properly handle input.
- widget_->Show();
- textfield_->RequestFocus();
+ event_generator_ =
+ std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_.get()));
+ event_generator_->set_target(ui::test::EventGenerator::Target::WINDOW);
+ event_target_ = textfield;
+}
- event_generator_ =
- std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_));
- event_generator_->set_target(ui::test::EventGenerator::Target::WINDOW);
- }
- ui::MenuModel* GetContextMenuModel() {
- test_api_->UpdateContextMenu();
- return test_api_->context_menu_contents();
- }
+ui::MenuModel* TextfieldTest::GetContextMenuModel() {
+ test_api_->UpdateContextMenu();
+ return test_api_->context_menu_contents();
+}
- // True if native Mac keystrokes should be used (to avoid ifdef litter).
- bool TestingNativeMac() {
+bool TextfieldTest::TestingNativeMac() const {
#if defined(OS_APPLE)
- return true;
+ return true;
#else
- return false;
+ return false;
#endif
- }
+}
- bool TestingNativeCrOs() const {
-#if defined(OS_CHROMEOS)
- return true;
+bool TextfieldTest::TestingNativeCrOs() const {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ return true;
#else
- return false;
-#endif // defined(OS_CHROMEOS)
- }
+ return false;
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+}
- protected:
- void SendKeyPress(ui::KeyboardCode key_code, int flags) {
- event_generator_->PressKey(key_code, flags);
- }
+void TextfieldTest::SendKeyPress(ui::KeyboardCode key_code, int flags) {
+ event_generator_->PressKey(key_code, flags);
+}
- void SendKeyEvent(ui::KeyboardCode key_code,
- bool alt,
- bool shift,
- bool control_or_command,
- bool caps_lock) {
- bool control = control_or_command;
- bool command = false;
-
- // By default, swap control and command for native events on Mac. This
- // handles most cases.
- if (TestingNativeMac())
- std::swap(control, command);
-
- int flags =
- (shift ? ui::EF_SHIFT_DOWN : 0) | (control ? ui::EF_CONTROL_DOWN : 0) |
- (alt ? ui::EF_ALT_DOWN : 0) | (command ? ui::EF_COMMAND_DOWN : 0) |
- (caps_lock ? ui::EF_CAPS_LOCK_ON : 0);
-
- SendKeyPress(key_code, flags);
- }
+void TextfieldTest::SendKeyEvent(ui::KeyboardCode key_code,
+ bool alt,
+ bool shift,
+ bool control_or_command,
+ bool caps_lock) {
+ bool control = control_or_command;
+ bool command = false;
- void SendKeyEvent(ui::KeyboardCode key_code,
- bool shift,
- bool control_or_command) {
- SendKeyEvent(key_code, false, shift, control_or_command, false);
- }
+ // By default, swap control and command for native events on Mac. This
+ // handles most cases.
+ if (TestingNativeMac())
+ std::swap(control, command);
- void SendKeyEvent(ui::KeyboardCode key_code) {
- SendKeyEvent(key_code, false, false);
- }
+ int flags =
+ (shift ? ui::EF_SHIFT_DOWN : 0) | (control ? ui::EF_CONTROL_DOWN : 0) |
+ (alt ? ui::EF_ALT_DOWN : 0) | (command ? ui::EF_COMMAND_DOWN : 0) |
+ (caps_lock ? ui::EF_CAPS_LOCK_ON : 0);
- void SendKeyEvent(base::char16 ch) { SendKeyEvent(ch, ui::EF_NONE, false); }
+ SendKeyPress(key_code, flags);
+}
- void SendKeyEvent(base::char16 ch, int flags) {
- SendKeyEvent(ch, flags, false);
- }
+void TextfieldTest::SendKeyEvent(ui::KeyboardCode key_code,
+ bool shift,
+ bool control_or_command) {
+ SendKeyEvent(key_code, false, shift, control_or_command, false);
+}
+
+void TextfieldTest::SendKeyEvent(ui::KeyboardCode key_code) {
+ SendKeyEvent(key_code, false, false);
+}
+
+void TextfieldTest::SendKeyEvent(base::char16 ch) {
+ SendKeyEvent(ch, ui::EF_NONE, false);
+}
+
+void TextfieldTest::SendKeyEvent(base::char16 ch, int flags) {
+ SendKeyEvent(ch, flags, false);
+}
- void SendKeyEvent(base::char16 ch, int flags, bool from_vk) {
- if (ch < 0x80) {
- ui::KeyboardCode code =
- ch == ' ' ? ui::VKEY_SPACE
- : static_cast<ui::KeyboardCode>(ui::VKEY_A + ch - 'a');
- SendKeyPress(code, flags);
- } else {
- // For unicode characters, assume they come from IME rather than the
- // keyboard. So they are dispatched directly to the input method. But on
- // Mac, key events don't pass through InputMethod. Hence they are
- // dispatched regularly.
- ui::KeyEvent event(ch, ui::VKEY_UNKNOWN, ui::DomCode::NONE, flags);
- if (from_vk) {
- ui::Event::Properties properties;
- properties[ui::kPropertyFromVK] =
- std::vector<uint8_t>(ui::kPropertyFromVKSize);
- event.SetProperties(properties);
- }
+void TextfieldTest::SendKeyEvent(base::char16 ch, int flags, bool from_vk) {
+ if (ch < 0x80) {
+ ui::KeyboardCode code =
+ ch == ' ' ? ui::VKEY_SPACE
+ : static_cast<ui::KeyboardCode>(ui::VKEY_A + ch - 'a');
+ SendKeyPress(code, flags);
+ } else {
+ // For unicode characters, assume they come from IME rather than the
+ // keyboard. So they are dispatched directly to the input method. But on
+ // Mac, key events don't pass through InputMethod. Hence they are
+ // dispatched regularly.
+ ui::KeyEvent event(ch, ui::VKEY_UNKNOWN, ui::DomCode::NONE, flags);
+ if (from_vk) {
+ ui::Event::Properties properties;
+ properties[ui::kPropertyFromVK] =
+ std::vector<uint8_t>(ui::kPropertyFromVKSize);
+ event.SetProperties(properties);
+ }
#if defined(OS_APPLE)
- event_generator_->Dispatch(&event);
+ event_generator_->Dispatch(&event);
#else
- input_method_->DispatchKeyEvent(&event);
+ input_method_->DispatchKeyEvent(&event);
#endif
- }
}
+}
+void TextfieldTest::DispatchMockInputMethodKeyEvent() {
// Send a key to trigger MockInputMethod::DispatchKeyEvent(). Note the
// specific VKEY isn't used (MockInputMethod will mock a ui::VKEY_PROCESSKEY
// whenever it has a test composition). However, on Mac, it can't be a letter
@@ -585,244 +592,220 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
// and don't have a meaningful ui::KeyEvent that would trigger
// DispatchKeyEvent(). It also can't be VKEY_ENTER, since those key events may
// need to be suppressed when interacting with real system IME.
- void DispatchMockInputMethodKeyEvent() { SendKeyEvent(ui::VKEY_INSERT); }
-
- // Sends a platform-specific move (and select) to the logical start of line.
- // Eg. this should move (and select) to the right end of line for RTL text.
- void SendHomeEvent(bool shift) {
- if (TestingNativeMac()) {
- // [NSResponder moveToBeginningOfLine:] is the correct way to do this on
- // Mac, but that doesn't have a default key binding. Since
- // views::Textfield doesn't currently support multiple lines, the same
- // effect can be achieved by Cmd+Up which maps to
- // [NSResponder moveToBeginningOfDocument:].
- SendKeyEvent(ui::VKEY_UP, shift /* shift */, true /* command */);
- return;
- }
- SendKeyEvent(ui::VKEY_HOME, shift /* shift */, false /* control */);
- }
+ SendKeyEvent(ui::VKEY_INSERT);
+}
- // Sends a platform-specific move (and select) to the logical end of line.
- void SendEndEvent(bool shift) {
- if (TestingNativeMac()) {
- SendKeyEvent(ui::VKEY_DOWN, shift, true); // Cmd+Down.
- return;
- }
- SendKeyEvent(ui::VKEY_END, shift, false);
+// Sends a platform-specific move (and select) to the logical start of line.
+// Eg. this should move (and select) to the right end of line for RTL text.
+void TextfieldTest::SendHomeEvent(bool shift) {
+ if (TestingNativeMac()) {
+ // [NSResponder moveToBeginningOfLine:] is the correct way to do this on
+ // Mac, but that doesn't have a default key binding. Since
+ // views::Textfield doesn't currently support multiple lines, the same
+ // effect can be achieved by Cmd+Up which maps to
+ // [NSResponder moveToBeginningOfDocument:].
+ SendKeyEvent(ui::VKEY_UP, shift /* shift */, true /* command */);
+ return;
}
+ SendKeyEvent(ui::VKEY_HOME, shift /* shift */, false /* control */);
+}
- // Sends {delete, move, select} word {forward, backward}.
- void SendWordEvent(ui::KeyboardCode key, bool shift) {
- bool alt = false;
- bool control = true;
- bool caps = false;
- if (TestingNativeMac()) {
- // Use Alt+Left/Right/Backspace on native Mac.
- alt = true;
- control = false;
- }
- SendKeyEvent(key, alt, shift, control, caps);
+// Sends a platform-specific move (and select) to the logical end of line.
+void TextfieldTest::SendEndEvent(bool shift) {
+ if (TestingNativeMac()) {
+ SendKeyEvent(ui::VKEY_DOWN, shift, true); // Cmd+Down.
+ return;
}
+ SendKeyEvent(ui::VKEY_END, shift, false);
+}
- // Sends Shift+Delete if supported, otherwise Cmd+X again.
- void SendAlternateCut() {
- if (TestingNativeMac())
- SendKeyEvent(ui::VKEY_X, false, true);
- else
- SendKeyEvent(ui::VKEY_DELETE, true, false);
+// Sends {delete, move, select} word {forward, backward}.
+void TextfieldTest::SendWordEvent(ui::KeyboardCode key, bool shift) {
+ bool alt = false;
+ bool control = true;
+ bool caps = false;
+ if (TestingNativeMac()) {
+ // Use Alt+Left/Right/Backspace on native Mac.
+ alt = true;
+ control = false;
}
+ SendKeyEvent(key, alt, shift, control, caps);
+}
- // Sends Ctrl+Insert if supported, otherwise Cmd+C again.
- void SendAlternateCopy() {
- if (TestingNativeMac())
- SendKeyEvent(ui::VKEY_C, false, true);
- else
- SendKeyEvent(ui::VKEY_INSERT, false, true);
- }
+// Sends Shift+Delete if supported, otherwise Cmd+X again.
+void TextfieldTest::SendAlternateCut() {
+ if (TestingNativeMac())
+ SendKeyEvent(ui::VKEY_X, false, true);
+ else
+ SendKeyEvent(ui::VKEY_DELETE, true, false);
+}
- // Sends Shift+Insert if supported, otherwise Cmd+V again.
- void SendAlternatePaste() {
- if (TestingNativeMac())
- SendKeyEvent(ui::VKEY_V, false, true);
- else
- SendKeyEvent(ui::VKEY_INSERT, true, false);
- }
+// Sends Ctrl+Insert if supported, otherwise Cmd+C again.
+void TextfieldTest::SendAlternateCopy() {
+ if (TestingNativeMac())
+ SendKeyEvent(ui::VKEY_C, false, true);
+ else
+ SendKeyEvent(ui::VKEY_INSERT, false, true);
+}
- View* GetFocusedView() {
- return widget_->GetFocusManager()->GetFocusedView();
- }
+// Sends Shift+Insert if supported, otherwise Cmd+V again.
+void TextfieldTest::SendAlternatePaste() {
+ if (TestingNativeMac())
+ SendKeyEvent(ui::VKEY_V, false, true);
+ else
+ SendKeyEvent(ui::VKEY_INSERT, true, false);
+}
- int GetCursorPositionX(int cursor_pos) {
- return test_api_->GetRenderText()
- ->GetCursorBounds(gfx::SelectionModel(cursor_pos, gfx::CURSOR_FORWARD),
- false)
- .x();
- }
+View* TextfieldTest::GetFocusedView() {
+ return widget_->GetFocusManager()->GetFocusedView();
+}
- int GetCursorYForTesting() {
- return test_api_->GetRenderText()->GetLineOffset(0).y() + 1;
- }
+int TextfieldTest::GetCursorPositionX(int cursor_pos) {
+ return test_api_->GetRenderText()
+ ->GetCursorBounds(gfx::SelectionModel(cursor_pos, gfx::CURSOR_FORWARD),
+ false)
+ .x();
+}
- // Get the current cursor bounds.
- gfx::Rect GetCursorBounds() {
- return test_api_->GetRenderText()->GetUpdatedCursorBounds();
- }
+int TextfieldTest::GetCursorYForTesting() {
+ return test_api_->GetRenderText()->GetLineOffset(0).y() + 1;
+}
- // Get the cursor bounds of |sel|.
- gfx::Rect GetCursorBounds(const gfx::SelectionModel& sel) {
- return test_api_->GetRenderText()->GetCursorBounds(sel, true);
- }
+gfx::Rect TextfieldTest::GetCursorBounds() {
+ return test_api_->GetRenderText()->GetUpdatedCursorBounds();
+}
- gfx::Rect GetDisplayRect() {
- return test_api_->GetRenderText()->display_rect();
- }
+// Gets the cursor bounds of |sel|.
+gfx::Rect TextfieldTest::GetCursorBounds(const gfx::SelectionModel& sel) {
+ return test_api_->GetRenderText()->GetCursorBounds(sel, true);
+}
+
+gfx::Rect TextfieldTest::GetDisplayRect() {
+ return test_api_->GetRenderText()->display_rect();
+}
+
+gfx::Rect TextfieldTest::GetCursorViewRect() {
+ return test_api_->GetCursorViewRect();
+}
- // Mouse click on the point whose x-axis is |bound|'s x plus |x_offset| and
- // y-axis is in the middle of |bound|'s vertical range.
- void MouseClick(const gfx::Rect bound, int x_offset) {
- gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2);
- ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point,
+// Performs a mouse click on the point whose x-axis is |bound|'s x plus
+// |x_offset| and y-axis is in the middle of |bound|'s vertical range.
+void TextfieldTest::MouseClick(const gfx::Rect bound, int x_offset) {
+ gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2);
+ ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point,
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ event_target_->OnMousePressed(click);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point,
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
- textfield_->OnMousePressed(click);
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point,
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_->OnMouseReleased(release);
- }
+ event_target_->OnMouseReleased(release);
+}
- // This is to avoid double/triple click.
- void NonClientMouseClick() {
- ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+// This is to avoid double/triple click.
+void TextfieldTest::NonClientMouseClick() {
+ ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(),
+ ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ event_target_->OnMousePressed(click);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(),
ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT,
ui::EF_LEFT_MOUSE_BUTTON);
- textfield_->OnMousePressed(click);
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
- ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_->OnMouseReleased(release);
- }
+ event_target_->OnMouseReleased(release);
+}
- void VerifyTextfieldContextMenuContents(bool textfield_has_selection,
- bool can_undo,
- ui::MenuModel* menu) {
- const auto& text = textfield_->GetText();
- const bool is_all_selected =
- !text.empty() &&
- textfield_->GetSelectedRange().length() == text.length();
+void TextfieldTest::VerifyTextfieldContextMenuContents(
+ bool textfield_has_selection,
+ bool can_undo,
+ ui::MenuModel* menu) {
+ const auto& text = textfield_->GetText();
+ const bool is_all_selected =
+ !text.empty() && textfield_->GetSelectedRange().length() == text.length();
- int menu_index = 0;
+ int menu_index = 0;
#if defined(OS_APPLE)
- 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 */));
- }
-
- EXPECT_EQ(can_undo, menu->IsEnabledAt(menu_index++ /* UNDO */));
- EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Separator */));
- EXPECT_EQ(textfield_has_selection,
- menu->IsEnabledAt(menu_index++ /* CUT */));
- EXPECT_EQ(textfield_has_selection,
- menu->IsEnabledAt(menu_index++ /* COPY */));
- EXPECT_NE(GetClipboardText(ui::ClipboardBuffer::kCopyPaste).empty(),
- menu->IsEnabledAt(menu_index++ /* PASTE */));
- EXPECT_EQ(textfield_has_selection,
- menu->IsEnabledAt(menu_index++ /* DELETE */));
+ if (textfield_has_selection) {
+ EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Look Up "Selection" */));
EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Separator */));
- EXPECT_EQ(!is_all_selected,
- menu->IsEnabledAt(menu_index++ /* SELECT ALL */));
- }
-
- void PressMouseButton(ui::EventFlags mouse_button_flags) {
- ui::MouseEvent press(ui::ET_MOUSE_PRESSED, mouse_position_, mouse_position_,
- ui::EventTimeForNow(), mouse_button_flags,
- mouse_button_flags);
- textfield_->OnMousePressed(press);
- }
-
- void ReleaseMouseButton(ui::EventFlags mouse_button_flags) {
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, mouse_position_,
- mouse_position_, ui::EventTimeForNow(),
- mouse_button_flags, mouse_button_flags);
- textfield_->OnMouseReleased(release);
- }
-
- void PressLeftMouseButton() { PressMouseButton(ui::EF_LEFT_MOUSE_BUTTON); }
-
- void ReleaseLeftMouseButton() {
- ReleaseMouseButton(ui::EF_LEFT_MOUSE_BUTTON);
- }
-
- void ClickLeftMouseButton() {
- PressLeftMouseButton();
- ReleaseLeftMouseButton();
- }
-
- void ClickRightMouseButton() {
- PressMouseButton(ui::EF_RIGHT_MOUSE_BUTTON);
- ReleaseMouseButton(ui::EF_RIGHT_MOUSE_BUTTON);
}
+#endif
- void DragMouseTo(const gfx::Point& where) {
- mouse_position_ = where;
- ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, where, where,
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
- textfield_->OnMouseDragged(drag);
+ if (ui::IsEmojiPanelSupported()) {
+ EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* EMOJI */));
+ EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Separator */));
}
- // Textfield does not listen to OnMouseMoved, so this function does not send
- // an event when it updates the cursor position.
- void MoveMouseTo(const gfx::Point& where) { mouse_position_ = where; }
-
- // Tap on the textfield.
- void TapAtCursor(ui::EventPointerType pointer_type) {
- ui::GestureEventDetails tap_down_details(ui::ET_GESTURE_TAP_DOWN);
- tap_down_details.set_primary_pointer_type(pointer_type);
- GestureEventForTest tap_down(GetCursorPositionX(0), 0, tap_down_details);
- textfield_->OnGestureEvent(&tap_down);
+ EXPECT_EQ(can_undo, menu->IsEnabledAt(menu_index++ /* UNDO */));
+ EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Separator */));
+ EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(menu_index++ /* CUT */));
+ EXPECT_EQ(textfield_has_selection,
+ menu->IsEnabledAt(menu_index++ /* COPY */));
+ EXPECT_NE(GetClipboardText(ui::ClipboardBuffer::kCopyPaste).empty(),
+ menu->IsEnabledAt(menu_index++ /* PASTE */));
+ EXPECT_EQ(textfield_has_selection,
+ menu->IsEnabledAt(menu_index++ /* DELETE */));
+ EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Separator */));
+ EXPECT_EQ(!is_all_selected, menu->IsEnabledAt(menu_index++ /* SELECT ALL */));
+}
- ui::GestureEventDetails tap_up_details(ui::ET_GESTURE_TAP);
- tap_up_details.set_primary_pointer_type(pointer_type);
- GestureEventForTest tap_up(GetCursorPositionX(0), 0, tap_up_details);
- textfield_->OnGestureEvent(&tap_up);
- }
+void TextfieldTest::PressMouseButton(ui::EventFlags mouse_button_flags) {
+ ui::MouseEvent press(ui::ET_MOUSE_PRESSED, mouse_position_, mouse_position_,
+ ui::EventTimeForNow(), mouse_button_flags,
+ mouse_button_flags);
+ event_target_->OnMousePressed(press);
+}
- // We need widget to populate wrapper class.
- Widget* widget_ = nullptr;
+void TextfieldTest::ReleaseMouseButton(ui::EventFlags mouse_button_flags) {
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, mouse_position_,
+ mouse_position_, ui::EventTimeForNow(),
+ mouse_button_flags, mouse_button_flags);
+ event_target_->OnMouseReleased(release);
+}
- TestTextfield* textfield_ = nullptr;
- std::unique_ptr<TextfieldTestApi> test_api_;
- TextfieldModel* model_ = nullptr;
+void TextfieldTest::PressLeftMouseButton() {
+ PressMouseButton(ui::EF_LEFT_MOUSE_BUTTON);
+}
- // The string from Controller::ContentsChanged callback.
- base::string16 last_contents_;
+void TextfieldTest::ReleaseLeftMouseButton() {
+ ReleaseMouseButton(ui::EF_LEFT_MOUSE_BUTTON);
+}
- // For testing input method related behaviors.
- MockInputMethod* input_method_ = nullptr;
+void TextfieldTest::ClickLeftMouseButton() {
+ PressLeftMouseButton();
+ ReleaseLeftMouseButton();
+}
- // Indicates how many times OnBeforeUserAction() is called.
- int on_before_user_action_ = 0;
+void TextfieldTest::ClickRightMouseButton() {
+ PressMouseButton(ui::EF_RIGHT_MOUSE_BUTTON);
+ ReleaseMouseButton(ui::EF_RIGHT_MOUSE_BUTTON);
+}
- // Indicates how many times OnAfterUserAction() is called.
- int on_after_user_action_ = 0;
+void TextfieldTest::DragMouseTo(const gfx::Point& where) {
+ mouse_position_ = where;
+ ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, where, where, ui::EventTimeForNow(),
+ ui::EF_LEFT_MOUSE_BUTTON, 0);
+ event_target_->OnMouseDragged(drag);
+}
- // Position of the mouse for synthetic mouse events.
- gfx::Point mouse_position_;
- ui::ClipboardBuffer copied_to_clipboard_ = ui::ClipboardBuffer::kMaxValue;
- std::unique_ptr<ui::test::EventGenerator> event_generator_;
+void TextfieldTest::MoveMouseTo(const gfx::Point& where) {
+ mouse_position_ = where;
+}
- private:
- DISALLOW_COPY_AND_ASSIGN(TextfieldTest);
-};
+// Taps on the textfield.
+void TextfieldTest::TapAtCursor(ui::EventPointerType pointer_type) {
+ ui::GestureEventDetails tap_down_details(ui::ET_GESTURE_TAP_DOWN);
+ tap_down_details.set_primary_pointer_type(pointer_type);
+ GestureEventForTest tap_down(GetCursorPositionX(0), 0, tap_down_details);
+ textfield_->OnGestureEvent(&tap_down);
+
+ ui::GestureEventDetails tap_up_details(ui::ET_GESTURE_TAP);
+ tap_up_details.set_primary_pointer_type(pointer_type);
+ GestureEventForTest tap_up(GetCursorPositionX(0), 0, tap_up_details);
+ textfield_->OnGestureEvent(&tap_up);
+}
TEST_F(TextfieldTest, ModelChangesTest) {
InitTextfield();
@@ -1297,16 +1280,16 @@ TEST_F(TextfieldTest, ModifySelectionWithMultipleSelections) {
TEST_F(TextfieldTest, InsertionDeletionTest) {
// Insert a test string in a textfield.
InitTextfield();
- for (size_t i = 0; i < 10; i++)
+ for (size_t i = 0; i < 10; ++i)
SendKeyEvent(static_cast<ui::KeyboardCode>(ui::VKEY_A + i));
EXPECT_STR_EQ("abcdefghij", textfield_->GetText());
// Test the delete and backspace keys.
textfield_->SetSelectedRange(gfx::Range(5));
- for (size_t i = 0; i < 3; i++)
+ for (size_t i = 0; i < 3; ++i)
SendKeyEvent(ui::VKEY_BACK);
EXPECT_STR_EQ("abfghij", textfield_->GetText());
- for (size_t i = 0; i < 3; i++)
+ for (size_t i = 0; i < 3; ++i)
SendKeyEvent(ui::VKEY_DELETE);
EXPECT_STR_EQ("abij", textfield_->GetText());
@@ -1586,7 +1569,9 @@ TEST_F(TextfieldTest, OnKeyPress) {
TEST_F(TextfieldTest, OnKeyPressBinding) {
InitTextfield();
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Install a TextEditKeyBindingsDelegateAuraLinux that does nothing.
class TestDelegate : public ui::TextEditKeyBindingsDelegateAuraLinux {
public:
@@ -1624,7 +1609,9 @@ TEST_F(TextfieldTest, OnKeyPressBinding) {
EXPECT_STR_EQ("a", textfield_->GetText());
textfield_->clear();
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
ui::SetTextEditKeyBindingsDelegate(nullptr);
#endif
}
@@ -1734,7 +1721,7 @@ TEST_F(TextfieldTest, ShouldShowCursor) {
}
TEST_F(TextfieldTest, FocusTraversalTest) {
- InitTextfields(3);
+ InitTextfield(3);
textfield_->RequestFocus();
EXPECT_EQ(1, GetFocusedView()->GetID());
@@ -1966,7 +1953,7 @@ TEST_F(TextfieldTest, DragAndDrop_AcceptDrop) {
ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE);
EXPECT_EQ(ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE,
textfield_->OnDragUpdated(drop));
- EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, textfield_->OnPerformDrop(drop));
+ EXPECT_EQ(ui::mojom::DragOperation::kCopy, textfield_->OnPerformDrop(drop));
EXPECT_STR_EQ("hello string world", textfield_->GetText());
// Ensure that textfields do not accept non-OSExchangeData::STRING types.
@@ -2059,7 +2046,7 @@ TEST_F(TextfieldTest, DragAndDrop_ToTheRight) {
EXPECT_TRUE(textfield_->CanDrop(data));
ui::DropTargetEvent drop_a(data, kDropPoint, kDropPoint, operations);
EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a));
+ EXPECT_EQ(ui::mojom::DragOperation::kMove, textfield_->OnPerformDrop(drop_a));
EXPECT_STR_EQ("h welloorld", textfield_->GetText());
textfield_->OnDragDone();
@@ -2110,7 +2097,7 @@ TEST_F(TextfieldTest, DragAndDrop_ToTheLeft) {
gfx::PointF drop_point(GetCursorPositionX(1), cursor_y);
ui::DropTargetEvent drop_a(data, drop_point, drop_point, operations);
EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a));
+ EXPECT_EQ(ui::mojom::DragOperation::kMove, textfield_->OnPerformDrop(drop_a));
EXPECT_STR_EQ("h worlellod", textfield_->GetText());
textfield_->OnDragDone();
@@ -2453,7 +2440,7 @@ TEST_F(TextfieldTest, RedoWithCtrlY) {
#if defined(OS_APPLE)
TEST_F(TextfieldTest, Yank) {
- InitTextfields(2);
+ InitTextfield(2);
textfield_->SetText(ASCIIToUTF16("abcdef"));
textfield_->SetSelectedRange(gfx::Range(2, 4));
@@ -2996,7 +2983,7 @@ TEST_F(TextfieldTest, CommitEmptyComposingTextTest) {
EXPECT_EQ(composed_text_length, static_cast<uint32_t>(0));
}
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
// SetCompositionFromExistingText is only available on Windows and Chrome OS.
TEST_F(TextfieldTest, SetCompositionFromExistingTextTest) {
InitTextfield();
@@ -3081,121 +3068,55 @@ TEST_F(TextfieldTest, GetCompositionCharacterBounds_ComplexText) {
// - rects[6] == rects[7]
}
-#if defined(OS_CHROMEOS)
-TEST_F(TextfieldTest, SetAutocorrectRangeText) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(TextfieldTest, SetAutocorrectRange) {
InitTextfield();
- ui::CompositionText composition;
- composition.text = UTF8ToUTF16("Initial txt");
- textfield_->SetCompositionText(composition);
- textfield_->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
- gfx::Range(8, 11));
+ textfield_->SetText(ASCIIToUTF16("abc def ghi"));
+ textfield_->SetAutocorrectRange(gfx::Range(4, 7));
gfx::Range autocorrect_range = textfield_->GetAutocorrectRange();
- EXPECT_EQ(autocorrect_range, gfx::Range(8, 24));
-
- base::string16 text;
- textfield_->GetTextFromRange(gfx::Range(0, 24), &text);
- EXPECT_EQ(text, UTF8ToUTF16("Initial text replacement"));
-}
-
-TEST_F(TextfieldTest, SetAutocorrectRangeExplicitlySet) {
- InitTextfield();
- textfield_->InsertText(UTF8ToUTF16("Initial txt"));
- textfield_->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
- gfx::Range(8, 11));
-
- gfx::Range autocorrectRange = textfield_->GetAutocorrectRange();
- EXPECT_EQ(autocorrectRange, gfx::Range(8, 24));
-
- base::string16 text;
- textfield_->GetTextFromRange(gfx::Range(0, 24), &text);
- EXPECT_EQ(text, UTF8ToUTF16("Initial text replacement"));
+ EXPECT_EQ(autocorrect_range, gfx::Range(4, 7));
}
TEST_F(TextfieldTest, DoesNotSetAutocorrectRangeWhenRangeGivenIsInvalid) {
InitTextfield();
- ui::CompositionText composition;
- composition.text = UTF8ToUTF16("Initial");
- textfield_->SetCompositionText(composition);
-
- EXPECT_FALSE(textfield_->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
- gfx::Range(8, 11)));
- EXPECT_EQ(gfx::Range(0, 0), textfield_->GetAutocorrectRange());
- gfx::Range range;
- textfield_->GetTextRange(&range);
- base::string16 text;
- textfield_->GetTextFromRange(range, &text);
- EXPECT_EQ(composition.text, text);
-}
-
-TEST_F(TextfieldTest,
- ClearsAutocorrectRangeWhenSetAutocorrectRangeWithEmptyText) {
- InitTextfield();
-
- ui::CompositionText composition;
- composition.text = UTF8ToUTF16("Initial");
- textfield_->SetCompositionText(composition);
+ textfield_->SetText(ASCIIToUTF16("abc"));
- EXPECT_TRUE(
- textfield_->SetAutocorrectRange(base::EmptyString16(), gfx::Range(0, 2)));
- EXPECT_EQ(gfx::Range(0, 0), textfield_->GetAutocorrectRange());
- gfx::Range range;
- textfield_->GetTextRange(&range);
- base::string16 text;
- textfield_->GetTextFromRange(range, &text);
- EXPECT_EQ(composition.text, text);
+ EXPECT_FALSE(textfield_->SetAutocorrectRange(gfx::Range(8, 11)));
+ EXPECT_TRUE(textfield_->GetAutocorrectRange().is_empty());
}
TEST_F(TextfieldTest,
ClearsAutocorrectRangeWhenSetAutocorrectRangeWithEmptyRange) {
InitTextfield();
- ui::CompositionText composition;
- composition.text = UTF8ToUTF16("Initial");
- textfield_->SetCompositionText(composition);
-
- EXPECT_TRUE(
- textfield_->SetAutocorrectRange(UTF8ToUTF16("Test"), gfx::Range(0, 0)));
- EXPECT_EQ(gfx::Range(0, 0), textfield_->GetAutocorrectRange());
- gfx::Range range;
- textfield_->GetTextRange(&range);
- base::string16 text;
- textfield_->GetTextFromRange(range, &text);
- EXPECT_EQ(composition.text, text);
-}
-
-TEST_F(TextfieldTest, ClearAutocorrectRange) {
- InitTextfield();
- textfield_->InsertText(UTF8ToUTF16("Initial txt"));
- textfield_->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
- gfx::Range(8, 11));
-
- EXPECT_EQ(textfield_->GetText(), UTF8ToUTF16("Initial text replacement"));
- EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range(8, 24));
-
- textfield_->ClearAutocorrectRange();
+ textfield_->SetText(ASCIIToUTF16("abc"));
- EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range());
+ EXPECT_TRUE(textfield_->SetAutocorrectRange(gfx::Range()));
+ EXPECT_TRUE(textfield_->GetAutocorrectRange().is_empty());
}
TEST_F(TextfieldTest, GetAutocorrectCharacterBoundsTest) {
InitTextfield();
- textfield_->InsertText(UTF8ToUTF16("hello placeholder text"));
- textfield_->SetAutocorrectRange(ASCIIToUTF16("longlonglongtext"),
- gfx::Range(3, 10));
+ textfield_->InsertText(
+ UTF8ToUTF16("hello placeholder text"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+ textfield_->SetAutocorrectRange(gfx::Range(3, 10));
- EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range(3, 19));
+ EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range(3, 10));
gfx::Rect rect_for_long_text = textfield_->GetAutocorrectCharacterBounds();
// Clear the text
textfield_->DeleteRange(gfx::Range(0, 99));
- textfield_->InsertText(UTF8ToUTF16("hello placeholder text"));
- textfield_->SetAutocorrectRange(ASCIIToUTF16("short"), gfx::Range(3, 10));
+ textfield_->InsertText(
+ UTF8ToUTF16("hello placeholder text"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+ textfield_->SetAutocorrectRange(gfx::Range(3, 8));
EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range(3, 8));
@@ -3214,7 +3135,7 @@ TEST_F(TextfieldTest, GetAutocorrectCharacterBoundsTest) {
// TODO(crbug.com/1108170): Add a test to check that when the composition /
// surrounding text is updated, the AutocorrectRange is updated accordingly.
-#endif // OS_CHROMEOS
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// The word we select by double clicking should remain selected regardless of
// where we drag the mouse afterwards without releasing the left button.
@@ -3241,7 +3162,9 @@ TEST_F(TextfieldTest, KeepInitiallySelectedWord) {
EXPECT_EQ(gfx::Range(7, 0), textfield_->GetSelectedRange());
}
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
TEST_F(TextfieldTest, SelectionClipboard) {
InitTextfield();
textfield_->SetText(ASCIIToUTF16("0123"));
@@ -3386,7 +3309,7 @@ TEST_F(TextfieldTest, SelectionClipboard) {
// Verify that the selection clipboard is not updated for selections on a
// password textfield.
TEST_F(TextfieldTest, SelectionClipboard_Password) {
- InitTextfields(2);
+ InitTextfield(2);
textfield_->SetText(ASCIIToUTF16("abcd"));
// Select-all should update the selection clipboard for a non-password
@@ -3501,13 +3424,13 @@ TEST_F(TextfieldTest, SetAccessibleNameNotifiesAccessibilityEvent) {
EXPECT_EQ(test_tooltip_text, ASCIIToUTF16(name));
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Check that when accessibility virtual keyboard is enabled, windows are
// shifted up when focused and restored when focus is lost.
TEST_F(TextfieldTest, VirtualKeyboardFocusEnsureCaretNotInRect) {
InitTextfield();
- aura::Window* root_window = GetRootWindow(widget_);
+ aura::Window* root_window = GetRootWindow(widget_.get());
int keyboard_height = 200;
gfx::Rect root_bounds = root_window->bounds();
gfx::Rect orig_widget_bounds = gfx::Rect(0, 300, 400, 200);
@@ -3535,7 +3458,7 @@ TEST_F(TextfieldTest, VirtualKeyboardFocusEnsureCaretNotInRect) {
// Window should be restored.
EXPECT_EQ(widget_->GetNativeView()->bounds(), orig_widget_bounds);
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
class TextfieldTouchSelectionTest : public TextfieldTest {
protected:
@@ -3566,7 +3489,7 @@ class TextfieldTouchSelectionTest : public TextfieldTest {
};
// Touch selection and dragging currently only works for chromeos.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(TextfieldTouchSelectionTest, TouchSelectionAndDraggingTest) {
InitTextfield();
textfield_->SetText(ASCIIToUTF16("hello world"));
@@ -3802,17 +3725,13 @@ TEST_F(TextfieldTest, TextfieldBoundsChangeTest) {
// Verify that after creating a new Textfield, the Textfield doesn't
// automatically receive focus and the text cursor is not visible.
TEST_F(TextfieldTest, TextfieldInitialization) {
- TestTextfield* new_textfield = new TestTextfield();
- new_textfield->set_controller(this);
- Widget* widget(new Widget());
- Widget::InitParams params =
- CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params.bounds = gfx::Rect(100, 100, 100, 100);
- widget->Init(std::move(params));
+ std::unique_ptr<Widget> widget = CreateTestWidget();
View* container = widget->SetContentsView(std::make_unique<View>());
- container->AddChildView(new_textfield);
- new_textfield->SetBoundsRect(params.bounds);
+ TestTextfield* new_textfield =
+ container->AddChildView(std::make_unique<TestTextfield>());
+ new_textfield->set_controller(this);
+ new_textfield->SetBoundsRect(gfx::Rect(100, 100, 100, 100));
new_textfield->SetID(1);
test_api_ = std::make_unique<TextfieldTestApi>(new_textfield);
widget->Show();
@@ -4070,6 +3989,7 @@ TEST_F(TextfieldTest, FocusReasonMultipleEvents) {
EXPECT_EQ(ui::TextInputClient::FOCUS_REASON_NONE,
textfield_->GetFocusReason());
+ // Pen tap, followed by a touch tap.
TapAtCursor(ui::EventPointerType::kPen);
TapAtCursor(ui::EventPointerType::kTouch);
EXPECT_EQ(ui::TextInputClient::FOCUS_REASON_PEN,
@@ -4123,6 +4043,32 @@ TEST_F(TextfieldTest, ChangeTextDirectionAndLayoutAlignmentTest) {
base::i18n::TextDirection::LEFT_TO_RIGHT);
EXPECT_EQ(textfield_->GetHorizontalAlignment(),
gfx::HorizontalAlignment::ALIGN_LEFT);
+
+ // If the text is center-aligned, only the text direction should change.
+ textfield_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
+ textfield_->ChangeTextDirectionAndLayoutAlignment(
+ base::i18n::TextDirection::RIGHT_TO_LEFT);
+ EXPECT_EQ(textfield_->GetTextDirection(),
+ base::i18n::TextDirection::RIGHT_TO_LEFT);
+ EXPECT_EQ(textfield_->GetHorizontalAlignment(),
+ gfx::HorizontalAlignment::ALIGN_CENTER);
+
+ // If the text is aligned to the text direction, its alignment should change
+ // iff the text direction changes. We test both scenarios.
+ auto dir = base::i18n::TextDirection::RIGHT_TO_LEFT;
+ auto opposite_dir = base::i18n::TextDirection::LEFT_TO_RIGHT;
+ EXPECT_EQ(textfield_->GetTextDirection(), dir);
+ textfield_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
+ textfield_->ChangeTextDirectionAndLayoutAlignment(opposite_dir);
+ EXPECT_EQ(textfield_->GetTextDirection(), opposite_dir);
+ EXPECT_NE(textfield_->GetHorizontalAlignment(), gfx::ALIGN_TO_HEAD);
+
+ dir = base::i18n::TextDirection::LEFT_TO_RIGHT;
+ EXPECT_EQ(textfield_->GetTextDirection(), dir);
+ textfield_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
+ textfield_->ChangeTextDirectionAndLayoutAlignment(dir);
+ EXPECT_EQ(textfield_->GetTextDirection(), dir);
+ EXPECT_EQ(textfield_->GetHorizontalAlignment(), gfx::ALIGN_TO_HEAD);
}
TEST_F(TextfieldTest, TextChangedCallbackTest) {
@@ -4154,9 +4100,53 @@ TEST_F(TextfieldTest, TextChangedCallbackTest) {
TEST_F(TextfieldTest, InsertInvalidCharsTest) {
InitTextfield();
- textfield_->InsertText(ASCIIToUTF16("\babc\ndef\t"));
+ textfield_->InsertText(
+ ASCIIToUTF16("\babc\ndef\t"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_EQ(textfield_->GetText(), ASCIIToUTF16("abcdef"));
}
+TEST_F(TextfieldTest, ScrollCommands) {
+ InitTextfield();
+
+ // Scroll commands are only available on Mac.
+#if defined(OS_APPLE)
+ textfield_->SetText(ASCIIToUTF16("12 34567 89"));
+ textfield_->SetEditableSelectionRange(gfx::Range(6));
+
+ EXPECT_TRUE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::SCROLL_PAGE_UP));
+ EXPECT_TRUE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::SCROLL_PAGE_DOWN));
+ EXPECT_TRUE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::SCROLL_TO_BEGINNING_OF_DOCUMENT));
+ EXPECT_TRUE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::SCROLL_TO_END_OF_DOCUMENT));
+
+ test_api_->ExecuteTextEditCommand(ui::TextEditCommand::SCROLL_PAGE_UP);
+ EXPECT_EQ(textfield_->GetCursorPosition(), 0u);
+
+ test_api_->ExecuteTextEditCommand(ui::TextEditCommand::SCROLL_PAGE_DOWN);
+ EXPECT_EQ(textfield_->GetCursorPosition(), 11u);
+
+ test_api_->ExecuteTextEditCommand(
+ ui::TextEditCommand::SCROLL_TO_BEGINNING_OF_DOCUMENT);
+ EXPECT_EQ(textfield_->GetCursorPosition(), 0u);
+
+ test_api_->ExecuteTextEditCommand(
+ ui::TextEditCommand::SCROLL_TO_END_OF_DOCUMENT);
+ EXPECT_EQ(textfield_->GetCursorPosition(), 11u);
+#else
+ EXPECT_FALSE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::SCROLL_PAGE_UP));
+ EXPECT_FALSE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::SCROLL_PAGE_DOWN));
+ EXPECT_FALSE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::SCROLL_TO_BEGINNING_OF_DOCUMENT));
+ EXPECT_FALSE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::SCROLL_TO_END_OF_DOCUMENT));
+#endif
+}
+} // namespace test
} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.h b/chromium/ui/views/controls/textfield/textfield_unittest.h
new file mode 100644
index 00000000000..daea3478371
--- /dev/null
+++ b/chromium/ui/views/controls/textfield/textfield_unittest.h
@@ -0,0 +1,184 @@
+// 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_CONTROLS_TEXTFIELD_TEXTFIELD_UNITTEST_H_
+#define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_UNITTEST_H_
+
+#include "ui/views/controls/textfield/textfield.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/events/event_constants.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/test/views_test_base.h"
+
+#define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(base::ASCIIToUTF16(ascii), utf16)
+
+namespace ui {
+namespace test {
+class EventGenerator;
+}
+} // namespace ui
+
+namespace views {
+
+class TextfieldTestApi;
+
+namespace test {
+
+class MockInputMethod;
+class TestTextfield;
+
+class TextfieldTest : public ViewsTestBase, public TextfieldController {
+ public:
+ TextfieldTest();
+ ~TextfieldTest() override;
+
+ // ViewsTestBase:
+ void SetUp() override;
+ void TearDown() override;
+
+ ui::ClipboardBuffer GetAndResetCopiedToClipboard();
+ base::string16 GetClipboardText(ui::ClipboardBuffer type);
+ void SetClipboardText(ui::ClipboardBuffer type, const std::string& text);
+
+ // TextfieldController:
+ void ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) override;
+ void OnBeforeUserAction(Textfield* sender) override;
+ void OnAfterUserAction(Textfield* sender) override;
+ void OnAfterCutOrCopy(ui::ClipboardBuffer clipboard_type) override;
+
+ void InitTextfield(int count = 1);
+ ui::MenuModel* GetContextMenuModel();
+
+ bool TestingNativeMac() const;
+ bool TestingNativeCrOs() const;
+
+ template <typename T>
+ T* PrepareTextfields(int count,
+ std::unique_ptr<T> textfield_owned,
+ gfx::Rect bounds) {
+ widget_ = CreateTestWidget();
+ widget_->SetBounds(bounds);
+
+ View* container = widget_->SetContentsView(std::make_unique<View>());
+ T* textfield = container->AddChildView(std::move(textfield_owned));
+
+ PrepareTextfieldsInternal(count, textfield, container, bounds);
+
+ return textfield;
+ }
+
+ protected:
+ void PrepareTextfieldsInternal(int count,
+ Textfield* textfield,
+ View* view,
+ gfx::Rect bounds);
+
+ void SendKeyPress(ui::KeyboardCode key_code, int flags);
+ void SendKeyEvent(ui::KeyboardCode key_code,
+ bool alt,
+ bool shift,
+ bool control_or_command,
+ bool caps_lock);
+ void SendKeyEvent(ui::KeyboardCode key_code,
+ bool shift,
+ bool control_or_command);
+ void SendKeyEvent(ui::KeyboardCode key_code);
+ void SendKeyEvent(base::char16 ch);
+ void SendKeyEvent(base::char16 ch, int flags);
+ void SendKeyEvent(base::char16 ch, int flags, bool from_vk);
+ void DispatchMockInputMethodKeyEvent();
+
+ // Sends a platform-specific move (and select) to the logical start of line.
+ // Eg. this should move (and select) to the right end of line for RTL text.
+ virtual void SendHomeEvent(bool shift);
+
+ // Sends a platform-specific move (and select) to the logical end of line.
+ virtual void SendEndEvent(bool shift);
+
+ // Sends {delete, move, select} word {forward, backward}.
+ void SendWordEvent(ui::KeyboardCode key, bool shift);
+
+ // Sends Shift+Delete if supported, otherwise Cmd+X again.
+ void SendAlternateCut();
+
+ // Sends Ctrl+Insert if supported, otherwise Cmd+C again.
+ void SendAlternateCopy();
+
+ // Sends Shift+Insert if supported, otherwise Cmd+V again.
+ void SendAlternatePaste();
+
+ View* GetFocusedView();
+ int GetCursorPositionX(int cursor_pos);
+ int GetCursorYForTesting();
+
+ // Get the current cursor bounds.
+ gfx::Rect GetCursorBounds();
+
+ // Get the cursor bounds of |sel|.
+ gfx::Rect GetCursorBounds(const gfx::SelectionModel& sel);
+
+ gfx::Rect GetDisplayRect();
+ gfx::Rect GetCursorViewRect();
+
+ // Mouse click on the point whose x-axis is |bound|'s x plus |x_offset| and
+ // y-axis is in the middle of |bound|'s vertical range.
+ void MouseClick(const gfx::Rect bound, int x_offset);
+
+ // This is to avoid double/triple click.
+ void NonClientMouseClick();
+
+ void VerifyTextfieldContextMenuContents(bool textfield_has_selection,
+ bool can_undo,
+ ui::MenuModel* menu);
+ void PressMouseButton(ui::EventFlags mouse_button_flags);
+ void ReleaseMouseButton(ui::EventFlags mouse_button_flags);
+ void PressLeftMouseButton();
+ void ReleaseLeftMouseButton();
+ void ClickLeftMouseButton();
+ void ClickRightMouseButton();
+ void DragMouseTo(const gfx::Point& where);
+
+ // Textfield does not listen to OnMouseMoved, so this function does not send
+ // an event when it updates the cursor position.
+ void MoveMouseTo(const gfx::Point& where);
+ void TapAtCursor(ui::EventPointerType pointer_type);
+
+ // We need widget to populate wrapper class.
+ std::unique_ptr<Widget> widget_ = nullptr;
+
+ TestTextfield* textfield_ = nullptr;
+ std::unique_ptr<TextfieldTestApi> test_api_;
+ TextfieldModel* model_ = nullptr;
+
+ // The string from Controller::ContentsChanged callback.
+ base::string16 last_contents_;
+
+ // For testing input method related behaviors.
+ MockInputMethod* input_method_ = nullptr;
+
+ // Indicates how many times OnBeforeUserAction() is called.
+ int on_before_user_action_ = 0;
+
+ // Indicates how many times OnAfterUserAction() is called.
+ int on_after_user_action_ = 0;
+
+ // Position of the mouse for synthetic mouse events.
+ gfx::Point mouse_position_;
+
+ ui::ClipboardBuffer copied_to_clipboard_ = ui::ClipboardBuffer::kMaxValue;
+ std::unique_ptr<ui::test::EventGenerator> event_generator_;
+ View* event_target_ = nullptr;
+};
+
+} // namespace test
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_UNITTEST_H_
diff --git a/chromium/ui/views/controls/theme_tracking_image_view.cc b/chromium/ui/views/controls/theme_tracking_image_view.cc
new file mode 100644
index 00000000000..18895f6609c
--- /dev/null
+++ b/chromium/ui/views/controls/theme_tracking_image_view.cc
@@ -0,0 +1,36 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/theme_tracking_image_view.h"
+
+#include "ui/gfx/color_utils.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
+
+namespace views {
+
+ThemeTrackingImageView::ThemeTrackingImageView(
+ const gfx::ImageSkia& light_image,
+ const gfx::ImageSkia& dark_image,
+ const base::RepeatingCallback<SkColor()>& get_background_color_callback)
+ : light_image_(light_image),
+ dark_image_(dark_image),
+ get_background_color_callback_(get_background_color_callback) {
+ DCHECK_EQ(light_image.size(), dark_image.size());
+ SetImage(light_image);
+}
+
+ThemeTrackingImageView::~ThemeTrackingImageView() = default;
+
+void ThemeTrackingImageView::OnThemeChanged() {
+ ImageView::OnThemeChanged();
+ SetImage(color_utils::IsDark(get_background_color_callback_.Run())
+ ? dark_image_
+ : light_image_);
+}
+
+BEGIN_METADATA(ThemeTrackingImageView, views::ImageView)
+END_METADATA
+
+} // namespace views
diff --git a/chromium/ui/views/controls/theme_tracking_image_view.h b/chromium/ui/views/controls/theme_tracking_image_view.h
new file mode 100644
index 00000000000..7275019b0df
--- /dev/null
+++ b/chromium/ui/views/controls/theme_tracking_image_view.h
@@ -0,0 +1,41 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_THEME_TRACKING_IMAGE_VIEW_H_
+#define UI_VIEWS_CONTROLS_THEME_TRACKING_IMAGE_VIEW_H_
+
+#include "ui/views/controls/image_view.h"
+
+namespace views {
+
+// An ImageView that displays either |light_image| or |dark_image| based on the
+// current background color returned by |get_background_color_callback|. Tracks
+// theme changes so the image is always the correct version. |light_image| and
+// |dark_image| must be of the same size. The |light_image| is set by default
+// upon construction.
+class VIEWS_EXPORT ThemeTrackingImageView : public ImageView {
+ public:
+ METADATA_HEADER(ThemeTrackingImageView);
+ ThemeTrackingImageView(
+ const gfx::ImageSkia& light_image,
+ const gfx::ImageSkia& dark_image,
+ const base::RepeatingCallback<SkColor()>& get_background_color_callback);
+ ThemeTrackingImageView(const ThemeTrackingImageView&) = delete;
+ ThemeTrackingImageView& operator=(const ThemeTrackingImageView&) = delete;
+ ~ThemeTrackingImageView() override;
+
+ // ImageView:
+ void OnThemeChanged() override;
+
+ private:
+ // The underlying light and dark mode images.
+ gfx::ImageSkia light_image_;
+ gfx::ImageSkia dark_image_;
+
+ base::RepeatingCallback<SkColor()> get_background_color_callback_;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_THEME_TRACKING_IMAGE_VIEW_H_
diff --git a/chromium/ui/views/controls/tree/tree_view_unittest.cc b/chromium/ui/views/controls/tree/tree_view_unittest.cc
index 0173210e0d1..839e7150a69 100644
--- a/chromium/ui/views/controls/tree/tree_view_unittest.cc
+++ b/chromium/ui/views/controls/tree/tree_view_unittest.cc
@@ -942,21 +942,29 @@ TEST_F(TreeViewTest, ExpandOrSelectChild) {
TEST_F(TreeViewTest, SelectOnKeyStroke) {
tree_->SetModel(&model_);
tree_->ExpandAll(model_.GetRoot());
- selector()->InsertText(ASCIIToUTF16("b"));
+ selector()->InsertText(
+ ASCIIToUTF16("b"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_EQ("b", GetSelectedNodeTitle());
EXPECT_EQ("b", GetSelectedAccessibilityViewName());
- selector()->InsertText(ASCIIToUTF16("1"));
+ selector()->InsertText(
+ ASCIIToUTF16("1"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_EQ("b1", GetSelectedNodeTitle());
EXPECT_EQ("b1", GetSelectedAccessibilityViewName());
// Invoke OnViewBlur() to reset time.
selector()->OnViewBlur();
- selector()->InsertText(ASCIIToUTF16("z"));
+ selector()->InsertText(
+ ASCIIToUTF16("z"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_EQ("b1", GetSelectedNodeTitle());
EXPECT_EQ("b1", GetSelectedAccessibilityViewName());
selector()->OnViewBlur();
- selector()->InsertText(ASCIIToUTF16("a"));
+ selector()->InsertText(
+ ASCIIToUTF16("a"),
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_EQ("a", GetSelectedNodeTitle());
EXPECT_EQ("a", GetSelectedAccessibilityViewName());
}
@@ -1068,6 +1076,7 @@ TEST_F(TreeViewTest, OnFocusAccessibilityEvents) {
// (in this case, the root node).
ClearAccessibilityEvents();
tree_->RequestFocus();
+ EXPECT_TRUE(tree_->HasFocus());
EXPECT_EQ((AccessibilityEventsVector{std::make_pair(
GetRootAccessibilityView(), ax::mojom::Event::kFocus)}),
accessibility_events());
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 a2c0df01350..531ebe33d19 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
@@ -85,7 +85,7 @@ bool ViewsTextServicesContextMenuBase::SupportsCommand(int command_id) const {
return command_id == IDS_CONTENT_CONTEXT_EMOJI;
}
-#if !defined(OS_APPLE)
+#if !defined(OS_APPLE) && !BUILDFLAG(IS_CHROMEOS_ASH)
// static
std::unique_ptr<ViewsTextServicesContextMenu>
ViewsTextServicesContextMenu::Create(ui::SimpleMenuModel* menu,
diff --git a/chromium/ui/views/controls/views_text_services_context_menu_base.h b/chromium/ui/views/controls/views_text_services_context_menu_base.h
index 2318cf80d6b..4651047e6b7 100644
--- a/chromium/ui/views/controls/views_text_services_context_menu_base.h
+++ b/chromium/ui/views/controls/views_text_services_context_menu_base.h
@@ -6,13 +6,16 @@
#define UI_VIEWS_CONTROLS_VIEWS_TEXT_SERVICES_CONTEXT_MENU_BASE_H_
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/views/controls/views_text_services_context_menu.h"
+#include "ui/views/views_export.h"
namespace views {
// This base class is used to add and handle text service items in the textfield
// context menu. Specific platforms may subclass and add additional items.
-class ViewsTextServicesContextMenuBase : public ViewsTextServicesContextMenu {
+class VIEWS_EXPORT ViewsTextServicesContextMenuBase
+ : public ViewsTextServicesContextMenu {
public:
ViewsTextServicesContextMenuBase(ui::SimpleMenuModel* menu,
Textfield* client);
@@ -31,7 +34,7 @@ class ViewsTextServicesContextMenuBase : public ViewsTextServicesContextMenu {
bool SupportsCommand(int command_id) const override;
protected:
-#if defined(OS_APPLE)
+#if defined(OS_APPLE) || BUILDFLAG(IS_CHROMEOS_ASH)
Textfield* client() { return client_; }
const Textfield* client() const { return client_; }
#endif
diff --git a/chromium/ui/views/controls/views_text_services_context_menu_chromeos.cc b/chromium/ui/views/controls/views_text_services_context_menu_chromeos.cc
new file mode 100644
index 00000000000..5a2d082aeef
--- /dev/null
+++ b/chromium/ui/views/controls/views_text_services_context_menu_chromeos.cc
@@ -0,0 +1,79 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/views_text_services_context_menu_chromeos.h"
+
+#include <utility>
+
+#include "base/no_destructor.h"
+#include "ui/views/controls/views_text_services_context_menu_base.h"
+
+namespace views {
+
+namespace {
+
+using ImplFactory = ViewsTextServicesContextMenuChromeos::ImplFactory;
+ImplFactory& GetImplFactory() {
+ static base::NoDestructor<ImplFactory> impl_factory;
+ return *impl_factory;
+}
+
+} // namespace
+
+// static
+void ViewsTextServicesContextMenuChromeos::SetImplFactory(
+ ImplFactory impl_factory) {
+ GetImplFactory() = std::move(impl_factory);
+}
+
+ViewsTextServicesContextMenuChromeos::ViewsTextServicesContextMenuChromeos(
+ ui::SimpleMenuModel* menu,
+ Textfield* client) {
+ auto& impl_factory = GetImplFactory();
+
+ // In unit tests, `impl_factory` may not be set. Use
+ // `ViewTextServicesContextMenuBase` in that case.
+ if (impl_factory)
+ impl_ = impl_factory.Run(menu, client);
+ else
+ impl_ = std::make_unique<ViewsTextServicesContextMenuBase>(menu, client);
+}
+
+ViewsTextServicesContextMenuChromeos::~ViewsTextServicesContextMenuChromeos() =
+ default;
+
+bool ViewsTextServicesContextMenuChromeos::GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) const {
+ return impl_->GetAcceleratorForCommandId(command_id, accelerator);
+}
+
+bool ViewsTextServicesContextMenuChromeos::IsCommandIdChecked(
+ int command_id) const {
+ return impl_->IsCommandIdChecked(command_id);
+}
+
+bool ViewsTextServicesContextMenuChromeos::IsCommandIdEnabled(
+ int command_id) const {
+ return impl_->IsCommandIdEnabled(command_id);
+}
+
+void ViewsTextServicesContextMenuChromeos::ExecuteCommand(int command_id,
+ int event_flags) {
+ return impl_->ExecuteCommand(command_id, event_flags);
+}
+
+bool ViewsTextServicesContextMenuChromeos::SupportsCommand(
+ int command_id) const {
+ return impl_->IsCommandIdEnabled(command_id);
+}
+
+// static
+std::unique_ptr<ViewsTextServicesContextMenu>
+ViewsTextServicesContextMenu::Create(ui::SimpleMenuModel* menu,
+ Textfield* client) {
+ return std::make_unique<ViewsTextServicesContextMenuChromeos>(menu, client);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/views_text_services_context_menu_chromeos.h b/chromium/ui/views/controls/views_text_services_context_menu_chromeos.h
new file mode 100644
index 00000000000..4dfd7d05d66
--- /dev/null
+++ b/chromium/ui/views/controls/views_text_services_context_menu_chromeos.h
@@ -0,0 +1,51 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_VIEWS_TEXT_SERVICES_CONTEXT_MENU_CHROMEOS_H_
+#define UI_VIEWS_CONTROLS_VIEWS_TEXT_SERVICES_CONTEXT_MENU_CHROMEOS_H_
+
+#include <memory>
+
+#include "ui/views/controls/views_text_services_context_menu.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+// This class is used to add and handle text service items in the text context
+// menu under the CrOS environment.
+class VIEWS_EXPORT ViewsTextServicesContextMenuChromeos
+ : public ViewsTextServicesContextMenu {
+ public:
+ using ImplFactory = base::RepeatingCallback<std::unique_ptr<
+ ViewsTextServicesContextMenu>(ui::SimpleMenuModel*, Textfield*)>;
+
+ // Injects the method to construct `impl_`.
+ static void SetImplFactory(ImplFactory factory);
+
+ ViewsTextServicesContextMenuChromeos(ui::SimpleMenuModel* menu,
+ Textfield* client);
+ ViewsTextServicesContextMenuChromeos(
+ const ViewsTextServicesContextMenuChromeos&) = delete;
+ ViewsTextServicesContextMenuChromeos& operator=(
+ const ViewsTextServicesContextMenuChromeos&) = delete;
+ ~ViewsTextServicesContextMenuChromeos() override;
+
+ // ViewsTextServicesContextMenu:
+ bool GetAcceleratorForCommandId(int command_id,
+ ui::Accelerator* accelerator) const override;
+ bool IsCommandIdChecked(int command_id) const override;
+ bool IsCommandIdEnabled(int command_id) const override;
+ void ExecuteCommand(int command_id, int event_flags) override;
+ bool SupportsCommand(int command_id) const override;
+
+ private:
+ // CrOS functionality must be provided by the embedder, so requests are
+ // forwarded to this concrete object, whose construction can be controlled by
+ // `SetImplFactory()`.
+ std::unique_ptr<ViewsTextServicesContextMenu> impl_;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_VIEWS_TEXT_SERVICES_CONTEXT_MENU_CHROMEOS_H_
diff --git a/chromium/ui/views/controls/webview/OWNERS b/chromium/ui/views/controls/webview/OWNERS
index d2e56866d7a..1356a8b6333 100644
--- a/chromium/ui/views/controls/webview/OWNERS
+++ b/chromium/ui/views/controls/webview/OWNERS
@@ -2,5 +2,4 @@ sadrul@chromium.org
sky@chromium.org
# For "EmbedFullscreenWidgetMode" changes. (Component: UI>Browser>TabCapture)
-miu@chromium.org
mfoltz@chromium.org
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 2a9ff959e44..0cf575a7876 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
@@ -5,7 +5,7 @@
#include "ui/views/controls/webview/web_contents_set_background_color.h"
#include "base/memory/ptr_util.h"
-#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
@@ -33,24 +33,13 @@ WebContentsSetBackgroundColor::WebContentsSetBackgroundColor(
WebContentsSetBackgroundColor::~WebContentsSetBackgroundColor() = default;
-void WebContentsSetBackgroundColor::RenderViewReady() {
- web_contents()
- ->GetMainFrame()
- ->GetRenderViewHost()
- ->GetWidget()
- ->GetView()
- ->SetBackgroundColor(color_);
-}
-
-void WebContentsSetBackgroundColor::RenderViewCreated(
- content::RenderViewHost* render_view_host) {
- render_view_host->GetWidget()->GetView()->SetBackgroundColor(color_);
-}
-
-void WebContentsSetBackgroundColor::RenderViewHostChanged(
- content::RenderViewHost* old_host,
- content::RenderViewHost* new_host) {
- new_host->GetWidget()->GetView()->SetBackgroundColor(color_);
+void WebContentsSetBackgroundColor::RenderFrameCreated(
+ content::RenderFrameHost* render_frame_host) {
+ // We set the background color just on the main frame's widget. Other frames
+ // that are local roots would have a widget of their own, but their background
+ // colors are part of, and controlled by, the webpage.
+ if (!render_frame_host->GetParent())
+ render_frame_host->GetView()->SetBackgroundColor(color_);
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(WebContentsSetBackgroundColor)
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 9bac23b4e8a..140ffa41f24 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
@@ -32,10 +32,7 @@ class WebContentsSetBackgroundColor
SkColor color);
// content::WebContentsObserver:
- void RenderViewReady() override;
- void RenderViewCreated(content::RenderViewHost* render_view_host) override;
- void RenderViewHostChanged(content::RenderViewHost* old_host,
- content::RenderViewHost* new_host) override;
+ void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
SkColor color_;
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.cc b/chromium/ui/views/controls/webview/web_dialog_view.cc
index 39a58363e71..d5730f11198 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.cc
+++ b/chromium/ui/views/controls/webview/web_dialog_view.cc
@@ -20,6 +20,7 @@
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/layout/fill_layout.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
@@ -69,6 +70,9 @@ void ObservableWebView::ResetDelegate() {
delegate_ = nullptr;
}
+BEGIN_METADATA(ObservableWebView, WebView)
+END_METADATA
+
////////////////////////////////////////////////////////////////////////////////
// WebDialogView, public:
@@ -473,4 +477,8 @@ void WebDialogView::InitDialog() {
web_view_->LoadInitialURL(GetDialogContentURL());
}
+BEGIN_METADATA(WebDialogView, ClientView)
+ADD_READONLY_PROPERTY_METADATA(ObservableWebView*, WebView);
+END_METADATA
+
} // namespace views
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.h b/chromium/ui/views/controls/webview/web_dialog_view.h
index 97142bc886e..d4cb57f0f04 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.h
+++ b/chromium/ui/views/controls/webview/web_dialog_view.h
@@ -17,6 +17,7 @@
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/controls/webview/webview_export.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"
#include "ui/web_dialogs/web_dialog_delegate.h"
@@ -33,8 +34,12 @@ namespace views {
// A kind of webview that can notify its delegate when its content is ready.
class ObservableWebView : public WebView {
public:
+ METADATA_HEADER(ObservableWebView);
+
ObservableWebView(content::BrowserContext* browser_context,
ui::WebDialogDelegate* delegate);
+ ObservableWebView(const ObservableWebView&) = delete;
+ ObservableWebView& operator=(const ObservableWebView&) = delete;
~ObservableWebView() override;
// content::WebContentsObserver
@@ -51,8 +56,6 @@ class ObservableWebView : public WebView {
private:
ui::WebDialogDelegate* delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(ObservableWebView);
};
////////////////////////////////////////////////////////////////////////////////
@@ -73,12 +76,16 @@ class WEBVIEW_EXPORT WebDialogView : public ClientView,
public ui::WebDialogDelegate,
public WidgetDelegate {
public:
+ METADATA_HEADER(WebDialogView);
+
// |handler| must not be nullptr.
// |use_dialog_frame| indicates whether to use dialog frame view for non
// client frame view.
WebDialogView(content::BrowserContext* context,
ui::WebDialogDelegate* delegate,
std::unique_ptr<WebContentsHandler> handler);
+ WebDialogView(const WebDialogView&) = delete;
+ WebDialogView& operator=(const WebDialogView&) = delete;
~WebDialogView() override;
content::WebContents* web_contents();
@@ -170,6 +177,9 @@ class WEBVIEW_EXPORT WebDialogView : public ClientView,
// Initializes the contents of the dialog.
void InitDialog();
+ // Accessor used by metadata only.
+ ObservableWebView* GetWebView() const { return web_view_; }
+
// This view is a delegate to the HTML content since it needs to get notified
// about when the dialog is closing. For all other actions (besides dialog
// closing) we delegate to the creator of this view, which we keep track of
@@ -205,8 +215,6 @@ class WEBVIEW_EXPORT WebDialogView : public ClientView,
UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
bool disable_url_load_for_test_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(WebDialogView);
};
} // namespace views
diff --git a/chromium/ui/views/controls/webview/web_dialog_view_unittest.cc b/chromium/ui/views/controls/webview/web_dialog_view_unittest.cc
index 004f97daf2a..352ffe730c3 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view_unittest.cc
+++ b/chromium/ui/views/controls/webview/web_dialog_view_unittest.cc
@@ -19,6 +19,7 @@
#include "content/test/test_web_contents.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/views/test/view_metadata_test_utils.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/window/dialog_delegate.h"
#include "ui/web_dialogs/test/test_web_contents_handler.h"
@@ -184,4 +185,8 @@ TEST_F(WebDialogViewUnitTest, ObservableWebViewOnWebDialogViewClosed) {
web_view()->ResourceLoadComplete(rfh, request_id, resource_load_info);
}
+TEST_F(WebDialogViewUnitTest, MetadataTest) {
+ test::TestViewMetadata(web_dialog_view());
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/webview/webview.cc b/chromium/ui/views/controls/webview/webview.cc
index 44a8fc6ef9d..2ade47b0077 100644
--- a/chromium/ui/views/controls/webview/webview.cc
+++ b/chromium/ui/views/controls/webview/webview.cc
@@ -13,7 +13,6 @@
#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"
#include "ipc/ipc_message.h"
@@ -90,13 +89,15 @@ void WebView::SetWebContents(content::WebContents* replacement) {
DetachWebContentsNativeView();
WebContentsObserver::Observe(replacement);
// web_contents() now returns |replacement| from here onwards.
- UpdateCrashedOverlayView();
if (wc_owner_.get() != replacement)
wc_owner_.reset();
AttachWebContentsNativeView();
- NotifyAccessibilityWebContentsChanged();
- MaybeEnableAutoResize();
+ if (replacement && replacement->GetMainFrame()->IsRenderFrameCreated()) {
+ SetUpNewMainFrame(replacement->GetMainFrame());
+ } else {
+ LostMainFrame();
+ }
}
content::BrowserContext* WebView::GetBrowserContext() {
@@ -124,7 +125,8 @@ void WebView::EnableSizingFromWebContents(const gfx::Size& min_size,
DCHECK(!max_size.IsEmpty());
min_size_ = min_size;
max_size_ = max_size;
- MaybeEnableAutoResize();
+ if (web_contents() && web_contents()->GetMainFrame()->IsRenderFrameCreated())
+ MaybeEnableAutoResize(web_contents()->GetMainFrame());
}
void WebView::SetCrashedOverlayView(View* crashed_overlay_view) {
@@ -298,31 +300,37 @@ void WebView::OnAXModeAdded(ui::AXMode mode) {
////////////////////////////////////////////////////////////////////////////////
// WebView, content::WebContentsObserver implementation:
-void WebView::RenderViewCreated(content::RenderViewHost* render_view_host) {
- MaybeEnableAutoResize();
-}
-
-void WebView::RenderViewReady() {
- UpdateCrashedOverlayView();
- NotifyAccessibilityWebContentsChanged();
-}
+void WebView::RenderFrameCreated(content::RenderFrameHost* render_frame_host) {
+ // Only handle the initial main frame, not speculative ones.
+ if (render_frame_host != web_contents()->GetMainFrame())
+ return;
-void WebView::RenderViewDeleted(content::RenderViewHost* render_view_host) {
- UpdateCrashedOverlayView();
- NotifyAccessibilityWebContentsChanged();
+ SetUpNewMainFrame(render_frame_host);
}
-void WebView::RenderViewHostChanged(content::RenderViewHost* old_host,
- content::RenderViewHost* new_host) {
- MaybeEnableAutoResize();
+void WebView::RenderFrameDeleted(content::RenderFrameHost* render_frame_host) {
+ // Only handle the active main frame, not speculative ones.
+ if (render_frame_host != web_contents()->GetMainFrame())
+ return;
- if (HasFocus())
- OnFocus();
- NotifyAccessibilityWebContentsChanged();
+ LostMainFrame();
}
-void WebView::WebContentsDestroyed() {
- NotifyAccessibilityWebContentsChanged();
+void WebView::RenderFrameHostChanged(content::RenderFrameHost* old_host,
+ content::RenderFrameHost* new_host) {
+ // Since we skipped speculative main frames in RenderFrameCreated, we must
+ // watch for them being swapped in by watching for RenderFrameHostChanged().
+ if (new_host != web_contents()->GetMainFrame())
+ return;
+ // Ignore the initial main frame host, as there's no renderer frame for it
+ // yet. If the DCHECK fires, then we would need to handle the initial main
+ // frame when it its renderer frame is created.
+ if (!old_host) {
+ DCHECK(!new_host->IsRenderFrameCreated());
+ return;
+ }
+
+ SetUpNewMainFrame(new_host);
}
void WebView::DidToggleFullscreenModeForTab(bool entered_fullscreen,
@@ -338,11 +346,6 @@ void WebView::OnWebContentsFocused(
RequestFocus();
}
-void WebView::RenderProcessGone(base::TerminationStatus status) {
- UpdateCrashedOverlayView();
- NotifyAccessibilityWebContentsChanged();
-}
-
void WebView::AXTreeIDForMainFrameHasChanged() {
NotifyAccessibilityWebContentsChanged();
}
@@ -425,15 +428,23 @@ std::unique_ptr<content::WebContents> WebView::CreateWebContents(
return contents;
}
-void WebView::MaybeEnableAutoResize() {
- if (max_size_.IsEmpty() || !web_contents() ||
- !web_contents()->GetRenderWidgetHostView()) {
- return;
- }
+void WebView::SetUpNewMainFrame(content::RenderFrameHost* frame_host) {
+ MaybeEnableAutoResize(frame_host);
+ UpdateCrashedOverlayView();
+ NotifyAccessibilityWebContentsChanged();
+ if (HasFocus())
+ OnFocus();
+}
+
+void WebView::LostMainFrame() {
+ UpdateCrashedOverlayView();
+ NotifyAccessibilityWebContentsChanged();
+}
- content::RenderWidgetHostView* render_widget_host_view =
- web_contents()->GetRenderWidgetHostView();
- render_widget_host_view->EnableAutoResize(min_size_, max_size_);
+void WebView::MaybeEnableAutoResize(content::RenderFrameHost* frame_host) {
+ DCHECK(frame_host->IsRenderFrameCreated());
+ if (!max_size_.IsEmpty())
+ frame_host->GetView()->EnableAutoResize(min_size_, max_size_);
}
BEGIN_METADATA(WebView, View)
diff --git a/chromium/ui/views/controls/webview/webview.h b/chromium/ui/views/controls/webview/webview.h
index 9604515c2d5..94e25679eab 100644
--- a/chromium/ui/views/controls/webview/webview.h
+++ b/chromium/ui/views/controls/webview/webview.h
@@ -138,12 +138,10 @@ class WEBVIEW_EXPORT WebView : public View,
void AddedToWidget() override;
// Overridden from content::WebContentsObserver:
- void RenderViewCreated(content::RenderViewHost* render_view_host) override;
- void RenderViewReady() override;
- void RenderViewDeleted(content::RenderViewHost* render_view_host) override;
- void RenderViewHostChanged(content::RenderViewHost* old_host,
- content::RenderViewHost* new_host) override;
- void WebContentsDestroyed() override;
+ void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
+ void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
+ void RenderFrameHostChanged(content::RenderFrameHost* old_host,
+ content::RenderFrameHost* new_host) override;
void DidToggleFullscreenModeForTab(bool entered_fullscreen,
bool will_cause_resize) override;
// Workaround for MSVC++ linker bug/feature that requires
@@ -153,7 +151,6 @@ class WEBVIEW_EXPORT WebView : public View,
void OnBadMessageReceived(const IPC::Message& message) override {}
void OnWebContentsFocused(
content::RenderWidgetHost* render_widget_host) override;
- void RenderProcessGone(base::TerminationStatus status) override;
void AXTreeIDForMainFrameHasChanged() override;
// Override from ui::AXModeObserver
@@ -167,10 +164,16 @@ class WEBVIEW_EXPORT WebView : public View,
void UpdateCrashedOverlayView();
void NotifyAccessibilityWebContentsChanged();
- // Registers for ResizeDueToAutoResize() notifications from the
+ // Called when the main frame in the renderer becomes present.
+ void SetUpNewMainFrame(content::RenderFrameHost* frame_host);
+ // Called when the main frame in the renderer is no longer present.
+ void LostMainFrame();
+
+ // Registers for ResizeDueToAutoResize() notifications from `frame_host`'s
// RenderWidgetHostView whenever it is created or changes, if
- // EnableSizingFromWebContents() has been called.
- void MaybeEnableAutoResize();
+ // EnableSizingFromWebContents() has been called. This should only be called
+ // for main frames; other frames can not have auto resize set.
+ void MaybeEnableAutoResize(content::RenderFrameHost* frame_host);
// Create a regular or test web contents (based on whether we're running
// in a unit test or not).
diff --git a/chromium/ui/views/controls/webview/webview_unittest.cc b/chromium/ui/views/controls/webview/webview_unittest.cc
index d407fb1dd0e..39005facc44 100644
--- a/chromium/ui/views/controls/webview/webview_unittest.cc
+++ b/chromium/ui/views/controls/webview/webview_unittest.cc
@@ -191,6 +191,11 @@ class WebViewUnitTest : public views::test::WidgetTest {
content::WebContents::CreateParams(browser_context_.get()));
}
+ std::unique_ptr<content::WebContents> CreateTestWebContents() const {
+ return content::WebContentsTester::CreateTestWebContents(
+ browser_context_.get(), /*site_instnace=*/nullptr);
+ }
+
private:
std::unique_ptr<content::RenderViewHostTestEnabler> rvh_enabler_;
std::unique_ptr<content::TestBrowserContext> browser_context_;
@@ -321,7 +326,11 @@ TEST_F(WebViewUnitTest, DetachedWebViewDestructor) {
// Test that the specified crashed overlay view is shown when a WebContents
// is in a crashed state.
TEST_F(WebViewUnitTest, CrashedOverlayView) {
- const std::unique_ptr<content::WebContents> web_contents(CreateWebContents());
+ const std::unique_ptr<content::WebContents> web_contents =
+ CreateTestWebContents();
+ content::WebContentsTester* tester =
+ content::WebContentsTester::For(web_contents.get());
+
std::unique_ptr<WebView> web_view(
new WebView(web_contents->GetBrowserContext()));
View* contents_view = top_level_widget()->GetContentsView();
@@ -335,18 +344,21 @@ TEST_F(WebViewUnitTest, CrashedOverlayView) {
// Normally when a renderer crashes, the WebView will learn about it
// automatically via WebContentsObserver. Since this is a test
// WebContents, simulate that by calling SetIsCrashed and then
- // explicitly calling RenderViewDeleted on the WebView to trigger it
+ // explicitly calling RenderFrameDeleted on the WebView to trigger it
// to swap in the crashed overlay view.
- web_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
+ tester->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
EXPECT_TRUE(web_contents->IsCrashed());
static_cast<content::WebContentsObserver*>(web_view.get())
- ->RenderViewDeleted(nullptr);
+ ->RenderFrameDeleted(web_contents->GetMainFrame());
EXPECT_TRUE(crashed_overlay_view->IsDrawn());
}
// Test that a crashed overlay view isn't deleted if it's owned by client.
TEST_F(WebViewUnitTest, CrashedOverlayViewOwnedbyClient) {
- const std::unique_ptr<content::WebContents> web_contents(CreateWebContents());
+ const std::unique_ptr<content::WebContents> web_contents =
+ CreateTestWebContents();
+ content::WebContentsTester* tester =
+ content::WebContentsTester::For(web_contents.get());
std::unique_ptr<WebView> web_view(
new WebView(web_contents->GetBrowserContext()));
View* contents_view = top_level_widget()->GetContentsView();
@@ -359,10 +371,10 @@ TEST_F(WebViewUnitTest, CrashedOverlayViewOwnedbyClient) {
EXPECT_FALSE(crashed_overlay_view->IsDrawn());
// Simulate a renderer crash (see above).
- web_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
+ tester->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
EXPECT_TRUE(web_contents->IsCrashed());
static_cast<content::WebContentsObserver*>(web_view.get())
- ->RenderViewDeleted(nullptr);
+ ->RenderFrameDeleted(web_contents->GetMainFrame());
EXPECT_TRUE(crashed_overlay_view->IsDrawn());
web_view->SetCrashedOverlayView(nullptr);
diff --git a/chromium/ui/views/corewm/DEPS b/chromium/ui/views/corewm/DEPS
index 059e550da2c..15ef6f5085a 100644
--- a/chromium/ui/views/corewm/DEPS
+++ b/chromium/ui/views/corewm/DEPS
@@ -16,6 +16,8 @@ specific_include_rules = {
"tooltip_aura.cc": [
"+ui/views/background.h",
"+ui/views/border.h",
+ "+ui/views/metadata/metadata_header_macros.h",
+ "+ui/views/metadata/metadata_impl_macros.h",
"+ui/views/painter.h",
"+ui/views/widget/widget.h",
"+ui/views/view.h",
diff --git a/chromium/ui/views/corewm/tooltip_aura.cc b/chromium/ui/views/corewm/tooltip_aura.cc
index 21ad5c996b5..363b4b04e4d 100644
--- a/chromium/ui/views/corewm/tooltip_aura.cc
+++ b/chromium/ui/views/corewm/tooltip_aura.cc
@@ -11,6 +11,7 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/aura/window.h"
@@ -25,6 +26,8 @@
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
+#include "ui/views/metadata/metadata_header_macros.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/painter.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -46,7 +49,9 @@ constexpr int kVerticalPaddingBottom = 5;
// TODO(varkha): Update if native widget can be transparent on Linux.
bool CanUseTranslucentTooltipWidget() {
-#if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_WIN)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || defined(OS_WIN)
return false;
#else
return true;
@@ -56,6 +61,7 @@ bool CanUseTranslucentTooltipWidget() {
// TODO(oshima): Consider to use views::Label.
class TooltipView : public views::View {
public:
+ METADATA_HEADER(TooltipView);
TooltipView() : render_text_(gfx::RenderText::CreateRenderText()) {
SetBorder(views::CreateEmptyBorder(kVerticalPaddingTop, kHorizontalPadding,
kVerticalPaddingBottom,
@@ -67,6 +73,8 @@ class TooltipView : public views::View {
ResetDisplayRect();
}
+ TooltipView(const TooltipView&) = delete;
+ TooltipView& operator=(const TooltipView&) = delete;
~TooltipView() override = default;
// views:View:
@@ -90,8 +98,6 @@ class TooltipView : public views::View {
return view_size;
}
- const char* GetClassName() const override { return "TooltipView"; }
-
void SetText(const base::string16& text) {
render_text_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
@@ -147,10 +153,11 @@ class TooltipView : public views::View {
std::unique_ptr<gfx::RenderText> render_text_;
int max_width_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(TooltipView);
};
+BEGIN_METADATA(TooltipView, views::View)
+END_METADATA
+
} // namespace
namespace views {
diff --git a/chromium/ui/views/corewm/tooltip_controller.cc b/chromium/ui/views/corewm/tooltip_controller.cc
index 0ac53224396..baecded4263 100644
--- a/chromium/ui/views/corewm/tooltip_controller.cc
+++ b/chromium/ui/views/corewm/tooltip_controller.cc
@@ -241,6 +241,10 @@ void TooltipController::OnCancelMode(ui::CancelModeEvent* event) {
HideTooltipAndResetStates();
}
+base::StringPiece TooltipController::GetLogContext() const {
+ return "TooltipController";
+}
+
void TooltipController::OnCursorVisibilityChanged(bool is_visible) {
UpdateIfRequired();
}
diff --git a/chromium/ui/views/corewm/tooltip_controller.h b/chromium/ui/views/corewm/tooltip_controller.h
index 8e2fd2f98ed..2fbe50261df 100644
--- a/chromium/ui/views/corewm/tooltip_controller.h
+++ b/chromium/ui/views/corewm/tooltip_controller.h
@@ -7,9 +7,11 @@
#include <map>
#include <memory>
+#include <string>
#include "base/macros.h"
#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
#include "base/timer/timer.h"
#include "ui/aura/client/cursor_client_observer.h"
#include "ui/aura/window_observer.h"
@@ -52,6 +54,7 @@ class VIEWS_EXPORT TooltipController
void OnMouseEvent(ui::MouseEvent* event) override;
void OnTouchEvent(ui::TouchEvent* event) override;
void OnCancelMode(ui::CancelModeEvent* event) override;
+ base::StringPiece GetLogContext() const override;
// Overridden from aura::client::CursorClientObserver.
void OnCursorVisibilityChanged(bool is_visible) override;
diff --git a/chromium/ui/views/corewm/tooltip_win.cc b/chromium/ui/views/corewm/tooltip_win.cc
index 4d8702870de..cb81f05e41e 100644
--- a/chromium/ui/views/corewm/tooltip_win.cc
+++ b/chromium/ui/views/corewm/tooltip_win.cc
@@ -6,6 +6,7 @@
#include "base/i18n/rtl.h"
#include "base/logging.h"
+#include "base/strings/string_util_win.h"
#include "base/win/windowsx_shim.h"
#include "ui/base/l10n/l10n_util_win.h"
#include "ui/display/display.h"
@@ -141,7 +142,7 @@ void TooltipWin::SetText(aura::Window* window,
base::string16 adjusted_text(tooltip_text);
base::i18n::AdjustStringForLocaleDirection(&adjusted_text);
- toolinfo_.lpszText = const_cast<WCHAR*>(adjusted_text.c_str());
+ toolinfo_.lpszText = base::as_writable_wcstr(adjusted_text);
SendMessage(tooltip_hwnd_, TTM_SETTOOLINFO, 0,
reinterpret_cast<LPARAM>(&toolinfo_));
diff --git a/chromium/ui/views/debug/BUILD.gn b/chromium/ui/views/debug/BUILD.gn
new file mode 100644
index 00000000000..e8b859e99eb
--- /dev/null
+++ b/chromium/ui/views/debug/BUILD.gn
@@ -0,0 +1,8 @@
+static_library("views_debug") {
+ sources = [
+ "debugger_utils.cc",
+ "debugger_utils.h",
+ ]
+
+ deps = [ "//base" ]
+}
diff --git a/chromium/ui/views/debug/DEPS b/chromium/ui/views/debug/DEPS
new file mode 100644
index 00000000000..67c1bd4dd7d
--- /dev/null
+++ b/chromium/ui/views/debug/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ # Views debug code should avoid relying on //ui/views code to ensure debugger
+ # extensions are resillient to version structure changes within the codebase.
+ "-ui/views",
+ "+ui/views/debug",
+]
diff --git a/chromium/ui/views/debug/debugger_utils.cc b/chromium/ui/views/debug/debugger_utils.cc
new file mode 100644
index 00000000000..a4660a36daa
--- /dev/null
+++ b/chromium/ui/views/debug/debugger_utils.cc
@@ -0,0 +1,147 @@
+// Copyright 2021 The Chromium 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/debug/debugger_utils.h"
+
+#include <inttypes.h>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+
+namespace views {
+namespace debug {
+
+namespace {
+
+using AttributeStrings = std::vector<std::string>;
+
+constexpr int kElementIndent = 2;
+constexpr int kAttributeIndent = 4;
+
+std::string ToString(bool val) {
+ return val ? "true" : "false";
+}
+
+std::string ToString(int val) {
+ return base::NumberToString(val);
+}
+
+std::string ToString(ViewDebugWrapper::BoundsTuple bounds) {
+ return base::StringPrintf("%d %d %dx%d", std::get<0>(bounds),
+ std::get<1>(bounds), std::get<2>(bounds),
+ std::get<3>(bounds));
+}
+
+// intptr_t can alias to int, preventing the use of overloading for ToString.
+std::string PtrToString(intptr_t val) {
+ return base::StringPrintf("0x%" PRIxPTR, val);
+}
+
+// Adds attribute string of the form <attribute_name>="<attribute_value>".
+template <typename T>
+void AddAttributeString(AttributeStrings& attributes,
+ const std::string& name,
+ const T& value) {
+ attributes.push_back(name + "=\"" + ToString(value) + "\"");
+}
+
+void AddPtrAttributeString(AttributeStrings& attributes,
+ const std::string& name,
+ const base::Optional<intptr_t>& value) {
+ if (!value)
+ return;
+
+ attributes.push_back(name + "=\"" + PtrToString(value.value()) + "\"");
+}
+
+AttributeStrings GetAttributeStrings(ViewDebugWrapper* view, bool verbose) {
+ AttributeStrings attributes;
+ if (verbose) {
+ view->ForAllProperties(base::BindRepeating(
+ [](AttributeStrings* attributes, const std::string& name,
+ const std::string& val) {
+ attributes->push_back(name + "=\"" + val + "\"");
+ },
+ base::Unretained(&attributes)));
+ } else {
+ AddPtrAttributeString(attributes, "address", view->GetAddress());
+ AddAttributeString(attributes, "bounds", view->GetBounds());
+ AddAttributeString(attributes, "enabled", view->GetNeedsLayout());
+ AddAttributeString(attributes, "id", view->GetID());
+ AddAttributeString(attributes, "needs-layout", view->GetNeedsLayout());
+ AddAttributeString(attributes, "visible", view->GetVisible());
+ }
+ return attributes;
+}
+
+std::string GetPaddedLine(int current_depth, bool attribute_line = false) {
+ const int padding = attribute_line
+ ? current_depth * kElementIndent + kAttributeIndent
+ : current_depth * kElementIndent;
+ return std::string(padding, ' ');
+}
+
+void PrintViewHierarchyImpl(std::ostream* out,
+ ViewDebugWrapper* view,
+ int current_depth,
+ bool verbose,
+ int target_depth,
+ size_t column_limit) {
+ std::string line = GetPaddedLine(current_depth);
+
+ line += "<" + view->GetViewClassName();
+
+ for (const std::string& attribute_string :
+ GetAttributeStrings(view, verbose)) {
+ if (line.size() + attribute_string.size() + 1 > column_limit) {
+ // If adding the attribute string would cause the line to exceed the
+ // column limit, send the line to `out` and start a new line. The new line
+ // should fit at least one attribute string even if it means exceeding the
+ // column limit.
+ *out << line << "\n";
+ line = GetPaddedLine(current_depth, true) + attribute_string;
+ } else {
+ // Keep attribute strings on the existing line if it fits within the
+ // column limit.
+ line += " " + attribute_string;
+ }
+ }
+
+ // Print children only if they exist and we are not yet at our target tree
+ // depth.
+ if (!view->GetChildren().empty() &&
+ (target_depth == -1 || current_depth < target_depth)) {
+ *out << line << ">\n";
+
+ for (ViewDebugWrapper* child : view->GetChildren()) {
+ PrintViewHierarchyImpl(out, child, current_depth + 1, verbose,
+ target_depth, column_limit);
+ }
+
+ line = GetPaddedLine(current_depth);
+ *out << line << "</" << view->GetViewClassName() << ">\n";
+ } else {
+ // If no children are to be printed use a self closing tag to terminate the
+ // View element.
+ *out << line << " />\n";
+ }
+}
+
+} // namespace
+
+base::Optional<intptr_t> ViewDebugWrapper::GetAddress() {
+ return base::nullopt;
+}
+
+void PrintViewHierarchy(std::ostream* out,
+ ViewDebugWrapper* view,
+ bool verbose,
+ int depth,
+ size_t column_limit) {
+ PrintViewHierarchyImpl(out, view, 0, verbose, depth, column_limit);
+}
+
+} // namespace debug
+} // namespace views
diff --git a/chromium/ui/views/debug/debugger_utils.h b/chromium/ui/views/debug/debugger_utils.h
new file mode 100644
index 00000000000..02cf56623b6
--- /dev/null
+++ b/chromium/ui/views/debug/debugger_utils.h
@@ -0,0 +1,54 @@
+// Copyright 2021 The Chromium 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_DEBUG_DEBUGGER_UTILS_H_
+#define UI_VIEWS_DEBUG_DEBUGGER_UTILS_H_
+
+#include <ostream>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/optional.h"
+
+namespace views {
+namespace debug {
+
+// This class acts as a "view" over the View class. This has been done to allow
+// debugger extensions to remnain resillient to structure and version changes in
+// the code base.
+// TODO(tluk): Replace use of //ui/views/debug_utils.h with this.
+class ViewDebugWrapper {
+ public:
+ // Tuple used to represent View bounds. Takes the form <x, y, width, height>.
+ using BoundsTuple = std::tuple<int, int, int, int>;
+ // Callback function used to iterate through all metadata properties.
+ using PropCallback =
+ base::RepeatingCallback<void(const std::string&, const std::string&)>;
+
+ ViewDebugWrapper() = default;
+ virtual ~ViewDebugWrapper() = default;
+
+ virtual std::string GetViewClassName() = 0;
+ virtual int GetID() = 0;
+ virtual BoundsTuple GetBounds() = 0;
+ virtual bool GetVisible() = 0;
+ virtual bool GetNeedsLayout() = 0;
+ virtual bool GetEnabled() = 0;
+ virtual std::vector<ViewDebugWrapper*> GetChildren() = 0;
+ virtual void ForAllProperties(PropCallback callback) {}
+ virtual base::Optional<intptr_t> GetAddress();
+};
+
+void PrintViewHierarchy(std::ostream* out,
+ ViewDebugWrapper* view,
+ bool verbose = false,
+ int depth = -1,
+ size_t column_limit = 240);
+
+} // namespace debug
+} // namespace views
+
+#endif // UI_VIEWS_DEBUG_DEBUGGER_UTILS_H_
diff --git a/chromium/ui/views/event_monitor_aura.cc b/chromium/ui/views/event_monitor_aura.cc
index 69edc44bc48..698f21eae39 100644
--- a/chromium/ui/views/event_monitor_aura.cc
+++ b/chromium/ui/views/event_monitor_aura.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/check_op.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/events/event_observer.h"
@@ -25,21 +25,23 @@ class WindowMonitorAura : public EventMonitorAura, public aura::WindowObserver {
const std::set<ui::EventType>& types)
: EventMonitorAura(event_observer, target_window, types),
target_window_(target_window) {
- window_observer_.Add(target_window);
+ window_observation_.Observe(target_window);
}
~WindowMonitorAura() override = default;
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override {
DCHECK_EQ(window, target_window_);
- window_observer_.Remove(target_window_);
+ DCHECK(window_observation_.IsObservingSource(target_window_));
+ window_observation_.Reset();
target_window_ = nullptr;
TearDown();
}
private:
aura::Window* target_window_;
- ScopedObserver<aura::Window, aura::WindowObserver> window_observer_{this};
+ base::ScopedObservation<aura::Window, aura::WindowObserver>
+ window_observation_{this};
DISALLOW_COPY_AND_ASSIGN(WindowMonitorAura);
};
diff --git a/chromium/ui/views/examples/BUILD.gn b/chromium/ui/views/examples/BUILD.gn
index 96aa4934dc6..21516c3591f 100644
--- a/chromium/ui/views/examples/BUILD.gn
+++ b/chromium/ui/views/examples/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
import("//testing/test.gni")
import("//tools/grit/grit_rule.gni")
@@ -68,6 +69,8 @@ component("views_examples_lib") {
"table_example.h",
"text_example.cc",
"text_example.h",
+ "textarea_example.cc",
+ "textarea_example.h",
"textfield_example.cc",
"textfield_example.h",
"throbber_example.cc",
@@ -131,6 +134,7 @@ source_set("views_examples_proc") {
":views_examples_lib",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//cc/paint",
"//components/viz/host",
"//components/viz/service",
@@ -144,7 +148,7 @@ source_set("views_examples_proc") {
"//ui/views:test_support",
]
- if (is_win || is_mac || (is_linux && !is_chromeos)) {
+ if (is_win || is_mac || (is_linux || is_chromeos_lacros)) {
sources += [
"examples_skia_gold_pixel_diff.cc",
"examples_skia_gold_pixel_diff.h",
@@ -168,7 +172,7 @@ source_set("views_examples_proc") {
if (use_x11) {
deps += [ "//ui/gfx/x" ]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [
"examples_views_delegate_chromeos.cc",
"examples_views_delegate_chromeos.h",
@@ -205,7 +209,6 @@ component("views_examples_with_content_lib") {
defines = [ "VIEWS_EXAMPLES_WITH_CONTENT_IMPLEMENTATION" ]
deps = [
- ":views_examples_lib",
":views_examples_resources_grd",
":views_examples_resources_pak",
"//base",
@@ -216,6 +219,7 @@ component("views_examples_with_content_lib") {
"//ui/views/controls/webview",
"//url",
]
+ public_deps = [ ":views_examples_lib" ]
}
executable("views_examples_with_content") {
diff --git a/chromium/ui/views/examples/README.md b/chromium/ui/views/examples/README.md
new file mode 100644
index 00000000000..deaa453ba9f
--- /dev/null
+++ b/chromium/ui/views/examples/README.md
@@ -0,0 +1,53 @@
+`views_examples` and `views_examples_with_content` are similar tools to show
+all the views widgets with some varied styles. The latter has extra support to
+`web_view` as well.
+
+*To run either of the programs:*
+
+`<output_dir>/<program> [--enable-examples=<example1,[example2...]>]`
+
+*To get help from the programs:*
+
+`<output_dir>/<program> --help` will print out the above usage info.
+
+`<output_dir>/<program> --enable-examples` will print out all names of available
+examples and execute as if all (the default) are specified.
+
+The current available examples are listed below:
+
+- Accessibility Features
+- Box Layout
+- Bubble
+- Button
+- Button (Sticker Sheet)
+- Checkbox
+- Colored Dialog
+- Combo Box
+- Dialog
+- Flex Layout
+- Label
+- Link
+- Login Bubble Dialog
+- Menu
+- Message Box View
+- Multiline RenderText
+- Native Theme Colors
+- Progress Bar
+- Radio Button
+- Scroll View
+- Slider
+- Tabbed Pane
+- Table
+- Text Styles
+- Textarea
+- Textfield
+- Throbber
+- Toggle Button
+- Tree View
+- Vector Icon
+- WebView
+- Widget
+
+Note: Both programs are available on all desktop platforms which support Views
+toolkit, except `views_examples` unavailable on Mac.
+
diff --git a/chromium/ui/views/examples/bubble_example.cc b/chromium/ui/views/examples/bubble_example.cc
index c820f71d040..18e1633d99a 100644
--- a/chromium/ui/views/examples/bubble_example.cc
+++ b/chromium/ui/views/examples/bubble_example.cc
@@ -95,30 +95,23 @@ void BubbleExample::CreateExampleView(View* container) {
container->SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::Orientation::kHorizontal, gfx::Insets(), 10));
+ no_shadow_legacy_ = container->AddChildView(std::make_unique<LabelButton>(
+ base::BindRepeating(&BubbleExample::ShowBubble, base::Unretained(this),
+ &no_shadow_legacy_, BubbleBorder::NO_SHADOW_LEGACY,
+ false),
+ ASCIIToUTF16("No Shadow Legacy")));
+ standard_shadow_ = container->AddChildView(std::make_unique<LabelButton>(
+ base::BindRepeating(&BubbleExample::ShowBubble, base::Unretained(this),
+ &standard_shadow_, BubbleBorder::STANDARD_SHADOW,
+ false),
+ ASCIIToUTF16("Standard Shadow")));
no_shadow_ = container->AddChildView(std::make_unique<LabelButton>(
base::BindRepeating(&BubbleExample::ShowBubble, base::Unretained(this),
&no_shadow_, BubbleBorder::NO_SHADOW, false),
ASCIIToUTF16("No Shadow")));
- no_shadow_opaque_ = container->AddChildView(std::make_unique<LabelButton>(
- base::BindRepeating(&BubbleExample::ShowBubble, base::Unretained(this),
- &no_shadow_opaque_,
- BubbleBorder::NO_SHADOW_OPAQUE_BORDER, false),
- ASCIIToUTF16("Opaque Border")));
- big_shadow_ = container->AddChildView(std::make_unique<LabelButton>(
- base::BindRepeating(&BubbleExample::ShowBubble, base::Unretained(this),
- &big_shadow_, BubbleBorder::BIG_SHADOW, false),
- ASCIIToUTF16("Big Shadow")));
- small_shadow_ = container->AddChildView(std::make_unique<LabelButton>(
- base::BindRepeating(&BubbleExample::ShowBubble, base::Unretained(this),
- &small_shadow_, BubbleBorder::SMALL_SHADOW, false),
- ASCIIToUTF16("Small Shadow")));
- no_assets_ = container->AddChildView(std::make_unique<LabelButton>(
- base::BindRepeating(&BubbleExample::ShowBubble, base::Unretained(this),
- &no_assets_, BubbleBorder::NO_ASSETS, false),
- ASCIIToUTF16("No Assets")));
persistent_ = container->AddChildView(std::make_unique<LabelButton>(
base::BindRepeating(&BubbleExample::ShowBubble, base::Unretained(this),
- &persistent_, BubbleBorder::NO_SHADOW, true),
+ &persistent_, BubbleBorder::NO_SHADOW_LEGACY, true),
ASCIIToUTF16("Persistent")));
}
diff --git a/chromium/ui/views/examples/bubble_example.h b/chromium/ui/views/examples/bubble_example.h
index f146df6c563..a2a931e29fc 100644
--- a/chromium/ui/views/examples/bubble_example.h
+++ b/chromium/ui/views/examples/bubble_example.h
@@ -32,11 +32,9 @@ class VIEWS_EXAMPLES_EXPORT BubbleExample : public ExampleBase {
bool persistent,
const ui::Event& event);
+ Button* no_shadow_legacy_;
+ Button* standard_shadow_;
Button* no_shadow_;
- Button* no_shadow_opaque_;
- Button* big_shadow_;
- Button* small_shadow_;
- Button* no_assets_;
Button* persistent_;
DISALLOW_COPY_AND_ASSIGN(BubbleExample);
diff --git a/chromium/ui/views/examples/button_example.cc b/chromium/ui/views/examples/button_example.cc
index daeaf564670..f65f18a4860 100644
--- a/chromium/ui/views/examples/button_example.cc
+++ b/chromium/ui/views/examples/button_example.cc
@@ -23,6 +23,7 @@
#include "ui/views/resources/grit/views_resources.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/view.h"
+#include "ui/views/view_utils.h"
using base::ASCIIToUTF16;
@@ -127,12 +128,13 @@ void ButtonExample::LabelButtonPressed(LabelButton* label_button,
label_button->IsAccessibilityFocusable()
? label_button->SetFocusBehavior(View::FocusBehavior::NEVER)
: label_button->SetFocusBehavior(
- PlatformStyle::DefaultFocusBehavior());
+ PlatformStyle::kDefaultFocusBehavior);
}
} else if (event.IsAltDown()) {
label_button->SetIsDefault(!label_button->GetIsDefault());
}
example_view()->GetLayoutManager()->Layout(example_view());
+ PrintViewHierarchy(example_view());
}
void ButtonExample::ImageButtonPressed() {
diff --git a/chromium/ui/views/examples/create_examples.cc b/chromium/ui/views/examples/create_examples.cc
index 1046b4a32d9..112d0b53ddb 100644
--- a/chromium/ui/views/examples/create_examples.cc
+++ b/chromium/ui/views/examples/create_examples.cc
@@ -30,6 +30,7 @@
#include "ui/views/examples/tabbed_pane_example.h"
#include "ui/views/examples/table_example.h"
#include "ui/views/examples/text_example.h"
+#include "ui/views/examples/textarea_example.h"
#include "ui/views/examples/textfield_example.h"
#include "ui/views/examples/throbber_example.h"
#include "ui/views/examples/toggle_button_example.h"
@@ -67,6 +68,7 @@ ExampleVector CreateExamples(ExampleVector extra_examples) {
examples.push_back(std::make_unique<TabbedPaneExample>());
examples.push_back(std::make_unique<TableExample>());
examples.push_back(std::make_unique<TextExample>());
+ examples.push_back(std::make_unique<TextareaExample>());
examples.push_back(std::make_unique<TextfieldExample>());
examples.push_back(std::make_unique<ToggleButtonExample>());
examples.push_back(std::make_unique<ThrobberExample>());
diff --git a/chromium/ui/views/examples/examples_main_proc.cc b/chromium/ui/views/examples/examples_main_proc.cc
index 9c276783152..883b4485071 100644
--- a/chromium/ui/views/examples/examples_main_proc.cc
+++ b/chromium/ui/views/examples/examples_main_proc.cc
@@ -24,6 +24,7 @@
#include "base/test/test_discardable_memory_allocator.h"
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "components/viz/common/features.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
@@ -52,7 +53,7 @@
#include "ui/wm/core/wm_state.h"
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/views/examples/examples_views_delegate_chromeos.h"
#endif
@@ -83,6 +84,9 @@ ExamplesExitCode ExamplesMainProc(bool under_test) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (CheckCommandLineUsage())
+ return ExamplesExitCode::kSucceeded;
+
// Disabling Direct Composition works around the limitation that
// InProcessContextFactory doesn't work with Direct Composition, causing the
// window to not render. See http://crbug.com/936249.
@@ -158,7 +162,7 @@ ExamplesExitCode ExamplesMainProc(bool under_test) {
ExamplesExitCode compare_result = ExamplesExitCode::kSucceeded;
{
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ExamplesViewsDelegateChromeOS views_delegate;
#else
views::DesktopTestViewsDelegate views_delegate;
diff --git a/chromium/ui/views/examples/examples_views_delegate_chromeos.cc b/chromium/ui/views/examples/examples_views_delegate_chromeos.cc
index cc3365f3e19..2a47b1d55f8 100644
--- a/chromium/ui/views/examples/examples_views_delegate_chromeos.cc
+++ b/chromium/ui/views/examples/examples_views_delegate_chromeos.cc
@@ -14,8 +14,7 @@ namespace {
constexpr gfx::Size kDefaultSize(1024, 768);
} // namespace
-ExamplesViewsDelegateChromeOS::ExamplesViewsDelegateChromeOS()
- : observer_(this) {}
+ExamplesViewsDelegateChromeOS::ExamplesViewsDelegateChromeOS() = default;
ExamplesViewsDelegateChromeOS::~ExamplesViewsDelegateChromeOS() = default;
@@ -28,7 +27,7 @@ void ExamplesViewsDelegateChromeOS::OnBeforeWidgetInit(
wm_helper_ = std::make_unique<wm::WMTestHelper>(kDefaultSize);
wm_helper_->host()->Show();
- observer_.Add(wm_helper_->host());
+ observation_.Observe(wm_helper_->host());
params->context = wm_helper_->host()->window();
}
}
@@ -37,7 +36,8 @@ void ExamplesViewsDelegateChromeOS::OnHostCloseRequested(
aura::WindowTreeHost* host) {
Widget* widget = GetExamplesWidget();
if (widget) {
- observer_.Remove(host);
+ DCHECK(observation_.IsObservingSource(host));
+ observation_.Reset();
widget->Close();
}
}
diff --git a/chromium/ui/views/examples/examples_views_delegate_chromeos.h b/chromium/ui/views/examples/examples_views_delegate_chromeos.h
index 1bba04ff8ba..3933cd53ad8 100644
--- a/chromium/ui/views/examples/examples_views_delegate_chromeos.h
+++ b/chromium/ui/views/examples/examples_views_delegate_chromeos.h
@@ -7,7 +7,7 @@
#include <memory>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/aura/window_tree_host.h"
#include "ui/aura/window_tree_host_observer.h"
#include "ui/views/test/desktop_test_views_delegate.h"
@@ -33,7 +33,8 @@ class ExamplesViewsDelegateChromeOS : public DesktopTestViewsDelegate,
// aura::WindowTreeHostObserver:
void OnHostCloseRequested(aura::WindowTreeHost* host) override;
- ScopedObserver<aura::WindowTreeHost, aura::WindowTreeHostObserver> observer_;
+ base::ScopedObservation<aura::WindowTreeHost, aura::WindowTreeHostObserver>
+ observation_{this};
std::unique_ptr<wm::WMTestHelper> wm_helper_;
};
diff --git a/chromium/ui/views/examples/examples_window.cc b/chromium/ui/views/examples/examples_window.cc
index aa986da800b..da35839048c 100644
--- a/chromium/ui/views/examples/examples_window.cc
+++ b/chromium/ui/views/examples/examples_window.cc
@@ -5,6 +5,7 @@
#include "ui/views/examples/examples_window.h"
#include <algorithm>
+#include <iostream>
#include <iterator>
#include <memory>
#include <string>
@@ -32,10 +33,20 @@ namespace views {
namespace examples {
const char kExamplesWidgetName[] = "ExamplesWidget";
+static const char kEnableExamples[] = "enable-examples";
-namespace {
+bool CheckCommandLineUsage() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch("help")) {
+ // Print the program usage.
+ std::cout << "Usage: " << command_line->GetProgram() << " [--"
+ << kEnableExamples << "=<example1,[example2...]>]\n";
+ return true;
+ }
+ return false;
+}
-const char kEnableExamples[] = "enable-examples";
+namespace {
ExampleVector GetExamplesToShow(ExampleVector examples) {
using StringVector = std::vector<std::string>;
@@ -47,7 +58,9 @@ ExampleVector GetExamplesToShow(ExampleVector examples) {
std::string enable_examples =
command_line->GetSwitchValueASCII(kEnableExamples);
+
if (!enable_examples.empty()) {
+ // Filter examples to show based on the command line switch.
StringVector enabled =
base::SplitString(enable_examples, ";,", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
@@ -73,6 +86,16 @@ ExampleVector GetExamplesToShow(ExampleVector examples) {
example->example_title()) == valid_examples.end();
});
}
+ } else if (command_line->HasSwitch(kEnableExamples)) {
+ std::string titles;
+ for (auto& example : examples) {
+ titles += "\n\t";
+ titles += example->example_title();
+ }
+ titles += "\n";
+ std::cout << "By default, all examples will be shown.";
+ std::cout << "You may want to specify the example(s) you want to run:"
+ << titles;
}
for (auto& example : examples)
diff --git a/chromium/ui/views/examples/examples_window.h b/chromium/ui/views/examples/examples_window.h
index 05aa540ea1c..f7f65403e04 100644
--- a/chromium/ui/views/examples/examples_window.h
+++ b/chromium/ui/views/examples/examples_window.h
@@ -23,6 +23,8 @@ namespace examples {
VIEWS_EXAMPLES_EXPORT extern const char kExamplesWidgetName[];
+VIEWS_EXAMPLES_EXPORT bool CheckCommandLineUsage();
+
// Returns the current widget.
VIEWS_EXAMPLES_EXPORT Widget* GetExamplesWidget();
diff --git a/chromium/ui/views/examples/examples_with_content_main.cc b/chromium/ui/views/examples/examples_with_content_main.cc
index fdc4a4f8bd6..31fac3aef46 100644
--- a/chromium/ui/views/examples/examples_with_content_main.cc
+++ b/chromium/ui/views/examples/examples_with_content_main.cc
@@ -9,6 +9,7 @@
#include "build/build_config.h"
#include "content/public/browser/browser_context.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/views/examples/examples_window.h"
#include "ui/views/examples/examples_window_with_content.h"
#include "ui/views_content_client/views_content_client.h"
@@ -65,6 +66,9 @@ int main(int argc, const char** argv) {
ui::ViewsContentClient views_content_client(argc, argv);
#endif
+ if (views::examples::CheckCommandLineUsage())
+ return 0;
+
#if defined(OS_APPLE)
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
// ViewsContentClient expects a const char** argv and
diff --git a/chromium/ui/views/examples/textarea_example.cc b/chromium/ui/views/examples/textarea_example.cc
new file mode 100644
index 00000000000..cf1ddf2a2bb
--- /dev/null
+++ b/chromium/ui/views/examples/textarea_example.cc
@@ -0,0 +1,36 @@
+// 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/examples/textarea_example.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/views/controls/textarea/textarea.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/view.h"
+
+namespace views {
+namespace examples {
+
+TextareaExample::TextareaExample() : ExampleBase("Textarea") {}
+
+void TextareaExample::CreateExampleView(View* container) {
+ constexpr char kLongText[] =
+ "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod"
+ " tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
+ "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
+ "commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate "
+ "velit esse cillum dolore eu fugiat nulla pariatur.\n\nExcepteur sint "
+ "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
+ "mollit anim id est laborum.";
+ auto textarea = std::make_unique<Textarea>();
+ textarea->SetText(base::UTF8ToUTF16(kLongText));
+ container->SetLayoutManager(std::make_unique<views::FillLayout>());
+ container->AddChildView(std::move(textarea));
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/textarea_example.h b/chromium/ui/views/examples/textarea_example.h
new file mode 100644
index 00000000000..2fdf1a8b8fd
--- /dev/null
+++ b/chromium/ui/views/examples/textarea_example.h
@@ -0,0 +1,26 @@
+// 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_EXAMPLES_TEXTAREA_EXAMPLE_H_
+#define UI_VIEWS_EXAMPLES_TEXTAREA_EXAMPLE_H_
+
+#include "base/macros.h"
+#include "ui/views/examples/example_base.h"
+
+namespace views {
+namespace examples {
+
+class VIEWS_EXAMPLES_EXPORT TextareaExample : public ExampleBase {
+ public:
+ TextareaExample();
+ ~TextareaExample() override = default;
+
+ // ExampleBase:
+ void CreateExampleView(View* container) override;
+};
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_TEXTAREA_EXAMPLE_H_
diff --git a/chromium/ui/views/examples/vector_example.cc b/chromium/ui/views/examples/vector_example.cc
index 26b9cf9eff9..50f3f455d4c 100644
--- a/chromium/ui/views/examples/vector_example.cc
+++ b/chromium/ui/views/examples/vector_example.cc
@@ -113,7 +113,7 @@ class VectorIconGallery : public View, public TextfieldController {
void FileGoButtonPressed() {
base::ScopedAllowBlockingForTesting allow_blocking;
#if defined(OS_WIN)
- base::FilePath path(file_chooser_->GetText());
+ base::FilePath path(base::UTF16ToWide(file_chooser_->GetText()));
#else
base::FilePath path(base::UTF16ToUTF8(file_chooser_->GetText()));
#endif
diff --git a/chromium/ui/views/examples/views_examples_resources.grd b/chromium/ui/views/examples/views_examples_resources.grd
index 207bbd371cf..b46b05d1ae8 100644
--- a/chromium/ui/views/examples/views_examples_resources.grd
+++ b/chromium/ui/views/examples/views_examples_resources.grd
@@ -7,7 +7,7 @@
</output>
<output filename="views_examples_resources.pak" type="data_package" lang="en" />
</outputs>
- <release seq="1" allow_pseudo="false">
+ <release seq="1">
<messages fallback_to_english="true">
<!-- colored dialog example -->
<message translateable="false" name="IDS_COLORED_DIALOG_CHOOSER_CHECKBOX">
diff --git a/chromium/ui/views/features.gni b/chromium/ui/views/features.gni
index e1e443cef1f..a85ffb124e5 100644
--- a/chromium/ui/views/features.gni
+++ b/chromium/ui/views/features.gni
@@ -3,7 +3,8 @@
# found in the LICENSE file.
import("//build/config/chromecast_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
# Enable desktop-oriented features implemented by DesktopNativeWidgetAura.
-enable_desktop_aura = use_aura && !is_chromeos && !is_chromecast
+enable_desktop_aura = use_aura && !is_chromeos_ash && !is_chromecast
diff --git a/chromium/ui/views/focus/focus_manager.cc b/chromium/ui/views/focus/focus_manager.cc
index 6fe9cab8422..b6f3bd3bc43 100644
--- a/chromium/ui/views/focus/focus_manager.cc
+++ b/chromium/ui/views/focus/focus_manager.cc
@@ -12,6 +12,7 @@
#include "base/check_op.h"
#include "base/i18n/rtl.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
@@ -621,7 +622,9 @@ bool FocusManager::RedirectAcceleratorToBubbleAnchorWidget(
if (!focus_manager->IsAcceleratorRegistered(accelerator))
return false;
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Processing an accelerator can delete things. Because we
// need these objects afterwards on Linux, save widget_ as weak pointer and
// save the close_on_deactivate property value of widget_delegate in a
@@ -636,7 +639,9 @@ bool FocusManager::RedirectAcceleratorToBubbleAnchorWidget(
const bool accelerator_processed =
focus_manager->ProcessAccelerator(accelerator);
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Need to manually close the bubble widget on Linux. On Linux when the
// bubble is shown, the main widget remains active. Because of that when
// focus is set to the main widget to process accelerator, the main widget
@@ -656,7 +661,8 @@ bool FocusManager::IsArrowKeyTraversalEnabledForWidget() const {
Widget* const widget = (focused_view_ && focused_view_->GetWidget())
? focused_view_->GetWidget()
: widget_;
- return widget->widget_delegate()->enable_arrow_key_traversal();
+ return widget && widget->widget_delegate() &&
+ widget->widget_delegate()->enable_arrow_key_traversal();
}
} // namespace views
diff --git a/chromium/ui/views/layout/animating_layout_manager.cc b/chromium/ui/views/layout/animating_layout_manager.cc
index faa7dd5abff..cc67d166b9b 100644
--- a/chromium/ui/views/layout/animating_layout_manager.cc
+++ b/chromium/ui/views/layout/animating_layout_manager.cc
@@ -11,6 +11,7 @@
#include <vector>
#include "base/auto_reset.h"
+#include "base/containers/contains.h"
#include "base/stl_util.h"
#include "ui/gfx/animation/animation_container.h"
#include "ui/gfx/animation/slide_animation.h"
@@ -145,8 +146,7 @@ class AnimatingLayoutManager::AnimationDelegate
}
void OnViewIsDeleting(View* observed_view) override {
- if (animation_delegate_->scoped_observer_.IsObserving(observed_view))
- animation_delegate_->scoped_observer_.Remove(observed_view);
+ animation_delegate_->scoped_observation_.Reset();
}
private:
@@ -164,7 +164,8 @@ class AnimatingLayoutManager::AnimationDelegate
AnimatingLayoutManager* const target_layout_manager_;
std::unique_ptr<gfx::SlideAnimation> animation_;
ViewWidgetObserver view_widget_observer_{this};
- ScopedObserver<View, ViewObserver> scoped_observer_{&view_widget_observer_};
+ base::ScopedObservation<View, ViewObserver> scoped_observation_{
+ &view_widget_observer_};
};
AnimatingLayoutManager::AnimationDelegate::AnimationDelegate(
@@ -178,7 +179,7 @@ AnimatingLayoutManager::AnimationDelegate::AnimationDelegate(
if (host_view->GetWidget())
MakeReadyForAnimation();
else
- scoped_observer_.Add(host_view);
+ scoped_observation_.Observe(host_view);
UpdateAnimationParameters();
}
@@ -204,8 +205,7 @@ void AnimatingLayoutManager::AnimationDelegate::MakeReadyForAnimation() {
if (!ready_to_animate_) {
target_layout_manager_->ResetLayout();
ready_to_animate_ = true;
- if (scoped_observer_.IsObserving(target_layout_manager_->host_view()))
- scoped_observer_.Remove(target_layout_manager_->host_view());
+ scoped_observation_.Reset();
}
}
diff --git a/chromium/ui/views/layout/animating_layout_manager_unittest.cc b/chromium/ui/views/layout/animating_layout_manager_unittest.cc
index d50d50d1c5a..02f66e60f65 100644
--- a/chromium/ui/views/layout/animating_layout_manager_unittest.cc
+++ b/chromium/ui/views/layout/animating_layout_manager_unittest.cc
@@ -8,7 +8,7 @@
#include <utility>
#include <vector>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -108,7 +108,7 @@ class AnimationEventLogger : public AnimatingLayoutManager::Observer {
~AnimationEventLogger() override = default;
explicit AnimationEventLogger(AnimatingLayoutManager* layout) {
- scoped_observer_.Add(layout);
+ scoped_observation_.Observe(layout);
}
void OnLayoutIsAnimatingChanged(AnimatingLayoutManager* source,
@@ -120,7 +120,8 @@ class AnimationEventLogger : public AnimatingLayoutManager::Observer {
private:
std::vector<bool> events_;
- ScopedObserver<AnimatingLayoutManager, Observer> scoped_observer_{this};
+ base::ScopedObservation<AnimatingLayoutManager, Observer> scoped_observation_{
+ this};
};
} // anonymous namespace
@@ -2879,7 +2880,7 @@ class AnimationWatcher : public AnimatingLayoutManager::Observer {
public:
explicit AnimationWatcher(AnimatingLayoutManager* layout_manager)
: layout_manager_(layout_manager) {
- observer_.Add(layout_manager);
+ observation_.Observe(layout_manager);
}
void OnLayoutIsAnimatingChanged(AnimatingLayoutManager*,
@@ -2901,8 +2902,9 @@ class AnimationWatcher : public AnimatingLayoutManager::Observer {
private:
AnimatingLayoutManager* const layout_manager_;
- ScopedObserver<AnimatingLayoutManager, AnimatingLayoutManager::Observer>
- observer_{this};
+ base::ScopedObservation<AnimatingLayoutManager,
+ AnimatingLayoutManager::Observer>
+ observation_{this};
std::unique_ptr<base::RunLoop> run_loop_;
bool waiting_ = false;
};
diff --git a/chromium/ui/views/layout/box_layout_view.cc b/chromium/ui/views/layout/box_layout_view.cc
index 452fe64da15..c923065d969 100644
--- a/chromium/ui/views/layout/box_layout_view.cc
+++ b/chromium/ui/views/layout/box_layout_view.cc
@@ -8,6 +8,7 @@
#include "ui/gfx/geometry/insets.h"
#include "ui/views/layout/layout_manager.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
namespace views {
@@ -132,4 +133,34 @@ void BoxLayoutView::ClearFlexForView(const View* view) {
InvalidateLayout();
}
+DEFINE_ENUM_CONVERTERS(BoxLayout::Orientation,
+ {BoxLayout::Orientation::kHorizontal,
+ STRING16_LITERAL("kHorizontal")},
+ {BoxLayout::Orientation::kVertical,
+ STRING16_LITERAL("kVertical")})
+
+DEFINE_ENUM_CONVERTERS(
+ BoxLayout::MainAxisAlignment,
+ {BoxLayout::MainAxisAlignment::kStart, STRING16_LITERAL("kStart")},
+ {BoxLayout::MainAxisAlignment::kCenter, STRING16_LITERAL("kCenter")},
+ {BoxLayout::MainAxisAlignment::kEnd, STRING16_LITERAL("kEnd")})
+
+DEFINE_ENUM_CONVERTERS(
+ BoxLayout::CrossAxisAlignment,
+ {BoxLayout::CrossAxisAlignment::kStretch, STRING16_LITERAL("kStretch")},
+ {BoxLayout::CrossAxisAlignment::kStart, STRING16_LITERAL("kStart")},
+ {BoxLayout::CrossAxisAlignment::kCenter, STRING16_LITERAL("kCenter")},
+ {BoxLayout::CrossAxisAlignment::kEnd, STRING16_LITERAL("kEnd")})
+
+BEGIN_METADATA(BoxLayoutView, View)
+ADD_PROPERTY_METADATA(BoxLayout::Orientation, Orientation)
+ADD_PROPERTY_METADATA(BoxLayout::MainAxisAlignment, MainAxisAlignment)
+ADD_PROPERTY_METADATA(BoxLayout::CrossAxisAlignment, CrossAxisAlignment)
+ADD_PROPERTY_METADATA(gfx::Insets, InsideBorderInsets)
+ADD_PROPERTY_METADATA(int, MinimumCrossAxisSize)
+ADD_PROPERTY_METADATA(int, BetweenChildSpacing)
+ADD_PROPERTY_METADATA(int, CollapseMarginsSpacing)
+ADD_PROPERTY_METADATA(int, DefaultFlex)
+END_METADATA
+
} // namespace views
diff --git a/chromium/ui/views/layout/box_layout_view.h b/chromium/ui/views/layout/box_layout_view.h
index 9b0dcad42fe..36dc2ec07c8 100644
--- a/chromium/ui/views/layout/box_layout_view.h
+++ b/chromium/ui/views/layout/box_layout_view.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_LAYOUT_BOX_LAYOUT_VIEW_H_
#include "ui/views/layout/box_layout.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/metadata/view_factory.h"
#include "ui/views/view.h"
@@ -17,6 +18,7 @@ namespace views {
class VIEWS_EXPORT BoxLayoutView : public View {
public:
+ METADATA_HEADER(BoxLayoutView);
BoxLayoutView();
BoxLayoutView(BoxLayoutView&) = delete;
BoxLayoutView& operator=(BoxLayoutView&) = delete;
diff --git a/chromium/ui/views/layout/flex_layout_view.cc b/chromium/ui/views/layout/flex_layout_view.cc
index 0ed1c1e7929..67e4ff8e379 100644
--- a/chromium/ui/views/layout/flex_layout_view.cc
+++ b/chromium/ui/views/layout/flex_layout_view.cc
@@ -6,6 +6,11 @@
#include <memory>
+#include "ui/views/layout/flex_layout_types.h"
+#include "ui/views/layout/layout_types.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
+#include "ui/views/metadata/type_conversion.h"
+
namespace views {
FlexLayoutView::FlexLayoutView()
@@ -140,4 +145,35 @@ FlexRule FlexLayoutView::GetDefaultFlexRule() const {
return layout_->GetDefaultFlexRule();
}
+DEFINE_ENUM_CONVERTERS(LayoutOrientation,
+ {LayoutOrientation::kHorizontal,
+ STRING16_LITERAL("kHorizontal")},
+ {LayoutOrientation::kVertical,
+ STRING16_LITERAL("kVertical")})
+
+DEFINE_ENUM_CONVERTERS(LayoutAlignment,
+ {LayoutAlignment::kStart, STRING16_LITERAL("kStart")},
+ {LayoutAlignment::kCenter, STRING16_LITERAL("kCenter")},
+ {LayoutAlignment::kEnd, STRING16_LITERAL("kEnd")},
+ {LayoutAlignment::kStretch,
+ STRING16_LITERAL("kStretch")})
+
+DEFINE_ENUM_CONVERTERS(FlexAllocationOrder,
+ {FlexAllocationOrder::kNormal,
+ STRING16_LITERAL("kNormal")},
+ {FlexAllocationOrder::kReverse,
+ STRING16_LITERAL("kReverse")})
+
+BEGIN_METADATA(FlexLayoutView, View)
+ADD_PROPERTY_METADATA(LayoutOrientation, Orientation)
+ADD_PROPERTY_METADATA(LayoutAlignment, MainAxisAlignment)
+ADD_PROPERTY_METADATA(LayoutAlignment, CrossAxisAlignment)
+ADD_PROPERTY_METADATA(const gfx::Insets, InteriorMargin)
+ADD_PROPERTY_METADATA(int, MinimumCrossAxisSize)
+ADD_PROPERTY_METADATA(bool, CollapseMargins)
+ADD_PROPERTY_METADATA(bool, IncludeHostInsetsInLayout)
+ADD_PROPERTY_METADATA(bool, IgnoreDefaultMainAxisMargins)
+ADD_PROPERTY_METADATA(FlexAllocationOrder, FlexAllocationOrder)
+END_METADATA
+
} // namespace views
diff --git a/chromium/ui/views/layout/flex_layout_view.h b/chromium/ui/views/layout/flex_layout_view.h
index 135324435dc..0645a5dd90b 100644
--- a/chromium/ui/views/layout/flex_layout_view.h
+++ b/chromium/ui/views/layout/flex_layout_view.h
@@ -7,6 +7,7 @@
#include "ui/views/layout/flex_layout.h"
#include "ui/views/layout/flex_layout_types.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/metadata/view_factory.h"
#include "ui/views/view.h"
#include "ui/views/views_export.h"
@@ -15,6 +16,7 @@ namespace views {
class VIEWS_EXPORT FlexLayoutView : public View {
public:
+ METADATA_HEADER(FlexLayoutView);
FlexLayoutView();
FlexLayoutView(const FlexLayoutView&) = delete;
FlexLayoutView operator=(const FlexLayoutView&) = delete;
diff --git a/chromium/ui/views/layout/grid_layout.cc b/chromium/ui/views/layout/grid_layout.cc
index 1f5bb2d12b6..ad18c6229ba 100644
--- a/chromium/ui/views/layout/grid_layout.cc
+++ b/chromium/ui/views/layout/grid_layout.cc
@@ -9,8 +9,8 @@
#include <numeric>
#include <utility>
+#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
#include "ui/views/border.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/view.h"
diff --git a/chromium/ui/views/layout/layout_manager.h b/chromium/ui/views/layout/layout_manager.h
index 5ff7e10fca6..494f67698a3 100644
--- a/chromium/ui/views/layout/layout_manager.h
+++ b/chromium/ui/views/layout/layout_manager.h
@@ -67,7 +67,11 @@ class VIEWS_EXPORT LayoutManager {
virtual int GetPreferredHeightForWidth(const View* host, int width) const;
// Returns the maximum space available in the layout for the specified child
- // view. Default is unbounded.
+ // view. Default is unbounded. May result in a layout calculation for |host|
+ // if the layout is not valid, so while it can be called during the Layout()
+ // method for |view|, it should never be called during the actual computation
+ // of |host|'s layout (e.g. in a FlexLayout FlexRule calculation) to prevent
+ // an infinite loop.
virtual SizeBounds GetAvailableSize(const View* host, const View* view) const;
// Called when a View is added as a child of the View the LayoutManager has
@@ -91,7 +95,7 @@ class VIEWS_EXPORT LayoutManager {
protected:
// Sets the visibility of a view without triggering ViewVisibilitySet().
- // During Layout(), use this method instead of View::SetVisibility().
+ // During Layout(), use this method instead of View::SetVisible().
void SetViewVisibility(View* view, bool visible);
// Gets the child views of the specified view in paint order (reverse
diff --git a/chromium/ui/views/layout/layout_manager_base.cc b/chromium/ui/views/layout/layout_manager_base.cc
index 68f18747f08..45415289f5a 100644
--- a/chromium/ui/views/layout/layout_manager_base.cc
+++ b/chromium/ui/views/layout/layout_manager_base.cc
@@ -63,6 +63,8 @@ int LayoutManagerBase::GetPreferredHeightForWidth(const View* host,
SizeBounds LayoutManagerBase::GetAvailableSize(const View* host,
const View* view) const {
DCHECK_EQ(host_view_, host);
+ if (!cached_layout_size_)
+ GetProposedLayout(host->size());
if (cached_layout_size_) {
for (const auto& child_layout : cached_layout_.child_layouts)
if (child_layout.child_view == view) {
@@ -92,6 +94,11 @@ std::vector<View*> LayoutManagerBase::GetChildViewsInPaintOrder(
ProposedLayout LayoutManagerBase::GetProposedLayout(
const gfx::Size& host_size) const {
if (cached_layout_size_ != host_size) {
+#if (DCHECK_IS_ON())
+ // This calculation must not be re-entrant.
+ DCHECK(!calculating_layout_);
+ base::AutoReset<bool> calculating_layout(&calculating_layout_, true);
+#endif
cached_layout_size_ = host_size;
cached_layout_ = CalculateProposedLayout(SizeBounds(host_size));
}
diff --git a/chromium/ui/views/layout/layout_manager_base.h b/chromium/ui/views/layout/layout_manager_base.h
index 8812cb5a17b..75362409b82 100644
--- a/chromium/ui/views/layout/layout_manager_base.h
+++ b/chromium/ui/views/layout/layout_manager_base.h
@@ -11,6 +11,7 @@
#include <utility>
#include <vector>
+#include "base/dcheck_is_on.h"
#include "base/macros.h"
#include "base/optional.h"
#include "ui/gfx/geometry/insets.h"
@@ -106,7 +107,7 @@ class VIEWS_EXPORT LayoutManagerBase : public LayoutManager {
// Returns whether the specified child view can be visible. To be able to be
// visible, |child| must be a child of the host view, and must have been
- // visible when it was added or most recently had GetVisible(true) called on
+ // visible when it was added or most recently had SetVisible(true) called on
// it by non-layout code.
bool CanBeVisible(const View* child) const;
@@ -216,6 +217,11 @@ class VIEWS_EXPORT LayoutManagerBase : public LayoutManager {
// whether their bounds have changed.
SizeBounds cached_available_size_;
+#if (DCHECK_IS_ON())
+ // Used to prevent GetProposedLayout() from being re-entrant.
+ mutable bool calculating_layout_ = false;
+#endif
+
// Do some really simple caching because layout generation can cost as much
// as 1ms or more for complex views.
mutable base::Optional<gfx::Size> cached_minimum_size_;
diff --git a/chromium/ui/views/metadata/metadata_impl_macros.h b/chromium/ui/views/metadata/metadata_impl_macros.h
index 0ebcc776042..640d83e6d07 100644
--- a/chromium/ui/views/metadata/metadata_impl_macros.h
+++ b/chromium/ui/views/metadata/metadata_impl_macros.h
@@ -16,33 +16,66 @@
// Generate the implementation of the metadata accessors and internal class with
// additional macros for defining the class' properties.
-#define BEGIN_METADATA_BASE(class_name) BEGIN_METADATA_INTERNAL(class_name)
+#define BEGIN_METADATA_BASE(class_name) \
+ BEGIN_METADATA_INTERNAL( \
+ class_name, METADATA_CLASS_NAME_INTERNAL(class_name), class_name)
-#define BEGIN_METADATA(class_name, parent_class_name) \
- static_assert(std::is_base_of<parent_class_name, class_name>::value, \
- "class not child of parent"); \
- BEGIN_METADATA_INTERNAL(class_name) \
+#define _BEGIN_NESTED_METADATA(outer_class, class_name, parent_class_name) \
+ BEGIN_METADATA_INTERNAL(outer_class::class_name, \
+ METADATA_CLASS_NAME_INTERNAL(class_name), \
+ parent_class_name) \
METADATA_PARENT_CLASS_INTERNAL(parent_class_name)
+#define _BEGIN_METADATA(class_name, parent_class_name) \
+ BEGIN_METADATA_INTERNAL( \
+ class_name, METADATA_CLASS_NAME_INTERNAL(class_name), parent_class_name) \
+ METADATA_PARENT_CLASS_INTERNAL(parent_class_name)
+
+#define _GET_MD_MACRO_NAME(_1, _2, _3, NAME, ...) NAME
+
+// The following macro overloads the above macros. For most cases, only two
+// parameters are used. In some instances when a class is nested within another
+// class, the first parameter should be the outer scope with the remaining
+// parameters same as the non-nested macro.
+
+#define BEGIN_METADATA(class_name1, class_name2, ...) \
+ _GET_MD_MACRO_NAME(class_name1, class_name2, ##__VA_ARGS__, \
+ _BEGIN_NESTED_METADATA, _BEGIN_METADATA) \
+ (class_name1, class_name2, ##__VA_ARGS__)
+
#define END_METADATA }
// This will fail to compile if the property accessors aren't in the form of
-// SetXXXX and GetXXXX.
-#define ADD_PROPERTY_METADATA(property_type, property_name) \
- std::unique_ptr<METADATA_PROPERTY_TYPE_INTERNAL(property_type, \
- property_name)> \
- property_name##_prop = std::make_unique<METADATA_PROPERTY_TYPE_INTERNAL( \
- property_type, property_name)>(#property_name, #property_type); \
+// SetXXXX and GetXXXX. If an explicit type converter is specified, it must have
+// already been specialized. See the comments in type_converter.h for further
+// information.
+#define ADD_PROPERTY_METADATA(property_type, property_name, ...) \
+ auto property_name##_prop = \
+ std::make_unique<METADATA_PROPERTY_TYPE_INTERNAL( \
+ property_type, property_name, ##__VA_ARGS__)>(#property_name, \
+ #property_type); \
AddMemberData(std::move(property_name##_prop));
// This will fail to compile if the property accessor isn't in the form of
-// GetXXXX.
-#define ADD_READONLY_PROPERTY_METADATA(property_type, property_name) \
- std::unique_ptr<METADATA_READONLY_PROPERTY_TYPE_INTERNAL(property_type, \
- property_name)> \
- property_name##_prop = \
- std::make_unique<METADATA_READONLY_PROPERTY_TYPE_INTERNAL( \
- property_type, property_name)>(#property_name, #property_type); \
+// GetXXXX. If an explicit type converter is specified, it must have already
+// been specialized. See the comments in type_converter.h for further
+// information.
+#define ADD_READONLY_PROPERTY_METADATA(property_type, property_name, ...) \
+ auto property_name##_prop = \
+ std::make_unique<METADATA_READONLY_PROPERTY_TYPE_INTERNAL( \
+ property_type, property_name, ##__VA_ARGS__)>(#property_name, \
+ #property_type); \
AddMemberData(std::move(property_name##_prop));
+// Adds a ui::ClassProperty of key |property_key| to metadata.
+// If the property value is an pointer of type |TValue*|, specify
+// |property_type| as |TValue| to allow inspecting the actually value.
+// Otherwise the metadata will treat the pointer as it is.
+#define ADD_CLASS_PROPERTY_METADATA(property_type, property_key, ...) \
+ auto property_key##_prop = \
+ std::make_unique<METADATA_CLASS_PROPERTY_TYPE_INTERNAL( \
+ property_type, property_key, ##__VA_ARGS__)>(property_key, \
+ #property_type); \
+ AddMemberData(std::move(property_key##_prop));
+
#endif // UI_VIEWS_METADATA_METADATA_IMPL_MACROS_H_
diff --git a/chromium/ui/views/metadata/metadata_macros_internal.h b/chromium/ui/views/metadata/metadata_macros_internal.h
index aef3fdd73f3..0fb4f6f9441 100644
--- a/chromium/ui/views/metadata/metadata_macros_internal.h
+++ b/chromium/ui/views/metadata/metadata_macros_internal.h
@@ -14,8 +14,6 @@
// Internal Metadata Generation Helpers ---------------------------------------
#define METADATA_CLASS_NAME_INTERNAL(class_name) class_name##_MetaData
-#define METADATA_FUNCTION_PREFIX_INTERNAL(class_name) \
- class_name::METADATA_CLASS_NAME_INTERNAL(class_name)
// Metadata Accessors ---------------------------------------------------------
#define METADATA_ACCESSORS_INTERNAL(class_name) \
@@ -53,43 +51,53 @@
static views::metadata::ClassMetaData* meta_data_ ALLOW_UNUSED_TYPE; \
}
-#define METADATA_PROPERTY_TYPE_INTERNAL(property_type, property_name) \
- views::metadata::ClassPropertyMetaData< \
- ViewClass, property_type, decltype(&ViewClass::Set##property_name), \
- &ViewClass::Set##property_name, \
- decltype(std::declval<ViewClass>().Get##property_name()), \
- &ViewClass::Get##property_name>
+#define METADATA_PROPERTY_TYPE_INTERNAL(property_type, property_name, ...) \
+ views::metadata::ObjectPropertyMetaData< \
+ ViewClass, property_type, decltype(&ViewClass::Set##property_name), \
+ &ViewClass::Set##property_name, \
+ decltype(std::declval<ViewClass>().Get##property_name()), \
+ &ViewClass::Get##property_name, ##__VA_ARGS__>
-#define METADATA_READONLY_PROPERTY_TYPE_INTERNAL(property_type, property_name) \
- views::metadata::ClassPropertyReadOnlyMetaData< \
+#define METADATA_READONLY_PROPERTY_TYPE_INTERNAL(property_type, property_name, \
+ ...) \
+ views::metadata::ObjectPropertyReadOnlyMetaData< \
ViewClass, property_type, \
decltype(std::declval<ViewClass>().Get##property_name()), \
- &ViewClass::Get##property_name>
+ &ViewClass::Get##property_name, ##__VA_ARGS__>
-#define BEGIN_METADATA_INTERNAL(class_name) \
- views::metadata::ClassMetaData* class_name::METADATA_CLASS_NAME_INTERNAL( \
- class_name)::meta_data_ = nullptr; \
- \
- views::metadata::ClassMetaData* class_name::MetaData() { \
- if (!METADATA_CLASS_NAME_INTERNAL(class_name)::meta_data_) { \
- METADATA_CLASS_NAME_INTERNAL(class_name)::meta_data_ = \
- views::metadata::MakeAndRegisterClassInfo< \
- METADATA_CLASS_NAME_INTERNAL(class_name)>(); \
- } \
- return METADATA_CLASS_NAME_INTERNAL(class_name)::meta_data_; \
- } \
- \
- views::metadata::ClassMetaData* class_name::GetClassMetaData() { \
- return MetaData(); \
- } \
- \
- const char* class_name::GetClassName() const { \
- return class_name::kViewClassName; \
- } \
- const char class_name::kViewClassName[] = #class_name; \
- \
- void METADATA_FUNCTION_PREFIX_INTERNAL(class_name)::BuildMetaData() { \
- SetTypeName(std::string(#class_name));
+#define METADATA_CLASS_PROPERTY_TYPE_INTERNAL(property_type, property_key, \
+ ...) \
+ views::metadata::ClassPropertyMetaData<decltype(property_key), \
+ property_type, ##__VA_ARGS__>
+
+#define BEGIN_METADATA_INTERNAL(qualified_class_name, metadata_class_name, \
+ parent_class_name) \
+ views::metadata::ClassMetaData* \
+ qualified_class_name::metadata_class_name::meta_data_ = nullptr; \
+ \
+ views::metadata::ClassMetaData* qualified_class_name::MetaData() { \
+ static_assert( \
+ std::is_base_of<parent_class_name, qualified_class_name>::value, \
+ "class not child of parent"); \
+ if (!qualified_class_name::metadata_class_name::meta_data_) { \
+ qualified_class_name::metadata_class_name::meta_data_ = \
+ views::metadata::MakeAndRegisterClassInfo< \
+ qualified_class_name::metadata_class_name>(); \
+ } \
+ return qualified_class_name::metadata_class_name::meta_data_; \
+ } \
+ \
+ views::metadata::ClassMetaData* qualified_class_name::GetClassMetaData() { \
+ return MetaData(); \
+ } \
+ \
+ const char* qualified_class_name::GetClassName() const { \
+ return kViewClassName; \
+ } \
+ const char qualified_class_name::kViewClassName[] = #qualified_class_name; \
+ \
+ void qualified_class_name::metadata_class_name::BuildMetaData() { \
+ SetTypeName(std::string(#qualified_class_name));
#define METADATA_PARENT_CLASS_INTERNAL(parent_class_name) \
SetParentClassMetaData(parent_class_name::MetaData());
diff --git a/chromium/ui/views/metadata/metadata_types.cc b/chromium/ui/views/metadata/metadata_types.cc
index 8ed567caf7f..bf467e43a4f 100644
--- a/chromium/ui/views/metadata/metadata_types.cc
+++ b/chromium/ui/views/metadata/metadata_types.cc
@@ -137,10 +137,18 @@ void ClassMetaData::SetTypeName(const std::string& type_name) {
type_name_ = type_name;
}
-void MemberMetaDataBase::SetValueAsString(void* obj,
+void MemberMetaDataBase::SetValueAsString(View* obj,
const base::string16& new_value) {
NOTREACHED();
}
+const char* MemberMetaDataBase::GetMemberNamePrefix() const {
+ return "";
+}
+
+MemberMetaDataBase::ValueStrings MemberMetaDataBase::GetValidValues() const {
+ return ValueStrings();
+}
+
} // namespace metadata
} // namespace views
diff --git a/chromium/ui/views/metadata/metadata_types.h b/chromium/ui/views/metadata/metadata_types.h
index 1d559678351..adb247f0ec4 100644
--- a/chromium/ui/views/metadata/metadata_types.h
+++ b/chromium/ui/views/metadata/metadata_types.h
@@ -14,18 +14,24 @@
#include "ui/views/views_export.h"
namespace views {
+
+class View;
+
namespace metadata {
enum class PropertyFlags : uint32_t {
// By default, properties are read/write. This flag indicates that the given
// property metadata instance needs no special attention.
kEmpty = 0x00,
- // Property metadata instance should be treated as read-only. Calling
- // SetValueAsString() will trigger a NOTREACHED() error under debug.
+ // Property metadata instance should be treated as read-only. SetValueAsString
+ // should not be called since there may not be a conversion from a string for
+ // the type of the property. (see kIsSerializable below for additional info).
+ // Calling SetValueAsString() may trigger a NOTREACHED() error under debug.
kReadOnly = 0x01,
// Property metadata can be serialized to or from a string. Needs to make sure
// this flag is set to have meaningful SetValueAsString() and
- // GetValueFromString().
+ // GetValueFromString(). This is ultimately a signal indicating the underlying
+ // TypeConverter is able to convert the value to/from a string.
kSerializable = 0x100,
};
@@ -140,6 +146,7 @@ class VIEWS_EXPORT ClassMetaData {
// accessors to get/set the value of the member on an object.
class VIEWS_EXPORT MemberMetaDataBase {
public:
+ using ValueStrings = std::vector<base::string16>;
MemberMetaDataBase(const std::string& member_name,
const std::string& member_type)
: member_name_(member_name), member_type_(member_type) {}
@@ -150,16 +157,27 @@ class VIEWS_EXPORT MemberMetaDataBase {
// Access the value of this member and return it as a string.
// |obj| is the instance on which to obtain the value of the property this
// metadata represents.
- virtual base::string16 GetValueAsString(void* obj) const = 0;
+ virtual base::string16 GetValueAsString(View* obj) const = 0;
// Set the value of this member through a string on a specified object.
// |obj| is the instance on which to set the value of the property this
// metadata represents.
- virtual void SetValueAsString(void* obj, const base::string16& new_value);
+ virtual void SetValueAsString(View* obj, const base::string16& new_value);
// Return various information flags about the property.
virtual PropertyFlags GetPropertyFlags() const = 0;
+ // Return a list of valid property values as a vector of strings. An empty
+ // vector indicates that the natural limits of the underlying type applies.
+ virtual ValueStrings GetValidValues() const;
+
+ // Return an optional prefix string used by the ui-devtools frontend to
+ // prepend to the member name which causes a special value editor to become
+ // available. For instance, an SkColor member type would add the "--" string
+ // which tells the frontend to display a color swatch and a color editing
+ // dialog.
+ virtual const char* GetMemberNamePrefix() const;
+
const std::string& member_name() const { return member_name_; }
const std::string& member_type() const { return member_type_; }
diff --git a/chromium/ui/views/metadata/metadata_unittest.cc b/chromium/ui/views/metadata/metadata_unittest.cc
index 3366a46477a..bd6322392a7 100644
--- a/chromium/ui/views/metadata/metadata_unittest.cc
+++ b/chromium/ui/views/metadata/metadata_unittest.cc
@@ -7,6 +7,8 @@
#include "base/strings/string_number_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+#include "ui/base/class_property.h"
+#include "ui/gfx/geometry/insets.h"
#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/metadata/metadata_types.h"
@@ -55,7 +57,7 @@ class MetadataTestBaseView : public views::View {
OnPropertyChanged(&int_property_, views::kPropertyEffectsNone);
}
int GetIntProperty() const { return int_property_; }
- views::PropertyChangedSubscription AddIntPropertyChangedCallback(
+ base::CallbackListSubscription AddIntPropertyChangedCallback(
views::PropertyChangedCallback callback) WARN_UNUSED_RESULT {
return AddPropertyChangedCallback(&int_property_, std::move(callback));
}
@@ -84,7 +86,7 @@ class MetadataTestView : public MetadataTestBaseView {
OnPropertyChanged(&float_property_, views::kPropertyEffectsNone);
}
float GetFloatProperty() const { return float_property_; }
- views::PropertyChangedSubscription AddFloatPropertyChangedCallback(
+ base::CallbackListSubscription AddFloatPropertyChangedCallback(
views::PropertyChangedCallback callback) WARN_UNUSED_RESULT {
return AddPropertyChangedCallback(&float_property_, std::move(callback));
}
@@ -97,6 +99,29 @@ BEGIN_METADATA(MetadataTestView, MetadataTestBaseView)
ADD_PROPERTY_METADATA(float, FloatProperty)
END_METADATA
+// Test view to which class properties are attached.
+class ClassPropertyMetaDataTestView : public views::View {
+ public:
+ ClassPropertyMetaDataTestView() = default;
+ ~ClassPropertyMetaDataTestView() override = default;
+
+ METADATA_HEADER(ClassPropertyMetaDataTestView);
+};
+
+DEFINE_UI_CLASS_PROPERTY_KEY(int, kIntKey, -1)
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Insets, kOwnedInsetsKey1, nullptr)
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Insets, kOwnedInsetsKey2, nullptr)
+DEFINE_UI_CLASS_PROPERTY_KEY(gfx::Insets*, kInsetsKey1, nullptr)
+DEFINE_UI_CLASS_PROPERTY_KEY(gfx::Insets*, kInsetsKey2, nullptr)
+
+BEGIN_METADATA(ClassPropertyMetaDataTestView, views::View)
+ADD_CLASS_PROPERTY_METADATA(int, kIntKey)
+ADD_CLASS_PROPERTY_METADATA(gfx::Insets, kOwnedInsetsKey1)
+ADD_CLASS_PROPERTY_METADATA(gfx::Insets*, kOwnedInsetsKey2)
+ADD_CLASS_PROPERTY_METADATA(gfx::Insets, kInsetsKey1)
+ADD_CLASS_PROPERTY_METADATA(gfx::Insets*, kInsetsKey2)
+END_METADATA
+
TEST_F(MetadataTest, TestFloatMetadataPropertyAccess) {
const float start_value = 12.34f;
@@ -115,7 +140,7 @@ TEST_F(MetadataTest, TestFloatPropertyChangedCallback) {
const float start_value = 12.34f;
MetadataTestView test_obj;
- views::PropertyChangedSubscription callback =
+ base::CallbackListSubscription callback =
test_obj.AddFloatPropertyChangedCallback(base::BindRepeating(
&MetadataTest::OnFloatPropertyChanged, base::Unretained(this)));
@@ -186,3 +211,43 @@ TEST_F(MetadataTest, TestMetaDataFile) {
CHECK_EQ(metadata->file(), "ui/views/metadata/metadata_unittest.cc");
}
+
+TEST_F(MetadataTest, TestClassPropertyMetaData) {
+ ClassPropertyMetaDataTestView view;
+ gfx::Insets insets1(8, 8, 8, 8), insets2 = insets1;
+
+ std::map<std::string, base::string16> expected_kv = {
+ {"kIntKey", base::ASCIIToUTF16("-1")},
+ {"kOwnedInsetsKey1", base::ASCIIToUTF16("(not assigned)")},
+ {"kOwnedInsetsKey2", base::ASCIIToUTF16("(not assigned)")},
+ {"kInsetsKey1", base::ASCIIToUTF16("(not assigned)")},
+ {"kInsetsKey2", base::ASCIIToUTF16("(not assigned)")}};
+
+ auto verify = [&]() {
+ views::metadata::ClassMetaData* metadata = view.GetClassMetaData();
+ for (auto member = metadata->begin(); member != metadata->end(); member++) {
+ std::string key = (*member)->member_name();
+ if (expected_kv.count(key)) {
+ EXPECT_EQ((*member)->GetValueAsString(&view), expected_kv[key]);
+ expected_kv.erase(key);
+ }
+ }
+ EXPECT_EQ(expected_kv.empty(), true);
+ };
+
+ verify();
+
+ view.SetProperty(kIntKey, 1);
+ view.SetProperty(kOwnedInsetsKey1, insets1);
+ view.SetProperty(kOwnedInsetsKey2, insets1);
+ view.SetProperty(kInsetsKey1, &insets1);
+ view.SetProperty(kInsetsKey2, &insets2);
+
+ expected_kv = {{"kIntKey", base::ASCIIToUTF16("1")},
+ {"kOwnedInsetsKey1", base::ASCIIToUTF16("8,8,8,8")},
+ {"kOwnedInsetsKey2", base::ASCIIToUTF16("(assigned)")},
+ {"kInsetsKey1", base::ASCIIToUTF16("8,8,8,8")},
+ {"kInsetsKey2", base::ASCIIToUTF16("(assigned)")}};
+
+ verify();
+}
diff --git a/chromium/ui/views/metadata/property_metadata.h b/chromium/ui/views/metadata/property_metadata.h
index 3dd90433514..d7a8d8dffb3 100644
--- a/chromium/ui/views/metadata/property_metadata.h
+++ b/chromium/ui/views/metadata/property_metadata.h
@@ -11,13 +11,49 @@
#include "base/macros.h"
#include "base/strings/string16.h"
+#include "ui/base/class_property.h"
#include "ui/views/metadata/metadata_cache.h"
#include "ui/views/metadata/metadata_types.h"
#include "ui/views/metadata/type_conversion.h"
+#include "ui/views/view.h"
#include "ui/views/views_export.h"
namespace views {
namespace metadata {
+namespace internal {
+
+template <typename TSource, typename TTarget, typename = void>
+struct DeRefHelper {
+ static TTarget Get(TSource value) { return value; }
+};
+
+template <typename TSource, typename TTarget>
+struct DeRefHelper<
+ TSource,
+ TTarget,
+ typename std::enable_if<!std::is_same<TSource, TTarget>::value>::type> {
+ static TTarget Get(TSource value) { return *value; }
+};
+
+template <typename TKey, typename TValue>
+struct ClassPropertyMetaDataTypeHelper;
+
+template <typename TKValue_, typename TValue_>
+struct ClassPropertyMetaDataTypeHelper<const ui::ClassProperty<TKValue_>* const,
+ TValue_> {
+ using TKValue = TKValue_;
+ using TValue = TValue_;
+
+ // Returns |value| when |TKValue| == |TValue|. Otherwise, TKValue must be the
+ // pointer type to TValue, returns |*value| instead.
+ // This is useful for owned propertyies like ui::ClassProperty<gfx::Insets*>
+ // where we want to inspect the actual value, rather than the pointer.
+ static TValue DeRef(TKValue value) {
+ return DeRefHelper<TKValue, TValue>::Get(value);
+ }
+};
+
+} // namespace internal
// Represents meta data for a specific read-only property member of class
// |TClass|, with underlying type |TValue|, as the type of the actual member.
@@ -26,29 +62,36 @@ namespace metadata {
template <typename TClass,
typename TValue,
typename TRet,
- TRet (TClass::*Get)() const>
-class ClassPropertyReadOnlyMetaData : public MemberMetaDataBase {
+ TRet (TClass::*Get)() const,
+ typename TConverter = TypeConverter<TValue>>
+class ObjectPropertyReadOnlyMetaData : public MemberMetaDataBase {
public:
using MemberMetaDataBase::MemberMetaDataBase;
- ~ClassPropertyReadOnlyMetaData() override = default;
-
- base::string16 GetValueAsString(void* obj) const override {
- if (!kIsSerializable)
+ ObjectPropertyReadOnlyMetaData(const ObjectPropertyReadOnlyMetaData&) =
+ delete;
+ ObjectPropertyReadOnlyMetaData& operator=(
+ const ObjectPropertyReadOnlyMetaData&) = delete;
+ ~ObjectPropertyReadOnlyMetaData() override = default;
+
+ base::string16 GetValueAsString(View* obj) const override {
+ if (!kTypeIsSerializable && !kTypeIsReadOnly)
return base::string16();
- return TypeConverter<TValue>::ToString((static_cast<TClass*>(obj)->*Get)());
+ return TConverter::ToString((static_cast<TClass*>(obj)->*Get)());
}
PropertyFlags GetPropertyFlags() const override {
- return kIsSerializable
+ return kTypeIsSerializable
? (PropertyFlags::kReadOnly | PropertyFlags::kSerializable)
: PropertyFlags::kReadOnly;
}
- private:
- static constexpr bool kIsSerializable =
- TypeConverter<TValue>::is_serializable;
+ const char* GetMemberNamePrefix() const override {
+ return TConverter::PropertyNamePrefix();
+ }
- DISALLOW_COPY_AND_ASSIGN(ClassPropertyReadOnlyMetaData);
+ private:
+ static constexpr bool kTypeIsSerializable = TConverter::is_serializable;
+ static constexpr bool kTypeIsReadOnly = TConverter::is_read_only;
};
// Represents meta data for a specific property member of class |TClass|, with
@@ -61,34 +104,99 @@ template <typename TClass,
typename TSig,
TSig Set,
typename TRet,
- TRet (TClass::*Get)() const>
-class ClassPropertyMetaData
- : public ClassPropertyReadOnlyMetaData<TClass, TValue, TRet, Get> {
+ TRet (TClass::*Get)() const,
+ typename TConverter = TypeConverter<TValue>>
+class ObjectPropertyMetaData
+ : public ObjectPropertyReadOnlyMetaData<TClass,
+ TValue,
+ TRet,
+ Get,
+ TConverter> {
public:
- using ClassPropertyReadOnlyMetaData<TClass, TValue, TRet, Get>::
- ClassPropertyReadOnlyMetaData;
- ~ClassPropertyMetaData() override = default;
-
- void SetValueAsString(void* obj, const base::string16& new_value) override {
- if (!kIsSerializable)
+ using ObjectPropertyReadOnlyMetaData<TClass, TValue, TRet, Get, TConverter>::
+ ObjectPropertyReadOnlyMetaData;
+ ObjectPropertyMetaData(const ObjectPropertyMetaData&) = delete;
+ ObjectPropertyMetaData& operator=(const ObjectPropertyMetaData&) = delete;
+ ~ObjectPropertyMetaData() override = default;
+
+ void SetValueAsString(View* obj, const base::string16& new_value) override {
+ if (!kTypeIsSerializable || kTypeIsReadOnly)
return;
- if (base::Optional<TValue> result =
- TypeConverter<TValue>::FromString(new_value)) {
+ if (base::Optional<TValue> result = TConverter::FromString(new_value)) {
(static_cast<TClass*>(obj)->*Set)(std::move(result.value()));
}
}
+ MemberMetaDataBase::ValueStrings GetValidValues() const override {
+ if (!kTypeIsSerializable)
+ return {};
+ return TConverter::GetValidStrings();
+ }
+
+ PropertyFlags GetPropertyFlags() const override {
+ PropertyFlags flags = PropertyFlags::kEmpty;
+ if (kTypeIsSerializable)
+ flags = flags | PropertyFlags::kSerializable;
+ if (kTypeIsReadOnly)
+ flags = flags | PropertyFlags::kReadOnly;
+ return flags;
+ }
+
+ private:
+ static constexpr bool kTypeIsSerializable = TConverter::is_serializable;
+ static constexpr bool kTypeIsReadOnly = TConverter::is_read_only;
+};
+
+// Represents metadata for a ui::ClassProperty attached on a class instance.
+// Converts property value to |TValue| when possible. This allows inspecting
+// the actual value when the property is a pointer of type |TValue*|.
+template <typename TKey,
+ typename TValue,
+ typename TConverter = TypeConverter<TValue>>
+class ClassPropertyMetaData : public MemberMetaDataBase {
+ public:
+ using TypeHelper = internal::ClassPropertyMetaDataTypeHelper<TKey, TValue>;
+ ClassPropertyMetaData(TKey key, const std::string& property_type)
+ : MemberMetaDataBase(key->name, property_type), key_(key) {}
+ ClassPropertyMetaData(const ClassPropertyMetaData&) = delete;
+ ClassPropertyMetaData& operator=(const ClassPropertyMetaData&) = delete;
+ ~ClassPropertyMetaData() override = default;
+
+ // Returns the property value as a string.
+ // If the property value is an pointer of type |TKValue*| and
+ // |TKValue| == |TValue|, dereferences the pointer.
+ base::string16 GetValueAsString(View* obj) const override {
+ typename TypeHelper::TKValue value = obj->GetProperty(key_);
+ if (std::is_pointer<typename TypeHelper::TKValue>::value && !value) {
+ return base::ASCIIToUTF16("(not assigned)");
+ } else {
+ // GetProperty() returns a pointer when this is an owned property.
+ // If |TValue| is not pointer, DeRef() returns |*value|, otherwise
+ // it returns |value| as it is.
+ return TConverter::ToString(TypeHelper::DeRef(value));
+ }
+ }
+
+ void SetValueAsString(View* obj, const base::string16& new_value) override {
+ base::Optional<TValue> value = TConverter::FromString(new_value);
+ if (value)
+ obj->SetProperty(key_, *value);
+ }
+
PropertyFlags GetPropertyFlags() const override {
- return kIsSerializable
- ? (PropertyFlags::kEmpty | PropertyFlags::kSerializable)
- : PropertyFlags::kEmpty;
+ PropertyFlags flags = PropertyFlags::kEmpty;
+ if (kTypeIsSerializable)
+ flags = flags | PropertyFlags::kSerializable;
+ if (kTypeIsReadOnly)
+ flags = flags | PropertyFlags::kReadOnly;
+ return flags;
}
private:
- static constexpr bool kIsSerializable =
- TypeConverter<TValue>::is_serializable;
+ TKey key_;
- DISALLOW_COPY_AND_ASSIGN(ClassPropertyMetaData);
+ static constexpr bool kTypeIsSerializable = TConverter::is_serializable;
+ static constexpr bool kTypeIsReadOnly = TConverter::is_read_only;
};
} // namespace metadata
diff --git a/chromium/ui/views/metadata/type_conversion.cc b/chromium/ui/views/metadata/type_conversion.cc
index ac0cf7632dc..cd2bcbd48e5 100644
--- a/chromium/ui/views/metadata/type_conversion.cc
+++ b/chromium/ui/views/metadata/type_conversion.cc
@@ -4,21 +4,39 @@
#include "ui/views/metadata/type_conversion.h"
+#include <cmath>
+#include <string>
+
+#include "base/numerics/ranges.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/url_formatter/url_fixer.h"
+#include "third_party/skia/include/core/SkScalar.h"
#include "ui/base/ime/text_input_type.h"
+#include "ui/gfx/color_utils.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/bubble/bubble_border.h"
+#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/scroll_view.h"
namespace views {
namespace metadata {
+const char kNoPrefix[] = "";
+const char kSkColorPrefix[] = "--";
+
+base::string16 PointerToString(const void* pointer_val) {
+ return pointer_val ? base::ASCIIToUTF16("(assigned)")
+ : base::ASCIIToUTF16("(not assigned)");
+}
+
const base::string16& GetNullOptStr() {
static const base::NoDestructor<base::string16> kNullOptStr(
base::ASCIIToUTF16("<Empty>"));
@@ -47,10 +65,19 @@ base::string16 TypeConverter<bool>::ToString(bool source_value) {
return base::ASCIIToUTF16(source_value ? "true" : "false");
}
+ValidStrings TypeConverter<bool>::GetValidStrings() {
+ return {base::ASCIIToUTF16("false"), base::ASCIIToUTF16("true")};
+}
+
base::string16 TypeConverter<const char*>::ToString(const char* source_value) {
return base::UTF8ToUTF16(source_value);
}
+base::string16 TypeConverter<base::FilePath>::ToString(
+ const base::FilePath& source_value) {
+ return source_value.AsUTF16Unsafe();
+}
+
base::string16 TypeConverter<base::string16>::ToString(
const base::string16& source_value) {
return source_value;
@@ -59,7 +86,37 @@ base::string16 TypeConverter<base::string16>::ToString(
base::string16 TypeConverter<base::TimeDelta>::ToString(
const base::TimeDelta& source_value) {
return base::NumberToString16(source_value.InSecondsF()) +
- base::ASCIIToUTF16(" s");
+ base::ASCIIToUTF16("s");
+}
+
+base::string16 TypeConverter<gfx::Insets>::ToString(
+ const gfx::Insets& source_value) {
+ return base::ASCIIToUTF16(source_value.ToString());
+}
+
+base::string16 TypeConverter<gfx::Point>::ToString(
+ const gfx::Point& source_value) {
+ return base::ASCIIToUTF16(source_value.ToString());
+}
+
+base::string16 TypeConverter<gfx::PointF>::ToString(
+ const gfx::PointF& source_value) {
+ return base::ASCIIToUTF16(source_value.ToString());
+}
+
+base::string16 TypeConverter<gfx::Range>::ToString(
+ const gfx::Range& source_value) {
+ return base::ASCIIToUTF16(source_value.ToString());
+}
+
+base::string16 TypeConverter<gfx::Rect>::ToString(
+ const gfx::Rect& source_value) {
+ return base::ASCIIToUTF16(source_value.ToString());
+}
+
+base::string16 TypeConverter<gfx::RectF>::ToString(
+ const gfx::RectF& source_value) {
+ return base::ASCIIToUTF16(source_value.ToString());
}
base::string16 TypeConverter<gfx::ShadowValues>::ToString(
@@ -76,21 +133,22 @@ base::string16 TypeConverter<gfx::ShadowValues>::ToString(
base::string16 TypeConverter<gfx::Size>::ToString(
const gfx::Size& source_value) {
- return base::ASCIIToUTF16(base::StringPrintf("{%i, %i}", source_value.width(),
- source_value.height()));
+ return base::ASCIIToUTF16(source_value.ToString());
}
-base::string16 TypeConverter<gfx::Range>::ToString(
- const gfx::Range& source_value) {
- return base::ASCIIToUTF16(base::StringPrintf(
- "{%i, %i}", source_value.GetMin(), source_value.GetMax()));
+base::string16 TypeConverter<gfx::SizeF>::ToString(
+ const gfx::SizeF& source_value) {
+ return base::ASCIIToUTF16(source_value.ToString());
}
-base::string16 TypeConverter<gfx::Insets>::ToString(
- const gfx::Insets& source_value) {
- return base::ASCIIToUTF16(base::StringPrintf(
- "{%d, %d, %d, %d}", source_value.top(), source_value.left(),
- source_value.bottom(), source_value.right()));
+base::string16 TypeConverter<GURL>::ToString(const GURL& source_value) {
+ return base::ASCIIToUTF16(source_value.possibly_invalid_spec());
+}
+
+base::string16 TypeConverter<url::Component>::ToString(
+ const url::Component& source_value) {
+ return base::ASCIIToUTF16(
+ base::StringPrintf("{%d,%d}", source_value.begin, source_value.len));
}
base::Optional<int8_t> TypeConverter<int8_t>::FromString(
@@ -129,7 +187,7 @@ base::Optional<int64_t> TypeConverter<int64_t>::FromString(
base::Optional<uint8_t> TypeConverter<uint8_t>::FromString(
const base::string16& source_value) {
- uint32_t ret = 0;
+ unsigned ret = 0;
if (base::StringToUint(source_value, &ret) &&
base::IsValueInRangeForNumericType<uint8_t>(ret)) {
return static_cast<uint8_t>(ret);
@@ -139,7 +197,7 @@ base::Optional<uint8_t> TypeConverter<uint8_t>::FromString(
base::Optional<uint16_t> TypeConverter<uint16_t>::FromString(
const base::string16& source_value) {
- uint32_t ret = 0;
+ unsigned ret = 0;
if (base::StringToUint(source_value, &ret) &&
base::IsValueInRangeForNumericType<uint16_t>(ret)) {
return static_cast<uint16_t>(ret);
@@ -149,7 +207,7 @@ base::Optional<uint16_t> TypeConverter<uint16_t>::FromString(
base::Optional<uint32_t> TypeConverter<uint32_t>::FromString(
const base::string16& source_value) {
- unsigned int value;
+ unsigned value;
return base::StringToUint(source_value, &value) ? base::make_optional(value)
: base::nullopt;
}
@@ -190,16 +248,101 @@ base::Optional<base::string16> TypeConverter<base::string16>::FromString(
return source_value;
}
+base::Optional<base::FilePath> TypeConverter<base::FilePath>::FromString(
+ const base::string16& source_value) {
+ return base::FilePath::FromUTF16Unsafe(source_value);
+}
+
base::Optional<base::TimeDelta> TypeConverter<base::TimeDelta>::FromString(
const base::string16& source_value) {
- if (!base::EndsWith(source_value, base::ASCIIToUTF16(" s"),
- base::CompareCase::SENSITIVE))
+ std::string source = base::UTF16ToUTF8(source_value);
+ return base::TimeDelta::FromString(source);
+}
+
+base::Optional<gfx::Insets> TypeConverter<gfx::Insets>::FromString(
+ const base::string16& source_value) {
+ const auto values =
+ base::SplitStringPiece(source_value, base::ASCIIToUTF16(","),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ int top, left, bottom, right;
+ if ((values.size() == 4) && base::StringToInt(values[0], &top) &&
+ base::StringToInt(values[1], &left) &&
+ base::StringToInt(values[2], &bottom) &&
+ base::StringToInt(values[3], &right)) {
+ return gfx::Insets(top, left, bottom, right);
+ }
+ return base::nullopt;
+}
+
+base::Optional<gfx::Point> TypeConverter<gfx::Point>::FromString(
+ const base::string16& source_value) {
+ const auto values =
+ base::SplitStringPiece(source_value, base::ASCIIToUTF16(","),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ int x, y;
+ if ((values.size() == 2) && base::StringToInt(values[0], &x) &&
+ base::StringToInt(values[1], &y)) {
+ return gfx::Point(x, y);
+ }
+ return base::nullopt;
+}
+
+base::Optional<gfx::PointF> TypeConverter<gfx::PointF>::FromString(
+ const base::string16& source_value) {
+ const auto values =
+ base::SplitStringPiece(source_value, base::ASCIIToUTF16(","),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ double x, y;
+ if ((values.size() == 2) && base::StringToDouble(values[0], &x) &&
+ base::StringToDouble(values[1], &y)) {
+ return gfx::PointF(x, y);
+ }
+ return base::nullopt;
+}
+
+base::Optional<gfx::Range> TypeConverter<gfx::Range>::FromString(
+ const base::string16& source_value) {
+ const auto values =
+ base::SplitStringPiece(source_value, base::ASCIIToUTF16("{,}"),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ unsigned min, max;
+ if ((values.size() == 2) && base::StringToUint(values[0], &min) &&
+ base::StringToUint(values[1], &max)) {
+ return gfx::Range(min, max);
+ }
+ return base::nullopt;
+}
+
+base::Optional<gfx::Rect> TypeConverter<gfx::Rect>::FromString(
+ const base::string16& source_value) {
+ const auto values =
+ base::SplitString(source_value, base::ASCIIToUTF16(" "),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ if (values.size() != 2)
return base::nullopt;
- double ret;
- return base::StringToDouble(source_value.substr(0, source_value.length() - 2),
- &ret)
- ? base::make_optional(base::TimeDelta::FromSecondsD(ret))
- : base::nullopt;
+ const base::Optional<gfx::Point> origin =
+ TypeConverter<gfx::Point>::FromString(values[0]);
+ const base::Optional<gfx::Size> size =
+ TypeConverter<gfx::Size>::FromString(values[1]);
+ if (origin && size)
+ return gfx::Rect(*origin, *size);
+ return base::nullopt;
+}
+
+base::Optional<gfx::RectF> TypeConverter<gfx::RectF>::FromString(
+ const base::string16& source_value) {
+ const auto values =
+ base::SplitString(source_value, base::ASCIIToUTF16(" "),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ if (values.size() != 2)
+ return base::nullopt;
+ const base::Optional<gfx::PointF> origin =
+ TypeConverter<gfx::PointF>::FromString(values[0]);
+ const base::Optional<gfx::SizeF> size =
+ TypeConverter<gfx::SizeF>::FromString(values[1]);
+ if (origin && size)
+ return gfx::RectF(*origin, *size);
+ return base::nullopt;
}
base::Optional<gfx::ShadowValues> TypeConverter<gfx::ShadowValues>::FromString(
@@ -210,21 +353,27 @@ base::Optional<gfx::ShadowValues> TypeConverter<gfx::ShadowValues>::FromString(
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
for (auto v : shadow_value_strings) {
- base::string16 member_string;
- base::RemoveChars(v, base::ASCIIToUTF16("()rgba"), &member_string);
- const auto members = base::SplitStringPiece(
- member_string, base::ASCIIToUTF16(","), base::TRIM_WHITESPACE,
- base::SPLIT_WANT_NONEMPTY);
- int x, y, r, g, b, a;
+ base::string16 value = base::string16(v);
+ base::String16Tokenizer tokenizer(
+ value, base::ASCIIToUTF16("(,)"),
+ base::String16Tokenizer::WhitespacePolicy::kSkipOver);
+ tokenizer.set_options(base::String16Tokenizer::RETURN_DELIMS);
+ int x, y;
double blur;
-
- if ((members.size() == 7) && base::StringToInt(members[0], &x) &&
- base::StringToInt(members[1], &y) &&
- base::StringToDouble(UTF16ToASCII(members[2]), &blur) &&
- base::StringToInt(members[3], &r) &&
- base::StringToInt(members[4], &g) &&
- base::StringToInt(members[5], &b) && base::StringToInt(members[6], &a))
- ret.emplace_back(gfx::Vector2d(x, y), blur, SkColorSetARGB(a, r, g, b));
+ if (tokenizer.GetNext() && tokenizer.token() == base::ASCIIToUTF16("(") &&
+ tokenizer.GetNext() && base::StringToInt(tokenizer.token(), &x) &&
+ tokenizer.GetNext() && tokenizer.token() == base::ASCIIToUTF16(",") &&
+ tokenizer.GetNext() && base::StringToInt(tokenizer.token(), &y) &&
+ tokenizer.GetNext() && tokenizer.token() == base::ASCIIToUTF16(")") &&
+ tokenizer.GetNext() && tokenizer.token() == base::ASCIIToUTF16(",") &&
+ tokenizer.GetNext() && base::StringToDouble(tokenizer.token(), &blur) &&
+ tokenizer.GetNext() && tokenizer.token() == base::ASCIIToUTF16(",") &&
+ tokenizer.GetNext()) {
+ const auto color =
+ SkColorConverter::GetNextColor(tokenizer.token_begin(), value.cend());
+ if (color)
+ ret.emplace_back(gfx::Vector2d(x, y), blur, color.value());
+ }
}
return ret;
}
@@ -232,7 +381,7 @@ base::Optional<gfx::ShadowValues> TypeConverter<gfx::ShadowValues>::FromString(
base::Optional<gfx::Size> TypeConverter<gfx::Size>::FromString(
const base::string16& source_value) {
const auto values =
- base::SplitStringPiece(source_value, base::ASCIIToUTF16("{,}"),
+ base::SplitStringPiece(source_value, base::ASCIIToUTF16("x"),
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
int width, height;
if ((values.size() == 2) && base::StringToInt(values[0], &width) &&
@@ -242,34 +391,205 @@ base::Optional<gfx::Size> TypeConverter<gfx::Size>::FromString(
return base::nullopt;
}
-base::Optional<gfx::Range> TypeConverter<gfx::Range>::FromString(
+base::Optional<gfx::SizeF> TypeConverter<gfx::SizeF>::FromString(
+ const base::string16& source_value) {
+ const auto values =
+ base::SplitStringPiece(source_value, base::ASCIIToUTF16("x"),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ double width, height;
+ if ((values.size() == 2) && base::StringToDouble(values[0], &width) &&
+ base::StringToDouble(values[1], &height)) {
+ return gfx::SizeF(width, height);
+ }
+ return base::nullopt;
+}
+
+base::Optional<GURL> TypeConverter<GURL>::FromString(
+ const base::string16& source_value) {
+ const GURL url =
+ url_formatter::FixupURL(base::UTF16ToUTF8(source_value), std::string());
+ return url.is_valid() ? base::make_optional(url) : base::nullopt;
+}
+
+base::Optional<url::Component> TypeConverter<url::Component>::FromString(
const base::string16& source_value) {
const auto values =
base::SplitStringPiece(source_value, base::ASCIIToUTF16("{,}"),
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- int min, max;
- if ((values.size() == 2) && base::StringToInt(values[0], &min) &&
- base::StringToInt(values[1], &max)) {
- return gfx::Range(min, max);
+ int begin, len;
+ if ((values.size() == 2) && base::StringToInt(values[0], &begin) &&
+ base::StringToInt(values[1], &len) && len >= -1) {
+ return url::Component(begin, len);
}
return base::nullopt;
}
-base::Optional<gfx::Insets> TypeConverter<gfx::Insets>::FromString(
+base::string16 TypeConverter<UNIQUE_TYPE_NAME(SkColor)>::ToString(
+ SkColor source_value) {
+ return base::UTF8ToUTF16(color_utils::SkColorToRgbaString(source_value));
+}
+
+base::Optional<SkColor> TypeConverter<UNIQUE_TYPE_NAME(SkColor)>::FromString(
const base::string16& source_value) {
+ return GetNextColor(source_value.cbegin(), source_value.cend());
+}
+
+ValidStrings TypeConverter<UNIQUE_TYPE_NAME(SkColor)>::GetValidStrings() {
+ return {};
+}
+
+bool TypeConverter<UNIQUE_TYPE_NAME(SkColor)>::GetNextColor(
+ base::string16::const_iterator start,
+ base::string16::const_iterator end,
+ base::string16& color,
+ base::string16::const_iterator& next_token) {
+ static const auto open_paren = STRING16_LITERAL('(');
+ static const auto close_paren = STRING16_LITERAL(')');
+ static const std::vector<base::string16> schemes = {
+ base::ASCIIToUTF16("hsl"), base::ASCIIToUTF16("hsla"),
+ base::ASCIIToUTF16("rgb"), base::ASCIIToUTF16("rgba")};
+ base::String16Tokenizer tokenizer(
+ start, end, base::ASCIIToUTF16("(,)"),
+ base::String16Tokenizer::WhitespacePolicy::kSkipOver);
+ tokenizer.set_options(base::String16Tokenizer::RETURN_DELIMS);
+ for (; tokenizer.GetNext();) {
+ if (!tokenizer.token_is_delim()) {
+ base::StringPiece16 token = tokenizer.token_piece();
+ base::string16::const_iterator start_color = tokenizer.token_begin();
+ if (base::ranges::find(schemes.begin(), schemes.end(), token) !=
+ schemes.end()) {
+ if (!tokenizer.GetNext() || *tokenizer.token_begin() != open_paren)
+ return false;
+ for (;
+ tokenizer.GetNext() && *tokenizer.token_begin() != close_paren;) {
+ }
+ if (*tokenizer.token_begin() != close_paren)
+ return false;
+ }
+ next_token = tokenizer.token_end();
+ color = base::string16(start_color, next_token);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TypeConverter<UNIQUE_TYPE_NAME(SkColor)>::GetNextColor(
+ base::string16::const_iterator start,
+ base::string16::const_iterator end,
+ base::string16& color) {
+ base::string16::const_iterator next_token;
+ return GetNextColor(start, end, color, next_token);
+}
+
+base::Optional<SkColor> TypeConverter<UNIQUE_TYPE_NAME(SkColor)>::GetNextColor(
+ base::string16::const_iterator start,
+ base::string16::const_iterator end,
+ base::string16::const_iterator& next_token) {
+ base::string16 color;
+ if (GetNextColor(start, end, color, next_token)) {
+ if (base::StartsWith(color, base::ASCIIToUTF16("hsl"),
+ base::CompareCase::SENSITIVE))
+ return ParseHslString(color);
+ if (base::StartsWith(color, base::ASCIIToUTF16("rgb"),
+ base::CompareCase::SENSITIVE))
+ return ParseRgbString(color);
+ if (base::StartsWith(color, base::ASCIIToUTF16("0x"),
+ base::CompareCase::INSENSITIVE_ASCII))
+ return ParseHexString(color);
+ SkColor value;
+ if (base::StringToUint(color, &value))
+ return base::make_optional(value);
+ }
+ return base::nullopt;
+}
+
+base::Optional<SkColor> TypeConverter<UNIQUE_TYPE_NAME(SkColor)>::GetNextColor(
+ base::string16::const_iterator start,
+ base::string16::const_iterator end) {
+ base::string16::const_iterator next_token;
+ return GetNextColor(start, end, next_token);
+}
+
+base::Optional<SkColor>
+TypeConverter<UNIQUE_TYPE_NAME(SkColor)>::RgbaPiecesToSkColor(
+ const std::vector<base::StringPiece16>& pieces,
+ size_t start_piece) {
+ int r, g, b;
+ double a;
+ return ((pieces.size() >= start_piece + 4) &&
+ base::StringToInt(pieces[start_piece], &r) &&
+ base::IsValueInRangeForNumericType<uint8_t>(r) &&
+ base::StringToInt(pieces[start_piece + 1], &g) &&
+ base::IsValueInRangeForNumericType<uint8_t>(g) &&
+ base::StringToInt(pieces[start_piece + 2], &b) &&
+ base::IsValueInRangeForNumericType<uint8_t>(b) &&
+ base::StringToDouble(pieces[start_piece + 3], &a) && a >= 0.0 &&
+ a <= 1.0)
+ ? base::make_optional(SkColorSetARGB(
+ base::ClampRound<SkAlpha>(a * SK_AlphaOPAQUE), r, g, b))
+ : base::nullopt;
+}
+
+base::Optional<SkColor>
+TypeConverter<UNIQUE_TYPE_NAME(SkColor)>::ParseHexString(
+ const base::string16& hex_string) {
+ SkColor value;
+ if (base::HexStringToUInt(base::UTF16ToUTF8(hex_string), &value)) {
+ // Add in a 1.0 alpha channel if it wasn't included in the input.
+ if (hex_string.length() <= 8)
+ value = SkColorSetA(value, 0xFF);
+ return base::make_optional(value);
+ }
+ return base::nullopt;
+}
+
+base::Optional<SkColor>
+TypeConverter<UNIQUE_TYPE_NAME(SkColor)>::ParseHslString(
+ const base::string16& hsl_string) {
+ base::string16 pruned_string;
+ base::RemoveChars(hsl_string, base::ASCIIToUTF16("(%)hsla"), &pruned_string);
const auto values =
- base::SplitStringPiece(source_value, base::ASCIIToUTF16("{,,,}"),
+ base::SplitStringPiece(pruned_string, base::ASCIIToUTF16(", "),
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- int top, left, bottom, right;
- if ((values.size() == 4) && base::StringToInt(values[0], &top) &&
- base::StringToInt(values[1], &left) &&
- base::StringToInt(values[2], &bottom) &&
- base::StringToInt(values[3], &right)) {
- return gfx::Insets(top, left, bottom, right);
+ double h, s, v;
+ double a = 1.0;
+ if (values.size() >= 3 && values.size() <= 4 &&
+ base::StringToDouble(values[0], &h) &&
+ base::StringToDouble(values[1], &s) &&
+ base::StringToDouble(values[2], &v) &&
+ (values.size() == 3 ||
+ (base::StringToDouble(values[3], &a) && a >= 0.0 && a <= 1.0))) {
+ SkScalar hsv[3];
+ hsv[0] = base::ClampToRange(std::fmod(h, 360.0), 0.0, 360.0);
+ hsv[1] = s > 1.0 ? base::ClampToRange(s, 0.0, 100.0) / 100.0
+ : base::ClampToRange(s, 0.0, 1.0);
+ hsv[2] = v > 1.0 ? base::ClampToRange(v, 0.0, 100.0) / 100.0
+ : base::ClampToRange(v, 0.0, 1.0);
+ return base::make_optional(
+ SkHSVToColor(base::ClampRound<SkAlpha>(a * SK_AlphaOPAQUE), hsv));
}
return base::nullopt;
}
+base::Optional<SkColor>
+TypeConverter<UNIQUE_TYPE_NAME(SkColor)>::ParseRgbString(
+ const base::string16& rgb_string) {
+ // Declare a constant string here for use below since it might trigger an
+ // ASAN error due to the stack temp going out of scope before the call to
+ // RgbaPiecesToSkColor.
+ static const auto opaque_alpha = base::ASCIIToUTF16("1.0");
+ base::string16 pruned_string;
+ base::RemoveChars(rgb_string, base::ASCIIToUTF16("()rgba"), &pruned_string);
+ auto values =
+ base::SplitStringPiece(pruned_string, base::ASCIIToUTF16(", "),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ // if it was just an rgb string, add the 1.0 alpha
+ if (values.size() == 3)
+ values.push_back(opaque_alpha);
+ return RgbaPiecesToSkColor(values, 0);
+}
+
} // namespace metadata
} // namespace views
@@ -363,6 +683,37 @@ DEFINE_ENUM_CONVERTERS(views::ScrollView::ScrollBarMode,
{views::ScrollView::ScrollBarMode::kEnabled,
base::ASCIIToUTF16("kEnabled")})
+DEFINE_ENUM_CONVERTERS(
+ views::BubbleFrameView::PreferredArrowAdjustment,
+ {views::BubbleFrameView::PreferredArrowAdjustment::kMirror,
+ base::ASCIIToUTF16("kMirror")},
+ {views::BubbleFrameView::PreferredArrowAdjustment::kOffset,
+ base::ASCIIToUTF16("kOffset")})
+
+DEFINE_ENUM_CONVERTERS(
+ views::BubbleBorder::Arrow,
+ {views::BubbleBorder::Arrow::TOP_LEFT, base::ASCIIToUTF16("TOP_LEFT")},
+ {views::BubbleBorder::Arrow::TOP_RIGHT, base::ASCIIToUTF16("TOP_RIGHT")},
+ {views::BubbleBorder::Arrow::BOTTOM_LEFT,
+ base::ASCIIToUTF16("BOTTOM_LEFT")},
+ {views::BubbleBorder::Arrow::BOTTOM_RIGHT,
+ base::ASCIIToUTF16("BOTTOM_RIGHT")},
+ {views::BubbleBorder::Arrow::LEFT_TOP, base::ASCIIToUTF16("LEFT_TOP")},
+ {views::BubbleBorder::Arrow::RIGHT_TOP, base::ASCIIToUTF16("RIGHT_TOP")},
+ {views::BubbleBorder::Arrow::LEFT_BOTTOM,
+ base::ASCIIToUTF16("LEFT_BOTTOM")},
+ {views::BubbleBorder::Arrow::RIGHT_BOTTOM,
+ base::ASCIIToUTF16("RIGHT_BOTTOM")},
+ {views::BubbleBorder::Arrow::TOP_CENTER, base::ASCIIToUTF16("TOP_CENTER")},
+ {views::BubbleBorder::Arrow::BOTTOM_CENTER,
+ base::ASCIIToUTF16("BOTTOM_CENTER")},
+ {views::BubbleBorder::Arrow::LEFT_CENTER,
+ base::ASCIIToUTF16("LEFT_CENTER")},
+ {views::BubbleBorder::Arrow::RIGHT_CENTER,
+ base::ASCIIToUTF16("RIGHT_CENTER")},
+ {views::BubbleBorder::Arrow::NONE, base::ASCIIToUTF16("NONE")},
+ {views::BubbleBorder::Arrow::FLOAT, base::ASCIIToUTF16("FLOAT")})
+
#define OP(enum_name) \
{ ui::NativeTheme::enum_name, base::ASCIIToUTF16(#enum_name) }
DEFINE_ENUM_CONVERTERS(ui::NativeTheme::ColorId, NATIVE_THEME_COLOR_IDS)
diff --git a/chromium/ui/views/metadata/type_conversion.h b/chromium/ui/views/metadata/type_conversion.h
index 9ba57d48a75..19dcf2523d5 100644
--- a/chromium/ui/views/metadata/type_conversion.h
+++ b/chromium/ui/views/metadata/type_conversion.h
@@ -7,28 +7,43 @@
#include <stdint.h>
+#include <algorithm> // Silence broken lint check
#include <memory>
#include <utility>
#include <vector>
+#include "base/files/file_path.h"
#include "base/no_destructor.h"
#include "base/optional.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/range/range.h"
#include "ui/gfx/shadow_value.h"
#include "ui/gfx/text_constants.h"
#include "ui/views/views_export.h"
+#include "url/gurl.h"
+#include "url/third_party/mozilla/url_parse.h"
namespace views {
namespace metadata {
+using ValidStrings = std::vector<base::string16>;
+
// Various metadata methods pass types either by value or const ref depending on
// whether the types are "small" (defined as "fundamental, enum, or pointer").
// ArgType<T> gives the appropriate type to use as an argument in such cases.
@@ -44,15 +59,56 @@ using ArgType =
T,
const T&>::type;
+VIEWS_EXPORT extern const char kNoPrefix[];
+VIEWS_EXPORT extern const char kSkColorPrefix[];
+
// General Type Conversion Template Functions ---------------------------------
-template <typename T>
-struct TypeConverter {
- static constexpr bool is_serializable = std::is_enum<T>::value;
+template <bool serializable,
+ bool read_only = false,
+ const char* name_prefix = kNoPrefix>
+struct BaseTypeConverter {
+ static constexpr bool is_serializable = serializable;
+ static constexpr bool is_read_only = read_only;
static bool IsSerializable() { return is_serializable; }
+ static bool IsReadOnly() { return is_read_only; }
+ static const char* PropertyNamePrefix() { return name_prefix; }
+};
+
+template <typename T>
+struct TypeConverter : BaseTypeConverter<std::is_enum<T>::value> {
static base::string16 ToString(ArgType<T> source_value);
static base::Optional<T> FromString(const base::string16& source_value);
+ static ValidStrings GetValidStrings();
};
+// The following definitions and macros are needed only in cases where a type
+// is a mere alias to a POD type AND a specialized type converter is also needed
+// to handle different the string conversions different from the existing POD
+// type converter. See SkColor below as an example of their use.
+// NOTE: This should be a rare occurrence and if possible use a unique type and
+// a TypeConverter specialization based on that unique type.
+
+template <typename T, typename K>
+struct Uniquifier {
+ using type = T;
+ using tag = K;
+};
+
+#define MAKE_TYPE_UNIQUE(type_name) \
+ struct type_name##Tag {}; \
+ using type_name##Unique = \
+ ::views::metadata::Uniquifier<type_name, type_name##Tag>
+
+#define _UNIQUE_TYPE_NAME1(type_name) type_name##Unique
+
+#define _UNIQUE_TYPE_NAME2(qualifier, type_name) qualifier::type_name##Unique
+
+#define _GET_TYPE_MACRO(_1, _2, NAME, ...) NAME
+
+#define UNIQUE_TYPE_NAME(name, ...) \
+ _GET_TYPE_MACRO(name, ##__VA_ARGS__, _UNIQUE_TYPE_NAME2, _UNIQUE_TYPE_NAME1) \
+ (name, ##__VA_ARGS__)
+
// Types and macros for generating enum converters ----------------------------
template <typename T>
struct EnumStrings {
@@ -64,6 +120,13 @@ struct EnumStrings {
explicit EnumStrings(std::vector<EnumString> init_val)
: pairs(std::move(init_val)) {}
+ ValidStrings GetStringValues() const {
+ ValidStrings string_values;
+ for (const auto& pair : pairs)
+ string_values.push_back(pair.str_value);
+ return string_values;
+ }
+
const std::vector<EnumString> pairs;
};
@@ -103,17 +166,24 @@ static const EnumStrings<T>& GetEnumStringsInstance();
} \
} \
return base::nullopt; \
+ } \
+ \
+ template <> \
+ views::metadata::ValidStrings \
+ views::metadata::TypeConverter<T>::GetValidStrings() { \
+ return GetEnumStringsInstance<T>().GetStringValues(); \
}
// String Conversions ---------------------------------------------------------
+VIEWS_EXPORT base::string16 PointerToString(const void* pointer_val);
+
#define DECLARE_CONVERSIONS(T) \
template <> \
- struct VIEWS_EXPORT TypeConverter<T> { \
- static constexpr bool is_serializable = true; \
- static bool IsSerializable() { return is_serializable; } \
+ struct VIEWS_EXPORT TypeConverter<T> : BaseTypeConverter<true> { \
static base::string16 ToString(ArgType<T> source_value); \
static base::Optional<T> FromString(const base::string16& source_value); \
+ static ValidStrings GetValidStrings() { return {}; } \
};
DECLARE_CONVERSIONS(int8_t)
@@ -126,25 +196,38 @@ DECLARE_CONVERSIONS(uint32_t)
DECLARE_CONVERSIONS(uint64_t)
DECLARE_CONVERSIONS(float)
DECLARE_CONVERSIONS(double)
-DECLARE_CONVERSIONS(bool)
DECLARE_CONVERSIONS(const char*)
+DECLARE_CONVERSIONS(base::FilePath)
DECLARE_CONVERSIONS(base::string16)
DECLARE_CONVERSIONS(base::TimeDelta)
+DECLARE_CONVERSIONS(gfx::Insets)
+DECLARE_CONVERSIONS(gfx::Point)
+DECLARE_CONVERSIONS(gfx::PointF)
+DECLARE_CONVERSIONS(gfx::Range)
+DECLARE_CONVERSIONS(gfx::Rect)
+DECLARE_CONVERSIONS(gfx::RectF)
DECLARE_CONVERSIONS(gfx::ShadowValues)
DECLARE_CONVERSIONS(gfx::Size)
-DECLARE_CONVERSIONS(gfx::Range)
-DECLARE_CONVERSIONS(gfx::Insets)
+DECLARE_CONVERSIONS(gfx::SizeF)
+DECLARE_CONVERSIONS(GURL)
+DECLARE_CONVERSIONS(url::Component)
#undef DECLARE_CONVERSIONS
-// Special Conversions for base::Optional<T> type ------------------------------
+template <>
+struct VIEWS_EXPORT TypeConverter<bool> : BaseTypeConverter<true> {
+ static base::string16 ToString(bool source_value);
+ static base::Optional<bool> FromString(const base::string16& source_value);
+ static ValidStrings GetValidStrings();
+};
+
+// Special conversions for wrapper types --------------------------------------
VIEWS_EXPORT const base::string16& GetNullOptStr();
template <typename T>
-struct TypeConverter<base::Optional<T>> {
- static constexpr bool is_serializable = TypeConverter<T>::is_serializable;
- static bool IsSerializable() { return is_serializable; }
+struct TypeConverter<base::Optional<T>>
+ : BaseTypeConverter<TypeConverter<T>::is_serializable> {
static base::string16 ToString(ArgType<base::Optional<T>> source_value) {
if (!source_value)
return GetNullOptStr();
@@ -158,17 +241,124 @@ struct TypeConverter<base::Optional<T>> {
auto ret = TypeConverter<T>::FromString(source_value);
return ret ? base::make_optional(ret) : base::nullopt;
}
+ static ValidStrings GetValidStrings() { return {}; }
};
+// Special Conversions for std:unique_ptr<T> and T* types ----------------------
+
template <typename T>
-struct TypeConverter<std::unique_ptr<T>> {
- static constexpr bool is_serializable = false;
- static bool IsSerializable() { return is_serializable; }
- static base::string16 ToString(const std::unique_ptr<T>& source_value);
+struct TypeConverter<std::unique_ptr<T>> : BaseTypeConverter<false, true> {
+ static base::string16 ToString(const std::unique_ptr<T>& source_value) {
+ return PointerToString(source_value.get());
+ }
+ static base::string16 ToString(const T* source_value) {
+ return PointerToString(source_value);
+ }
static base::Optional<std::unique_ptr<T>> FromString(
- const base::string16& source_value);
+ const base::string16& source_value) {
+ DCHECK(false) << "Type converter cannot convert from string.";
+ return base::nullopt;
+ }
+ static ValidStrings GetValidStrings() { return {}; }
+};
+
+template <typename T>
+struct TypeConverter<T*> : BaseTypeConverter<false, true> {
+ static base::string16 ToString(ArgType<T*> source_value) {
+ return PointerToString(source_value);
+ }
+ static base::Optional<T*> FromString(const base::string16& source_value) {
+ DCHECK(false) << "Type converter cannot convert from string.";
+ return base::nullopt;
+ }
+ static ValidStrings GetValidStrings() { return {}; }
+};
+
+template <typename T>
+struct TypeConverter<std::vector<T>>
+ : BaseTypeConverter<TypeConverter<T>::is_serializable> {
+ static base::string16 ToString(ArgType<std::vector<T>> source_value) {
+ std::vector<base::string16> serialized;
+ base::ranges::transform(source_value, std::back_inserter(serialized),
+ &TypeConverter<T>::ToString);
+ return STRING16_LITERAL("{") +
+ base::JoinString(serialized, STRING16_LITERAL(",")) +
+ STRING16_LITERAL("}");
+ }
+ static base::Optional<std::vector<T>> FromString(
+ const base::string16& source_value) {
+ if (source_value.empty() || source_value.front() != STRING16_LITERAL('{') ||
+ source_value.back() != STRING16_LITERAL('}'))
+ return base::nullopt;
+ const auto values = base::SplitString(
+ source_value.substr(1, source_value.length() - 2),
+ base::ASCIIToUTF16(","), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ std::vector<T> output;
+ for (const auto& value : values) {
+ auto ret = TypeConverter<T>::FromString(value);
+ if (!ret)
+ return base::nullopt;
+ output.push_back(*ret);
+ }
+ return base::make_optional(output);
+ }
+ static ValidStrings GetValidStrings() { return {}; }
};
+MAKE_TYPE_UNIQUE(SkColor);
+
+template <>
+struct VIEWS_EXPORT TypeConverter<UNIQUE_TYPE_NAME(SkColor)>
+ : BaseTypeConverter<true, false, kSkColorPrefix> {
+ static base::string16 ToString(SkColor source_value);
+ static base::Optional<SkColor> FromString(const base::string16& source_value);
+ static ValidStrings GetValidStrings();
+
+ // Parses a string within |start| and |end| for a color string in the forms
+ // rgb(r, g, b), rgba(r, g, b, a), hsl(h, s%, l%), hsla(h, s%, l%, a),
+ // 0xXXXXXX, 0xXXXXXXXX, <decimal number>
+ // Returns the full string in |color| and the position immediately following
+ // the last token in |next_token|.
+ // Returns false if the input string cannot be properly parsed. |color| and
+ // |next_token| will be undefined.
+ static bool GetNextColor(base::string16::const_iterator start,
+ base::string16::const_iterator end,
+ base::string16& color,
+ base::string16::const_iterator& next_token);
+ static bool GetNextColor(base::string16::const_iterator start,
+ base::string16::const_iterator end,
+ base::string16& color);
+
+ // Same as above, except returns the color string converted into an |SkColor|.
+ // Returns base::nullopt if the color string cannot be properly parsed or the
+ // string cannot be converted into a valid SkColor and |next_token| may be
+ // undefined.
+ static base::Optional<SkColor> GetNextColor(
+ base::string16::const_iterator start,
+ base::string16::const_iterator end,
+ base::string16::const_iterator& next_token);
+ static base::Optional<SkColor> GetNextColor(
+ base::string16::const_iterator start,
+ base::string16::const_iterator end);
+
+ // Converts the four elements of |pieces| beginning at |start_piece| to an
+ // SkColor by assuming the pieces are split from a string like
+ // "rgba(r,g,b,a)". Returns nullopt if conversion was unsuccessful.
+ static base::Optional<SkColor> RgbaPiecesToSkColor(
+ const std::vector<base::StringPiece16>& pieces,
+ size_t start_piece);
+
+ private:
+ static base::Optional<SkColor> ParseHexString(
+ const base::string16& hex_string);
+ static base::Optional<SkColor> ParseHslString(
+ const base::string16& hsl_string);
+ static base::Optional<SkColor> ParseRgbString(
+ const base::string16& rgb_string);
+};
+
+using SkColorConverter = TypeConverter<UNIQUE_TYPE_NAME(SkColor)>;
+
} // namespace metadata
} // namespace views
diff --git a/chromium/ui/views/metadata/type_conversion_unittest.cc b/chromium/ui/views/metadata/type_conversion_unittest.cc
index d1630597c00..81fc7f90679 100644
--- a/chromium/ui/views/metadata/type_conversion_unittest.cc
+++ b/chromium/ui/views/metadata/type_conversion_unittest.cc
@@ -4,6 +4,8 @@
#include "ui/views/metadata/type_conversion.h"
+#include "base/ranges/ranges.h"
+#include "base/strings/string_tokenizer.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -95,7 +97,7 @@ TEST_F(TypeConversionTest, TestConversion_ShadowValuesToString) {
TEST_F(TypeConversionTest, TestConversion_StringToShadowValues) {
base::Optional<gfx::ShadowValues> opt_result =
metadata::TypeConverter<gfx::ShadowValues>::FromString(base::ASCIIToUTF16(
- "[ (6,4),0.53,rgba(23,44,0,255); (93,83),4.33,rgba(10,20,0,15) ]"));
+ "[ (6,4),0.53,rgba(23,44,0,1); (93,83),4.33,rgba(10,20,0,0.059) ]"));
EXPECT_EQ(opt_result.has_value(), true);
gfx::ShadowValues result = opt_result.value();
@@ -114,19 +116,124 @@ TEST_F(TypeConversionTest, TestConversion_StringToShadowValues) {
EXPECT_EQ(result[1].blur(), 4.33);
}
+TEST_F(TypeConversionTest, TestConversion_SkColorConversions) {
+ // Check conversion from rgb hex string
+ base::Optional<SkColor> result =
+ metadata::SkColorConverter::FromString(base::ASCIIToUTF16("0x112233"));
+ EXPECT_TRUE(result);
+ EXPECT_EQ(result.value(), SkColorSetRGB(0x11, 0x22, 0x33));
+
+ // Check conversion from argb hex string
+ result =
+ metadata::SkColorConverter::FromString(base::ASCIIToUTF16("0x7F112233"));
+ EXPECT_TRUE(result);
+ EXPECT_EQ(result.value(), SkColorSetARGB(0x7F, 0x11, 0x22, 0x33));
+
+ // Check conversion from rgb(r,g,b) string
+ result = metadata::SkColorConverter::FromString(
+ base::ASCIIToUTF16("rgb(0, 128, 192)"));
+ EXPECT_TRUE(result);
+ EXPECT_EQ(result.value(), SkColorSetRGB(0, 128, 192));
+
+ // Check conversion from rgba(r,g,b,a) string
+ result = metadata::SkColorConverter::FromString(
+ base::ASCIIToUTF16("rgba(0, 128, 192, 0.5)"));
+ EXPECT_TRUE(result);
+ EXPECT_EQ(result.value(), SkColorSetARGB(128, 0, 128, 192));
+
+ // Check conversion from hsl(h,s,l) string
+ result = metadata::SkColorConverter::FromString(
+ base::ASCIIToUTF16("hsl(195, 100%, 50%)"));
+ EXPECT_TRUE(result);
+ const SkScalar hsv[3] = {195.0, 1.0, 0.5};
+ EXPECT_EQ(result.value(), SkHSVToColor(hsv));
+
+ // Check conversion from hsla(h,s,l,a) string
+ result = metadata::SkColorConverter::FromString(
+ base::ASCIIToUTF16("hsl(195, 100%, 50%, 0.5)"));
+ EXPECT_TRUE(result);
+ EXPECT_EQ(result.value(), SkHSVToColor(128, hsv));
+
+ // Check conversion from a decimal integer value
+ result =
+ metadata::SkColorConverter::FromString(base::ASCIIToUTF16("4278239231"));
+ EXPECT_TRUE(result);
+ EXPECT_EQ(result.value(), SkColorSetARGB(255, 0, 191, 255));
+
+ // Check without commas.
+ result = metadata::SkColorConverter::FromString(
+ base::ASCIIToUTF16("rgba(92 92 92 1)"));
+ EXPECT_TRUE(result);
+ EXPECT_EQ(result.value(), SkColorSetARGB(255, 92, 92, 92));
+
+ // Don't support the CSS hash color style
+ result = metadata::SkColorConverter::FromString(base::ASCIIToUTF16("#03254"));
+ EXPECT_FALSE(result);
+
+ // Don't support some common invalid values
+ result = metadata::SkColorConverter::FromString(
+ base::ASCIIToUTF16("rgba(1,2,3,4)"));
+ EXPECT_FALSE(result);
+
+ result = metadata::SkColorConverter::FromString(
+ base::ASCIIToUTF16("rgba(1,2,3,4"));
+ EXPECT_FALSE(result);
+
+ result = metadata::SkColorConverter::FromString(
+ base::ASCIIToUTF16("hsla(1,2,3,4)"));
+ EXPECT_FALSE(result);
+}
+
+TEST_F(TypeConversionTest, TestConversion_ColorParserTest) {
+ using converter = metadata::SkColorConverter;
+ base::string16 color;
+ const base::string16 source = base::ASCIIToUTF16(
+ "rgb(0, 128, 192), hsl(90, 100%, 30%), rgba(128, 128, 128, 0.5), "
+ "hsla(240, 100%, 50%, 0.5)");
+ auto start_pos = source.cbegin();
+ EXPECT_TRUE(
+ converter::GetNextColor(start_pos, source.cend(), color, start_pos));
+ EXPECT_EQ(color, base::ASCIIToUTF16("rgb(0, 128, 192)"));
+ EXPECT_TRUE(
+ converter::GetNextColor(start_pos, source.cend(), color, start_pos));
+ EXPECT_EQ(color, base::ASCIIToUTF16("hsl(90, 100%, 30%)"));
+ EXPECT_TRUE(
+ converter::GetNextColor(start_pos, source.cend(), color, start_pos));
+ EXPECT_EQ(color, base::ASCIIToUTF16("rgba(128, 128, 128, 0.5)"));
+ EXPECT_TRUE(converter::GetNextColor(start_pos, source.cend(), color));
+ EXPECT_EQ(color, base::ASCIIToUTF16("hsla(240, 100%, 50%, 0.5)"));
+}
+
TEST_F(TypeConversionTest, TestConversion_InsetsToString) {
+ constexpr gfx::Insets kInsets(3, 5, 7, 9);
+
base::string16 to_string =
- metadata::TypeConverter<gfx::Insets>::ToString(gfx::Insets(3, 5, 7, 9));
+ metadata::TypeConverter<gfx::Insets>::ToString(kInsets);
- EXPECT_EQ(to_string, base::ASCIIToUTF16("{3, 5, 7, 9}"));
+ EXPECT_EQ(to_string, base::ASCIIToUTF16(kInsets.ToString()));
}
TEST_F(TypeConversionTest, TestConversion_StringToInsets) {
- base::string16 from_string = base::ASCIIToUTF16("{2, 3, 4, 5}");
+ base::string16 from_string = base::ASCIIToUTF16("2,3,4,5");
EXPECT_EQ(metadata::TypeConverter<gfx::Insets>::FromString(from_string),
gfx::Insets(2, 3, 4, 5));
}
+TEST_F(TypeConversionTest, TestConversion_VectorToString) {
+ const std::vector<int> kVector{3, 5, 7, 9};
+
+ base::string16 to_string =
+ metadata::TypeConverter<std::vector<int>>::ToString(kVector);
+
+ EXPECT_EQ(to_string, STRING16_LITERAL("{3,5,7,9}"));
+}
+
+TEST_F(TypeConversionTest, TestConversion_StringToVector) {
+ base::string16 from_string = base::ASCIIToUTF16("{2,3,4,5}");
+ EXPECT_EQ(metadata::TypeConverter<std::vector<int>>::FromString(from_string),
+ std::vector<int>({2, 3, 4, 5}));
+}
+
TEST_F(TypeConversionTest, CheckIsSerializable) {
// Test types with explicitly added converters.
EXPECT_TRUE(metadata::TypeConverter<int8_t>::IsSerializable());
diff --git a/chromium/ui/views/selection_controller.cc b/chromium/ui/views/selection_controller.cc
index 4f8f035a342..ef23305628e 100644
--- a/chromium/ui/views/selection_controller.cc
+++ b/chromium/ui/views/selection_controller.cc
@@ -9,6 +9,7 @@
#include "base/numerics/ranges.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/events/event.h"
#include "ui/gfx/render_text.h"
#include "ui/views/metrics.h"
@@ -23,7 +24,9 @@ SelectionController::SelectionController(SelectionControllerDelegate* delegate)
delegate_(delegate),
handles_selection_clipboard_(false) {
// On Linux, update the selection clipboard on a text selection.
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
set_handles_selection_clipboard(true);
#endif
diff --git a/chromium/ui/views/style/platform_style.cc b/chromium/ui/views/style/platform_style.cc
index f264720140d..53e65bd03b7 100644
--- a/chromium/ui/views/style/platform_style.cc
+++ b/chromium/ui/views/style/platform_style.cc
@@ -17,7 +17,7 @@
#include "ui/views/controls/focusable_border.h"
#include "ui/views/controls/scrollbar/scroll_bar_views.h"
-#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
#include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
#endif
@@ -50,11 +50,15 @@ const bool PlatformStyle::kUseRipples = true;
const bool PlatformStyle::kTextfieldScrollsToStartOnFocusChange = false;
const bool PlatformStyle::kTextfieldUsesDragCursorWhenDraggable = true;
const bool PlatformStyle::kInactiveWidgetControlsAppearDisabled = false;
+const View::FocusBehavior PlatformStyle::kDefaultFocusBehavior =
+ View::FocusBehavior::ALWAYS;
// Linux clips bubble windows that extend outside their parent window
// bounds.
const bool PlatformStyle::kAdjustBubbleIfOffscreen =
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
false;
#else
true;
@@ -62,7 +66,7 @@ const bool PlatformStyle::kAdjustBubbleIfOffscreen =
// static
std::unique_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) {
-#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
return std::make_unique<OverlayScrollBar>(is_horizontal);
#else
return std::make_unique<ScrollBarViews>(is_horizontal);
@@ -81,11 +85,6 @@ gfx::Range PlatformStyle::RangeToDeleteBackwards(const base::string16& text,
return gfx::Range(cursor_position, previous_grapheme_index);
}
-// static
-View::FocusBehavior PlatformStyle::DefaultFocusBehavior() {
- return View::FocusBehavior::ALWAYS;
-}
-
#endif // OS_APPLE
#if !BUILDFLAG(ENABLE_DESKTOP_AURA) || \
diff --git a/chromium/ui/views/style/platform_style.h b/chromium/ui/views/style/platform_style.h
index a5c8d415300..e117cdc734e 100644
--- a/chromium/ui/views/style/platform_style.h
+++ b/chromium/ui/views/style/platform_style.h
@@ -80,6 +80,9 @@ class VIEWS_EXPORT PlatformStyle {
// for bubbles going off-screen to bring more bubble area into view.
static const bool kAdjustBubbleIfOffscreen;
+ // Default focus behavior on the platform.
+ static const View::FocusBehavior kDefaultFocusBehavior;
+
// Creates the default scrollbar for the given orientation.
static std::unique_ptr<ScrollBar> CreateScrollBar(bool is_horizontal);
@@ -99,9 +102,6 @@ class VIEWS_EXPORT PlatformStyle {
static gfx::Range RangeToDeleteBackwards(const base::string16& text,
size_t cursor_position);
- // Returns the default focus behavior based on the platform.
- static View::FocusBehavior DefaultFocusBehavior();
-
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformStyle);
};
diff --git a/chromium/ui/views/style/platform_style_mac.mm b/chromium/ui/views/style/platform_style_mac.mm
index 527f947a2b7..6572f9f3c32 100644
--- a/chromium/ui/views/style/platform_style_mac.mm
+++ b/chromium/ui/views/style/platform_style_mac.mm
@@ -44,6 +44,8 @@ const bool PlatformStyle::kTreeViewSelectionPaintsEntireRow = true;
const bool PlatformStyle::kUseRipples = false;
const bool PlatformStyle::kInactiveWidgetControlsAppearDisabled = true;
const bool PlatformStyle::kAdjustBubbleIfOffscreen = false;
+const View::FocusBehavior PlatformStyle::kDefaultFocusBehavior =
+ View::FocusBehavior::ACCESSIBLE_ONLY;
const Button::KeyClickAction PlatformStyle::kKeyClickActionOnSpace =
Button::KeyClickAction::kOnKeyPress;
@@ -68,9 +70,9 @@ gfx::Range PlatformStyle::RangeToDeleteBackwards(const base::string16& text,
if (cursor_position == 0)
return gfx::Range();
- base::ScopedCFTypeRef<CFStringRef> cf_string(
- CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, text.data(),
- text.size(), kCFAllocatorNull));
+ base::ScopedCFTypeRef<CFStringRef> cf_string(CFStringCreateWithCharacters(
+ kCFAllocatorDefault, reinterpret_cast<const UniChar*>(text.data()),
+ text.size()));
CFRange range_to_delete = CFStringGetRangeOfCharacterClusterAtIndex(
cf_string, cursor_position - 1, kCFStringBackwardDeletionCluster);
@@ -82,9 +84,4 @@ gfx::Range PlatformStyle::RangeToDeleteBackwards(const base::string16& text,
range_to_delete.location);
}
-// static
-View::FocusBehavior PlatformStyle::DefaultFocusBehavior() {
- return View::FocusBehavior::ACCESSIBLE_ONLY;
-}
-
} // namespace views
diff --git a/chromium/ui/views/style/typography.cc b/chromium/ui/views/style/typography.cc
index e269daff59a..b917ca796de 100644
--- a/chromium/ui/views/style/typography.cc
+++ b/chromium/ui/views/style/typography.cc
@@ -20,6 +20,12 @@ void ValidateContextAndStyle(int context, int style) {
} // namespace
+ui::ResourceBundle::FontDetails GetFontDetails(int context, int style) {
+ ValidateContextAndStyle(context, style);
+ return LayoutProvider::Get()->GetTypographyProvider().GetFontDetails(context,
+ style);
+}
+
const gfx::FontList& GetFont(int context, int style) {
ValidateContextAndStyle(context, style);
return LayoutProvider::Get()->GetTypographyProvider().GetFont(context, style);
diff --git a/chromium/ui/views/style/typography.h b/chromium/ui/views/style/typography.h
index bd21fc8fe4e..3a4e86920b6 100644
--- a/chromium/ui/views/style/typography.h
+++ b/chromium/ui/views/style/typography.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_STYLE_TYPOGRAPHY_H_
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/resource/resource_bundle.h"
#include "ui/views/views_export.h"
namespace gfx {
@@ -106,6 +107,8 @@ enum TextStyle {
// current LayoutProvider. |view| is the View requesting the property. |context|
// can be an enum value from TextContext, or a value understood by the
// embedder's TypographyProvider. Similarly, |style| corresponds to TextStyle.
+VIEWS_EXPORT ui::ResourceBundle::FontDetails GetFontDetails(int context,
+ int style);
VIEWS_EXPORT const gfx::FontList& GetFont(int context, int style);
VIEWS_EXPORT SkColor GetColor(const views::View& view, int context, int style);
VIEWS_EXPORT int GetLineHeight(int context, int style);
diff --git a/chromium/ui/views/style/typography_provider.cc b/chromium/ui/views/style/typography_provider.cc
index 6e9f7eec223..dff000de729 100644
--- a/chromium/ui/views/style/typography_provider.cc
+++ b/chromium/ui/views/style/typography_provider.cc
@@ -4,6 +4,8 @@
#include "ui/views/style/typography_provider.h"
+#include <string>
+
#include "base/logging.h"
#include "build/build_config.h"
#include "ui/base/default_style.h"
@@ -31,45 +33,6 @@ gfx::Font::Weight GetValueBolderThan(gfx::Font::Weight weight) {
}
}
-void GetDefaultFont(int context,
- int style,
- int* size_delta,
- gfx::Font::Weight* font_weight) {
- *font_weight = gfx::Font::Weight::NORMAL;
-
- switch (context) {
- case style::CONTEXT_BUTTON_MD:
- *size_delta = ui::kLabelFontSizeDelta;
- *font_weight = TypographyProvider::MediumWeightForUI();
- break;
- case style::CONTEXT_DIALOG_TITLE:
- *size_delta = ui::kTitleFontSizeDelta;
- break;
- case style::CONTEXT_TOUCH_MENU:
- *size_delta = 2;
- break;
- default:
- *size_delta = ui::kLabelFontSizeDelta;
- break;
- }
-
- switch (style) {
- case style::STYLE_TAB_ACTIVE:
- *font_weight = gfx::Font::Weight::BOLD;
- break;
- case style::STYLE_DIALOG_BUTTON_DEFAULT:
- // Only non-MD default buttons should "increase" in boldness.
- if (context == style::CONTEXT_BUTTON) {
- *font_weight = GetValueBolderThan(
- ui::ResourceBundle::GetSharedInstance()
- .GetFontListWithDelta(*size_delta, gfx::Font::NORMAL,
- *font_weight)
- .GetFontWeight());
- }
- break;
- }
-}
-
ui::NativeTheme::ColorId GetDisabledColorId(int context) {
switch (context) {
case style::CONTEXT_BUTTON_MD:
@@ -128,12 +91,48 @@ ui::NativeTheme::ColorId GetColorId(int context, int style) {
} // namespace
+ui::ResourceBundle::FontDetails TypographyProvider::GetFontDetails(
+ int context,
+ int style) const {
+ ui::ResourceBundle::FontDetails details;
+
+ switch (context) {
+ case style::CONTEXT_BUTTON_MD:
+ details.size_delta = ui::kLabelFontSizeDelta;
+ details.weight = TypographyProvider::MediumWeightForUI();
+ break;
+ case style::CONTEXT_DIALOG_TITLE:
+ details.size_delta = ui::kTitleFontSizeDelta;
+ break;
+ case style::CONTEXT_TOUCH_MENU:
+ details.size_delta = 2;
+ break;
+ default:
+ details.size_delta = ui::kLabelFontSizeDelta;
+ break;
+ }
+
+ switch (style) {
+ case style::STYLE_TAB_ACTIVE:
+ details.weight = gfx::Font::Weight::BOLD;
+ break;
+ case style::STYLE_DIALOG_BUTTON_DEFAULT:
+ // Only non-MD default buttons should "increase" in boldness.
+ if (context == style::CONTEXT_BUTTON) {
+ details.weight =
+ GetValueBolderThan(ui::ResourceBundle::GetSharedInstance()
+ .GetFontListForDetails(details)
+ .GetFontWeight());
+ }
+ break;
+ }
+
+ return details;
+}
+
const gfx::FontList& TypographyProvider::GetFont(int context, int style) const {
- int size_delta;
- gfx::Font::Weight font_weight;
- GetDefaultFont(context, style, &size_delta, &font_weight);
- return ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
- size_delta, gfx::Font::NORMAL, font_weight);
+ return ui::ResourceBundle::GetSharedInstance().GetFontListForDetails(
+ GetFontDetails(context, style));
}
SkColor TypographyProvider::GetColor(const View& view,
@@ -162,7 +161,7 @@ gfx::Font::Weight TypographyProvider::MediumWeightForUI() {
// BOLD font for dialog text; deriving MEDIUM from that would replace the BOLD
// attribute with something lighter.
if (ui::ResourceBundle::GetSharedInstance()
- .GetFontListWithDelta(0, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL)
+ .GetFontListForDetails(ui::ResourceBundle::FontDetails())
.GetFontWeight() < gfx::Font::Weight::MEDIUM)
return gfx::Font::Weight::MEDIUM;
return gfx::Font::Weight::NORMAL;
diff --git a/chromium/ui/views/style/typography_provider.h b/chromium/ui/views/style/typography_provider.h
index 3184eae2e5e..973c861c1b5 100644
--- a/chromium/ui/views/style/typography_provider.h
+++ b/chromium/ui/views/style/typography_provider.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/font.h"
#include "ui/views/views_export.h"
@@ -24,8 +25,12 @@ class VIEWS_EXPORT TypographyProvider {
TypographyProvider() = default;
virtual ~TypographyProvider() = default;
- // Gets the FontList for the given |context| and |style|.
- virtual const gfx::FontList& GetFont(int context, int style) const;
+ // Gets the FontDetails for the given |context| and |style|.
+ virtual ui::ResourceBundle::FontDetails GetFontDetails(int context,
+ int style) const;
+
+ // Convenience wrapper that gets a FontList for |context| and |style|.
+ const gfx::FontList& GetFont(int context, int style) const;
// Gets the color for the given |context| and |style|. |view| is the View
// requesting the color.
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.cc b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
index a5dbd5b1750..3b8e79ae6c0 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
@@ -21,6 +21,8 @@
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
#include "ui/resources/grit/ui_resources.h"
+#include "ui/views/metadata/metadata_header_macros.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -196,6 +198,7 @@ using EditingHandleView = TouchSelectionControllerImpl::EditingHandleView;
// A View that displays the text selection handle.
class TouchSelectionControllerImpl::EditingHandleView : public View {
public:
+ METADATA_HEADER(EditingHandleView);
EditingHandleView(TouchSelectionControllerImpl* controller,
gfx::NativeView parent,
bool is_cursor_handle)
@@ -225,7 +228,7 @@ class TouchSelectionControllerImpl::EditingHandleView : public View {
widget_->CloseNow();
}
- gfx::SelectionBound::Type selection_bound_type() {
+ gfx::SelectionBound::Type GetSelectionBoundType() const {
return selection_bound_.type();
}
@@ -277,7 +280,7 @@ class TouchSelectionControllerImpl::EditingHandleView : public View {
return GetSelectionWidgetBounds(selection_bound_).size();
}
- bool IsWidgetVisible() const { return widget_->IsVisible(); }
+ bool GetWidgetVisible() const { return widget_->IsVisible(); }
void SetWidgetVisible(bool visible) {
if (widget_->IsVisible() == visible)
@@ -286,6 +289,7 @@ class TouchSelectionControllerImpl::EditingHandleView : public View {
widget_->Show();
else
widget_->Hide();
+ OnPropertyChanged(&widget_, kPropertyEffectsNone);
}
// If |is_visible| is true, this will update the widget and trigger a repaint
@@ -339,8 +343,9 @@ class TouchSelectionControllerImpl::EditingHandleView : public View {
if (draw_invisible_ == draw_invisible)
return;
draw_invisible_ = draw_invisible;
- SchedulePaint();
+ OnPropertyChanged(&draw_invisible_, kPropertyEffectsPaint);
}
+ bool GetDrawInvisible() const { return draw_invisible_; }
private:
TouchSelectionControllerImpl* controller_;
@@ -368,6 +373,19 @@ class TouchSelectionControllerImpl::EditingHandleView : public View {
Widget* widget_ = nullptr;
};
+DEFINE_ENUM_CONVERTERS(
+ gfx::SelectionBound::Type,
+ {gfx::SelectionBound::Type::LEFT, STRING16_LITERAL("LEFT")},
+ {gfx::SelectionBound::Type::RIGHT, STRING16_LITERAL("RIGHT")},
+ {gfx::SelectionBound::Type::CENTER, STRING16_LITERAL("CENTER")},
+ {gfx::SelectionBound::Type::EMPTY, STRING16_LITERAL("EMPTY")})
+
+BEGIN_METADATA(TouchSelectionControllerImpl, EditingHandleView, View)
+ADD_READONLY_PROPERTY_METADATA(gfx::SelectionBound::Type, SelectionBoundType)
+ADD_PROPERTY_METADATA(bool, WidgetVisible)
+ADD_PROPERTY_METADATA(bool, DrawInvisible)
+END_METADATA
+
TouchSelectionControllerImpl::TouchSelectionControllerImpl(
ui::TouchEditable* client_view)
: client_view_(client_view),
@@ -544,7 +562,7 @@ void TouchSelectionControllerImpl::SetHandleBound(
const gfx::SelectionBound& bound,
const gfx::SelectionBound& bound_in_screen) {
handle->SetWidgetVisible(ShouldShowHandleFor(bound));
- handle->SetBoundInScreen(bound_in_screen, handle->IsWidgetVisible());
+ handle->SetBoundInScreen(bound_in_screen, handle->GetWidgetVisible());
}
bool TouchSelectionControllerImpl::ShouldShowHandleFor(
@@ -653,7 +671,7 @@ void TouchSelectionControllerImpl::HideQuickMenu() {
gfx::Rect TouchSelectionControllerImpl::GetQuickMenuAnchorRect() const {
// Get selection end points in client_view's space.
gfx::SelectionBound b1_in_screen = selection_bound_1_clipped_;
- gfx::SelectionBound b2_in_screen = cursor_handle_->IsWidgetVisible()
+ gfx::SelectionBound b2_in_screen = cursor_handle_->GetWidgetVisible()
? b1_in_screen
: selection_bound_2_clipped_;
// Convert from screen to client.
@@ -686,7 +704,7 @@ gfx::NativeView TouchSelectionControllerImpl::GetCursorHandleNativeView() {
gfx::SelectionBound::Type
TouchSelectionControllerImpl::GetSelectionHandle1Type() {
- return selection_handle_1_->selection_bound_type();
+ return selection_handle_1_->GetSelectionBoundType();
}
gfx::Rect TouchSelectionControllerImpl::GetSelectionHandle1Bounds() {
@@ -702,15 +720,15 @@ gfx::Rect TouchSelectionControllerImpl::GetCursorHandleBounds() {
}
bool TouchSelectionControllerImpl::IsSelectionHandle1Visible() {
- return selection_handle_1_->IsWidgetVisible();
+ return selection_handle_1_->GetWidgetVisible();
}
bool TouchSelectionControllerImpl::IsSelectionHandle2Visible() {
- return selection_handle_2_->IsWidgetVisible();
+ return selection_handle_2_->GetWidgetVisible();
}
bool TouchSelectionControllerImpl::IsCursorHandleVisible() {
- return cursor_handle_->IsWidgetVisible();
+ return cursor_handle_->GetWidgetVisible();
}
gfx::Rect TouchSelectionControllerImpl::GetExpectedHandleBounds(
diff --git a/chromium/ui/views/touchui/touch_selection_menu_views.cc b/chromium/ui/views/touchui/touch_selection_menu_views.cc
index d183819e841..f8e35ededbd 100644
--- a/chromium/ui/views/touchui/touch_selection_menu_views.cc
+++ b/chromium/ui/views/touchui/touch_selection_menu_views.cc
@@ -52,7 +52,7 @@ TouchSelectionMenuViews::TouchSelectionMenuViews(
DCHECK(client_);
DialogDelegate::SetButtons(ui::DIALOG_BUTTON_NONE);
- set_shadow(BubbleBorder::SMALL_SHADOW);
+ set_shadow(BubbleBorder::STANDARD_SHADOW);
set_parent_window(context);
constexpr gfx::Insets kMenuMargins = gfx::Insets(1);
set_margins(kMenuMargins);
@@ -147,8 +147,7 @@ void TouchSelectionMenuViews::CreateButtons() {
LabelButton* TouchSelectionMenuViews::CreateButton(
const base::string16& title,
Button::PressedCallback callback) {
- base::string16 label =
- gfx::RemoveAcceleratorChar(title, '&', nullptr, nullptr);
+ base::string16 label = gfx::RemoveAccelerator(title);
auto* button = AddChildView(std::make_unique<LabelButton>(
std::move(callback), label, style::CONTEXT_TOUCH_MENU));
constexpr gfx::Size kMenuButtonMinSize = gfx::Size(63, 38);
diff --git a/chromium/ui/views/view.cc b/chromium/ui/views/view.cc
index 39e229e165a..e8ef37bf8f8 100644
--- a/chromium/ui/views/view.cc
+++ b/chromium/ui/views/view.cc
@@ -11,12 +11,13 @@
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/containers/adapters.h"
+#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/i18n/rtl.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/notreached.h"
-#include "base/scoped_observer.h"
-#include "base/stl_util.h"
+#include "base/scoped_observation.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
@@ -26,7 +27,7 @@
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/base/ime/input_method.h"
#include "ui/compositor/clip_recorder.h"
#include "ui/compositor/compositor.h"
@@ -54,8 +55,8 @@
#include "ui/views/context_menu_controller.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/drag_controller.h"
-#include "ui/views/layout/layout_manager.h"
#include "ui/views/metadata/metadata_impl_macros.h"
+#include "ui/views/view_class_properties.h"
#include "ui/views/view_observer.h"
#include "ui/views/view_tracker.h"
#include "ui/views/views_features.h"
@@ -80,6 +81,13 @@ constexpr bool kContextMenuOnMousePress = false;
constexpr bool kContextMenuOnMousePress = true;
#endif
+// Having UseDefaultFillLayout true by default wreaks a bit of havoc right now,
+// so it is false for the time being. Once the various sites which currently use
+// FillLayout are converted to using this and the other places that either
+// override Layout() or do nothing are also validated, this can be switched to
+// true.
+constexpr bool kUseDefaultFillLayout = false;
+
// Default horizontal drag threshold in pixels.
// Same as what gtk uses.
constexpr int kDefaultHorizontalDragThreshold = 8;
@@ -88,6 +96,13 @@ constexpr int kDefaultHorizontalDragThreshold = 8;
// Same as what gtk uses.
constexpr int kDefaultVerticalDragThreshold = 8;
+// The following are used to offset the keys for the callbacks associated with
+// the bounds element callbacks.
+constexpr int kXChangedKey = sizeof(int) * 0;
+constexpr int kYChangedKey = sizeof(int) * 1;
+constexpr int kWidthChangedKey = sizeof(int) * 2;
+constexpr int kHeightChangedKey = sizeof(int) * 3;
+
// Returns the top view in |view|'s hierarchy.
const View* GetHierarchyRoot(const View* view) {
const View* root = view;
@@ -145,7 +160,7 @@ class VIEWS_EXPORT ViewMaskLayer : public ui::LayerDelegate,
// views::ViewObserver:
void OnViewBoundsChanged(View* observed_view) override;
- ScopedObserver<View, ViewObserver> observed_view_{this};
+ base::ScopedObservation<View, ViewObserver> observed_view_{this};
SkPath path_;
ui::Layer layer_;
@@ -156,7 +171,7 @@ ViewMaskLayer::ViewMaskLayer(const SkPath& path, View* observed_view)
layer_.set_delegate(this);
layer_.SetFillsBoundsOpaquely(false);
layer_.SetName("ViewMaskLayer");
- observed_view_.Add(observed_view);
+ observed_view_.Observe(observed_view);
OnViewBoundsChanged(observed_view);
}
@@ -188,6 +203,8 @@ void ViewMaskLayer::OnViewBoundsChanged(View* observed_view) {
View::View() {
SetTargetHandler(this);
+ if (kUseDefaultFillLayout)
+ default_fill_layout_.emplace(DefaultFillLayout());
}
View::~View() {
@@ -232,6 +249,8 @@ View::~View() {
// called at the end so observers can examine properties inside
// OnViewIsDeleting(), for instance.
ClearProperties();
+
+ life_cycle_state_ = LifeCycleState::kDestroyed;
}
// Tree operations -------------------------------------------------------------
@@ -362,8 +381,7 @@ void View::SetBoundsRect(const gfx::Rect& bounds) {
}
OnBoundsChanged(prev);
- if (bounds_ != prev)
- NotifyAccessibilityEvent(ax::mojom::Event::kLocationChanged, false);
+ NotifyAccessibilityEvent(ax::mojom::Event::kLocationChanged, false);
if (needs_layout_ || is_size_changed) {
needs_layout_ = false;
@@ -385,6 +403,17 @@ void View::SetBoundsRect(const gfx::Rect& bounds) {
for (ViewObserver& observer : observers_)
observer.OnViewBoundsChanged(this);
+
+ // The property effects have already been taken into account above. No need to
+ // redo them here.
+ if (prev.x() != bounds_.x())
+ OnPropertyChanged(&bounds_ + kXChangedKey, kPropertyEffectsNone);
+ if (prev.y() != bounds_.y())
+ OnPropertyChanged(&bounds_ + kYChangedKey, kPropertyEffectsNone);
+ if (prev.width() != bounds_.width())
+ OnPropertyChanged(&bounds_ + kWidthChangedKey, kPropertyEffectsNone);
+ if (prev.height() != bounds_.height())
+ OnPropertyChanged(&bounds_ + kHeightChangedKey, kPropertyEffectsNone);
}
void View::SetSize(const gfx::Size& size) {
@@ -485,8 +514,8 @@ void View::SizeToPreferredSize() {
}
gfx::Size View::GetMinimumSize() const {
- if (layout_manager_)
- return layout_manager_->GetMinimumSize(this);
+ if (HasLayoutManager())
+ return GetLayoutManager()->GetMinimumSize(this);
return GetPreferredSize();
}
@@ -496,14 +525,14 @@ gfx::Size View::GetMaximumSize() const {
}
int View::GetHeightForWidth(int w) const {
- if (layout_manager_)
- return layout_manager_->GetPreferredHeightForWidth(this, w);
+ if (HasLayoutManager())
+ return GetLayoutManager()->GetPreferredHeightForWidth(this, w);
return GetPreferredSize().height();
}
SizeBounds View::GetAvailableSize(const View* child) const {
- if (layout_manager_)
- return layout_manager_->GetAvailableSize(this, child);
+ if (HasLayoutManager())
+ return GetLayoutManager()->GetAvailableSize(this, child);
return SizeBounds();
}
@@ -546,7 +575,7 @@ void View::SetVisible(bool visible) {
}
}
-PropertyChangedSubscription View::AddVisibleChangedCallback(
+base::CallbackListSubscription View::AddVisibleChangedCallback(
PropertyChangedCallback callback) {
return AddPropertyChangedCallback(&visible_, std::move(callback));
}
@@ -555,6 +584,10 @@ bool View::IsDrawn() const {
return visible_ && parent_ ? parent_->IsDrawn() : false;
}
+bool View::GetIsDrawn() const {
+ return IsDrawn();
+}
+
bool View::GetEnabled() const {
return enabled_;
}
@@ -569,14 +602,14 @@ void View::SetEnabled(bool enabled) {
OnPropertyChanged(&enabled_, kPropertyEffectsPaint);
}
-PropertyChangedSubscription View::AddEnabledChangedCallback(
+base::CallbackListSubscription View::AddEnabledChangedCallback(
PropertyChangedCallback callback) {
return AddPropertyChangedCallback(&enabled_, std::move(callback));
}
View::Views View::GetChildrenInZOrder() {
- if (layout_manager_) {
- const auto result = layout_manager_->GetChildViewsInPaintOrder(this);
+ if (HasLayoutManager()) {
+ const auto result = GetLayoutManager()->GetChildViewsInPaintOrder(this);
DCHECK_EQ(children_.size(), result.size());
return result;
}
@@ -771,8 +804,8 @@ void View::Layout() {
needs_layout_ = false;
// If we have a layout manager, let it handle the layout for us.
- if (layout_manager_)
- layout_manager_->Layout(this);
+ if (HasLayoutManager())
+ GetLayoutManager()->Layout(this);
// Make sure to propagate the Layout() call to any children that haven't
// received it yet through the layout manager and need to be laid out. This
@@ -782,8 +815,9 @@ void View::Layout() {
// the call can take appropriate action.
internal::ScopedChildrenLock lock(this);
for (auto* child : children_) {
- if (child->needs_layout_ || !layout_manager_) {
- TRACE_EVENT1("views", "View::Layout", "class", child->GetClassName());
+ if (child->needs_layout_ || !HasLayoutManager()) {
+ TRACE_EVENT1("views", "View::LayoutChildren", "class",
+ child->GetClassName());
child->needs_layout_ = false;
child->Layout();
}
@@ -794,8 +828,8 @@ void View::InvalidateLayout() {
// Always invalidate up. This is needed to handle the case of us already being
// valid, but not our parent.
needs_layout_ = true;
- if (layout_manager_)
- layout_manager_->InvalidateLayout();
+ if (HasLayoutManager())
+ GetLayoutManager()->InvalidateLayout();
if (parent_) {
parent_->InvalidateLayout();
@@ -807,13 +841,37 @@ void View::InvalidateLayout() {
}
LayoutManager* View::GetLayoutManager() const {
- return layout_manager_.get();
+ if (layout_manager_)
+ return layout_manager_.get();
+ if (default_fill_layout_.has_value())
+ return &const_cast<View*>(this)->default_fill_layout_.value();
+ return nullptr;
}
void View::SetLayoutManager(std::nullptr_t) {
SetLayoutManagerImpl(nullptr);
}
+bool View::GetUseDefaultFillLayout() const {
+ if (layout_manager_)
+ return false;
+ return default_fill_layout_.has_value();
+}
+
+void View::SetUseDefaultFillLayout(bool value) {
+ if (value == default_fill_layout_.has_value())
+ return;
+
+ if (value) {
+ default_fill_layout_.emplace(DefaultFillLayout());
+ // Kill the currently assigned layout manager if one had been assigned.
+ layout_manager_.reset();
+ } else {
+ default_fill_layout_.reset();
+ }
+ OnPropertyChanged(&default_fill_layout_, kPropertyEffectsLayout);
+}
+
// Attributes ------------------------------------------------------------------
const View* View::GetViewByID(int id) const {
@@ -842,7 +900,7 @@ void View::SetID(int id) {
OnPropertyChanged(&id_, kPropertyEffectsNone);
}
-PropertyChangedSubscription View::AddIDChangedCallback(
+base::CallbackListSubscription View::AddIDChangedCallback(
PropertyChangedCallback callback) {
return AddPropertyChangedCallback(&id_, callback);
}
@@ -860,7 +918,7 @@ int View::GetGroup() const {
return group_;
}
-PropertyChangedSubscription View::AddGroupChangedCallback(
+base::CallbackListSubscription View::AddGroupChangedCallback(
PropertyChangedCallback callback) {
return AddPropertyChangedCallback(&group_, callback);
}
@@ -1002,6 +1060,8 @@ void View::SchedulePaintInRect(const gfx::Rect& rect) {
}
void View::Paint(const PaintInfo& parent_paint_info) {
+ CHECK_EQ(life_cycle_state_, LifeCycleState::kAlive);
+
if (!ShouldPaint())
return;
@@ -1101,6 +1161,8 @@ void View::Paint(const PaintInfo& parent_paint_info) {
OnPaint(canvas);
}
+ CHECK_EQ(life_cycle_state_, LifeCycleState::kAlive);
+
// View::Paint() recursion over the subtree.
PaintChildren(paint_info);
}
@@ -1110,6 +1172,10 @@ void View::SetBackground(std::unique_ptr<Background> b) {
SchedulePaint();
}
+Background* View::GetBackground() const {
+ return background_.get();
+}
+
void View::SetBorder(std::unique_ptr<Border> b) {
const gfx::Rect old_contents_bounds = GetContentsBounds();
border_ = std::move(b);
@@ -1127,6 +1193,10 @@ void View::SetBorder(std::unique_ptr<Border> b) {
SchedulePaint();
}
+Border* View::GetBorder() const {
+ return border_.get();
+}
+
const ui::ThemeProvider* View::GetThemeProvider() const {
const Widget* widget = GetWidget();
return widget ? widget->GetThemeProvider() : nullptr;
@@ -1167,7 +1237,8 @@ void View::SetFlipCanvasOnPaintForRTLUI(bool enable) {
OnPropertyChanged(&flip_canvas_on_paint_for_rtl_ui_, kPropertyEffectsPaint);
}
-PropertyChangedSubscription View::AddFlipCanvasOnPaintForRTLUIChangedCallback(
+base::CallbackListSubscription
+View::AddFlipCanvasOnPaintForRTLUIChangedCallback(
PropertyChangedCallback callback) {
return AddPropertyChangedCallback(&flip_canvas_on_paint_for_rtl_ui_,
std::move(callback));
@@ -1229,14 +1300,7 @@ View* View::GetTooltipHandlerForPoint(const gfx::Point& point) {
}
gfx::NativeCursor View::GetCursor(const ui::MouseEvent& event) {
-#if defined(OS_WIN)
- static ui::Cursor arrow;
- if (!arrow.platform())
- arrow.SetPlatformCursor(LoadCursor(nullptr, IDC_ARROW));
- return arrow;
-#else
return gfx::kNullCursor;
-#endif
}
bool View::HitTestPoint(const gfx::Point& point) const {
@@ -1281,10 +1345,10 @@ void View::OnMouseEntered(const ui::MouseEvent& event) {}
void View::OnMouseExited(const ui::MouseEvent& event) {}
-void View::SetMouseHandler(View* new_mouse_handler) {
- // |new_mouse_handler| may be nullptr.
+void View::SetMouseAndGestureHandler(View* new_handler) {
+ // |new_handler| may be nullptr.
if (parent_)
- parent_->SetMouseHandler(new_mouse_handler);
+ parent_->SetMouseAndGestureHandler(new_handler);
}
bool View::OnKeyPressed(const ui::KeyEvent& event) {
@@ -1357,6 +1421,10 @@ void View::OnTouchEvent(ui::TouchEvent* event) {
void View::OnGestureEvent(ui::GestureEvent* event) {}
+base::StringPiece View::GetLogContext() const {
+ return GetClassName();
+}
+
void View::SetNotifyEnterExitOnChild(bool notify) {
notify_enter_exit_on_child_ = notify;
}
@@ -1561,7 +1629,7 @@ View::FocusBehavior View::GetFocusBehavior() const {
}
void View::SetFocusBehavior(FocusBehavior focus_behavior) {
- if (focus_behavior_ == focus_behavior)
+ if (GetFocusBehavior() == focus_behavior)
return;
focus_behavior_ = focus_behavior;
@@ -1571,11 +1639,12 @@ void View::SetFocusBehavior(FocusBehavior focus_behavior) {
}
bool View::IsFocusable() const {
- return focus_behavior_ == FocusBehavior::ALWAYS && GetEnabled() && IsDrawn();
+ return GetFocusBehavior() == FocusBehavior::ALWAYS && GetEnabled() &&
+ IsDrawn();
}
bool View::IsAccessibilityFocusable() const {
- return focus_behavior_ != FocusBehavior::NEVER && GetEnabled() && IsDrawn();
+ return GetViewAccessibility().IsAccessibilityFocusable();
}
FocusManager* View::GetFocusManager() {
@@ -1659,8 +1728,8 @@ int View::OnDragUpdated(const ui::DropTargetEvent& event) {
void View::OnDragExited() {}
-int View::OnPerformDrop(const ui::DropTargetEvent& event) {
- return ui::DragDropTypes::DRAG_NONE;
+ui::mojom::DragOperation View::OnPerformDrop(const ui::DropTargetEvent& event) {
+ return ui::mojom::DragOperation::kNone;
}
void View::OnDragDone() {}
@@ -1673,9 +1742,9 @@ bool View::ExceededDragThreshold(const gfx::Vector2d& delta) {
// Accessibility----------------------------------------------------------------
-ViewAccessibility& View::GetViewAccessibility() {
+ViewAccessibility& View::GetViewAccessibility() const {
if (!view_accessibility_)
- view_accessibility_ = ViewAccessibility::Create(this);
+ view_accessibility_ = ViewAccessibility::Create(const_cast<View*>(this));
return *view_accessibility_;
}
@@ -1726,6 +1795,12 @@ gfx::NativeViewAccessible View::GetNativeViewAccessible() {
void View::NotifyAccessibilityEvent(ax::mojom::Event event_type,
bool send_native_event) {
+ // If it belongs to a widget but its native widget is already destructed, do
+ // not send such accessibility event as it's unexpected to send such events
+ // during destruction, and is likely to lead to crashes/problems.
+ if (GetWidget() && !GetWidget()->GetNativeView())
+ return;
+
AXEventManager::Get()->NotifyViewEvent(this, event_type);
if (send_native_event && GetWidget())
@@ -1766,8 +1841,8 @@ bool View::HasObserver(const ViewObserver* observer) const {
// Size and disposition --------------------------------------------------------
gfx::Size View::CalculatePreferredSize() const {
- if (layout_manager_)
- return layout_manager_->GetPreferredSize(this);
+ if (HasLayoutManager())
+ return GetLayoutManager()->GetPreferredSize(this);
return gfx::Size();
}
@@ -2177,7 +2252,7 @@ void View::HandlePropertyChangeEffects(PropertyEffects effects) {
SchedulePaint();
}
-PropertyChangedSubscription View::AddPropertyChangedCallback(
+base::CallbackListSubscription View::AddPropertyChangedCallback(
PropertyKey property,
PropertyChangedCallback callback) {
auto entry = property_changed_vectors_.find(property);
@@ -2204,6 +2279,34 @@ void View::OnPropertyChanged(PropertyKey property,
property_changed_callbacks->Notify();
}
+int View::GetX() const {
+ return x();
+}
+
+int View::GetY() const {
+ return y();
+}
+
+int View::GetWidth() const {
+ return width();
+}
+
+int View::GetHeight() const {
+ return height();
+}
+
+void View::SetWidth(int width) {
+ SetBounds(x(), y(), width, height());
+}
+
+void View::SetHeight(int height) {
+ SetBounds(x(), y(), width(), height);
+}
+
+base::string16 View::GetTooltip() const {
+ return GetTooltipText(gfx::Point());
+}
+
////////////////////////////////////////////////////////////////////////////////
// View, private:
@@ -2388,17 +2491,17 @@ void View::AddChildViewAtImpl(View* view, int index) {
// inherit the visibility of the owner View.
view->UpdateLayerVisibility();
+ // Need to notify the layout manager because one of the callbacks below might
+ // want to know the view's new preferred size, minimum size, etc.
+ if (HasLayoutManager())
+ GetLayoutManager()->ViewAdded(this, view);
+
if (widget) {
const ui::NativeTheme* new_theme = view->GetNativeTheme();
if (new_theme != old_theme)
view->PropagateThemeChanged();
}
- // Need to notify the layout manager because one of the callbacks below might
- // want to know the view's new preferred size, minimum size, etc.
- if (layout_manager_)
- layout_manager_->ViewAdded(this, view);
-
ViewHierarchyChangedDetails details(true, this, view, parent);
for (View* v = this; v; v = v->parent_)
@@ -2452,8 +2555,8 @@ void View::DoRemoveChildView(View* view,
// Need to notify the layout manager because one of the callbacks below might
// want to know the view's new preferred size, minimum size, etc.
- if (layout_manager_)
- layout_manager_->ViewRemoved(this, view);
+ if (HasLayoutManager())
+ GetLayoutManager()->ViewRemoved(this, view);
view->PropagateRemoveNotifications(this, new_parent, is_removed_from_widget);
view->parent_ = nullptr;
@@ -2641,6 +2744,12 @@ void View::SetLayoutManagerImpl(std::unique_ptr<LayoutManager> layout_manager) {
layout_manager_ = std::move(layout_manager);
if (layout_manager_)
layout_manager_->Installed(this);
+ // Only reset |default_fill_layout_| if it's already been set and there is a
+ // layout manager.
+ if (default_fill_layout_.has_value() && layout_manager_)
+ default_fill_layout_.reset();
+ else if (kUseDefaultFillLayout)
+ default_fill_layout_.emplace(DefaultFillLayout());
}
void View::SetLayerBounds(const gfx::Size& size,
@@ -2818,6 +2927,13 @@ void View::CreateMaskLayer() {
layer()->SetMaskLayer(mask_layer_->layer());
}
+// Layout ----------------------------------------------------------------------
+
+bool View::HasLayoutManager() const {
+ return ((default_fill_layout_.has_value() && !children_.empty()) ||
+ layout_manager_);
+}
+
// Input -----------------------------------------------------------------------
bool View::ProcessMousePressed(const ui::MouseEvent& event) {
@@ -3068,6 +3184,41 @@ bool View::DoDrag(const ui::LocatedEvent& event,
return true;
}
+View::DefaultFillLayout::DefaultFillLayout() = default;
+
+View::DefaultFillLayout::~DefaultFillLayout() = default;
+
+void View::DefaultFillLayout::Layout(View* host) {
+ const gfx::Rect contents_bounds = host->GetContentsBounds();
+ for (auto* child : host->children()) {
+ if (!child->GetProperty(kViewIgnoredByLayoutKey))
+ child->SetBoundsRect(contents_bounds);
+ }
+}
+
+gfx::Size View::DefaultFillLayout::GetPreferredSize(const View* host) const {
+ gfx::Size preferred_size;
+ for (auto* child : host->children()) {
+ if (!child->GetProperty(kViewIgnoredByLayoutKey))
+ preferred_size.SetToMax(child->GetPreferredSize());
+ }
+ return preferred_size;
+}
+
+int View::DefaultFillLayout::GetPreferredHeightForWidth(const View* host,
+ int width) const {
+ const gfx::Insets insets = host->GetInsets();
+ int preferred_height = 0;
+ for (auto* child : host->children()) {
+ if (!child->GetProperty(kViewIgnoredByLayoutKey)) {
+ preferred_height = std::max(
+ preferred_height,
+ child->GetHeightForWidth(width - insets.width()) + insets.height());
+ }
+ }
+ return preferred_height;
+}
+
DEFINE_ENUM_CONVERTERS(View::FocusBehavior,
{View::FocusBehavior::ACCESSIBLE_ONLY,
base::ASCIIToUTF16("ACCESSIBLE_ONLY")},
@@ -3079,18 +3230,31 @@ DEFINE_ENUM_CONVERTERS(View::FocusBehavior,
// This block requires the existence of METADATA_HEADER(View) in the class
// declaration for View.
BEGIN_METADATA_BASE(View)
+ADD_PROPERTY_METADATA(std::unique_ptr<Background>, Background)
+ADD_PROPERTY_METADATA(std::unique_ptr<Border>, Border)
ADD_READONLY_PROPERTY_METADATA(const char*, ClassName)
ADD_PROPERTY_METADATA(bool, Enabled)
ADD_PROPERTY_METADATA(View::FocusBehavior, FocusBehavior)
ADD_PROPERTY_METADATA(bool, FlipCanvasOnPaintForRTLUI)
ADD_PROPERTY_METADATA(int, Group)
+ADD_PROPERTY_METADATA(int, Height)
ADD_PROPERTY_METADATA(int, ID)
+ADD_READONLY_PROPERTY_METADATA(bool, IsDrawn);
ADD_READONLY_PROPERTY_METADATA(gfx::Size, MaximumSize)
ADD_READONLY_PROPERTY_METADATA(gfx::Size, MinimumSize)
ADD_PROPERTY_METADATA(bool, Mirrored)
ADD_PROPERTY_METADATA(bool, NotifyEnterExitOnChild)
+ADD_READONLY_PROPERTY_METADATA(base::string16, Tooltip)
ADD_PROPERTY_METADATA(bool, Visible)
ADD_PROPERTY_METADATA(bool, CanProcessEventsWithinSubtree)
+ADD_PROPERTY_METADATA(bool, UseDefaultFillLayout)
+ADD_PROPERTY_METADATA(int, Width)
+ADD_PROPERTY_METADATA(int, X)
+ADD_PROPERTY_METADATA(int, Y)
+ADD_CLASS_PROPERTY_METADATA(gfx::Insets, kMarginsKey)
+ADD_CLASS_PROPERTY_METADATA(gfx::Insets, kInternalPaddingKey)
+ADD_CLASS_PROPERTY_METADATA(LayoutAlignment, kCrossAxisAlignmentKey)
+ADD_CLASS_PROPERTY_METADATA(bool, kViewIgnoredByLayoutKey)
END_METADATA
} // namespace views
diff --git a/chromium/ui/views/view.h b/chromium/ui/views/view.h
index 758e7d17bea..0ae7efa3082 100644
--- a/chromium/ui/views/view.h
+++ b/chromium/ui/views/view.h
@@ -24,6 +24,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
+#include "base/strings/string_piece.h"
#include "build/build_config.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
@@ -46,6 +47,7 @@
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/views/layout/layout_manager.h"
#include "ui/views/layout/layout_types.h"
#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/metadata/view_factory.h"
@@ -81,7 +83,6 @@ class ContextMenuController;
class DragController;
class FocusManager;
class FocusTraversable;
-class LayoutManager;
class ScrollView;
class ViewAccessibility;
class ViewMaskLayer;
@@ -129,8 +130,6 @@ using PropertyKey = const void*;
using PropertyChangedCallbacks = base::RepeatingClosureList;
using PropertyChangedCallback = PropertyChangedCallbacks::CallbackType;
-using PropertyChangedSubscription =
- std::unique_ptr<PropertyChangedCallbacks::Subscription>;
// The elements in PropertyEffects represent bits which define what effect(s) a
// changed Property has on the containing class. Additional elements should
@@ -202,7 +201,7 @@ enum PropertyEffects {
// Each property should also have a way to "listen" to changes by registering
// a callback.
//
-// PropertyChangedSubscription AddFrobbleChangedCallback(
+// base::CallbackListSubscription AddFrobbleChangedCallback(
// PropertyChangedCallback callback) WARN_UNUSED_RETURN;
//
// Each callback uses the the existing base::Bind mechanisms which allow for
@@ -214,7 +213,7 @@ enum PropertyEffects {
// ...
// private:
// void OnFrobbleChanged();
-// PropertyChangeSubscription frobble_changed_subscription_;
+// base::CallbackListSubscription frobble_changed_subscription_;
// }
//
// ...
@@ -226,7 +225,7 @@ enum PropertyEffects {
//
// void MyView::ValidateFrobbleChanged() {
// bool frobble_changed = false;
-// PropertyChangedSubscription subscription =
+// base::CallbackListSubscription subscription =
// frobble_view_->AddFrobbleChangedCallback(
// base::BindRepeating([](bool* frobble_changed_ptr) {
// *frobble_changed_ptr = true;
@@ -573,9 +572,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Return whether a view is visible.
bool GetVisible() const;
- // Adds a callback subscription associated with the above Visible property.
- // The callback will be invoked whenever the Visible property changes.
- PropertyChangedSubscription AddVisibleChangedCallback(
+ // Adds a callback associated with the above Visible property. The callback
+ // will be invoked whenever the Visible property changes.
+ base::CallbackListSubscription AddVisibleChangedCallback(
PropertyChangedCallback callback) WARN_UNUSED_RESULT;
// Returns true if this view is drawn on screen.
@@ -591,9 +590,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Returns whether the view is enabled.
bool GetEnabled() const;
- // Adds a callback subscription associated with the above |Enabled| property.
- // The callback will be invoked whenever the property changes.
- PropertyChangedSubscription AddEnabledChangedCallback(
+ // Adds a callback associated with the above |Enabled| property. The callback
+ // will be invoked whenever the property changes.
+ base::CallbackListSubscription AddEnabledChangedCallback(
PropertyChangedCallback callback) WARN_UNUSED_RESULT;
// Returns the child views ordered in reverse z-order. That is, views later in
@@ -734,8 +733,13 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// parent views do not change.
void InvalidateLayout();
+ // TODO(kylixrd): Update comment once UseDefaultFillLayout is true by default.
+ // UseDefaultFillLayout will be set to true by default once the codebase is
+ // audited and refactored.
+ //
// Gets/Sets the Layout Manager used by this view to size and place its
- // children.
+ // children. NOTE: This will force UseDefaultFillLayout to false if it had
+ // been set to true.
//
// The LayoutManager is owned by the View and is deleted when the view is
// deleted, or when a new LayoutManager is installed. Call
@@ -758,6 +762,11 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
}
void SetLayoutManager(std::nullptr_t);
+ // Sets whether or not the default layout manager should be used for this
+ // view. NOTE: this can only be set if |layout_manager_| isn't assigned.
+ bool GetUseDefaultFillLayout() const;
+ void SetUseDefaultFillLayout(bool value);
+
// Attributes ----------------------------------------------------------------
// Recursively descends the view tree starting at this view, and returns
@@ -771,9 +780,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
int GetID() const { return id_; }
void SetID(int id);
- // Adds a callback subscription associated with the above |ID| property.
- // The callback will be invoked whenever the property changes.
- PropertyChangedSubscription AddIDChangedCallback(
+ // Adds a callback associated with the above |ID| property. The callback will
+ // be invoked whenever the property changes.
+ base::CallbackListSubscription AddIDChangedCallback(
PropertyChangedCallback callback) WARN_UNUSED_RESULT;
// A group id is used to tag views which are part of the same logical group.
@@ -784,9 +793,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Returns the group id of the view, or -1 if the id is not set yet.
int GetGroup() const;
- // Adds a callback subscription associated with the above |Group| property.
- // The callback will be invoked whenever the property changes.
- PropertyChangedSubscription AddGroupChangedCallback(
+ // Adds a callback associated with the above |Group| property. The callback
+ // will be invoked whenever the property changes.
+ base::CallbackListSubscription AddGroupChangedCallback(
PropertyChangedCallback callback) WARN_UNUSED_RESULT;
// If this returns true, the views from the same group can each be focused
@@ -870,11 +879,13 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// The background object may be null.
void SetBackground(std::unique_ptr<Background> b);
+ Background* GetBackground() const;
const Background* background() const { return background_.get(); }
Background* background() { return background_.get(); }
// The border object may be null.
virtual void SetBorder(std::unique_ptr<Border> b);
+ Border* GetBorder() const;
const Border* border() const { return border_.get(); }
Border* border() { return border_.get(); }
@@ -913,10 +924,10 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// the UI directionality.
void SetFlipCanvasOnPaintForRTLUI(bool enable);
- // Adds a callback subscription associated with the above
- // FlipCanvasOnPaintForRTLUI property. The callback will be invoked whenever
- // the FlipCanvasOnPaintForRTLUI property changes.
- PropertyChangedSubscription AddFlipCanvasOnPaintForRTLUIChangedCallback(
+ // Adds a callback associated with the above FlipCanvasOnPaintForRTLUI
+ // property. The callback will be invoked whenever the
+ // FlipCanvasOnPaintForRTLUI property changes.
+ base::CallbackListSubscription AddFlipCanvasOnPaintForRTLUIChangedCallback(
PropertyChangedCallback callback) WARN_UNUSED_RESULT;
// When set, this view will ignore base::l18n::IsRTL() and instead be drawn
@@ -1036,7 +1047,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Default implementation does nothing. Override as needed.
virtual void OnMouseExited(const ui::MouseEvent& event);
- // Set the MouseHandler for a drag session.
+ // Set both the MouseHandler and the GestureHandler for a drag session.
//
// A drag session is a stream of mouse events starting
// with a MousePressed event, followed by several MouseDragged
@@ -1053,9 +1064,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
//
// Note: if the mouse handler is no longer connected to a
// view hierarchy, events won't be sent.
- //
- // TODO(sky): rename this.
- virtual void SetMouseHandler(View* new_mouse_handler);
+ virtual void SetMouseAndGestureHandler(View* new_handler);
// Invoked when a key is pressed or released.
// Subclasses should return true if the event has been processed and false
@@ -1112,6 +1121,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
void OnScrollEvent(ui::ScrollEvent* event) override;
void OnTouchEvent(ui::TouchEvent* event) final;
void OnGestureEvent(ui::GestureEvent* event) override;
+ base::StringPiece GetLogContext() const override;
// Accelerators --------------------------------------------------------------
@@ -1157,7 +1167,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
void InsertAfterInFocusList(View* view);
// Gets/sets |FocusBehavior|. SetFocusBehavior() advances focus if necessary.
- FocusBehavior GetFocusBehavior() const;
+ virtual FocusBehavior GetFocusBehavior() const;
void SetFocusBehavior(FocusBehavior focus_behavior);
// Returns true if this view is focusable, |enabled_| and drawn.
@@ -1299,7 +1309,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Invoked during a drag and drop session when OnDragUpdated returns a valid
// operation and the user release the mouse.
- virtual int OnPerformDrop(const ui::DropTargetEvent& event);
+ virtual ui::mojom::DragOperation OnPerformDrop(
+ const ui::DropTargetEvent& event);
// Invoked from DoDrag after the drag completes. This implementation does
// nothing, and is intended for subclasses to do cleanup.
@@ -1312,9 +1323,10 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Accessibility -------------------------------------------------------------
// Get the object managing the accessibility interface for this View.
- ViewAccessibility& GetViewAccessibility();
+ ViewAccessibility& GetViewAccessibility() const;
- // Modifies |node_data| to reflect the current accessible state of this view.
+ // Modifies |node_data| to reflect the current accessible state of this
+ // view.
virtual void GetAccessibleNodeData(ui::AXNodeData* node_data) {}
// Handle a request from assistive technology to perform an action on this
@@ -1583,7 +1595,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Property Support ----------------------------------------------------------
- PropertyChangedSubscription AddPropertyChangedCallback(
+ base::CallbackListSubscription AddPropertyChangedCallback(
PropertyKey property,
PropertyChangedCallback callback) WARN_UNUSED_RESULT;
void OnPropertyChanged(PropertyKey property,
@@ -1595,6 +1607,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
friend class internal::RootView;
friend class internal::ScopedChildrenLock;
friend class FocusManager;
+ friend class ViewDebugWrapperImpl;
friend class ViewLayerTest;
friend class ViewLayerPixelCanvasTest;
friend class ViewTestApi;
@@ -1603,6 +1616,27 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
FRIEND_TEST_ALL_PREFIXES(ViewTest, PaintWithMovedViewUsesCacheInRTL);
FRIEND_TEST_ALL_PREFIXES(ViewTest, PaintWithUnknownInvalidation);
+ // http://crbug.com/1162949 : Instrumentation that indicates if this is alive.
+ enum class LifeCycleState : uint32_t {
+ kAlive = 0x600D600D,
+ kDestroyed = 0xBAADBAAD,
+ };
+
+ // This is the default view layout. It is a very simple version of FillLayout,
+ // which merely sets the bounds of the children to the content bounds. The
+ // actual FillLayout isn't used here because it supports a couple of features
+ // not used in the vast majority of instances. It also descends from
+ // LayoutManagerBase which adds some extra overhead not needed here.
+
+ class DefaultFillLayout : public LayoutManager {
+ public:
+ DefaultFillLayout();
+ ~DefaultFillLayout() override;
+ void Layout(View* host) override;
+ gfx::Size GetPreferredSize(const View* host) const override;
+ int GetPreferredHeightForWidth(const View* host, int width) const override;
+ };
+
using PropertyChangedVectors =
std::map<PropertyKey, std::unique_ptr<PropertyChangedCallbacks>>;
@@ -1807,6 +1841,12 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Creates a mask layer for the current view using |clip_path_|.
void CreateMaskLayer();
+ // Layout --------------------------------------------------------------------
+
+ // Returns whether a layout is deferred to a layout manager, either the
+ // default fill layout or the assigned layout manager.
+ bool HasLayoutManager() const;
+
// Input ---------------------------------------------------------------------
bool ProcessMousePressed(const ui::MouseEvent& event);
@@ -1871,6 +1911,20 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// function is NOT called if effects == kPropertyEffectsNone.
void HandlePropertyChangeEffects(PropertyEffects effects);
+ // The following methods are used by the property access system described in
+ // the comments above. They follow the required naming convention in order to
+ // allow them to be visible via the metadata.
+ int GetX() const;
+ int GetY() const;
+ int GetWidth() const;
+ int GetHeight() const;
+ void SetWidth(int width);
+ void SetHeight(int height);
+ bool GetIsDrawn() const;
+
+ // Special property accessor used by metadata to get the ToolTip text.
+ base::string16 GetTooltip() const;
+
//////////////////////////////////////////////////////////////////////////////
// Creation and lifetime -----------------------------------------------------
@@ -1954,6 +2008,11 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Views. The default is absolute positioning according to bounds_.
std::unique_ptr<LayoutManager> layout_manager_;
+ // The default "fill" layout manager. This is set only if |layout_manager_|
+ // isn't set and SetUseDefaultFillLayout(true) is called or
+ // |kUseDefaultFillLayout| is true.
+ base::Optional<DefaultFillLayout> default_fill_layout_;
+
// Whether this View's layer should be snapped to the pixel boundary.
bool snap_layer_to_pixel_boundary_ = false;
@@ -2053,7 +2112,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Accessibility -------------------------------------------------------------
// Manages the accessibility interface for this View.
- std::unique_ptr<ViewAccessibility> view_accessibility_;
+ mutable std::unique_ptr<ViewAccessibility> view_accessibility_;
// Observers -----------------------------------------------------------------
@@ -2062,6 +2121,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Property Changed Callbacks ------------------------------------------------
PropertyChangedVectors property_changed_vectors_;
+ // http://crbug.com/1162949 : Instrumentation that indicates if this is alive.
+ LifeCycleState life_cycle_state_ = LifeCycleState::kAlive;
+
DISALLOW_COPY_AND_ASSIGN(View);
};
@@ -2086,6 +2148,7 @@ VIEW_BUILDER_PROPERTY(bool, NotifyEnterExitOnChild)
VIEW_BUILDER_PROPERTY(gfx::Transform, Transform)
VIEW_BUILDER_PROPERTY(bool, Visible)
VIEW_BUILDER_PROPERTY(bool, CanProcessEventsWithinSubtree)
+VIEW_BUILDER_PROPERTY(bool, UseDefaultFillLayout)
END_VIEW_BUILDER
} // namespace views
diff --git a/chromium/ui/views/view_class_properties.cc b/chromium/ui/views/view_class_properties.cc
index a2799b0c428..1335c4d3543 100644
--- a/chromium/ui/views/view_class_properties.cc
+++ b/chromium/ui/views/view_class_properties.cc
@@ -41,5 +41,6 @@ DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(FlexSpecification, kFlexBehaviorKey, nullptr)
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(LayoutAlignment,
kCrossAxisAlignmentKey,
nullptr)
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kViewIgnoredByLayoutKey, false)
} // namespace views
diff --git a/chromium/ui/views/view_class_properties.h b/chromium/ui/views/view_class_properties.h
index bf7abfd4716..260742d4c3b 100644
--- a/chromium/ui/views/view_class_properties.h
+++ b/chromium/ui/views/view_class_properties.h
@@ -58,6 +58,12 @@ VIEWS_EXPORT extern const ui::ClassProperty<FlexSpecification*>* const
VIEWS_EXPORT extern const ui::ClassProperty<LayoutAlignment*>* const
kCrossAxisAlignmentKey;
+// Property indicating whether a view should be ignored by a layout. Supported
+// by View::DefaultFillLayout.
+// TODO(kylixrd): Revisit using for FillLayout.
+VIEWS_EXPORT extern const ui::ClassProperty<bool>* const
+ kViewIgnoredByLayoutKey;
+
} // namespace views
// Declaring the template specialization here to make sure that the
diff --git a/chromium/ui/views/view_tracker.cc b/chromium/ui/views/view_tracker.cc
index 7b54e203261..eaa66daf363 100644
--- a/chromium/ui/views/view_tracker.cc
+++ b/chromium/ui/views/view_tracker.cc
@@ -16,10 +16,10 @@ void ViewTracker::SetView(View* view) {
if (view == view_)
return;
- observer_.RemoveAll();
+ observation_.Reset();
view_ = view;
if (view_)
- observer_.Add(view_);
+ observation_.Observe(view_);
}
void ViewTracker::OnViewIsDeleting(View* observed_view) {
diff --git a/chromium/ui/views/view_tracker.h b/chromium/ui/views/view_tracker.h
index fead2fa1c08..d0bf0f67cfe 100644
--- a/chromium/ui/views/view_tracker.h
+++ b/chromium/ui/views/view_tracker.h
@@ -5,7 +5,7 @@
#ifndef UI_VIEWS_VIEW_TRACKER_H_
#define UI_VIEWS_VIEW_TRACKER_H_
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/views/view.h"
#include "ui/views/view_observer.h"
#include "ui/views/views_export.h"
@@ -21,6 +21,7 @@ class VIEWS_EXPORT ViewTracker : public ViewObserver {
void SetView(View* view);
View* view() { return view_; }
+ const View* view() const { return view_; }
// ViewObserver:
void OnViewIsDeleting(View* observed_view) override;
@@ -28,7 +29,7 @@ class VIEWS_EXPORT ViewTracker : public ViewObserver {
private:
View* view_ = nullptr;
- ScopedObserver<View, ViewObserver> observer_{this};
+ base::ScopedObservation<View, ViewObserver> observation_{this};
};
} // namespace views
diff --git a/chromium/ui/views/view_unittest.cc b/chromium/ui/views/view_unittest.cc
index 957d0e21cd1..6ffbb89d096 100644
--- a/chromium/ui/views/view_unittest.cc
+++ b/chromium/ui/views/view_unittest.cc
@@ -14,10 +14,10 @@
#include "base/command_line.h"
#include "base/i18n/rtl.h"
+#include "base/containers/contains.h"
#include "base/macros.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
-#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -5387,6 +5387,18 @@ TEST_F(ViewTest, TestEnabledPropertyMetadata) {
EXPECT_EQ(enabled_property->GetValueAsString(test_view.get()), false_value);
}
+TEST_F(ViewTest, TestMarginsPropertyMetadata) {
+ auto test_view = std::make_unique<View>();
+ views::metadata::ClassMetaData* view_metadata = View::MetaData();
+ ASSERT_TRUE(view_metadata);
+ views::metadata::MemberMetaDataBase* insets_property =
+ view_metadata->FindMemberData("kMarginsKey");
+ ASSERT_TRUE(insets_property);
+ base::string16 insets_value = base::ASCIIToUTF16("8,8,8,8");
+ insets_property->SetValueAsString(test_view.get(), insets_value);
+ EXPECT_EQ(insets_property->GetValueAsString(test_view.get()), insets_value);
+}
+
TEST_F(ViewTest, TestEnabledChangedCallback) {
auto test_view = std::make_unique<View>();
bool enabled_changed = false;
diff --git a/chromium/ui/views/view_utils.cc b/chromium/ui/views/view_utils.cc
new file mode 100644
index 00000000000..5df39fcb64f
--- /dev/null
+++ b/chromium/ui/views/view_utils.cc
@@ -0,0 +1,67 @@
+// Copyright 2021 The Chromium 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/view_utils.h"
+
+namespace views {
+
+ViewDebugWrapperImpl::ViewDebugWrapperImpl(View* view) : view_(view) {}
+
+ViewDebugWrapperImpl::~ViewDebugWrapperImpl() = default;
+
+std::string ViewDebugWrapperImpl::GetViewClassName() {
+ return view_->GetClassName();
+}
+
+int ViewDebugWrapperImpl::GetID() {
+ return view_->GetID();
+}
+
+debug::ViewDebugWrapper::BoundsTuple ViewDebugWrapperImpl::GetBounds() {
+ const auto& bounds = view_->bounds();
+ return BoundsTuple(bounds.x(), bounds.y(), bounds.width(), bounds.height());
+}
+
+bool ViewDebugWrapperImpl::GetVisible() {
+ return view_->GetVisible();
+}
+
+bool ViewDebugWrapperImpl::GetNeedsLayout() {
+ return view_->needs_layout();
+}
+
+bool ViewDebugWrapperImpl::GetEnabled() {
+ return view_->GetEnabled();
+}
+
+std::vector<debug::ViewDebugWrapper*> ViewDebugWrapperImpl::GetChildren() {
+ children_.clear();
+ for (auto* child : view_->children())
+ children_.push_back(std::make_unique<ViewDebugWrapperImpl>(child));
+
+ std::vector<debug::ViewDebugWrapper*> child_ptrs;
+ for (auto& child : children_)
+ child_ptrs.push_back(child.get());
+ return child_ptrs;
+}
+
+void ViewDebugWrapperImpl::ForAllProperties(PropCallback callback) {
+ views::View* view = const_cast<views::View*>(view_);
+ for (auto* member : *(view->GetClassMetaData())) {
+ auto flags = member->GetPropertyFlags();
+ if (!!(flags & views::metadata::PropertyFlags::kSerializable)) {
+ callback.Run(member->member_name(),
+ base::UTF16ToUTF8(member->GetValueAsString(view)));
+ }
+ }
+}
+
+void PrintViewHierarchy(View* view, bool verbose, int depth) {
+ ViewDebugWrapperImpl debug_view(view);
+ std::ostringstream out;
+ debug::PrintViewHierarchy(&out, &debug_view, verbose, depth);
+ LOG(ERROR) << '\n' << out.str();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/view_utils.h b/chromium/ui/views/view_utils.h
index 071c093f458..11893d7752f 100644
--- a/chromium/ui/views/view_utils.h
+++ b/chromium/ui/views/view_utils.h
@@ -5,13 +5,40 @@
#ifndef UI_VIEWS_VIEW_UTILS_H_
#define UI_VIEWS_VIEW_UTILS_H_
+#include <memory>
+#include <string>
#include <type_traits>
+#include <vector>
+#include "ui/views/debug/debugger_utils.h"
#include "ui/views/metadata/metadata_types.h"
#include "ui/views/view.h"
+#include "ui/views/views_export.h"
namespace views {
+class ViewDebugWrapperImpl : public debug::ViewDebugWrapper {
+ public:
+ explicit ViewDebugWrapperImpl(View* view);
+ ViewDebugWrapperImpl(const ViewDebugWrapperImpl&) = delete;
+ ViewDebugWrapperImpl& operator=(const ViewDebugWrapperImpl&) = delete;
+ ~ViewDebugWrapperImpl() override;
+
+ // debug::ViewDebugWrapper:
+ std::string GetViewClassName() override;
+ int GetID() override;
+ debug::ViewDebugWrapper::BoundsTuple GetBounds() override;
+ bool GetVisible() override;
+ bool GetNeedsLayout() override;
+ bool GetEnabled() override;
+ std::vector<debug::ViewDebugWrapper*> GetChildren() override;
+ void ForAllProperties(PropCallback callback) override;
+
+ private:
+ const View* const view_;
+ std::vector<std::unique_ptr<ViewDebugWrapperImpl>> children_;
+};
+
template <typename V>
bool IsViewClass(View* view) {
static_assert(std::is_base_of<View, V>::value, "Only View classes supported");
@@ -22,6 +49,10 @@ bool IsViewClass(View* view) {
return !!child;
}
+VIEWS_EXPORT void PrintViewHierarchy(View* view,
+ bool verbose = false,
+ int depth = -1);
+
} // namespace views
#endif // UI_VIEWS_VIEW_UTILS_H_
diff --git a/chromium/ui/views/views_delegate.cc b/chromium/ui/views/views_delegate.cc
index f856122274b..6e5bd4fe5a4 100644
--- a/chromium/ui/views/views_delegate.cc
+++ b/chromium/ui/views/views_delegate.cc
@@ -73,6 +73,10 @@ ViewsDelegate::ProcessAcceleratorWhileMenuShowing(
return ProcessMenuAcceleratorResult::LEAVE_MENU_OPEN;
}
+bool ViewsDelegate::ShouldCloseMenuIfMouseCaptureLost() const {
+ return true;
+}
+
#if defined(OS_WIN)
HICON ViewsDelegate::GetDefaultWindowIcon() const {
return nullptr;
@@ -86,7 +90,7 @@ bool ViewsDelegate::IsWindowInMetro(gfx::NativeWindow window) const {
return false;
}
#elif BUILDFLAG(ENABLE_DESKTOP_AURA) && \
- (defined(OS_LINUX) || defined(OS_CHROMEOS))
+ (defined(OS_LINUX) || defined(OS_CHROMEOS))
gfx::ImageSkia* ViewsDelegate::GetDefaultWindowIcon() const {
return nullptr;
}
diff --git a/chromium/ui/views/views_delegate.h b/chromium/ui/views/views_delegate.h
index 177271c66b2..87328d7ac3f 100644
--- a/chromium/ui/views/views_delegate.h
+++ b/chromium/ui/views/views_delegate.h
@@ -125,6 +125,10 @@ class VIEWS_EXPORT ViewsDelegate {
virtual ProcessMenuAcceleratorResult ProcessAcceleratorWhileMenuShowing(
const ui::Accelerator& accelerator);
+ // If a menu is showing and its window loses mouse capture, it will close if
+ // this returns true.
+ virtual bool ShouldCloseMenuIfMouseCaptureLost() const;
+
#if defined(OS_WIN)
// Retrieves the default window icon to use for windows if none is specified.
virtual HICON GetDefaultWindowIcon() const;
@@ -134,7 +138,7 @@ class VIEWS_EXPORT ViewsDelegate {
// environment.
virtual bool IsWindowInMetro(gfx::NativeWindow window) const;
#elif BUILDFLAG(ENABLE_DESKTOP_AURA) && \
- (defined(OS_LINUX) || defined(OS_CHROMEOS))
+ (defined(OS_LINUX) || defined(OS_CHROMEOS))
virtual gfx::ImageSkia* GetDefaultWindowIcon() const;
#endif
diff --git a/chromium/ui/views/views_features.cc b/chromium/ui/views/views_features.cc
index 83a10c42e3c..58b20ac6244 100644
--- a/chromium/ui/views/views_features.cc
+++ b/chromium/ui/views/views_features.cc
@@ -12,12 +12,6 @@ namespace features {
// Please keep alphabetized.
-// Increase corner radius on Dialogs for the material design refresh.
-// TODO(tluk): Remove this feature flag when platform inconsistencies
-// have been fixed as recorded on: https://crbug.com/932970
-const base::Feature kEnableMDRoundedCornersOnDialogs{
- "EnableMDRoundedCornersOnDialogs", base::FEATURE_DISABLED_BY_DEFAULT};
-
// Use a high-contrast style for ink drops when in platform high-contrast mode,
// including full opacity and a high-contrast color
const base::Feature kEnablePlatformHighContrastInkDrop{
@@ -37,7 +31,7 @@ const base::Feature kTextfieldFocusOnTapUp{"TextfieldFocusOnTapUp",
// Allows a "New" badge to be displayed on menu items that provide access to new
// features.
const base::Feature kEnableNewBadgeOnMenuItems{
- "EnableNewBadgeOnMenuItems", base::FEATURE_DISABLED_BY_DEFAULT};
+ "EnableNewBadgeOnMenuItems", base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace features
} // namespace views
diff --git a/chromium/ui/views/views_features.h b/chromium/ui/views/views_features.h
index f0f77154191..9a042adc3f8 100644
--- a/chromium/ui/views/views_features.h
+++ b/chromium/ui/views/views_features.h
@@ -14,7 +14,6 @@ namespace features {
// Please keep alphabetized.
-VIEWS_EXPORT extern const base::Feature kEnableMDRoundedCornersOnDialogs;
VIEWS_EXPORT extern const base::Feature kEnablePlatformHighContrastInkDrop;
VIEWS_EXPORT extern const base::Feature kEnableViewPaintOptimization;
VIEWS_EXPORT extern const base::Feature kTextfieldFocusOnTapUp;
diff --git a/chromium/ui/views/views_test_suite.cc b/chromium/ui/views/views_test_suite.cc
index 0c0796dd0a3..652033831cc 100644
--- a/chromium/ui/views/views_test_suite.cc
+++ b/chromium/ui/views/views_test_suite.cc
@@ -10,6 +10,7 @@
#include "base/path_service.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
+#include "build/chromeos_buildflags.h"
#include "gpu/ipc/service/image_transport_surface.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/resource/resource_bundle.h"
@@ -22,7 +23,7 @@
#include "ui/aura/env.h"
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/command_line.h"
#include "ui/gl/gl_switches.h"
#endif
@@ -49,7 +50,7 @@ int ViewsTestSuite::RunTestsSerially() {
void ViewsTestSuite::Initialize() {
base::TestSuite::Initialize();
-#if defined(OS_CHROMEOS) && defined(MEMORY_SANITIZER)
+#if BUILDFLAG(IS_CHROMEOS_ASH) && defined(MEMORY_SANITIZER)
// Force software-gl. This is necessary for mus tests to avoid an msan warning
// in gl init.
base::CommandLine::ForCurrentProcess()->AppendSwitch(
diff --git a/chromium/ui/views/views_test_suite.h b/chromium/ui/views/views_test_suite.h
index c9ab3d62545..c9b048b0bc5 100644
--- a/chromium/ui/views/views_test_suite.h
+++ b/chromium/ui/views/views_test_suite.h
@@ -17,6 +17,11 @@ class Env;
}
#endif
+#if defined(USE_OZONE)
+#include "ui/base/ui_base_features.h"
+#include "ui/ozone/public/ozone_platform.h"
+#endif
+
namespace views {
class ViewsTestSuite : public base::TestSuite {
@@ -49,6 +54,17 @@ class ViewsTestSuite : public base::TestSuite {
DISALLOW_COPY_AND_ASSIGN(ViewsTestSuite);
};
+#if defined(USE_OZONE)
+// Skips the X11-specific test on Ozone if the current platform is not X11.
+#define SKIP_TEST_IF_NOT_OZONE_X11() \
+ if (features::IsUsingOzonePlatform() && \
+ ui::OzonePlatform::GetPlatformNameForTest() != "x11") { \
+ GTEST_SKIP() << "This test is X11-only"; \
+ }
+#else
+#define SKIP_TEST_IF_NOT_OZONE_X11()
+#endif
+
} // namespace views
#endif // UI_VIEWS_VIEWS_TEST_SUITE_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
index 420b91a8ec2..e908394d3e8 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
@@ -27,7 +27,6 @@
#include "ui/ozone/public/ozone_platform.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/views/controls/image_view.h"
-#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
#include "ui/views/widget/widget.h"
namespace views {
@@ -112,10 +111,8 @@ DesktopDragDropClientOzone::DragContext::~DragContext() = default;
DesktopDragDropClientOzone::DesktopDragDropClientOzone(
aura::Window* root_window,
- views::DesktopNativeCursorManager* cursor_manager,
ui::WmDragHandler* drag_handler)
: root_window_(root_window),
- cursor_manager_(cursor_manager),
drag_handler_(drag_handler) {}
DesktopDragDropClientOzone::~DesktopDragDropClientOzone() {
@@ -147,8 +144,7 @@ int DesktopDragDropClientOzone::StartDragAndDrop(
auto initial_cursor = source_window->GetHost()->last_cursor();
drag_operation_ = operation;
if (cursor_client) {
- cursor_client->SetCursor(cursor_manager_->GetInitializedCursor(
- ui::mojom::CursorType::kGrabbing));
+ cursor_client->SetCursor(ui::mojom::CursorType::kGrabbing);
}
if (DragImageIsNeeded()) {
@@ -237,8 +233,10 @@ int DesktopDragDropClientOzone::OnDragMotion(const gfx::PointF& point,
int client_operation = ui::DragDropTypes::DRAG_NONE;
std::unique_ptr<ui::DropTargetEvent> event =
UpdateTargetAndCreateDropEvent(point, modifiers);
- if (drag_drop_delegate_ && event)
- client_operation = drag_drop_delegate_->OnDragUpdated(*event);
+ if (drag_drop_delegate_ && event) {
+ client_operation =
+ drag_drop_delegate_->OnDragUpdated(*event).drag_operation;
+ }
return client_operation;
}
@@ -331,7 +329,7 @@ void DesktopDragDropClientOzone::OnDragOperationChanged(
cursor_type = ui::mojom::CursorType::kDndLink;
break;
}
- cursor_client->SetCursor(cursor_manager_->GetInitializedCursor(cursor_type));
+ cursor_client->SetCursor(cursor_type);
}
void DesktopDragDropClientOzone::OnDragFinished(int dnd_action) {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
index e2420a3ad5f..3fe03e66457 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
@@ -30,7 +30,6 @@ class DropTargetEvent;
}
namespace views {
-class DesktopNativeCursorManager;
class Widget;
class VIEWS_EXPORT DesktopDragDropClientOzone
@@ -40,7 +39,6 @@ class VIEWS_EXPORT DesktopDragDropClientOzone
public aura::WindowObserver {
public:
DesktopDragDropClientOzone(aura::Window* root_window,
- views::DesktopNativeCursorManager* cursor_manager,
ui::WmDragHandler* drag_handler);
~DesktopDragDropClientOzone() override;
@@ -126,8 +124,6 @@ class VIEWS_EXPORT DesktopDragDropClientOzone
aura::Window* const root_window_;
- DesktopNativeCursorManager* cursor_manager_;
-
ui::WmDragHandler* const drag_handler_;
// Last window under the mouse.
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 9c6073c46e1..796ff465e98 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
@@ -10,22 +10,25 @@
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
-#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/wm/wm_drag_handler.h"
#include "ui/platform_window/wm/wm_drop_handler.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/views_delegate.h"
-#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
namespace views {
-
namespace {
+
+using ::ui::mojom::DragOperation;
+
class FakePlatformWindow : public ui::PlatformWindow, public ui::WmDragHandler {
public:
FakePlatformWindow() { SetWmDragHandler(this, this); }
@@ -153,7 +156,9 @@ class FakeDragDropDelegate : public aura::client::DragDropDelegate {
int last_event_flags() const { return last_event_flags_; }
ui::OSExchangeData* received_data() const { return received_data_.get(); }
- void SetOperation(int operation) { destination_operation_ = operation; }
+ void SetOperation(DragOperation operation) {
+ destination_operation_ = operation;
+ }
private:
// aura::client::DragDropDelegate:
@@ -166,20 +171,25 @@ class FakeDragDropDelegate : public aura::client::DragDropDelegate {
last_event_flags_ = event.flags();
}
- int OnDragUpdated(const ui::DropTargetEvent& event) override {
+ aura::client::DragUpdateInfo OnDragUpdated(
+ const ui::DropTargetEvent& event) override {
// The event must always have valid data. This will crash if it doesn't.
// See crbug.com/1151836.
auto dummy_copy = event.data().provider().Clone();
++num_updates_;
last_event_flags_ = event.flags();
- return destination_operation_;
+
+ return aura::client::DragUpdateInfo(
+ static_cast<int>(destination_operation_),
+ ui::DataTransferEndpoint(ui::EndpointType::kDefault));
}
void OnDragExited() override { ++num_exits_; }
- int OnPerformDrop(const ui::DropTargetEvent& event,
- std::unique_ptr<ui::OSExchangeData> data) override {
+ DragOperation OnPerformDrop(
+ const ui::DropTargetEvent& event,
+ std::unique_ptr<ui::OSExchangeData> data) override {
// The event must always have valid data. This will crash if it doesn't.
// See crbug.com/1151836.
auto dummy_copy = event.data().provider().Clone();
@@ -195,7 +205,7 @@ class FakeDragDropDelegate : public aura::client::DragDropDelegate {
int num_exits_;
int num_drops_;
std::unique_ptr<ui::OSExchangeData> received_data_;
- int destination_operation_;
+ DragOperation destination_operation_;
int last_event_flags_ = ui::EF_NONE;
DISALLOW_COPY_AND_ASSIGN(FakeDragDropDelegate);
@@ -247,18 +257,16 @@ class DesktopDragDropClientOzoneTest : public ViewsTestBase {
dragdrop_delegate_ = std::make_unique<FakeDragDropDelegate>();
aura::client::SetDragDropDelegate(window, dragdrop_delegate_.get());
- cursor_manager_ = std::make_unique<DesktopNativeCursorManager>();
platform_window_ = std::make_unique<FakePlatformWindow>();
ui::WmDragHandler* drag_handler = ui::GetWmDragHandler(*(platform_window_));
// Creates DesktopDragDropClientOzone with |window| and |drag_handler|.
- client_ = std::make_unique<DesktopDragDropClientOzone>(
- window, cursor_manager_.get(), drag_handler);
+ client_ =
+ std::make_unique<DesktopDragDropClientOzone>(window, drag_handler);
SetWmDropHandler(platform_window_.get(), client_.get());
}
void TearDown() override {
client_.reset();
- cursor_manager_.reset();
platform_window_.reset();
widget_.reset();
ViewsTestBase::TearDown();
@@ -270,7 +278,6 @@ class DesktopDragDropClientOzoneTest : public ViewsTestBase {
private:
std::unique_ptr<DesktopDragDropClientOzone> client_;
- std::unique_ptr<DesktopNativeCursorManager> cursor_manager_;
// The widget used to initiate drags.
std::unique_ptr<Widget> widget_;
@@ -281,7 +288,7 @@ class DesktopDragDropClientOzoneTest : public ViewsTestBase {
// TODO(1119787): fix this.
TEST_F(DesktopDragDropClientOzoneTest, DISABLED_StartDrag) {
// Set the operation which the destination can accept.
- dragdrop_delegate_->SetOperation(ui::DragDropTypes::DRAG_COPY);
+ dragdrop_delegate_->SetOperation(DragOperation::kCopy);
// Start Drag and Drop with the operations suggested.
int operation = StartDragAndDrop(ui::DragDropTypes::DRAG_COPY |
ui::DragDropTypes::DRAG_MOVE);
@@ -300,7 +307,7 @@ TEST_F(DesktopDragDropClientOzoneTest, DISABLED_StartDrag) {
TEST_F(DesktopDragDropClientOzoneTest, DISABLED_StartDragCtrlPressed) {
SetModifiers(ui::EF_CONTROL_DOWN);
// Set the operation which the destination can accept.
- dragdrop_delegate_->SetOperation(ui::DragDropTypes::DRAG_COPY);
+ dragdrop_delegate_->SetOperation(DragOperation::kCopy);
// Start Drag and Drop with the operations suggested.
int operation = StartDragAndDrop(ui::DragDropTypes::DRAG_COPY |
ui::DragDropTypes::DRAG_MOVE);
@@ -317,7 +324,7 @@ TEST_F(DesktopDragDropClientOzoneTest, DISABLED_StartDragCtrlPressed) {
TEST_F(DesktopDragDropClientOzoneTest, ReceiveDrag) {
// Set the operation which the destination can accept.
- int operation = ui::DragDropTypes::DRAG_MOVE;
+ auto operation = DragOperation::kMove;
dragdrop_delegate_->SetOperation(operation);
// Set the data which will be delivered.
@@ -339,7 +346,7 @@ TEST_F(DesktopDragDropClientOzoneTest, ReceiveDrag) {
// The |updated_operation| decided through negotiation should be
// 'ui::DragDropTypes::DRAG_MOVE'.
- EXPECT_EQ(operation, updated_operation);
+ EXPECT_EQ(static_cast<int>(operation), updated_operation);
base::string16 string_data;
dragdrop_delegate_->received_data()->GetString(&string_data);
@@ -356,7 +363,7 @@ TEST_F(DesktopDragDropClientOzoneTest, TargetDestroyedDuringDrag) {
ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
// Set the operation which the destination can accept.
- dragdrop_delegate_->SetOperation(ui::DragDropTypes::DRAG_MOVE);
+ dragdrop_delegate_->SetOperation(DragOperation::kMove);
// Set the data which will be delivered.
const base::string16 sample_data = base::ASCIIToUTF16("ReceiveDrag");
@@ -384,14 +391,13 @@ TEST_F(DesktopDragDropClientOzoneTest, TargetDestroyedDuringDrag) {
auto another_dragdrop_delegate = std::make_unique<FakeDragDropDelegate>();
aura::client::SetDragDropDelegate(another_window,
another_dragdrop_delegate.get());
- another_dragdrop_delegate->SetOperation(ui::DragDropTypes::DRAG_COPY);
+ another_dragdrop_delegate->SetOperation(DragOperation::kCopy);
- auto another_cursor_manager = std::make_unique<DesktopNativeCursorManager>();
auto another_platform_window = std::make_unique<FakePlatformWindow>();
ui::WmDragHandler* drag_handler =
ui::GetWmDragHandler(*(another_platform_window));
auto another_client = std::make_unique<DesktopDragDropClientOzone>(
- another_window, another_cursor_manager.get(), drag_handler);
+ another_window, drag_handler);
SetWmDropHandler(another_platform_window.get(), another_client.get());
std::unique_ptr<ui::OSExchangeData> another_data =
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 eac8953797e..7e4a7f1299c 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
@@ -13,6 +13,7 @@
#include "ui/aura/window_tree_host.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drop_target_event.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
#include "ui/events/event_constants.h"
@@ -77,7 +78,7 @@ DWORD DesktopDropTargetWin::OnDragOver(IDataObject* data_object,
DragDropDelegate* delegate;
Translate(data_object, key_state, position, effect, &data, &event, &delegate);
if (delegate)
- drag_operation = delegate->OnDragUpdated(*event);
+ drag_operation = delegate->OnDragUpdated(*event).drag_operation;
return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
}
@@ -90,7 +91,7 @@ DWORD DesktopDropTargetWin::OnDrop(IDataObject* data_object,
DWORD key_state,
POINT position,
DWORD effect) {
- int drag_operation = ui::DragDropTypes::DRAG_NONE;
+ auto drag_operation = ui::mojom::DragOperation::kNone;
std::unique_ptr<OSExchangeData> data;
std::unique_ptr<ui::DropTargetEvent> event;
DragDropDelegate* delegate;
@@ -101,7 +102,8 @@ DWORD DesktopDropTargetWin::OnDrop(IDataObject* data_object,
target_window_->RemoveObserver(this);
target_window_ = nullptr;
}
- return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
+ return ui::DragDropTypes::DragOperationToDropEffect(
+ static_cast<int>(drag_operation));
}
void DesktopDropTargetWin::OnWindowDestroyed(aura::Window* window) {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
index fd44f73d9b5..3ef05e395c0 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
@@ -14,18 +14,10 @@
namespace views {
-DesktopNativeCursorManager::DesktopNativeCursorManager()
- : cursor_loader_(ui::CursorLoader::Create()) {}
+DesktopNativeCursorManager::DesktopNativeCursorManager() = default;
DesktopNativeCursorManager::~DesktopNativeCursorManager() = default;
-gfx::NativeCursor DesktopNativeCursorManager::GetInitializedCursor(
- ui::mojom::CursorType type) {
- gfx::NativeCursor cursor(type);
- cursor_loader_->SetPlatformCursor(&cursor);
- return cursor;
-}
-
void DesktopNativeCursorManager::AddHost(aura::WindowTreeHost* host) {
hosts_.insert(host);
}
@@ -37,8 +29,8 @@ void DesktopNativeCursorManager::RemoveHost(aura::WindowTreeHost* host) {
void DesktopNativeCursorManager::SetDisplay(
const display::Display& display,
wm::NativeCursorManagerDelegate* delegate) {
- cursor_loader_->SetDisplayData(display.rotation(),
- display.device_scale_factor());
+ cursor_loader_.SetDisplayData(display.rotation(),
+ display.device_scale_factor());
SetCursor(delegate->GetCursor(), delegate);
}
@@ -47,7 +39,7 @@ void DesktopNativeCursorManager::SetCursor(
gfx::NativeCursor cursor,
wm::NativeCursorManagerDelegate* delegate) {
gfx::NativeCursor new_cursor = cursor;
- cursor_loader_->SetPlatformCursor(&new_cursor);
+ cursor_loader_.SetPlatformCursor(&new_cursor);
delegate->CommitCursor(new_cursor);
if (delegate->IsCursorVisible()) {
@@ -67,7 +59,7 @@ void DesktopNativeCursorManager::SetVisibility(
SetCursor(delegate->GetCursor(), delegate);
} else {
gfx::NativeCursor invisible_cursor(ui::mojom::CursorType::kNone);
- cursor_loader_->SetPlatformCursor(&invisible_cursor);
+ cursor_loader_.SetPlatformCursor(&invisible_cursor);
for (auto* host : hosts_)
host->SetCursor(invisible_cursor);
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
index d926393dd7f..61d621b20b9 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "ui/base/cursor/cursor_loader.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
#include "ui/views/views_export.h"
#include "ui/wm/core/native_cursor_manager.h"
@@ -18,10 +19,6 @@ namespace aura {
class WindowTreeHost;
}
-namespace ui {
-class CursorLoader;
-}
-
namespace wm {
class NativeCursorManagerDelegate;
}
@@ -36,10 +33,6 @@ class VIEWS_EXPORT DesktopNativeCursorManager : public wm::NativeCursorManager {
DesktopNativeCursorManager();
~DesktopNativeCursorManager() override;
- // Builds a cursor and sets the internal platform representation. The return
- // value should not be cached.
- gfx::NativeCursor GetInitializedCursor(ui::mojom::CursorType type);
-
// Adds |host| to the set |hosts_|.
void AddHost(aura::WindowTreeHost* host);
@@ -64,7 +57,7 @@ class VIEWS_EXPORT DesktopNativeCursorManager : public wm::NativeCursorManager {
using Hosts = std::set<aura::WindowTreeHost*>;
Hosts hosts_;
- std::unique_ptr<ui::CursorLoader> cursor_loader_;
+ ui::CursorLoader cursor_loader_;
DISALLOW_COPY_AND_ASSIGN(DesktopNativeCursorManager);
};
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 3d70eb212ae..935bf612181 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
@@ -17,6 +17,7 @@
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/window_parenting_client.h"
#include "ui/aura/env.h"
@@ -25,6 +26,7 @@
#include "ui/aura/window_occlusion_tracker.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/class_property.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
@@ -548,8 +550,7 @@ void DesktopNativeWidgetAura::InitNativeWidget(Widget::InitParams params) {
position_client_ = desktop_window_tree_host_->CreateScreenPositionClient();
- drag_drop_client_ =
- desktop_window_tree_host_->CreateDragDropClient(native_cursor_manager_);
+ drag_drop_client_ = desktop_window_tree_host_->CreateDragDropClient();
// Mus returns null from CreateDragDropClient().
if (drag_drop_client_)
aura::client::SetDragDropClient(host_->window(), drag_drop_client_.get());
@@ -1168,6 +1169,10 @@ void DesktopNativeWidgetAura::OnGestureEvent(ui::GestureEvent* event) {
native_widget_delegate_->OnGestureEvent(event);
}
+base::StringPiece DesktopNativeWidgetAura::GetLogContext() const {
+ return "DesktopNativeWidgetAura";
+}
+
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, wm::ActivationDelegate implementation:
@@ -1223,11 +1228,15 @@ void DesktopNativeWidgetAura::OnDragEntered(const ui::DropTargetEvent& event) {
event.data(), event.location(), event.source_operations());
}
-int DesktopNativeWidgetAura::OnDragUpdated(const ui::DropTargetEvent& event) {
+aura::client::DragUpdateInfo DesktopNativeWidgetAura::OnDragUpdated(
+ const ui::DropTargetEvent& event) {
DCHECK(drop_helper_.get() != nullptr);
last_drop_operation_ = drop_helper_->OnDragOver(
event.data(), event.location(), event.source_operations());
- return last_drop_operation_;
+
+ return aura::client::DragUpdateInfo(
+ last_drop_operation_,
+ ui::DataTransferEndpoint(ui::EndpointType::kDefault));
}
void DesktopNativeWidgetAura::OnDragExited() {
@@ -1235,7 +1244,7 @@ void DesktopNativeWidgetAura::OnDragExited() {
drop_helper_->OnDragExit();
}
-int DesktopNativeWidgetAura::OnPerformDrop(
+ui::mojom::DragOperation DesktopNativeWidgetAura::OnPerformDrop(
const ui::DropTargetEvent& event,
std::unique_ptr<ui::OSExchangeData> data) {
DCHECK(drop_helper_.get() != nullptr);
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 41a7b8afa78..10850c57467 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
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/client/focus_change_observer.h"
#include "ui/aura/window_delegate.h"
@@ -228,6 +229,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
void OnMouseEvent(ui::MouseEvent* event) override;
void OnScrollEvent(ui::ScrollEvent* event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
+ base::StringPiece GetLogContext() const override;
// wm::ActivationDelegate:
bool ShouldActivate() const override;
@@ -243,10 +245,12 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
// ura::client::DragDropDelegate:
void OnDragEntered(const ui::DropTargetEvent& event) override;
- int OnDragUpdated(const ui::DropTargetEvent& event) override;
+ aura::client::DragUpdateInfo OnDragUpdated(
+ const ui::DropTargetEvent& event) override;
void OnDragExited() override;
- int OnPerformDrop(const ui::DropTargetEvent& event,
- std::unique_ptr<ui::OSExchangeData> data) override;
+ ui::mojom::DragOperation OnPerformDrop(
+ const ui::DropTargetEvent& event,
+ std::unique_ptr<ui::OSExchangeData> data) override;
// aura::WindowTreeHostObserver:
void OnHostCloseRequested(aura::WindowTreeHost* host) 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 0f317eb423c..e64917121c0 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
@@ -13,6 +13,7 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/focus_client.h"
@@ -161,7 +162,7 @@ TEST_F(DesktopNativeWidgetAuraTest, DesktopAuraWindowShowFrameless) {
#endif // OS_WIN
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(crbug.com/916272): investigate fixing and enabling on Chrome OS.
#define MAYBE_GlobalCursorState DISABLED_GlobalCursorState
#else
@@ -295,7 +296,7 @@ std::unique_ptr<Widget> CreateAndShowControlWidget(aura::Window* parent) {
} // namespace
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(crbug.com/916272): investigate fixing and enabling on Chrome OS.
#define MAYBE_ReorderDoesntRecomputeOcclusion \
DISABLED_ReorderDoesntRecomputeOcclusion
@@ -607,7 +608,7 @@ TEST_F(DesktopAuraWidgetTest, CloseWidgetDuringMouseReleased) {
RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(crbug.com/916272): investigate fixing and enabling on Chrome OS.
#define MAYBE_WindowMouseModalityTest DISABLED_WindowMouseModalityTest
#else
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen.cc
index 50ac4c71dbf..5ced5db5288 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen.cc
@@ -4,12 +4,13 @@
#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#include "build/chromeos_buildflags.h"
#include "ui/display/screen.h"
namespace views {
void InstallDesktopScreenIfNecessary() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// ChromeOS ozone builds use another path instead, where display::Screen is
// properly set. Thus, do early return here.
return;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
index e9bb45ad238..91c516429c2 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
@@ -28,6 +28,11 @@ gfx::NativeWindow DesktopScreenWin::GetNativeWindowFromHWND(HWND hwnd) const {
: gfx::kNullNativeWindow;
}
+bool DesktopScreenWin::IsNativeWindowOccluded(gfx::NativeWindow window) const {
+ return window->GetHost()->GetNativeWindowOcclusionState() ==
+ aura::Window::OcclusionState::OCCLUDED;
+}
+
////////////////////////////////////////////////////////////////////////////////
display::Screen* CreateDesktopScreen() {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h
index 52f54f2e6b8..32c43c5be40 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h
@@ -21,6 +21,7 @@ class VIEWS_EXPORT DesktopScreenWin : public display::win::ScreenWin {
// display::win::ScreenWin:
HWND GetHWNDFromNativeWindow(gfx::NativeWindow window) const override;
gfx::NativeWindow GetNativeWindowFromHWND(HWND hwnd) const override;
+ bool IsNativeWindowOccluded(gfx::NativeWindow window) const override;
display::Screen* const old_screen_ = display::Screen::SetScreenInstance(this);
};
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index 3bbb56ca869..0a6e1e72af2 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -19,6 +19,7 @@
#include "ui/display/display.h"
#include "ui/display/display_finder.h"
#include "ui/display/util/display_util.h"
+#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/point_conversions.h"
@@ -33,7 +34,7 @@ namespace views {
DesktopScreenX11::DesktopScreenX11() {
if (LinuxUI::instance())
- display_scale_factor_observer_.Add(LinuxUI::instance());
+ display_scale_factor_observer_.Observe(LinuxUI::instance());
}
DesktopScreenX11::~DesktopScreenX11() {
@@ -41,9 +42,8 @@ DesktopScreenX11::~DesktopScreenX11() {
}
void DesktopScreenX11::Init() {
- if (x11_display_manager_->IsXrandrAvailable() &&
- ui::X11EventSource::HasInstance())
- event_source_observer_.Add(ui::X11EventSource::GetInstance());
+ if (x11_display_manager_->IsXrandrAvailable())
+ event_observer_.Observe(x11::Connection::Get());
x11_display_manager_->Init();
}
@@ -162,8 +162,8 @@ std::string DesktopScreenX11::GetCurrentWorkspace() {
return x11_display_manager_->GetCurrentWorkspace();
}
-bool DesktopScreenX11::DispatchXEvent(x11::Event* event) {
- return x11_display_manager_->ProcessEvent(event);
+void DesktopScreenX11::OnEvent(const x11::Event& event) {
+ x11_display_manager_->OnEvent(event);
}
void DesktopScreenX11::OnDeviceScaleFactorChanged() {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
index 54954d61993..efbb8498cb3 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
@@ -6,12 +6,13 @@
#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_X11_H_
#include <memory>
+#include <set>
+#include <string>
#include <vector>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/base/x/x11_display_manager.h"
#include "ui/display/screen.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/event.h"
#include "ui/views/linux_ui/device_scale_factor_observer.h"
#include "ui/views/linux_ui/linux_ui.h"
@@ -22,7 +23,7 @@ class DesktopScreenX11Test;
// Screen implementation that talks to XRandR
class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
- public ui::XEventDispatcher,
+ public x11::EventObserver,
public ui::XDisplayManager::Delegate,
public DeviceScaleFactorObserver {
public:
@@ -53,8 +54,8 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
void RemoveObserver(display::DisplayObserver* observer) override;
std::string GetCurrentWorkspace() override;
- // ui::XEventDispatcher:
- bool DispatchXEvent(x11::Event* event) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& event) override;
// DeviceScaleFactorObserver:
void OnDeviceScaleFactorChanged() override;
@@ -71,16 +72,16 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
display::Screen* const old_screen_ = display::Screen::SetScreenInstance(this);
std::unique_ptr<ui::XDisplayManager> x11_display_manager_ =
std::make_unique<ui::XDisplayManager>(this);
- ScopedObserver<LinuxUI,
- DeviceScaleFactorObserver,
- &LinuxUI::AddDeviceScaleFactorObserver,
- &LinuxUI::RemoveDeviceScaleFactorObserver>
+ base::ScopedObservation<LinuxUI,
+ DeviceScaleFactorObserver,
+ &LinuxUI::AddDeviceScaleFactorObserver,
+ &LinuxUI::RemoveDeviceScaleFactorObserver>
display_scale_factor_observer_{this};
- ScopedObserver<ui::X11EventSource,
- XEventDispatcher,
- &ui::X11EventSource::AddXEventDispatcher,
- &ui::X11EventSource::RemoveXEventDispatcher>
- event_source_observer_{this};
+ base::ScopedObservation<x11::Connection,
+ x11::EventObserver,
+ &x11::Connection::AddEventObserver,
+ &x11::Connection::RemoveEventObserver>
+ event_observer_{this};
};
} // 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 77a3bbfd623..5617645dced 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
@@ -69,8 +69,8 @@ class VIEWS_EXPORT DesktopWindowTreeHost {
// Creates and returns the DragDropClient implementation to use. Return value
// is owned by DesktopNativeWidgetAura and lives as long as
// DesktopWindowTreeHost.
- virtual std::unique_ptr<aura::client::DragDropClient> CreateDragDropClient(
- DesktopNativeCursorManager* cursor_manager) = 0;
+ virtual std::unique_ptr<aura::client::DragDropClient>
+ CreateDragDropClient() = 0;
// Creates the ScreenPositionClient to use for the WindowTreeHost. Default
// implementation creates DesktopScreenPositionClient.
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
index 0bdc1470708..a0f75cc909f 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
@@ -339,17 +339,6 @@ void DesktopWindowTreeHostLinux::DestroyNonClientEventFilter() {
non_client_window_event_filter_.reset();
}
-void DesktopWindowTreeHostLinux::GetWindowMask(const gfx::Size& size,
- SkPath* window_mask) {
- DCHECK(window_mask);
- Widget* widget = native_widget_delegate()->AsWidget();
- if (widget->non_client_view()) {
- // Some frame views define a custom (non-rectangular) window mask. If
- // so, use it to define the window shape. If not, fall through.
- widget->non_client_view()->GetWindowMask(size, window_mask);
- }
-}
-
void DesktopWindowTreeHostLinux::OnLostMouseGrab() {
dispatcher()->OnHostLostMouseGrab();
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
index 4b6a5a4476a..e0339379e1a 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
@@ -19,8 +19,6 @@
#include "ui/views/views_export.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
-class SkPath;
-
namespace aura {
class ScopedWindowTargeter;
} // namespace aura
@@ -106,7 +104,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux
void DestroyNonClientEventFilter();
// X11ExtensionDelegate overrides:
- void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override;
void OnLostMouseGrab() override;
#if BUILDFLAG(USE_ATK)
bool OnAtkKeyEvent(AtkKeyEventStruct* atk_key_event, bool transient) override;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc
index ee8f425455c..2dbd06da94d 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc
@@ -20,9 +20,9 @@
#include "ui/base/ime/input_method.h"
#include "ui/base/x/test/x11_property_change_waiter.h"
#include "ui/base/x/x11_util.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_util.h"
#include "ui/views/controls/textfield/textfield.h"
#endif // defined(USE_X11)
@@ -79,8 +79,7 @@ void DispatchMouseMotionEvent(DesktopWindowTreeHostLinux* desktop_host,
.same_screen = true,
};
- x11::Event x11_event(xev);
- ui::X11EventSource::GetInstance()->ProcessXEvent(&x11_event);
+ connection->DispatchEvent(x11::Event{xev});
}
// Blocks till |window| gets activated.
@@ -98,10 +97,10 @@ class ActivationWaiter : public ui::X11PropertyChangeWaiter {
private:
// ui::X11PropertyChangeWaiter:
- bool ShouldKeepOnWaiting(x11::Event* event) override {
+ bool ShouldKeepOnWaiting() override {
x11::Window window = x11::Window::None;
- ui::GetProperty(ui::GetX11RootWindow(), gfx::GetAtom("_NET_ACTIVE_WINDOW"),
- &window);
+ GetProperty(ui::GetX11RootWindow(), x11::GetAtom("_NET_ACTIVE_WINDOW"),
+ &window);
return window != window_;
}
@@ -510,9 +509,6 @@ TEST_F(DesktopWindowTreeHostLinuxTest,
// Chrome even if it not possible to deactivate the window wrt to the x server.
// This behavior is required by several interactive_ui_tests.
TEST_F(DesktopWindowTreeHostLinuxTest, Deactivate) {
- // TODO(1109112): enable this test.
- if (features::IsUsingOzonePlatform())
- GTEST_SKIP();
std::unique_ptr<Widget> widget(CreateWidget(gfx::Rect(100, 100, 100, 100)));
ActivationWaiter waiter(static_cast<x11::Window>(
@@ -538,9 +534,6 @@ TEST_F(DesktopWindowTreeHostLinuxTest, Deactivate) {
// Chrome synchronously switches the window that mouse events are forwarded to
// when capture is changed.
TEST_F(DesktopWindowTreeHostLinuxTest, CaptureEventForwarding) {
- // TODO(1109112): enable this test.
- if (features::IsUsingOzonePlatform())
- GTEST_SKIP();
std::unique_ptr<Widget> widget1(CreateWidget(gfx::Rect(100, 100, 100, 100)));
aura::Window* window1 = widget1->GetNativeWindow();
DesktopWindowTreeHostLinux* host1 =
@@ -615,9 +608,6 @@ TEST_F(DesktopWindowTreeHostLinuxTest, CaptureEventForwarding) {
}
TEST_F(DesktopWindowTreeHostLinuxTest, InputMethodFocus) {
- // TODO(1109112): enable this test.
- if (features::IsUsingOzonePlatform())
- GTEST_SKIP();
std::unique_ptr<Widget> widget(CreateWidget(gfx::Rect(100, 100, 100, 100)));
// Waiter should be created as early as possible so that PropertyNotify has
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 6a1fcf7fe75..beb8c975f0f 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
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/focus_client.h"
@@ -27,6 +28,7 @@
#include "ui/views/corewm/tooltip_aura.h"
#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/window_shape_updater.h"
#include "ui/views/widget/widget_aura_utils.h"
#include "ui/views/window/native_frame_view.h"
#include "ui/wm/core/window_util.h"
@@ -88,6 +90,20 @@ ui::PlatformWindowType GetPlatformWindowType(
return ui::PlatformWindowType::kPopup;
}
+ui::PlatformWindowShadowType GetPlatformWindowShadowType(
+ Widget::InitParams::ShadowType shadow_type) {
+ switch (shadow_type) {
+ case Widget::InitParams::ShadowType::kDefault:
+ return ui::PlatformWindowShadowType::kDefault;
+ case Widget::InitParams::ShadowType::kNone:
+ return ui::PlatformWindowShadowType::kNone;
+ case Widget::InitParams::ShadowType::kDrop:
+ return ui::PlatformWindowShadowType::kDrop;
+ }
+ NOTREACHED();
+ return ui::PlatformWindowShadowType::kNone;
+}
+
ui::PlatformWindowInitProperties ConvertWidgetInitParamsToInitProperties(
const Widget::InitParams& params) {
ui::PlatformWindowInitProperties properties;
@@ -101,6 +117,7 @@ ui::PlatformWindowInitProperties ConvertWidgetInitParamsToInitProperties(
properties.remove_standard_frame = params.remove_standard_frame;
properties.workspace = params.workspace;
properties.opacity = GetPlatformWindowOpacity(params.opacity);
+ properties.shadow_type = GetPlatformWindowShadowType(params.shadow_type);
if (params.parent && params.parent->GetHost())
properties.parent_widget = params.parent->GetHost()->GetAcceleratedWidget();
@@ -198,7 +215,15 @@ void DesktopWindowTreeHostPlatform::OnNativeWidgetCreated(
native_widget_delegate_->OnNativeWidgetCreated();
}
-void DesktopWindowTreeHostPlatform::OnWidgetInitDone() {}
+void DesktopWindowTreeHostPlatform::OnWidgetInitDone() {
+ // WindowShape is updated from ShapeRects transformed from
+ // NonClientView::GetWindowMask. We can guarantee that |NonClientView|
+ // is created OnWidgetInitDone.
+ if (ShouldUseLayerForShapedWindow()) {
+ WindowShapeUpdater::CreateWindowShapeUpdater(
+ this, this->desktop_native_widget_aura());
+ }
+}
void DesktopWindowTreeHostPlatform::OnActiveWindowChanged(bool active) {}
@@ -208,12 +233,10 @@ DesktopWindowTreeHostPlatform::CreateTooltip() {
}
std::unique_ptr<aura::client::DragDropClient>
-DesktopWindowTreeHostPlatform::CreateDragDropClient(
- DesktopNativeCursorManager* cursor_manager) {
+DesktopWindowTreeHostPlatform::CreateDragDropClient() {
ui::WmDragHandler* drag_handler = ui::GetWmDragHandler(*(platform_window()));
std::unique_ptr<DesktopDragDropClientOzone> drag_drop_client =
- std::make_unique<DesktopDragDropClientOzone>(window(), cursor_manager,
- drag_handler);
+ std::make_unique<DesktopDragDropClientOzone>(window(), drag_handler);
// Set a class property key, which allows |drag_drop_client| to be used for
// drop action.
SetWmDropHandler(platform_window(), drag_drop_client.get());
@@ -436,6 +459,8 @@ gfx::Rect DesktopWindowTreeHostPlatform::GetWorkAreaBoundsInScreen() const {
void DesktopWindowTreeHostPlatform::SetShape(
std::unique_ptr<Widget::ShapeRects> native_shape) {
+ // TODO(crbug.com/1158733) : When supporting PlatformWindow::SetShape,
+ // Calls ui::Layer::SetAlphaShape and sets |is_shape_explicitly_set_| to true.
platform_window()->SetShape(std::move(native_shape), GetRootTransform());
}
@@ -558,7 +583,8 @@ bool DesktopWindowTreeHostPlatform::ShouldUseNativeFrame() const {
}
bool DesktopWindowTreeHostPlatform::ShouldWindowContentsBeTransparent() const {
- return platform_window()->ShouldWindowContentsBeTransparent();
+ return platform_window()->ShouldWindowContentsBeTransparent() ||
+ ShouldUseLayerForShapedWindow();
}
void DesktopWindowTreeHostPlatform::FrameTypeChanged() {
@@ -583,7 +609,10 @@ void DesktopWindowTreeHostPlatform::SetFullscreen(bool fullscreen) {
if (IsFullscreen() == fullscreen)
return;
+ auto weak_ptr = GetWeakPtr();
platform_window()->ToggleFullscreen();
+ if (!weak_ptr)
+ return;
// The state must change synchronously to let media react on fullscreen
// changes.
@@ -655,7 +684,7 @@ gfx::Transform DesktopWindowTreeHostPlatform::GetRootTransform() const {
// This might be called before the |platform_window| is created. Thus,
// explicitly check if that exists before trying to access its visibility and
// the display where it is shown.
- if (platform_window() && IsVisible()) {
+ if (platform_window()) {
display = display::Screen::GetScreen()->GetDisplayNearestWindow(
GetWidget()->GetNativeWindow());
}
@@ -738,6 +767,21 @@ DesktopWindowTreeHostPlatform::GetMaximumSizeForWindow() {
.size();
}
+SkPath DesktopWindowTreeHostPlatform::GetWindowMaskForWindowShapeInPixels() {
+ if (!GetWidget()->non_client_view())
+ return SkPath();
+
+ SkPath window_mask;
+ // Some frame views define a custom (non-rectanguar) window mask.
+ // If so, use it to define the window shape. If not, fall through.
+ GetWidget()->non_client_view()->GetWindowMask(
+ GetWindowBoundsInScreen().size(), &window_mask);
+ // Convert SkPath in DIPs to pixels.
+ if (!window_mask.isEmpty())
+ window_mask.transform(SkMatrix(GetRootTransform().matrix()));
+ return window_mask;
+}
+
void DesktopWindowTreeHostPlatform::OnWorkspaceChanged() {
OnHostWorkspaceChanged();
}
@@ -787,6 +831,10 @@ void DesktopWindowTreeHostPlatform::AddAdditionalInitProperties(
const Widget::InitParams& params,
ui::PlatformWindowInitProperties* properties) {}
+bool DesktopWindowTreeHostPlatform::ShouldUseLayerForShapedWindow() const {
+ return platform_window()->ShouldUseLayerForShapedWindow();
+}
+
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHost:
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
index 8db9bca8f17..3ceb234664d 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
@@ -42,14 +42,15 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
aura::Window* GetContentWindow();
const aura::Window* GetContentWindow() const;
+ bool is_shape_explicitly_set() const { return is_shape_explicitly_set_; }
+
// DesktopWindowTreeHost:
void Init(const Widget::InitParams& params) override;
void OnNativeWidgetCreated(const Widget::InitParams& params) override;
void OnWidgetInitDone() override;
void OnActiveWindowChanged(bool active) override;
std::unique_ptr<corewm::Tooltip> CreateTooltip() override;
- std::unique_ptr<aura::client::DragDropClient> CreateDragDropClient(
- DesktopNativeCursorManager* cursor_manager) override;
+ std::unique_ptr<aura::client::DragDropClient> CreateDragDropClient() override;
void Close() override;
void CloseNow() override;
aura::WindowTreeHost* AsWindowTreeHost() override;
@@ -121,6 +122,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
void OnActivationChanged(bool active) override;
base::Optional<gfx::Size> GetMinimumSizeForWindow() override;
base::Optional<gfx::Size> GetMaximumSizeForWindow() override;
+ SkPath GetWindowMaskForWindowShapeInPixels() override;
// ui::WorkspaceExtensionDelegate:
void OnWorkspaceChanged() override;
@@ -135,6 +137,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
return desktop_native_widget_aura_;
}
+ ui::PlatformWindowState window_show_state() { return old_state_; }
+
// These are not general purpose methods and must be used with care. Please
// make sure you understand the rounding direction before using.
gfx::Rect ToDIPRect(const gfx::Rect& rect_in_pixels) const;
@@ -154,6 +158,10 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
const Widget::InitParams& params,
ui::PlatformWindowInitProperties* properties);
+ // Returns true if WindowShapeUpdater should update the window shape by
+ // window mask, otherwise false when window shape is already updated in views.
+ virtual bool ShouldUseLayerForShapedWindow() const;
+
internal::NativeWidgetDelegate* const native_widget_delegate_;
DesktopNativeWidgetAura* const desktop_native_widget_aura_;
@@ -174,6 +182,10 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
// Used for tab dragging in move loop requests.
WindowMoveClientPlatform window_move_client_;
+ // ui::Layer::SetAlphaShape can be set from either SetShape or default window
+ // mask. When explicitly setting from SetShape, |explicitly_set_shape_:true|.
+ bool is_shape_explicitly_set_ = false;
+
base::WeakPtrFactory<DesktopWindowTreeHostPlatform> close_widget_factory_{
this};
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
index c9119b8606c..6d431251754 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
@@ -7,7 +7,12 @@
#include <memory>
#include <utility>
+#include "base/command_line.h"
#include "base/run_loop.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/aura/window_tree_host_observer.h"
+#include "ui/display/display_switches.h"
+#include "ui/platform_window/platform_window.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/widget_observer.h"
@@ -165,6 +170,35 @@ TEST_F(DesktopWindowTreeHostPlatformTest,
EXPECT_TRUE(widget->GetNativeWindow()->IsVisible());
}
+// Tests that the window shape is updated from the
+// |NonClientView::GetWindowMask|.
+TEST_F(DesktopWindowTreeHostPlatformTest, UpdateWindowShapeFromWindowMask) {
+ std::unique_ptr<Widget> widget = CreateWidgetWithNativeWidget();
+ widget->Show();
+
+ auto* host_platform = DesktopWindowTreeHostPlatform::GetHostForWidget(
+ widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+ ASSERT_TRUE(host_platform);
+ if (!host_platform->platform_window()->ShouldUseLayerForShapedWindow())
+ return;
+
+ auto* content_window =
+ DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
+ widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+ ASSERT_TRUE(content_window);
+ // alpha_shape for the layer of content window is updated from the
+ // |NonClientView::GetWindowMask|.
+ EXPECT_FALSE(host_platform->GetWindowMaskForWindowShapeInPixels().isEmpty());
+ EXPECT_TRUE(content_window->layer()->alpha_shape());
+
+ // When fullscreen mode, alpha_shape is set to empty since there is no
+ // |NonClientView::GetWindowMask|.
+ host_platform->SetFullscreen(true);
+ widget->SetBounds(gfx::Rect(800, 800));
+ EXPECT_TRUE(host_platform->GetWindowMaskForWindowShapeInPixels().isEmpty());
+ EXPECT_FALSE(content_window->layer()->alpha_shape());
+}
+
// A Widget that allows setting the min/max size for the widget.
class CustomSizeWidget : public Widget {
public:
@@ -207,4 +241,107 @@ TEST_F(DesktopWindowTreeHostPlatformTest, SetBoundsWithMinMax) {
widget.GetWindowBoundsInScreen().size().ToString());
}
+class ResizeObserver : public aura::WindowTreeHostObserver {
+ public:
+ explicit ResizeObserver(aura::WindowTreeHost* host) : host_(host) {
+ host_->AddObserver(this);
+ }
+ ResizeObserver(const ResizeObserver&) = delete;
+ ResizeObserver& operator=(const ResizeObserver&) = delete;
+ ~ResizeObserver() override { host_->RemoveObserver(this); }
+
+ int bounds_change_count() const { return bounds_change_count_; }
+ int resize_count() const { return resize_count_; }
+
+ // aura::WindowTreeHostObserver:
+ void OnHostResized(aura::WindowTreeHost* host) override { resize_count_++; }
+ void OnHostWillProcessBoundsChange(aura::WindowTreeHost* host) override {
+ bounds_change_count_++;
+ }
+
+ private:
+ aura::WindowTreeHost* const host_;
+ int resize_count_ = 0;
+ int bounds_change_count_ = 0;
+};
+
+// Verifies that setting widget bounds, just after creating it, with the same
+// size passed in InitParams does not lead to a "bounds change" event. Prevents
+// regressions, such as https://crbug.com/1151092.
+TEST_F(DesktopWindowTreeHostPlatformTest, SetBoundsWithUnchangedSize) {
+ auto widget = CreateWidgetWithNativeWidget();
+ widget->Show();
+
+ EXPECT_EQ(gfx::Size(100, 100), widget->GetWindowBoundsInScreen().size());
+ auto* host = widget->GetNativeWindow()->GetHost();
+ ResizeObserver observer(host);
+
+ auto* dwth_platform = DesktopWindowTreeHostPlatform::GetHostForWidget(
+ widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+ ASSERT_TRUE(dwth_platform);
+
+ // Check with different origin.
+ dwth_platform->SetBoundsInPixels(gfx::Rect(2, 2, 100, 100));
+ EXPECT_EQ(1, observer.bounds_change_count());
+ EXPECT_EQ(0, observer.resize_count());
+}
+
+class DesktopWindowTreeHostPlatformHighDPITest
+ : public DesktopWindowTreeHostPlatformTest {
+ public:
+ DesktopWindowTreeHostPlatformHighDPITest() = default;
+ ~DesktopWindowTreeHostPlatformHighDPITest() override = default;
+
+ private:
+ void SetUp() override {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "2");
+
+ DesktopWindowTreeHostPlatformTest::SetUp();
+ }
+};
+
+// Tests that the window shape is updated properly from the
+// |NonClientView::GetWindowMask| in HighDPI.
+TEST_F(DesktopWindowTreeHostPlatformHighDPITest, VerifyWindowShapeInHighDPI) {
+ std::unique_ptr<Widget> widget = CreateWidgetWithNativeWidget();
+ widget->Show();
+
+ auto* host_platform = DesktopWindowTreeHostPlatform::GetHostForWidget(
+ widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+ ASSERT_TRUE(host_platform);
+ if (!host_platform->platform_window()->ShouldUseLayerForShapedWindow())
+ return;
+
+ auto* content_window =
+ DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
+ widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+ ASSERT_TRUE(content_window);
+ // Check device scale factor.
+ EXPECT_EQ(host_platform->device_scale_factor(), 2.0);
+
+ // alpha_shape for the layer of content window is updated from the
+ // |NonClientView::GetWindowMask|.
+ SkPath path_in_pixels = host_platform->GetWindowMaskForWindowShapeInPixels();
+ EXPECT_FALSE(path_in_pixels.isEmpty());
+
+ // Converts path to DIPs and calculates expected region from it.
+ SkPath path_in_dips;
+ path_in_pixels.transform(
+ SkMatrix(host_platform->GetInverseRootTransform().matrix()),
+ &path_in_dips);
+ SkRegion region;
+ region.setRect(path_in_dips.getBounds().round());
+ SkRegion expected_region;
+ expected_region.setPath(path_in_dips, region);
+
+ SkRegion shape_region;
+ for (auto& bound : *(content_window->layer()->alpha_shape()))
+ shape_region.op(gfx::RectToSkIRect(bound), SkRegion::Op::kUnion_Op);
+
+ // Test that region from alpha_shape is same as the expected region from path
+ // in DIPs.
+ EXPECT_EQ(shape_region, expected_region);
+}
+
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
index 3b132d4d761..e0875040c63 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
@@ -22,7 +22,7 @@
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/class_property.h"
-#include "ui/base/cursor/cursor_loader_win.h"
+#include "ui/base/cursor/win/win_cursor.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/win/event_creation_utils.h"
@@ -189,8 +189,7 @@ std::unique_ptr<corewm::Tooltip> DesktopWindowTreeHostWin::CreateTooltip() {
}
std::unique_ptr<aura::client::DragDropClient>
-DesktopWindowTreeHostWin::CreateDragDropClient(
- DesktopNativeCursorManager* cursor_manager) {
+DesktopWindowTreeHostWin::CreateDragDropClient() {
drag_drop_client_ = new DesktopDragDropClientWin(window(), GetHWND(), this);
return base::WrapUnique(drag_drop_client_);
}
@@ -421,7 +420,7 @@ Widget::MoveLoopResult DesktopWindowTreeHostWin::RunMoveLoop(
Widget::MoveLoopSource source,
Widget::MoveLoopEscapeBehavior escape_behavior) {
const bool hide_on_escape =
- escape_behavior == Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE;
+ escape_behavior == Widget::MoveLoopEscapeBehavior::kHide;
return message_handler_->RunMoveLoop(drag_offset, hide_on_escape)
? Widget::MOVE_LOOP_SUCCESSFUL
: Widget::MOVE_LOOP_CANCELED;
@@ -463,7 +462,10 @@ void DesktopWindowTreeHostWin::FrameTypeChanged() {
}
void DesktopWindowTreeHostWin::SetFullscreen(bool fullscreen) {
+ auto weak_ptr = GetWeakPtr();
message_handler_->SetFullscreen(fullscreen);
+ if (!weak_ptr)
+ return;
// TODO(sky): workaround for ScopedFullscreenVisibility showing window
// directly. Instead of this should listen for visibility changes and then
// update window.
@@ -632,10 +634,11 @@ DesktopWindowTreeHostWin::GetKeyboardLayoutMap() {
void DesktopWindowTreeHostWin::SetCursorNative(gfx::NativeCursor cursor) {
TRACE_EVENT1("ui,input", "DesktopWindowTreeHostWin::SetCursorNative",
"cursor", cursor.type());
- ui::CursorLoaderWin cursor_loader;
- cursor_loader.SetPlatformCursor(&cursor);
- message_handler_->SetCursor(cursor.platform());
+ ui::WinCursor* platform_cursor =
+ static_cast<ui::WinCursor*>(cursor.platform());
+ DCHECK(platform_cursor);
+ message_handler_->SetCursor(platform_cursor->hcursor());
}
void DesktopWindowTreeHostWin::OnCursorVisibilityChangedNative(bool show) {
@@ -747,7 +750,17 @@ int DesktopWindowTreeHostWin::GetNonClientComponent(
void DesktopWindowTreeHostWin::GetWindowMask(const gfx::Size& size,
SkPath* path) {
if (GetWidget()->non_client_view()) {
- GetWidget()->non_client_view()->GetWindowMask(size, path);
+ GetWidget()->non_client_view()->GetWindowMask(
+ display::win::ScreenWin::ScreenToDIPSize(GetHWND(), size), path);
+ // Convert path in DIPs to pixels.
+ if (!path->isEmpty()) {
+ const float scale =
+ display::win::ScreenWin::GetScaleFactorForHWND(GetHWND());
+ SkScalar sk_scale = SkFloatToScalar(scale);
+ SkMatrix matrix;
+ matrix.setScale(sk_scale, sk_scale);
+ path->transform(matrix);
+ }
} else if (!window_enlargement_.IsZero()) {
gfx::Rect bounds(WidgetSizeIsClientSize()
? message_handler_->GetClientAreaBoundsInScreen()
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 0229c1c4150..ed3b2fe4866 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
@@ -72,8 +72,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
void OnActiveWindowChanged(bool active) override;
void OnWidgetInitDone() override;
std::unique_ptr<corewm::Tooltip> CreateTooltip() override;
- std::unique_ptr<aura::client::DragDropClient> CreateDragDropClient(
- DesktopNativeCursorManager* cursor_manager) override;
+ std::unique_ptr<aura::client::DragDropClient> CreateDragDropClient() override;
void Close() override;
void CloseNow() override;
aura::WindowTreeHost* AsWindowTreeHost() override;
diff --git a/chromium/ui/views/widget/desktop_aura/window_move_client_platform.cc b/chromium/ui/views/widget/desktop_aura/window_move_client_platform.cc
index d561307dbca..252c8d2e807 100644
--- a/chromium/ui/views/widget/desktop_aura/window_move_client_platform.cc
+++ b/chromium/ui/views/widget/desktop_aura/window_move_client_platform.cc
@@ -24,7 +24,7 @@ wm::WindowMoveResult WindowMoveClientPlatform::RunMoveLoop(
move_source == wm::WindowMoveSource::WINDOW_MOVE_SOURCE_MOUSE
? Widget::MoveLoopSource::kMouse
: Widget::MoveLoopSource::kTouch,
- Widget::MoveLoopEscapeBehavior::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE);
+ Widget::MoveLoopEscapeBehavior::kHide);
return move_loop_result == Widget::MOVE_LOOP_SUCCESSFUL ? wm::MOVE_SUCCESSFUL
: wm::MOVE_CANCELED;
diff --git a/chromium/ui/views/widget/desktop_aura/window_shape_updater.cc b/chromium/ui/views/widget/desktop_aura/window_shape_updater.cc
new file mode 100644
index 00000000000..5c145331ef0
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/window_shape_updater.cc
@@ -0,0 +1,80 @@
+// Copyright 2021 The Chromium 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/window_shape_updater.h"
+
+#include "ui/gfx/skia_util.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
+
+namespace {
+
+std::unique_ptr<ui::Layer::ShapeRects> ConvertToShapeRects(const SkPath& path) {
+ // Converts to ShapeRects from SkPath.
+ auto shape_rects = std::make_unique<ui::Layer::ShapeRects>();
+ SkRegion clip_region;
+ clip_region.setRect(path.getBounds().round());
+ SkRegion region;
+ region.setPath(path, clip_region);
+ for (SkRegion::Iterator it(region); !it.done(); it.next())
+ shape_rects->push_back(gfx::SkIRectToRect(it.rect()));
+ return shape_rects;
+}
+
+} // namespace
+
+namespace views {
+
+// static
+WindowShapeUpdater* WindowShapeUpdater::CreateWindowShapeUpdater(
+ DesktopWindowTreeHostPlatform* tree_host,
+ DesktopNativeWidgetAura* native_widget_aura) {
+ return new WindowShapeUpdater(tree_host, native_widget_aura);
+}
+
+WindowShapeUpdater::WindowShapeUpdater(
+ DesktopWindowTreeHostPlatform* tree_host,
+ DesktopNativeWidgetAura* native_widget_aura)
+ : tree_host_(tree_host), native_widget_aura_(native_widget_aura) {
+ tree_host_->GetContentWindow()->AddObserver(this);
+ UpdateWindowShapeFromWindowMask(tree_host_->GetContentWindow());
+}
+
+void WindowShapeUpdater::OnWindowBoundsChanged(
+ aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ ui::PropertyChangeReason reason) {
+ UpdateWindowShapeFromWindowMask(window);
+}
+
+void WindowShapeUpdater::OnWindowDestroying(aura::Window* window) {
+ window->RemoveObserver(this);
+ delete this;
+}
+
+void WindowShapeUpdater::UpdateWindowShapeFromWindowMask(aura::Window* window) {
+ // If |ui::Layer::alpha_shape_| is set explicitly from SetShape,
+ // we don't need to set default window mask from non_client_view.
+ if (tree_host_->is_shape_explicitly_set())
+ return;
+ // WindowTransparency should be updated as well when the window shape is
+ // changed. When a window mask exists, transparent should be true to prevent
+ // compositor from filling the entire screen in AppendQuadsToFillScreen.
+ // Otherwise, transparent should be false.
+ native_widget_aura_->UpdateWindowTransparency();
+ SkPath path = tree_host_->GetWindowMaskForWindowShapeInPixels();
+ if (path.isEmpty()) {
+ window->layer()->SetAlphaShape(nullptr);
+ return;
+ }
+ SkPath path_in_dips;
+ path.transform(SkMatrix(tree_host_->GetInverseRootTransform().matrix()),
+ &path_in_dips);
+
+ // SetAlphaShape to the layer of |content_window_|
+ window->layer()->SetAlphaShape(ConvertToShapeRects(path_in_dips));
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/window_shape_updater.h b/chromium/ui/views/widget/desktop_aura/window_shape_updater.h
new file mode 100644
index 00000000000..ec773625273
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/window_shape_updater.h
@@ -0,0 +1,49 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_WINDOW_SHAPE_UPDATER_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_WINDOW_SHAPE_UPDATER_H_
+
+#include <memory>
+
+#include "ui/aura/window_observer.h"
+#include "ui/compositor/layer.h"
+
+namespace views {
+
+class DesktopNativeWidgetAura;
+class DesktopWindowTreeHostPlatform;
+
+// Class to observe the window bounds changed to update window shape
+// for the rounded corner of the browser frame.
+class WindowShapeUpdater : public aura::WindowObserver {
+ public:
+ static WindowShapeUpdater* CreateWindowShapeUpdater(
+ DesktopWindowTreeHostPlatform* tree_host,
+ DesktopNativeWidgetAura* native_widget_aura);
+
+ private:
+ WindowShapeUpdater(DesktopWindowTreeHostPlatform* tree_host,
+ DesktopNativeWidgetAura* native_widget_aura);
+ WindowShapeUpdater(const WindowShapeUpdater&) = delete;
+ WindowShapeUpdater& operator=(const WindowShapeUpdater&) = delete;
+ ~WindowShapeUpdater() override = default;
+
+ // aura::WindowObserver:
+ void OnWindowBoundsChanged(aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ ui::PropertyChangeReason reason) override;
+
+ void OnWindowDestroying(aura::Window* window) override;
+
+ void UpdateWindowShapeFromWindowMask(aura::Window* window);
+
+ DesktopWindowTreeHostPlatform* tree_host_ = nullptr;
+ DesktopNativeWidgetAura* native_widget_aura_ = nullptr;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_WINDOW_SHAPE_UPDATER_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_drag_drop_client_unittest.cc b/chromium/ui/views/widget/desktop_aura/x11_drag_drop_client_unittest.cc
index 7836638956f..dfa4f342e36 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_drag_drop_client_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_drag_drop_client_unittest.cc
@@ -22,6 +22,9 @@
#include "ui/aura/test/test_screen.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/cursor/cursor_loader.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/x/x11_cursor.h"
@@ -32,6 +35,7 @@
#include "ui/events/event_utils.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_util.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
@@ -104,8 +108,7 @@ class SimpleTestDragDropClient : public aura::client::DragDropClient,
public ui::XDragDropClient::Delegate,
public ui::X11MoveLoopDelegate {
public:
- SimpleTestDragDropClient(aura::Window*,
- DesktopNativeCursorManager* cursor_manager);
+ explicit SimpleTestDragDropClient(aura::Window*);
~SimpleTestDragDropClient() override;
// Sets |window| as the topmost window for all mouse positions.
@@ -171,8 +174,7 @@ class TestDragDropClient : public SimpleTestDragDropClient {
static constexpr int kMouseMoveX = 100;
static constexpr int kMouseMoveY = 200;
- TestDragDropClient(aura::Window* window,
- DesktopNativeCursorManager* cursor_manager);
+ explicit TestDragDropClient(aura::Window* window);
~TestDragDropClient() override;
// Returns the x11::Window of the window which initiated the drag.
@@ -281,9 +283,7 @@ void TestMoveLoop::EndMoveLoop() {
///////////////////////////////////////////////////////////////////////////////
// SimpleTestDragDropClient
-SimpleTestDragDropClient::SimpleTestDragDropClient(
- aura::Window* window,
- DesktopNativeCursorManager* cursor_manager)
+SimpleTestDragDropClient::SimpleTestDragDropClient(aura::Window* window)
: ui::XDragDropClient(
this,
static_cast<x11::Window>(window->GetHost()->GetAcceleratedWidget())) {
@@ -319,15 +319,13 @@ int SimpleTestDragDropClient::StartDragAndDrop(
// Windows has a specific method, DoDragDrop(), which performs the entire
// drag. We have to emulate this, so we spin off a nested runloop which will
// track all cursor movement and reroute events to a specific handler.
- auto cursor_manager_ = std::make_unique<DesktopNativeCursorManager>();
+ ui::CursorLoader cursor_loader;
+ ui::Cursor grabbing = ui::mojom::CursorType::kGrabbing;
+ cursor_loader.SetPlatformCursor(&grabbing);
auto* last_cursor = static_cast<ui::X11Cursor*>(
source_window->GetHost()->last_cursor().platform());
- loop_->RunMoveLoop(
- !source_window->HasCapture(), last_cursor,
- static_cast<ui::X11Cursor*>(
- cursor_manager_
- ->GetInitializedCursor(ui::mojom::CursorType::kGrabbing)
- .platform()));
+ loop_->RunMoveLoop(!source_window->HasCapture(), last_cursor,
+ static_cast<ui::X11Cursor*>(grabbing.platform()));
auto resulting_operation = negotiated_operation();
CleanupDrag();
@@ -386,10 +384,8 @@ void SimpleTestDragDropClient::OnMoveLoopEnded() {
///////////////////////////////////////////////////////////////////////////////
// TestDragDropClient
-TestDragDropClient::TestDragDropClient(
- aura::Window* window,
- DesktopNativeCursorManager* cursor_manager)
- : SimpleTestDragDropClient(window, cursor_manager),
+TestDragDropClient::TestDragDropClient(aura::Window* window)
+ : SimpleTestDragDropClient(window),
source_window_(
static_cast<x11::Window>(window->GetHost()->GetAcceleratedWidget())) {
}
@@ -397,7 +393,7 @@ TestDragDropClient::TestDragDropClient(
TestDragDropClient::~TestDragDropClient() = default;
x11::Atom TestDragDropClient::GetAtom(const char* name) {
- return gfx::GetAtom(name);
+ return x11::GetAtom(name);
}
bool TestDragDropClient::MessageHasType(const x11::ClientMessageEvent& event,
@@ -497,16 +493,12 @@ class X11DragDropClientTest : public ViewsTestBase {
widget_->Init(std::move(params));
widget_->Show();
- cursor_manager_ = std::make_unique<DesktopNativeCursorManager>();
-
- client_ = std::make_unique<TestDragDropClient>(widget_->GetNativeWindow(),
- cursor_manager_.get());
+ client_ = std::make_unique<TestDragDropClient>(widget_->GetNativeWindow());
// client_->Init();
}
void TearDown() override {
client_.reset();
- cursor_manager_.reset();
widget_.reset();
ViewsTestBase::TearDown();
}
@@ -515,7 +507,6 @@ class X11DragDropClientTest : public ViewsTestBase {
private:
std::unique_ptr<TestDragDropClient> client_;
- std::unique_ptr<DesktopNativeCursorManager> cursor_manager_;
// The widget used to initiate drags.
std::unique_ptr<Widget> widget_;
@@ -541,7 +532,8 @@ void BasicStep2(TestDragDropClient* client, x11::Window toplevel) {
static_cast<x11::Window>(events[0].data.data32[0]));
EXPECT_EQ(1u, events[0].data.data32[1] & 1);
std::vector<x11::Atom> targets;
- ui::GetAtomArrayProperty(client->source_xwindow(), "XdndTypeList", &targets);
+ GetArrayProperty(client->source_xwindow(), x11::GetAtom("XdndTypeList"),
+ &targets);
EXPECT_FALSE(targets.empty());
EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
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 12f95a35876..6263432ab40 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,14 +10,13 @@
#include <memory>
#include <vector>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "build/build_config.h"
#include "third_party/skia/include/core/SkRect.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/x/test/x11_property_change_waiter.h"
#include "ui/base/x/x11_util.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
@@ -25,6 +24,7 @@
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_path.h"
#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_util.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
@@ -49,10 +49,11 @@ class MinimizeWaiter : public ui::X11PropertyChangeWaiter {
private:
// ui::X11PropertyChangeWaiter:
- bool ShouldKeepOnWaiting(x11::Event* event) override {
+ bool ShouldKeepOnWaiting() override {
std::vector<x11::Atom> wm_states;
- if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &wm_states)) {
- return !base::Contains(wm_states, gfx::GetAtom("_NET_WM_STATE_HIDDEN"));
+ if (GetArrayProperty(xwindow(), x11::GetAtom("_NET_WM_STATE"),
+ &wm_states)) {
+ return !base::Contains(wm_states, x11::GetAtom("_NET_WM_STATE_HIDDEN"));
}
return true;
}
@@ -75,7 +76,7 @@ class StackingClientListWaiter : public ui::X11PropertyChangeWaiter {
void Wait() override {
// StackingClientListWaiter may be created after
// _NET_CLIENT_LIST_STACKING already contains |expected_windows|.
- if (!ShouldKeepOnWaiting(nullptr))
+ if (!ShouldKeepOnWaiting())
return;
ui::X11PropertyChangeWaiter::Wait();
@@ -83,7 +84,7 @@ class StackingClientListWaiter : public ui::X11PropertyChangeWaiter {
private:
// ui::X11PropertyChangeWaiter:
- bool ShouldKeepOnWaiting(x11::Event* event) override {
+ bool ShouldKeepOnWaiting() override {
std::vector<x11::Window> stack;
ui::GetXWindowStack(ui::GetX11RootWindow(), &stack);
return !std::all_of(
@@ -98,7 +99,7 @@ class StackingClientListWaiter : public ui::X11PropertyChangeWaiter {
void IconifyWindow(x11::Connection* connection, x11::Window window) {
ui::SendClientMessage(window, ui::GetX11RootWindow(),
- gfx::GetAtom("WM_CHANGE_STATE"),
+ x11::GetAtom("WM_CHANGE_STATE"),
{ui::WM_STATE_ICONIC, 0, 0, 0, 0});
}
@@ -114,8 +115,7 @@ class X11TopmostWindowFinderTest : public test::DesktopWidgetTestInteractive {
#if defined(USE_OZONE)
// Run tests only for X11 (ozone or not Ozone).
if (features::IsUsingOzonePlatform() &&
- std::strcmp(ui::OzonePlatform::GetInstance()->GetPlatformName(),
- "x11") != 0) {
+ ui::OzonePlatform::GetPlatformNameForTest() != "x11") {
// SetUp still is required to be run. Otherwise, ViewsTestBase CHECKs in
// the dtor.
DesktopWidgetTestInteractive::SetUp();
@@ -241,7 +241,7 @@ TEST_F(X11TopmostWindowFinderTest, Basic) {
x11::Window windows[] = {x11_window1, x11_window2, x11_window3};
StackingClientListWaiter waiter(windows, base::size(windows));
waiter.Wait();
- ui::X11EventSource::GetInstance()->DispatchXEvents();
+ connection()->DispatchAll();
EXPECT_EQ(x11_window1, FindTopmostXWindowAt(150, 150));
EXPECT_EQ(window1, FindTopmostLocalProcessWindowAt(150, 150));
@@ -285,7 +285,7 @@ TEST_F(X11TopmostWindowFinderTest, Minimized) {
x11::Window windows[] = {x11_window1, x11_window2};
StackingClientListWaiter stack_waiter(windows, base::size(windows));
stack_waiter.Wait();
- ui::X11EventSource::GetInstance()->DispatchXEvents();
+ connection()->DispatchAll();
EXPECT_EQ(x11_window1, FindTopmostXWindowAt(150, 150));
{
@@ -328,7 +328,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangular) {
skregion2.op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op);
skregion2.op(SkIRect::MakeXYWH(10, 0, 90, 100), SkRegion::kUnion_Op);
x11::Window window2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100));
- auto region2 = gfx::CreateRegionFromSkRegion(skregion2);
+ auto region2 = x11::CreateRegionFromSkRegion(skregion2);
x11::Connection::Get()->shape().Rectangles({
.operation = x11::Shape::So::Set,
.destination_kind = x11::Shape::Sk::Bounding,
@@ -339,7 +339,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangular) {
x11::Window windows[] = {window1, window2};
StackingClientListWaiter stack_waiter(windows, base::size(windows));
stack_waiter.Wait();
- ui::X11EventSource::GetInstance()->DispatchXEvents();
+ connection()->DispatchAll();
EXPECT_EQ(window1, FindTopmostXWindowAt(105, 120));
EXPECT_NE(window1, FindTopmostXWindowAt(105, 105));
@@ -371,7 +371,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularEmptyShape) {
x11::Window windows[] = {window1};
StackingClientListWaiter stack_waiter(windows, base::size(windows));
stack_waiter.Wait();
- ui::X11EventSource::GetInstance()->DispatchXEvents();
+ connection()->DispatchAll();
EXPECT_NE(window1, FindTopmostXWindowAt(105, 105));
}
@@ -401,7 +401,7 @@ TEST_F(X11TopmostWindowFinderTest, MAYBE_NonRectangularNullShape) {
x11::Window windows[] = {window1};
StackingClientListWaiter stack_waiter(windows, base::size(windows));
stack_waiter.Wait();
- ui::X11EventSource::GetInstance()->DispatchXEvents();
+ connection()->DispatchAll();
EXPECT_EQ(window1, FindTopmostXWindowAt(105, 105));
}
@@ -424,12 +424,12 @@ TEST_F(X11TopmostWindowFinderTest, DISABLED_Menu) {
.override_redirect = x11::Bool32(true),
});
- ui::SetAtomProperty(menu_window, "_NET_WM_WINDOW_TYPE", "ATOM",
- gfx::GetAtom("_NET_WM_WINDOW_TYPE_MENU"));
+ SetProperty(menu_window, x11::GetAtom("_NET_WM_WINDOW_TYPE"), x11::Atom::ATOM,
+ x11::GetAtom("_NET_WM_WINDOW_TYPE_MENU"));
ui::SetUseOSWindowFrame(menu_window, false);
ShowAndSetXWindowBounds(menu_window, gfx::Rect(140, 110, 100, 100));
- ui::X11EventSource::GetInstance()->DispatchXEvents();
+ connection()->DispatchAll();
// |menu_window| is never added to _NET_CLIENT_LIST_STACKING.
x11::Window windows[] = {window};
diff --git a/chromium/ui/views/widget/drop_helper.cc b/chromium/ui/views/widget/drop_helper.cc
index 445cd80b3e4..38d1b129c2c 100644
--- a/chromium/ui/views/widget/drop_helper.cc
+++ b/chromium/ui/views/widget/drop_helper.cc
@@ -10,13 +10,15 @@
#include "base/no_destructor.h"
#include "build/build_config.h"
#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
namespace views {
-
namespace {
+using ::ui::mojom::DragOperation;
+
const View* g_drag_entered_callback_view = nullptr;
base::RepeatingClosure* GetDragEnteredCallback() {
@@ -77,17 +79,17 @@ void DropHelper::OnDragExit() {
deepest_view_ = target_view_ = nullptr;
}
-int DropHelper::OnDrop(const OSExchangeData& data,
- const gfx::Point& root_view_location,
- int drag_operation) {
+DragOperation DropHelper::OnDrop(const OSExchangeData& data,
+ const gfx::Point& root_view_location,
+ int drag_operation) {
View* drop_view = target_view_;
deepest_view_ = target_view_ = nullptr;
if (!drop_view)
- return ui::DragDropTypes::DRAG_NONE;
+ return DragOperation::kNone;
if (drag_operation == ui::DragDropTypes::DRAG_NONE) {
drop_view->OnDragExited();
- return ui::DragDropTypes::DRAG_NONE;
+ return DragOperation::kNone;
}
gfx::Point view_location(root_view_location);
diff --git a/chromium/ui/views/widget/drop_helper.h b/chromium/ui/views/widget/drop_helper.h
index 16c4d585909..f878fd47ad3 100644
--- a/chromium/ui/views/widget/drop_helper.h
+++ b/chromium/ui/views/widget/drop_helper.h
@@ -9,6 +9,7 @@
#include "base/callback_forward.h"
#include "base/macros.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"
#include "ui/views/views_export.h"
namespace gfx {
@@ -68,9 +69,9 @@ class VIEWS_EXPORT DropHelper {
//
// NOTE: implementations must invoke OnDragOver before invoking this,
// supplying the return value from OnDragOver as the drag_operation.
- int OnDrop(const OSExchangeData& data,
- const gfx::Point& root_view_location,
- int drag_operation);
+ ui::mojom::DragOperation OnDrop(const OSExchangeData& data,
+ const gfx::Point& root_view_location,
+ int drag_operation);
// Calculates the target view for a drop given the specified location in
// the coordinate system of the rootview. This tries to avoid continually
diff --git a/chromium/ui/views/widget/focus_manager_event_handler.cc b/chromium/ui/views/widget/focus_manager_event_handler.cc
index f87e4381ce2..97bc2c9ae82 100644
--- a/chromium/ui/views/widget/focus_manager_event_handler.cc
+++ b/chromium/ui/views/widget/focus_manager_event_handler.cc
@@ -28,4 +28,8 @@ void FocusManagerEventHandler::OnKeyEvent(ui::KeyEvent* event) {
}
}
+base::StringPiece FocusManagerEventHandler::GetLogContext() const {
+ return "FocusManagerEventHandler";
+}
+
} // namespace views
diff --git a/chromium/ui/views/widget/focus_manager_event_handler.h b/chromium/ui/views/widget/focus_manager_event_handler.h
index fcba5ac2673..c6a263d00b6 100644
--- a/chromium/ui/views/widget/focus_manager_event_handler.h
+++ b/chromium/ui/views/widget/focus_manager_event_handler.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_WIDGET_FOCUS_MANAGER_EVENT_HANDLER_H_
#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "ui/events/event_handler.h"
namespace aura {
@@ -25,6 +26,7 @@ class FocusManagerEventHandler : public ui::EventHandler {
// Implementation of ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
+ base::StringPiece GetLogContext() const override;
private:
Widget* widget_;
diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc
index 9f5dff1077c..95d47dfdd50 100644
--- a/chromium/ui/views/widget/native_widget_aura.cc
+++ b/chromium/ui/views/widget/native_widget_aura.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
@@ -17,6 +18,7 @@
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/client/window_parenting_client.h"
@@ -27,6 +29,7 @@
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/class_property.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/ui_base_types.h"
#include "ui/compositor/layer.h"
@@ -171,6 +174,19 @@ void NativeWidgetAura::InitNativeWidget(Widget::InitParams params) {
*params.corner_radius);
}
window_->SetProperty(aura::client::kShowStateKey, params.show_state);
+
+ int desk_index;
+ // Set workspace property of this window created with a specified workspace
+ // in InitParams. The desk index can be kActiveWorkspace=-1, representing
+ // an active desk. If the window is visible on all workspaces, it belongs on
+ // the active desk.
+ if (params.visible_on_all_workspaces) {
+ window_->SetProperty(aura::client::kWindowWorkspaceKey,
+ aura::client::kUnassignedWorkspace);
+ } else if (base::StringToInt(params.workspace, &desk_index)) {
+ window_->SetProperty(aura::client::kWindowWorkspaceKey, desk_index);
+ }
+
if (params.type == Widget::InitParams::TYPE_BUBBLE)
wm::SetHideOnDeactivate(window_, true);
window_->SetTransparent(params.opacity ==
@@ -244,6 +260,8 @@ void NativeWidgetAura::InitNativeWidget(Widget::InitParams params) {
SetRestoreBounds(window_, window_bounds);
else
SetBounds(window_bounds);
+ // For similar reasons, wait to set visible on all workspaces.
+ SetVisibleOnAllWorkspaces(params.visible_on_all_workspaces);
window_->SetEventTargetingPolicy(
params.accept_events ? aura::EventTargetingPolicy::kTargetAndDescendants
: aura::EventTargetingPolicy::kNone);
@@ -491,7 +509,10 @@ gfx::Rect NativeWidgetAura::GetRestoredBounds() const {
}
std::string NativeWidgetAura::GetWorkspace() const {
- return std::string();
+ int desk_index = window_->GetProperty(aura::client::kWindowWorkspaceKey);
+ return desk_index == aura::client::kUnassignedWorkspace
+ ? std::string()
+ : base::NumberToString(desk_index);
}
void NativeWidgetAura::SetBounds(const gfx::Rect& bounds) {
@@ -645,11 +666,13 @@ ui::ZOrderLevel NativeWidgetAura::GetZOrderLevel() const {
}
void NativeWidgetAura::SetVisibleOnAllWorkspaces(bool always_visible) {
- // Not implemented on chromeos or for child widgets.
+ window_->SetProperty(aura::client::kVisibleOnAllWorkspacesKey,
+ always_visible);
}
bool NativeWidgetAura::IsVisibleOnAllWorkspaces() const {
- return false;
+ return window_ &&
+ window_->GetProperty(aura::client::kVisibleOnAllWorkspacesKey);
}
void NativeWidgetAura::Maximize() {
@@ -955,6 +978,11 @@ void NativeWidgetAura::OnWindowPropertyChanged(aura::Window* window,
intptr_t old) {
if (key == aura::client::kShowStateKey)
delegate_->OnNativeWidgetWindowShowStateChanged();
+
+ if (key == aura::client::kWindowWorkspaceKey ||
+ key == aura::client::kVisibleOnAllWorkspacesKey) {
+ delegate_->OnNativeWidgetWorkspaceChanged();
+ }
}
void NativeWidgetAura::OnResizeLoopStarted(aura::Window* window) {
@@ -1046,11 +1074,14 @@ void NativeWidgetAura::OnDragEntered(const ui::DropTargetEvent& event) {
event.data(), event.location(), event.source_operations());
}
-int NativeWidgetAura::OnDragUpdated(const ui::DropTargetEvent& event) {
+aura::client::DragUpdateInfo NativeWidgetAura::OnDragUpdated(
+ const ui::DropTargetEvent& event) {
DCHECK(drop_helper_.get() != nullptr);
last_drop_operation_ = drop_helper_->OnDragOver(
event.data(), event.location(), event.source_operations());
- return last_drop_operation_;
+ return aura::client::DragUpdateInfo(
+ last_drop_operation_,
+ ui::DataTransferEndpoint(ui::EndpointType::kDefault));
}
void NativeWidgetAura::OnDragExited() {
@@ -1058,8 +1089,9 @@ void NativeWidgetAura::OnDragExited() {
drop_helper_->OnDragExit();
}
-int NativeWidgetAura::OnPerformDrop(const ui::DropTargetEvent& event,
- std::unique_ptr<ui::OSExchangeData> data) {
+ui::mojom::DragOperation NativeWidgetAura::OnPerformDrop(
+ const ui::DropTargetEvent& event,
+ std::unique_ptr<ui::OSExchangeData> data) {
DCHECK(drop_helper_.get() != nullptr);
return drop_helper_->OnDrop(event.data(), event.location(),
last_drop_operation_);
diff --git a/chromium/ui/views/widget/native_widget_aura.h b/chromium/ui/views/widget/native_widget_aura.h
index d70aa0a5fb8..f8b75b34b17 100644
--- a/chromium/ui/views/widget/native_widget_aura.h
+++ b/chromium/ui/views/widget/native_widget_aura.h
@@ -210,10 +210,12 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate,
// aura::client::DragDropDelegate:
void OnDragEntered(const ui::DropTargetEvent& event) override;
- int OnDragUpdated(const ui::DropTargetEvent& event) override;
+ aura::client::DragUpdateInfo OnDragUpdated(
+ const ui::DropTargetEvent& event) override;
void OnDragExited() override;
- int OnPerformDrop(const ui::DropTargetEvent& event,
- std::unique_ptr<ui::OSExchangeData> data) override;
+ ui::mojom::DragOperation OnPerformDrop(
+ const ui::DropTargetEvent& event,
+ std::unique_ptr<ui::OSExchangeData> data) override;
protected:
~NativeWidgetAura() override;
diff --git a/chromium/ui/views/widget/native_widget_aura_unittest.cc b/chromium/ui/views/widget/native_widget_aura_unittest.cc
index 39ba6823954..d45d6cfeb83 100644
--- a/chromium/ui/views/widget/native_widget_aura_unittest.cc
+++ b/chromium/ui/views/widget/native_widget_aura_unittest.cc
@@ -419,7 +419,7 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51),
ui::EventTimeForNow(),
ui::PointerDetails(ui::EventPointerType::kTouch, 1));
- ui::EventDispatchDetails details = event_sink()->OnEventFromSource(&press);
+ ui::EventDispatchDetails details = GetEventSink()->OnEventFromSource(&press);
ASSERT_FALSE(details.dispatcher_destroyed);
// Both views should get the press.
EXPECT_TRUE(view->got_gesture_event());
@@ -434,7 +434,7 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(250, 251),
ui::EventTimeForNow(),
ui::PointerDetails(ui::EventPointerType::kTouch, 1));
- details = event_sink()->OnEventFromSource(&release);
+ details = GetEventSink()->OnEventFromSource(&release);
ASSERT_FALSE(details.dispatcher_destroyed);
EXPECT_TRUE(view->got_gesture_event());
EXPECT_FALSE(child->got_gesture_event());
diff --git a/chromium/ui/views/widget/native_widget_delegate.h b/chromium/ui/views/widget/native_widget_delegate.h
index d8ed38d2de5..12e70210788 100644
--- a/chromium/ui/views/widget/native_widget_delegate.h
+++ b/chromium/ui/views/widget/native_widget_delegate.h
@@ -93,7 +93,8 @@ class VIEWS_EXPORT NativeWidgetDelegate {
// e.g. maximize.
virtual void OnNativeWidgetSizeChanged(const gfx::Size& new_size) = 0;
- // Called when NativeWidget changed workspaces.
+ // Called when NativeWidget changed workspaces or its visible on all
+ // workspaces state changes.
virtual void OnNativeWidgetWorkspaceChanged() = 0;
// Called when the NativeWidget changes its window state.
diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm
index 4b1cf535a38..d6793bb73fa 100644
--- a/chromium/ui/views/widget/native_widget_mac.mm
+++ b/chromium/ui/views/widget/native_widget_mac.mm
@@ -665,7 +665,7 @@ void NativeWidgetMac::SetOpacity(float opacity) {
void NativeWidgetMac::SetAspectRatio(const gfx::SizeF& aspect_ratio) {
if (!GetNSWindowMojo())
return;
- GetNSWindowMojo()->SetContentAspectRatio(aspect_ratio);
+ GetNSWindowMojo()->SetAspectRatio(aspect_ratio);
}
void NativeWidgetMac::FlashFrame(bool flash_frame) {
diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm
index 41ef0a06f87..2b3d0570fbc 100644
--- a/chromium/ui/views/widget/native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm
@@ -18,6 +18,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_timeouts.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
#import "components/remote_cocoa/app_shim/bridged_content_view.h"
#import "components/remote_cocoa/app_shim/native_widget_mac_nswindow.h"
#import "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
@@ -432,8 +433,6 @@ TEST_F(NativeWidgetMacTest, ChildWidgetOnInactiveSpace) {
// Test minimized states triggered externally, implied visibility and restored
// bounds whilst minimized.
TEST_F(NativeWidgetMacTest, MiniaturizeExternally) {
- if (base::mac::IsOS10_10())
- return; // Fails when swarmed. http://crbug.com/660582
Widget* widget = new Widget;
Widget::InitParams init_params(Widget::InitParams::TYPE_WINDOW);
widget->Init(std::move(init_params));
@@ -833,10 +832,6 @@ TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) {
// deminiaturize on the parent window (after attempting to show the child while
// the parent was miniaturized).
TEST_F(NativeWidgetMacTest, VisibleAfterNativeParentDeminiaturize) {
- // Disabled on 10.10 due to flakes. See http://crbug.com/777247.
- if (base::mac::IsOS10_10())
- return;
-
NSWindow* native_parent = MakeBorderlessNativeParent();
[native_parent makeKeyAndOrderFront:nil];
[native_parent miniaturize:nil];
@@ -1230,21 +1225,14 @@ TEST_F(NativeWidgetMacTest, ShowAnimationControl) {
EXPECT_FALSE([retained_animation isAnimating]);
}
-// Expect that |children|, the list of child windows of a window that has a
-// sheet open, is logically empty. "Logically empty" accounts for the
-// AppKit-created visual effect window that shows atop windows with open sheets
-// on macOS 11.
-void AssertNoChildrenForWindowWithSheet(NSArray<NSWindow*>* children) {
- if (base::mac::IsAtLeastOS11()) {
- ASSERT_EQ(1u, children.count);
- EXPECT_NSEQ(@"NSSheetEffectDimmingWindow", children[0].className);
- } else {
- ASSERT_EQ(0u, children.count);
- }
-}
-
// Tests behavior of window-modal dialogs, displayed as sheets.
-TEST_F(NativeWidgetMacTest, WindowModalSheet) {
+#if defined(ARCH_CPU_ARM64)
+// Bulk-disabled as part of arm64 bot stabilization: https://crbug.com/1154345
+#define MAYBE_WindowModalSheet DISABLED_WindowModalSheet
+#else
+#define MAYBE_WindowModalSheet WindowModalSheet
+#endif
+TEST_F(NativeWidgetMacTest, MAYBE_WindowModalSheet) {
NSWindow* native_parent = MakeClosableTitledNativeParent();
Widget* sheet_widget = views::DialogDelegate::CreateDialogWidget(
@@ -1300,7 +1288,7 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) {
ASSERT_EQ(2u, children.size());
EXPECT_TRUE(children.count(sheet_widget));
- AssertNoChildrenForWindowWithSheet(native_parent.childWindows);
+ ASSERT_EQ(0U, native_parent.childWindows.count);
// Modal, so the close button in the parent window should get disabled.
EXPECT_FALSE([parent_close_button isEnabled]);
@@ -1323,7 +1311,7 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) {
widget_observer.WaitForVisibleCounts(1, 1);
EXPECT_FALSE(sheet_widget->IsVisible());
[native_parent makeKeyAndOrderFront:nil];
- AssertNoChildrenForWindowWithSheet(native_parent.childWindows);
+ ASSERT_EQ(0u, native_parent.childWindows.count);
widget_observer.WaitForVisibleCounts(2, 1);
EXPECT_TRUE(sheet_widget->IsVisible());
diff --git a/chromium/ui/views/widget/root_view.cc b/chromium/ui/views/widget/root_view.cc
index 2ebd95f6631..604adeff632 100644
--- a/chromium/ui/views/widget/root_view.cc
+++ b/chromium/ui/views/widget/root_view.cc
@@ -9,9 +9,11 @@
#include "base/logging.h"
#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
#include "ui/base/ui_base_switches_util.h"
@@ -20,9 +22,11 @@
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
+#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/drag_controller.h"
-#include "ui/views/layout/fill_layout.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/metadata/metadata_impl_macros.h"
+#include "ui/views/view_class_properties.h"
#include "ui/views/view_targeter.h"
#include "ui/views/widget/root_view_targeter.h"
#include "ui/views/widget/widget.h"
@@ -60,6 +64,7 @@ class MouseEnterExitEvent : public ui::MouseEvent {
// is the reason this system exists at all).
class AnnounceTextView : public View {
public:
+ METADATA_HEADER(AnnounceTextView);
~AnnounceTextView() override = default;
void Announce(const base::string16& text) {
@@ -75,12 +80,16 @@ class AnnounceTextView : public View {
// May require setting kLiveStatus, kContainerLiveStatus to "polite".
node_data->role = ax::mojom::Role::kAlert;
node_data->SetName(announce_text_);
+ node_data->AddState(ax::mojom::State::kInvisible);
}
private:
base::string16 announce_text_;
};
+BEGIN_METADATA(AnnounceTextView, View)
+END_METADATA
+
// This event handler receives events in the pre-target phase and takes care of
// the following:
// - Shows keyboard-triggered context menus.
@@ -89,6 +98,8 @@ class PreEventDispatchHandler : public ui::EventHandler {
explicit PreEventDispatchHandler(View* owner) : owner_(owner) {
owner_->AddPreTargetHandler(this);
}
+ PreEventDispatchHandler(const PreEventDispatchHandler&) = delete;
+ PreEventDispatchHandler& operator=(const PreEventDispatchHandler&) = delete;
~PreEventDispatchHandler() override { owner_->RemovePreTargetHandler(this); }
private:
@@ -121,9 +132,11 @@ class PreEventDispatchHandler : public ui::EventHandler {
#endif
}
- View* owner_;
+ base::StringPiece GetLogContext() const override {
+ return "PreEventDispatchHandler";
+ }
- DISALLOW_COPY_AND_ASSIGN(PreEventDispatchHandler);
+ View* owner_;
};
// This event handler receives events in the post-target phase and takes care of
@@ -133,6 +146,8 @@ class PostEventDispatchHandler : public ui::EventHandler {
public:
PostEventDispatchHandler()
: touch_dnd_enabled_(::switches::IsTouchDragDropEnabled()) {}
+ PostEventDispatchHandler(const PostEventDispatchHandler&) = delete;
+ PostEventDispatchHandler& operator=(const PostEventDispatchHandler&) = delete;
~PostEventDispatchHandler() override = default;
private:
@@ -167,9 +182,11 @@ class PostEventDispatchHandler : public ui::EventHandler {
}
}
- bool touch_dnd_enabled_;
+ base::StringPiece GetLogContext() const override {
+ return "PostEventDispatchHandler";
+ }
- DISALLOW_COPY_AND_ASSIGN(PostEventDispatchHandler);
+ bool touch_dnd_enabled_;
};
////////////////////////////////////////////////////////////////////////////////
@@ -179,22 +196,10 @@ class PostEventDispatchHandler : public ui::EventHandler {
RootView::RootView(Widget* widget)
: widget_(widget),
- mouse_pressed_handler_(nullptr),
- mouse_move_handler_(nullptr),
- last_click_handler_(nullptr),
- explicit_mouse_handler_(false),
- last_mouse_event_flags_(0),
- last_mouse_event_x_(-1),
- last_mouse_event_y_(-1),
- gesture_handler_(nullptr),
- gesture_handler_set_before_processing_(false),
- pre_dispatch_handler_(new internal::PreEventDispatchHandler(this)),
- post_dispatch_handler_(new internal::PostEventDispatchHandler),
- focus_search_(this, false, false),
- focus_traversable_parent_(nullptr),
- focus_traversable_parent_view_(nullptr),
- event_dispatch_target_(nullptr),
- old_dispatch_target_(nullptr) {
+ pre_dispatch_handler_(
+ std::make_unique<internal::PreEventDispatchHandler>(this)),
+ post_dispatch_handler_(
+ std::make_unique<internal::PostEventDispatchHandler>()) {
AddPostTargetHandler(post_dispatch_handler_.get());
SetEventTargeter(
std::unique_ptr<ViewTargeter>(new RootViewTargeter(this, this)));
@@ -213,7 +218,7 @@ void RootView::SetContentsView(View* contents_view) {
<< "Can't be called until after the native widget is created!";
// The ContentsView must be set up _after_ the window is created so that its
// Widget pointer is valid.
- SetLayoutManager(std::make_unique<FillLayout>());
+ SetUseDefaultFillLayout(true);
if (!children().empty())
RemoveAllChildViews(true);
AddChildView(contents_view);
@@ -263,16 +268,16 @@ void RootView::DeviceScaleFactorChanged(float old_device_scale_factor,
void RootView::AnnounceText(const base::string16& text) {
#if defined(OS_APPLE)
- // MacOSX has its own API for making announcements; see AnnounceText()
- // override in ax_platform_node_mac.[h|mm]
- NOTREACHED();
+ gfx::NativeViewAccessible native = GetViewAccessibility().GetNativeObject();
+ auto* ax_node = ui::AXPlatformNode::FromNativeViewAccessible(native);
+ if (ax_node)
+ ax_node->AnnounceText(text);
#else
DCHECK(GetWidget());
DCHECK(GetContentsView());
if (!announce_view_) {
announce_view_ = AddChildView(std::make_unique<AnnounceTextView>());
- static_cast<FillLayout*>(GetLayoutManager())
- ->SetChildViewIgnoredByLayout(announce_view_, true);
+ announce_view_->SetProperty(kViewIgnoredByLayoutKey, true);
}
announce_view_->Announce(text);
#endif
@@ -305,6 +310,7 @@ ui::EventTargeter* RootView::GetDefaultEventTargeter() {
}
void RootView::OnEventProcessingStarted(ui::Event* event) {
+ VLOG(5) << "RootView::OnEventProcessingStarted(" << event->ToString() << ")";
if (!event->IsGestureEvent())
return;
@@ -339,6 +345,7 @@ void RootView::OnEventProcessingStarted(ui::Event* event) {
}
void RootView::OnEventProcessingFinished(ui::Event* event) {
+ VLOG(5) << "RootView::OnEventProcessingFinished(" << event->ToString() << ")";
// If |event| was not handled and |gesture_handler_| was not set by the
// dispatch of a previous gesture event, then no default gesture handler
// should be set prior to the next gesture event being received.
@@ -463,7 +470,12 @@ void RootView::OnMouseReleased(const ui::MouseEvent& event) {
// We allow the view to delete us from the event dispatch callback. As such,
// configure state such that we're done first, then call View.
View* mouse_pressed_handler = mouse_pressed_handler_;
+
+ // The gesture handler should not be reset when handling the mouse release.
+ // Otherwise, the gesture movements in progress such as the gesture scroll
+ // is interrupted.
SetMouseHandler(nullptr);
+
ui::EventDispatchDetails dispatch_details =
DispatchEvent(mouse_pressed_handler, &mouse_released);
if (dispatch_details.dispatcher_destroyed)
@@ -485,7 +497,7 @@ void RootView::OnMouseCaptureLost() {
// configure state such that we're done first, then call View.
View* mouse_pressed_handler = mouse_pressed_handler_;
View* gesture_handler = gesture_handler_;
- SetMouseHandler(nullptr);
+ SetMouseAndGestureHandler(nullptr);
if (mouse_pressed_handler)
mouse_pressed_handler->OnMouseCaptureLost();
else
@@ -625,12 +637,9 @@ bool RootView::OnMouseWheel(const ui::MouseWheelEvent& event) {
return event.handled();
}
-void RootView::SetMouseHandler(View* new_mh) {
- // If we're clearing the mouse handler, clear explicit_mouse_handler_ as well.
- explicit_mouse_handler_ = (new_mh != nullptr);
- mouse_pressed_handler_ = new_mh;
- gesture_handler_ = new_mh;
- drag_info_.Reset();
+void RootView::SetMouseAndGestureHandler(View* new_handler) {
+ SetMouseHandler(new_handler);
+ gesture_handler_ = new_handler;
}
void RootView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
@@ -746,6 +755,13 @@ ui::EventDispatchDetails RootView::NotifyEnterExitOfDescendant(
return ui::EventDispatchDetails();
}
+void RootView::SetMouseHandler(View* new_mouse_handler) {
+ // If we're clearing the mouse handler, clear explicit_mouse_handler_ as well.
+ explicit_mouse_handler_ = (new_mouse_handler != nullptr);
+ mouse_pressed_handler_ = new_mouse_handler;
+ drag_info_.Reset();
+}
+
bool RootView::CanDispatchToTarget(ui::EventTarget* target) {
return event_dispatch_target_ == target;
}
@@ -777,7 +793,7 @@ ui::EventDispatchDetails RootView::PostDispatchEvent(ui::EventTarget* target,
// In case a drag was in progress, reset all the handlers. Otherwise, just
// reset the gesture handler.
if (gesture_handler_ && gesture_handler_ == mouse_pressed_handler_)
- SetMouseHandler(nullptr);
+ SetMouseAndGestureHandler(nullptr);
else
gesture_handler_ = nullptr;
}
diff --git a/chromium/ui/views/widget/root_view.h b/chromium/ui/views/widget/root_view.h
index c72230774d9..e7d34e12a58 100644
--- a/chromium/ui/views/widget/root_view.h
+++ b/chromium/ui/views/widget/root_view.h
@@ -58,6 +58,8 @@ class VIEWS_EXPORT RootView : public View,
// Creation and lifetime -----------------------------------------------------
explicit RootView(Widget* widget);
+ RootView(const RootView&) = delete;
+ RootView& operator=(const RootView&) = delete;
~RootView() override;
// Tree operations -----------------------------------------------------------
@@ -121,7 +123,7 @@ class VIEWS_EXPORT RootView : public View,
void OnMouseMoved(const ui::MouseEvent& event) override;
void OnMouseExited(const ui::MouseEvent& event) override;
bool OnMouseWheel(const ui::MouseWheelEvent& event) override;
- void SetMouseHandler(View* new_mouse_handler) override;
+ void SetMouseAndGestureHandler(View* new_handler) override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
void UpdateParentLayer() override;
@@ -166,6 +168,9 @@ class VIEWS_EXPORT RootView : public View,
View* view,
View* sibling) WARN_UNUSED_RESULT;
+ // Updates the mouse handler and other related data members.
+ void SetMouseHandler(View* new_mouse_handler);
+
// ui::EventDispatcherDelegate:
bool CanDispatchToTarget(ui::EventTarget* target) override;
ui::EventDispatchDetails PreDispatchEvent(ui::EventTarget* target,
@@ -185,26 +190,26 @@ class VIEWS_EXPORT RootView : public View,
// ViewTargeter / RootViewTargeter.
// The view currently handing down - drag - up
- View* mouse_pressed_handler_;
+ View* mouse_pressed_handler_ = nullptr;
// The view currently handling enter / exit
- View* mouse_move_handler_;
+ View* mouse_move_handler_ = nullptr;
// The last view to handle a mouse click, so that we can determine if
// a double-click lands on the same view as its single-click part.
- View* last_click_handler_;
+ View* last_click_handler_ = nullptr;
// true if mouse_pressed_handler_ has been explicitly set
- bool explicit_mouse_handler_;
+ bool explicit_mouse_handler_ = false;
// Last position/flag of a mouse press/drag. Used if capture stops and we need
// to synthesize a release.
- int last_mouse_event_flags_;
- int last_mouse_event_x_;
- int last_mouse_event_y_;
+ int last_mouse_event_flags_ = 0;
+ int last_mouse_event_x_ = -1;
+ int last_mouse_event_y_ = -1;
// The View currently handling gesture events.
- View* gesture_handler_;
+ View* gesture_handler_ = nullptr;
// Used to indicate if the |gesture_handler_| member was set prior to the
// processing of the current event (i.e., if |gesture_handler_| was set
@@ -212,7 +217,7 @@ class VIEWS_EXPORT RootView : public View,
// TODO(tdanderson): It may be possible to eliminate the need for this
// member if |event_dispatch_target_| can be used in
// its place.
- bool gesture_handler_set_before_processing_;
+ bool gesture_handler_set_before_processing_ = false;
std::unique_ptr<internal::PreEventDispatchHandler> pre_dispatch_handler_;
std::unique_ptr<internal::PostEventDispatchHandler> post_dispatch_handler_;
@@ -220,20 +225,20 @@ class VIEWS_EXPORT RootView : public View,
// Focus ---------------------------------------------------------------------
// The focus search algorithm.
- FocusSearch focus_search_;
+ FocusSearch focus_search_{this, false, false};
// Whether this root view belongs to the current active window.
// bool activated_;
// The parent FocusTraversable, used for focus traversal.
- FocusTraversable* focus_traversable_parent_;
+ FocusTraversable* focus_traversable_parent_ = nullptr;
// The View that contains this RootView. This is used when we have RootView
// wrapped inside native components, and is used for the focus traversal.
- View* focus_traversable_parent_view_;
+ View* focus_traversable_parent_view_ = nullptr;
- View* event_dispatch_target_;
- View* old_dispatch_target_;
+ View* event_dispatch_target_ = nullptr;
+ View* old_dispatch_target_ = nullptr;
// Drag and drop -------------------------------------------------------------
@@ -245,8 +250,6 @@ class VIEWS_EXPORT RootView : public View,
// Hidden view used to make announcements to the screen reader via an alert or
// live region update.
AnnounceTextView* announce_view_ = nullptr;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(RootView);
};
} // namespace internal
diff --git a/chromium/ui/views/widget/root_view_unittest.cc b/chromium/ui/views/widget/root_view_unittest.cc
index a733d70972b..62e53105c17 100644
--- a/chromium/ui/views/widget/root_view_unittest.cc
+++ b/chromium/ui/views/widget/root_view_unittest.cc
@@ -5,6 +5,7 @@
#include "ui/views/widget/root_view.h"
#include <memory>
+#include <set>
#include <utility>
#include "base/macros.h"
@@ -21,6 +22,10 @@
#include "ui/views/widget/widget_deletion_observer.h"
#include "ui/views/window/dialog_delegate.h"
+#if defined(OS_MAC)
+#include "base/mac/mac_util.h"
+#endif
+
namespace views {
namespace test {
@@ -178,6 +183,89 @@ class GestureHandlingView : public View {
DISALLOW_COPY_AND_ASSIGN(GestureHandlingView);
};
+// View which handles both mouse and gesture events.
+class EventHandlingView : public View {
+ public:
+ EventHandlingView() = default;
+ EventHandlingView(const EventHandlingView&) = delete;
+ EventHandlingView& operator=(const EventHandlingView&) = delete;
+ ~EventHandlingView() override = default;
+
+ // Returns whether an event specified by `type_to_query` has been handled.
+ bool HandledEventBefore(ui::EventType type_to_query) const {
+ return handled_gestures_set_.find(type_to_query) !=
+ handled_gestures_set_.cend();
+ }
+
+ // View:
+ void OnMouseEvent(ui::MouseEvent* event) override { event->SetHandled(); }
+
+ void OnGestureEvent(ui::GestureEvent* event) override {
+ // Record the handled gesture event.
+ auto insertion_ret = handled_gestures_set_.insert(event->type());
+ EXPECT_TRUE(insertion_ret.second);
+
+ event->SetHandled();
+ }
+
+ private:
+ std::set<ui::EventType> handled_gestures_set_;
+};
+
+// Verifies that when the mouse click interrupts the gesture scroll, the view
+// where the gesture scroll starts should receive the scroll end event.
+TEST_F(RootViewTest, MouseClickInterruptsGestureScroll) {
+#if defined(OS_MAC)
+ if (base::mac::IsOS11())
+ GTEST_SKIP() << "Flaky on macOS 11: https://crbug.com/1195879";
+#endif
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.bounds = gfx::Rect(100, 100);
+ widget.Init(std::move(init_params));
+ widget.Show();
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget.GetRootView());
+ View* contents_view = widget.SetContentsView(std::make_unique<View>());
+ View* child_view =
+ contents_view->AddChildView(std::make_unique<EventHandlingView>());
+ child_view->SetBoundsRect(gfx::Rect(gfx::Size{50, 50}));
+
+ // Emulate to start gesture scroll on `child_view`.
+ const gfx::Point center_point = child_view->GetBoundsInScreen().CenterPoint();
+ ui::GestureEvent scroll_begin(
+ center_point.x(), center_point.y(), ui::EF_NONE, base::TimeTicks(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
+ root_view->OnEventFromSource(&scroll_begin);
+ ui::GestureEvent scroll_update(
+ center_point.x(), center_point.y(), ui::EF_NONE, base::TimeTicks(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, /*delta_x=*/20,
+ /*delta_y=*/10));
+ root_view->OnEventFromSource(&scroll_update);
+
+ // Emulate the mouse click on `child_view_`.
+ ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED, center_point, center_point,
+ ui::EventTimeForNow(), ui::EF_NONE,
+ /*changed_button_flags=*/0);
+ ui::MouseEvent released_event(ui::ET_MOUSE_RELEASED, center_point,
+ center_point, ui::EventTimeForNow(),
+ ui::EF_NONE, /*changed_button_flags=*/0);
+ root_view->OnMousePressed(pressed_event);
+ root_view->OnMouseReleased(released_event);
+
+ // End the gesture scroll.
+ ui::GestureEvent scroll_end(
+ center_point.x(), center_point.y(), ui::EF_NONE, base::TimeTicks(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
+ root_view->OnEventFromSource(&scroll_end);
+
+ // Verify that `child_view` receives the gesture scroll end event.
+ EXPECT_TRUE(static_cast<EventHandlingView*>(child_view)
+ ->HandledEventBefore(ui::ET_GESTURE_SCROLL_END));
+}
+
// Tests that context menus are shown for long press by the post-target handler
// installed on the RootView only if the event is targetted at a view which can
// show a context menu.
diff --git a/chromium/ui/views/widget/unique_widget_ptr.cc b/chromium/ui/views/widget/unique_widget_ptr.cc
index fe1d2607c84..6e219970dee 100644
--- a/chromium/ui/views/widget/unique_widget_ptr.cc
+++ b/chromium/ui/views/widget/unique_widget_ptr.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
@@ -32,7 +32,7 @@ class UniqueWidgetPtr::UniqueWidgetPtrImpl : public WidgetObserver {
// deliberately implicit.
UniqueWidgetPtrImpl(std::unique_ptr<Widget> widget) // NOLINT
: widget_closer_(widget.release()) {
- widget_observer_.Add(widget_closer_.get());
+ widget_observation_.Observe(widget_closer_.get());
}
UniqueWidgetPtrImpl(const UniqueWidgetPtrImpl&) = delete;
@@ -46,19 +46,19 @@ class UniqueWidgetPtr::UniqueWidgetPtrImpl : public WidgetObserver {
void Reset() {
if (!widget_closer_)
return;
- widget_observer_.RemoveAll();
+ widget_observation_.Reset();
widget_closer_.reset();
}
// WidgetObserver overrides.
void OnWidgetDestroying(Widget* widget) override {
DCHECK_EQ(widget, widget_closer_.get());
- widget_observer_.RemoveAll();
+ widget_observation_.Reset();
widget_closer_.release();
}
private:
- ScopedObserver<Widget, WidgetObserver> widget_observer_{this};
+ base::ScopedObservation<Widget, WidgetObserver> widget_observation_{this};
WidgetAutoClosePtr widget_closer_;
};
diff --git a/chromium/ui/views/widget/unique_widget_ptr_unittest.cc b/chromium/ui/views/widget/unique_widget_ptr_unittest.cc
index df8804ab1f9..3e333ba3edc 100644
--- a/chromium/ui/views/widget/unique_widget_ptr_unittest.cc
+++ b/chromium/ui/views/widget/unique_widget_ptr_unittest.cc
@@ -5,8 +5,9 @@
#include "ui/views/widget/unique_widget_ptr.h"
#include <memory>
+#include <utility>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -29,7 +30,7 @@ class UniqueWidgetPtrTest : public ViewsTestBase, public WidgetObserver {
std::unique_ptr<Widget> AllocateTestWidget() override {
auto widget = ViewsTestBase::AllocateTestWidget();
widget->Init(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS));
- widget_observer_.Add(widget.get());
+ widget_observation_.Observe(widget.get());
return widget;
}
@@ -46,13 +47,14 @@ class UniqueWidgetPtrTest : public ViewsTestBase, public WidgetObserver {
void OnWidgetDestroying(Widget* widget) override {
ASSERT_NE(widget_, nullptr);
ASSERT_EQ(widget_, widget);
- widget_observer_.Remove(widget_);
+ ASSERT_TRUE(widget_observation_.IsObservingSource(widget_));
+ widget_observation_.Reset();
widget_ = nullptr;
}
private:
Widget* widget_ = nullptr;
- ScopedObserver<Widget, WidgetObserver> widget_observer_{this};
+ base::ScopedObservation<Widget, WidgetObserver> widget_observation_{this};
};
// Make sure explicitly resetting the |unique_widget_ptr| variable properly
diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc
index c27777b9e95..cf8bb3500d4 100644
--- a/chromium/ui/views/widget/widget.cc
+++ b/chromium/ui/views/widget/widget.cc
@@ -87,7 +87,9 @@ void NotifyCaretBoundsChanged(ui::InputMethod* input_method) {
} // namespace
// static
-bool Widget::g_disable_activation_change_handling_ = false;
+Widget::DisableActivationChangeHandlingType
+ Widget::g_disable_activation_change_handling_ =
+ Widget::DisableActivationChangeHandlingType::kNone;
// A default implementation of WidgetDelegate, used by Widget when no
// WidgetDelegate is supplied.
@@ -271,16 +273,18 @@ void Widget::ReparentNativeView(gfx::NativeView native_view,
// static
int Widget::GetLocalizedContentsWidth(int col_resource_id) {
- return ui::GetLocalizedContentsWidthForFont(
- col_resource_id, ui::ResourceBundle::GetSharedInstance().GetFontWithDelta(
- ui::kMessageFontSizeDelta));
+ return ui::GetLocalizedContentsWidthForFontList(
+ col_resource_id,
+ ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
+ ui::kMessageFontSizeDelta));
}
// static
int Widget::GetLocalizedContentsHeight(int row_resource_id) {
- return ui::GetLocalizedContentsHeightForFont(
- row_resource_id, ui::ResourceBundle::GetSharedInstance().GetFontWithDelta(
- ui::kMessageFontSizeDelta));
+ return ui::GetLocalizedContentsHeightForFontList(
+ row_resource_id,
+ ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
+ ui::kMessageFontSizeDelta));
}
// static
@@ -394,7 +398,7 @@ void Widget::Init(InitParams params) {
SetInitialBoundsForFramelessWindow(bounds);
}
- observer_manager_.Add(GetNativeTheme());
+ observation_.Observe(GetNativeTheme());
native_widget_initialized_ = true;
native_widget_->OnWidgetInitDone();
@@ -610,6 +614,15 @@ void Widget::CloseWithReason(ClosedReason closed_reason) {
if (widget_delegate_ && !widget_delegate_->OnCloseRequested(closed_reason))
return;
+ // Cancel widget close on focus lost. This is used in UI Devtools to lock
+ // bubbles and in some tests where we want to ignore spurious deactivation.
+ if (closed_reason == ClosedReason::kLostFocus &&
+ (g_disable_activation_change_handling_ ==
+ DisableActivationChangeHandlingType::kIgnore ||
+ g_disable_activation_change_handling_ ==
+ DisableActivationChangeHandlingType::kIgnoreDeactivationOnly))
+ 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;
@@ -742,7 +755,10 @@ void Widget::SetFullscreen(bool fullscreen) {
if (IsFullscreen() == fullscreen)
return;
+ auto weak_ptr = GetWeakPtr();
native_widget_->SetFullscreen(fullscreen);
+ if (!weak_ptr)
+ return;
if (non_client_view_)
non_client_view_->InvalidateLayout();
@@ -996,7 +1012,7 @@ void Widget::SetCapture(View* view) {
if (native_widget_->IsMouseButtonDown())
is_mouse_button_pressed_ = true;
- root_view_->SetMouseHandler(view);
+ root_view_->SetMouseAndGestureHandler(view);
}
void Widget::ReleaseCapture() {
@@ -1055,8 +1071,7 @@ std::string Widget::GetName() const {
return native_widget_->GetName();
}
-std::unique_ptr<Widget::PaintAsActiveCallbackList::Subscription>
-Widget::RegisterPaintAsActiveChangedCallback(
+base::CallbackListSubscription Widget::RegisterPaintAsActiveChangedCallback(
PaintAsActiveCallbackList::CallbackType callback) {
return paint_as_active_callbacks_.Add(std::move(callback));
}
@@ -1100,7 +1115,11 @@ bool Widget::IsNativeWidgetInitialized() const {
}
bool Widget::OnNativeWidgetActivationChanged(bool active) {
- if (g_disable_activation_change_handling_)
+ if (g_disable_activation_change_handling_ ==
+ DisableActivationChangeHandlingType::kIgnore ||
+ (g_disable_activation_change_handling_ ==
+ DisableActivationChangeHandlingType::kIgnoreDeactivationOnly &&
+ !active))
return false;
// On windows we may end up here before we've completed initialization (from
@@ -1501,16 +1520,16 @@ View* Widget::GetFocusTraversableParentView() {
void Widget::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) {
TRACE_EVENT0("ui", "Widget::OnNativeThemeUpdated");
- DCHECK(observer_manager_.IsObserving(observed_theme));
+ DCHECK(observation_.IsObservingSource(observed_theme));
#if defined(OS_APPLE) || defined(OS_WIN)
ui::NativeTheme* current_native_theme = observed_theme;
#else
ui::NativeTheme* current_native_theme = GetNativeTheme();
#endif
- if (!observer_manager_.IsObserving(current_native_theme)) {
- observer_manager_.RemoveAll();
- observer_manager_.Add(current_native_theme);
+ if (!observation_.IsObservingSource(current_native_theme)) {
+ observation_.Reset();
+ observation_.Observe(current_native_theme);
}
PropagateNativeThemeChanged();
diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h
index b0e093c4f94..cd0c29c10bf 100644
--- a/chromium/ui/views/widget/widget.h
+++ b/chromium/ui/views/widget/widget.h
@@ -14,7 +14,7 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "build/build_config.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"
#include "ui/base/ui_base_types.h"
@@ -47,6 +47,10 @@ class OSExchangeData;
class ThemeProvider;
} // namespace ui
+namespace ui_devtools {
+class PageAgentViews;
+}
+
namespace views {
class DesktopWindowTreeHost;
@@ -121,12 +125,12 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
};
// Behavior when escape is pressed during a move loop.
- enum MoveLoopEscapeBehavior {
+ enum class MoveLoopEscapeBehavior {
// Indicates the window should be hidden.
- MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE,
+ kHide,
// Indicates the window should not be hidden.
- MOVE_LOOP_ESCAPE_BEHAVIOR_DONT_HIDE,
+ kDontHide,
};
// Type of visibility change transition that should animate.
@@ -931,8 +935,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// Registers |callback| to be called whenever the "paint as active" state
// changes.
- std::unique_ptr<PaintAsActiveCallbackList::Subscription>
- RegisterPaintAsActiveChangedCallback(
+ base::CallbackListSubscription RegisterPaintAsActiveChangedCallback(
PaintAsActiveCallbackList::CallbackType callback);
// Prevents the widget from being rendered as inactive during the lifetime of
@@ -1018,6 +1021,13 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
virtual void OnDragComplete();
private:
+ // Type of ways to ignore activation changes.
+ enum class DisableActivationChangeHandlingType {
+ kNone = 0, // Don't ignore any activation changes.
+ kIgnore, // Ignore both activation and deactivation changes.
+ kIgnoreDeactivationOnly, // Ignore only deactivation changes.
+ };
+
class PaintAsActiveLockImpl;
friend class ButtonTest;
@@ -1025,8 +1035,19 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
friend class PaintAsActiveLockImpl;
friend class TextfieldTest;
friend class ViewAuraTest;
+ friend class ui_devtools::PageAgentViews;
friend void DisableActivationChangeHandlingForTests();
+ // Sets/gets the type of disabling widget activation change handling.
+ static void SetDisableActivationChangeHandling(
+ DisableActivationChangeHandlingType new_type) {
+ g_disable_activation_change_handling_ = new_type;
+ }
+ static DisableActivationChangeHandlingType
+ GetDisableActivationChangeHandling() {
+ return g_disable_activation_change_handling_;
+ }
+
// Persists the window's restored position and "show" state using the
// window delegate.
void SaveWindowPlacement();
@@ -1057,7 +1078,8 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// If a descendent of |root_view_| is focused, then clear the focus.
void ClearFocusFromWidget();
- static bool g_disable_activation_change_handling_;
+ static DisableActivationChangeHandlingType
+ g_disable_activation_change_handling_;
internal::NativeWidgetPrivate* native_widget_ = nullptr;
@@ -1174,8 +1196,8 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// Block the widget from closing.
bool block_close_ = false;
- ScopedObserver<ui::NativeTheme, ui::NativeThemeObserver> observer_manager_{
- this};
+ base::ScopedObservation<ui::NativeTheme, ui::NativeThemeObserver>
+ observation_{this};
base::WeakPtrFactory<Widget> weak_ptr_factory_{this};
diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc
index 383ca7e0a11..6f70e71d97f 100644
--- a/chromium/ui/views/widget/widget_delegate.cc
+++ b/chromium/ui/views/widget/widget_delegate.cc
@@ -139,7 +139,10 @@ bool WidgetDelegate::ShouldShowCloseButton() const {
}
gfx::ImageSkia WidgetDelegate::GetWindowAppIcon() {
- // Use the window icon as app icon by default.
+ // Prefer app icon if available.
+ if (!params_.app_icon.isNull())
+ return params_.app_icon;
+ // Fall back to the window icon.
return GetWindowIcon();
}
@@ -322,6 +325,12 @@ void WidgetDelegate::SetIcon(const gfx::ImageSkia& icon) {
GetWidget()->UpdateWindowIcon();
}
+void WidgetDelegate::SetAppIcon(const gfx::ImageSkia& icon) {
+ params_.app_icon = icon;
+ if (GetWidget())
+ GetWidget()->UpdateWindowIcon();
+}
+
void WidgetDelegate::SetInitiallyFocusedView(View* initially_focused_view) {
DCHECK(!GetWidget());
params_.initially_focused_view = initially_focused_view;
diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h
index 211ac11173e..623bbcf3778 100644
--- a/chromium/ui/views/widget/widget_delegate.h
+++ b/chromium/ui/views/widget/widget_delegate.h
@@ -12,6 +12,8 @@
#include "base/macros.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/base/ui_base_types.h"
+#include "ui/views/metadata/metadata_header_macros.h"
+#include "ui/views/metadata/view_factory.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -82,6 +84,9 @@ class VIEWS_EXPORT WidgetDelegate {
// The widget's icon, if any.
gfx::ImageSkia icon;
+ // The widget's app icon, a larger icon used for task bar and Alt-Tab.
+ gfx::ImageSkia app_icon;
+
// The widget's initially focused view, if any. This can only be set before
// this WidgetDelegate is used to initialize a Widget.
base::Optional<View*> initially_focused_view;
@@ -116,6 +121,8 @@ class VIEWS_EXPORT WidgetDelegate {
};
WidgetDelegate();
+ WidgetDelegate(const WidgetDelegate&) = delete;
+ WidgetDelegate& operator=(const WidgetDelegate&) = delete;
virtual ~WidgetDelegate();
// Sets the return value of CanActivate(). Default is true.
@@ -326,6 +333,7 @@ class VIEWS_EXPORT WidgetDelegate {
void SetFocusTraversesOut(bool focus_traverses_out);
void SetEnableArrowKeyTraversal(bool enable_arrow_key_traversal);
void SetIcon(const gfx::ImageSkia& icon);
+ void SetAppIcon(const gfx::ImageSkia& icon);
void SetInitiallyFocusedView(View* initially_focused_view);
void SetModalType(ui::ModalType modal_type);
void SetOwnedByWidget(bool delete_self);
@@ -423,8 +431,6 @@ class VIEWS_EXPORT WidgetDelegate {
ClientViewFactory client_view_factory_;
NonClientFrameViewFactory non_client_frame_view_factory_;
OverlayViewFactory overlay_view_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(WidgetDelegate);
};
// A WidgetDelegate implementation that is-a View. Used to override GetWidget()
@@ -436,17 +442,21 @@ class VIEWS_EXPORT WidgetDelegateView : public WidgetDelegate, public View {
METADATA_HEADER(WidgetDelegateView);
WidgetDelegateView();
+ WidgetDelegateView(const WidgetDelegateView&) = delete;
+ WidgetDelegateView& operator=(const WidgetDelegateView&) = delete;
~WidgetDelegateView() override;
// WidgetDelegate:
Widget* GetWidget() override;
const Widget* GetWidget() const override;
View* GetContentsView() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WidgetDelegateView);
};
+BEGIN_VIEW_BUILDER(VIEWS_EXPORT, WidgetDelegateView, View)
+END_VIEW_BUILDER
+
} // namespace views
+DEFINE_VIEW_BUILDER(VIEWS_EXPORT, WidgetDelegateView)
+
#endif // UI_VIEWS_WIDGET_WIDGET_DELEGATE_H_
diff --git a/chromium/ui/views/widget/widget_delegate_unittest.cc b/chromium/ui/views/widget/widget_delegate_unittest.cc
index e5f3305f9d0..80209ee9d0a 100644
--- a/chromium/ui/views/widget/widget_delegate_unittest.cc
+++ b/chromium/ui/views/widget/widget_delegate_unittest.cc
@@ -7,6 +7,8 @@
#include <utility>
#include "base/test/bind.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_unittest_util.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
#include "ui/views/view_tracker.h"
@@ -113,5 +115,25 @@ TEST_F(WidgetDelegateTest, OverlayViewFactoryCanReplaceOverlayView) {
EXPECT_EQ(tracker.view(), overlay.get());
}
+TEST_F(WidgetDelegateTest, AppIconCanDifferFromWindowIcon) {
+ auto delegate = std::make_unique<WidgetDelegate>();
+
+ gfx::ImageSkia window_icon = gfx::test::CreateImageSkia(16, 16);
+ delegate->SetIcon(window_icon);
+ gfx::ImageSkia app_icon = gfx::test::CreateImageSkia(48, 48);
+ delegate->SetAppIcon(app_icon);
+ EXPECT_TRUE(delegate->GetWindowIcon().BackedBySameObjectAs(window_icon));
+ EXPECT_TRUE(delegate->GetWindowAppIcon().BackedBySameObjectAs(app_icon));
+}
+
+TEST_F(WidgetDelegateTest, AppIconFallsBackToWindowIcon) {
+ auto delegate = std::make_unique<WidgetDelegate>();
+
+ gfx::ImageSkia window_icon = gfx::test::CreateImageSkia(16, 16);
+ delegate->SetIcon(window_icon);
+ // Don't set an independent app icon.
+ EXPECT_TRUE(delegate->GetWindowAppIcon().BackedBySameObjectAs(window_icon));
+}
+
} // namespace
} // namespace views
diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc
index 287c0de9e87..edff7544cce 100644
--- a/chromium/ui/views/widget/widget_interactive_uitest.cc
+++ b/chromium/ui/views/widget/widget_interactive_uitest.cc
@@ -20,6 +20,7 @@
#include "base/timer/timer.h"
#include "base/win/windows_version.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/resource/resource_bundle.h"
@@ -888,7 +889,7 @@ TEST_F(DesktopWidgetTestInteractive, CanActivateFlagIsHonored) {
#if defined(USE_AURA)
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(crbug.com/916272): investigate fixing and enabling on Chrome OS.
#define MAYBE_TouchSelectionQuickMenuIsNotActivated \
DISABLED_TouchSelectionQuickMenuIsNotActivated
@@ -1218,7 +1219,7 @@ TEST_F(DesktopWidgetTestInteractive, EventHandlersClearedOnWidgetMinimize) {
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);
+ root_view->SetMouseAndGestureHandler(&mouse_handler_view);
EXPECT_TRUE(GetGestureHandler(root_view));
widget->Minimize();
@@ -1652,7 +1653,7 @@ TEST_F(WidgetCaptureTest, GrabUngrab) {
#if defined(OS_APPLE)
#define MAYBE_SystemModalWindowReleasesCapture \
DISABLED_SystemModalWindowReleasesCapture
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
// Investigate enabling for Chrome OS. It probably requires help from the window
// service.
#define MAYBE_SystemModalWindowReleasesCapture \
@@ -1704,7 +1705,7 @@ TEST_F(WidgetCaptureTest, MAYBE_SystemModalWindowReleasesCapture) {
// Regression test for http://crbug.com/382421 (Linux-Aura issue).
// TODO(pkotwicz): Make test pass on CrOS and Windows.
// TODO(tapted): Investigate for toolkit-views on Mac http;//crbug.com/441064.
-#if defined(OS_CHROMEOS) || defined(OS_APPLE)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_APPLE)
#define MAYBE_MouseExitOnCaptureGrab DISABLED_MouseExitOnCaptureGrab
#else
#define MAYBE_MouseExitOnCaptureGrab MouseExitOnCaptureGrab
@@ -1874,7 +1875,7 @@ TEST_F(WidgetCaptureTest, MouseEventDispatchedToRightWindow) {
ui::MouseEvent mouse_event(ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
ui::EventDispatchDetails details =
- widget1.GetNativeWindow()->GetHost()->event_sink()->OnEventFromSource(
+ widget1.GetNativeWindow()->GetHost()->GetEventSink()->OnEventFromSource(
&mouse_event);
ASSERT_FALSE(details.dispatcher_destroyed);
EXPECT_TRUE(widget1.GetAndClearGotMouseEvent());
diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc
index e0dbbb691dc..17d494db682 100644
--- a/chromium/ui/views/widget/widget_unittest.cc
+++ b/chromium/ui/views/widget/widget_unittest.cc
@@ -12,6 +12,7 @@
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/layer_animation_observer.h"
@@ -34,6 +35,7 @@
#include "ui/views/test/test_widget_observer.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/view_test_api.h"
+#include "ui/views/views_test_suite.h"
#include "ui/views/widget/native_widget_delegate.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/root_view.h"
@@ -1215,14 +1217,7 @@ TEST_F(WidgetTest, GetWindowPlacement) {
#else
TEST_F(DesktopWidgetTest, GetWindowPlacement) {
#endif
-#if defined(OS_APPLE)
- if (base::mac::IsOS10_10())
- return; // Fails when swarmed. http://crbug.com/660582
-#endif
-#if defined(USE_X11)
- if (features::IsUsingOzonePlatform())
- return; // TODO(https://crbug.com/1109112): Will be enabled later.
-#endif
+ SKIP_TEST_IF_NOT_OZONE_X11();
WidgetAutoclosePtr widget;
widget.reset(CreateTopLevelNativeWidget());
@@ -1498,7 +1493,7 @@ class DesktopAuraTestValidPaintWidget : public Widget, public WidgetObserver {
public:
explicit DesktopAuraTestValidPaintWidget(Widget::InitParams init_params)
: Widget(std::move(init_params)) {
- observer_.Add(this);
+ observation_.Observe(this);
}
~DesktopAuraTestValidPaintWidget() override = default;
@@ -1541,7 +1536,7 @@ class DesktopAuraTestValidPaintWidget : public Widget, public WidgetObserver {
bool expect_paint_ = true;
bool received_paint_while_hidden_ = false;
base::OnceClosure quit_closure_;
- ScopedObserver<Widget, WidgetObserver> observer_{this};
+ base::ScopedObservation<Widget, WidgetObserver> observation_{this};
DISALLOW_COPY_AND_ASSIGN(DesktopAuraTestValidPaintWidget);
};
@@ -2466,7 +2461,9 @@ TEST_F(DesktopWidgetTest, ValidDuringOnNativeWidgetDestroyingFromClose) {
EXPECT_EQ(gfx::Rect(), observer.bounds());
base::RunLoop().RunUntilIdle();
// Broken on Linux. See http://crbug.com/515379.
-#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
EXPECT_EQ(screen_rect, observer.bounds());
#endif
}
@@ -3277,6 +3274,41 @@ TEST_F(DesktopWidgetTest, FullscreenStatePropagated_DesktopWidget) {
IsNativeWindowVisible(top_level_widget->GetNativeWindow()));
}
+// Used to delete the widget when the supplied bounds changes.
+class DestroyingWidgetBoundsObserver : public WidgetObserver {
+ public:
+ explicit DestroyingWidgetBoundsObserver(std::unique_ptr<Widget> widget)
+ : widget_(std::move(widget)) {
+ widget_->AddObserver(this);
+ }
+
+ // There are no assertions here as not all platforms call
+ // OnWidgetBoundsChanged() when going fullscreen.
+ ~DestroyingWidgetBoundsObserver() override = default;
+
+ // WidgetObserver:
+ void OnWidgetBoundsChanged(Widget* widget,
+ const gfx::Rect& new_bounds) override {
+ widget_->RemoveObserver(this);
+ widget_.reset();
+ }
+
+ private:
+ std::unique_ptr<Widget> widget_;
+};
+
+// Deletes a Widget when the bounds change as part of toggling fullscreen.
+// This is a regression test for https://crbug.com/1197436 .
+TEST_F(DesktopWidgetTest, DeleteInSetFullscreen) {
+ std::unique_ptr<Widget> widget = std::make_unique<Widget>();
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(std::move(params));
+ Widget* w = widget.get();
+ DestroyingWidgetBoundsObserver destroyer(std::move(widget));
+ w->SetFullscreen(true);
+}
+
namespace {
class FullscreenAwareFrame : public views::NonClientFrameView {
diff --git a/chromium/ui/views/widget/widget_utils.cc b/chromium/ui/views/widget/widget_utils.cc
index 81c67ad1a4d..0675d724523 100644
--- a/chromium/ui/views/widget/widget_utils.cc
+++ b/chromium/ui/views/widget/widget_utils.cc
@@ -21,16 +21,16 @@ WidgetOpenTimer::~WidgetOpenTimer() = default;
void WidgetOpenTimer::OnWidgetDestroying(Widget* widget) {
DCHECK(open_timer_.has_value());
- DCHECK(observed_widget_.IsObserving(widget));
+ DCHECK(observed_widget_.IsObservingSource(widget));
callback_.Run(open_timer_->Elapsed());
open_timer_.reset();
- observed_widget_.Remove(widget);
+ observed_widget_.Reset();
}
void WidgetOpenTimer::Reset(Widget* widget) {
DCHECK(!open_timer_.has_value());
- DCHECK(!observed_widget_.IsObserving(widget));
- observed_widget_.Add(widget);
+ DCHECK(!observed_widget_.IsObservingSource(widget));
+ observed_widget_.Observe(widget);
open_timer_ = base::ElapsedTimer();
}
diff --git a/chromium/ui/views/widget/widget_utils.h b/chromium/ui/views/widget/widget_utils.h
index cb092fe7e0f..ee84051bc6c 100644
--- a/chromium/ui/views/widget/widget_utils.h
+++ b/chromium/ui/views/widget/widget_utils.h
@@ -6,7 +6,7 @@
#define UI_VIEWS_WIDGET_WIDGET_UTILS_H_
#include "base/callback.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "ui/gfx/native_widget_types.h"
@@ -39,7 +39,7 @@ class VIEWS_EXPORT WidgetOpenTimer : public WidgetObserver {
// Time the bubble has been open. Used for UMA metrics collection.
base::Optional<base::ElapsedTimer> open_timer_;
- ScopedObserver<Widget, WidgetObserver> observed_widget_{this};
+ base::ScopedObservation<Widget, WidgetObserver> observed_widget_{this};
};
// Returns the root window for |widget|. On non-Aura, this is equivalent to
diff --git a/chromium/ui/views/win/fullscreen_handler.cc b/chromium/ui/views/win/fullscreen_handler.cc
index 8791362556f..708d28f4502 100644
--- a/chromium/ui/views/win/fullscreen_handler.cc
+++ b/chromium/ui/views/win/fullscreen_handler.cc
@@ -70,6 +70,7 @@ void FullscreenHandler::SetFullscreenImpl(bool fullscreen) {
fullscreen_ = fullscreen;
+ auto ref = weak_ptr_factory_.GetWeakPtr();
if (fullscreen_) {
// Set new window style and size.
SetWindowLong(hwnd_, GWL_STYLE,
@@ -102,6 +103,8 @@ void FullscreenHandler::SetFullscreenImpl(bool fullscreen) {
new_rect.height(),
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
+ if (!ref)
+ return;
MarkFullscreen(fullscreen);
}
diff --git a/chromium/ui/views/win/fullscreen_handler.h b/chromium/ui/views/win/fullscreen_handler.h
index fe17c7f0368..c76ef18a6f5 100644
--- a/chromium/ui/views/win/fullscreen_handler.h
+++ b/chromium/ui/views/win/fullscreen_handler.h
@@ -11,6 +11,7 @@
#include <map>
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
namespace gfx {
class Rect;
@@ -54,6 +55,8 @@ class FullscreenHandler {
// Used to mark a window as fullscreen.
Microsoft::WRL::ComPtr<ITaskbarList2> task_bar_list_;
+ base::WeakPtrFactory<FullscreenHandler> weak_ptr_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(FullscreenHandler);
};
diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc
index 5e202cabf38..610d2f5d175 100644
--- a/chromium/ui/views/win/hwnd_message_handler.cc
+++ b/chromium/ui/views/win/hwnd_message_handler.cc
@@ -20,6 +20,7 @@
#include "base/macros.h"
#include "base/metrics/histogram_functions.h"
#include "base/single_thread_task_runner.h"
+#include "base/strings/string_util_win.h"
#include "base/task/current_thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -55,6 +56,7 @@
#include "ui/events/win/system_event_state_lookup.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/resize_utils.h"
#include "ui/gfx/icon_util.h"
#include "ui/gfx/path_win.h"
#include "ui/gfx/win/hwnd_util.h"
@@ -210,11 +212,6 @@ bool GetMonitorAndRects(const RECT& rect,
return true;
}
-struct FindOwnedWindowsData {
- HWND window;
- std::vector<Widget*> owned_widgets;
-};
-
// Enables or disables the menu item for the specified command and menu.
void EnableMenuItemByCommand(HMENU menu, UINT command, bool enabled) {
UINT flags = MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
@@ -255,28 +252,28 @@ bool IsHitTestOnResizeHandle(LRESULT hittest) {
hittest == HTBOTTOMLEFT || hittest == HTBOTTOMRIGHT;
}
-// Convert |param| to the HitTest used in WindowResizeUtils.
-HitTest GetWindowResizeHitTest(UINT param) {
+// Convert |param| to the gfx::ResizeEdge used in gfx::SizeRectToAspectRatio().
+gfx::ResizeEdge GetWindowResizeEdge(UINT param) {
switch (param) {
case WMSZ_BOTTOM:
- return HitTest::kBottom;
+ return gfx::ResizeEdge::kBottom;
case WMSZ_TOP:
- return HitTest::kTop;
+ return gfx::ResizeEdge::kTop;
case WMSZ_LEFT:
- return HitTest::kLeft;
+ return gfx::ResizeEdge::kLeft;
case WMSZ_RIGHT:
- return HitTest::kRight;
+ return gfx::ResizeEdge::kRight;
case WMSZ_TOPLEFT:
- return HitTest::kTopLeft;
+ return gfx::ResizeEdge::kTopLeft;
case WMSZ_TOPRIGHT:
- return HitTest::kTopRight;
+ return gfx::ResizeEdge::kTopRight;
case WMSZ_BOTTOMLEFT:
- return HitTest::kBottomLeft;
+ return gfx::ResizeEdge::kBottomLeft;
case WMSZ_BOTTOMRIGHT:
- return HitTest::kBottomRight;
+ return gfx::ResizeEdge::kBottomRight;
default:
NOTREACHED();
- return HitTest::kBottomRight;
+ return gfx::ResizeEdge::kBottomRight;
}
}
@@ -460,7 +457,7 @@ void HWNDMessageHandler::Init(HWND parent, const gfx::Rect& bounds) {
hwnd(), ui::WindowEventTarget::kWin32InputEventTarget,
static_cast<ui::WindowEventTarget*>(this));
DCHECK(delegate_->GetHWNDMessageDelegateInputMethod());
- observer_.Add(delegate_->GetHWNDMessageDelegateInputMethod());
+ observation_.Observe(delegate_->GetHWNDMessageDelegateInputMethod());
// The usual way for UI Automation to obtain a fragment root is through
// WM_GETOBJECT. However, if there's a relation such as "Controller For"
@@ -853,21 +850,22 @@ void HWNDMessageHandler::SetVisibilityChangedAnimationsEnabled(bool enabled) {
}
bool HWNDMessageHandler::SetTitle(const base::string16& title) {
- base::string16 current_title;
+ std::wstring current_title;
size_t len_with_null = GetWindowTextLength(hwnd()) + 1;
if (len_with_null == 1 && title.length() == 0)
return false;
if (len_with_null - 1 == title.length() &&
GetWindowText(hwnd(), base::WriteInto(&current_title, len_with_null),
len_with_null) &&
- current_title == title)
+ current_title == base::AsWStringPiece(title))
return false;
- SetWindowText(hwnd(), title.c_str());
+ SetWindowText(hwnd(), base::as_wcstr(title));
return true;
}
void HWNDMessageHandler::SetCursor(HCURSOR cursor) {
- TRACE_EVENT1("ui,input", "HWNDMessageHandler::SetCursor", "cursor", cursor);
+ TRACE_EVENT1("ui,input", "HWNDMessageHandler::SetCursor", "cursor",
+ static_cast<const void*>(cursor));
::SetCursor(cursor);
current_cursor_ = cursor;
}
@@ -898,7 +896,10 @@ void HWNDMessageHandler::SetWindowIcons(const gfx::ImageSkia& window_icon,
void HWNDMessageHandler::SetFullscreen(bool fullscreen) {
background_fullscreen_hack_ = false;
+ auto ref = msg_handler_weak_factory_.GetWeakPtr();
fullscreen_handler()->SetFullscreen(fullscreen);
+ if (!ref)
+ return;
// Add the fullscreen window to the fullscreen window map which is used to
// handle window activations.
@@ -929,7 +930,7 @@ void HWNDMessageHandler::SetAspectRatio(float aspect_ratio) {
if (GetWindowRect(hwnd(), &window_rect)) {
gfx::Rect rect(window_rect);
- SizeRectToAspectRatio(WMSZ_BOTTOMRIGHT, &rect);
+ SizeWindowToAspectRatio(WMSZ_BOTTOMRIGHT, &rect);
SetBoundsInternal(rect, false);
}
}
@@ -1400,8 +1401,10 @@ void HWNDMessageHandler::ClientAreaSizeChanged() {
// Ignore size changes due to fullscreen windows losing activation.
if (background_fullscreen_hack_ && !sent_window_size_changing_)
return;
- gfx::Size s = GetClientAreaBounds().size();
- delegate_->HandleClientSizeChanged(s);
+ auto ref = msg_handler_weak_factory_.GetWeakPtr();
+ delegate_->HandleClientSizeChanged(GetClientAreaBounds().size());
+ if (!ref)
+ return;
current_window_size_message_++;
sent_window_size_changing_ = false;
@@ -1669,7 +1672,13 @@ void HWNDMessageHandler::OnDisplayChange(UINT bits_per_pixel,
const gfx::Size& screen_size) {
TRACE_EVENT0("ui", "HWNDMessageHandler::OnDisplayChange");
+ base::WeakPtr<HWNDMessageHandler> ref(msg_handler_weak_factory_.GetWeakPtr());
delegate_->HandleDisplayChange();
+
+ // HandleDisplayChange() may result in |this| being deleted.
+ if (!ref)
+ return;
+
// Force a WM_NCCALCSIZE to occur to ensure that we handle auto hide
// taskbars correctly.
SendFrameChanged();
@@ -2587,7 +2596,7 @@ void HWNDMessageHandler::OnSizing(UINT param, RECT* rect) {
return;
gfx::Rect window_rect(*rect);
- SizeRectToAspectRatio(param, &window_rect);
+ SizeWindowToAspectRatio(param, &window_rect);
// TODO(apacible): Account for window borders as part of the aspect ratio.
// https://crbug/869487.
@@ -2929,8 +2938,11 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) {
void HWNDMessageHandler::OnWindowPosChanged(WINDOWPOS* window_pos) {
TRACE_EVENT0("ui", "HWNDMessageHandler::OnWindowPosChanged");
+ base::WeakPtr<HWNDMessageHandler> ref(msg_handler_weak_factory_.GetWeakPtr());
if (DidClientAreaSizeChange(window_pos))
ClientAreaSizeChanged();
+ if (!ref)
+ return;
if (window_pos->flags & SWP_FRAMECHANGED)
SetDwmFrameExtension(DwmFrameState::kOn);
if (window_pos->flags & SWP_SHOWWINDOW) {
@@ -3535,18 +3547,15 @@ void HWNDMessageHandler::DestroyAXSystemCaret() {
ax_system_caret_ = nullptr;
}
-void HWNDMessageHandler::SizeRectToAspectRatio(UINT param,
- gfx::Rect* window_rect) {
+void HWNDMessageHandler::SizeWindowToAspectRatio(UINT param,
+ gfx::Rect* window_rect) {
gfx::Size min_window_size;
gfx::Size max_window_size;
delegate_->GetMinMaxSize(&min_window_size, &max_window_size);
- WindowResizeUtils::SizeMinMaxToAspectRatio(
- aspect_ratio_.value(), &min_window_size, &max_window_size);
min_window_size = delegate_->DIPToScreenSize(min_window_size);
max_window_size = delegate_->DIPToScreenSize(max_window_size);
- WindowResizeUtils::SizeRectToAspectRatio(
- GetWindowResizeHitTest(param), aspect_ratio_.value(), min_window_size,
- max_window_size, window_rect);
+ gfx::SizeRectToAspectRatio(GetWindowResizeEdge(param), aspect_ratio_.value(),
+ min_window_size, max_window_size, window_rect);
}
POINT HWNDMessageHandler::GetCursorPos() const {
diff --git a/chromium/ui/views/win/hwnd_message_handler.h b/chromium/ui/views/win/hwnd_message_handler.h
index 5e5845b4b95..042392a659f 100644
--- a/chromium/ui/views/win/hwnd_message_handler.h
+++ b/chromium/ui/views/win/hwnd_message_handler.h
@@ -18,7 +18,7 @@
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/strings/string16.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/win_util.h"
@@ -36,7 +36,6 @@
#include "ui/views/views_export.h"
#include "ui/views/win/pen_event_processor.h"
#include "ui/views/win/scoped_enable_unadjusted_mouse_events_win.h"
-#include "ui/views/window/window_resize_utils.h"
namespace gfx {
class ImageSkia;
@@ -608,7 +607,7 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
// Updates |rect| to adhere to the |aspect_ratio| of the window. |param|
// refers to the edge of the window being sized.
- void SizeRectToAspectRatio(UINT param, gfx::Rect* rect);
+ void SizeWindowToAspectRatio(UINT param, gfx::Rect* rect);
// Get the cursor position, which may be mocked if running a test
POINT GetCursorPos() const;
@@ -820,7 +819,8 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
// Populated if the cursor position is being mocked for testing purposes.
base::Optional<gfx::Point> mock_cursor_position_;
- ScopedObserver<ui::InputMethod, ui::InputMethodObserver> observer_{this};
+ base::ScopedObservation<ui::InputMethod, ui::InputMethodObserver>
+ observation_{this};
// The WeakPtrFactories below (one inside the
// CR_MSG_MAP_CLASS_DECLARATIONS macro and autohide_factory_) must
diff --git a/chromium/ui/views/window/custom_frame_view.cc b/chromium/ui/views/window/custom_frame_view.cc
index d72f31b31ce..eda68f689da 100644
--- a/chromium/ui/views/window/custom_frame_view.cc
+++ b/chromium/ui/views/window/custom_frame_view.cc
@@ -11,6 +11,7 @@
#include "base/containers/adapters.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
@@ -154,8 +155,7 @@ void CustomFrameView::GetWindowMask(const gfx::Size& size,
if (frame_->IsMaximized() || !ShouldShowTitleBarAndBorder())
return;
- GetDefaultWindowMask(size, frame_->GetCompositor()->device_scale_factor(),
- window_mask);
+ GetDefaultWindowMask(size, window_mask);
}
void CustomFrameView::ResetWindowControls() {
@@ -191,7 +191,6 @@ void CustomFrameView::OnPaint(gfx::Canvas* canvas) {
frame_background_->set_frame_color(GetFrameColor());
frame_background_->set_use_custom_frame(true);
frame_background_->set_is_active(ShouldPaintAsActive());
- frame_background_->set_incognito(false);
const gfx::ImageSkia frame_image = GetFrameImage();
frame_background_->set_theme_image(frame_image);
frame_background_->set_top_area_height(frame_image.height());
@@ -257,7 +256,9 @@ int CustomFrameView::NonClientTopBorderHeight() const {
int CustomFrameView::CaptionButtonY() const {
// Maximized buttons start at window top so that even if their images aren't
// drawn flush with the screen edge, they still obey Fitts' Law.
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
return FrameBorderThickness();
#else
return frame_->IsMaximized() ? FrameBorderThickness() : kFrameShadowThickness;
diff --git a/chromium/ui/views/window/custom_frame_view.h b/chromium/ui/views/window/custom_frame_view.h
index cb702728f20..d5e1adf130f 100644
--- a/chromium/ui/views/window/custom_frame_view.h
+++ b/chromium/ui/views/window/custom_frame_view.h
@@ -156,11 +156,10 @@ class VIEWS_EXPORT CustomFrameView : public NonClientFrameView {
int minimum_title_bar_x_ = 0;
int maximum_title_bar_x_ = -1;
- std::unique_ptr<Widget::PaintAsActiveCallbackList::Subscription>
- paint_as_active_subscription_ =
- frame_->RegisterPaintAsActiveChangedCallback(
- base::BindRepeating(&CustomFrameView::SchedulePaint,
- base::Unretained(this)));
+ base::CallbackListSubscription paint_as_active_subscription_ =
+ frame_->RegisterPaintAsActiveChangedCallback(
+ base::BindRepeating(&CustomFrameView::SchedulePaint,
+ base::Unretained(this)));
DISALLOW_COPY_AND_ASSIGN(CustomFrameView);
};
diff --git a/chromium/ui/views/window/dialog_client_view.cc b/chromium/ui/views/window/dialog_client_view.cc
index 98a32c4a5e4..9ac1f87136c 100644
--- a/chromium/ui/views/window/dialog_client_view.cc
+++ b/chromium/ui/views/window/dialog_client_view.cc
@@ -20,6 +20,7 @@
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_provider.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/view_observer.h"
@@ -54,7 +55,10 @@ gfx::Size GetBoundingSizeForVerticalStack(const gfx::Size& size1,
// Simple container to bubble child view changes up the view hierarchy.
class DialogClientView::ButtonRowContainer : public View {
public:
+ METADATA_HEADER(ButtonRowContainer);
explicit ButtonRowContainer(DialogClientView* owner) : owner_(owner) {}
+ ButtonRowContainer(const ButtonRowContainer&) = delete;
+ ButtonRowContainer& operator=(const ButtonRowContainer&) = delete;
// View:
void ChildPreferredSizeChanged(View* child) override {
@@ -66,10 +70,11 @@ class DialogClientView::ButtonRowContainer : public View {
private:
DialogClientView* const owner_;
-
- DISALLOW_COPY_AND_ASSIGN(ButtonRowContainer);
};
+BEGIN_METADATA(DialogClientView, ButtonRowContainer, View)
+END_METADATA
+
DialogClientView::DialogClientView(Widget* owner, View* contents_view)
: ClientView(owner, contents_view),
button_row_insets_(
@@ -160,7 +165,9 @@ void DialogClientView::Layout() {
bool DialogClientView::AcceleratorPressed(const ui::Accelerator& accelerator) {
DCHECK_EQ(accelerator.key_code(), ui::VKEY_ESCAPE);
- GetWidget()->CloseWithReason(Widget::ClosedReason::kEscKeyPressed);
+ if (DialogDelegate* delegate = GetDialogDelegate())
+ delegate->CancelDialog();
+
return true;
}
diff --git a/chromium/ui/views/window/dialog_delegate.cc b/chromium/ui/views/window/dialog_delegate.cc
index e689e58075d..cf62e629d2e 100644
--- a/chromium/ui/views/window/dialog_delegate.cc
+++ b/chromium/ui/views/window/dialog_delegate.cc
@@ -21,6 +21,7 @@
#include "ui/views/buildflags.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/layout/layout_provider.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/views_features.h"
#include "ui/views/widget/widget.h"
@@ -417,11 +418,14 @@ ax::mojom::Role DialogDelegate::GetAccessibleWindowRole() {
}
int DialogDelegate::GetCornerRadius() const {
- return base::FeatureList::IsEnabled(
- features::kEnableMDRoundedCornersOnDialogs)
- ? LayoutProvider::Get()->GetCornerRadiusMetric(
- views::EMPHASIS_MEDIUM)
- : 2;
+#if defined(OS_MAC)
+ // TODO(crbug.com/1116680): On Mac MODAL_TYPE_WINDOW is implemented using
+ // sheets which causes visual artifacts when corner radius is increased for
+ // modal types. Remove this after this issue has been addressed.
+ if (GetModalType() == ui::MODAL_TYPE_WINDOW)
+ return 2;
+#endif
+ return LayoutProvider::Get()->GetCornerRadiusMetric(views::EMPHASIS_MEDIUM);
}
std::unique_ptr<View> DialogDelegate::DisownFootnoteView() {
@@ -455,4 +459,7 @@ View* DialogDelegateView::GetContentsView() {
return this;
}
+BEGIN_METADATA(DialogDelegateView, View)
+END_METADATA
+
} // namespace views
diff --git a/chromium/ui/views/window/dialog_delegate.h b/chromium/ui/views/window/dialog_delegate.h
index e04889916e2..d07c7becaa7 100644
--- a/chromium/ui/views/window/dialog_delegate.h
+++ b/chromium/ui/views/window/dialog_delegate.h
@@ -14,6 +14,9 @@
#include "base/time/time.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
#include "ui/base/ui_base_types.h"
+#include "ui/views/metadata/metadata_header_macros.h"
+#include "ui/views/metadata/view_factory.h"
+#include "ui/views/view.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -67,6 +70,8 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
};
DialogDelegate();
+ DialogDelegate(const DialogDelegate&) = delete;
+ DialogDelegate& operator=(const DialogDelegate&) = delete;
~DialogDelegate() override;
// Creates a widget at a default location.
@@ -347,8 +352,6 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
// Whether any of the three callbacks just above has been delivered yet, *or*
// one of the Accept/Cancel methods have been called and returned true.
bool already_started_close_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(DialogDelegate);
};
// A DialogDelegate implementation that is-a View. Used to override GetWidget()
@@ -357,18 +360,23 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
// view's hierarchy and is expected to be deleted on DeleteDelegate call.
class VIEWS_EXPORT DialogDelegateView : public DialogDelegate, public View {
public:
+ METADATA_HEADER(DialogDelegateView);
DialogDelegateView();
+ DialogDelegateView(const DialogDelegateView&) = delete;
+ DialogDelegateView& operator=(const DialogDelegateView&) = delete;
~DialogDelegateView() override;
// DialogDelegate:
Widget* GetWidget() override;
const Widget* GetWidget() const override;
View* GetContentsView() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DialogDelegateView);
};
+BEGIN_VIEW_BUILDER(VIEWS_EXPORT, DialogDelegateView, View)
+END_VIEW_BUILDER
+
} // namespace views
+DEFINE_VIEW_BUILDER(VIEWS_EXPORT, DialogDelegateView)
+
#endif // UI_VIEWS_WINDOW_DIALOG_DELEGATE_H_
diff --git a/chromium/ui/views/window/dialog_delegate_unittest.cc b/chromium/ui/views/window/dialog_delegate_unittest.cc
index 426cfde3bb4..d054cb24826 100644
--- a/chromium/ui/views/window/dialog_delegate_unittest.cc
+++ b/chromium/ui/views/window/dialog_delegate_unittest.cc
@@ -162,10 +162,10 @@ TEST_F(DialogTest, OkButtonAccepts) {
EXPECT_TRUE(accepted_);
}
-TEST_F(DialogTest, EscButtonCloses) {
- EXPECT_FALSE(closed_);
+TEST_F(DialogTest, EscButtonCancels) {
+ EXPECT_FALSE(cancelled_);
SimulateKeyPress(ui::VKEY_ESCAPE);
- EXPECT_TRUE(closed_);
+ EXPECT_TRUE(cancelled_);
}
TEST_F(DialogTest, ReturnDirectedToOkButtonPlatformStyle) {
diff --git a/chromium/ui/views/window/frame_background.cc b/chromium/ui/views/window/frame_background.cc
index 50e11d3ccea..6a26e3f6235 100644
--- a/chromium/ui/views/window/frame_background.cc
+++ b/chromium/ui/views/window/frame_background.cc
@@ -105,7 +105,6 @@ void FrameBackground::PaintMaximized(gfx::Canvas* canvas,
ui::NativeTheme::ExtraParams params;
params.frame_top_area.use_custom_frame = use_custom_frame_;
params.frame_top_area.is_active = is_active_;
- params.frame_top_area.incognito = incognito_;
params.frame_top_area.default_background_color = frame_color_;
native_theme->Paint(canvas->sk_canvas(), ui::NativeTheme::kFrameTopArea,
ui::NativeTheme::kNormal,
diff --git a/chromium/ui/views/window/frame_background.h b/chromium/ui/views/window/frame_background.h
index ece082abca5..bf5b4e09c82 100644
--- a/chromium/ui/views/window/frame_background.h
+++ b/chromium/ui/views/window/frame_background.h
@@ -36,9 +36,6 @@ class VIEWS_EXPORT FrameBackground {
// Sets whether the frame to be drawn should have focus.
void set_is_active(bool is_active) { is_active_ = is_active; }
- // Sets whether the frame to be drawn is in incognito mode.
- void set_incognito(bool incognito) { incognito_ = incognito; }
-
// Sets the theme image for the top of the window. May be null (empty).
// Memory is owned by the caller.
void set_theme_image(const gfx::ImageSkia& image) { theme_image_ = image; }
@@ -90,7 +87,6 @@ class VIEWS_EXPORT FrameBackground {
SkColor frame_color_ = 0;
bool use_custom_frame_ = true;
bool is_active_ = true;
- bool incognito_ = false;
gfx::ImageSkia theme_image_;
int theme_image_y_inset_ = 0;
gfx::ImageSkia theme_overlay_image_;
diff --git a/chromium/ui/views/window/frame_caption_button.cc b/chromium/ui/views/window/frame_caption_button.cc
index e8412e3877f..f2a2692ee86 100644
--- a/chromium/ui/views/window/frame_caption_button.cc
+++ b/chromium/ui/views/window/frame_caption_button.cc
@@ -22,6 +22,7 @@
#include "ui/views/animation/ink_drop_ripple.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/highlight_path_generator.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/window/caption_button_layout_constants.h"
#include "ui/views/window/hit_test_utils.h"
@@ -57,16 +58,13 @@ class FrameCaptionButton::HighlightPathGenerator
gfx::Rect bounds = gfx::ToRoundedRect(rect);
bounds.Inset(frame_caption_button_->GetInkdropInsets(bounds.size()));
return gfx::RRectF(gfx::RectF(bounds),
- frame_caption_button_->ink_drop_corner_radius());
+ frame_caption_button_->GetInkDropCornerRadius());
}
private:
FrameCaptionButton* const frame_caption_button_;
};
-// static
-const char FrameCaptionButton::kViewClassName[] = "FrameCaptionButton";
-
FrameCaptionButton::FrameCaptionButton(PressedCallback callback,
CaptionButtonIcon icon,
int hit_test_type)
@@ -111,11 +109,9 @@ SkColor FrameCaptionButton::GetButtonColor(SkColor background_color) {
: gfx::kGoogleGrey700;
const SkColor high_contrast_foreground =
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.
- return color_utils::BlendForMinContrast(default_foreground, background_color,
- high_contrast_foreground, 3.0f)
+ return color_utils::BlendForMinContrast(
+ default_foreground, background_color, high_contrast_foreground,
+ color_utils::kMinimumVisibleContrastRatio)
.color;
}
@@ -168,10 +164,6 @@ void FrameCaptionButton::SetAlpha(int alpha) {
}
}
-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
@@ -192,7 +184,9 @@ void FrameCaptionButton::OnGestureEvent(ui::GestureEvent* event) {
event->StopPropagation();
}
}
- Button::OnGestureEvent(event);
+
+ if (!event->handled())
+ Button::OnGestureEvent(event);
}
views::PaintInfo::ScaleType FrameCaptionButton::GetPaintScaleType() const {
@@ -224,6 +218,21 @@ void FrameCaptionButton::SetBackgroundColor(SkColor background_color) {
UpdateInkDropBaseColor();
}
+SkColor FrameCaptionButton::GetBackgroundColor() const {
+ return background_color_;
+}
+
+void FrameCaptionButton::SetInkDropCornerRadius(int ink_drop_corner_radius) {
+ ink_drop_corner_radius_ = ink_drop_corner_radius;
+ // Changes to |ink_drop_corner_radius| will affect the ink drop. Therefore
+ // this effect is handled by the ink drop.
+ OnPropertyChanged(&ink_drop_corner_radius_, kPropertyEffectsNone);
+}
+
+int FrameCaptionButton::GetInkDropCornerRadius() const {
+ return ink_drop_corner_radius_;
+}
+
void FrameCaptionButton::PaintButtonContents(gfx::Canvas* canvas) {
constexpr SkAlpha kHighlightVisibleOpacity = 0x14;
SkAlpha highlight_alpha = SK_AlphaTRANSPARENT;
@@ -321,4 +330,33 @@ void FrameCaptionButton::UpdateInkDropBaseColor() {
GetColorWithMaxContrast(GetColorWithMaxContrast(button_color)));
}
+DEFINE_ENUM_CONVERTERS(
+ views::CaptionButtonIcon,
+ {{views::CaptionButtonIcon::CAPTION_BUTTON_ICON_MINIMIZE,
+ base::ASCIIToUTF16("CAPTION_BUTTON_ICON_MINIMIZE")},
+ {views::CaptionButtonIcon::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE,
+ base::ASCIIToUTF16("CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE")},
+ {views::CaptionButtonIcon::CAPTION_BUTTON_ICON_CLOSE,
+ base::ASCIIToUTF16("CAPTION_BUTTON_ICON_CLOSE")},
+ {views::CaptionButtonIcon::CAPTION_BUTTON_ICON_LEFT_SNAPPED,
+ base::ASCIIToUTF16("CAPTION_BUTTON_ICON_LEFT_SNAPPED")},
+ {views::CaptionButtonIcon::CAPTION_BUTTON_ICON_RIGHT_SNAPPED,
+ base::ASCIIToUTF16("CAPTION_BUTTON_ICON_RIGHT_SNAPPED")},
+ {views::CaptionButtonIcon::CAPTION_BUTTON_ICON_BACK,
+ base::ASCIIToUTF16("CAPTION_BUTTON_ICON_BACK")},
+ {views::CaptionButtonIcon::CAPTION_BUTTON_ICON_LOCATION,
+ base::ASCIIToUTF16("CAPTION_BUTTON_ICON_LOCATION")},
+ {views::CaptionButtonIcon::CAPTION_BUTTON_ICON_MENU,
+ base::ASCIIToUTF16("CAPTION_BUTTON_ICON_MENU")},
+ {views::CaptionButtonIcon::CAPTION_BUTTON_ICON_ZOOM,
+ base::ASCIIToUTF16("CAPTION_BUTTON_ICON_ZOOM")},
+ {views::CaptionButtonIcon::CAPTION_BUTTON_ICON_COUNT,
+ base::ASCIIToUTF16("CAPTION_BUTTON_ICON_COUNT")}})
+
+BEGIN_METADATA(FrameCaptionButton, Button)
+ADD_PROPERTY_METADATA(SkColor, BackgroundColor, metadata::SkColorConverter)
+ADD_PROPERTY_METADATA(int, InkDropCornerRadius)
+ADD_READONLY_PROPERTY_METADATA(CaptionButtonIcon, Icon)
+END_METADATA
+
} // namespace views
diff --git a/chromium/ui/views/window/frame_caption_button.h b/chromium/ui/views/window/frame_caption_button.h
index dd3733c8dab..6683a0cc09b 100644
--- a/chromium/ui/views/window/frame_caption_button.h
+++ b/chromium/ui/views/window/frame_caption_button.h
@@ -11,6 +11,7 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/focus_ring.h"
+#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/views_export.h"
#include "ui/views/window/caption_button_types.h"
@@ -25,13 +26,14 @@ namespace views {
// close).
class VIEWS_EXPORT FrameCaptionButton : public views::Button {
public:
+ METADATA_HEADER(FrameCaptionButton);
enum Animate { ANIMATE_YES, ANIMATE_NO };
- static const char kViewClassName[];
-
FrameCaptionButton(PressedCallback callback,
CaptionButtonIcon icon,
int hit_test_type);
+ FrameCaptionButton(const FrameCaptionButton&) = delete;
+ FrameCaptionButton& operator=(const FrameCaptionButton&) = delete;
~FrameCaptionButton() override;
// Gets the color to use for a frame caption button.
@@ -56,13 +58,13 @@ class VIEWS_EXPORT FrameCaptionButton : public views::Button {
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;
void SetBackgroundColor(SkColor background_color);
+ SkColor GetBackgroundColor() const;
void set_paint_as_active(bool paint_as_active) {
paint_as_active_ = paint_as_active;
@@ -70,12 +72,10 @@ class VIEWS_EXPORT FrameCaptionButton : public views::Button {
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;
- }
- int ink_drop_corner_radius() const { return ink_drop_corner_radius_; }
+ void SetInkDropCornerRadius(int ink_drop_corner_radius);
+ int GetInkDropCornerRadius() const;
- CaptionButtonIcon icon() const { return icon_; }
+ CaptionButtonIcon GetIcon() const { return icon_; }
const gfx::ImageSkia& icon_image() const { return icon_image_; }
@@ -127,8 +127,6 @@ class VIEWS_EXPORT FrameCaptionButton : public views::Button {
// 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
diff --git a/chromium/ui/views/window/frame_caption_button_unittest.cc b/chromium/ui/views/window/frame_caption_button_unittest.cc
index 2c698f9d5d7..85f5109f535 100644
--- a/chromium/ui/views/window/frame_caption_button_unittest.cc
+++ b/chromium/ui/views/window/frame_caption_button_unittest.cc
@@ -8,6 +8,7 @@
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/hit_test.h"
#include "ui/gfx/color_utils.h"
+#include "ui/views/test/view_metadata_test_utils.h"
#include "ui/views/view.h"
#include "ui/views/window/caption_button_types.h"
@@ -38,4 +39,10 @@ TEST(FrameCaptionButtonTest, DefaultAccessibilityFocus) {
EXPECT_EQ(View::FocusBehavior::ACCESSIBLE_ONLY, button.GetFocusBehavior());
}
+TEST(FrameCaptionButtonTest, MetadataTest) {
+ FrameCaptionButton button(Button::PressedCallback(),
+ CAPTION_BUTTON_ICON_MINIMIZE, HTMINBUTTON);
+ test::TestViewMetadata(&button);
+}
+
} // namespace views
diff --git a/chromium/ui/views/window/native_frame_view.cc b/chromium/ui/views/window/native_frame_view.cc
index 32c5da168ef..12edd20f200 100644
--- a/chromium/ui/views/window/native_frame_view.cc
+++ b/chromium/ui/views/window/native_frame_view.cc
@@ -5,6 +5,7 @@
#include "ui/views/window/native_frame_view.h"
#include "build/build_config.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/widget/native_widget.h"
#include "ui/views/widget/widget.h"
@@ -17,9 +18,6 @@ namespace views {
////////////////////////////////////////////////////////////////////////////////
// NativeFrameView, public:
-// static
-const char NativeFrameView::kViewClassName[] = "NativeFrameView";
-
NativeFrameView::NativeFrameView(Widget* frame) : frame_(frame) {}
NativeFrameView::~NativeFrameView() = default;
@@ -94,8 +92,7 @@ gfx::Size NativeFrameView::GetMaximumSize() const {
return frame_->client_view()->GetMaximumSize();
}
-const char* NativeFrameView::GetClassName() const {
- return kViewClassName;
-}
+BEGIN_METADATA(NativeFrameView, NonClientFrameView)
+END_METADATA
} // namespace views
diff --git a/chromium/ui/views/window/native_frame_view.h b/chromium/ui/views/window/native_frame_view.h
index 93066f31e1e..0b185af8709 100644
--- a/chromium/ui/views/window/native_frame_view.h
+++ b/chromium/ui/views/window/native_frame_view.h
@@ -6,6 +6,8 @@
#define UI_VIEWS_WINDOW_NATIVE_FRAME_VIEW_H_
#include "base/macros.h"
+#include "ui/views/metadata/metadata_header_macros.h"
+#include "ui/views/metadata/view_factory.h"
#include "ui/views/window/non_client_view.h"
namespace views {
@@ -14,9 +16,10 @@ class Widget;
class VIEWS_EXPORT NativeFrameView : public NonClientFrameView {
public:
- static const char kViewClassName[];
-
+ METADATA_HEADER(NativeFrameView);
explicit NativeFrameView(Widget* frame);
+ NativeFrameView(const NativeFrameView&) = delete;
+ NativeFrameView& operator=(const NativeFrameView&) = delete;
~NativeFrameView() override;
// NonClientFrameView overrides:
@@ -34,15 +37,17 @@ class VIEWS_EXPORT NativeFrameView : public NonClientFrameView {
gfx::Size CalculatePreferredSize() const override;
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
- const char* GetClassName() const override;
private:
// Our containing frame.
Widget* frame_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeFrameView);
};
+BEGIN_VIEW_BUILDER(VIEWS_EXPORT, NativeFrameView, NonClientFrameView)
+END_VIEW_BUILDER
+
} // namespace views
+DEFINE_VIEW_BUILDER(VIEWS_EXPORT, NativeFrameView)
+
#endif // UI_VIEWS_WINDOW_NATIVE_FRAME_VIEW_H_
diff --git a/chromium/ui/views/window/non_client_view.h b/chromium/ui/views/window/non_client_view.h
index b8df6d4d2fc..59c3cdfdf99 100644
--- a/chromium/ui/views/window/non_client_view.h
+++ b/chromium/ui/views/window/non_client_view.h
@@ -9,6 +9,8 @@
#include "base/macros.h"
#include "build/build_config.h"
+#include "ui/views/metadata/metadata_header_macros.h"
+#include "ui/views/metadata/view_factory.h"
#include "ui/views/view.h"
#include "ui/views/view_targeter_delegate.h"
@@ -40,6 +42,8 @@ class VIEWS_EXPORT NonClientFrameView : public View,
};
NonClientFrameView();
+ NonClientFrameView(const NonClientFrameView&) = delete;
+ NonClientFrameView& operator=(const NonClientFrameView&) = delete;
~NonClientFrameView() override;
// Used to determine if the frame should be painted as active. Keyed off the
@@ -110,8 +114,6 @@ class VIEWS_EXPORT NonClientFrameView : public View,
// offset into the caption area; the caller will take care of this.
virtual int GetSystemMenuY() const;
#endif
-
- DISALLOW_COPY_AND_ASSIGN(NonClientFrameView);
};
////////////////////////////////////////////////////////////////////////////////
@@ -155,6 +157,8 @@ class VIEWS_EXPORT NonClientView : public View, public ViewTargeterDelegate {
METADATA_HEADER(NonClientView);
explicit NonClientView(ClientView* client_view);
+ NonClientView(const NonClientView&) = delete;
+ NonClientView& operator=(const NonClientView&) = delete;
~NonClientView() override;
// Returns the current NonClientFrameView instance, or NULL if
@@ -245,10 +249,18 @@ class VIEWS_EXPORT NonClientView : public View, public ViewTargeterDelegate {
// The accessible name of this view.
base::string16 accessible_name_;
-
- DISALLOW_COPY_AND_ASSIGN(NonClientView);
};
+BEGIN_VIEW_BUILDER(VIEWS_EXPORT, NonClientFrameView, View)
+END_VIEW_BUILDER
+
+BEGIN_VIEW_BUILDER(VIEWS_EXPORT, NonClientView, View)
+VIEW_BUILDER_VIEW_PROPERTY(NonClientFrameView, FrameView)
+END_VIEW_BUILDER
+
} // namespace views
+DEFINE_VIEW_BUILDER(VIEWS_EXPORT, NonClientFrameView)
+DEFINE_VIEW_BUILDER(VIEWS_EXPORT, NonClientView)
+
#endif // UI_VIEWS_WINDOW_NON_CLIENT_VIEW_H_
diff --git a/chromium/ui/views/window/window_resize_utils.cc b/chromium/ui/views/window/window_resize_utils.cc
deleted file mode 100644
index 5578e3ac267..00000000000
--- a/chromium/ui/views/window/window_resize_utils.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/window/window_resize_utils.h"
-
-#include <algorithm>
-
-#include "base/check_op.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace views {
-
-// static
-void WindowResizeUtils::SizeMinMaxToAspectRatio(float aspect_ratio,
- gfx::Size* min_window_size,
- gfx::Size* max_window_size) {
- DCHECK_GT(aspect_ratio, 0.0f);
-
- // Calculate the height using the min-width and aspect ratio.
- int min_height = min_window_size->width() / aspect_ratio;
- if (min_height < min_window_size->height()) {
- // The supplied width is too small to honor the min size, so use the height
- // to determine the minimum width.
- min_window_size->set_width(min_window_size->height() * aspect_ratio);
- } else {
- min_window_size->set_height(min_height);
- }
-
- // Calculate the height using the max-width and aspect ratio.
- int max_height = max_window_size->width() / aspect_ratio;
- if (max_height > max_window_size->height()) {
- // The supplied width is too large to honor the max size, so use the height
- // to determine the maximum width.
- max_window_size->set_width(max_window_size->height() * aspect_ratio);
- } else {
- max_window_size->set_height(max_height);
- }
-
- DCHECK_GE(max_window_size->width(), min_window_size->width());
- DCHECK_GE(max_window_size->height(), min_window_size->height());
-}
-
-// static
-void WindowResizeUtils::SizeRectToAspectRatio(HitTest param,
- float aspect_ratio,
- const gfx::Size& min_window_size,
- const gfx::Size& max_window_size,
- gfx::Rect* rect) {
- DCHECK_GT(aspect_ratio, 0.0f);
- DCHECK_GE(max_window_size.width(), min_window_size.width());
- DCHECK_GE(max_window_size.height(), min_window_size.height());
-
- float rect_width = 0.0;
- float rect_height = 0.0;
- if (param == HitTest::kLeft || param == HitTest::kRight ||
- param == HitTest::kTopLeft ||
- param == HitTest::kBottomLeft) { /* horizontal axis to pivot */
- rect_width = std::min(max_window_size.width(),
- std::max(rect->width(), min_window_size.width()));
- rect_height = rect_width / aspect_ratio;
- } else { /* vertical axis to pivot */
- rect_height = std::min(max_window_size.height(),
- std::max(rect->height(), min_window_size.height()));
- rect_width = rect_height * aspect_ratio;
- }
-
- // |rect| bounds before sizing to aspect ratio.
- int left = rect->x();
- int top = rect->y();
- int right = rect->right();
- int bottom = rect->bottom();
-
- switch (param) {
- case HitTest::kRight:
- case HitTest::kBottom:
- right = rect_width + left;
- bottom = top + rect_height;
- break;
- case HitTest::kTop:
- right = rect_width + left;
- top = bottom - rect_height;
- break;
- case HitTest::kLeft:
- case HitTest::kTopLeft:
- left = right - rect_width;
- top = bottom - rect_height;
- break;
- case HitTest::kTopRight:
- right = left + rect_width;
- top = bottom - rect_height;
- break;
- case HitTest::kBottomLeft:
- left = right - rect_width;
- bottom = top + rect_height;
- break;
- case HitTest::kBottomRight:
- right = left + rect_width;
- bottom = top + rect_height;
- break;
- }
-
- rect->SetByBounds(left, top, right, bottom);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/window/window_resize_utils.h b/chromium/ui/views/window/window_resize_utils.h
deleted file mode 100644
index 77d3b162b21..00000000000
--- a/chromium/ui/views/window/window_resize_utils.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WINDOW_WINDOW_RESIZE_UTILS_H_
-#define UI_VIEWS_WINDOW_WINDOW_RESIZE_UTILS_H_
-
-#include "base/macros.h"
-#include "ui/views/views_export.h"
-
-namespace gfx {
-class Size;
-class Rect;
-} // namespace gfx
-
-namespace views {
-
-enum class HitTest {
- kBottom,
- kBottomLeft,
- kBottomRight,
- kLeft,
- kRight,
- kTop,
- kTopLeft,
- kTopRight
-};
-
-class VIEWS_EXPORT WindowResizeUtils {
- public:
- // Force the min and max window sizes to adhere to the aspect ratio.
- // |aspect_ratio| must be valid and is found using width / height.
- static void SizeMinMaxToAspectRatio(float aspect_ratio,
- gfx::Size* min_window_size,
- gfx::Size* max_window_size);
-
- // Updates |rect| to adhere to the |aspect_ratio| of the window, if it has
- // been set. |param| refers to the edge of the window being sized.
- // |min_window_size| and |max_window_size| are expected to adhere to the
- // given aspect ratio.
- // |aspect_ratio| must be valid and is found using width / height.
- // TODO(apacible): |max_window_size| is expected to be non-empty. Handle
- // unconstrained max sizes and sizing when windows are maximized.
- static void SizeRectToAspectRatio(HitTest param,
- float aspect_ratio,
- const gfx::Size& min_window_size,
- const gfx::Size& max_window_size,
- gfx::Rect* rect);
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(WindowResizeUtils);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WINDOW_WINDOW_RESIZE_UTILS_H_
diff --git a/chromium/ui/views/window/window_resize_utils_unittest.cc b/chromium/ui/views/window/window_resize_utils_unittest.cc
deleted file mode 100644
index 4b5ba7f85f0..00000000000
--- a/chromium/ui/views/window/window_resize_utils_unittest.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/window/window_resize_utils.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace views {
-
-namespace {
-// Aspect ratio is defined by width / height.
-constexpr float kAspectRatioSquare = 1.0f;
-constexpr float kAspectRatioHorizontal = 2.0f;
-constexpr float kAspectRatioVertical = 0.5f;
-
-const gfx::Size kMinSizeSquare = gfx::Size(10, 10);
-const gfx::Size kMaxSizeSquare = gfx::Size(50, 50);
-
-const gfx::Size kMinSizeHorizontal = gfx::Size(20, 10);
-const gfx::Size kMaxSizeHorizontal = gfx::Size(50, 25);
-
-const gfx::Size kMinSizeVertical = gfx::Size(10, 20);
-const gfx::Size kMaxSizeVertical = gfx::Size(25, 50);
-} // namespace
-
-// Tests resizing of window with a 1:1 aspect ratio. This test also tests the
-// 'pivot points' when resizing, i.e. the opposite side or corner of the
-// window.
-TEST(WindowResizeUtilsTest, SizeToSquareAspectRatio) {
- // Size from the top of the window.
- // |window_rect| within the bounds of kMinSizeSquare and kMaxSizeSquare.
- gfx::Rect window_rect(100, 100, 15, 15);
- WindowResizeUtils::SizeRectToAspectRatio(HitTest::kTop, kAspectRatioSquare,
- kMinSizeSquare, kMaxSizeSquare,
- &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 100, 15, 15));
-
- // Size from the bottom right corner of the window.
- // |window_rect| smaller than kMinSizeSquare.
- window_rect.SetRect(100, 100, 5, 5);
- WindowResizeUtils::SizeRectToAspectRatio(HitTest::kBottomRight,
- kAspectRatioSquare, kMinSizeSquare,
- kMaxSizeSquare, &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 100, kMinSizeSquare.width(),
- kMinSizeSquare.height()));
-
- // Size from the top of the window.
- // |window_rect| larger than kMaxSizeSquare.
- window_rect.SetRect(100, 100, 100, 100);
- WindowResizeUtils::SizeRectToAspectRatio(HitTest::kTop, kAspectRatioSquare,
- kMinSizeSquare, kMaxSizeSquare,
- &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 150, kMaxSizeSquare.width(),
- kMaxSizeSquare.height()));
-
- // Size from the bottom of the window.
- window_rect.SetRect(100, 100, 100, 100);
- WindowResizeUtils::SizeRectToAspectRatio(HitTest::kBottom, kAspectRatioSquare,
- kMinSizeSquare, kMaxSizeSquare,
- &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 100, kMaxSizeSquare.width(),
- kMaxSizeSquare.height()));
-
- // Size from the left of the window.
- window_rect.SetRect(100, 100, 100, 100);
- WindowResizeUtils::SizeRectToAspectRatio(HitTest::kLeft, kAspectRatioSquare,
- kMinSizeSquare, kMaxSizeSquare,
- &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(150, 150, kMaxSizeSquare.width(),
- kMaxSizeSquare.height()));
-
- // Size from the right of the window.
- window_rect.SetRect(100, 100, 100, 100);
- WindowResizeUtils::SizeRectToAspectRatio(HitTest::kRight, kAspectRatioSquare,
- kMinSizeSquare, kMaxSizeSquare,
- &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 100, kMaxSizeSquare.width(),
- kMaxSizeSquare.height()));
-
- // Size from the top left corner of the window.
- window_rect.SetRect(100, 100, 100, 100);
- WindowResizeUtils::SizeRectToAspectRatio(HitTest::kTopLeft,
- kAspectRatioSquare, kMinSizeSquare,
- kMaxSizeSquare, &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(150, 150, kMaxSizeSquare.width(),
- kMaxSizeSquare.height()));
-
- // Size from the top right corner of the window.
- window_rect.SetRect(100, 100, 100, 100);
- WindowResizeUtils::SizeRectToAspectRatio(HitTest::kTopRight,
- kAspectRatioSquare, kMinSizeSquare,
- kMaxSizeSquare, &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 150, kMaxSizeSquare.width(),
- kMaxSizeSquare.height()));
-
- // Size from the bottom left corner of the window.
- window_rect.SetRect(100, 100, 100, 100);
- WindowResizeUtils::SizeRectToAspectRatio(HitTest::kBottomLeft,
- kAspectRatioSquare, kMinSizeSquare,
- kMaxSizeSquare, &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(150, 100, kMaxSizeSquare.width(),
- kMaxSizeSquare.height()));
-}
-
-// Tests the aspect ratio of the gfx::Rect adheres to the horizontal aspect
-// ratio.
-TEST(WindowResizeUtilsTest, SizeToHorizontalAspectRatio) {
- // |window_rect| within bounds of kMinSizeHorizontal and kMaxSizeHorizontal.
- gfx::Rect window_rect(100, 100, 20, 10);
- WindowResizeUtils::SizeRectToAspectRatio(
- HitTest::kTop, kAspectRatioHorizontal, kMinSizeHorizontal,
- kMaxSizeHorizontal, &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 100, 20, 10));
-
- // |window_rect| smaller than kMinSizeHorizontal.
- window_rect.SetRect(100, 100, 5, 5);
- WindowResizeUtils::SizeRectToAspectRatio(
- HitTest::kBottomRight, kAspectRatioHorizontal, kMinSizeHorizontal,
- kMaxSizeHorizontal, &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 100, kMinSizeHorizontal.width(),
- kMinSizeHorizontal.height()));
-
- // |window_rect| greater than kMaxSizeHorizontal.
- window_rect.SetRect(100, 100, 100, 100);
- WindowResizeUtils::SizeRectToAspectRatio(
- HitTest::kTop, kAspectRatioHorizontal, kMinSizeHorizontal,
- kMaxSizeHorizontal, &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 175, kMaxSizeHorizontal.width(),
- kMaxSizeHorizontal.height()));
-}
-
-// Tests the aspect ratio of the gfx::Rect adheres to the vertical aspect ratio.
-TEST(WindowResizeUtilsTest, SizeToVerticalAspectRatio) {
- // |window_rect| within bounds of kMinSizeVertical and kMaxSizeVertical.
- gfx::Rect window_rect(100, 100, 10, 20);
- WindowResizeUtils::SizeRectToAspectRatio(
- HitTest::kBottomRight, kAspectRatioVertical, kMinSizeVertical,
- kMaxSizeVertical, &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 100, 10, 20));
-
- // |window_rect| smaller than kMinSizeVertical.
- window_rect.SetRect(100, 100, 5, 5);
- WindowResizeUtils::SizeRectToAspectRatio(
- HitTest::kBottomRight, kAspectRatioVertical, kMinSizeVertical,
- kMaxSizeVertical, &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 100, kMinSizeVertical.width(),
- kMinSizeVertical.height()));
-
- // |window_rect| greater than kMaxSizeVertical.
- window_rect.SetRect(100, 100, 100, 100);
- WindowResizeUtils::SizeRectToAspectRatio(
- HitTest::kBottomRight, kAspectRatioVertical, kMinSizeVertical,
- kMaxSizeVertical, &window_rect);
- EXPECT_EQ(window_rect, gfx::Rect(100, 100, kMaxSizeVertical.width(),
- kMaxSizeVertical.height()));
-}
-
-} // namespace views
diff --git a/chromium/ui/views/window/window_shape.cc b/chromium/ui/views/window/window_shape.cc
index b9c4d82417a..f94857842b5 100644
--- a/chromium/ui/views/window/window_shape.cc
+++ b/chromium/ui/views/window/window_shape.cc
@@ -10,11 +10,9 @@
namespace views {
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;
+ const SkScalar width = SkIntToScalar(size.width());
+ const SkScalar height = SkIntToScalar(size.height());
window_mask->moveTo(0, 3);
window_mask->lineTo(1, 3);
@@ -41,10 +39,6 @@ void GetDefaultWindowMask(const gfx::Size& size,
window_mask->lineTo(0, height - 3);
window_mask->close();
-
- SkMatrix m;
- m.setScale(sk_scale, sk_scale);
- window_mask->transform(m);
}
} // namespace views
diff --git a/chromium/ui/views/window/window_shape.h b/chromium/ui/views/window/window_shape.h
index bfd6130e4c0..f3219b26708 100644
--- a/chromium/ui/views/window/window_shape.h
+++ b/chromium/ui/views/window/window_shape.h
@@ -18,7 +18,6 @@ namespace views {
// Sets the window mask to a style that most likely matches
// ui/resources/window_*
VIEWS_EXPORT void GetDefaultWindowMask(const gfx::Size& size,
- float scale,
SkPath* window_mask);
} // namespace views
diff --git a/chromium/ui/views_content_client/BUILD.gn b/chromium/ui/views_content_client/BUILD.gn
index 57ca84c094e..bee5a733d2d 100644
--- a/chromium/ui/views_content_client/BUILD.gn
+++ b/chromium/ui/views_content_client/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
component("views_content_client") {
@@ -18,7 +19,7 @@ component("views_content_client") {
"views_content_main_delegate.h",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [ "views_content_client_main_parts_chromeos.cc" ]
}
@@ -31,6 +32,7 @@ component("views_content_client") {
deps = [
"//base",
"//base:i18n",
+ "//build:chromeos_buildflags",
"//content",
"//content/shell:content_shell_lib",
"//third_party/icu",
@@ -53,7 +55,7 @@ component("views_content_client") {
"views_content_client_main_parts_aura.h",
]
- if (!is_chromeos) {
+ if (!is_chromeos_ash) {
sources += [ "views_content_client_main_parts_desktop_aura.cc" ]
}
@@ -63,7 +65,7 @@ component("views_content_client") {
]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [
"//ui/aura:test_support",
"//ui/wm:test_support",
diff --git a/chromium/ui/views_content_client/views_content_client_main_parts_aura.cc b/chromium/ui/views_content_client/views_content_client_main_parts_aura.cc
index bbda25948b5..2c057cc4852 100644
--- a/chromium/ui/views_content_client/views_content_client_main_parts_aura.cc
+++ b/chromium/ui/views_content_client/views_content_client_main_parts_aura.cc
@@ -4,6 +4,7 @@
#include "ui/views_content_client/views_content_client_main_parts_aura.h"
+#include "build/chromeos_buildflags.h"
#include "ui/wm/core/wm_state.h"
namespace ui {
@@ -20,7 +21,7 @@ ViewsContentClientMainPartsAura::~ViewsContentClientMainPartsAura() {
void ViewsContentClientMainPartsAura::ToolkitInitialized() {
ViewsContentClientMainParts::ToolkitInitialized();
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
wm_state_ = std::make_unique<::wm::WMState>();
#endif
}
diff --git a/chromium/ui/web_dialogs/DIR_METADATA b/chromium/ui/web_dialogs/DIR_METADATA
new file mode 100644
index 00000000000..643d2bac512
--- /dev/null
+++ b/chromium/ui/web_dialogs/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals>Core"
+}
diff --git a/chromium/ui/web_dialogs/OWNERS b/chromium/ui/web_dialogs/OWNERS
deleted file mode 100644
index 3605f481f0c..00000000000
--- a/chromium/ui/web_dialogs/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# COMPONENT: Internals>Core
diff --git a/chromium/ui/web_dialogs/web_dialog_ui.cc b/chromium/ui/web_dialogs/web_dialog_ui.cc
index 721d9fdbad8..0007c16227c 100644
--- a/chromium/ui/web_dialogs/web_dialog_ui.cc
+++ b/chromium/ui/web_dialogs/web_dialog_ui.cc
@@ -88,8 +88,10 @@ void WebDialogUIBase::HandleRenderFrameCreated(
delegate->GetWebUIMessageHandlers(&handlers);
}
- if (0 != (web_ui_->GetBindings() & content::BINDINGS_POLICY_WEB_UI))
+ if (content::BINDINGS_POLICY_NONE !=
+ (web_ui_->GetBindings() & content::BINDINGS_POLICY_WEB_UI)) {
render_frame_host->SetWebUIProperty("dialogArguments", dialog_args);
+ }
for (WebUIMessageHandler* handler : handlers)
web_ui_->AddMessageHandler(base::WrapUnique(handler));
diff --git a/chromium/ui/webui/BUILD.gn b/chromium/ui/webui/BUILD.gn
index 4d523c55d21..eb730496f57 100644
--- a/chromium/ui/webui/BUILD.gn
+++ b/chromium/ui/webui/BUILD.gn
@@ -8,10 +8,16 @@ static_library("webui") {
"mojo_bubble_web_ui_controller.h",
"mojo_web_ui_controller.cc",
"mojo_web_ui_controller.h",
+ "untrusted_web_ui_controller.cc",
+ "untrusted_web_ui_controller.h",
+ "untrusted_web_ui_controller_factory.cc",
+ "untrusted_web_ui_controller_factory.h",
"webui_allowlist.cc",
"webui_allowlist.h",
"webui_allowlist_provider.cc",
"webui_allowlist_provider.h",
+ "webui_config.cc",
+ "webui_config.h",
]
deps = [
@@ -21,3 +27,19 @@ static_library("webui") {
"//services/service_manager/public/cpp",
]
}
+
+source_set("test_support") {
+ testonly = true
+
+ sources = [
+ "untrusted_web_ui_browsertest_util.cc",
+ "untrusted_web_ui_browsertest_util.h",
+ ]
+
+ deps = [
+ ":webui",
+ "//base",
+ "//content/public/browser",
+ "//content/test:test_support",
+ ]
+}
diff --git a/chromium/ui/webui/OWNERS b/chromium/ui/webui/OWNERS
index 1dbead9cf13..30003d775a9 100644
--- a/chromium/ui/webui/OWNERS
+++ b/chromium/ui/webui/OWNERS
@@ -1,3 +1,3 @@
file://ui/webui/PLATFORM_OWNERS
-fukino@chromium.org
+noel@chromium.org
diff --git a/chromium/ui/webui/resources/BUILD.gn b/chromium/ui/webui/resources/BUILD.gn
index 988878976b1..6bb3412c605 100644
--- a/chromium/ui/webui/resources/BUILD.gn
+++ b/chromium/ui/webui/resources/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//third_party/closure_compiler/compile_js.gni")
import("//ui/webui/resources/tools/generate_grd.gni")
@@ -14,16 +15,30 @@ generate_grd("build_grd") {
deps = [
"css:build_grdp",
"html:build_grdp",
+ "images:build_grdp",
"js:build_grdp",
"js/cr/ui:build_grdp",
]
grdp_files = [
"$target_gen_dir/css/resources.grdp",
"$target_gen_dir/html/resources.grdp",
+ "$target_gen_dir/images/resources.grdp",
"$target_gen_dir/js/cr/ui/resources.grdp",
"$target_gen_dir/js/resources.grdp",
]
+ if (!is_chromeos_ash && !is_android) {
+ # Roboto Font. Roboto-Regular and Roboto-Light is already available on
+ # Android, and Roboto-Medium is not used on Android. All 6 weights of
+ # Roboto are available on Chrome OS.
+ input_files_base_dir = rebase_path(".", "//")
+ input_files = [
+ "roboto/roboto-bold.woff2",
+ "roboto/roboto-medium.woff2",
+ "roboto/roboto-regular.woff2",
+ ]
+ }
+
if (include_polymer) {
deps += [
"cr_components:build_grdp",
@@ -39,7 +54,7 @@ generate_grd("build_grd") {
]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//third_party/web-animations-js:build_grdp" ]
grdp_files += [ "$root_gen_dir/third_party/web-animations-js/web_animations_resources.grdp" ]
}
diff --git a/chromium/ui/webui/resources/cr_components/BUILD.gn b/chromium/ui/webui/resources/cr_components/BUILD.gn
index 5d11cb92984..c58c0846275 100644
--- a/chromium/ui/webui/resources/cr_components/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/BUILD.gn
@@ -2,14 +2,16 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//third_party/closure_compiler/compile_js.gni")
-import("//tools/grit/preprocess_grit.gni")
+import("//tools/grit/preprocess_if_expr.gni")
import("//ui/webui/resources/tools/generate_grd.gni")
import("//ui/webui/webui_features.gni")
preprocess_folder =
"$root_gen_dir/ui/webui/resources/preprocessed/cr_components"
preprocess_gen_manifest = "preprocessed_gen_manifest.json"
+preprocess_mojom_manifest = "preprocessed_mojom_manifest.json"
preprocess_polymer2_manifest = "preprocessed_polymer2_manifest.json"
preprocess_src_manifest = "preprocessed_src_manifest.json"
@@ -17,8 +19,52 @@ generate_grd("build_grdp") {
grd_prefix = "cr_components"
out_grd = "$target_gen_dir/${grd_prefix}_resources.grdp"
deps = [ ":preprocess" ]
+ input_files_base_dir = rebase_path(".", "//")
+ input_files = [
+ "customize_themes/colorize.svg",
+ "customize_themes/brush.svg",
+ ]
+ if (is_chromeos_ash) {
+ input_files += [
+ "chromeos/multidevice_setup/all_set_1x.svg",
+ "chromeos/multidevice_setup/all_set_2x.svg",
+ "chromeos/multidevice_setup/start_setup_icon_1x.png",
+ "chromeos/multidevice_setup/start_setup_icon_2x.png",
+ "chromeos/cellular_setup/error_1x.png",
+ "chromeos/cellular_setup/error_2x.png",
+ "chromeos/cellular_setup/final_page_success_1x.png",
+ "chromeos/cellular_setup/final_page_success_2x.png",
+ "chromeos/cellular_setup/psim_1x.png",
+ "chromeos/cellular_setup/psim_2x.png",
+ "chromeos/cellular_setup/esim_1x.png",
+ "chromeos/cellular_setup/esim_2x.png",
+ "chromeos/cellular_setup/default_esim_profile.svg",
+ "chromeos/network/cellular_0_with_x.svg",
+ "chromeos/network/cellular_0.svg",
+ "chromeos/network/cellular_1.svg",
+ "chromeos/network/cellular_2.svg",
+ "chromeos/network/cellular_3.svg",
+ "chromeos/network/cellular_4.svg",
+ "chromeos/network/cellular_off.svg",
+ "chromeos/network/ethernet.svg",
+ "chromeos/network/vpn.svg",
+ "chromeos/network/wifi_0_with_x.svg",
+ "chromeos/network/wifi_0.svg",
+ "chromeos/network/wifi_1.svg",
+ "chromeos/network/wifi_2.svg",
+ "chromeos/network/wifi_3.svg",
+ "chromeos/network/wifi_4.svg",
+ "chromeos/network/wifi_off.svg",
+ "chromeos/network_health/test_canceled.png",
+ "chromeos/network_health/test_failed.png",
+ "chromeos/network_health/test_not_run.png",
+ "chromeos/network_health/test_passed.png",
+ "chromeos/network_health/test_warning.png",
+ ]
+ }
manifest_files = [
"$target_gen_dir/$preprocess_gen_manifest",
+ "$target_gen_dir/$preprocess_mojom_manifest",
"$target_gen_dir/$preprocess_polymer2_manifest",
"$target_gen_dir/$preprocess_src_manifest",
]
@@ -28,12 +74,13 @@ generate_grd("build_grdp") {
group("preprocess") {
public_deps = [
":preprocess_generated",
+ ":preprocess_mojom",
":preprocess_polymer2",
":preprocess_src",
]
}
-preprocess_grit("preprocess_src") {
+preprocess_if_expr("preprocess_src") {
in_folder = "./"
out_folder = "$preprocess_folder"
out_manifest = "$target_gen_dir/$preprocess_src_manifest"
@@ -48,14 +95,22 @@ preprocess_grit("preprocess_src") {
}
}
-preprocess_grit("preprocess_generated") {
+preprocess_if_expr("preprocess_mojom") {
+ deps =
+ [ "//ui/webui/resources/cr_components/customize_themes:mojom_webui_js" ]
+ in_folder = "$root_gen_dir/mojom-webui/ui/webui/resources/cr_components"
+ out_folder = "$preprocess_folder"
+ out_manifest = "$target_gen_dir/$preprocess_mojom_manifest"
+ in_files = [ "customize_themes/customize_themes.mojom-webui.js" ]
+}
+
+preprocess_if_expr("preprocess_generated") {
deps = [ ":polymer3_elements" ]
in_folder = target_gen_dir
out_folder = "$preprocess_folder"
out_manifest = "$target_gen_dir/$preprocess_gen_manifest"
in_files = [
"customize_themes/customize_themes.js",
- "customize_themes/customize_themes.mojom-lite.js",
"customize_themes/theme_icon.js",
"managed_footnote/managed_footnote.m.js",
"omnibox/cr_autocomplete_match_list.js",
@@ -79,28 +134,51 @@ preprocess_grit("preprocess_generated") {
]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
in_files += [
"chromeos/bluetooth/bluetooth_dialog.m.js",
"chromeos/cellular_setup/activation_code_page.m.js",
"chromeos/cellular_setup/base_page.m.js",
"chromeos/cellular_setup/button_bar.m.js",
"chromeos/cellular_setup/cellular_setup_delegate.m.js",
+ "chromeos/cellular_setup/cellular_setup_icons.m.js",
"chromeos/cellular_setup/cellular_setup.m.js",
"chromeos/cellular_setup/cellular_types.m.js",
+ "chromeos/cellular_setup/confirmation_code_page.m.js",
"chromeos/cellular_setup/esim_flow_ui.m.js",
"chromeos/cellular_setup/final_page.m.js",
"chromeos/cellular_setup/mojo_interface_provider.m.js",
+ "chromeos/cellular_setup/esim_manager_listener_behavior.m.js",
+ "chromeos/cellular_setup/esim_manager_utils.m.js",
"chromeos/cellular_setup/profile_discovery_list_item.m.js",
"chromeos/cellular_setup/profile_discovery_list_page.m.js",
"chromeos/cellular_setup/provisioning_page.m.js",
"chromeos/cellular_setup/psim_flow_ui.m.js",
"chromeos/cellular_setup/setup_selection_flow.m.js",
- "chromeos/cellular_setup/sim_detect_page.m.js",
+ "chromeos/cellular_setup/cellular_eid_popup.m.js",
+ "chromeos/cellular_setup/setup_loading_page.m.js",
"chromeos/cellular_setup/subflow_behavior.m.js",
"chromeos/cellular_setup/webview_post_util.m.js",
+ "chromeos/multidevice_setup/mojo_api.m.js",
+ "chromeos/multidevice_setup/fake_mojo_service.m.js",
+ "chromeos/multidevice_setup/button_bar.m.js",
+ "chromeos/multidevice_setup/multidevice_setup.m.js",
+ "chromeos/multidevice_setup/multidevice_setup_browser_proxy.m.js",
+ "chromeos/multidevice_setup/multidevice_setup_delegate.m.js",
+ "chromeos/multidevice_setup/password_page.m.js",
+ "chromeos/multidevice_setup/setup_succeeded_page.m.js",
+ "chromeos/multidevice_setup/start_setup_page.m.js",
+ "chromeos/multidevice_setup/ui_page_container_behavior.m.js",
+ "chromeos/multidevice_setup/multidevice_setup_shared_css.m.js",
+ "chromeos/multidevice_setup/ui_page.m.js",
+ "chromeos/multidevice_setup/icons.m.js",
+ "chromeos/network_health/network_health_container.m.js",
+ "chromeos/network_health/network_health_summary.m.js",
+ "chromeos/network_health/network_health_mojo.m.js",
"chromeos/network_health/network_diagnostics.m.js",
"chromeos/network_health/network_diagnostics_mojo.m.js",
+ "chromeos/network_health/network_diagnostics_types.m.js",
+ "chromeos/network_health/routine_group.m.js",
"chromeos/network/cr_policy_network_behavior_mojo.m.js",
"chromeos/network/cr_policy_network_indicator_mojo.m.js",
"chromeos/network/mojo_interface_provider.m.js",
@@ -109,6 +187,7 @@ preprocess_grit("preprocess_generated") {
"chromeos/network/network_config_element_behavior.m.js",
"chromeos/network/network_config_input.m.js",
"chromeos/network/network_config.m.js",
+ "chromeos/network/cellular_utils.m.js",
"chromeos/network/network_config_select.m.js",
"chromeos/network/network_config_toggle.m.js",
"chromeos/network/network_icon.m.js",
@@ -138,7 +217,7 @@ preprocess_grit("preprocess_generated") {
}
}
-preprocess_grit("preprocess_polymer2") {
+preprocess_if_expr("preprocess_polymer2") {
in_folder = "./"
out_folder = "$preprocess_folder"
out_manifest = "$target_gen_dir/$preprocess_polymer2_manifest"
@@ -146,7 +225,7 @@ preprocess_grit("preprocess_polymer2") {
"managed_footnote/managed_footnote.html",
"managed_footnote/managed_footnote.js",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
if (!optimize_webui) {
in_files += [
"chromeos/bluetooth/bluetooth_dialog.html",
@@ -193,16 +272,23 @@ preprocess_grit("preprocess_polymer2") {
"chromeos/cellular_setup/button_bar.js",
"chromeos/cellular_setup/cellular_setup_delegate.html",
"chromeos/cellular_setup/cellular_setup_delegate.js",
+ "chromeos/cellular_setup/cellular_setup_icons.html",
"chromeos/cellular_setup/cellular_setup.html",
"chromeos/cellular_setup/cellular_setup.js",
"chromeos/cellular_setup/cellular_types.html",
"chromeos/cellular_setup/cellular_types.js",
+ "chromeos/cellular_setup/confirmation_code_page.html",
+ "chromeos/cellular_setup/confirmation_code_page.js",
"chromeos/cellular_setup/esim_flow_ui.html",
"chromeos/cellular_setup/esim_flow_ui.js",
"chromeos/cellular_setup/final_page.html",
"chromeos/cellular_setup/final_page.js",
"chromeos/cellular_setup/mojo_interface_provider.html",
"chromeos/cellular_setup/mojo_interface_provider.js",
+ "chromeos/cellular_setup/esim_manager_listener_behavior.html",
+ "chromeos/cellular_setup/esim_manager_listener_behavior.js",
+ "chromeos/cellular_setup/esim_manager_utils.html",
+ "chromeos/cellular_setup/esim_manager_utils.js",
"chromeos/cellular_setup/profile_discovery_list_item.html",
"chromeos/cellular_setup/profile_discovery_list_item.js",
"chromeos/cellular_setup/profile_discovery_list_page.html",
@@ -213,8 +299,10 @@ preprocess_grit("preprocess_polymer2") {
"chromeos/cellular_setup/psim_flow_ui.js",
"chromeos/cellular_setup/setup_selection_flow.html",
"chromeos/cellular_setup/setup_selection_flow.js",
- "chromeos/cellular_setup/sim_detect_page.html",
- "chromeos/cellular_setup/sim_detect_page.js",
+ "chromeos/cellular_setup/cellular_eid_popup.html",
+ "chromeos/cellular_setup/cellular_eid_popup.js",
+ "chromeos/cellular_setup/setup_loading_page.html",
+ "chromeos/cellular_setup/setup_loading_page.js",
"chromeos/cellular_setup/subflow_behavior.html",
"chromeos/cellular_setup/subflow_behavior.js",
"chromeos/cellular_setup/webview_post_util.html",
@@ -251,8 +339,16 @@ preprocess_grit("preprocess_polymer2") {
"chromeos/network_health/network_diagnostics.js",
"chromeos/network_health/network_diagnostics_mojo.html",
"chromeos/network_health/network_diagnostics_mojo.js",
+ "chromeos/network_health/network_diagnostics_types.html",
+ "chromeos/network_health/network_diagnostics_types.js",
+ "chromeos/network_health/network_health_container.html",
+ "chromeos/network_health/network_health_container.js",
"chromeos/network_health/network_health_summary.html",
"chromeos/network_health/network_health_summary.js",
+ "chromeos/network_health/network_health_mojo.html",
+ "chromeos/network_health/network_health_mojo.js",
+ "chromeos/network_health/routine_group.html",
+ "chromeos/network_health/routine_group.js",
"chromeos/network/mojo_interface_provider.html",
"chromeos/network/mojo_interface_provider.js",
"chromeos/network/network_icon.html",
@@ -260,6 +356,8 @@ preprocess_grit("preprocess_polymer2") {
"chromeos/network/network_icons.html",
"chromeos/network/network_listener_behavior.html",
"chromeos/network/network_listener_behavior.js",
+ "chromeos/network/cellular_utils.html",
+ "chromeos/network/cellular_utils.js",
"chromeos/network/network_list.html",
"chromeos/network/network_list_item.html",
"chromeos/network/network_list_item.js",
@@ -294,7 +392,7 @@ group("closure_compile") {
"omnibox:closure_compile",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "chromeos:closure_compile" ]
}
}
@@ -306,7 +404,7 @@ group("polymer3_elements") {
"managed_footnote:managed_footnote_module",
"omnibox:web_components",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
public_deps += [ "chromeos:polymer3_elements" ]
}
}
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html
index b3fa0b940eb..629b5723708 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html
@@ -12,7 +12,7 @@
<cr-policy-indicator indicator-type="[[getPolicyIndicatorType_(model)]]">
</cr-policy-indicator>
<cr-expand-button expanded="{{expanded_}}"
- alt="[[i18n('certificateManagerExpandA11yLabel')]]">
+ aria-label="[[i18n('certificateManagerExpandA11yLabel')]]">
</cr-expand-button>
</div>
<template is="dom-if" if="[[expanded_]]">
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_browser_proxy.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_browser_proxy.js
index 57e3428ec13..f4ca727001b 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_browser_proxy.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_browser_proxy.js
@@ -17,6 +17,7 @@ import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
*
* @typedef {{
* certProfileId: string,
+ * certProfileName: string,
* isDeviceWide: boolean,
* status: string,
* stateId: number,
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.html
index fba5360e091..6aae708405c 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.html
@@ -29,21 +29,41 @@
</div>
<div slot="body">
<div class="two-line">
- <div class="label">[[i18n('certificateProvisioningProfile')]]</div>
- <div class="value">[[model.certProfileId]]</div>
+ <div class="label" aria-describedby="certProfileName">
+ [[i18n('certificateProvisioningProfileName')]]
+ </div>
+ <div class="value" id="certProfileName" aria-hidden="true">
+ [[model.certProfileName]]
+ </div>
+ </div>
+ <div class="two-line">
+ <div class="label" aria-describedby="certProfileId">
+ [[i18n('certificateProvisioningProfileId')]]
+ </div>
+ <div class="value" id="certProfileId" aria-hidden="true">
+ [[model.certProfileId]]
+ </div>
</div>
<div class="button-box">
<div class="two-line flex">
- <div class="label">[[i18n('certificateProvisioningStatus')]]</div>
- <span class="value">[[model.status]]</span>
+ <div class="label" aria-describedby="status">
+ [[i18n('certificateProvisioningStatus')]]
+ </div>
+ <span class="value" id="status" aria-hidden="true">
+ [[model.status]]
+ </span>
</div>
<cr-button id="refresh" role="button" on-click="onRefresh_">
[[i18n('certificateProvisioningRefresh')]]
</cr-button>
</div>
<div class="two-line">
- <div class="label">[[i18n('certificateProvisioningLastUpdate')]]</div>
- <div class="value">[[model.timeSinceLastUpdate]]</div>
+ <div class="label" aria-describedby="timeSinceLastUpdate">
+ [[i18n('certificateProvisioningLastUpdate')]]
+ </div>
+ <div class="value" id="timeSinceLastUpdate" aria-hidden="true">
+ [[model.timeSinceLastUpdate]]
+ </div>
</div>
<hr></hr>
<cr-expand-button expanded="{{advancedExpanded_}}"
@@ -52,12 +72,20 @@
</cr-expand-button>
<iron-collapse id="advancedInfo" opened="[[advancedExpanded_]]">
<div class="two-line">
- <div class="label">[[i18n('certificateProvisioningStatusId')]]</div>
- <div class="value">[[model.stateId]]</div>
+ <div class="label" aria-describedby="stateId">
+ [[i18n('certificateProvisioningStatusId')]]
+ </div>
+ <div class="value" id="stateId" aria-hidden="true">
+ [[model.stateId]]
+ </div>
</div>
<div class="two-line">
- <div class="label">[[i18n('certificateProvisioningPublicKey')]]</div>
- <div class="value">[[model.publicKey]]</div>
+ <div class="label" aria-describedby="publicKey">
+ [[i18n('certificateProvisioningPublicKey')]]
+ </div>
+ <div class="value" id="publicKey" aria-hidden="true">
+ [[model.publicKey]]
+ </div>
</div>
</iron-collapse>
</div>
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.js
index c04422d3534..a601972e4b0 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.js
@@ -36,6 +36,10 @@ Polymer({
advancedExpanded_: Boolean,
},
+ close() {
+ /** @type {!CrDialogElement} */ (this.$.dialog).close();
+ },
+
/** @private */
onRefresh_() {
CertificateProvisioningBrowserProxyImpl.getInstance()
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_entry.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_entry.html
index c2efcda5f2f..70f3a5623af 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_entry.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_entry.html
@@ -8,7 +8,7 @@
}
</style>
<div class="cert-box">
- <div class="flex" tabindex="0">[[model.certProfileId]]</div>
+ <div class="flex" tabindex="0">[[model.certProfileName]]</div>
<cr-icon-button class="icon-more-vert" id="dots"
title="[[i18n('moreActions')]]" on-click="onDotsClick_">
</cr-icon-button>
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_list.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_list.js
index 3e7d02518c5..26c5ae7f916 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_list.js
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_list.js
@@ -83,6 +83,10 @@ Polymer({
});
if (newDialogModel) {
this.provisioningDetailsDialogModel_ = newDialogModel;
+ } else {
+ // Close cert provisioning process details dialog if the process is no
+ // longer in the list eg. when process completed successfully.
+ this.$$('certificate-provisioning-details-dialog').close();
}
},
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn
index 125836958c8..4f185562fc1 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn
@@ -8,18 +8,15 @@ assert(is_chromeos, "Only ChromeOS components belong here.")
group("closure_compile") {
deps = [
- "bluetooth:closure_compile",
"bluetooth:closure_compile_module",
- "cellular_setup:closure_compile",
"cellular_setup:closure_compile_module",
"multidevice_setup:closure_compile",
+ "multidevice_setup:closure_compile_module",
"network:closure_compile",
"network:closure_compile_module",
- "network_health:closure_compile",
"network_health:closure_compile_module",
"quick_unlock:closure_compile",
"quick_unlock:closure_compile_module",
- "smb_shares:closure_compile",
"smb_shares:closure_compile_module",
]
}
@@ -28,6 +25,7 @@ group("polymer3_elements") {
public_deps = [
"bluetooth:polymer3_elements",
"cellular_setup:polymer3_elements",
+ "multidevice_setup:polymer3_elements",
"network:polymer3_elements",
"network_health:polymer3_elements",
"quick_unlock:polymer3_elements",
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth/BUILD.gn
index 16484cc89e9..784546d7be5 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth/BUILD.gn
@@ -8,29 +8,6 @@ import("//ui/webui/resources/tools/js_modulizer.gni")
assert(is_chromeos, "Bluetooth dialog is Chrome OS only.")
-js_type_check("closure_compile") {
- deps = [ ":bluetooth_dialog" ]
-}
-
-js_library("bluetooth_dialog") {
- deps = [
- "//third_party/polymer/v1_0/components-chromium/iron-resizable-behavior:iron-resizable-behavior-extracted",
- "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
- "//ui/webui/resources/cr_elements/cr_input:cr_input",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:i18n_behavior",
- ]
- externs_list = chrome_extension_public_externs + [
- "$externs_path/bluetooth.js",
- "$externs_path/bluetooth_private.js",
- ]
- extra_sources = [
- "$interfaces_path/bluetooth_interface.js",
- "$interfaces_path/bluetooth_private_interface.js",
- ]
-}
-
js_type_check("closure_compile_module") {
is_polymer3 = true
deps = [ ":bluetooth_dialog.m" ]
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn
index 0c87689c71c..49b33d3a8e5 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn
@@ -9,175 +9,28 @@ import("../os_cr_components.gni")
assert(is_chromeos, "CellularSetup UI is Chrome OS only.")
-js_type_check("closure_compile") {
- deps = [
- ":activation_code_page",
- ":base_page",
- ":button_bar",
- ":cellular_setup",
- ":cellular_setup_delegate",
- ":cellular_types",
- ":final_page",
- ":mojo_interface_provider",
- ":profile_discovery_list_item",
- ":profile_discovery_list_page",
- ":provisioning_page",
- ":psim_flow_ui",
- ":setup_selection_flow",
- ":sim_detect_page",
- ":webview_post_util",
- ]
-}
-
-js_library("button_bar") {
- deps = [
- ":cellular_types",
- "//ui/webui/resources/js:i18n_behavior",
- ]
-}
-
-js_library("base_page") {
- deps = [ "//ui/webui/resources/js:i18n_behavior" ]
-}
-
-js_library("sim_detect_page") {
- deps = [
- ":base_page",
- ":cellular_setup_delegate",
- ]
-}
-
-js_library("webview_post_util") {
- deps = [ "//ui/webui/resources/js:cr" ]
- externs_list = [
- "$externs_path/chrome_extensions.js",
- "$externs_path/webview_tag.js",
- ]
-}
-
-js_library("provisioning_page") {
- deps = [
- ":base_page",
- ":cellular_setup_delegate",
- ":webview_post_util",
- ]
- externs_list = [
- "$externs_path/chrome_extensions.js",
- "$externs_path/webview_tag.js",
- ]
-}
-
-js_library("final_page") {
- deps = [ ":base_page" ]
-}
-
-js_library("activation_code_page") {
- deps = [
- ":cellular_setup_delegate",
- ":subflow_behavior",
- "//ui/webui/resources/js:i18n_behavior",
- ]
-}
-
-js_library("profile_discovery_list_page") {
- deps = [
- "//third_party/polymer/v1_0/components-chromium/iron-list:iron-list-extracted",
- "//ui/webui/resources/js:i18n_behavior",
- ]
-}
-
-js_library("profile_discovery_list_item") {
- deps = [ "//ui/webui/resources/js:i18n_behavior" ]
-}
-
-js_library("psim_flow_ui") {
- deps = [
- ":cellular_setup_delegate",
- ":cellular_types",
- ":final_page",
- ":mojo_interface_provider",
- ":provisioning_page",
- ":sim_detect_page",
- ":subflow_behavior",
- "//chromeos/services/cellular_setup/public/mojom:mojom_js_library_for_compile",
- "//ui/webui/resources/js:assert.m",
- "//ui/webui/resources/js:i18n_behavior",
- ]
-}
-
-js_library("esim_flow_ui") {
- deps = [
- ":activation_code_page",
- ":cellular_setup_delegate",
- ":profile_discovery_list_item",
- ":profile_discovery_list_page",
- ":subflow_behavior",
- "//ui/webui/resources/js:i18n_behavior",
- ]
-}
-
-js_library("setup_selection_flow") {
- deps = [
- ":cellular_types",
- ":subflow_behavior",
- "//ui/webui/resources/js:i18n_behavior",
- ]
-}
-
-js_library("subflow_behavior") {
- deps = [
- ":cellular_types",
- "//ui/webui/resources/js:cr",
- ]
-}
-
-js_library("cellular_types") {
- deps = [ "//ui/webui/resources/js:cr" ]
-}
-
-js_library("cellular_setup_delegate") {
- deps = [ "//ui/webui/resources/js:cr" ]
-}
-
-js_library("cellular_setup") {
- deps = [
- ":button_bar",
- ":cellular_setup_delegate",
- ":cellular_types",
- ":esim_flow_ui",
- ":psim_flow_ui",
- ":setup_selection_flow",
- "//ui/webui/resources/js:i18n_behavior",
- ]
-}
-
-js_library("mojo_interface_provider") {
- deps = [
- "//chromeos/services/cellular_setup/public/mojom:mojom_js_library_for_compile",
- "//ui/webui/resources/js:cr",
- ]
-}
-
-# Polymer3 files
-
js_type_check("closure_compile_module") {
is_polymer3 = true
deps = [
":activation_code_page.m",
":base_page.m",
":button_bar.m",
+ ":cellular_eid_popup.m",
":cellular_setup.m",
":cellular_setup_delegate.m",
":cellular_types.m",
+ ":confirmation_code_page.m",
":esim_flow_ui.m",
+ ":esim_manager_listener_behavior.m",
+ ":esim_manager_utils.m",
":final_page.m",
":mojo_interface_provider.m",
":profile_discovery_list_item.m",
":profile_discovery_list_page.m",
":provisioning_page.m",
":psim_flow_ui.m",
+ ":setup_loading_page.m",
":setup_selection_flow.m",
- ":sim_detect_page.m",
":subflow_behavior.m",
":webview_post_util.m",
]
@@ -207,15 +60,28 @@ js_library("activation_code_page.m") {
deps = [
":cellular_setup_delegate.m",
":subflow_behavior.m",
+ "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/js:i18n_behavior.m",
]
extra_deps = [ ":activation_code_page_module" ]
}
+js_library("confirmation_code_page.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.m.js" ]
+ deps = [
+ "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
+ "//ui/webui/resources/js:i18n_behavior.m",
+ ]
+ extra_deps = [ ":confirmation_code_page_module" ]
+}
+
js_library("profile_discovery_list_item.m") {
sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.m.js" ]
- deps = [ "//ui/webui/resources/js:i18n_behavior.m" ]
+ deps = [
+ "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
+ "//ui/webui/resources/js:i18n_behavior.m",
+ ]
extra_deps = [ ":profile_discovery_list_item_module" ]
}
@@ -237,6 +103,18 @@ js_library("mojo_interface_provider.m") {
extra_deps = [ ":modulize" ]
}
+js_library("esim_manager_utils.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.m.js" ]
+ deps = [ ":mojo_interface_provider.m" ]
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("esim_manager_listener_behavior.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.m.js" ]
+ deps = [ ":mojo_interface_provider.m" ]
+ extra_deps = [ ":modulize" ]
+}
+
js_library("webview_post_util.m") {
sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.m.js" ]
deps = []
@@ -247,13 +125,14 @@ js_library("webview_post_util.m") {
extra_deps = [ ":modulize" ]
}
-js_library("sim_detect_page.m") {
- sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.m.js" ]
+js_library("setup_loading_page.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.m.js" ]
deps = [
":base_page.m",
":cellular_setup_delegate.m",
+ "//ui/webui/resources/js:assert.m",
]
- extra_deps = [ ":sim_detect_page_module" ]
+ extra_deps = [ ":setup_loading_page_module" ]
}
js_library("provisioning_page.m") {
@@ -279,6 +158,7 @@ js_library("button_bar.m") {
":cellular_types.m",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/js:i18n_behavior.m",
+ "//ui/webui/resources/js/cr/ui:focus_without_ink.m",
]
extra_deps = [ ":button_bar_module" ]
}
@@ -307,7 +187,7 @@ js_library("psim_flow_ui.m") {
":final_page.m",
":mojo_interface_provider.m",
":provisioning_page.m",
- ":sim_detect_page.m",
+ ":setup_loading_page.m",
":subflow_behavior.m",
"//chromeos/services/cellular_setup/public/mojom:mojom_js_library_for_compile",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
@@ -323,11 +203,17 @@ js_library("esim_flow_ui.m") {
":activation_code_page.m",
":cellular_setup_delegate.m",
":cellular_types.m",
+ ":confirmation_code_page.m",
+ ":esim_manager_utils.m",
":final_page.m",
+ ":mojo_interface_provider.m",
":profile_discovery_list_item.m",
":profile_discovery_list_page.m",
":subflow_behavior.m",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ "//ui/webui/resources/cr_components/chromeos/network:cellular_utils.m",
+ "//ui/webui/resources/cr_components/chromeos/network:network_listener_behavior.m",
+ "//ui/webui/resources/js:assert.m",
"//ui/webui/resources/js:i18n_behavior.m",
]
extra_deps = [ ":esim_flow_ui_module" ]
@@ -343,6 +229,12 @@ js_library("setup_selection_flow.m") {
extra_deps = [ ":setup_selection_flow_module" ]
}
+js_library("cellular_eid_popup.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.m.js" ]
+ deps = [ "//ui/webui/resources/js:i18n_behavior.m" ]
+ extra_deps = [ ":cellular_eid_popup_module" ]
+}
+
js_library("cellular_setup.m") {
sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.m.js" ]
deps = [
@@ -352,6 +244,8 @@ js_library("cellular_setup.m") {
":esim_flow_ui.m",
":psim_flow_ui.m",
":setup_selection_flow.m",
+ "//ui/webui/resources/cr_components/chromeos/network:cellular_utils.m",
+ "//ui/webui/resources/cr_components/chromeos/network:mojo_interface_provider.m",
"//ui/webui/resources/js:i18n_behavior.m",
]
extra_deps = [ ":cellular_setup_module" ]
@@ -362,7 +256,10 @@ group("polymer3_elements") {
":activation_code_page_module",
":base_page_module",
":button_bar_module",
+ ":cellular_eid_popup_module",
+ ":cellular_setup_icons_module",
":cellular_setup_module",
+ ":confirmation_code_page_module",
":esim_flow_ui_module",
":final_page_module",
":modulize",
@@ -370,8 +267,8 @@ group("polymer3_elements") {
":profile_discovery_list_page_module",
":provisioning_page_module",
":psim_flow_ui_module",
+ ":setup_loading_page_module",
":setup_selection_flow_module",
- ":sim_detect_page_module",
]
}
@@ -407,9 +304,17 @@ polymer_modulizer("button_bar") {
auto_imports = cr_components_chromeos_auto_imports
}
-polymer_modulizer("sim_detect_page") {
- js_file = "sim_detect_page.js"
- html_file = "sim_detect_page.html"
+polymer_modulizer("confirmation_code_page") {
+ js_file = "confirmation_code_page.js"
+ html_file = "confirmation_code_page.html"
+ html_type = "dom-module"
+ namespace_rewrites = cr_components_chromeos_namespace_rewrites
+ auto_imports = cr_components_chromeos_auto_imports
+}
+
+polymer_modulizer("setup_loading_page") {
+ js_file = "setup_loading_page.js"
+ html_file = "setup_loading_page.html"
html_type = "dom-module"
namespace_rewrites = cr_components_chromeos_namespace_rewrites
auto_imports = cr_components_chromeos_auto_imports
@@ -463,6 +368,14 @@ polymer_modulizer("setup_selection_flow") {
auto_imports = cr_components_chromeos_auto_imports
}
+polymer_modulizer("cellular_eid_popup") {
+ js_file = "cellular_eid_popup.js"
+ html_file = "cellular_eid_popup.html"
+ html_type = "dom-module"
+ namespace_rewrites = cr_components_chromeos_namespace_rewrites
+ auto_imports = cr_components_chromeos_auto_imports
+}
+
polymer_modulizer("cellular_setup") {
js_file = "cellular_setup.js"
html_file = "cellular_setup.html"
@@ -471,11 +384,19 @@ polymer_modulizer("cellular_setup") {
auto_imports = cr_components_chromeos_auto_imports
}
+polymer_modulizer("cellular_setup_icons") {
+ js_file = "cellular_setup_icons.m.js"
+ html_file = "cellular_setup_icons.html"
+ html_type = "iron-iconset"
+}
+
js_modulizer("modulize") {
input_files = [
"cellular_types.js",
"cellular_setup_delegate.js",
"mojo_interface_provider.js",
+ "esim_manager_utils.js",
+ "esim_manager_listener_behavior.js",
"subflow_behavior.js",
"webview_post_util.js",
]
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.html
index 8e9086e9818..8a6243f857c 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.html
@@ -1,13 +1,17 @@
<link rel="import" href="../../../html/polymer.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-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
<link rel="import" href="../../../html/i18n_behavior.html">
<link rel="import" href="../../../cr_elements/cr_input/cr_input.html">
<link rel="import" href="base_page.html">
<link rel="import" href="cellular_setup_delegate.html">
+<link rel="import" href="cellular_setup_icons.html">
<dom-module id="activation-code-page">
<template>
- <style>
+ <style include="iron-positioning">
[slot='page-body'] {
height: 300px;
margin-top: -20px;
@@ -35,13 +39,8 @@
background-color: transparent;
}
- #scanSuccessMessage {
- color: green;
- font-size: medium;
- }
-
- #scanSuccessMessage:hover {
- cursor: default;
+ cr-button[disabled] {
+ background-color: transparent;
}
.center {
@@ -51,34 +50,65 @@
transform: translateY(-50%) translateX(-50%);
}
+ .width-92 {
+ width: 92%;
+ }
+
.label {
font-weight: 500;
}
.button-image {
- height: 20px;
margin-inline-end: 8px;
- width: 20px;
}
- #useCameraAgainButton {
- font-weight: 500;
- left: 50%;
- margin-top: 16px;
- transform: translateX(-50%);
- }
-
- #scanSuccessImage {
- height: 20px;
+ .scan-finish-image {
position: absolute;
- width: 20px;
}
- #scanSuccessMessage {
+ .scan-finish-message {
padding-inline-end: 0;
padding-inline-start: 30px;
}
+ .scan-finish-message:hover {
+ cursor: default;
+ }
+
+ .blue-icon {
+ --iron-icon-fill-color: #1A73E8;
+ }
+
+ #scanSucessHeader {
+ --iron-icon-fill-color: #1E8E3E;
+ margin-bottom: 8px;
+ }
+
+ #scanSuccessMessage {
+ color: green;
+ font-size: medium;
+ }
+
+ #scanFailureHeader {
+ --iron-icon-fill-color: #D93025;
+ margin-bottom: 4px;
+ }
+
+ #scanFailureMessage {
+ color: var(--google-red-600);
+ }
+
+ #useCameraAgainButton {
+ display: block;
+ font-weight: 500;
+ text-align: center;
+ }
+
+ #tryAgainButton {
+ display: block;
+ text-align: center;
+ }
+
#switchCameraButton {
background-color: rgba(0, 0, 0, 0.04);
border-radius: 4px;
@@ -90,60 +120,107 @@
z-index: 2;
}
- #switchCameraButton img {
+ #switchCameraButton iron-icon {
filter: brightness(2.1);
+ --iron-icon-fill-color: #5F6368;
+ }
+
+ paper-spinner-lite {
+ height: 20px;
+ position: absolute;
+ right: 16px;
+ top: 24px;
+ width: 20px;
+ }
+
+ #loadingMessage {
+ bottom: 0;
+ color: var(--google-grey-refresh-500);
+ font-size: var(--cr-form-field-label-font-size);
+ letter-spacing: .4px;
+ line-height: var(--cr-form-field-label-line-height);
+ position: absolute;
}
</style>
<base-page>
<div slot="page-body">
<span id="scanQrCodeDescription">
- [[i18n('scanQRCode')]]
+ [[getDescription_(showNoProfilesMessage, cameraCount_ )]]
</span>
- <div id="esimQrCodeDetection">
- <cr-button id="switchCameraButton"
- on-click="onSwitchCameraButtonPressed_"
- hidden$="[[isUiElementHidden_(UiElement.SWITCH_CAMERA, state_, hasMultipleCameras_)]]"
- disabled="[[isUiElementDisabled_(UiElement.SWITCH_CAMERA, state_)]]">
- <img class="button-image"
- src="activation_code_page_switch_camera.svg"
- aria-hidden="true">
- [[i18n('switchCamera')]]
- </cr-button>
- <video id="video"
- hidden$="[[isUiElementHidden_(UiElement.VIDEO, state_)]]">
- </video>
- <div class="center" id="startScanningContainer"
- hidden$="[[isUiElementHidden_(UiElement.START_SCANNING, state_)]]">
- <cr-button class="label"
- id="startScanningButton"
- on-click="startScanning_"
- aria-describedby="scanQrCodeDescription">
- <img class="button-image"
- src="activation_code_page_camera.svg"
- aria-hidden="true">
- [[i18n('useCamera')]]
+ <template is="dom-if"
+ if="[[isScanningAvailable_(cameraCount_, qrCodeDetector_.*)]]" restamp>
+ <div id="esimQrCodeDetection">
+ <cr-button id="switchCameraButton"
+ on-click="onSwitchCameraButtonPressed_"
+ hidden$="[[isUiElementHidden_(UiElement.SWITCH_CAMERA, state_, cameraCount_)]]"
+ disabled="[[isUiElementDisabled_(UiElement.SWITCH_CAMERA, state_, showBusy)]]">
+ <iron-icon class="button-image" icon="cellular-setup:switch-camera"></iron-icon>
+ [[i18n('switchCamera')]]
</cr-button>
- </div>
- <div class="center" id="scanSuccessContainer"
- hidden$="[[isUiElementHidden_(UiElement.SCAN_SUCCESS, state_)]]">
- <div>
- <img id="scanSuccessImage"
- src="activation_code_page_checked.svg"
- aria-hidden="true">
- <span class="label" id="scanSuccessMessage">
- [[i18n('scanQRCodeSuccess')]]
- </span>
+ <video id="video"
+ hidden$="[[isUiElementHidden_(UiElement.VIDEO, state_)]]">
+ </video>
+ <div class="center" id="startScanningContainer" class="blue-icon"
+ hidden$="[[isUiElementHidden_(UiElement.START_SCANNING, state_)]]">
+ <cr-button class="label"
+ id="startScanningButton"
+ on-click="startScanning_"
+ aria-describedby="scanQrCodeDescription"
+ disabled="[[isUiElementDisabled_(UiElement.START_SCANNING, state_, showBusy)]]">
+ <iron-icon class="button-image" icon="cellular-setup:camera"></iron-icon>
+ [[i18n('useCamera')]]
+ </cr-button>
+ </div>
+ <div class="center" id="scanFinishContainer"
+ hidden$="[[isUiElementHidden_(UiElement.SCAN_FINISH, state_)]]">
+ <div>
+ <div id="scanSuccessContainer"
+ hidden$="[[isUiElementHidden_(UiElement.SCAN_SUCCESS, state_)]]">
+ <div id=scanSucessHeader>
+ <iron-icon class="scan-finish-image" icon="cellular-setup:checked"></iron-icon>
+ <span class="label scan-finish-message" id="scanSuccessMessage">
+ [[i18n('scanQRCodeSuccess')]]
+ </span>
+ </div>
+ <cr-button id="useCameraAgainButton" class="blue-icon"
+ on-click="startScanning_"
+ disabled="[[isUiElementDisabled_(UiElement.SCAN_SUCCESS, state_, showBusy)]]">
+ <iron-icon class="button-image" icon="cellular-setup:camera"></iron-icon>
+ [[i18n('qrCodeUseCameraAgain')]]
+ </cr-button>
+ </div>
+ <div id="scanFailureContainer"
+ hidden$="[[isUiElementHidden_(UiElement.SCAN_FAILURE, state_)]]">
+ <div id="scanFailureHeader" class="blue-icon">
+ <iron-icon class="scan-finish-image" icon="cellular-setup:error"></iron-icon>
+ <span class="label scan-finish-message" id="scanFailureMessage">
+ [[i18n('scanQrCodeError')]]
+ </span>
+ </div>
+ <cr-button id="tryAgainButton" class="blue-icon"
+ on-click="startScanning_"
+ disabled="[[isUiElementDisabled_(UiElement.SCAN_FAILURE, state_, showBusy)]]">
+ <iron-icon class="button-image" icon="cellular-setup:try-again"></iron-icon>
+ [[i18n('qrCodeRetry')]]
+ </cr-button>
+ </div>
+ </div>
</div>
- <cr-button id="useCameraAgainButton"
- on-click="startScanning_">
- [[i18n('qrCodeRetry')]]
- </cr-button>
</div>
- </div>
- <cr-input id="activationCode"
+ </template>
+ <div id="activationCodeContainer" class$="[[computeActivationCodeClass_(cameraCount_)]]">
+ <cr-input id="activationCode"
label="[[i18n('activationCode')]]"
- value="{{activationCode_}}">
- </cr-input>
+ value="{{activationCode}}"
+ disabled="[[showBusy]]">
+ </cr-input>
+ <paper-spinner-lite active
+ hidden$="[[!showBusy]]">
+ </paper-spinner-lite>
+ <div id="loadingMessage" hidden$="[[!showBusy]]">
+ [[i18n('scanQrCodeLoading')]]
+ </div>
+ </div>
</div>
</base-page>
</template>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js
index eb391054d34..23a6bf848ad 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js
@@ -16,17 +16,26 @@ const PageState = {
SWITCHING_CAM_USER_TO_ENVIRONMENT: 4,
SWITCHING_CAM_ENVIRONMENT_TO_USER: 5,
SUCCESS: 6,
+ FAILURE: 7,
};
/** @enum {number} */
const UiElement = {
START_SCANNING: 1,
VIDEO: 2,
- SCAN_SUCCESS: 3,
- SWITCH_CAMERA: 4,
+ SWITCH_CAMERA: 3,
+ SCAN_FINISH: 4,
+ SCAN_SUCCESS: 5,
+ SCAN_FAILURE: 6,
};
/**
+ * barcode format used by |BarcodeDetector|
+ * @private {string}
+ */
+const QR_CODE_FORMAT = 'qr_code';
+
+/**
* Page in eSIM Setup flow that accepts activation code. User has option for
* manual entry or scan a QR code.
*/
@@ -36,13 +45,26 @@ Polymer({
behaviors: [I18nBehavior],
properties: {
- /** @private */
- activationCode_: {
+ activationCode: {
type: String,
- value: '',
+ notify: true,
observer: 'onActivationCodeChanged_',
},
+ showError: {
+ type: Boolean,
+ notify: true,
+ observer: 'onShowErrorChanged_',
+ },
+
+ /**
+ * Indicates the UI is busy with an operation and cannot be interacted with.
+ */
+ showBusy: {
+ type: Boolean,
+ value: false,
+ },
+
/**
* @type {!PageState}
* @private
@@ -50,13 +72,14 @@ Polymer({
state_: {
type: Object,
value: PageState,
+ observer: 'onStateChanged_',
},
/** @private */
- hasMultipleCameras_: {
- type: Boolean,
- value: false,
- observer: 'onHasMultipleCamerasChanged_',
+ cameraCount_: {
+ type: Number,
+ value: 0,
+ observer: 'onHasCameraCountChanged_',
},
/**
@@ -70,6 +93,11 @@ Polymer({
type: Object,
value: UiElement,
},
+
+ /** @private */
+ showNoProfilesMessage: {
+ type: Boolean,
+ }
},
/**
@@ -90,9 +118,25 @@ Polymer({
*/
qrCodeDetectorTimer_: null,
+ /**
+ * TODO(crbug.com/1093185): add type |BarcodeDetector| when externs
+ * becomes available
+ * @private
+ */
+ qrCodeDetector_: null,
+
+ /**
+ * TODO(crbug.com/1093185): add type |BarcodeDetector| when externs
+ * becomes available
+ * @suppress {undefinedVars|missingProperties}
+ * @private
+ */
+ barcodeDetectorClass_: BarcodeDetector,
+
/** @override */
ready() {
this.setMediaDevices(navigator.mediaDevices);
+ this.initBarcodeDetector();
this.state_ = PageState.INITIAL;
},
@@ -105,7 +149,36 @@ Polymer({
clearTimeout(this.qrCodeDetectorTimer_);
}
this.mediaDevices_.removeEventListener(
- 'devicechange', this.updateHasMultipleCameras_.bind(this));
+ 'devicechange', this.updateCameraCount_.bind(this));
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ isScanningAvailable_() {
+ return this.cameraCount_ > 0 && !!this.qrCodeDetector_;
+ },
+
+ /**
+ * TODO(crbug.com/1093185): Remove suppression when shape_detection extern
+ * definitions become available.
+ * @suppress {undefinedVars|missingProperties}
+ * @private
+ */
+ async initBarcodeDetector() {
+ const formats = await this.barcodeDetectorClass_.getSupportedFormats();
+
+ if (!formats || formats.length === 0) {
+ this.qrCodeDetector_ = null;
+ return;
+ }
+
+ const qrCodeFormat = formats.find(format => format === QR_CODE_FORMAT);
+ if (qrCodeFormat) {
+ this.qrCodeDetector_ =
+ new this.barcodeDetectorClass_({formats: [QR_CODE_FORMAT]});
+ }
},
/**
@@ -113,25 +186,42 @@ Polymer({
*/
setMediaDevices(mediaDevices) {
this.mediaDevices_ = mediaDevices;
+ this.updateCameraCount_();
this.mediaDevices_.addEventListener(
- 'devicechange', this.updateHasMultipleCameras_.bind(this));
+ 'devicechange', this.updateCameraCount_.bind(this));
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeActivationCodeClass_() {
+ return this.isScanningAvailable_() ? 'relative' : 'center width-92';
},
/** @private */
- updateHasMultipleCameras_() {
- this.mediaDevices_.enumerateDevices().then(devices => {
- const numVideoInputDevices =
- devices.filter(device => device.kind === 'videoinput').length;
- this.hasMultipleCameras_ = numVideoInputDevices > 1;
- });
+ updateCameraCount_() {
+ if (!this.mediaDevices_ || !this.mediaDevices_.enumerateDevices) {
+ this.cameraCount_ = 0;
+ return;
+ }
+
+ this.mediaDevices_.enumerateDevices()
+ .then(devices => {
+ this.cameraCount_ =
+ devices.filter(device => device.kind === 'videoinput').length;
+ })
+ .catch(e => {
+ this.cameraCount_ = 0;
+ });
},
/** @private */
- onHasMultipleCamerasChanged_() {
+ onHasCameraCountChanged_() {
// If the user was using an environment-facing camera and it was removed,
// restart scanning with the user-facing camera.
if ((this.state_ === PageState.SCANNING_ENVIRONMENT_FACING) &&
- !this.hasMultipleCameras_) {
+ this.cameraCount_ === 1) {
this.state_ = PageState.SWITCHING_CAM_ENVIRONMENT_TO_USER;
this.startScanning_();
}
@@ -157,8 +247,8 @@ Polymer({
})
.then(stream => {
this.stream_ = stream;
- if (stream) {
- const video = this.$.video;
+ if (this.stream_) {
+ const video = this.$$('#video');
video.srcObject = stream;
video.play();
}
@@ -166,38 +256,41 @@ Polymer({
oldStream.getTracks()[0].stop();
}
- this.activationCode_ = '';
+ this.activationCode = '';
this.state_ = useUserFacingCamera ?
PageState.SCANNING_USER_FACING :
PageState.SCANNING_ENVIRONMENT_FACING;
- this.detectQrCode_(stream);
+ if (this.stream_) {
+ this.detectQrCode_();
+ }
+ })
+ .catch(e => {
+ this.state_ = PageState.FAILURE;
});
},
/**
* Continuously checks stream if it contains a QR code. If a QR code is
- * detected, activationCode_ is set to the QR code's value and the detection
+ * detected, activationCode is set to the QR code's value and the detection
* stops.
- * @param {MediaStream} stream
* @private
*/
- async detectQrCode_(stream) {
+ async detectQrCode_() {
try {
this.qrCodeDetectorTimer_ = setInterval(
(async function() {
- const capturer = new ImageCapture(stream.getVideoTracks()[0]);
+ const capturer = new ImageCapture(this.stream_.getVideoTracks()[0]);
const frame = await capturer.grabFrame();
const activationCode = await this.detectActivationCode_(frame);
if (activationCode) {
clearTimeout(this.qrCodeDetectorTimer_);
- this.activationCode_ = activationCode;
+ this.activationCode = activationCode;
}
}).bind(this),
QR_CODE_DETECTION_INTERVAL_MS);
} catch (error) {
- // TODO(crbug.com/1093185): Update the UI in response to the error.
- console.log(error);
+ this.state_ = PageState.FAILURE;
}
},
@@ -210,12 +303,11 @@ Polymer({
* @private
*/
async detectActivationCode_(frame) {
- const qrCodeDetector = new BarcodeDetector({
- formats: [
- 'qr_code',
- ]
- });
- const qrCodes = await qrCodeDetector.detect(frame);
+ if (!this.qrCodeDetector_) {
+ return null;
+ }
+
+ const qrCodes = await this.qrCodeDetector_.detect(frame);
if (qrCodes.length > 0) {
return qrCodes[0].rawValue;
}
@@ -224,14 +316,15 @@ Polymer({
/** @private */
onActivationCodeChanged_() {
- const activationCode = this.validateActivationCode_(this.activationCode_);
+ const activationCode = this.validateActivationCode_(this.activationCode);
this.fire('activation-code-updated', {activationCode: activationCode});
- // TODO(crbug.com/1093185): Handle if activation code is invalid.
if (activationCode) {
if (this.stream_) {
this.stream_.getTracks()[0].stop();
}
this.state_ = PageState.SUCCESS;
+ } else {
+ this.state_ = PageState.FAILURE;
}
},
@@ -261,34 +354,56 @@ Polymer({
this.startScanning_();
},
+ /** @private */
+ onShowErrorChanged_() {
+ if (this.showError) {
+ this.state_ = PageState.FAILURE;
+ }
+ },
+
+ /** @private */
+ onStateChanged_() {
+ if (this.state_ !== PageState.FAILURE) {
+ this.showError = false;
+ }
+ },
+
/**
* @param {UiElement} uiElement
* @param {PageState} state
- * @param {boolean} hasMultipleCameras
+ * @param {number} cameraCount
* @private
*/
- isUiElementHidden_(uiElement, state, hasMultipleCameras) {
+ isUiElementHidden_(uiElement, state, cameraCount) {
switch (uiElement) {
case UiElement.START_SCANNING:
return state !== PageState.INITIAL;
case UiElement.VIDEO:
return state !== PageState.SCANNING_USER_FACING &&
state !== PageState.SCANNING_ENVIRONMENT_FACING;
- case UiElement.SCAN_SUCCESS:
- return state !== PageState.SUCCESS;
case UiElement.SWITCH_CAMERA:
const isScanning = state === PageState.SCANNING_USER_FACING ||
state === PageState.SCANNING_ENVIRONMENT_FACING;
- return !(isScanning && hasMultipleCameras);
+ return !(isScanning && this.cameraCount_ > 1);
+ case UiElement.SCAN_FINISH:
+ return state !== PageState.SUCCESS && state !== PageState.FAILURE;
+ case UiElement.SCAN_SUCCESS:
+ return state !== PageState.SUCCESS;
+ case UiElement.SCAN_FAILURE:
+ return state !== PageState.FAILURE;
}
},
/**
* @param {UiElement} uiElement
* @param {PageState} state
+ * @param {boolean} showBusy
* @private
*/
- isUiElementDisabled_(uiElement, state) {
+ isUiElementDisabled_(uiElement, state, showBusy) {
+ if (showBusy) {
+ return true;
+ }
switch (uiElement) {
case UiElement.SWITCH_CAMERA:
return state === PageState.SWITCHING_CAM_USER_TO_ENVIRONMENT ||
@@ -297,4 +412,16 @@ Polymer({
return false;
}
},
+
+ /**
+ * @return {string}
+ * @private
+ */
+ getDescription_() {
+ if (!this.isScanningAvailable_()) {
+ return this.i18n('scanQRCodeEnterActivationCode');
+ }
+ return this.showNoProfilesMessage ? this.i18n('scanQRCodeNoProfiles') :
+ this.i18n('scanQRCode');
+ },
});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_camera.svg b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_camera.svg
deleted file mode 100644
index 9e8e0fe771c..00000000000
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_camera.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="a" maskUnits="userSpaceOnUse" x="1" y="2" width="18" height="16"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.667 4.167h-2.642L12.5 2.5h-5L5.975 4.167H3.334c-.917 0-1.667.75-1.667 1.666v10c0 .917.75 1.667 1.667 1.667h13.333c.917 0 1.667-.75 1.667-1.667v-10c0-.916-.75-1.666-1.667-1.666zm0 11.666H3.334v-10h13.333v10zm-10-5A3.332 3.332 0 1 1 10 14.166a3.332 3.332 0 0 1-3.333-3.333z" fill="#fff"/></mask><g mask="url(#a)"><path fill="#1A73E8" d="M0 0h20v20H0z"/></g></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_checked.svg b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_checked.svg
deleted file mode 100644
index adf445fe700..00000000000
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_checked.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.707 7.293a1 1 0 0 0-1.414 0L9 10.586 7.707 9.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 0-1.414z" fill="#1E8E3E"/><path fill-rule="evenodd" clip-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-2a6 6 0 1 0 0-12 6 6 0 0 0 0 12z" fill="#1E8E3E"/></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_switch_camera.svg b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_switch_camera.svg
deleted file mode 100644
index ba6127d7e39..00000000000
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_switch_camera.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M7 9V7H4.802A5.996 5.996 0 0 1 10 4a6 6 0 0 1 5.917 5h2.021c-.491-3.945-3.853-7-7.93-7a7.992 7.992 0 0 0-6.009 2.712L4 3H2v6h5zm5.938 2v2h2.198a5.996 5.996 0 0 1-5.198 3 6 6 0 0 1-5.917-5H2c.492 3.945 3.853 7 7.93 7a7.992 7.992 0 0 0 6.009-2.712V17h2v-6h-5zM10 12a2 2 0 1 0 0-4 2 2 0 0 0 0 4z" fill="#5F6368"/></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.html
index 0a0e2fe045e..2f8fc2a6930 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.html
@@ -2,10 +2,12 @@
<link rel="import" href="../../../cr_elements/shared_vars_css.html">
<link rel="import" href="../../../html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/cr_components/chromeos/cellular_setup/cellular_setup_icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<dom-module id="base-page">
<template>
- <style>
+ <style include="iron-positioning">
#title {
color: var(--google-grey-900);
font-weight: normal;
@@ -21,11 +23,21 @@
height: 256px;
width: 100%;
}
+
+ #message iron-icon {
+ padding-inline-end: 4px;
+ }
</style>
<template is="dom-if" if="[[isTitleShown_(title)]]" restamp>
<h3 id="title">[[getTitle_(title)]]</h3>
</template>
- <div id="message">[[message]]</div>
+ <div id="message">
+ <iron-icon
+ icon$="cellular-setup:[[messageIcon]]"
+ hidden$="[[!isMessageIconShown_(messageIcon)]]">
+ </iron-icon>
+ [[message]]
+ </div>
<slot name="page-body"></slot>
</template>
<script src="base_page.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.js
index edaac70c770..3efd9ecd352 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.js
@@ -22,6 +22,16 @@ Polymer({
* @type {string}
*/
message: String,
+
+ /**
+ * Name for the cellular-setup iconset iron-icon displayed beside message.
+ *
+ * @type {string}
+ */
+ messageIcon: {
+ type: String,
+ value: '',
+ }
},
/**
@@ -38,5 +48,13 @@ Polymer({
*/
isTitleShown_() {
return !!this.title;
+ },
+
+ /**
+ * @returns {boolean}
+ * @private
+ */
+ isMessageIconShown_() {
+ return !!this.messageIcon;
}
});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html
index a3908c637a4..54b88a776fb 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html
@@ -6,6 +6,7 @@
<link rel="import" href="../../../cr_elements/shared_style_css.html">
<link rel="import" href="../../../cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html">
<dom-module id="button-bar">
@@ -44,26 +45,12 @@
hidden$="[[isButtonHidden_(Button.TRY_AGAIN, buttonState.*)]]">
[[i18n('tryAgain')]]
</cr-button>
- <cr-button id="done"
+ <cr-button id="forward"
class="action-button"
- on-click="onDoneButtonClicked_"
- disabled="[[isButtonDisabled_(Button.DONE, buttonState.*)]]"
- hidden$="[[isButtonHidden_(Button.DONE, buttonState.*)]]">
- [[i18n('done')]]
- </cr-button>
- <cr-button id="skipDiscovery"
- class="action-button"
- on-click="onNextButtonClicked_"
- disabled="[[isButtonDisabled_(Button.SKIP_DISCOVERY, buttonState.*)]]"
- hidden$="[[isButtonHidden_(Button.SKIP_DISCOVERY, buttonState.*)]]">
- [[i18n('skipDiscovery')]]
- </cr-button>
- <cr-button id="next"
- class="action-button"
- on-click="onNextButtonClicked_"
- disabled="[[isButtonDisabled_(Button.NEXT, buttonState.*)]]"
- hidden$="[[isButtonHidden_(Button.NEXT, buttonState.*)]]">
- [[i18n('next')]]
+ on-click="onForwardButtonClicked_"
+ disabled="[[isButtonDisabled_(Button.FORWARD, buttonState.*)]]"
+ hidden$="[[isButtonHidden_(Button.FORWARD, buttonState.*)]]">
+ [[forwardButtonLabel]]
</cr-button>
</template>
<script src="button_bar.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.js
index 05b648c5b6f..21dd2c9de8c 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.js
@@ -15,7 +15,10 @@ Polymer({
* Sets the states of all buttons
* @type {!cellularSetup.ButtonBarState}
*/
- buttonState: {type: Object, value: {}},
+ buttonState: {
+ type: Object,
+ value: {},
+ },
/**
* @type {!cellularSetup.Button}
@@ -24,6 +27,11 @@ Polymer({
type: Object,
value: cellularSetup.Button,
},
+
+ forwardButtonLabel: {
+ type: String,
+ value: '',
+ }
},
/**
@@ -32,8 +40,7 @@ Polymer({
* @private
*/
isButtonHidden_(buttonName) {
- const state = this.getButtonBarState_(buttonName);
- return state === cellularSetup.ButtonState.HIDDEN;
+ return !this.getButtonBarState_(buttonName);
},
/**
@@ -43,7 +50,19 @@ Polymer({
*/
isButtonDisabled_(buttonName) {
const state = this.getButtonBarState_(buttonName);
- return state === cellularSetup.ButtonState.SHOWN_BUT_DISABLED;
+ return state === cellularSetup.ButtonState.DISABLED;
+ },
+
+ focusDefaultButton() {
+ const buttons = this.shadowRoot.querySelectorAll('cr-button');
+ // Focus the first non-disabled, non-hidden button from the end.
+ for (let i = buttons.length - 1; i >= 0; i--) {
+ const button = buttons.item(i);
+ if (!button.disabled && !button.hidden) {
+ cr.ui.focusWithoutInk(button);
+ return;
+ }
+ }
},
/** @private */
@@ -62,12 +81,7 @@ Polymer({
},
/** @private */
- onDoneButtonClicked_() {
- this.fire('complete-flow-requested');
- },
-
- /** @private */
- onNextButtonClicked_() {
+ onForwardButtonClicked_() {
this.fire('forward-nav-requested');
},
@@ -83,17 +97,13 @@ Polymer({
return this.buttonState.backward;
case cellularSetup.Button.CANCEL:
return this.buttonState.cancel;
- case cellularSetup.Button.DONE:
- return this.buttonState.done;
- case cellularSetup.Button.NEXT:
- return this.buttonState.next;
+ case cellularSetup.Button.FORWARD:
+ return this.buttonState.forward;
case cellularSetup.Button.TRY_AGAIN:
return this.buttonState.tryAgain;
- case cellularSetup.Button.SKIP_DISCOVERY:
- return this.buttonState.skipDiscovery;
default:
assertNotReached();
- return cellularSetup.ButtonState.SHOWN_AND_ENABLED;
+ return cellularSetup.ButtonState.ENABLED;
}
}
});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.html
new file mode 100644
index 00000000000..b045ae54b57
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.html
@@ -0,0 +1,96 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.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">
+
+<dom-module id="cellular-eid-popup">
+ <template>
+ <style include="cr-shared-style iron-flex">
+ :host {
+ background-color: white;
+ border-radius: 4px;
+ box-shadow: 0 2px 5px rgba(0,0,0,0.18);
+ margin: 34px 0 0 12px;
+ position: absolute;
+ width: 275px;
+ z-index: 1;
+ }
+
+ .cellular-network-list-header {
+ border-top: var(--cr-separator-line);
+ padding: 16px 0 8px 0;
+ }
+
+ .body {
+ margin-top: 6px;
+ }
+
+ .cellular-network-content {
+ margin: 8px 0 8px 32px;
+ }
+
+ .cellular-not-setup {
+ color: var(--google-grey-700);
+ font-size: smaller;
+ margin-bottom: 16px;
+ }
+
+ .header {
+ display: flex;
+ justify-content: space-between;
+ }
+
+ .title {
+ align-self: center;
+ }
+
+ #container {
+ padding: 8px 16px;
+ }
+
+ #closeBtn {
+ align-self: center;
+ cursor: pointer;
+ }
+
+ #qrCodeCanvas {
+ width: 100%;
+ }
+
+ #eid {
+ margin-top: 15px;
+ }
+ </style>
+ <div id="container"
+ class="dialog"
+ tabindex="1"
+ aria-labelledby="eidTitle"
+ aria-describedby="eidDescription">
+ <div class="header">
+ <div id="eidTitle" class="title" arian-hidden="true">
+ [[i18n('eidPopupTitle')]]
+ </div>
+ <cr-icon-button
+ id="eidPopupCloseIcon"
+ iron-icon="cr:close"
+ title="[[i18n('closeEidPopupButtonLabel')]]"
+ aria-label="[[i18n('closeEidPopupButtonLabel')]]"
+ on-click="onCloseTap_">
+ </cr-icon-button>
+ </div>
+ <div class="body">
+ <div id="eidDescription" arian-hidden="true">
+ [[i18n('eidPopupDescription')]]
+ </div>
+ <div id="eid">[[eid_]]</div>
+ <canvas id="qrCodeCanvas"
+ width="[[canvasSize_]]"
+ height="[[canvasSize_]]">
+ </canvas>
+ </div>
+ </div>
+ </template>
+ <script src="cellular_eid_popup.js"></script>
+</dom-module> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.js
new file mode 100644
index 00000000000..983d4bbe040
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.js
@@ -0,0 +1,117 @@
+// Copyright 2020 The Chromium 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 displaying cellular EID and QR code
+ */
+
+// The size of each tile in pixels.
+const QR_CODE_TILE_SIZE = 5;
+// Amount of padding around the QR code in pixels.
+const QR_CODE_PADDING = 4 * QR_CODE_TILE_SIZE;
+// Styling for filled tiles in the QR code.
+const QR_CODE_FILL_STYLE = '#000000';
+
+Polymer({
+ is: 'cellular-eid-popup',
+
+ behaviors: [
+ I18nBehavior,
+ ],
+
+ properties: {
+ /**
+ * The euicc object whose EID and QRCode should be shown in the popup.
+ */
+ euicc: Object,
+
+ /** @private */
+ canvasSize_: Number,
+
+ /** @private */
+ eid_: String,
+ },
+
+ /**
+ * @private {?CanvasRenderingContext2D}
+ */
+ canvasContext_: null,
+
+ /** @override */
+ attached() {
+ if (!this.euicc) {
+ return;
+ }
+ this.euicc.getEidQRCode().then(this.updateQRCode_.bind(this));
+ this.euicc.getProperties().then(this.updateEid_.bind(this));
+ },
+
+ /** @override */
+ focus() {
+ this.$$('.dialog').focus();
+ },
+
+ /**@private */
+ onCloseTap_() {
+ this.fire('close-eid-popup');
+ },
+
+ /**
+ * @private
+ * @param {{qrCode: chromeos.cellularSetup.mojom.QRCode} | null} response
+ */
+ updateQRCode_(response) {
+ if (!response || !response.qrCode) {
+ return;
+ }
+ this.canvasSize_ =
+ response.qrCode.size * QR_CODE_TILE_SIZE + 2 * QR_CODE_PADDING;
+ Polymer.dom.flush();
+ const context = this.getCanvasContext_();
+ context.clearRect(0, 0, this.canvasSize_, this.canvasSize_);
+ context.fillStyle = QR_CODE_FILL_STYLE;
+ let index = 0;
+ for (let x = 0; x < response.qrCode.size; x++) {
+ for (let y = 0; y < response.qrCode.size; y++) {
+ if (response.qrCode.data[index]) {
+ context.fillRect(
+ x * QR_CODE_TILE_SIZE + QR_CODE_PADDING,
+ y * QR_CODE_TILE_SIZE + QR_CODE_PADDING, QR_CODE_TILE_SIZE,
+ QR_CODE_TILE_SIZE);
+ }
+ index++;
+ }
+ }
+ },
+
+ /**
+ * @private
+ * @param {{properties: chromeos.cellularSetup.mojom.EuiccProperties}}
+ * response
+ */
+ updateEid_(response) {
+ if (!response || !response.properties) {
+ return;
+ }
+ this.eid_ = response.properties.eid;
+ },
+
+ /**
+ * @private
+ * @return {CanvasRenderingContext2D}
+ */
+ getCanvasContext_() {
+ if (this.canvasContext_) {
+ return this.canvasContext_;
+ }
+ return this.$.qrCodeCanvas.getContext('2d');
+ },
+
+ /**
+ * @param {CanvasRenderingContext2D} canvasContext
+ */
+ setCanvasContextForTest(canvasContext) {
+ this.canvasContext_ = canvasContext;
+ }
+});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html
index dd55d49c420..6b5e07912ff 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html
@@ -7,6 +7,8 @@
<link rel="import" href="cellular_setup_delegate.html">
<link rel="import" href="setup_selection_flow.html">
<link rel="import" href="../../../html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/cr_components/chromeos/network/cellular_utils.html">
+<link rel="import" href="chrome://resources/cr_components/chromeos/network/mojo_interface_provider.html">
<dom-module id="cellular-setup">
<template>
@@ -17,7 +19,8 @@
<setup-selection-flow
selected-page="{{selectedFlow_}}"
button-state="{{buttonState_}}"
- id="setup-selection-flow">
+ id="setup-selection-flow"
+ forward-button-label="{{forwardButtonLabel_}}">
</setup-selection-flow>
<template is="dom-if"
if="[[isPSimSelected_(currentPageName)]]" restamp>
@@ -25,7 +28,8 @@
button-state="{{buttonState_}}"
name-of-carrier-pending-setup="{{flowTitle}}"
delegate="[[delegate]]"
- id="psim-flow-ui">
+ id="psim-flow-ui"
+ forward-button-label="{{forwardButtonLabel_}}">
</psim-flow-ui>
</template>
<template is="dom-if"
@@ -33,11 +37,15 @@
<esim-flow-ui
button-state="{{buttonState_}}"
delegate="[[delegate]]"
- id="esim-flow-ui">
+ id="esim-flow-ui"
+ forward-button-label="{{forwardButtonLabel_}}">
</esim-flow-ui>
</template>
</iron-pages>
- <button-bar button-state="[[buttonState_]]">
+ <button-bar
+ id="buttonBar"
+ button-state="[[buttonState_]]"
+ forward-button-label="[[forwardButtonLabel_]]">
</button-bar>
</template>
<script src="cellular_setup.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js
index d716ce4538a..677186b6508 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js
@@ -24,10 +24,7 @@ Polymer({
* Name of the currently displayed sub-page.
* @private {!cellularSetup.CellularSetupPageName|null}
*/
- currentPageName: {
- type: String,
- value: cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION,
- },
+ currentPageName: String,
/**
* Current user selected setup flow page name.
@@ -57,14 +54,65 @@ Polymer({
type: Object,
observer: 'onPageChange_',
},
+
+ /**
+ * Text for the button_bar's 'Forward' button.
+ * @private {string}
+ */
+ forwardButtonLabel_: {
+ type: String,
+ }
},
listeners: {
'backward-nav-requested': 'onBackwardNavRequested_',
'retry-requested': 'onRetryRequested_',
- 'complete-flow-requested': 'onCompleteFlowRequested_',
'forward-nav-requested': 'onForwardNavRequested_',
'cancel-requested': 'onCancelRequested_',
+ 'focus-default-button': 'onFocusDefaultButton_',
+ },
+
+
+ /** @override */
+ attached() {
+ if (!this.currentPageName) {
+ this.setCurrentPage_();
+ }
+ },
+
+ /**
+ * Sets current cellular setup flow, one of eSIM flow, pSIM flow or
+ * selection flow, depending on available pSIM and eSIM slots.
+ * @private
+ */
+ setCurrentPage_() {
+ const networkConfig = network_config.MojoInterfaceProviderImpl.getInstance()
+ .getMojoServiceRemote();
+ networkConfig.getDeviceStateList().then(response => {
+ const deviceStateList = response.result;
+
+ const deviceState = deviceStateList.find(
+ (device) => device.type ===
+ chromeos.networkConfig.mojom.NetworkType.kCellular);
+
+ if (!deviceState) {
+ this.currentPageName =
+ cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION;
+ return;
+ }
+
+ const {pSimSlots, eSimSlots} = getSimSlotCount(deviceState);
+
+ if (pSimSlots > 0 && eSimSlots === 0) {
+ this.currentPageName = cellularSetup.CellularSetupPageName.PSIM_FLOW_UI;
+ return;
+ } else if (pSimSlots === 0 && eSimSlots > 0) {
+ this.currentPageName = cellularSetup.CellularSetupPageName.ESIM_FLOW_UI;
+ return;
+ }
+ this.currentPageName =
+ cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION;
+ });
},
/** @private */
@@ -83,7 +131,7 @@ Polymer({
// navigation any more. Switch back to the selection flow in this case so
// that the user can select a flow again.
if (!isNavHandled) {
- this.currentPageName_ =
+ this.currentPageName =
cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION;
}
},
@@ -98,22 +146,22 @@ Polymer({
},
/** @private */
- onCompleteFlowRequested_() {
- // TODO(crbug.com/1093185): Add completion logic.
- },
-
- /** @private */
onForwardNavRequested_() {
// Switch current page to user selected flow when navigating forward from
// setup selection.
- if (this.currentPageName_ ===
+ if (this.currentPageName ===
cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION) {
- this.currentPageName_ = this.selectedFlow_;
+ this.currentPageName = this.selectedFlow_;
return;
}
this.currentPage_.navigateForward();
},
+ /** @private */
+ onFocusDefaultButton_() {
+ this.$.buttonBar.focusDefaultButton();
+ },
+
/**
* @param {string} currentPage
* @private
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup_icons.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup_icons.html
new file mode 100644
index 00000000000..c68f68cdbb1
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup_icons.html
@@ -0,0 +1,18 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html">
+
+<!-- These icons were converted from source .svg files. -->
+
+<iron-iconset-svg name="cellular-setup" size="20">
+ <svg>
+ <defs>
+ <g id="camera" viewBox="0 0 20 20"><mask id="a" maskUnits="userSpaceOnUse" x="1" y="2" width="18" height="16"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.667 4.167h-2.642L12.5 2.5h-5L5.975 4.167H3.334c-.917 0-1.667.75-1.667 1.666v10c0 .917.75 1.667 1.667 1.667h13.333c.917 0 1.667-.75 1.667-1.667v-10c0-.916-.75-1.666-1.667-1.666zm0 11.666H3.334v-10h13.333v10zm-10-5A3.332 3.332 0 1 1 10 14.166a3.332 3.332 0 0 1-3.333-3.333z" fill="#fff"></mask><g mask="url(#a)"><path d="M0 0h20v20H0z"></g></g>
+ <g id="checked" viewBox="0 0 20 20"><path d="M13.707 7.293a1 1 0 0 0-1.414 0L9 10.586 7.707 9.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 0-1.414z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-2a6 6 0 1 0 0-12 6 6 0 0 0 0 12z"></path></g>
+ <g id="error" viewBox="0 0 20 20"><path fill-rule="evenodd" clip-rule="evenodd" d="M9 10h2V6H9v4zm1-8c-4.416 0-8 3.584-8 8s3.584 8 8 8 8-3.584 8-8-3.584-8-8-8zm0 14c-3.308 0-6-2.693-6-6 0-3.308 2.692-6 6-6 3.307 0 6 2.692 6 6 0 3.307-2.693 6-6 6zm-1-2h2v-2H9v2z"></g>
+ <g id="switch-camera" viewBox="0 0 20 20"><path fill-rule="evenodd" clip-rule="evenodd" d="M7 9V7H4.802A5.996 5.996 0 0 1 10 4a6 6 0 0 1 5.917 5h2.021c-.491-3.945-3.853-7-7.93-7a7.992 7.992 0 0 0-6.009 2.712L4 3H2v6h5zm5.938 2v2h2.198a5.996 5.996 0 0 1-5.198 3 6 6 0 0 1-5.917-5H2c.492 3.945 3.853 7 7.93 7a7.992 7.992 0 0 0 6.009-2.712V17h2v-6h-5zM10 12a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"></g>
+ <g id="try-again" viewBox="0 0 20 20"><path path fill-rule="evenodd" clip-rule="evenodd" d="M10 3C6.136 3 3 6.136 3 10C3 13.864 6.136 17 10 17C12.1865 17 14.1399 15.9959 15.4239 14.4239L13.9984 12.9984C13.0852 14.2129 11.6325 15 10 15C7.24375 15 5 12.7563 5 10C5 7.24375 7.24375 5 10 5C11.6318 5 13.0839 5.78641 13.9972 7H11V9H17V3H15V5.10253C13.7292 3.80529 11.9581 3 10 3Z"></g>
+ <g id="warning" viewBox="0 0 20 20"><path d="M9 12H11V8H9V12Z"></path><path d="M11 15H9V13H11V15Z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M9.13177 2.50386C9.51566 1.83205 10.4844 1.83205 10.8683 2.50386L18.8683 16.5039C19.2492 17.1705 18.7678 18 18 18H2.00001C1.23219 18 0.750823 17.1705 1.13177 16.5039L9.13177 2.50386ZM10 5.01556L3.72321 16H16.2768L10 5.01556Z"></g>
+ </defs>
+ </svg>
+</iron-iconset-svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_types.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_types.js
index ec12f757a6b..338e9ccd40b 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_types.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_types.js
@@ -15,29 +15,24 @@ cr.define('cellularSetup', function() {
/** @enum {number} */
/* #export */ const ButtonState = {
- HIDDEN: 1,
- SHOWN_AND_ENABLED: 2,
- SHOWN_BUT_DISABLED: 3,
+ ENABLED: 1,
+ DISABLED: 2,
};
/** @enum {number} */
/* #export */ const Button = {
BACKWARD: 1,
CANCEL: 2,
- DONE: 3,
- NEXT: 4,
- TRY_AGAIN: 5,
- SKIP_DISCOVERY: 6,
+ FORWARD: 3,
+ TRY_AGAIN: 4,
};
/**
* @typedef {{
* backward: (!cellularSetup.ButtonState|undefined),
* cancel: (!cellularSetup.ButtonState|undefined),
- * done: (!cellularSetup.ButtonState|undefined),
- * next: (!cellularSetup.ButtonState|undefined),
+ * forward: (!cellularSetup.ButtonState|undefined),
* tryAgain: (!cellularSetup.ButtonState|undefined),
- * skipDiscovery: (!cellularSetup.ButtonState|undefined),
* }}
*/
/* #export */ let ButtonBarState;
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.html
new file mode 100644
index 00000000000..e055c141766
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.html
@@ -0,0 +1,89 @@
+<link rel="import" href="../../../html/polymer.html">
+
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
+<link rel="import" href="../../../html/i18n_behavior.html">
+<link rel="import" href="base_page.html">
+
+<dom-module id="confirmation-code-page">
+ <template>
+ <style include="iron-flex iron-positioning">
+ [slot='page-body'] {
+ margin-top: -20px;
+ }
+
+ #outerDiv {
+ height: 236px;
+ }
+
+ .container {
+ width: 472px;
+ }
+
+ #details {
+ align-items: center;
+ color: var(--cr-primary-text-color);
+ display: flex;
+ margin-bottom: 40px;
+ }
+
+ #profileImage {
+ margin-inline-end: 16px;
+ }
+
+ #confirmationCodeContainer {
+ margin-inline-end: 16px;
+ }
+
+ paper-spinner-lite {
+ height: 20px;
+ position: absolute;
+ right: 16px;
+ top: 24px;
+ width: 20px;
+ }
+
+ #loadingMessage {
+ bottom: 0;
+ color: var(--google-grey-refresh-500);
+ font-size: var(--cr-form-field-label-font-size);
+ letter-spacing: .4px;
+ line-height: var(--cr-form-field-label-line-height);
+ position: absolute;
+ }
+ </style>
+ <base-page>
+ <div slot="page-body">
+ <div id="description">[[i18n('confirmationCodeMessage')]]</div>
+ <div id="outerDiv" class="layout horizontal center">
+ <div class="container">
+ <div id="details" hidden$="[[!shouldShowProfileDetails_(profile)]]">
+ <!-- TODO(crbug.com/1093185): Update with real profile image. -->
+ <img id="profileImage" src="chrome://resources/cr_components/chromeos/cellular_setup/default_esim_profile.svg">
+ <div>
+ [[getProfileName_(profileProperties_)]]
+ </div>
+ </div>
+ <div id="confirmationCodeContainer" class="relative">
+ <cr-input id="confirmationCode"
+ label="[[i18n('confirmationCodeInput')]]"
+ value="{{confirmationCode}}"
+ aria-describedby="description"
+ error-message="[[i18n('confirmationCodeError')]]"
+ invalid="[[showError]]"
+ disabled="[[showBusy]]">
+ </cr-input>
+ <paper-spinner-lite active
+ hidden$="[[!showBusy]]">
+ </paper-spinner-lite>
+ <div id="loadingMessage" hidden$="[[!showBusy]]">
+ [[i18n('confirmationCodeLoading')]]
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </base-page>
+ </template>
+ <script src="confirmation_code_page.js"></script>
+</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.js
new file mode 100644
index 00000000000..374a5e9f606
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.js
@@ -0,0 +1,80 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Page in eSIM Cellular Setup flow shown if an eSIM profile requires a
+ * confirmation code to install. This element contains an input for the user to
+ * enter the confirmation code.
+ */
+Polymer({
+ is: 'confirmation-code-page',
+
+ behaviors: [I18nBehavior],
+
+ properties: {
+ /**
+ * @type {?chromeos.cellularSetup.mojom.ESimProfileRemote}
+ */
+ profile: {
+ type: Object,
+ observer: 'onProfileChanged_',
+ },
+
+ confirmationCode: {
+ type: String,
+ notify: true,
+ },
+
+ showError: {
+ type: Boolean,
+ },
+
+ /**
+ * Indicates the UI is busy with an operation and cannot be interacted with.
+ */
+ showBusy: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
+ * @type {?chromeos.cellularSetup.mojom.ESimProfileProperties}
+ * @private
+ */
+ profileProperties_: {
+ type: Object,
+ value: null,
+ },
+ },
+
+ /** @private */
+ onProfileChanged_() {
+ if (!this.profile) {
+ this.profileProperties_ = null;
+ return;
+ }
+ this.profile.getProperties().then(response => {
+ this.profileProperties_ = response.properties;
+ });
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ shouldShowProfileDetails_() {
+ return !!this.profile;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ getProfileName_() {
+ if (!this.profileProperties_) {
+ return '';
+ }
+ return String.fromCharCode(...this.profileProperties_.name.data);
+ },
+}); \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/default_esim_profile.svg b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/default_esim_profile.svg
new file mode 100644
index 00000000000..058d7e0ce38
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/default_esim_profile.svg
@@ -0,0 +1 @@
+<svg width="31" height="20" viewBox="0 0 31 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h23a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H4zm7.704 10.915h-3.55V6.18h-1.36V14h4.91v-1.085zm4.254-5.64h2.438V6.18h-6.203v1.095h2.417V14h1.348V7.275zm4.823 3.234h3.212V9.435h-3.212v-2.16h3.717V6.18h-5.076V14h5.114v-1.085H20.78v-2.406z" fill="#5F6368"/></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html
index 4657fa02d5c..36651ea37bc 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html
@@ -1,12 +1,19 @@
+<link rel="import" href="chrome://resources/cr_components/chromeos/network/cellular_utils.html">
+<link rel="import" href="chrome://resources/cr_components/chromeos/network/network_listener_behavior.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
<link rel="import" href="../../../html/polymer.html">
<link rel="import" href="../../../html/i18n_behavior.html">
+<link rel="import" href="mojo_interface_provider.html">
+<link rel="import" href="esim_manager_utils.html">
<link rel="import" href="subflow_behavior.html">
<link rel="import" href="cellular_types.html">
<link rel="import" href="cellular_setup_delegate.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
+<link rel="import" href="setup_loading_page.html">
<link rel="import" href="activation_code_page.html">
<link rel="import" href="final_page.html">
<link rel="import" href="profile_discovery_list_page.html">
+<link rel="import" href="confirmation_code_page.html">
<dom-module id="esim-flow-ui">
<template>
@@ -20,14 +27,34 @@
</style>
<iron-pages attr-for-selected="id"
selected="[[selectedESimPageName_]]">
+ <setup-loading-page id="profileLoadingPage"
+ delegate="[[delegate]]"
+ loading-message="[[i18n('eSimProfileDetectMessage')]]"
+ state="[[getLoadingPageState_(hasActivePSimNetwork_)]]">
+ </setup-loading-page>
<profile-discovery-list-page id="profileDiscoveryPage"
- selected-profiles="{{selectedProfiles_}}">
+ pending-profiles="[[pendingProfiles_]]"
+ selected-profile="{{selectedProfile_}}"
+ show-busy="[[shouldShowSubpageBusy_(state_)]]">
</profile-discovery-list-page>
- <activation-code-page id="activationCodePage"></activation-code-page>
+ <activation-code-page id="activationCodePage"
+ activation-code="{{activationCode_}}"
+ show-no-profiles-message="[[getShowNoProfilesMessage_(pendingProfiles_)]]"
+ show-error="{{showError_}}"
+ show-busy="[[shouldShowSubpageBusy_(state_)]]">
+ </activation-code-page>
+ <confirmation-code-page id="confirmationCodePage"
+ confirmation-code="{{confirmationCode_}}"
+ profile="[[selectedProfile_]]"
+ show-error="{{showError_}}"
+ show-busy="[[shouldShowSubpageBusy_(state_)]]">
+ </confirmation-code-page>
<final-page
id="finalPage"
delegate="[[delegate]]"
- show-error="[[showError_]]">
+ show-error="[[showError_]]"
+ message="[[i18n('eSimFinalPageMessage')]]"
+ error-message="[[i18n('eSimFinalPageErrorMessage')]]">
</final-page>
</iron-pages>
</template>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js
index 745f808b82c..1ebf329afe7 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js
@@ -5,10 +5,27 @@
cr.define('cellular_setup', function() {
/** @enum{string} */
/* #export */ const ESimPageName = {
+ PROFILE_LOADING: 'profileLoadingPage',
PROFILE_DISCOVERY: 'profileDiscoveryPage',
- ESIM: 'activationCodePage',
+ ACTIVATION_CODE: 'activationCodePage',
+ CONFIRMATION_CODE: 'confirmationCodePage',
FINAL: 'finalPage',
};
+
+ /** @enum{string} */
+ /* #export */ const ESimUiState = {
+ PROFILE_SEARCH: 'profile-search',
+ ACTIVATION_CODE_ENTRY: 'activation-code-entry',
+ ACTIVATION_CODE_ENTRY_READY: 'activation-code-entry-ready',
+ ACTIVATION_CODE_ENTRY_INSTALLING: 'activation-code-entry-installing',
+ CONFIRMATION_CODE_ENTRY: 'confirmation-code-entry',
+ CONFIRMATION_CODE_ENTRY_READY: 'confirmation-code-entry-ready',
+ CONFIRMATION_CODE_ENTRY_INSTALLING: 'confirmation-code-entry-installing',
+ PROFILE_SELECTION: 'profile-selection',
+ PROFILE_SELECTION_INSTALLING: 'profile-selection-installing',
+ SETUP_FINISH: 'setup-finish',
+ };
+
/**
* Root element for the eSIM cellular setup flow. This element interacts with
* the CellularSetup service to carry out the esim activation flow.
@@ -18,6 +35,7 @@ cr.define('cellular_setup', function() {
behaviors: [
I18nBehavior,
+ NetworkListenerBehavior,
SubflowBehavior,
],
@@ -25,17 +43,30 @@ cr.define('cellular_setup', function() {
/** @type {!cellular_setup.CellularSetupDelegate} */
delegate: Object,
+ forwardButtonLabel: {
+ type: String,
+ notify: true,
+ },
+
/**
- * Element name of the current selected sub-page.
- * @type {!cellular_setup.ESimPageName}
+ * @type {!cellular_setup.ESimUiState}
* @private
*/
- selectedESimPageName_: {
+ state_: {
type: String,
- value: ESimPageName.PROFILE_DISCOVERY,
+ value: ESimUiState.PROFILE_SEARCH,
+ observer: 'onStateChanged_',
},
/**
+ * Element name of the current selected sub-page.
+ * This is set in updateSelectedPage_ on initialization.
+ * @type {?cellular_setup.ESimPageName}
+ * @private
+ */
+ selectedESimPageName_: String,
+
+ /**
* Whether error state should be shown for the current page.
* @private {boolean}
*/
@@ -45,72 +76,408 @@ cr.define('cellular_setup', function() {
},
/**
- * @type {Array<!Object>}
+ * Profiles fetched that have status kPending.
+ * @type {!Array<!chromeos.cellularSetup.mojom.ESimProfileRemote>}
+ * @private
+ */
+ pendingProfiles_: {
+ type: Array,
+ },
+
+ /**
+ * Profile selected to be installed.
+ * @type {?chromeos.cellularSetup.mojom.ESimProfileRemote}
* @private
*/
- selectedProfiles_: {
+ selectedProfile_: {
type: Object,
},
+
+ /** @private */
+ activationCode_: {
+ type: String,
+ value: '',
+ },
+
+ /** @private */
+ confirmationCode_: {
+ type: String,
+ value: '',
+ observer: 'onConfirmationCodeUpdated_',
+ },
+
+ /** @private */
+ hasActivePSimNetwork_: {
+ type: Boolean,
+ value: false,
+ },
},
+ /**
+ * Provides an interface to the ESimManager Mojo service.
+ * @private {?chromeos.cellularSetup.mojom.ESimManagerRemote}
+ */
+ eSimManagerRemote_: null,
+
+ /** @private {?chromeos.cellularSetup.mojom.EuiccRemote} */
+ euicc_: null,
+
listeners: {
'activation-code-updated': 'onActivationCodeUpdated_',
},
- observers: ['onSelectedProfilesChanged_(selectedProfiles_.splices)'],
+ observers: ['onSelectedProfileChanged_(selectedProfile_)'],
+
+ /** @override */
+ created() {
+ this.eSimManagerRemote_ = cellular_setup.getESimManagerRemote();
+ },
initSubflow() {
- this.buttonState = {
- backward: cellularSetup.ButtonState.HIDDEN,
- cancel: this.delegate.shouldShowCancelButton() ?
- cellularSetup.ButtonState.SHOWN_AND_ENABLED :
- cellularSetup.ButtonState.HIDDEN,
- done: cellularSetup.ButtonState.HIDDEN,
- next: cellularSetup.ButtonState.HIDDEN,
- tryAgain: cellularSetup.ButtonState.HIDDEN,
- skipDiscovery: cellularSetup.ButtonState.SHOWN_AND_ENABLED,
- };
+ this.fetchProfiles_();
+ this.onNetworkStateListChanged();
+ },
+
+ /** @private */
+ async fetchProfiles_() {
+ const euicc = await cellular_setup.getEuicc();
+ if (!euicc) {
+ // TODO(crbug.com/1093185) User should have at least 1 EUICC or
+ // we shouldn't have gotten to this flow. Add check for this in
+ // cellular_setup.
+ console.error('No Euiccs found');
+ return;
+ }
+ this.euicc_ = euicc;
+ const requestPendingProfilesResponse =
+ await euicc.requestPendingProfiles();
+ if (requestPendingProfilesResponse.result ===
+ chromeos.cellularSetup.mojom.ESimOperationResult.kFailure) {
+ console.error(
+ 'Error requesting pending profiles: ',
+ requestPendingProfilesResponse);
+ }
+ this.pendingProfiles_ =
+ await cellular_setup.getPendingESimProfiles(euicc);
+ switch (this.pendingProfiles_.length) {
+ case 0:
+ this.state_ = ESimUiState.ACTIVATION_CODE_ENTRY;
+ break;
+ case 1:
+ this.selectedProfile_ = this.pendingProfiles_[0];
+ // Assume installing the profile doesn't require a confirmation
+ // code, send an empty string.
+ this.selectedProfile_.installProfile('').then(
+ this.handleProfileInstallResponse_.bind(this));
+ break;
+ default:
+ this.state_ = ESimUiState.PROFILE_SELECTION;
+ break;
+ }
+ },
+
+ /**
+ * @private
+ * @param {{result: chromeos.cellularSetup.mojom.ProfileInstallResult}}
+ * response
+ */
+ handleProfileInstallResponse_(response) {
+ if (response.result ===
+ chromeos.cellularSetup.mojom.ProfileInstallResult
+ .kErrorNeedsConfirmationCode) {
+ this.state_ = ESimUiState.CONFIRMATION_CODE_ENTRY;
+ return;
+ }
+ this.showError_ = response.result !==
+ chromeos.cellularSetup.mojom.ProfileInstallResult.kSuccess;
+ if (response.result ===
+ chromeos.cellularSetup.mojom.ProfileInstallResult.kFailure &&
+ this.state_ === ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING) {
+ this.state_ = ESimUiState.CONFIRMATION_CODE_ENTRY_READY;
+ return;
+ }
+ if (response.result ===
+ chromeos.cellularSetup.mojom.ProfileInstallResult
+ .kErrorInvalidActivationCode) {
+ this.state_ = ESimUiState.ACTIVATION_CODE_ENTRY_READY;
+ return;
+ }
+ if (response.result ===
+ chromeos.cellularSetup.mojom.ProfileInstallResult.kSuccess ||
+ response.result ===
+ chromeos.cellularSetup.mojom.ProfileInstallResult.kFailure) {
+ this.state_ = ESimUiState.SETUP_FINISH;
+ }
+ },
+
+ /** @private */
+ onStateChanged_(newState, oldState) {
+ this.updateButtonBarState_();
+ this.updateSelectedPage_();
+ this.initializePageState_(newState, oldState);
+ },
+
+ /** @private */
+ updateSelectedPage_() {
+ const oldSelectedESimPageName = this.selectedESimPageName_;
+ switch (this.state_) {
+ case ESimUiState.PROFILE_SEARCH:
+ this.selectedESimPageName_ = ESimPageName.PROFILE_LOADING;
+ break;
+ case ESimUiState.ACTIVATION_CODE_ENTRY:
+ case ESimUiState.ACTIVATION_CODE_ENTRY_READY:
+ case ESimUiState.ACTIVATION_CODE_ENTRY_INSTALLING:
+ this.selectedESimPageName_ = ESimPageName.ACTIVATION_CODE;
+ break;
+ case ESimUiState.CONFIRMATION_CODE_ENTRY:
+ case ESimUiState.CONFIRMATION_CODE_ENTRY_READY:
+ case ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING:
+ this.selectedESimPageName_ = ESimPageName.CONFIRMATION_CODE;
+ break;
+ case ESimUiState.PROFILE_SELECTION:
+ case ESimUiState.PROFILE_SELECTION_INSTALLING:
+ this.selectedESimPageName_ = ESimPageName.PROFILE_DISCOVERY;
+ break;
+ case ESimUiState.SETUP_FINISH:
+ this.selectedESimPageName_ = ESimPageName.FINAL;
+ break;
+ default:
+ assertNotReached();
+ break;
+ }
+ // If there is a page change, fire focus event.
+ if (oldSelectedESimPageName !== this.selectedESimPageName_) {
+ this.fire('focus-default-button');
+ }
+ },
+
+ /** @private */
+ updateButtonBarState_() {
+ let buttonState;
+ const cancelButtonStateIfEnabled =
+ this.delegate.shouldShowCancelButton() ?
+ cellularSetup.ButtonState.ENABLED :
+ undefined;
+ switch (this.state_) {
+ case ESimUiState.PROFILE_SEARCH:
+ case ESimUiState.ACTIVATION_CODE_ENTRY:
+ this.forwardButtonLabel = this.i18n('next');
+ buttonState = {
+ backward: cellularSetup.ButtonState.ENABLED,
+ cancel: cancelButtonStateIfEnabled,
+ forward: cellularSetup.ButtonState.DISABLED,
+ };
+ break;
+ case ESimUiState.ACTIVATION_CODE_ENTRY_READY:
+ this.forwardButtonLabel = this.i18n('next');
+ buttonState = {
+ backward: cellularSetup.ButtonState.ENABLED,
+ cancel: cancelButtonStateIfEnabled,
+ forward: cellularSetup.ButtonState.ENABLED,
+ };
+ break;
+ case ESimUiState.CONFIRMATION_CODE_ENTRY:
+ this.forwardButtonLabel = this.i18n('confirm');
+ buttonState = {
+ backward: cellularSetup.ButtonState.ENABLED,
+ cancel: cancelButtonStateIfEnabled,
+ forward: cellularSetup.ButtonState.DISABLED,
+ };
+ break;
+ case ESimUiState.CONFIRMATION_CODE_ENTRY_READY:
+ this.forwardButtonLabel = this.i18n('confirm');
+ buttonState = {
+ backward: cellularSetup.ButtonState.ENABLED,
+ cancel: cancelButtonStateIfEnabled,
+ forward: cellularSetup.ButtonState.ENABLED,
+ };
+ break;
+ case ESimUiState.PROFILE_SELECTION:
+ this.forwardButtonLabel = this.selectedProfile_ ?
+ this.i18n('next') :
+ this.i18n('skipDiscovery');
+ buttonState = {
+ backward: cellularSetup.ButtonState.ENABLED,
+ cancel: cancelButtonStateIfEnabled,
+ forward: cellularSetup.ButtonState.ENABLED,
+ };
+ break;
+ case ESimUiState.ACTIVATION_CODE_ENTRY_INSTALLING:
+ case ESimUiState.PROFILE_SELECTION_INSTALLING:
+ case ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING:
+ buttonState = {
+ backward: cellularSetup.ButtonState.DISABLED,
+ cancel: cancelButtonStateIfEnabled,
+ forward: cellularSetup.ButtonState.DISABLED,
+ };
+ break;
+ case ESimUiState.SETUP_FINISH:
+ this.forwardButtonLabel = this.i18n('done');
+ buttonState = {
+ forward: cellularSetup.ButtonState.ENABLED,
+ };
+ break;
+ default:
+ assertNotReached();
+ break;
+ }
+ this.set('buttonState', buttonState);
+ },
+
+ /** @private */
+ initializePageState_(newState, oldState) {
+ if (newState === ESimUiState.CONFIRMATION_CODE_ENTRY &&
+ oldState !== ESimUiState.CONFIRMATION_CODE_ENTRY_READY) {
+ this.confirmationCode_ = '';
+ }
+ if (newState === ESimUiState.ACTIVATION_CODE_ENTRY &&
+ oldState !== ESimUiState.ACTIVATION_CODE_ENTRY_READY) {
+ this.activationCode_ = '';
+ }
},
/** @private */
onActivationCodeUpdated_(event) {
- if (event.detail.activationCode) {
- this.set(
- 'buttonState.next', cellularSetup.ButtonState.SHOWN_AND_ENABLED);
- } else {
- this.set(
- 'buttonState.next', cellularSetup.ButtonState.SHOWN_BUT_DISABLED);
+ // initializePageState_() may cause this observer to fire and update the
+ // buttonState when we're not on the activation code page. Check we're on
+ // the activation code page before proceeding.
+ if (this.state_ !== ESimUiState.ACTIVATION_CODE_ENTRY &&
+ this.state_ !== ESimUiState.ACTIVATION_CODE_ENTRY_READY) {
+ return;
+ }
+ this.state_ = event.detail.activationCode ?
+ ESimUiState.ACTIVATION_CODE_ENTRY_READY :
+ ESimUiState.ACTIVATION_CODE_ENTRY;
+ },
+
+ /** @private */
+ onSelectedProfileChanged_() {
+ // initializePageState_() may cause this observer to fire and update the
+ // buttonState when we're not on the profile selection page. Check we're
+ // on the profile selection page before proceeding.
+ if (this.state_ !== ESimUiState.PROFILE_SELECTION) {
+ return;
}
+ this.forwardButtonLabel = this.selectedProfile_ ?
+ this.i18n('next') :
+ this.i18n('skipDiscovery');
},
/** @private */
- onSelectedProfilesChanged_() {
- // TODO(crbug.com/1093185): Add navigation logic.
- if (this.selectedProfiles_.length > 0) {
- this.set('buttonState.skipDiscovery', cellularSetup.ButtonState.HIDDEN);
- this.set(
- 'buttonState.done', cellularSetup.ButtonState.SHOWN_AND_ENABLED);
- } else {
- this.set(
- 'buttonState.skipDiscovery',
- cellularSetup.ButtonState.SHOWN_AND_ENABLED);
- this.set('buttonState.done', cellularSetup.ButtonState.HIDDEN);
+ onConfirmationCodeUpdated_() {
+ // initializePageState_() may cause this observer to fire and update the
+ // buttonState when we're not on the confirmation code page. Check we're
+ // on the confirmation code page before proceeding.
+ if (this.state_ !== ESimUiState.CONFIRMATION_CODE_ENTRY &&
+ this.state_ !== ESimUiState.CONFIRMATION_CODE_ENTRY_READY) {
+ return;
}
+ this.state_ = this.confirmationCode_ ?
+ ESimUiState.CONFIRMATION_CODE_ENTRY_READY :
+ ESimUiState.CONFIRMATION_CODE_ENTRY;
},
+ /** SubflowBehavior override */
navigateForward() {
- this.selectedESimPageName_ = ESimPageName.FINAL;
+ this.showError_ = false;
+
+ switch (this.state_) {
+ case ESimUiState.ACTIVATION_CODE_ENTRY_READY:
+ // Assume installing the profile doesn't require a confirmation
+ // code, send an empty string.
+ this.state_ = ESimUiState.ACTIVATION_CODE_ENTRY_INSTALLING;
+ this.euicc_
+ .installProfileFromActivationCode(
+ this.activationCode_, /*confirmationCode=*/ '')
+ .then(this.handleProfileInstallResponse_.bind(this));
+ break;
+ case ESimUiState.PROFILE_SELECTION:
+ if (this.selectedProfile_) {
+ this.state_ = ESimUiState.PROFILE_SELECTION_INSTALLING;
+ // Assume installing the profile doesn't require a confirmation
+ // code, send an empty string.
+ this.selectedProfile_.installProfile('').then(
+ this.handleProfileInstallResponse_.bind(this));
+ } else {
+ this.state_ = ESimUiState.ACTIVATION_CODE_ENTRY;
+ }
+ break;
+ case ESimUiState.CONFIRMATION_CODE_ENTRY_READY:
+ this.state_ = ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING;
+ if (this.selectedProfile_) {
+ this.selectedProfile_.installProfile(this.confirmationCode_)
+ .then(this.handleProfileInstallResponse_.bind(this));
+ } else {
+ this.euicc_
+ .installProfileFromActivationCode(
+ this.activationCode_, this.confirmationCode_)
+ .then(this.handleProfileInstallResponse_.bind(this));
+ }
+ break;
+ case ESimUiState.SETUP_FINISH:
+ this.fire('exit-cellular-setup');
+ break;
+ default:
+ assertNotReached();
+ break;
+ }
},
/**
* @returns {boolean} true if backward navigation was handled
+ * SubflowBehavior override
*/
attemptBackwardNavigation() {
- // TODO(crbug.com/1093185): Handle state when camera is used
+ if ((this.state_ === ESimUiState.ACTIVATION_CODE_ENTRY ||
+ this.state_ === ESimUiState.ACTIVATION_CODE_ENTRY_READY) &&
+ this.pendingProfiles_.length > 1) {
+ this.state_ = ESimUiState.PROFILE_SELECTION;
+ return true;
+ } else if (
+ this.state_ === ESimUiState.CONFIRMATION_CODE_ENTRY ||
+ this.state_ === ESimUiState.CONFIRMATION_CODE_ENTRY_READY) {
+ if (this.activationCode_) {
+ this.state_ = ESimUiState.ACTIVATION_CODE_ENTRY_READY;
+ } else if (this.pendingProfiles_.length > 1) {
+ this.state_ = ESimUiState.PROFILE_SELECTION;
+ } else {
+ return false;
+ }
+ return true;
+ }
return false;
},
+
+ /** @private */
+ getShowNoProfilesMessage_() {
+ return !(this.pendingProfiles_ && this.pendingProfiles_.length > 0);
+ },
+
+ /** NetworkListenerBehavior override */
+ onNetworkStateListChanged() {
+ hasActivePSimNetwork().then((hasActive) => {
+ this.hasActivePSimNetwork_ = hasActive;
+ });
+ },
+
+ /** @private */
+ shouldShowSubpageBusy_() {
+ return this.state_ === ESimUiState.ACTIVATION_CODE_ENTRY_INSTALLING ||
+ this.state_ === ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING ||
+ this.state_ === ESimUiState.PROFILE_SELECTION_INSTALLING;
+ },
+
+ /**
+ * @param {boolean} hasActivePSimNetwork
+ * @private
+ */
+ getLoadingPageState_(hasActivePSimNetwork) {
+ return hasActivePSimNetwork ?
+ LoadingPageState.CELLULAR_DISCONNECT_WARNING :
+ LoadingPageState.LOADING;
+ },
});
// #cr_define_end
- return {ESimPageName: ESimPageName};
+ return {ESimPageName: ESimPageName, ESimUiState: ESimUiState};
}); \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.html
new file mode 100644
index 00000000000..dff799113c8
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.html
@@ -0,0 +1,2 @@
+<link rel="import" href="mojo_interface_provider.html">
+<script src="esim_manager_listener_behavior.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.js
new file mode 100644
index 00000000000..339c8153a79
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.js
@@ -0,0 +1,40 @@
+// Copyright 2020 The Chromium 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 {observeESimManager} from './mojo_interface_provider.m.js';
+
+/**
+ * @fileoverview Polymer behavior for observing ESimManagerObserver
+ * events.
+ */
+
+/** @polymerBehavior */
+/* #export */ const ESimManagerListenerBehavior = {
+ /** @private {?chromeos.cellularSetup.mojom.ESimManagerObserver} */
+ observer_: null,
+
+ /** @override */
+ attached() {
+ cellular_setup.observeESimManager(this);
+ },
+
+ // ESimManagerObserver methods. Override these in the implementation.
+
+ onAvailableEuiccListChanged() {},
+
+ /**
+ * @param {!chromeos.cellularSetup.mojom.EuiccRemote} euicc
+ */
+ onProfileListChanged(euicc) {},
+
+ /**
+ * @param {!chromeos.cellularSetup.mojom.EuiccRemote} euicc
+ */
+ onEuiccChanged(euicc) {},
+
+ /**
+ * @param {!chromeos.cellularSetup.mojom.ESimProfileRemote} profile
+ */
+ onProfileChanged(profile) {},
+}; \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.html
new file mode 100644
index 00000000000..8ae13b6392a
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.html
@@ -0,0 +1,2 @@
+<link rel="import" href="mojo_interface_provider.html">
+<script src="esim_manager_utils.js"></script> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.js
new file mode 100644
index 00000000000..4f5613aedad
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.js
@@ -0,0 +1,98 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// clang-format off
+// #import {getESimManagerRemote} from 'chrome://resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.m.js';
+// #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+// clang-format on
+
+cr.define('cellular_setup', function() {
+ /**
+ * Fetches the EUICC's eSIM profiles with status 'Pending'.
+ * @param {!chromeos.cellularSetup.mojom.EuiccRemote} euicc
+ * @return {!Promise<!Array<!chromeos.cellularSetup.mojom.ESimProfileRemote>>}
+ */
+ /* #export */ function getPendingESimProfiles(euicc) {
+ return euicc.getProfileList().then(response => {
+ return filterForPendingProfiles_(response.profiles);
+ });
+ }
+
+ /**
+ * @private
+ * @param {!Array<!chromeos.cellularSetup.mojom.ESimProfileRemote>} profiles
+ * @return {!Promise<Array<!chromeos.cellularSetup.mojom.ESimProfileRemote>>}
+ */
+ function filterForPendingProfiles_(profiles) {
+ const profilePromises = profiles.map(profile => {
+ return profile.getProperties().then(response => {
+ if (response.properties.state !==
+ chromeos.cellularSetup.mojom.ProfileState.kPending) {
+ return null;
+ }
+ return profile;
+ });
+ });
+ return Promise.all(profilePromises).then(profiles => {
+ return profiles.filter(profile => {
+ return profile !== null;
+ });
+ });
+ }
+
+ /**
+ * Returns the Euicc that should be used for eSim operations or null
+ * if there is none available.
+ * @return {!Promise<?chromeos.cellularSetup.mojom.EuiccRemote>}
+ */
+ /* #export */ async function getEuicc() {
+ const eSimManagerRemote = cellular_setup.getESimManagerRemote();
+ const response = await eSimManagerRemote.getAvailableEuiccs();
+ if (!response || !response.euiccs) {
+ return null;
+ }
+ // Onboard Euicc always appears at index 0. If useExternalEuicc flag
+ // is set, use the next available Euicc.
+ const euiccIndex = loadTimeData.getBoolean('useExternalEuicc') ? 1 : 0;
+ if (euiccIndex >= response.euiccs.length) {
+ return null;
+ }
+ return response.euiccs[euiccIndex];
+ }
+
+ /**
+ * Returns the eSIM profile with iccid in the first EUICC and null if none
+ * found.
+ * @param {string} iccid
+ * @return {!Promise<?chromeos.cellularSetup.mojom.ESimProfileRemote>}
+ */
+ /* #export */ async function getESimProfile(iccid) {
+ if (!iccid) {
+ return null;
+ }
+ const euicc = await cellular_setup.getEuicc();
+
+ if (!euicc) {
+ console.error('No Euiccs found');
+ return null;
+ }
+ const esimProfilesRemotes = await euicc.getProfileList();
+
+ for (const profileRemote of esimProfilesRemotes.profiles) {
+ const profileProperties = await profileRemote.getProperties();
+
+ if (profileProperties.properties.iccid === iccid) {
+ return profileRemote;
+ }
+ }
+ return null;
+ }
+
+ // #cr_define_end
+ return {
+ getEuicc,
+ getESimProfile,
+ getPendingESimProfiles,
+ };
+});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.html
index dae2b94d6ee..262113316ef 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.html
@@ -9,16 +9,18 @@
<style>
[slot='page-body'] {
background-image: -webkit-image-set(
- url(final_page_success_1x.png) 1x,
- url(final_page_success_2x.png) 2x);
+ url(chrome://resources/cr_components/chromeos/cellular_setup/final_page_success_1x.png) 1x,
+ url(chrome://resources/cr_components/chromeos/cellular_setup/final_page_success_2x.png) 2x);
background-position: center center;
background-repeat: no-repeat;
+ background-size: contain;
}
.error[slot='page-body'] {
background-image: -webkit-image-set(
- url(error_1x.png) 1x,
- url(error_2x.png) 2x);
+ url(chrome://resources/cr_components/chromeos/cellular_setup/error_1x.png) 1x,
+ url(chrome://resources/cr_components/chromeos/cellular_setup/error_2x.png) 2x);
+ background-size: contain;
}
</style>
<base-page title="[[getTitle_(showError)]]"
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.js
index d35c9b99f50..41f4c15eea6 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.js
@@ -21,6 +21,12 @@ Polymer({
* @type {boolean}
*/
showError: Boolean,
+
+ /** @type {string} */
+ message: String,
+
+ /** @type {string} */
+ errorMessage: String,
},
/**
@@ -42,8 +48,7 @@ Polymer({
* @private
*/
getMessage_(showError) {
- return showError ? this.i18n('finalPageErrorMessage') :
- this.i18n('finalPageMessage');
+ return showError ? this.errorMessage : this.message;
},
/**
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html
index b7096a0baf6..b465a3a18d7 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html
@@ -1,4 +1,7 @@
<link rel="import" href="../../../html/cr.html">
<link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html">
+<link rel="import" href="chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom.html">
+<link rel="import" href="chrome://resources/mojo/mojo/public/mojom/base/string16.mojom.html">
<link rel="import" href="chrome://resources/mojo/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom.html">
+<link rel="import" href="chrome://resources/mojo/chromeos/services/cellular_setup/public/mojom/esim_manager.mojom.html">
<script src="mojo_interface_provider.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.js
index 01e24f158c6..5b79070c145 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.js
@@ -5,11 +5,16 @@
// clang-format off
// #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
// #import 'chrome://resources/mojo/url/mojom/url.mojom-lite.js';
+// #import 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js';
+// #import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js';
// #import 'chrome://resources/mojo/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom-lite.js';
+// #import 'chrome://resources/mojo/chromeos/services/cellular_setup/public/mojom/esim_manager.mojom-lite.js';
// clang-format on
cr.define('cellular_setup', function() {
let cellularRemote = null;
+ let eSimManagerRemote = null;
+ let isTesting = false;
/**
* @param {?chromeos.cellularSetup.mojom.CellularSetupRemote}
@@ -17,6 +22,7 @@ cr.define('cellular_setup', function() {
*/
/* #export */ function setCellularSetupRemoteForTesting(testCellularRemote) {
cellularRemote = testCellularRemote;
+ isTesting = true;
}
/**
@@ -32,6 +38,53 @@ cr.define('cellular_setup', function() {
return cellularRemote;
}
+ /**
+ * @param {?chromeos.cellularSetup.mojom.ESimManagerRemote}
+ * testESimManagerRemote A test eSimManager remote
+ */
+ /* #export */ function setESimManagerRemoteForTesting(testESimManagerRemote) {
+ eSimManagerRemote = testESimManagerRemote;
+ isTesting = true;
+ }
+
+ /**
+ * @returns {!chromeos.cellularSetup.mojom.ESimManagerRemote}
+ */
+ /* #export */ function getESimManagerRemote() {
+ if (eSimManagerRemote) {
+ return eSimManagerRemote;
+ }
+
+ eSimManagerRemote = chromeos.cellularSetup.mojom.ESimManager.getRemote();
+
+ return eSimManagerRemote;
+ }
+
+ /**
+ * @param {!chromeos.cellularSetup.mojom.ESimManagerObserverInterface}
+ * observer
+ * @returns {?chromeos.cellularSetup.mojom.ESimManagerObserverReceiver}
+ */
+ /* #export */ function observeESimManager(observer) {
+ if (isTesting) {
+ getESimManagerRemote().addObserver(
+ /** @type {!chromeos.cellularSetup.mojom.ESimManagerObserverRemote} */
+ (observer));
+ return null;
+ }
+
+ const receiver =
+ new chromeos.cellularSetup.mojom.ESimManagerObserverReceiver(observer);
+ getESimManagerRemote().addObserver(receiver.$.bindNewPipeAndPassRemote());
+ return receiver;
+ }
+
// #cr_define_end
- return {setCellularSetupRemoteForTesting, getCellularSetupRemote};
+ return {
+ setCellularSetupRemoteForTesting,
+ getCellularSetupRemote,
+ setESimManagerRemoteForTesting,
+ getESimManagerRemote,
+ observeESimManager
+ };
});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.html
index f6069727917..10eadd33d7f 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.html
@@ -3,10 +3,13 @@
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.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-spinner/paper-spinner-lite.html">
+<link rel="import" href="cellular_setup_icons.html">
<dom-module id="profile-discovery-list-item">
<template>
- <style include="iron-flex">
+ <style include="iron-flex iron-positioning">
#details {
align-items: center;
display: flex;
@@ -22,32 +25,48 @@
color: var(--cr-primary-text-color);
}
- #checkmark {
- -webkit-mask: url(activation_code_page_checked.svg) no-repeat center;
- background-color: var(--google-blue-600);
- height: 20px;
+ .icon {
margin-inline-end: 8px;
- mask: url(activation_code_page_checked.svg) no-repeat center;
padding-inline-end: var(--cr-section-padding);
- width: 20px;
+ }
+
+ #checkmark {
+ --iron-icon-fill-color: var(--google-blue-600);
+ }
+
+ paper-spinner-lite {
+ height: 16px;
+ vertical-align: middle;
+ width: 16px;
}
</style>
<div class="two-line no-padding" selectable>
<div class="flex layout horizontal center link-wrapper">
- <div id="details" no-flex$="false">
+ <!-- TODO(crbug.com/1093185): Update UI to new spec. -->
+ <div id="details">
<!-- TODO(crbug.com/1093185): Update with real profile image. -->
- <img id="profileImage" src="../../../images/200-logo_googleg.png">
+ <img id="profileImage" src="chrome://resources/cr_components/chromeos/cellular_setup/default_esim_profile.svg">
+ <!-- The item's aria properties are set in profile_discovery_list_page. -->
<div class="flex settings-box-text">
<div id="profileTitleLabel">
- [[profile.name]]
+ [[getProfileName_(profileProperties_)]]
</div>
<div id="profileProviderLabel">
- [[profile.provider]]
+ [[getProfileProvider_(profileProperties_)]]
</div>
</div>
</div>
- <span id="checkmark" hidden$="[[!selected]]"
- tabindex="-1">
+ <div class="icon"
+ hidden$="[[!selected]]">
+ <iron-icon id="checkmark"
+ icon="cellular-setup:checked"
+ tabindex="-1"
+ hidden$="[[showLoadingIndicator]]">
+ </iron-icon>
+ <paper-spinner-lite active
+ hidden$="[[!showLoadingIndicator]]">
+ </paper-spinner-lite>
+ </div>
</div>
</div>
</template>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.js
index a2705ddff12..088344d980c 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.js
@@ -14,16 +14,57 @@ Polymer({
behaviors: [I18nBehavior],
properties: {
- // TODO(crbug.com/1093185) Add type annotation when the real Profile struct
- // is available.
+ /** @type {?chromeos.cellularSetup.mojom.ESimProfileRemote} */
profile: {
type: Object,
value: null,
+ observer: 'onProfileChanged_',
},
selected: {
type: Boolean,
reflectToAttribute: true,
},
+
+ showLoadingIndicator: {
+ type: Boolean,
+ },
+
+ /**
+ * @type {?chromeos.cellularSetup.mojom.ESimProfileProperties}
+ * @private
+ */
+ profileProperties_: {
+ type: Object,
+ value: null,
+ notify: true,
+ },
+ },
+
+ /** @private */
+ onProfileChanged_() {
+ if (!this.profile) {
+ this.profileProperties_ = null;
+ return;
+ }
+ this.profile.getProperties().then(response => {
+ this.profileProperties_ = response.properties;
+ });
+ },
+
+ /** @private */
+ getProfileName_() {
+ if (!this.profileProperties_) {
+ return '';
+ }
+ return String.fromCharCode(...this.profileProperties_.name.data);
+ },
+
+ /** @private */
+ getProfileProvider_() {
+ if (!this.profileProperties_) {
+ return '';
+ }
+ return String.fromCharCode(...this.profileProperties_.serviceProvider.data);
},
});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.html
index a6cad8e1d48..7fa907286c6 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.html
@@ -33,18 +33,19 @@
<div slot="page-body">
<div>[[i18n('profileListPageMessage')]]</div>
<div id="container" class="layout vertical flex" scrollable>
- <iron-list id="profileList" items="[[profiles_]]"
- scroll-target="container" selection-enabled
- preserve-focus multi-selection
- selected-items="{{selectedProfiles}}"
- role="listbox"
- aria-multiselectable="true">
+ <iron-list id="profileList" items="[[pendingProfiles]]"
+ scroll-target="container"
+ selection-enabled="[[!showBusy]]"
+ preserve-focus
+ selected-item="{{selectedProfile}}"
+ role="listbox">
<template>
<profile-discovery-list-item profile="[[item]]"
- selected="[[isProfileSelected_(item, selectedProfiles.length)]]"
+ selected="[[isProfileSelected_(item, selectedProfile)]]"
tabindex="0"
role="option"
- aria-selected="[[isProfileSelected_(item, selectedProfiles.length)]]">
+ aria-selected="[[isProfileSelected_(item, selectedProfile)]]"
+ show-loading-indicator="[[showBusy]]">
</profile-discovery-list-item>
</template>
</iron-list>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.js
index 7ac95a631b0..f8ff38ab3e8 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.js
@@ -14,45 +14,36 @@ Polymer({
properties: {
/**
- * TODO(crbug.com/1093185) Fetch real profiles.
- * @type {Array<!Object>}
+ * @type {Array<!chromeos.cellularSetup.mojom.ESimProfileRemote>}
* @private
*/
- profiles_: {
+ pendingProfiles: {
type: Array,
- value() {
- return [
- {
- name: 'Profile 1',
- provider: 'Google Fi',
- },
- {
- name: 'Profile 2',
- provider: 'Verizon',
- },
- {
- name: 'Profile 3',
- provider: 'Google Fi',
- },
- ];
- },
},
/**
- * @type {Array<!Object>}
+ * @type {?chromeos.cellularSetup.mojom.ESimProfileRemote}
* @private
*/
- selectedProfiles: {
+ selectedProfile: {
type: Object,
notify: true,
},
+
+ /**
+ * Indicates the UI is busy with an operation and cannot be interacted with.
+ */
+ showBusy: {
+ type: Boolean,
+ value: false,
+ },
},
/**
- * @param {Object} profile
+ * @param {chromeos.cellularSetup.mojom.ESimProfileRemote} profile
* @private
*/
isProfileSelected_(profile) {
- return this.selectedProfiles.some(p => p === profile);
+ return this.selectedProfile === profile;
}
});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/provisioning_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/provisioning_page.html
index e0d9e9cee3d..ba6ac6e1c4b 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/provisioning_page.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/provisioning_page.html
@@ -14,8 +14,8 @@
<template>
<style include="iron-flex cr-hidden-style">
paper-spinner-lite {
- height: 200px;
- width: 200px;
+ height: 32px;
+ width: 32px;
}
#portalContainer {
@@ -25,8 +25,8 @@
#error-icon-container {
background-image: -webkit-image-set(
- url(error_1x.png) 1x,
- url(error_2x.png) 2x);
+ url(chrome://resources/cr_components/chromeos/cellular_setup/error_1x.png) 1x,
+ url(chrome://resources/cr_components/chromeos/cellular_setup/error_2x.png) 2x);
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html
index 3df8674d08f..a500531b5a6 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html
@@ -2,7 +2,7 @@
<link rel="import" href="../../../html/i18n_behavior.html">
<link rel="import" href="mojo_interface_provider.html">
-<link rel="import" href="sim_detect_page.html">
+<link rel="import" href="setup_loading_page.html">
<link rel="import" href="provisioning_page.html">
<link rel="import" href="final_page.html">
<link rel="import" href="subflow_behavior.html">
@@ -23,16 +23,25 @@
flex-direction: column;
}
</style>
- <iron-pages attr-for-selected="is"
+ <iron-pages attr-for-selected="id"
selected="[[selectedPSimPageName_]]"
selected-item="{{selectedPage_}}">
- <sim-detect-page delegate="[[delegate]]" show-error="[[showError_]]"></sim-detect-page>
- <provisioning-page delegate="[[delegate]]" show-error="{{showError_}}"
+ <setup-loading-page id="simDetectPage"
+ delegate="[[delegate]]" state="[[getLoadingPageState_(showError)]]"
+ loading-message="[[i18n('establishNetworkConnectionMessage')]]">
+ </setup-loading-page>
+ <provisioning-page id="provisioningPage"
+ delegate="[[delegate]]" show-error="{{showError_}}"
cellular-metadata="[[cellularMetadata_]]"
on-carrier-portal-loaded="onCarrierPortalLoaded_"
on-carrier-portal-result="onCarrierPortalResult_">
</provisioning-page>
- <final-page delegate="[[delegate]]" show-error="[[showError_]]"></final-page>
+ <final-page id="finalPage"
+ delegate="[[delegate]]"
+ show-error="[[showError_]]"
+ message="[[i18n('finalPageMessage')]]"
+ error-message="[[i18n('finalPageErrorMessage')]]">
+ </final-page>
</iron-pages>
</template>
<script src="psim_flow_ui.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js
index 3da72094f86..75b34bc3e12 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js
@@ -5,9 +5,9 @@
cr.define('cellularSetup', function() {
/** @enum{string} */
/* #export */ const PSimPageName = {
- SIM_DETECT: 'sim-detect-page',
- PROVISIONING: 'provisioning-page',
- FINAL: 'final-page',
+ SIM_DETECT: 'simDetectPage',
+ PROVISIONING: 'provisioningPage',
+ FINAL: 'finalPage',
};
/** @enum{string} */
@@ -82,6 +82,11 @@ cr.define('cellularSetup', function() {
'selectedPSimPageName_, cellularMetadata_.*)',
},
+ forwardButtonLabel: {
+ type: String,
+ notify: true,
+ },
+
/**
* @type {!cellularSetup.PSimUIState}
* @private
@@ -104,7 +109,7 @@ cr.define('cellularSetup', function() {
/**
* DOM Element for the current selected sub-page.
- * @private {!SimDetectPageElement|!ProvisioningPageElement|
+ * @private {!SetupLoadingPageElement|!ProvisioningPageElement|
* !FinalPageElement}
*/
selectedPage_: Object,
@@ -181,10 +186,21 @@ cr.define('cellularSetup', function() {
},
navigateForward() {
- // Navigate forward is only called by clicking next button
- // from the provisioning page.
- assert(this.selectedPSimPageName_ === PSimPageName.PROVISIONING);
- this.state_ = PSimUIState.WAITING_FOR_ACTIVATION_TO_FINISH;
+ switch (this.state_) {
+ case PSimUIState.WAITING_FOR_PORTAL_TO_LOAD:
+ case PSimUIState.TIMEOUT_PORTAL_LOAD:
+ case PSimUIState.WAITING_FOR_USER_PAYMENT:
+ case PSimUIState.ACTIVATION_SUCCESS:
+ this.state_ = PSimUIState.WAITING_FOR_ACTIVATION_TO_FINISH;
+ break;
+ case PSimUIState.WAITING_FOR_ACTIVATION_TO_FINISH:
+ case PSimUIState.TIMEOUT_FINISH_ACTIVATION:
+ this.fire('exit-cellular-setup');
+ break;
+ default:
+ assertNotReached();
+ break;
+ }
},
/**
@@ -207,35 +223,25 @@ cr.define('cellularSetup', function() {
case PSimUIState.TIMEOUT_PORTAL_LOAD:
case PSimUIState.WAITING_FOR_USER_PAYMENT:
buttonState = {
- backward: cellularSetup.ButtonState.SHOWN_AND_ENABLED,
- cancel: cellularSetup.ButtonState.SHOWN_AND_ENABLED,
- done: cellularSetup.ButtonState.HIDDEN,
- next: cellularSetup.ButtonState.SHOWN_BUT_DISABLED,
- tryAgain: cellularSetup.ButtonState.HIDDEN,
- skipDiscovery: cellularSetup.ButtonState.HIDDEN,
+ backward: cellularSetup.ButtonState.ENABLED,
+ cancel: cellularSetup.ButtonState.ENABLED,
+ forward: cellularSetup.ButtonState.DISABLED,
};
break;
case PSimUIState.ACTIVATION_SUCCESS:
case PSimUIState.ALREADY_ACTIVATED:
case PSimUIState.ACTIVATION_FAILURE:
buttonState = {
- backward: cellularSetup.ButtonState.SHOWN_AND_ENABLED,
- cancel: cellularSetup.ButtonState.SHOWN_AND_ENABLED,
- done: cellularSetup.ButtonState.HIDDEN,
- next: cellularSetup.ButtonState.SHOWN_AND_ENABLED,
- tryAgain: cellularSetup.ButtonState.HIDDEN,
- skipDiscovery: cellularSetup.ButtonState.HIDDEN,
+ backward: cellularSetup.ButtonState.ENABLED,
+ cancel: cellularSetup.ButtonState.ENABLED,
+ forward: cellularSetup.ButtonState.ENABLED,
};
break;
case PSimUIState.WAITING_FOR_ACTIVATION_TO_FINISH:
case PSimUIState.TIMEOUT_FINISH_ACTIVATION:
+ this.forwardButtonLabel = this.i18n('done');
buttonState = {
- backward: cellularSetup.ButtonState.HIDDEN,
- cancel: cellularSetup.ButtonState.HIDDEN,
- done: cellularSetup.ButtonState.SHOWN_AND_ENABLED,
- next: cellularSetup.ButtonState.HIDDEN,
- tryAgain: cellularSetup.ButtonState.HIDDEN,
- skipDiscovery: cellularSetup.ButtonState.HIDDEN,
+ forward: cellularSetup.ButtonState.ENABLED,
};
break;
default:
@@ -416,6 +422,15 @@ cr.define('cellularSetup', function() {
this.state_ = success ? PSimUIState.ACTIVATION_SUCCESS :
PSimUIState.ACTIVATION_FAILURE;
},
+
+ /**
+ * @param {boolean} showError
+ * @private
+ */
+ getLoadingPageState_(showError) {
+ return showError ? LoadingPageState.SIM_DETECT_ERROR :
+ LoadingPageState.LOADING;
+ },
});
// #cr_define_end
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html
new file mode 100644
index 00000000000..9e77036fb7b
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html
@@ -0,0 +1,49 @@
+<link rel="import" href="../../../html/polymer.html">
+
+<link rel="import" href="../../../html/i18n_behavior.html">
+<link rel="import" href="base_page.html">
+<link rel="import" href="cellular_setup_delegate.html">
+<link rel="import" href="../../../cr_elements/hidden_style_css.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
+
+<dom-module id="setup-loading-page">
+ <template>
+ <style include="iron-flex cr-hidden-style">
+ paper-spinner-lite {
+ height: 32px;
+ margin-bottom: 8px;
+ width: 32px;
+ }
+
+ #simDetectError {
+ background-image: -webkit-image-set(
+ url(chrome://resources/cr_components/chromeos/cellular_setup/error_1x.png) 1x,
+ url(chrome://resources/cr_components/chromeos/cellular_setup/error_2x.png) 2x);
+ background-position: center center;
+ background-repeat: no-repeat;
+ background-size: contain;
+ height: 100%;
+ width: 100%;
+ }
+
+ #networkConnectionMessage {
+ text-align: center;
+ }
+ </style>
+ <base-page title="[[getTitle_(state)]]"
+ message="[[getMessage_(state)]]"
+ message-icon="[[getMessageIcon_(state)]]">
+ <div slot="page-body" class="layout vertical center-center">
+ <paper-spinner-lite active hidden$="[[shouldShowSimDetectError_(state)]]">
+ </paper-spinner-lite>
+ <div id="networkConnectionMessage" hidden$="[[shouldShowSimDetectError_(state)]]">
+ [[loadingMessage]]
+ </div>
+ <div id="simDetectError" hidden$="[[!shouldShowSimDetectError_(state)]]"></div>
+ </div>
+ </base-page>
+ </template>
+ <script src="setup_loading_page.js"></script>
+</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.js
new file mode 100644
index 00000000000..284e9cecf5f
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.js
@@ -0,0 +1,91 @@
+// 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.
+
+/** @enum {number} */
+/* #export */ const LoadingPageState = {
+ LOADING: 1,
+ SIM_DETECT_ERROR: 2,
+ CELLULAR_DISCONNECT_WARNING: 3,
+};
+
+/**
+ * Loading subpage in Cellular Setup flow. This element contains image
+ * asset and description to indicate that a SIM detection or eSIM profiles
+ * loading is in progress. It can show a 'detecting sim' error or a 'cellular
+ * disconnection' warning depending on its state.
+ */
+Polymer({
+ is: 'setup-loading-page',
+
+ behaviors: [I18nBehavior],
+
+ properties: {
+ /** @type {!cellular_setup.CellularSetupDelegate} */
+ delegate: Object,
+
+ /** @type {!LoadingPageState} */
+ state: {
+ type: Object,
+ value: LoadingPageState.LOADING,
+ },
+
+ /**
+ * Message displayed with spinner when in LOADING state.
+ */
+ loadingMessage: {
+ type: String,
+ value: '',
+ },
+ },
+
+ /**
+ * @param {LoadingPageState} state
+ * @return {?string}
+ * @private
+ */
+ getTitle_(state) {
+ if (this.delegate.shouldShowPageTitle() &&
+ state === LoadingPageState.SIM_DETECT_ERROR) {
+ return this.i18n('simDetectPageErrorTitle');
+ }
+ return null;
+ },
+
+ /**
+ * @param {LoadingPageState} state
+ * @return {string}
+ * @private
+ */
+ getMessage_(state) {
+ switch (state) {
+ case LoadingPageState.SIM_DETECT_ERROR:
+ return this.i18n('simDetectPageErrorMessage');
+ case LoadingPageState.CELLULAR_DISCONNECT_WARNING:
+ return this.i18n('eSimConnectionWarning');
+ case LoadingPageState.LOADING:
+ return '';
+ default:
+ assertNotReached();
+ }
+ },
+
+ /**
+ * @param {LoadingPageState} state
+ * @return {string}
+ * @private
+ */
+ getMessageIcon_(state) {
+ return state === LoadingPageState.CELLULAR_DISCONNECT_WARNING ? 'warning' :
+ '';
+ },
+
+ /**
+ * @param {LoadingPageState} state
+ * @return {boolean}
+ * @private
+ */
+ shouldShowSimDetectError_(state) {
+ return state === LoadingPageState.SIM_DETECT_ERROR;
+ },
+});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.html
index 1e663c6e725..9a52fbdbbd3 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.html
@@ -75,14 +75,14 @@
#psimIconContainer {
background-image: -webkit-image-set(
- url(psim_1x.png) 1x,
- url(psim_2x.png) 2x);
+ url(chrome://resources/cr_components/chromeos/cellular_setup/psim_1x.png) 1x,
+ url(chrome://resources/cr_components/chromeos/cellular_setup/psim_2x.png) 2x);
}
#esimIconContainer {
background-image: -webkit-image-set(
- url(esim_1x.png) 1x,
- url(esim_2x.png) 2x);
+ url(chrome://resources/cr_components/chromeos/cellular_setup/esim_1x.png) 1x,
+ url(chrome://resources/cr_components/chromeos/cellular_setup/esim_2x.png) 2x);
}
.sim-btn-text {
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.js
index 16339d8e58e..474073bd9e7 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.js
@@ -17,11 +17,16 @@ Polymer({
properties: {
/**
* Element name of the current selected sub-page.
- * @private {!cellularSetup.CellularSetupPageName}
+ * @type {!cellularSetup.CellularSetupPageName}
*/
selectedPage: {
type: String,
notify: true,
+ },
+
+ forwardButtonLabel: {
+ type: String,
+ notify: true,
}
},
@@ -43,18 +48,15 @@ Polymer({
* @private
*/
updateButtonState_(selectedPage) {
+ this.forwardButtonLabel = this.i18n('next');
this.buttonState = {
- backward: cellularSetup.ButtonState.HIDDEN,
- cancel: cellularSetup.ButtonState.SHOWN_AND_ENABLED,
- done: cellularSetup.ButtonState.HIDDEN,
- tryAgain: cellularSetup.ButtonState.HIDDEN,
- skipDiscovery: cellularSetup.ButtonState.HIDDEN,
+ cancel: cellularSetup.ButtonState.ENABLED,
};
if (selectedPage === cellularSetup.CellularSetupPageName.PSIM_FLOW_UI ||
selectedPage === cellularSetup.CellularSetupPageName.ESIM_FLOW_UI) {
- this.buttonState.next = cellularSetup.ButtonState.SHOWN_AND_ENABLED;
+ this.set('buttonState.forward', cellularSetup.ButtonState.ENABLED);
} else {
- this.buttonState.next = cellularSetup.ButtonState.SHOWN_BUT_DISABLED;
+ this.set('buttonState.forward', cellularSetup.ButtonState.DISABLED);
}
}
}); \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.html
deleted file mode 100644
index b5e6b9148f6..00000000000
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<link rel="import" href="../../../html/polymer.html">
-
-<link rel="import" href="../../../html/i18n_behavior.html">
-<link rel="import" href="base_page.html">
-<link rel="import" href="cellular_setup_delegate.html">
-<link rel="import" href="../../../cr_elements/hidden_style_css.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
-
-<dom-module id="sim-detect-page">
- <template>
- <style include="iron-flex cr-hidden-style">
- #error-icon-container {
- background-image: -webkit-image-set(
- url(error_1x.png) 1x,
- url(error_2x.png) 2x);
- background-position: center center;
- background-repeat: no-repeat;
- background-size: contain;
- height: 100%;
- width: 100%;
- }
-
- #network-connection-message {
- text-align: center;
- }
- </style>
- <base-page title="[[getTitle_(showError)]]"
- message="[[getMessage_(showError)]]">
- <div slot="page-body" class="layout horizontal center-center">
- <!-- TODO(crbug.com/1093185): Conditionally show spinner when setup is added in OOBE -->
- <div id="network-connection-message" hidden$="[[showError]]">
- [[i18n('establishNetworkConnectionMessage')]]
- </div>
- <div id="error-icon-container" hidden$="[[!showError]]"></div>
- </div>
- </base-page>
- </template>
- <script src="sim_detect_page.js"></script>
-</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.js
deleted file mode 100644
index 61a68987c46..00000000000
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.js
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.
-
-/**
- * SIM Detection subpage in Cellular Setup flow. This element contains image
- * asset and description to indicate that the SIM detection is in progress.
- * It also has an error state that displays a message for errors that may
- * happen during this step.
- */
-Polymer({
- is: 'sim-detect-page',
-
- behaviors: [I18nBehavior],
-
- properties: {
- /** @type {!cellular_setup.CellularSetupDelegate} */
- delegate: Object,
-
- /**
- * Whether error state should be shown.
- * @type {boolean}
- */
- showError: Boolean,
- },
-
- /**
- * @param {boolean} showError
- * @return {?string}
- * @private
- */
- getTitle_(showError) {
- if (this.delegate.shouldShowPageTitle() && showError) {
- return this.i18n('simDetectPageErrorTitle');
- }
- return null;
- },
-
- /**
- * @param {boolean} showError
- * @return {string}
- * @private
- */
- getMessage_(showError) {
- return showError ? this.i18n('simDetectPageErrorMessage') : '';
- },
-});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.js
index 5ee36ed4016..0ec5e8c3796 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.js
@@ -4,8 +4,8 @@
/**
* @fileoverview Provides utility methods used by the cellular activation flow.
- * Current: chrome://mobilesetup (mobile_setup.html/mobile_setup_portal.html)
- * New UI: chrome://cellular-setup (cellular_setup_dialog.html)
+ * Current: chrome://mobilesetup (mobile_setup.html/mobile_setup_portal.html)
+ * New UI: cr_components/chromeos/cellular_setup/cellular_setup.html
*/
cr.define('webviewPost.util', function() {
/**
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 63fd8b30f9d..fc7414712d3 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
@@ -3,10 +3,14 @@
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/polymer/polymer.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
+import("../os_cr_components.gni")
assert(is_chromeos, "MultiDevice UI is Chrome OS only.")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [
":button_bar",
":fake_mojo_service",
@@ -82,6 +86,7 @@ js_library("setup_succeeded_page") {
js_library("start_setup_page") {
deps = [
":ui_page_container_behavior",
+ "//ui/webui/resources/cr_elements/cr_lottie:cr_lottie",
"//ui/webui/resources/js:web_ui_listener_behavior",
]
}
@@ -92,3 +97,219 @@ js_library("ui_page_container_behavior") {
"//ui/webui/resources/js:i18n_behavior",
]
}
+
+# Polymer 3 files
+
+js_type_check("closure_compile_module") {
+ is_polymer3 = true
+ deps = [
+ ":button_bar.m",
+ ":fake_mojo_service.m",
+ ":mojo_api.m",
+ ":multidevice_setup.m",
+ ":multidevice_setup_browser_proxy.m",
+ ":multidevice_setup_delegate.m",
+ ":multidevice_setup_shared_css.m",
+ ":setup_succeeded_page.m",
+ ":start_setup_page.m",
+ ":ui_page.m",
+ ":ui_page_container_behavior.m",
+ "//ui/webui/resources/js:web_ui_listener_behavior.m",
+ ]
+}
+
+js_library("button_bar.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.m.js" ]
+ deps = [
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ ]
+ extra_deps = [ ":button_bar_module" ]
+}
+
+js_library("fake_mojo_service.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.m.js" ]
+ deps = [
+ "//chromeos/services/multidevice_setup/public/mojom:mojom_js_library_for_compile",
+ "//ui/webui/resources/js:cr.m",
+ ]
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("mojo_api.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.m.js" ]
+ deps = [
+ "//chromeos/services/multidevice_setup/public/mojom:mojom_js_library_for_compile",
+ "//ui/webui/resources/js:cr.m",
+ ]
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("multidevice_setup.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.m.js" ]
+ deps = [
+ ":button_bar.m",
+ ":fake_mojo_service.m",
+ ":mojo_api.m",
+ ":multidevice_setup_delegate.m",
+ ":multidevice_setup_shared_css.m",
+ ":password_page.m",
+ ":setup_succeeded_page.m",
+ ":start_setup_page.m",
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js:web_ui_listener_behavior.m",
+ ]
+ extra_deps = [ ":multidevice_setup_module" ]
+}
+
+js_library("multidevice_setup_browser_proxy.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.m.js" ]
+ deps = [ "//ui/webui/resources/js:cr.m" ]
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("multidevice_setup_delegate.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.m.js" ]
+ deps = [ "//ui/webui/resources/js:cr.m" ]
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("password_page.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.m.js" ]
+ deps = [
+ ":multidevice_setup_browser_proxy.m",
+ ":multidevice_setup_shared_css.m",
+ ]
+ extra_deps = [ ":password_page_module" ]
+ externs_list = chrome_extension_public_externs +
+ [ "$externs_path/quick_unlock_private.js" ]
+ extra_sources = [ "$interfaces_path/quick_unlock_private_interface.js" ]
+}
+
+js_library("setup_succeeded_page.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.m.js" ]
+ deps = [
+ ":multidevice_setup_browser_proxy.m",
+ ":multidevice_setup_shared_css.m",
+ ":ui_page_container_behavior.m",
+ ]
+ extra_deps = [ ":setup_succeeded_page_module" ]
+}
+
+js_library("start_setup_page.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.m.js" ]
+ deps = [
+ ":mojo_api.m",
+ ":multidevice_setup_delegate.m",
+ ":multidevice_setup_shared_css.m",
+ ":ui_page_container_behavior.m",
+ "//ui/webui/resources/cr_elements/cr_lottie:cr_lottie.m",
+ "//ui/webui/resources/js:web_ui_listener_behavior.m",
+ ]
+ extra_deps = [ ":start_setup_page_module" ]
+}
+
+js_library("ui_page_container_behavior.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.m.js" ]
+ deps = [
+ "//ui/webui/resources/js:cr.m",
+ "//ui/webui/resources/js:i18n_behavior.m",
+ ]
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("multidevice_setup_shared_css.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_shared_css.m.js" ]
+ deps = []
+ extra_deps = [ ":multidevice_setup_shared_css_module" ]
+}
+
+js_library("ui_page.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.m.js" ]
+ deps = [ ":multidevice_setup_shared_css.m" ]
+ extra_deps = [ ":ui_page_module" ]
+}
+
+group("polymer3_elements") {
+ public_deps = [
+ ":button_bar_module",
+ ":icons_module",
+ ":modulize",
+ ":multidevice_setup_module",
+ ":multidevice_setup_shared_css_module",
+ ":password_page_module",
+ ":setup_succeeded_page_module",
+ ":start_setup_page_module",
+ ":ui_page_module",
+ ]
+}
+
+polymer_modulizer("button_bar") {
+ js_file = "button_bar.js"
+ html_file = "button_bar.html"
+ html_type = "dom-module"
+ namespace_rewrites = cr_components_chromeos_namespace_rewrites
+ auto_imports = cr_components_chromeos_auto_imports
+}
+
+polymer_modulizer("multidevice_setup") {
+ js_file = "multidevice_setup.js"
+ html_file = "multidevice_setup.html"
+ html_type = "dom-module"
+ namespace_rewrites = cr_components_chromeos_namespace_rewrites
+ auto_imports = cr_components_chromeos_auto_imports
+}
+
+polymer_modulizer("password_page") {
+ js_file = "password_page.js"
+ html_file = "password_page.html"
+ html_type = "dom-module"
+ namespace_rewrites = cr_components_chromeos_namespace_rewrites
+ auto_imports = cr_components_chromeos_auto_imports
+}
+
+polymer_modulizer("setup_succeeded_page") {
+ js_file = "setup_succeeded_page.js"
+ html_file = "setup_succeeded_page.html"
+ html_type = "dom-module"
+ namespace_rewrites = cr_components_chromeos_namespace_rewrites
+ auto_imports = cr_components_chromeos_auto_imports
+}
+
+polymer_modulizer("start_setup_page") {
+ js_file = "start_setup_page.js"
+ html_file = "start_setup_page.html"
+ html_type = "dom-module"
+ namespace_rewrites = cr_components_chromeos_namespace_rewrites
+ auto_imports = cr_components_chromeos_auto_imports
+}
+
+polymer_modulizer("multidevice_setup_shared_css") {
+ js_file = "multidevice_setup_shared_css.m.js"
+ html_file = "multidevice_setup_shared_css.html"
+ html_type = "style-module"
+}
+
+polymer_modulizer("ui_page") {
+ js_file = "ui_page.js"
+ html_file = "ui_page.html"
+ html_type = "dom-module"
+ namespace_rewrites = cr_components_chromeos_namespace_rewrites
+ auto_imports = cr_components_chromeos_auto_imports
+}
+
+polymer_modulizer("icons") {
+ js_file = "icons.m.js"
+ html_file = "icons.html"
+ html_type = "iron-iconset"
+}
+
+js_modulizer("modulize") {
+ input_files = [
+ "fake_mojo_service.js",
+ "mojo_api.js",
+ "multidevice_setup_browser_proxy.js",
+ "multidevice_setup_delegate.js",
+ "ui_page_container_behavior.js",
+ ]
+ namespace_rewrites = cr_components_chromeos_namespace_rewrites
+}
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_1x.svg b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_1x.svg
new file mode 100644
index 00000000000..bbaed9067ff
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_1x.svg
@@ -0,0 +1 @@
+<svg width="520" height="320" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M0 0h520v320H0z"/><path d="M436.519 96.534h-49.22c-3.716 0-6.728 3.13-6.728 6.991v116.686c0 3.861 3.012 6.992 6.728 6.992h49.22c3.716 0 6.728-3.131 6.728-6.992V103.525c0-3.861-3.012-6.991-6.728-6.991z" fill="#D2E3FC"/><path d="M436.519 96.534h-49.22c-3.716 0-6.728 3.13-6.728 6.991v116.686c0 3.861 3.012 6.992 6.728 6.992h49.22c3.716 0 6.728-3.131 6.728-6.992V103.525c0-3.861-3.012-6.991-6.728-6.991z" fill="#D2E3FC"/><path d="M284.416 114.222c3.759 0 6.806-3.166 6.806-7.073 0-3.907-3.047-7.073-6.806-7.073s-6.807 3.166-6.807 7.073c0 3.907 3.048 7.073 6.807 7.073z" fill="#34A853"/><path d="M193.845 126.414l-49.152 13.901c-.353.1-.675.294-.932.564a2.177 2.177 0 0 0-.536.972c-.092.368-.09.755.006 1.121.097.367.285.7.546.967l36.15 37.281c.261.268.586.459.942.554.356.095.729.09 1.083-.014.353-.104.673-.304.929-.578.255-.275.435-.615.523-.985l12.992-51.183a2.243 2.243 0 0 0-.021-1.104 2.177 2.177 0 0 0-.543-.95 2.065 2.065 0 0 0-.924-.546 1.998 1.998 0 0 0-1.063 0z" fill="#FFBA00"/><path d="M380.571 146.488c-5.209.224-10.298-1.663-14.194-5.262l-5.092-4.708-2.315-1.935a16.471 16.471 0 0 0-8.236-2.974 16.36 16.36 0 0 0-6.574.844 16.806 16.806 0 0 0-5.762 3.397 17.537 17.537 0 0 0-4.071 5.431 18.253 18.253 0 0 0-.936 13.468 17.791 17.791 0 0 0 3.277 5.983 17.08 17.08 0 0 0 5.232 4.223c.639.327 1.297.614 1.97.859h.049s2.768.758 2.847.768l6.678 1.433c5.222 1.129 9.801 4.36 12.736 8.988l3.31 5.231a25.023 25.023 0 0 0 3.083 4.862 24.214 24.214 0 0 0 8.008 6.469" fill="#D2E3FC"/><path d="M380.571 193.596a23.405 23.405 0 0 0 12.022 2.444 23.544 23.544 0 0 0 9.972-2.957 24.527 24.527 0 0 0 7.869-7.019 25.66 25.66 0 0 0 4.325-9.795 26.16 26.16 0 0 0-.012-10.777 25.637 25.637 0 0 0-4.346-9.785 24.497 24.497 0 0 0-7.884-7.001 23.549 23.549 0 0 0-9.978-2.935 23.27 23.27 0 0 0-5.595.338l-6.018.369h-.345" fill="#4285F4"/><path d="M333.714 163.02c12.561 0 22.744-10.582 22.744-23.636 0-13.054-10.183-23.636-22.744-23.636s-22.743 10.582-22.743 23.636c0 13.054 10.182 23.636 22.743 23.636zm76.682-58.778h11.85" stroke="#4285F4" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><path d="M403.857 105.839c.849 0 1.536-.715 1.536-1.597s-.687-1.597-1.536-1.597-1.537.715-1.537 1.597.688 1.597 1.537 1.597z" fill="#4285F4"/><mask id="a" maskUnits="userSpaceOnUse" x="332" y="131" width="49" height="63"><path d="M380.571 146.488c-5.209.224-10.298-1.663-14.194-5.262l-5.092-4.709-2.315-1.934a17.18 17.18 0 0 0-1.852-1.137 16.487 16.487 0 0 0-6.384-1.837 16.36 16.36 0 0 0-6.574.844 16.806 16.806 0 0 0-5.762 3.397 17.525 17.525 0 0 0-4.071 5.431 18.253 18.253 0 0 0-.936 13.468 17.791 17.791 0 0 0 3.277 5.983 17.062 17.062 0 0 0 5.232 4.222c.639.328 1.297.615 1.97.86h.049s2.768.758 2.847.768l6.678 1.433c5.222 1.129 9.801 4.36 12.736 8.988l3.31 5.231a25.023 25.023 0 0 0 3.083 4.862 24.226 24.226 0 0 0 8.008 6.469" fill="#D2E3FC"/></mask><g mask="url(#a)"><path d="M333.714 163.02c12.561 0 22.744-10.582 22.744-23.636 0-13.054-10.183-23.636-22.744-23.636s-22.743 10.582-22.743 23.636c0 13.054 10.182 23.636 22.743 23.636z" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></g><path d="M99.748 162.416a24.382 24.382 0 0 1 9.84-1.028 24.595 24.595 0 0 1 9.467 2.971 25.54 25.54 0 0 1 7.647 6.517 26.638 26.638 0 0 1 4.659 9.066 27.275 27.275 0 0 1 .957 10.229 27.036 27.036 0 0 1-2.889 9.829 26.104 26.104 0 0 1-6.296 7.926 24.985 24.985 0 0 1-8.738 4.812" fill="#F882FF"/><path d="M85.14 118.03l30.899 109.531 107.001-1.31" stroke="#4285F4" stroke-width="6" stroke-linejoin="round"/><path d="M178.045 129.966a17.323 17.323 0 0 1 .283-6.508 16.966 16.966 0 0 1 2.661-5.898 16.303 16.303 0 0 1 4.633-4.387 15.668 15.668 0 0 1 5.898-2.206l37.105-5.957a15.45 15.45 0 0 1 6.255.292 15.788 15.788 0 0 1 5.671 2.759 16.453 16.453 0 0 1 4.223 4.804 17.097 17.097 0 0 1 2.133 6.117v0a17.321 17.321 0 0 1-.278 6.5 16.985 16.985 0 0 1-2.651 5.893 16.284 16.284 0 0 1-4.621 4.39 15.668 15.668 0 0 1-5.886 2.216l-37.105 5.948a15.463 15.463 0 0 1-6.265-.276 15.777 15.777 0 0 1-5.685-2.752 16.446 16.446 0 0 1-4.234-4.807 17.113 17.113 0 0 1-2.137-6.128v0z" stroke="#FE2C25" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><mask id="b" maskUnits="userSpaceOnUse" x="143" y="126" width="54" height="56"><path d="M193.845 126.414l-49.152 13.901a2.062 2.062 0 0 0-.932.563c-.258.27-.443.606-.536.973-.092.368-.09.755.006 1.121.097.367.285.7.546.967l36.15 37.281c.261.268.586.459.942.554.356.095.729.09 1.083-.014.353-.104.673-.304.929-.578.255-.275.435-.615.523-.985l12.992-51.183a2.247 2.247 0 0 0-.021-1.105 2.18 2.18 0 0 0-.543-.949 2.056 2.056 0 0 0-.924-.546 1.998 1.998 0 0 0-1.063 0z" fill="#FFBA00"/></mask><g mask="url(#b)"><path d="M178.045 129.966a17.323 17.323 0 0 1 .283-6.508 16.966 16.966 0 0 1 2.661-5.898 16.303 16.303 0 0 1 4.633-4.387 15.668 15.668 0 0 1 5.898-2.206l37.105-5.957a15.45 15.45 0 0 1 6.255.292 15.788 15.788 0 0 1 5.671 2.759 16.453 16.453 0 0 1 4.223 4.804 17.097 17.097 0 0 1 2.133 6.117v0a17.321 17.321 0 0 1-.278 6.5 16.985 16.985 0 0 1-2.651 5.893 16.284 16.284 0 0 1-4.621 4.39 15.668 15.668 0 0 1-5.886 2.216l-37.105 5.948a15.463 15.463 0 0 1-6.265-.276 15.777 15.777 0 0 1-5.685-2.752 16.446 16.446 0 0 1-4.234-4.807 17.113 17.113 0 0 1-2.137-6.128v0z" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></g></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_2x.svg b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_2x.svg
new file mode 100644
index 00000000000..0ea7ffbff02
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_2x.svg
@@ -0,0 +1 @@
+<svg width="1040" height="640" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M0 0h1040v640H0z"/><path d="M873.039 193.068h-98.441c-7.431 0-13.455 6.26-13.455 13.983v233.371c0 7.723 6.024 13.983 13.455 13.983h98.441c7.431 0 13.455-6.26 13.455-13.983V207.051c0-7.723-6.024-13.983-13.455-13.983z" fill="#D2E3FC"/><path d="M873.039 193.068h-98.441c-7.431 0-13.455 6.26-13.455 13.983v233.371c0 7.723 6.024 13.983 13.455 13.983h98.441c7.431 0 13.455-6.26 13.455-13.983V207.051c0-7.723-6.024-13.983-13.455-13.983z" fill="#D2E3FC"/><path d="M568.831 228.445c7.519 0 13.613-6.334 13.613-14.147 0-7.813-6.094-14.147-13.613-14.147-7.518 0-13.612 6.334-13.612 14.147 0 7.813 6.094 14.147 13.612 14.147z" fill="#34A853"/><path d="M387.689 252.828l-98.303 27.803a4.128 4.128 0 0 0-1.865 1.126 4.372 4.372 0 0 0-1.07 1.946 4.48 4.48 0 0 0 .012 2.242c.194.733.57 1.4 1.091 1.933l72.299 74.563a4.13 4.13 0 0 0 1.885 1.107 4.01 4.01 0 0 0 2.165-.028 4.122 4.122 0 0 0 1.858-1.157 4.364 4.364 0 0 0 1.046-1.97l25.984-102.365a4.49 4.49 0 0 0-.04-2.209 4.364 4.364 0 0 0-1.087-1.899 4.115 4.115 0 0 0-1.849-1.092 4.006 4.006 0 0 0-2.126 0z" fill="#FFBA00"/><path d="M761.142 292.976c-10.417.448-20.595-3.325-28.388-10.523l-10.185-9.418-4.629-3.869a34.255 34.255 0 0 0-3.704-2.273 32.946 32.946 0 0 0-12.768-3.675 32.732 32.732 0 0 0-13.149 1.688 33.644 33.644 0 0 0-11.524 6.793 35.106 35.106 0 0 0-8.141 10.863 36.309 36.309 0 0 0-3.517 13.275 36.552 36.552 0 0 0 1.644 13.662 35.654 35.654 0 0 0 6.554 11.966 34.13 34.13 0 0 0 10.465 8.444 34.818 34.818 0 0 0 3.94 1.72h.098s5.536 1.515 5.693 1.535l13.357 2.866c10.443 2.257 19.602 8.72 25.472 17.976l6.619 10.461a50.166 50.166 0 0 0 6.166 9.725c4.394 5.446 9.854 9.857 16.017 12.939" fill="#D2E3FC"/><path d="M761.143 387.192a52.023 52.023 0 0 0 3.546 1.597 46.793 46.793 0 0 0 20.497 3.292 47.103 47.103 0 0 0 19.944-5.915c6.159-3.445 11.528-8.234 15.738-14.038 4.21-5.805 7.16-12.488 8.649-19.591a52.284 52.284 0 0 0-.023-21.554c-1.504-7.098-4.469-13.775-8.691-19.57s-9.602-10.572-15.768-14.002a47.09 47.09 0 0 0-19.957-5.869 46.49 46.49 0 0 0-11.19.676l-12.036.737h-.69" fill="#4285F4"/><path d="M667.429 326.04c25.122 0 45.487-21.165 45.487-47.273 0-26.107-20.365-47.272-45.487-47.272-25.122 0-45.488 21.165-45.488 47.272 0 26.108 20.366 47.273 45.488 47.273zm153.364-117.556h23.699" stroke="#4285F4" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/><path d="M807.714 211.678c1.697 0 3.073-1.43 3.073-3.194s-1.376-3.194-3.073-3.194-3.073 1.43-3.073 3.194 1.376 3.194 3.073 3.194z" fill="#4285F4"/><mask id="a" maskUnits="userSpaceOnUse" x="665" y="263" width="97" height="125"><path d="M761.142 292.976c-10.417.447-20.595-3.325-28.388-10.524l-10.185-9.417-4.629-3.87a34.405 34.405 0 0 0-3.704-2.272 32.946 32.946 0 0 0-12.768-3.675 32.732 32.732 0 0 0-13.149 1.688 33.628 33.628 0 0 0-11.524 6.793 35.106 35.106 0 0 0-8.141 10.863 36.304 36.304 0 0 0-3.517 13.274 36.557 36.557 0 0 0 1.644 13.663 35.64 35.64 0 0 0 6.554 11.965 34.119 34.119 0 0 0 10.465 8.445 34.818 34.818 0 0 0 3.94 1.72h.098s5.536 1.515 5.693 1.535l13.357 2.866c10.443 2.257 19.602 8.72 25.472 17.975l6.619 10.462a50.197 50.197 0 0 0 6.166 9.725c4.394 5.446 9.854 9.857 16.017 12.939" fill="#D2E3FC"/></mask><g mask="url(#a)"><path d="M667.429 326.04c25.122 0 45.487-21.165 45.487-47.273 0-26.107-20.365-47.272-45.487-47.272-25.122 0-45.488 21.165-45.488 47.272 0 26.108 20.366 47.273 45.488 47.273z" stroke="#fff" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/></g><path d="M199.496 324.832a48.765 48.765 0 0 1 19.68-2.056 49.19 49.19 0 0 1 18.934 5.943c5.873 3.256 11.071 7.685 15.294 13.033a53.257 53.257 0 0 1 9.317 18.132 54.55 54.55 0 0 1 1.915 20.458A54.092 54.092 0 0 1 258.857 400c-3.152 6.093-7.431 11.481-12.59 15.852-5.16 4.372-11.099 7.643-17.477 9.625" fill="#F882FF"/><path d="M170.279 236.061l61.799 219.061 214.001-2.621" stroke="#4285F4" stroke-width="12" stroke-linejoin="round"/><path d="M356.091 259.932a34.598 34.598 0 0 1 .564-13.015 33.917 33.917 0 0 1 5.323-11.796 32.527 32.527 0 0 1 9.267-8.774 31.303 31.303 0 0 1 11.795-4.413l74.21-11.915a30.918 30.918 0 0 1 12.51.586 31.566 31.566 0 0 1 11.342 5.517 32.914 32.914 0 0 1 8.446 9.607 34.203 34.203 0 0 1 4.266 12.236v0a34.616 34.616 0 0 1-.556 12.999 33.93 33.93 0 0 1-5.303 11.787 32.561 32.561 0 0 1-9.241 8.779 31.31 31.31 0 0 1-11.771 4.433l-74.21 11.894c-4.171.675-8.43.488-12.531-.551a31.546 31.546 0 0 1-11.37-5.504 32.897 32.897 0 0 1-8.468-9.615 34.155 34.155 0 0 1-4.273-12.255v0z" stroke="#FE2C25" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/><mask id="b" maskUnits="userSpaceOnUse" x="286" y="252" width="107" height="112"><path d="M387.689 252.828l-98.303 27.802a4.13 4.13 0 0 0-1.865 1.127 4.367 4.367 0 0 0-1.07 1.946 4.477 4.477 0 0 0 .012 2.241c.194.733.57 1.4 1.091 1.934l72.299 74.562a4.123 4.123 0 0 0 1.885 1.108 4.01 4.01 0 0 0 2.165-.029 4.129 4.129 0 0 0 1.858-1.156 4.37 4.37 0 0 0 1.046-1.97l25.984-102.365a4.49 4.49 0 0 0-.04-2.209 4.364 4.364 0 0 0-1.087-1.899 4.126 4.126 0 0 0-1.849-1.093 4.006 4.006 0 0 0-2.126.001z" fill="#FFBA00"/></mask><g mask="url(#b)"><path d="M356.091 259.932a34.598 34.598 0 0 1 .564-13.015 33.917 33.917 0 0 1 5.323-11.796 32.527 32.527 0 0 1 9.267-8.774 31.303 31.303 0 0 1 11.795-4.413l74.21-11.915a30.918 30.918 0 0 1 12.51.586 31.566 31.566 0 0 1 11.342 5.517 32.914 32.914 0 0 1 8.446 9.607 34.203 34.203 0 0 1 4.266 12.236v0a34.616 34.616 0 0 1-.556 12.999 33.93 33.93 0 0 1-5.303 11.787 32.561 32.561 0 0 1-9.241 8.779 31.31 31.31 0 0 1-11.771 4.433l-74.21 11.894c-4.171.675-8.43.488-12.531-.551a31.546 31.546 0 0 1-11.37-5.504 32.897 32.897 0 0 1-8.468-9.615 34.155 34.155 0 0 1-4.273-12.255v0z" stroke="#fff" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/></g></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html
index b448b290e00..cd25990692e 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html
@@ -27,7 +27,7 @@
}
}
</style>
- <div id="shadow" hidden></div>
+ <div id="shadow" hidden$="[[!shouldShowShadow]]"></div>
<div id="button-container">
<div id="backward"
on-click="onBackwardButtonClicked_"
@@ -47,6 +47,5 @@
</div>
</div>
</template>
- <script src="button_bar.js">
- </script>
+ <script src="button_bar.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.js
index d3176fc6f14..c635763ead5 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.js
@@ -32,7 +32,6 @@ Polymer({
shouldShowShadow: {
type: Boolean,
value: false,
- observer: 'onShouldShowShadowChange_',
}
},
@@ -50,9 +49,4 @@ Polymer({
onBackwardButtonClicked_() {
this.fire('backward-navigation-requested');
},
-
- /** @private */
- onShouldShowShadowChange_() {
- this.$.shadow.hidden = !!this.shouldShowShadow;
- },
});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html
index a2c17b6179d..55f5b15b2ab 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html
@@ -1,4 +1,3 @@
<link rel="import" href="../../../html/cr.html">
-<script src="fake_mojo_service.js">
-</script>
+<script src="fake_mojo_service.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.js
index 965b3fb3a28..8c7af90e813 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.js
@@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// clang-format off
+// #import {assertNotReached} from 'chrome://resources/js/assert.m.js';
+// clang-format on
+
/**
* @implements {chromeos.multideviceSetup.mojom.MultiDeviceSetupInterface}
*/
-class FakeMojoService {
+/* #export */ class FakeMojoService {
constructor() {
/**
* The number of devices to return in a getEligibleHostDevices() call.
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/icons.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/icons.html
index 10b457d3e43..c8544a0de02 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/icons.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/icons.html
@@ -23,20 +23,20 @@
<svg>
<defs>
<g id="messages" fill="none" fill-rule="evenodd">
- <path d="M16.3107503,3 L3.66666667,3 C2.75,3 2,3.75 2,4.66666667 L2,18.3161621 L5.33333333,15 L16.3107503,15 C17.227417,15 17.977417,14.2328288 17.977417,13.3161621 L17.977417,4.66666667 C17.977417,3.75 17.227417,3 16.3107503,3 Z M16,13 L4,13 L4,5 L16,5 L16,13 Z M6,8 L8,8 L8,10 L6,10 L6,8 Z M9,8 L11,8 L11,10 L9,10 L9,8 Z M12,8 L14,8 L14,10 L12,10 L12,8 Z" fill="#9AA0A6"></path>
+ <path d="M16.3107503,3 L3.66666667,3 C2.75,3 2,3.75 2,4.66666667 L2,18.3161621 L5.33333333,15 L16.3107503,15 C17.227417,15 17.977417,14.2328288 17.977417,13.3161621 L17.977417,4.66666667 C17.977417,3.75 17.227417,3 16.3107503,3 Z M16,13 L4,13 L4,5 L16,5 L16,13 Z M6,8 L8,8 L8,10 L6,10 L6,8 Z M9,8 L11,8 L11,10 L9,10 L9,8 Z M12,8 L14,8 L14,10 L12,10 L12,8 Z" fill="#1E88E5"></path>
</g>
<g id="notifications" fill="none" fill-rule="evenodd">
- <path d="M11,3.10001812 C13.2822403,3.56328845 15,5.58104209 15,8 C15,10.7614237 15,13 15,13 L17,13 L17,15 L3,15 L3,13 L5,13 C5,13 5,9.9021552 5,8 C5,5.58104209 6.71775968,3.56328845 9,3.10001812 L9,2.5 C9,1.94771525 9.44771525,1.5 10,1.5 C10.5522847,1.5 11,1.94771525 11,2.5 L11,3.10001812 Z M7,8 L7,13 L13,13 L13,8 C13,6.34314575 11.6568542,5 10,5 C8.34314575,5 7,6.34314575 7,8 Z M10,18 C8.8954305,18 8,17.1045695 8,16 L12,16 C12,17.1045695 11.1045695,18 10,18 Z" fill="#9AA0A6"></path>
+ <path d="M11,3.10001812 C13.2822403,3.56328845 15,5.58104209 15,8 C15,10.7614237 15,13 15,13 L17,13 L17,15 L3,15 L3,13 L5,13 C5,13 5,9.9021552 5,8 C5,5.58104209 6.71775968,3.56328845 9,3.10001812 L9,2.5 C9,1.94771525 9.44771525,1.5 10,1.5 C10.5522847,1.5 11,1.94771525 11,2.5 L11,3.10001812 Z M7,8 L7,13 L13,13 L13,8 C13,6.34314575 11.6568542,5 10,5 C8.34314575,5 7,6.34314575 7,8 Z M10,18 C8.8954305,18 8,17.1045695 8,16 L12,16 C12,17.1045695 11.1045695,18 10,18 Z" fill="#1E88E5"></path>
</g>
<g id="wifi" fill="none" fill-rule="evenodd">
- <path d="M10.01 17.99L20 5.46C19.613 5.164 15.765 2 10 2 4.227 2 .387 5.165 0 5.46l9.99 12.53.01.01.01-.01z" fill="#9AA0A6" fill-opacity=".3"></path>
- <path d="M2.942 9.143l7.05 8.85L10 18l.008-.008 7.05-8.85C16.7 8.867 14.008 6.668 10 6.668s-6.7 2.2-7.058 2.476z" fill="#9AA0A6"></path>
+ <path d="M10.01 17.99L20 5.46C19.613 5.164 15.765 2 10 2 4.227 2 .387 5.165 0 5.46l9.99 12.53.01.01.01-.01z" fill="#1E88E5" fill-opacity=".3"></path>
+ <path d="M2.942 9.143l7.05 8.85L10 18l.008-.008 7.05-8.85C16.7 8.867 14.008 6.668 10 6.668s-6.7 2.2-7.058 2.476z" fill="#1E88E5"></path>
</g>
<g id="downloads" fill="none" fill-rule="evenodd">
- <path d="M2,13 L4,13 L4,16 L16,16 L16,13 L18,13 L18,16 C18,17.1 17.1,18 16,18 L4,18 C2.9,18 2,17.1 2,16 L2,13 Z M13.59,7.59 L11,10.17 L11,2 L9,2 L9,10.17 L6.41,7.59 L5,9 L10,14 L15,9 L13.59,7.59 Z" fill="#9AA0A6"></path>
+ <path d="M2,13 L4,13 L4,16 L16,16 L16,13 L18,13 L18,16 C18,17.1 17.1,18 16,18 L4,18 C2.9,18 2,17.1 2,16 L2,13 Z M13.59,7.59 L11,10.17 L11,2 L9,2 L9,10.17 L6.41,7.59 L5,9 L10,14 L15,9 L13.59,7.59 Z" fill="#1E88E5"></path>
</g>
<g id="features" fill="none" fill-rule="evenodd">
- <path d="M5,5 L18,5 L18,3.5 L5.16080729,3.5 C4.24414063,3.5 3.49414062,4.23125 3.49414062,5.125 L3.49414062,14 L1,14 L1,17 L11,17 L11,14 L5,14 L5,5 Z M18.1666667,6.49829102 L13.3713582,6.49829102 C12.9130249,6.49829102 12.5,6.86391602 12.5,7.31079102 L12.5,16.171875 C12.5,16.61875 12.9130249,17 13.3713582,17 L18.1666667,17 C18.625,17 19,16.61875 19,16.171875 L19,7.31079102 C19,6.86391602 18.625,6.49829102 18.1666667,6.49829102 Z M17.5,14 L14,14 L14,8.5 L17.5,8.5 L17.5,14 Z" fill="#9AA0A6"></path>
+ <path d="M5,5 L18,5 L18,3.5 L5.16080729,3.5 C4.24414063,3.5 3.49414062,4.23125 3.49414062,5.125 L3.49414062,14 L1,14 L1,17 L11,17 L11,14 L5,14 L5,5 Z M18.1666667,6.49829102 L13.3713582,6.49829102 C12.9130249,6.49829102 12.5,6.86391602 12.5,7.31079102 L12.5,16.171875 C12.5,16.61875 12.9130249,17 13.3713582,17 L18.1666667,17 C18.625,17 19,16.61875 19,16.171875 L19,7.31079102 C19,6.86391602 18.625,6.49829102 18.1666667,6.49829102 Z M17.5,14 L14,14 L14,8.5 L17.5,8.5 L17.5,14 Z" fill="#1E88E5"></path>
</g>
</defs>
</svg>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js
index c34499265b6..6d5ba3ad4ee 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js
@@ -2,9 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// clang-format off
+// #import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
+// #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
+// #import 'chrome://resources/mojo/mojo/public/mojom/base/time.mojom-lite.js';
+// #import 'chrome://resources/mojo/chromeos/components/multidevice/mojom/multidevice_types.mojom-lite.js';
+// #import 'chrome://resources/mojo/chromeos/services/device_sync/public/mojom/device_sync.mojom-lite.js';
+// #import 'chrome://resources/mojo/chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom-lite.js';
+// clang-format on
+
cr.define('multidevice_setup', function() {
/** @interface */
- class MojoInterfaceProvider {
+ /* #export */ class MojoInterfaceProvider {
/**
* @return {!chromeos.multideviceSetup.mojom.MultiDeviceSetupRemote}
*/
@@ -12,7 +21,7 @@ cr.define('multidevice_setup', function() {
}
/** @implements {multidevice_setup.MojoInterfaceProvider} */
- class MojoInterfaceProviderImpl {
+ /* #export */ class MojoInterfaceProviderImpl {
constructor() {
/** @private {?chromeos.multideviceSetup.mojom.MultiDeviceSetupRemote} */
this.remote_ = null;
@@ -31,6 +40,7 @@ cr.define('multidevice_setup', function() {
cr.addSingletonGetter(MojoInterfaceProviderImpl);
+ // #cr_define_end
return {
MojoInterfaceProvider: MojoInterfaceProvider,
MojoInterfaceProviderImpl: MojoInterfaceProviderImpl,
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 6e61d099146..5ee7f92a284 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
@@ -10,6 +10,7 @@
<link rel="import" href="start_setup_page.html">
<link rel="import" href="../../../html/cr.html">
<link rel="import" href="../../../html/web_ui_listener_behavior.html">
+<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
<dom-module id="multidevice-setup">
@@ -31,8 +32,6 @@
height: 100%;
line-height: 16px;
margin: auto;
- max-width: var(--multidevice-setup-width, var(--default-ui-width));
- padding: 32px;
}
iron-pages {
@@ -40,26 +39,49 @@
padding: 0 32px;
}
+ :host-context([new-layout]) iron-pages {
+ height: 100%;
+ padding: 0;
+ }
+
+ :host-context([new-layout]) button-bar {
+ padding: 24px;
+ }
+
+ @media screen and (orientation: portrait) {
+ :host-context([new-layout][screen=oobe]) button-bar,
+ :host-context([new-layout][screen=gaia-signin]) button-bar {
+ align-items: center;
+ }
+ }
+
+ :host-context(html:not([new-layout])) #container {
+ max-width: var(--multidevice-setup-width, var(--default-ui-width));
+ padding: 32px;
+ }
+
@media screen and (max-width: 767px) {
/* On narrow screens, decrease width/padding. */
- #container {
+ :host-context(html:not([new-layout])) #container {
height: auto;
- /* Add height of buttons plus padding on top and bottom of buttons. */
+ /*
+ * Add height of buttons plus padding on top and bottom of buttons.
+ */
margin-bottom: calc(var(--narrow-button-bar-height) +
calc(2 * var(--narrow-button-bar-spacing)));
padding: 32px 32px 0 32px;
}
- iron-pages {
+ :host-context(html:not([new-layout])) iron-pages {
padding: 0;
}
/*
- * Fix the button bar to the bottom of the window. Some content may be
- * beneath the button bar, so make the background slightly transparent
- * so that the content can be seen.
- */
- button-bar {
+ * Fix the button bar to the bottom of the window. Some content may be
+ * beneath the button bar, so make the background slightly transparent
+ * so that the content can be seen.
+ */
+ :host-context(html:not([new-layout])) button-bar {
background: rgba(255, 255, 255, 0.9);
bottom: 0;
height: var(--narrow-button-bar-height);
@@ -105,6 +127,5 @@
</button-bar>
</div>
</template>
- <script src="multidevice_setup.js">
- </script>
+ <script src="multidevice_setup.js"></script>
</dom-module>
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 a565031984e..241167e28dc 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
@@ -4,7 +4,7 @@
cr.define('multidevice_setup', function() {
/** @enum {string} */
- const PageName = {
+ /* #export */ const PageName = {
PASSWORD: 'password-page',
SUCCESS: 'setup-succeeded-page',
START: 'start-setup-page',
@@ -176,6 +176,7 @@ cr.define('multidevice_setup', function() {
},
initializeSetupFlow() {
+ this.$$('start-setup-page').setPlayAnimation(true);
this.mojoInterfaceProvider_.getMojoServiceRemote()
.getEligibleActiveHostDevices()
.then((responseParams) => {
@@ -364,10 +365,12 @@ cr.define('multidevice_setup', function() {
* @private
*/
exitSetupFlow_(didUserCompleteSetup) {
+ this.$$('start-setup-page').setPlayAnimation(false);
this.fire('setup-exited', {didUserCompleteSetup: didUserCompleteSetup});
},
});
+ // #cr_define_end
return {
MultiDeviceSetup: MultiDeviceSetup,
PageName: PageName,
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html
index 38c23fdedf0..29e0582cae9 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html
@@ -1,3 +1,2 @@
<link rel="import" href="../../../html/cr.html">
-<script src="multidevice_setup_browser_proxy.js">
-</script>
+<script src="multidevice_setup_browser_proxy.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js
index be88d746277..841f851c376 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js
@@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// clang-format off
+// #import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+// clang-format on
+
cr.define('multidevice_setup', function() {
/** @interface */
- class BrowserProxy {
+ /* #export */ class BrowserProxy {
/**
* Requests profile information; namely, a dictionary containing the user's
* e-mail address and profile photo.
@@ -20,7 +24,7 @@ cr.define('multidevice_setup', function() {
}
/** @implements {multidevice_setup.BrowserProxy} */
- class BrowserProxyImpl {
+ /* #export */ class BrowserProxyImpl {
/** @override */
getProfileInfo() {
return cr.sendWithPromise('getProfileInfo');
@@ -34,6 +38,7 @@ cr.define('multidevice_setup', function() {
cr.addSingletonGetter(BrowserProxyImpl);
+ // #cr_define_end
return {
BrowserProxy: BrowserProxy,
BrowserProxyImpl: BrowserProxyImpl,
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html
index 22e3eb30088..6995ddafd40 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html
@@ -1,4 +1,3 @@
<link rel="import" href="../../../html/cr.html">
-<script src="multidevice_setup_delegate.js">
-</script>
+<script src="multidevice_setup_delegate.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js
index 448de24c41d..60f52a81c8e 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js
@@ -8,7 +8,7 @@ cr.define('multidevice_setup', function() {
* related logic.
* @interface
*/
- class MultiDeviceSetupDelegate {
+ /* #export */ class MultiDeviceSetupDelegate {
/** @return {boolean} */
isPasswordRequiredToSetHost() {}
@@ -29,6 +29,7 @@ cr.define('multidevice_setup', function() {
getStartSetupCancelButtonTextId() {}
}
+ // #cr_define_end
return {
MultiDeviceSetupDelegate: MultiDeviceSetupDelegate,
};
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html
index 1d1b634c8f8..e9d6365feb3 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html
@@ -1,5 +1,6 @@
<link rel="import" href="../../../html/polymer.html">
+<link rel="import" href="multidevice_setup_browser_proxy.html">
<link rel="import" href="multidevice_setup_shared_css.html">
<link rel="import" href="ui_page.html">
<link rel="import" href="ui_page_container_behavior.html">
@@ -13,6 +14,7 @@
align-items: center;
color: var(--paper-grey-600);
display: flex;
+ padding-top: 32px;
}
#profile-photo {
@@ -24,13 +26,33 @@
#passwordInput {
height: 32px;
- margin-top: 64px;
+ margin-top: 48px;
width: 100%;
}
+
+ :host-context([new-layout][orientation=horizontal]) #passwordInput {
+ width: min(calc(var(--multidevice-setup-dialog-width) -
+ 2 * var(--multidevice-setup-dialog-content-padding)), 640px);
+ }
+
+ :host-context([new-layout][orientation=vertical]) #passwordInput {
+ width: min(calc(var(--multidevice-setup-dialog-width) -
+ 2 * var(--multidevice-setup-dialog-content-padding)), 480px);
+ }
+
+ :host-context([new-layout][orientation=vertical]) #content-container {
+ align-items: center;
+ display: flex;
+ flex-direction: column;
+ }
+
+ :host-context([new-layout][orientation=horizontal]) #user-info-container {
+ padding-top: 0;
+ }
</style>
<ui-page header-text="[[i18nDynamic(locale, 'passwordPageHeader')]]"
icon-name="google-g">
- <div id="content-container" slot="additional-content">
+ <div id="content-container" slot="message">
<div id="user-info-container">
<img id="profile-photo" src="[[profilePhotoUrl_]]"></img>
<span id="email">[[email_]]</span>
@@ -46,6 +68,5 @@
</div>
</ui-page>
</template>
- <script src="password_page.js">
- </script>
+ <script src="password_page.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_1x.png b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_1x.png
deleted file mode 100644
index 03074bd5735..00000000000
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_1x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_2x.png b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_2x.png
deleted file mode 100644
index 271b0484e3e..00000000000
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_2x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html
index fefc1dc6e55..e23c207471d 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html
@@ -10,27 +10,28 @@
<template>
<style include="multidevice-setup-shared">
#page-icon-container {
+ align-items: center;
display: flex;
+ flex: 1;
+ flex-direction: column;
justify-content: center;
}
- #page-icon {
- background-image: -webkit-image-set(
- url(setup_succeeded_icon_1x.png) 1x,
- url(setup_succeeded_icon_2x.png) 2x);
- height: 156px;
- margin-top: 64px;
- width: 416px;
+ img {
+ max-height: 100%;
+ max-width: 100%;
+ object-fit: contain;
}
</style>
<ui-page header-text="[[i18nDynamic(locale, 'setupSucceededPageHeader')]]"
icon-name="google-g">
<span slot="message" inner-h-t-m-l="[[getMessageHtml_()]]"></span>
<div id="page-icon-container" slot="additional-content">
- <div id="page-icon"></div>
+ <img id="success-img" aria-hidden="true"
+ srcset="chrome://resources/cr_components/chromeos/multidevice_setup/all_set_1x.svg 1x,
+ chrome://resources/cr_components/chromeos/multidevice_setup/all_set_2x.svg 2x">
</div>
</ui-page>
</template>
- <script src="setup_succeeded_page.js">
- </script>
+ <script src="setup_succeeded_page.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html
index 6ed75f58049..4af72ffac47 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html
@@ -1,108 +1,146 @@
<link rel="import" href="../../../html/polymer.html">
<link rel="import" href="icons.html">
+<link rel="import" href="mojo_api.html">
+<link rel="import" href="multidevice_setup_delegate.html">
<link rel="import" href="multidevice_setup_shared_css.html">
<link rel="import" href="ui_page.html">
<link rel="import" href="ui_page_container_behavior.html">
<link rel="import" href="../../../html/cr.html">
<link rel="import" href="../../../html/web_ui_listener_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_lottie/cr_lottie.html">
+<link rel="import" href="chrome://resources/html/load_time_data.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
<dom-module id="start-setup-page">
<template>
<style include="multidevice-setup-shared">
- #selector-and-details-container {
- display: flex;
- margin-top: 20px;
- min-height: 246px;
+ #multidevice-summary-message a {
+ display: inline-block;
+ }
+
+ .feature-detail iron-icon {
+ --iron-icon-height: 20px;
+ --iron-icon-width: 20px;
+ min-width: 20px;
}
#singleDeviceName {
color: var(--google-grey-900);
- margin-top: 16px;
+ }
+
+ .offline-device-name {
+ color: var(--google-grey-700);
+ }
+
+ #animation-container {
+ padding-inline-end: 8px;
+ padding-top: 16px;
+ }
+
+ .footnote {
+ padding-top: 16px;
+ }
+
+ #deviceSelectionContainer {
+ display: flex;
+ flex-direction: column;
}
#deviceDropdown {
- margin-top: 16px;
+ margin-top: 8px;
}
- .offline-device-name {
- color: var(--google-grey-600);
+ #singleDeviceName {
+ margin-top: 8px;
}
- #page-icon-container {
+ .feature-detail {
+ align-items: center;
+ box-sizing: border-box;
display: flex;
- justify-content: center;
+ min-height: 48px;
+ padding: 12px 0;
+ }
+
+ #image-container {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
}
#page-icon {
- background-image: -webkit-image-set(url(start_setup_icon_1x.png) 1x,
- url(start_setup_icon_2x.png) 2x);
+ background-image: -webkit-image-set(url(chrome://resources/cr_components/chromeos/multidevice_setup/start_setup_icon_1x.png) 1x,
+ url(chrome://resources/cr_components/chromeos/multidevice_setup/start_setup_icon_2x.png) 2x);
height: 116px;
margin-top: 10px;
width: 320px;
}
- #deviceSelectionContainer {
- color: var(--paper-grey-600);
+ #page-icon-container {
display: flex;
- flex-direction: column;
+ justify-content: center;
}
- #feature-details-container {
- border-inline-start: 1px solid rgb(218, 220, 224);
+ #feature-details-container-header {
+ margin-bottom: 16px;
+ }
+
+ :host-context([new-layout][orientation=horizontal])
+ #additional-content-container {
display: flex;
flex-direction: column;
justify-content: center;
- padding-inline-start: 24px;
}
- #feature-details-container-header {
- margin-bottom: 18px;
+ :host-context([new-layout]) #feature-details-container {
+ color: var(--google-grey-900);
+ padding-top: 40px;
}
- .feature-detail {
- align-items: center;
- box-sizing: border-box;
- display: flex;
- padding: 10px 0;
+ :host-context([new-layout]) .feature-detail:not(:last-child) {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
- .feature-detail iron-icon {
- --iron-icon-height: 20px;
- --iron-icon-width: 20px;
- min-width: 20px;
+ :host-context([new-layout]) .feature-detail iron-icon {
+ padding: 0 20px;
}
- .feature-detail span {
- margin-inline-start: 8px;
+ :host-context(html:not([new-layout])) #selector-and-details-container {
+ display: flex;
+ margin-top: 20px;
+ min-height: 246px;
}
- #footnote {
- color: var(--paper-grey-600);
- padding-top: 12px;
+ :host-context(html:not([new-layout])) #feature-details-container {
+ border-inline-start: 1px solid rgb(218, 220, 224);
+ padding-inline-start: 24px;
}
- #multidevice-summary-message a {
- display: inline-block;
+ :host-context(html:not([new-layout])) .feature-detail span {
+ margin-inline-start: 8px;
}
/* On devices with small screens, use a single-column layout. */
@media screen and (max-width: 767px) {
- #selector-and-details-container {
+ :host-context(html:not([new-layout])) #selector-and-details-container {
display: flex;
flex-direction: column;
margin-top: 32px;
}
- #feature-details-container {
+ :host-context(html:not([new-layout])) #feature-details-container {
border-inline-start: none;
margin-top: 32px;
padding-inline-start: inherit;
}
+ }
- .feature-detail {
- min-height: 45px;
+ @media screen and (max-height: 736px) {
+ :host-context([screen=oobe]) #animation-container,
+ :host-context([screen=gaia-signin]) #animation-container {
+ height: 143px;
+ padding-top: 0;
}
}
</style>
@@ -112,7 +150,15 @@
<span slot="message" id="multidevice-summary-message" inner-h-t-m-l=
"[[i18nAdvancedDynamic_(locale, 'startSetupPageMessage')]]">
</span>
- <div slot="additional-content">
+ <span slot="message" hidden$="[[!newLayoutEnabled_]]">
+ <div id="animation-container">
+ <cr-lottie id="multideviceSetupAnimation"
+ animation-url="multidevice_setup.json">
+ </cr-lottie>
+ </div>
+ </span>
+ <div id="additional-content-container" slot="additional-content"
+ class="flex">
<div id="selector-and-details-container">
<div id="deviceSelectionContainer" class="flex">
[[getDeviceSelectionHeader_(devices)]]
@@ -133,35 +179,21 @@
</template>
</select>
</div>
- <div class="flex"></div>
- <div id="page-icon-container">
- <div id="page-icon"></div>
- </div>
- <div class="flex"></div>
- <div id="footnote">
- [[i18nAdvancedDynamic_(locale, 'startSetupPageFootnote')]]
+ <div id="image-container" hidden$="[[newLayoutEnabled_]]">
+ <div class="flex"></div>
+ <div id="page-icon-container">
+ <div id="page-icon"></div>
+ </div>
+ <div class="flex"></div>
+ <div class="footnote">
+ [[i18nAdvancedDynamic_(locale, 'startSetupPageFootnote')]]
+ </div>
</div>
</div>
<div id="feature-details-container" class="flex">
<div id="feature-details-container-header">
[[i18nDynamic(locale, 'startSetupPageFeatureListHeader')]]
</div>
- <div class="feature-detail">
- <iron-icon icon="multidevice-setup-icons-20:messages"></iron-icon>
- <span id="awm-summary-message" inner-h-t-m-l="
- [[i18nAdvancedDynamic_(
- locale, 'startSetupPageFeatureListAwm')]]">
- </span>
- </div>
- <template is="dom-if" if="[[phoneHubEnabled_]]">
- <div class="feature-detail">
- <iron-icon icon="multidevice-setup-icons-20:notifications">
- </iron-icon>
- <span>
- [[i18nDynamic(locale, 'startSetupPageFeatureMirrorPhoneNotifications')]]
- </span>
- </div>
- </template>
<template is="dom-if" if="[[wifiSyncEnabled_]]">
<div class="feature-detail">
<iron-icon icon="multidevice-setup-icons-20:wifi">
@@ -172,23 +204,18 @@
</div>
</template>
<div class="feature-detail">
- <iron-icon icon="multidevice-setup-icons-20:downloads">
- </iron-icon>
- <span>
- [[i18nDynamic(locale, 'startSetupPageFeatureListInstallApps')]]
- </span>
- </div>
- <div class="feature-detail">
<iron-icon icon="multidevice-setup-icons-20:features"></iron-icon>
<span>
[[i18nDynamic(locale, 'startSetupPageFeatureListAddFeatures')]]
</span>
</div>
</div>
+ <div class="footnote" hidden$="[[!newLayoutEnabled_]]">
+ [[i18nAdvancedDynamic_(locale, 'startSetupPageFootnote')]]
+ </div>
</div>
</div>
</ui-page>
</template>
- <script src="start_setup_page.js">
- </script>
+ <script src="start_setup_page.js"></script>
</dom-module>
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 234c722d45d..a5a7b033c9a 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
@@ -53,21 +53,25 @@ Polymer({
delegate: Object,
/** @private */
- phoneHubEnabled_: {
+ wifiSyncEnabled_: {
type: Boolean,
value() {
- return loadTimeData.valueExists('phoneHubEnabled') &&
- loadTimeData.getBoolean('phoneHubEnabled');
+ return loadTimeData.valueExists('wifiSyncEnabled') &&
+ loadTimeData.getBoolean('wifiSyncEnabled');
},
},
- /** @private */
- wifiSyncEnabled_: {
+ /**
+ * Whether new OOBE layout is enabled.
+ *
+ * @type {boolean}
+ */
+ newLayoutEnabled_: {
type: Boolean,
value() {
- return loadTimeData.valueExists('wifiSyncEnabled') &&
- loadTimeData.getBoolean('wifiSyncEnabled');
- },
+ return loadTimeData.valueExists('newLayoutEnabled') &&
+ loadTimeData.getBoolean('newLayoutEnabled');
+ }
},
},
@@ -83,6 +87,15 @@ Polymer({
this.initializeSetupFlow_.bind(this));
},
+ /**
+ * This will play or stop the screen's lottie animation.
+ * @param {boolean} enabled Whether the animation should play or not.
+ */
+ setPlayAnimation(enabled) {
+ /** @type {!CrLottieElement} */ (this.$.multideviceSetupAnimation)
+ .setPlay(enabled);
+ },
+
/** @private */
initializeSetupFlow_() {
// The "Learn More" links are inside a grdp string, so we cannot actually
@@ -90,7 +103,6 @@ Polymer({
// manaully add onclick handlers.
const helpArticleLinks = [
this.$$('#multidevice-summary-message a'),
- this.$$('#awm-summary-message a')
];
for (let i = 0; i < helpArticleLinks.length; i++) {
helpArticleLinks[i].onclick = this.fire.bind(
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html
index 1bdfe7b6e32..c6b77e6bcdb 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html
@@ -1,5 +1,5 @@
<link rel="import" href="../../../html/polymer.html">
-
+<link rel="import" href="chrome://resources/html/load_time_data.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
<link rel="import" href="icons.html">
<link rel="import" href="multidevice_setup_shared_css.html">
@@ -7,6 +7,39 @@
<dom-module id="ui-page">
<template>
<style include="multidevice-setup-shared">
+ :host {
+ --multidevice-setup-dialog-height: var(--oobe-oobe-dialog-height-base);
+ --multidevice-setup-dialog-width: var(--oobe-oobe-dialog-width-base);
+ --multidevice-setup-dialog-content-padding: 40px;
+ }
+
+ :host-context([orientation=horizontal]) {
+ --multidevice-setup-dialog-content-direction: row;
+ --multidevice-setup-dialog-item-alignment: unset;
+ --multidevice-setup-text-alignment: start;
+ --multidevice-setup-dialog-content-width: calc(
+ var(--multidevice-setup-dialog-width) -
+ 4 * var(--multidevice-setup-dialog-content-padding) -
+ var(--multidevice-setup-dialog-header-width));
+ /* Header takes 40% of the width remaining after applying padding */
+ --multidevice-setup-dialog-header-width: clamp(302px,
+ calc(0.4 * (var(--multidevice-setup-dialog-width) -
+ 4 * var(--multidevice-setup-dialog-content-padding))) , 346px);
+ }
+
+ :host-context([orientation=vertical]) {
+ --multidevice-setup-dialog-content-direction: column;
+ --multidevice-setup-dialog-item-alignment: center;
+ --multidevice-setup-text-alignment: center;
+ --multidevice-setup-dialog-content-width: calc(
+ var(--multidevice-setup-dialog-width) -
+ 2 * var(--multidevice-setup-dialog-content-padding));
+ /* Header takes 60% of the width remaining after applying padding */
+ --multidevice-setup-dialog-header-width: clamp(346px,
+ calc(0.6 * (var(--multidevice-setup-dialog-width) -
+ 2 * var(--multidevice-setup-dialog-content-padding))) , 520px);
+ }
+
iron-icon {
--iron-icon-width: 32px;
--iron-icon-height: 32px;
@@ -14,29 +47,96 @@
h1 {
color: var(--google-grey-900);
- font-family: 'Google Sans';
+ font-family: 'Google Sans', Roboto, sans-serif;
font-size: 28px;
font-weight: normal;
line-height: 28px;
margin: 0;
- padding-top: 36px;
+ padding-top: 40px;
}
#message-container {
- box-sizing: border-box;
min-height: 32px;
padding-top: 16px;
}
+
+ :host-context([new-layout]) #message-container {
+ color: var(--google-grey-700);
+ line-height: 18px;
+ overflow-wrap: break-word;
+ text-align: var(--multidevice-setup-text-alignment);
+ }
+
+ :host-context([new-layout]) #main-container {
+ align-items: var(--multidevice-setup-dialog-item-alignment);
+ display: flex;
+ flex-direction: var(--multidevice-setup-dialog-content-direction);
+ height: 100%;
+ }
+
+ :host-context([new-layout]) #header-container {
+ align-items: var(--multidevice-setup-dialog-item-alignment);
+ display: flex;
+ flex-direction: column;
+ padding-bottom: 0;
+ padding-inline-end: var(--multidevice-setup-dialog-content-padding);
+ padding-inline-start: var(--multidevice-setup-dialog-content-padding);
+ padding-top: var(--multidevice-setup-dialog-content-padding);
+ width: var(--multidevice-setup-dialog-header-width);
+ }
+
+ :host-context([new-layout][screen=oobe]) #header-container,
+ :host-context([new-layout][screen=gaia-signin]) #header-container {
+ padding-top: calc(var(--multidevice-setup-dialog-content-padding)
+ + 2 * min(40px, max(24px, calc(var(--multidevice-setup-dialog-height)
+ * 0.025))) + 32px);
+ }
+
+ :host-context([new-layout]) #additional-content-container {
+ border: transparent;
+ display: flex;
+ flex: 1;
+ padding-bottom: 0;
+ padding-inline-end: var(--multidevice-setup-dialog-content-padding);
+ padding-inline-start: var(--multidevice-setup-dialog-content-padding);
+ padding-top: 0;
+ width: var(--multidevice-setup-dialog-content-width);
+ }
+
+ :host-context([new-layout][orientation=vertical])
+ #additional-content-container {
+ margin-top: 40px;
+ }
+
+ :host-context([new-layout][orientation=horizontal][screen=oobe])
+ #additional-content-container,
+ :host-context([new-layout][orientation=horizontal][screen=gaia-signin])
+ #additional-content-container {
+ margin-top: 80px;
+ }
+
+ :host-context([new-layout][screen=oobe]) #additional-content-container,
+ :host-context([new-layout][screen=gaia-signin])
+ #additional-content-container {
+ overflow-y: auto;
+ }
+
+ :host-context([new-layout]) h1 {
+ text-align: var(--multidevice-setup-text-alignment);
+ }
</style>
- <iron-icon icon="[[computeIconIdentifier_(iconName)]]"></iron-icon>
- <h1>[[headerText]]</h1>
- <div id="message-container">
- <slot name="message"></slot>
- </div>
- <div id="additional-content-container">
- <slot name="additional-content"></slot>
+ <div id="main-container">
+ <div id="header-container">
+ <iron-icon icon="[[computeIconIdentifier_(iconName)]]"></iron-icon>
+ <h1>[[headerText]]</h1>
+ <div id="message-container">
+ <slot name="message"></slot>
+ </div>
+ </div>
+ <div id="additional-content-container">
+ <slot name="additional-content"></slot>
+ </div>
</div>
</template>
- <script src="ui_page.js">
- </script>
+ <script src="ui_page.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html
index 3485a99540e..020f05077ed 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html
@@ -1,5 +1,4 @@
<link rel="import" href="../../../html/cr.html">
<link rel="import" href="../../../html/i18n_behavior.html">
-<script src="ui_page_container_behavior.js">
-</script>
+<script src="ui_page_container_behavior.js"></script>
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 785a3e7a893..06603d543bb 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
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// clang-format off
+// #import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+// clang-format on
+
/** @polymerBehavior */
const UiPageContainerBehaviorImpl = {
properties: {
@@ -45,7 +49,7 @@ const UiPageContainerBehaviorImpl = {
};
/** @polymerBehavior */
-const UiPageContainerBehavior = [
+/* #export */ const UiPageContainerBehavior = [
I18nBehavior,
UiPageContainerBehaviorImpl,
];
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
index 1a9096bdc1b..636bafc181c 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
@@ -8,7 +8,9 @@ import("../os_cr_components.gni")
assert(is_chromeos, "Only ChromeOS components belong here.")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [
+ ":cellular_utils",
":cr_policy_network_behavior_mojo",
":cr_policy_network_indicator_mojo",
":mojo_interface_provider",
@@ -212,6 +214,7 @@ js_library("network_list") {
js_library("network_list_item") {
deps = [
":cr_policy_network_behavior_mojo",
+ ":mojo_interface_provider",
":network_list_types",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:i18n_behavior",
@@ -249,9 +252,17 @@ js_library("onc_mojo") {
]
}
+js_library("cellular_utils") {
+ deps = [
+ ":mojo_interface_provider",
+ ":onc_mojo",
+ ]
+}
+
js_type_check("closure_compile_module") {
is_polymer3 = true
deps = [
+ ":cellular_utils.m",
":cr_policy_network_behavior_mojo.m",
":cr_policy_network_indicator_mojo.m",
":mojo_interface_provider.m",
@@ -440,6 +451,7 @@ js_library("network_list.m") {
deps = [
":network_list_item.m",
":network_list_types.m",
+ ":onc_mojo.m",
"//third_party/polymer/v3_0/components-chromium/iron-list:iron-list",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/cr_elements:cr_scrollable_behavior.m",
@@ -451,7 +463,11 @@ js_library("network_list.m") {
js_library("network_list_item.m") {
sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network/network_list_item.m.js" ]
deps = [
+ ":cr_policy_network_behavior_mojo.m",
+ ":mojo_interface_provider.m",
":network_list_types.m",
+ ":onc_mojo.m",
+ "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/js/cr/ui:focus_row_behavior.m",
]
@@ -460,6 +476,7 @@ js_library("network_list_item.m") {
js_library("network_list_types.m") {
sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network/network_list_types.m.js" ]
+ deps = [ ":onc_mojo.m" ]
extra_deps = [ ":modulize" ]
}
@@ -610,6 +627,15 @@ js_library("onc_mojo.m") {
extra_deps = [ ":modulize" ]
}
+js_library("cellular_utils.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network/cellular_utils.m.js" ]
+ deps = [
+ ":mojo_interface_provider.m",
+ ":onc_mojo.m",
+ ]
+ extra_deps = [ ":modulize" ]
+}
+
import("//tools/polymer/polymer.gni")
group("polymer3_elements") {
@@ -729,6 +755,7 @@ polymer_modulizer("network_list_item") {
html_file = "network_list_item.html"
html_type = "dom-module"
auto_imports = cr_components_chromeos_auto_imports
+ namespace_rewrites = cr_components_chromeos_namespace_rewrites
}
polymer_modulizer("network_nameservers") {
@@ -805,6 +832,7 @@ js_modulizer("modulize") {
"cr_policy_network_behavior_mojo.js",
"mojo_interface_provider.js",
"network_config_element_behavior.js",
+ "cellular_utils.js",
"network_listener_behavior.js",
"network_list_types.js",
"onc_mojo.js",
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.html b/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.html
new file mode 100644
index 00000000000..20e09fecf39
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.html
@@ -0,0 +1,2 @@
+<link rel="import" href="mojo_interface_provider.html">
+<script src="cellular_utils.js"></script> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.js b/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.js
new file mode 100644
index 00000000000..74363e9ef09
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.js
@@ -0,0 +1,76 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// clang-format off
+// #import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
+// #import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
+// clang-format on
+
+/**
+ * Checks if the device has a currently active pSIM network.
+ * @return {!Promise<boolean>}
+ */
+/* #export */ function hasActivePSimNetwork() {
+ const mojom = chromeos.networkConfig.mojom;
+ const networkConfig = network_config.MojoInterfaceProviderImpl.getInstance()
+ .getMojoServiceRemote();
+ return networkConfig
+ .getNetworkStateList({
+ filter: mojom.FilterType.kActive,
+ networkType: mojom.NetworkType.kCellular,
+ limit: mojom.NO_LIMIT,
+ })
+ .then((response) => {
+ // Filter out non-connected networks and check the remaining if they are
+ // pSIM.
+ return Promise.all(response.result
+ .filter(network => {
+ return network.connectionState !==
+ mojom.ConnectionStateType.kNotConnected;
+ })
+ .map(networkIsPSim_));
+ })
+ .then((networkIsPSimResults) => {
+ return networkIsPSimResults.some((isPSimNetwork) => isPSimNetwork);
+ });
+}
+
+/**
+ * Returns whether a network is a pSIM network or not.
+ * @private
+ * @param {!chromeos.networkConfig.mojom.NetworkStateProperties} network
+ * @return {!Promise<boolean>}
+ */
+function networkIsPSim_(network) {
+ const networkConfig = network_config.MojoInterfaceProviderImpl.getInstance()
+ .getMojoServiceRemote();
+ return networkConfig.getManagedProperties(network.guid).then((response) => {
+ return !response.result.typeProperties.cellular.eid;
+ });
+}
+
+/**
+ * Returns number of phyical SIM and eSIM slots on the current device
+ * @param {!chromeos.networkConfig.mojom.DeviceStateProperties}
+ * deviceState
+ * @return {!{pSimSlots: number, eSimSlots: number}}
+ */
+/* #export */ function getSimSlotCount(deviceState) {
+ let pSimSlots = 0;
+ let eSimSlots = 0;
+
+ if (!deviceState || !deviceState.simInfos) {
+ return {pSimSlots, eSimSlots};
+ }
+
+ for (const simInfo of deviceState.simInfos) {
+ if (simInfo.eid) {
+ eSimSlots++;
+ continue;
+ }
+ pSimSlots++;
+ }
+
+ return {pSimSlots, eSimSlots};
+}
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 4f4aa91b86a..b4a2a16eecd 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
@@ -183,15 +183,11 @@ Polymer({
* @private
*/
setApnSelectList_(activeApn) {
- assert(!activeApn || activeApn.accessPointName);
- // The generated APN list ensures nonempty accessPointName and name
- // properties.
const apnList = this.generateApnList_();
- if (apnList === undefined) {
- // No APNList property indicates that the network is not in a
- // connectable state. Disable the UI.
- this.apnSelectList_ = [];
- this.set('selectedApn_', '');
+ if (apnList === undefined || apnList.length === 0) {
+ // Show other APN when no APN list property is available.
+ this.apnSelectList_ = [this.otherApn_];
+ this.set('selectedApn_', kOtherAccessPointName);
return;
}
// Get the list entry for activeApn if it exists. It will have 'name' set.
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html
index 45faa6f1825..d2d74437302 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html
@@ -9,6 +9,7 @@
<link rel="import" href="../../../cr_elements/policy/cr_policy_indicator.html">
<link rel="import" href="../../../html/action_link.html">
<link rel="import" href="../../../html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/html/assert.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-icon/iron-icon.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
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 9a9fe325cf0..c7bd8953fcb 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
@@ -1179,10 +1179,11 @@ Polymer({
this.selectedServerCaHash_ = DEFAULT_HASH;
} else if (!this.guid && this.serverCaCerts_[0]) {
// For unconfigured networks, default to the first available
- // certificate, or DO_NOT_CHECK (i.e. skip DEFAULT_HASH). See
- /// onNetworkCertificatesChanged() for how certificates are added.
+ // certificate and fallback to DEFAULT_HASH. See
+ // onNetworkCertificatesChanged() for how certificates are added.
let cert = this.serverCaCerts_[0];
- if (cert.hash === DEFAULT_HASH && this.serverCaCerts_[1]) {
+ if (cert.hash === DEFAULT_HASH &&
+ this.isRealCertUsableForNetworkAuth_(this.serverCaCerts_[1])) {
cert = this.serverCaCerts_[1];
}
this.selectedServerCaHash_ = cert.hash;
@@ -1207,7 +1208,17 @@ Polymer({
}
}
},
-
+ /**
+ * Checks that the hash of the certificate is set and not one of the default
+ * special strings.
+ * @param {chromeos.networkConfig.mojom.NetworkCertificate|undefined} cert
+ * @return {boolean}
+ * @private
+ */
+ isRealCertUsableForNetworkAuth_(cert) {
+ return !!cert && cert.hash !== DO_NOT_CHECK_HASH &&
+ cert.hash !== DEFAULT_HASH;
+ },
/**
* @return {boolean}
* @private
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_icon.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_icon.html
index 84065f5c3bf..e25a5c4001d 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_icon.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_icon.html
@@ -44,41 +44,41 @@
/* Images */
#icon.ethernet {
- background: url(ethernet.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/ethernet.svg);
}
#icon.vpn {
- background: url(vpn.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/vpn.svg);
}
/* Wi-Fi images */
#icon.wifi-not-connected {
- background: url(wifi_0_with_x.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_0_with_x.svg);
}
#icon.wifi-no-network,
#icon.wifi-0 {
- background: url(wifi_0.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_0.svg);
}
#icon.wifi-1 {
- background: url(wifi_1.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_1.svg);
}
#icon.wifi-2 {
- background: url(wifi_2.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_2.svg);
}
#icon.wifi-3 {
- background: url(wifi_3.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_3.svg);
}
#icon.wifi-4 {
- background: url(wifi_4.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_4.svg);
}
#icon.wifi-off {
- background: url(wifi_off.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_off.svg);
}
#icon.wifi-connecting {
@@ -88,41 +88,51 @@
}
@keyframes wifi-levels {
- 0% { background: url(wifi_0.svg); }
- 25% { background: url(wifi_1.svg); }
- 50% { background: url(wifi_2.svg); }
- 75% { background: url(wifi_3.svg); }
- 100% { background: url(wifi_4.svg); }
+ 0% {
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_0.svg);
+ }
+ 25% {
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_1.svg);
+ }
+ 50% {
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_2.svg);
+ }
+ 75% {
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_3.svg);
+ }
+ 100% {
+ background: url(chrome://resources/cr_components/chromeos/network/wifi_4.svg);
+ }
}
/* Cellular images */
#icon.cellular-not-connected {
- background: url(cellular_0_with_x.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_0_with_x.svg);
}
#icon.cellular-no-network,
#icon.cellular-0 {
- background: url(cellular_0.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_0.svg);
}
#icon.cellular-1 {
- background: url(cellular_1.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_1.svg);
}
#icon.cellular-2 {
- background: url(cellular_2.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_2.svg);
}
#icon.cellular-3 {
- background: url(cellular_3.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_3.svg);
}
#icon.cellular-4 {
- background: url(cellular_4.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_4.svg);
}
#icon.cellular-off {
- background: url(cellular_off.svg);
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_off.svg);
}
#icon.cellular-connecting {
@@ -132,11 +142,21 @@
}
@keyframes cellular-levels {
- 0% { background: url(cellular_0.svg); }
- 25% { background: url(cellular_1.svg); }
- 50% { background: url(cellular_2.svg); }
- 75% { background: url(cellular_3.svg); }
- 100% { background: url(cellular_4.svg); }
+ 0% {
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_0.svg);
+ }
+ 25% {
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_1.svg);
+ }
+ 50% {
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_2.svg);
+ }
+ 75% {
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_3.svg);
+ }
+ 100% {
+ background: url(chrome://resources/cr_components/chromeos/network/cellular_4.svg);
+ }
}
</style>
<div id="icon"
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_icons.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_icons.html
index fd5018a72ae..e1e85634a72 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_icons.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_icons.html
@@ -18,6 +18,14 @@
<g id="badge-hspa-plus"><path d="M5.22527 7H6.26374V1H5.22527V3.49725H2.54258V1H1.5V7H2.54258V4.33379H5.22527V7ZM11.2788 3.69918H9.71291V2.03022H8.74038V3.69918H7.16621V4.61401H8.74038V6.39835H9.71291V4.61401H11.2788V3.69918Z"></path></g>
<g id="badge-lte"><path d="M2 1H3V5H5V6H2V1ZM10 1H13V2H11V3H12.5V4H11V5H13V6H10V1ZM5 1H9V2H7.5V6H6.5V2H5V1Z"></path></g>
<g id="badge-lte-advanced"><path d="M2 1H3V5H5V6H2V1ZM10 1H13V2H11V3H12.5V4H11V5H13V6H10V1ZM5 1H9V2H7.5V6H6.5V2H5V1ZM14 2H15V1H16V2H17V3H16V4H15V3H14V2Z"></path></g>
+
+ <!-- Icons -->
+ <!-- TODO(crbug.com/1157123) Update network_icon to use iron_icon
+ and migrate the rest of the icons used by network_icon
+ into this iconset. -->
+ <g id="cellular-0"><path fill-rule="evenodd" clip-rule="evenodd" d="M15.002 15.002V7.41622L7.41622 15.002H15.002ZM16.002 17.002C16.5543 17.002 17.002 16.5543 17.002 16.002V5.002C17.002 4.1111 15.9249 3.66493 15.2949 4.2949L4.2949 15.2949C3.66493 15.9249 4.1111 17.002 5.002 17.002H16.002Z" ></g>
+
+ <g id="download" viewBox="0 0 20 20"><path d="M11 9.2L13.5 6.5L15 8L10 13L5 8L6.5 6.5L9 9.2V3H11V9.2Z"></path><path d="M6 15V13H4V15.375C4 16.2688 4.73125 17 5.625 17H14.375C15.2688 17 16 16.2688 16 15.375V13H14V15H6Z"></path></g>
</defs>
</svg>
</iron-iconset-svg>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list.html
index 67c933d9669..17c8ff3c919 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list.html
@@ -2,6 +2,7 @@
<link rel="import" href="network_list_item.html">
<link rel="import" href="network_list_types.html">
+<link rel="import" href="onc_mojo.html">
<link rel="import" href="../../../cr_elements/cr_scrollable_behavior.html">
<link rel="import" href="../../../cr_elements/shared_style_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
@@ -14,7 +15,6 @@
network-list-item {
align-items: center;
- height: 48px;
}
#container {
@@ -22,6 +22,10 @@
overflow-y: auto;
}
+ #networkList {
+ height: 100%;
+ }
+
/* Override scrollable border-bottom-color */
#container[no-bottom-scroll-border] {
border-bottom-color: transparent;
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.html
index a2347543db2..5c57a802174 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.html
@@ -1,6 +1,9 @@
<link rel="import" href="../../../html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
+<link rel="import" href="chrome://resources/html/load_time_data.html">
+<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="../../../cr_elements/cr_icon_button/cr_icon_button.html">
<link rel="import" href="../../../cr_elements/icons.html">
<link rel="import" href="../../../cr_elements/policy/cr_policy_indicator.html">
@@ -11,6 +14,7 @@
<link rel="import" href="cr_policy_network_behavior_mojo.html">
<link rel="import" href="network_icon.html">
<link rel="import" href="network_list_types.html">
+<link rel="import" href="mojo_interface_provider.html">
<link rel="import" href="onc_mojo.html">
<dom-module id="network-list-item">
@@ -22,8 +26,26 @@
}
#divOuter {
- height: 100%;
+ height: var(--cr-network-row-height, 48px);
+ overflow: auto;
+ padding-bottom: var(--cr-network-row-padding-bottom, 0);
padding-inline-end: var(--cr-icon-ripple-padding);
+ padding-top: var(--cr-network-row-padding-bottom, 0);
+ }
+
+ :host([is-e-sim-pending-profile_]) #divText {
+ opacity: 0.4;
+ }
+
+ :host(:not([is-e-sim-pending-profile_])) #divIcon {
+ height: 24px;
+ width: 24px;
+ }
+
+ :host([is-e-sim-pending-profile_]) #divIcon {
+ height: 20px;
+ opacity: 0.4;
+ width: 20px;
}
#divDetail {
@@ -48,11 +70,6 @@
color: var(--google-green-500);
}
- iron-icon {
- height: 24px;
- width: 24px;
- }
-
cr-policy-indicator {
padding: 0 var(--cr-controlled-by-spacing);
}
@@ -60,6 +77,17 @@
#wrapper {
height: 100%;
}
+
+ cr-button iron-icon {
+ --iron-icon-fill-color: #1A73E8;
+ margin-inline-end: 8px;
+ }
+
+ paper-spinner-lite {
+ height: 20px;
+ margin-inline-end: 16px;
+ width: 20px;
+ }
</style>
<div id="wrapper" focus-row-container
class="layout horizontal center flex">
@@ -81,10 +109,17 @@
</network-icon>
</template>
<template is="dom-if" if="[[item.polymerIcon]]">
- <iron-icon icon="[[item.polymerIcon]]"></iron-icon>
+ <iron-icon id="divIcon" icon="[[item.polymerIcon]]"></iron-icon>
</template>
<div id="divText" class="layout horizontal flex">
- <div aria-hidden="true">[[getItemName_(item)]]</div>
+ <div id="networkName" aria-hidden="true">
+ [[getItemName_(item)]]
+ </div>
+ <div id="subtitle"
+ hidden$="[[!isSubtitleVisible_(subtitle_)]]"
+ aria-hidden="true">
+ [[getSubtitle(subtitle_)]]
+ </div>
<div id="networkStateText"
class="cr-secondary-text"
hidden$="[[!isStateTextVisible_(networkState)]]"
@@ -110,6 +145,18 @@
</cr-icon-button>
</div>
</template>
+ <template is="dom-if" if="[[isESimPendingProfile_]]" restamp>
+ <cr-button id="installButton"
+ aria-label$="[[getItemName_(item)]], [[i18n('networkListItemDownload')]]"
+ on-click="onInstallButtonClick_">
+ <iron-icon icon="network:download"></iron-icon>
+ [[i18n('networkListItemDownload')]]
+ </cr-button>
+ </template>
+ <template is="dom-if" if="[[isESimInstallingProfile_(item, item.customItemType)]]" restamp>
+ <paper-spinner-lite active></paper-spinner-lite>
+ [[i18n('networkListItemAddingProfile')]]
+ </template>
</div>
</div>
</template>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.js
index 91d70ebcdc2..faeb93d4f75 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.js
@@ -56,7 +56,7 @@ Polymer({
rowLabel: {
type: String,
notify: true,
- computed: 'getRowLabel_(item, networkState)',
+ computed: 'getRowLabel_(item, networkState, subtitle_)',
},
buttonLabel: {
@@ -72,6 +72,17 @@ Polymer({
},
/**
+ * Whether the network item is a cellular one and is of an esim
+ * pending profile.
+ */
+ isESimPendingProfile_: {
+ type: Boolean,
+ reflectToAttribute: true,
+ value: false,
+ computed: 'computeIsESimPendingProfile_(item, item.customItemType)',
+ },
+
+ /**
* The cached ConnectionState for the network.
* @type {!chromeos.networkConfig.mojom.ConnectionStateType|undefined}
*/
@@ -95,6 +106,32 @@ Polymer({
* @private {!OncMojo.DeviceStateProperties|undefined} deviceState
*/
deviceState: Object,
+
+ /**
+ * Subtitle for item.
+ * @private {string}
+ */
+ subtitle_: {
+ type: String,
+ value: '',
+ },
+
+ /** @private */
+ isUpdatedCellularUiEnabled_: {
+ type: Boolean,
+ value() {
+ return loadTimeData.getBoolean('updatedCellularActivationUi');
+ }
+ },
+ },
+
+ /** @private {?chromeos.networkConfig.mojom.CrosNetworkConfigRemote} */
+ networkConfig_: null,
+
+ /** @override */
+ created() {
+ this.networkConfig_ = network_config.MojoInterfaceProviderImpl.getInstance()
+ .getMojoServiceRemote();
},
/** @override */
@@ -109,12 +146,49 @@ Polymer({
/** @private */
itemChanged_() {
- if (this.item && !this.item.hasOwnProperty('customItemName')) {
+ if (this.item && !this.item.hasOwnProperty('customItemType')) {
this.networkState =
/** @type {!OncMojo.NetworkStateProperties} */ (this.item);
- } else if (this.networkState) {
+ } else {
this.networkState = undefined;
}
+ this.setSubtitle_();
+ },
+
+ /** @private */
+ setSubtitle_() {
+ const mojom = chromeos.networkConfig.mojom;
+
+ if (this.item.hasOwnProperty('customItemSubtitle') &&
+ this.item.customItemSubtitle) {
+ // Item is a custom OOBE network or pending eSIM profile.
+ const item = /** @type {!NetworkList.CustomItemState} */ (this.item);
+ this.subtitle_ = item.customItemSubtitle;
+ return;
+ }
+
+ if (!this.networkState) {
+ return;
+ }
+
+ if (this.networkState.type !== mojom.NetworkType.kCellular ||
+ !this.isUpdatedCellularUiEnabled_) {
+ return;
+ }
+
+ this.networkConfig_.getManagedProperties(this.networkState.guid)
+ .then(response => {
+ if (!response || !response.result ||
+ !response.result.typeProperties.cellular.eid) {
+ return;
+ }
+ const managedProperty = response.result;
+
+ if (managedProperty.typeProperties.cellular.homeProvider) {
+ this.subtitle_ =
+ managedProperty.typeProperties.cellular.homeProvider.name;
+ }
+ });
},
/** @private */
@@ -138,10 +212,9 @@ Polymer({
getItemName_() {
if (this.item.hasOwnProperty('customItemName')) {
const item = /** @type {!NetworkList.CustomItemState} */ (this.item);
- const name = item.customItemName || '';
- const customName = this.i18n(item.customItemName);
-
- return customName ? customName : name;
+ return this.i18nExists(item.customItemName) ?
+ this.i18n(item.customItemName) :
+ item.customItemName;
}
return OncMojo.getNetworkStateDisplayName(
/** @type {!OncMojo.NetworkStateProperties} */ (this.item));
@@ -162,6 +235,10 @@ Polymer({
* @private
*/
getRowLabel_() {
+ if (!this.item) {
+ return '';
+ }
+
const NetworkType = chromeos.networkConfig.mojom.NetworkType;
const OncSource = chromeos.networkConfig.mojom.OncSource;
const SecurityType = chromeos.networkConfig.mojom.SecurityType;
@@ -187,21 +264,46 @@ Polymer({
case NetworkType.kCellular:
if (isManaged) {
if (status) {
+ if (this.subtitle_) {
+ return this.i18n(
+ 'networkListItemLabelCellularManagedWithConnectionStatusAndProviderName',
+ index, total, this.getItemName_(), this.subtitle_, status,
+ this.item.typeState.cellular.signalStrength);
+ }
return this.i18n(
'networkListItemLabelCellularManagedWithConnectionStatus',
index, total, this.getItemName_(), status,
this.item.typeState.cellular.signalStrength);
}
+ if (this.subtitle_) {
+ return this.i18n(
+ 'networkListItemLabelCellularManagedWithProviderName', index,
+ total, this.getItemName_(), this.subtitle_,
+ this.item.typeState.cellular.signalStrength);
+ }
return this.i18n(
'networkListItemLabelCellularManaged', index, total,
this.getItemName_(), this.item.typeState.cellular.signalStrength);
}
if (status) {
+ if (this.subtitle_) {
+ return this.i18n(
+ 'networkListItemLabelCellularWithConnectionStatusAndProviderName',
+ index, total, this.getItemName_(), this.subtitle_, status,
+ this.item.typeState.cellular.signalStrength);
+ }
return this.i18n(
'networkListItemLabelCellularWithConnectionStatus', index, total,
this.getItemName_(), status,
this.item.typeState.cellular.signalStrength);
}
+
+ if (this.subtitle_) {
+ return this.i18n(
+ 'networkListItemLabelCellularWithProviderName', index, total,
+ this.getItemName_(), this.subtitle_,
+ this.item.typeState.cellular.signalStrength);
+ }
return this.i18n(
'networkListItemLabelCellular', index, total, this.getItemName_(),
this.item.typeState.cellular.signalStrength);
@@ -226,12 +328,26 @@ Polymer({
case NetworkType.kTether:
// Tether networks will never be controlled by policy (only disabled).
if (status) {
+ if (this.subtitle_) {
+ return this.i18n(
+ 'networkListItemLabelTetherWithConnectionStatusAndProviderName',
+ index, total, this.getItemName_(), this.subtitle_, status,
+ this.item.typeState.tether.signalStrength,
+ this.item.typeState.tether.batteryPercentage);
+ }
return this.i18n(
'networkListItemLabelTetherWithConnectionStatus', index, total,
this.getItemName_(), status,
this.item.typeState.tether.signalStrength,
this.item.typeState.tether.batteryPercentage);
}
+ if (this.subtitle_) {
+ return this.i18n(
+ 'networkListItemLabelTetherWithProviderName', index, total,
+ this.getItemName_(), this.subtitle_,
+ this.item.typeState.tether.signalStrength,
+ this.item.typeState.tether.batteryPercentage);
+ }
return this.i18n(
'networkListItemLabelTether', index, total, this.getItemName_(),
this.item.typeState.tether.signalStrength,
@@ -263,6 +379,25 @@ Polymer({
'networkListItemLabelWifi', index, total, this.getItemName_(),
secured, this.item.typeState.wifi.signalStrength);
default:
+ if (this.isESimPendingProfile_) {
+ if (this.subtitle_) {
+ return this.i18n(
+ 'networkListItemLabelESimPendingProfileWithProviderName', index,
+ total, this.getItemName_(), this.subtitle_);
+ }
+ return this.i18n(
+ 'networkListItemLabelESimPendingProfile', index, total,
+ this.getItemName_());
+ } else if (this.isESimInstallingProfile_()) {
+ if (this.subtitle_) {
+ return this.i18n(
+ 'networkListItemLabelESimPendingProfileWithProviderNameInstalling',
+ index, total, this.getItemName_(), this.subtitle_);
+ }
+ return this.i18n(
+ 'networkListItemLabelESimPendingProfileInstalling', index, total,
+ this.getItemName_());
+ }
return this.i18n(
'networkListItemLabel', index, total, this.getItemName_());
}
@@ -312,6 +447,22 @@ Polymer({
},
/**
+ * @return {string}
+ * @private
+ */
+ getSubtitle() {
+ return this.subtitle_ ? this.subtitle_ : '';
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ isSubtitleVisible_() {
+ return !!this.subtitle_;
+ },
+
+ /**
* @param {!OncMojo.NetworkStateProperties|undefined} networkState
* @param {boolean} showButtons
* @return {boolean}
@@ -364,6 +515,8 @@ Polymer({
if (this.isSubpageButtonVisible_(this.networkState, this.showButtons) &&
this.$$('#subpage-button') === this.shadowRoot.activeElement) {
this.fireShowDetails_(event);
+ } else if (this.isESimPendingProfile_) {
+ this.onInstallButtonClick_();
} else if (this.item.hasOwnProperty('customItemName')) {
this.fire('custom-item-selected', this.item);
} else {
@@ -420,4 +573,29 @@ Polymer({
// isFocused is supplied by FocusRowBehavior.
return this.isFocused ? 'polite' : 'off';
},
+
+ /** @private */
+ onInstallButtonClick_() {
+ this.fire('install-profile', {iccid: this.item.customData.iccid});
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ computeIsESimPendingProfile_() {
+ return !!this.item && this.item.hasOwnProperty('customItemType') &&
+ this.item.customItemType ===
+ NetworkList.CustomItemType.ESIM_PENDING_PROFILE;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ isESimInstallingProfile_() {
+ return !!this.item && this.item.hasOwnProperty('customItemType') &&
+ this.item.customItemType ===
+ NetworkList.CustomItemType.ESIM_INSTALLING_PROFILE;
+ },
});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_types.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_types.js
index e8efab5ccfd..82e395130f0 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_types.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_types.js
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// clang-format off
+// #import {OncMojo} from './onc_mojo.m.js';
+// clang-format on
+
/**
* @fileoverview
* This file contains typedefs properties for NetworkList, shared by
@@ -10,10 +14,19 @@
/* #export */ const NetworkList = {};
+/** @enum {number} */
+NetworkList.CustomItemType = {
+ OOBE: 1,
+ ESIM_PENDING_PROFILE: 2,
+ ESIM_INSTALLING_PROFILE: 3,
+};
+
/**
* Custom data for implementation specific network list items.
* @typedef {{
+ * customItemType: NetworkList.CustomItemType,
* customItemName: string,
+ * customItemSubtitle: string,
* polymerIcon: (string|undefined),
* customData: (!Object|undefined),
* showBeforeNetworksList: boolean,
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.html
index d2abd388d3d..4b066ea8bed 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.html
@@ -1,6 +1,7 @@
<link rel="import" href="../../../html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-progress/paper-progress.html">
<link rel="import" href="mojo_interface_provider.html">
<link rel="import" href="network_list.html">
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.js
index 5c385f28b65..1e6757de278 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.js
@@ -39,13 +39,30 @@ Polymer({
},
/** Whether to show technology badges on mobile network icons. */
- showTechnologyBadge: {type: Boolean, value: true},
+ showTechnologyBadge: {
+ type: Boolean,
+ value: true,
+ },
+
+ /**
+ * Whether this element should trigger periodic Wi-Fi scans to update the
+ * list of networks. If true, a background scan is performed every 10
+ * seconds.
+ */
+ enableWifiScans: {
+ type: Boolean,
+ value: true,
+ observer: 'onEnableWifiScansChanged_',
+ },
/**
* Whether to show a progress indicator at the top of the network list while
* a scan (e.g., for nearby Wi-Fi networks) is in progress.
*/
- showScanProgress: {type: Boolean, value: false},
+ showScanProgress: {
+ type: Boolean,
+ value: false,
+ },
/** Whether cellular activation is unavailable in the current context. */
activationUnavailable: Boolean,
@@ -65,7 +82,10 @@ Polymer({
* Whether a network scan is currently in progress.
* @private
*/
- isScanOngoing_: {type: Boolean, value: false},
+ isScanOngoing_: {
+ type: Boolean,
+ value: false,
+ },
/**
* The cellular DeviceState, or undefined if there is no Cellular device.
@@ -93,23 +113,12 @@ Polymer({
/** @override */
attached() {
this.refreshNetworks();
-
- const INTERVAL_MS = 10 * 1000;
- // Request only WiFi network scans. Tether and Cellular scans are not useful
- // here. Cellular scans are disruptive and should only be triggered by
- // explicit user action.
- const kWiFi = chromeos.networkConfig.mojom.NetworkType.kWiFi;
- this.networkConfig_.requestNetworkScan(kWiFi);
- this.scanIntervalId_ = window.setInterval(function() {
- this.networkConfig_.requestNetworkScan(kWiFi);
- }.bind(this), INTERVAL_MS);
+ this.onEnableWifiScansChanged_();
},
/** @override */
detached() {
- if (this.scanIntervalId_ !== null) {
- window.clearInterval(this.scanIntervalId_);
- }
+ this.clearScheduledScans_();
},
/**
@@ -194,6 +203,42 @@ Polymer({
},
/**
+ * Handler for changes to |enableWifiScans| which either schedules upcoming
+ * scans or clears already-scheduled scans.
+ * @private
+ */
+ onEnableWifiScansChanged_() {
+ // Clear any scans which are already scheduled.
+ this.clearScheduledScans_();
+
+ // If Scans are disabled, return early.
+ if (!this.enableWifiScans) {
+ return;
+ }
+
+ const INTERVAL_MS = 10 * 1000;
+ // Request only WiFi network scans. Tether and Cellular scans are not useful
+ // here. Cellular scans are disruptive and should only be triggered by
+ // explicit user action.
+ const kWiFi = chromeos.networkConfig.mojom.NetworkType.kWiFi;
+ this.networkConfig_.requestNetworkScan(kWiFi);
+ this.scanIntervalId_ = window.setInterval(function() {
+ this.networkConfig_.requestNetworkScan(kWiFi);
+ }.bind(this), INTERVAL_MS);
+ },
+
+ /**
+ * Clears any scheduled Wi-FI scans; no-op if there were no scans scheduled.
+ * @private
+ */
+ clearScheduledScans_() {
+ if (this.scanIntervalId_ !== null) {
+ window.clearInterval(this.scanIntervalId_);
+ this.scanIntervalId_ = null;
+ }
+ },
+
+ /**
* @param {!Array<!OncMojo.DeviceStateProperties>} deviceStates
* @private
*/
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
index 528d7296677..bdc1a973e86 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
@@ -29,7 +29,7 @@
color: red;
font-size: 125%;
font-weight: 500;
- margin-top: 10px;
+ margin-bottom: 10px;
}
.error {
@@ -60,7 +60,7 @@
</div>
<!-- SIM locked -->
- <div class="property-box two-line"
+ <div id="simLocked" class="property-box two-line"
hidden$="[[!showSimLocked_(deviceState)]]">
<div class="start layout horizontal center">
<iron-icon icon="cr:sim-lock"></iron-icon>
@@ -181,6 +181,9 @@
label="[[i18n('networkSimEnterPuk')]]"
disabled="[[inProgress_]]">
</network-password-input>
+ <div class="dialog-error">
+ [[getErrorMsg_(error_, deviceState)]]
+ </div>
<network-password-input id="unlockPin1" value="{{pin_new1_}}"
label="[[i18n('networkSimEnterNewPin')]]"
disabled="[[inProgress_]]">
@@ -192,9 +195,6 @@
<div class="dialog-error">
[[i18n('networkSimLockedWarning')]]
</div>
- <div class="dialog-error">
- [[getErrorMsg_(error_, deviceState)]]
- </div>
</div>
<div slot="button-container">
<cr-button class="cancel-button" on-click="closeDialogs_">
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 db23a954686..e47a727d5f0 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
@@ -112,9 +112,6 @@ Polymer({
/** @private {boolean|undefined} */
setLockEnabled_: undefined,
- /** @private {boolean} */
- simUnlockSent_: false,
-
/** @private {?chromeos.networkConfig.mojom.CrosNetworkConfigRemote} */
networkConfig_: null,
@@ -125,11 +122,6 @@ Polymer({
},
/** @override */
- attached() {
- this.simUnlockSent_ = false;
- },
-
- /** @override */
detached() {
this.closeDialogs_();
},
@@ -294,7 +286,6 @@ Polymer({
setInProgress_() {
this.error_ = ErrorType.NONE;
this.inProgress_ = true;
- this.simUnlockSent_ = true;
},
/**
@@ -508,29 +499,35 @@ Polymer({
getErrorMsg_() {
if (this.error_ === ErrorType.NONE) {
return '';
+ } else if (this.error_ === ErrorType.MISMATCHED_PIN) {
+ return this.i18n('networkSimErrorPinMismatch');
}
- const retriesLeft = (this.simUnlockSent_ && this.deviceState &&
- this.deviceState.simLockStatus) ?
+
+ let errorStringId = '';
+ switch (this.error_) {
+ case ErrorType.INCORRECT_PIN:
+ errorStringId = 'networkSimErrorIncorrectPin';
+ break;
+ case ErrorType.INCORRECT_PUK:
+ errorStringId = 'networkSimErrorIncorrectPuk';
+ break;
+ case ErrorType.INVALID_PIN:
+ errorStringId = 'networkSimErrorInvalidPin';
+ break;
+ case ErrorType.INVALID_PUK:
+ errorStringId = 'networkSimErrorInvalidPuk';
+ break;
+ default:
+ assertNotReached();
+ }
+
+ const retriesLeft = (this.deviceState && this.deviceState.simLockStatus) ?
this.deviceState.simLockStatus.retriesLeft :
0;
-
- if (this.error_ === ErrorType.INCORRECT_PIN) {
- return this.i18n('networkSimErrorIncorrectPin', retriesLeft);
- }
- if (this.error_ === ErrorType.INCORRECT_PUK) {
- return this.i18n('networkSimErrorIncorrectPuk', retriesLeft);
- }
- if (this.error_ === ErrorType.MISMATCHED_PIN) {
- return this.i18n('networkSimErrorPinMismatch');
- }
- if (this.error_ === ErrorType.INVALID_PIN) {
- return this.i18n('networkSimErrorInvalidPin', retriesLeft);
- }
- if (this.error_ === ErrorType.INVALID_PUK) {
- return this.i18n('networkSimErrorInvalidPuk', retriesLeft);
+ if (retriesLeft !== 1) {
+ errorStringId += 'Plural';
}
- assertNotReached();
- return '';
+ return this.i18n(errorStringId, retriesLeft);
},
/**
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/onc_mojo.js b/chromium/ui/webui/resources/cr_components/chromeos/network/onc_mojo.js
index 932940e4306..97f830ea95f 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/onc_mojo.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/onc_mojo.js
@@ -192,6 +192,8 @@
return 'Prohibited';
case DeviceStateType.kUnavailable:
return 'Unavailable';
+ case DeviceStateType.kInhibited:
+ return 'Inhibited';
}
assertNotReached('Unexpected enum value: ' + OncMojo.getEnumString(value));
return '';
@@ -208,6 +210,7 @@
case DeviceStateType.kDisabling:
case DeviceStateType.kEnabling:
case DeviceStateType.kUnavailable:
+ case DeviceStateType.kInhibited:
return true;
case DeviceStateType.kDisabled:
case DeviceStateType.kEnabled:
@@ -269,6 +272,16 @@
}
/**
+ * @param {!chromeos.networkConfig.mojom.NetworkType} value
+ * @return {boolean}
+ */
+ static networkTypeHasConfigurationFlow(value) {
+ // Cellular networks are considered "configured" by their SIM, and Instant
+ // Tethering networks do not have a configuration flow.
+ return !OncMojo.networkTypeIsMobile(value);
+ }
+
+ /**
* @param {string} value
* @return {!chromeos.networkConfig.mojom.NetworkType}
*/
@@ -542,6 +555,25 @@
}
/**
+ * Determines whether a connection to |network| can be attempted. Note that
+ * this function does not consider policies which may block a connection from
+ * succeeding.
+ * @param {!chromeos.networkConfig.mojom.NetworkStateProperties|
+ * !chromeos.networkConfig.mojom.ManagedProperties} network
+ * @return {boolean} Whether the network can currently be connected; if the
+ * network is not connectable, it must first be configured.
+ */
+ static isNetworkConnectable(network) {
+ // Networks without a configuration flow are always connectable since no
+ // additional configuration can be performed to attempt a connection.
+ if (!OncMojo.networkTypeHasConfigurationFlow(network.type)) {
+ return true;
+ }
+
+ return network.connectable;
+ }
+
+ /**
* @param {string} key
* @return {boolean}
*/
@@ -590,6 +622,8 @@
switch (type) {
case mojom.NetworkType.kCellular:
result.typeState.cellular = {
+ iccid: '',
+ eid: '',
activationState: mojom.ActivationStateType.kUnknown,
networkTechnology: '',
roaming: false,
@@ -622,6 +656,7 @@
bssid: '',
frequency: 0,
hexSsid: opt_name || '',
+ hiddenSsid: false,
security: mojom.SecurityType.kNone,
signalStrength: 0,
ssid: '',
@@ -728,6 +763,7 @@
activationState: mojom.ActivationStateType.kUnknown,
allowRoaming: false,
signalStrength: 0,
+ simLocked: false,
supportNetworkScan: false,
}
};
@@ -794,7 +830,14 @@
case mojom.NetworkType.kWiFi:
// Note: wifi.security can not be changed, so |security| will be ignored
// for existing configurations.
- return {typeConfig: {wifi: {security: mojom.SecurityType.kNone}}};
+ return {
+ typeConfig: {
+ wifi: {
+ security: mojom.SecurityType.kNone,
+ hiddenSsid: mojom.HiddenSsidMode.kAutomatic
+ }
+ }
+ };
break;
}
assertNotReached('Unexpected type: ' + type.toString());
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn
index a326dc50a52..359a0e05c0d 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn
@@ -8,52 +8,23 @@ import("//ui/webui/resources/tools/js_modulizer.gni")
assert(is_chromeos, "Only ChromeOS components belong here.")
-# JS type check for Polymer 2 and 3
-
-js_type_check("closure_compile") {
- deps = [
- ":network_diagnostics",
- ":network_health_summary",
- ]
-}
-
js_type_check("closure_compile_module") {
is_polymer3 = true
deps = [
":network_diagnostics.m",
":network_diagnostics_mojo.m",
+ ":network_diagnostics_types.m",
+ ":network_health_container.m",
+ ":network_health_mojo.m",
":network_health_summary.m",
- ]
-}
-
-# Sources with Polymer 3 generated modules
-
-js_library("network_health_summary") {
- deps = [
- "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile",
- "//ui/webui/resources/cr_components/chromeos/network:onc_mojo",
- "//ui/webui/resources/js:i18n_behavior",
- ]
-}
-
-js_library("network_diagnostics") {
- deps = [
- "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile",
- "//ui/webui/resources/js:i18n_behavior",
- ]
-}
-
-js_library("network_diagnostics_mojo") {
- deps = [
- "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile",
- "//ui/webui/resources/js:cr",
+ ":routine_group.m",
]
}
js_library("network_health_summary.m") {
sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.m.js" ]
deps = [
- "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile",
+ ":network_health_mojo.m",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/cr_components/chromeos/network:onc_mojo",
"//ui/webui/resources/js:i18n_behavior.m",
@@ -61,10 +32,25 @@ js_library("network_health_summary.m") {
extra_deps = [ ":network_health_summary_module" ]
}
+js_library("network_health_mojo.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.m.js" ]
+ deps = [ "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile" ]
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("network_health_container.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.m.js" ]
+ deps =
+ [ "//third_party/polymer/v3_0/components-chromium/iron-icon:iron-icon" ]
+ extra_deps = [ ":network_health_container_module" ]
+}
+
js_library("network_diagnostics.m") {
sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.m.js" ]
deps = [
":network_diagnostics_mojo.m",
+ ":network_diagnostics_types.m",
+ ":routine_group.m",
"//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/js:i18n_behavior.m",
@@ -74,32 +60,73 @@ js_library("network_diagnostics.m") {
js_library("network_diagnostics_mojo.m") {
sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_mojo.m.js" ]
- deps = [ "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js_library_for_compile" ]
+ deps = [ "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile" ]
+ extra_deps = [ ":modulize" ]
+}
+
+js_library("network_diagnostics_types.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.m.js" ]
+ deps = [ ":network_diagnostics_mojo.m" ]
extra_deps = [ ":modulize" ]
}
+js_library("routine_group.m") {
+ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/routine_group.m.js" ]
+ deps = [
+ ":network_diagnostics_mojo.m",
+ ":network_diagnostics_types.m",
+ ":network_health_container.m",
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ "//ui/webui/resources/js:i18n_behavior.m",
+ ]
+ extra_deps = [ ":routine_group_module" ]
+}
+
# polymer_modulizer for converting Polymer2 to Polymer3
polymer_modulizer("network_health_summary") {
js_file = "network_health_summary.js"
html_file = "network_health_summary.html"
html_type = "dom-module"
+ auto_imports = [
+ "ui/webui/resources/cr_components/chromeos/network/onc_mojo.html|OncMojo",
+ ]
+}
+
+polymer_modulizer("network_health_container") {
+ js_file = "network_health_container.js"
+ html_file = "network_health_container.html"
+ html_type = "dom-module"
}
polymer_modulizer("network_diagnostics") {
js_file = "network_diagnostics.js"
html_file = "network_diagnostics.html"
html_type = "dom-module"
+ auto_imports = [ "ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.html|Routine,RoutineResponse,RoutineGroup,RoutineType" ]
+}
+
+polymer_modulizer("routine_group") {
+ js_file = "routine_group.js"
+ html_file = "routine_group.html"
+ html_type = "dom-module"
+ auto_imports = [ "ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.html|Icons,Routine,RoutineResponse" ]
}
js_modulizer("modulize") {
- input_files = [ "network_diagnostics_mojo.js" ]
+ input_files = [
+ "network_health_mojo.js",
+ "network_diagnostics_mojo.js",
+ "network_diagnostics_types.js",
+ ]
}
group("polymer3_elements") {
public_deps = [
":modulize",
":network_diagnostics_module",
+ ":network_health_container_module",
":network_health_summary_module",
+ ":routine_group_module",
]
}
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html
index 4e0997eba8d..9acf444ba16 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html
@@ -1,50 +1,35 @@
<link rel="import" href="../../../html/polymer.html">
-<link rel="import" href="chrome://resources/cr_components/chromeos/network_health/network_diagnostics_mojo.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
<link rel="import" href="../../../cr_elements/cr_button/cr_button.html">
<link rel="import" href="../../../html/i18n_behavior.html">
+<link rel="import" href="network_diagnostics_mojo.html">
+<link rel="import" href="network_diagnostics_types.html">
+<link rel="import" href="routine_group.html">
<dom-module id="network-diagnostics">
<template>
- <style>
- .routine-container {
- align-items: center;
- border: 2px solid rgb(175, 175, 175);
- display: flex;
- height: 30px;
- margin: 10px;
- padding: 5px;
- }
-
- .routine-icon {
- height: 25px;
- padding-inline-end: 10px;
- width: auto;
- }
-
- .routine-name {
- flex: 1;
- font-size: 1rem;
- }
- </style>
- <template is="dom-repeat" items="[[routines_]]" as="routine">
- <div class="routine-container" aria-label="[[i18n(routine.name)]]"
- aria-description="[[routine.ariaDescription]]">
- <img class="routine-icon" src="[[getRoutineIcon_(routine.result)]]">
- <div aria-hidden="true" class="routine-name">
- [[i18n(routine.name)]]
- </div>
- <div aria-hidden="true" class="routine-result"
- hidden="[[!routine.resultMsg]]">
- [[routine.resultMsg]]
- </div>
-
- <template is="dom-if" if="[[routine.running]]">
- <paper-spinner-lite active></paper-spinner-lite>
- </template>
- </div>
- </template>
+ <routine-group name="[[i18n('NetworkDiagnosticsConnectionGroup')]]"
+ routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.CONNECTION)]]">
+ </routine-group>
+ <routine-group name="[[i18n('NetworkDiagnosticsWifiGroup')]]"
+ routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.WIFI)]]">
+ </routine-group>
+ <routine-group name="[[i18n('NetworkDiagnosticsCaptivePortal')]]"
+ routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.PORTAL)]]">
+ </routine-group>
+ <routine-group name="[[i18n('NetworkDiagnosticsGatewayGroup')]]"
+ routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.GATEWAY)]]">
+ </routine-group>
+ <routine-group name="[[i18n('NetworkDiagnosticsFirewallGroup')]]"
+ routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.FIREWALL)]]">
+ </routine-group>
+ <routine-group name="[[i18n('NetworkDiagnosticsDnsGroup')]]"
+ routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.DNS)]]">
+ </routine-group>
+ <routine-group name="[[i18n('NetworkDiagnosticsGoogleServicesGroup')]]"
+ routines=
+ "[[getRoutineGroup_(routines_.*, RoutineGroup_.GOOGLE_SERVICES)]]">
+ </routine-group>
</template>
<script src="network_diagnostics.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.js
index 1bc363c0810..a721ccb8cbf 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.js
@@ -1,4 +1,3 @@
-
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,57 +10,19 @@
const diagnosticsMojom = chromeos.networkDiagnostics.mojom;
/**
- * A routine response from the Network Diagnostics mojo service.
- * @typedef {{
- * verdict: chromeos.networkDiagnostics.mojom.RoutineVerdict,
- * }}
- * RoutineResponse can optionally have a `problems` field, which is an array of
- * enums relevant to the routine run. Unfortunately the closure compiler cannot
- * handle optional object fields.
- */
-let RoutineResponse;
-
-/**
- * A network diagnostics routine. Holds descriptive information about the
- * routine, and it's transient state.
- * @typedef {{
- * name: string,
- * type: !RoutineType,
- * running: boolean,
- * resultMsg: string,
- * result: ?RoutineResponse,
- * }}
- */
-let Routine;
-
-/**
- * Definition for all Network diagnostic routine types. This enum is intended
- * to be used as an index in an array of routines.
- * @enum {number}
- */
-const RoutineType = {
- LAN_CONNECTIVITY: 0,
- SIGNAL_STRENGTH: 1,
- GATEWAY_PING: 2,
- SECURE_WIFI: 3,
- DNS_RESOLVER: 4,
- DNS_LATENCY: 5,
- DNS_RESOLUTION: 6,
- HTTP_FIREWALL: 7,
- HTTPS_FIREWALL: 8,
- HTTPS_LATENCY: 9,
-};
-
-/**
* Helper function to create a routine object.
* @param {string} name
* @param {!RoutineType} type
+ * @param {!RoutineGroup} group
+ * @param {!function()} func
* @return {!Routine} Routine object
*/
-function createRoutine(name, type) {
+function createRoutine(name, type, group, func) {
return {
name: name,
type: type,
+ group: group,
+ func: func,
running: false,
resultMsg: '',
result: null,
@@ -84,30 +45,125 @@ Polymer({
routines_: {
type: Array,
value: function() {
+ const routineGroups = [
+ {
+ group: RoutineGroup.CONNECTION,
+ routines: [
+ {
+ name: 'NetworkDiagnosticsLanConnectivity',
+ type: RoutineType.LAN_CONNECTIVITY,
+ func: () => this.networkDiagnostics_.lanConnectivity(),
+ },
+ ]
+ },
+ {
+ group: RoutineGroup.WIFI,
+ routines: [
+ {
+ name: 'NetworkDiagnosticsSignalStrength',
+ type: RoutineType.SIGNAL_STRENGTH,
+ func: () => this.networkDiagnostics_.signalStrength(),
+ },
+ {
+ name: 'NetworkDiagnosticsHasSecureWiFiConnection',
+ type: RoutineType.SECURE_WIFI,
+ func: () => this.networkDiagnostics_.hasSecureWiFiConnection(),
+ },
+ ]
+ },
+ {
+ group: RoutineGroup.PORTAL,
+ routines: [
+ {
+ name: 'NetworkDiagnosticsCaptivePortal',
+ type: RoutineType.CAPTIVE_PORTAL,
+ func: () => this.networkDiagnostics_.captivePortal(),
+ },
+ ]
+ },
+ {
+ group: RoutineGroup.GATEWAY,
+ routines: [
+ {
+ name: 'NetworkDiagnosticsGatewayCanBePinged',
+ type: RoutineType.GATEWAY_PING,
+ func: () => this.networkDiagnostics_.gatewayCanBePinged(),
+ },
+ ]
+ },
+ {
+ group: RoutineGroup.FIREWALL,
+ routines: [
+ {
+ name: 'NetworkDiagnosticsHttpFirewall',
+ type: RoutineType.HTTP_FIREWALL,
+ func: () => this.networkDiagnostics_.httpFirewall(),
+ },
+ {
+ name: 'NetworkDiagnosticsHttpsFirewall',
+ type: RoutineType.HTTPS_FIREWALL,
+ func: () => this.networkDiagnostics_.httpsFirewall(),
+ },
+ {
+ name: 'NetworkDiagnosticsHttpsLatency',
+ type: RoutineType.HTTPS_LATENCY,
+ func: () => this.networkDiagnostics_.httpsLatency(),
+ },
+ ]
+ },
+ {
+ group: RoutineGroup.DNS,
+ routines: [
+ {
+ name: 'NetworkDiagnosticsDnsResolverPresent',
+ type: RoutineType.DNS_RESOLVER,
+ func: () => this.networkDiagnostics_.dnsResolverPresent(),
+ },
+ {
+ name: 'NetworkDiagnosticsDnsLatency',
+ type: RoutineType.DNS_LATENCY,
+ func: () => this.networkDiagnostics_.dnsLatency(),
+ },
+ {
+ name: 'NetworkDiagnosticsDnsResolution',
+ type: RoutineType.DNS_RESOLUTION,
+ func: () => this.networkDiagnostics_.dnsResolution(),
+ },
+ ]
+ },
+ {
+ group: RoutineGroup.GOOGLE_SERVICES,
+ routines: [
+ {
+ name: 'NetworkDiagnosticsVideoConferencing',
+ type: RoutineType.VIDEO_CONFERENCING,
+ // A null stun_server_hostname will use the routine default.
+ func: () => this.networkDiagnostics_.videoConferencing(
+ /*stun_server_hostname=*/ null),
+ },
+ ]
+ },
+ ];
const routines = [];
- routines[RoutineType.LAN_CONNECTIVITY] = createRoutine(
- 'NetworkDiagnosticsLanConnectivity', RoutineType.LAN_CONNECTIVITY);
- routines[RoutineType.SIGNAL_STRENGTH] = createRoutine(
- 'NetworkDiagnosticsSignalStrength', RoutineType.SIGNAL_STRENGTH);
- routines[RoutineType.GATEWAY_PING] = createRoutine(
- 'NetworkDiagnosticsGatewayCanBePinged', RoutineType.GATEWAY_PING);
- routines[RoutineType.SECURE_WIFI] = createRoutine(
- 'NetworkDiagnosticsHasSecureWiFiConnection',
- RoutineType.SECURE_WIFI);
- routines[RoutineType.DNS_RESOLVER] = createRoutine(
- 'NetworkDiagnosticsDnsResolverPresent', RoutineType.DNS_RESOLVER);
- routines[RoutineType.DNS_LATENCY] = createRoutine(
- 'NetworkDiagnosticsDnsLatency', RoutineType.DNS_LATENCY);
- routines[RoutineType.DNS_RESOLUTION] = createRoutine(
- 'NetworkDiagnosticsDnsResolution', RoutineType.DNS_RESOLUTION);
- routines[RoutineType.HTTP_FIREWALL] = createRoutine(
- 'NetworkDiagnosticsHttpFirewall', RoutineType.HTTP_FIREWALL);
- routines[RoutineType.HTTPS_FIREWALL] = createRoutine(
- 'NetworkDiagnosticsHttpsFirewall', RoutineType.HTTPS_FIREWALL);
- routines[RoutineType.HTTPS_LATENCY] = createRoutine(
- 'NetworkDiagnosticsHttpsLatency', RoutineType.HTTPS_LATENCY);
+
+ for (const group of routineGroups) {
+ for (const routine of group.routines) {
+ routines[routine.type] = createRoutine(
+ routine.name, routine.type, group.group, routine.func);
+ }
+ }
+
return routines;
}
+ },
+
+ /**
+ * Enum of Routine Groups
+ * @private {Object}
+ */
+ RoutineGroup_: {
+ type: Object,
+ value: RoutineGroup,
}
},
@@ -160,6 +216,17 @@ Polymer({
},
/**
+ * Runs all supported network diagnostics routines.
+ * @param {!PolymerDeepPropertyChange} routines
+ * @param {Number} group
+ * @return {!Array<!Routine>}
+ * @private
+ */
+ getRoutineGroup_(routines, group) {
+ return routines.base.filter(r => r.group === group);
+ },
+
+ /**
* @param {!Event} event
* @private
*/
@@ -179,48 +246,8 @@ Polymer({
`routines_.${type}.ariaDescription`,
this.i18n('NetworkDiagnosticsRunning'));
- switch (type) {
- case RoutineType.LAN_CONNECTIVITY:
- this.networkDiagnostics_.lanConnectivity().then(
- result => this.evaluateRoutine_(type, result));
- break;
- case RoutineType.SIGNAL_STRENGTH:
- this.networkDiagnostics_.signalStrength().then(
- result => this.evaluateRoutine_(type, result));
- break;
- case RoutineType.GATEWAY_PING:
- this.networkDiagnostics_.gatewayCanBePinged().then(
- result => this.evaluateRoutine_(type, result));
- break;
- case RoutineType.SECURE_WIFI:
- this.networkDiagnostics_.hasSecureWiFiConnection().then(
- result => this.evaluateRoutine_(type, result));
- break;
- case RoutineType.DNS_RESOLVER:
- this.networkDiagnostics_.dnsResolverPresent().then(
- result => this.evaluateRoutine_(type, result));
- break;
- case RoutineType.DNS_LATENCY:
- this.networkDiagnostics_.dnsLatency().then(
- result => this.evaluateRoutine_(type, result));
- break;
- case RoutineType.DNS_RESOLUTION:
- this.networkDiagnostics_.dnsResolution().then(
- result => this.evaluateRoutine_(type, result));
- break;
- case RoutineType.HTTP_FIREWALL:
- this.networkDiagnostics_.httpFirewall().then(
- result => this.evaluateRoutine_(type, result));
- break;
- case RoutineType.HTTPS_FIREWALL:
- this.networkDiagnostics_.httpsFirewall().then(
- result => this.evaluateRoutine_(type, result));
- break;
- case RoutineType.HTTPS_LATENCY:
- this.networkDiagnostics_.httpsLatency().then(
- result => this.evaluateRoutine_(type, result));
- break;
- }
+ this.routines_[type].func().then(
+ result => this.evaluateRoutine_(type, result));
},
/**
@@ -239,29 +266,6 @@ Polymer({
},
/**
- * Helper function to get the icon for a routine based on the result.
- * @param {RoutineResponse} result
- * @return {string}
- * @private
- */
- getRoutineIcon_(result) {
- if (!result) {
- return 'test_not_run.png';
- }
-
- switch (result.verdict) {
- case diagnosticsMojom.RoutineVerdict.kNoProblem:
- return 'test_passed.png';
- case diagnosticsMojom.RoutineVerdict.kProblem:
- return 'test_failed.png';
- case diagnosticsMojom.RoutineVerdict.kNotRun:
- return 'test_canceled.png';
- }
-
- return '';
- },
-
- /**
* Helper function to generate the routine result string.
* @param {Routine} routine
* @return {string}
@@ -310,9 +314,6 @@ Polymer({
switch (type) {
case RoutineType.SIGNAL_STRENGTH:
switch (problem) {
- case diagnosticsMojom.SignalStrengthProblem.kSignalNotFound:
- problemStrings.push(getString('SignalStrengthProblem_NotFound'));
- break;
case diagnosticsMojom.SignalStrengthProblem.kWeakSignal:
problemStrings.push(getString('SignalStrengthProblem_Weak'));
break;
@@ -452,6 +453,48 @@ Polymer({
getString('HttpsLatencyProblem_VeryHighLatency'));
break;
}
+
+ case RoutineType.CAPTIVE_PORTAL:
+ switch (problem) {
+ case diagnosticsMojom.CaptivePortalProblem.kNoActiveNetworks:
+ problemStrings.push(
+ getString('CaptivePortalProblem_NoActiveNetworks'));
+ break;
+ case diagnosticsMojom.CaptivePortalProblem.kUnknownPortalState:
+ problemStrings.push(
+ getString('CaptivePortalProblem_UnknownPortalState'));
+ break;
+ case diagnosticsMojom.CaptivePortalProblem.kPortalSuspected:
+ problemStrings.push(
+ getString('CaptivePortalProblem_PortalSuspected'));
+ break;
+ case diagnosticsMojom.CaptivePortalProblem.kPortal:
+ problemStrings.push(getString('CaptivePortalProblem_Portal'));
+ break;
+ case diagnosticsMojom.CaptivePortalProblem.kProxyAuthRequired:
+ problemStrings.push(
+ getString('CaptivePortalProblem_ProxyAuthRequired'));
+ break;
+ case diagnosticsMojom.CaptivePortalProblem.kNoInternet:
+ problemStrings.push(getString('CaptivePortalProblem_NoInternet'));
+ break;
+ }
+
+ case RoutineType.VIDEO_CONFERENCING:
+ switch (problem) {
+ case diagnosticsMojom.VideoConferencingProblem.kUdpFailure:
+ problemStrings.push(
+ getString('VideoConferencingProblem_UdpFailure'));
+ break;
+ case diagnosticsMojom.VideoConferencingProblem.kTcpFailure:
+ problemStrings.push(
+ getString('VideoConferencingProblem_TcpFailure'));
+ break;
+ case diagnosticsMojom.VideoConferencingProblem.kMediaFailure:
+ problemStrings.push(
+ getString('VideoConferencingProblem_MediaFailure'));
+ break;
+ }
}
}
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.html
new file mode 100644
index 00000000000..d8434fc447b
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.html
@@ -0,0 +1,3 @@
+<link rel="import" href="network_diagnostics_mojo.html">
+
+<script src="network_diagnostics_types.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.js
new file mode 100644
index 00000000000..e67a463f6d3
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.js
@@ -0,0 +1,79 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// clang-format off
+// #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
+// #import 'chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_diagnostics.mojom-lite.js';
+// clang-format on
+
+/**
+ * @fileoverview
+ * This file contains shared types for the network diagnostics components.
+ */
+
+/**
+ * A routine response from the Network Diagnostics mojo service.
+ * @typedef {{
+ * verdict: chromeos.networkDiagnostics.mojom.RoutineVerdict,
+ * }}
+ * RoutineResponse can optionally have a `problems` field, which is an array of
+ * enums relevant to the routine run. Unfortunately the closure compiler cannot
+ * handle optional object fields.
+ */
+/* #export */ let RoutineResponse;
+
+/**
+ * A network diagnostics routine. Holds descriptive information about the
+ * routine, and it's transient state.
+ * @typedef {{
+ * name: string,
+ * type: !RoutineType,
+ * group: !RoutineGroup,
+ * func: function(),
+ * running: boolean,
+ * resultMsg: string,
+ * result: ?RoutineResponse,
+ * }}
+ */
+/* #export */ let Routine;
+
+/**
+ * Definition for all Network diagnostic routine types. This enum is intended
+ * to be used as an index in an array of routines.
+ * @enum {number}
+ */
+/* #export */ const RoutineType = {
+ LAN_CONNECTIVITY: 0,
+ SIGNAL_STRENGTH: 1,
+ GATEWAY_PING: 2,
+ SECURE_WIFI: 3,
+ DNS_RESOLVER: 4,
+ DNS_LATENCY: 5,
+ DNS_RESOLUTION: 6,
+ HTTP_FIREWALL: 7,
+ HTTPS_FIREWALL: 8,
+ HTTPS_LATENCY: 9,
+ CAPTIVE_PORTAL: 10,
+ VIDEO_CONFERENCING: 11,
+};
+
+/**
+ * Definition for different groups of network routines.
+ * @enum {number}
+ */
+/* #export */ const RoutineGroup = {
+ CONNECTION: 0,
+ WIFI: 1,
+ PORTAL: 2,
+ GATEWAY: 3,
+ FIREWALL: 4,
+ DNS: 5,
+ GOOGLE_SERVICES: 6,
+};
+
+/* #export */ const Icons = {
+ TEST_FAILED: 'test_failed.png',
+ TEST_NOT_RUN: 'test_not_run.png',
+ TEST_PASSED: 'test_passed.png'
+};
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.html
new file mode 100644
index 00000000000..5f36e04b83a
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.html
@@ -0,0 +1,41 @@
+<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/cr_elements/icons.html">
+
+<dom-module id="network-health-container">
+ <template>
+ <style>
+ .container {
+ border: 1.5px solid rgb(175, 175, 175);
+ border-radius: 10px;
+ margin: 10px;
+ padding: 5px;
+ }
+
+ .container-header {
+ align-items: center;
+ cursor: pointer;
+ display: flex;
+ min-height: 30px;
+ }
+
+ .container-name {
+ flex: 1;
+ font-size: 1rem;
+ }
+ </style>
+
+ <div class="container">
+ <div class="container-header" on-click="onClick_">
+ <div class="container-name">[[label]]</div>
+ <slot name="header"></slot>
+ <iron-icon icon="[[getArrowIcon_(expanded)]]"></iron-icon>
+ </div>
+ <template is="dom-if" if="[[expanded]]">
+ <slot></slot>
+ </template>
+ </div>
+
+ </template>
+ <script src="network_health_container.js"></script>
+</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.js
new file mode 100644
index 00000000000..a942baea3c6
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.js
@@ -0,0 +1,47 @@
+// Copyright 2021 The Chromium 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 a container used in displaying network
+ * health info.
+ */
+
+Polymer({
+ is: 'network-health-container',
+
+ properties: {
+ /**
+ * Boolean flag if the container is expanded.
+ */
+ expanded: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
+ * Container label.
+ */
+ label: {
+ type: String,
+ value: '',
+ },
+ },
+
+ /**
+ * Returns the correct arrow icon depending on if the container is expanded.
+ * @param {boolean} expanded
+ */
+ getArrowIcon_(expanded) {
+ return expanded ? 'cr:expand-less' : 'cr:expand-more';
+ },
+
+ /**
+ * Helper function to toggle the expanded properties when the routine group
+ * is clicked.
+ * @private
+ */
+ onClick_() {
+ this.set('expanded', !this.expanded);
+ },
+});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.html
new file mode 100644
index 00000000000..ec34eaa7dd0
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.html
@@ -0,0 +1,4 @@
+<link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html">
+
+<script src="chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_health.mojom-lite.js"></script>
+<script src="network_health_mojo.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.js
new file mode 100644
index 00000000000..c923f0eb763
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.js
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// clang-format off
+// #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
+// #import 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-lite.js';
+// #import 'chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_health.mojom-lite.js';
+// clang-format on
+
+/**
+ * @fileoverview Wrapper around Network Health mojom file and associated
+ * utilities.
+ * TODO(crbug/1111852): Remove this wrapper once Polymer2 no longer needs to be
+ * supported. These imports can be used directly.
+ */
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html
index e739493b39e..e7c0869063a 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html
@@ -1,51 +1,124 @@
<link rel="import" href="../../../html/polymer.html">
-<link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html">
-<link rel="import" href="chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_health.mojom.html">
<link rel="import" href="../../../cr_elements/shared_style_css.html">
<link rel="import" href="../../../html/i18n_behavior.html">
-
+<link rel="import" href="../network/onc_mojo.html">
+<link rel="import" href="network_health_mojo.html">
<dom-module id="network-health-summary">
<template>
<style>
- table {
- width: 100%;
+ .network-attribute-container {
+ align-items: center;
+ display: flex;
+ margin: 5px;
+ }
+
+ .network-attribute-label {
+ flex: 1;
+ padding-inline-start: 10px;
+ }
+
+ .network-attribute-value {
+ flex: 1;
}
- tr,
- td {
- border: 1px solid rgb(220, 220, 220);
- font-size: 13px;
- padding: 5px;
+ .open-settings-icon {
+ height: 15px;
}
- .table-header {
- font-size: 15px;
- font-weight: bold;
- padding-bottom: 15px;
+ .type-icon {
+ height: 20px;
+ width: 20px;
}
</style>
- <table>
- <tr class="table-header">
- <td>[[i18n('OncName')]]</td>
- <td>[[i18n('OncType')]]</td>
- <td>[[i18n('NetworkHealthState')]]</td>
- <td>[[i18n('OncWiFi-SignalStrength')]]</td>
- <td>[[i18n('OncMacAddress')]]</td>
- </tr>
- <hr>
- <template is="dom-repeat"
- items="[[networkHealthState_.networks]]" as="network">
- <tr>
- <td>[[network.name]]</td>
- <td>[[getNetworkTypeString_(network.type)]]</td>
- <td>[[getNetworkStateString_(network.state)]]</td>
- <td>[[getSignalStrengthString_(network.signalStrength)]]</td>
- <td>[[network.macAddress]]</td>
- </tr>
- </template>
- </table>
+ <template is="dom-repeat" items="[[networkHealthState_.networks]]"
+ as="network">
+ <network-health-container label="[[getNetworkTypeString_(network.type)]]">
+ <span slot="header">
+ <img class="type-icon" src="[[getNetworkTypeIcon_(network.type)]]">
+ </span>
+ <template is="dom-if" if="[[network.name]]">
+ <div class="network-attribute-container">
+ <div class="network-attribute-label">
+ [[i18n('OncName')]]
+ </div>
+ <span class="network-attribute-value">
+ [[network.name]]
+ </span>
+ </div>
+ </template>
+ <div class="network-attribute-container">
+ <div class="network-attribute-label">
+ [[i18n('NetworkHealthState')]]
+ </div>
+ <span class="network-attribute-value">
+ [[getNetworkStateString_(network.state)]]
+ </span>
+ </div>
+ <template is="dom-if" if="[[showPortalState_(network)]]">
+ <div class="network-attribute-container">
+ <div class="network-attribute-label">
+ [[i18n('OncPortalState')]]
+ </div>
+ <span class="network-attribute-value">
+ [[getPortalStateString_(network.portalState)]]
+ </span>
+ </div>
+ </template>
+ <template is="dom-if" if="[[network.signalStrength]]">
+ <div class="network-attribute-container">
+ <div class="network-attribute-label">
+ [[i18n('OncWiFi-SignalStrength')]]
+ </div>
+ <span class="network-attribute-value">
+ [[getSignalStrengthString_(network.signalStrength)]]
+ </span>
+ </div>
+ </template>
+ <template is="dom-if" if="[[network.ipv4Address]]">
+ <div class="network-attribute-container">
+ <div class="network-attribute-label">
+ [[i18n('OncIpv4Address')]]
+ </div>
+ <span class="network-attribute-value">
+ [[network.ipv4Address]]
+ </span>
+ </div>
+ </template>
+ <template is="dom-if" if="[[network.ipv6Addresses.length]]">
+ <div class="network-attribute-container">
+ <div class="network-attribute-label">
+ [[i18n('OncIpv6Address')]]
+ </div>
+ <span class="network-attribute-value">
+ [[joinAddresses_(network.ipv6Addresses)]]
+ </span>
+ </div>
+ </template>
+ <template is="dom-if" if="[[network.macAddress]]">
+ <div class="network-attribute-container">
+ <div class="network-attribute-label">
+ [[i18n('OncMacAddress')]]
+ </div>
+ <span class="network-attribute-value">
+ [[network.macAddress]]
+ </span>
+ </div>
+ </template>
+ <template is="dom-if" if="[[showSettingsLink_(network)]]">
+ <div class="network-attribute-container">
+ <a href="[[getNetworkUrl_(network)]]">
+ <div class="network-attribute-label">
+ [[i18n('OpenInSettings')]]
+ <iron-icon class="open-settings-icon" icon="cr:open-in-new">
+ </iron-icon>
+ </div>
+ </a>
+ </div>
+ </template>
+ </network-health-container>
+ </template>
</template>
<script src="network_health_summary.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.js
index a681b7e9aea..e40500ccb6a 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.js
@@ -2,6 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+const TechnologyIcons = {
+ CELLULAR: 'cellular_0.svg',
+ ETHERNET: 'ethernet.svg',
+ VPN: 'vpn.svg',
+ WIFI: 'wifi_0.svg',
+};
+
/**
* @fileoverview Polymer element for displaying NetworkHealth properties.
*/
@@ -83,6 +90,46 @@ Polymer({
},
/**
+ * Returns a boolean flag to show the PortalState attribute. The information
+ * is not meaningful in all cases and should be hidden to prevent confusion.
+ * @private
+ * @param {chromeos.networkHealth.mojom.Network} network
+ * @return {boolean}
+ */
+ showPortalState_(network) {
+ const NetworkState = chromeos.networkHealth.mojom.NetworkState;
+ const PortalState = chromeos.networkConfig.mojom.PortalState;
+
+ if (network.state === NetworkState.kOnline &&
+ network.portalState === PortalState.kOnline) {
+ return false;
+ }
+
+ const notApplicableStates = [
+ NetworkState.kUninitialized,
+ NetworkState.kDisabled,
+ NetworkState.kProhibited,
+ NetworkState.kConnecting,
+ NetworkState.kNotConnected,
+ ];
+ if (notApplicableStates.includes(network.state)) {
+ return false;
+ }
+
+ return true;
+ },
+
+ /**
+ * Returns a string for the given PortalState.
+ * @private
+ * @param {chromeos.networkConfig.mojom.PortalState} state
+ * @return {string}
+ */
+ getPortalStateString_(state) {
+ return this.i18n('OncPortalState' + OncMojo.getPortalStateString(state));
+ },
+
+ /**
* Returns a string for the given NetworkType.
* @private
* @param {chromeos.networkConfig.mojom.NetworkType} type
@@ -93,6 +140,29 @@ Polymer({
},
/**
+ * Returns a icon for the given NetworkType.
+ * @private
+ * @param {chromeos.networkConfig.mojom.NetworkType} type
+ * @return {string}
+ */
+ getNetworkTypeIcon_(type) {
+ switch (type) {
+ case chromeos.networkConfig.mojom.NetworkType.kEthernet:
+ return TechnologyIcons.ETHERNET;
+ case chromeos.networkConfig.mojom.NetworkType.kWiFi:
+ return TechnologyIcons.WIFI;
+ case chromeos.networkConfig.mojom.NetworkType.kVPN:
+ return TechnologyIcons.VPN;
+ case chromeos.networkConfig.mojom.NetworkType.kTether:
+ case chromeos.networkConfig.mojom.NetworkType.kMobile:
+ case chromeos.networkConfig.mojom.NetworkType.kCellular:
+ return TechnologyIcons.CELLULAR;
+ default:
+ return '';
+ }
+ },
+
+ /**
* Returns a string for the given signal strength.
* @private
* @param {?chromeos.networkHealth.mojom.UInt32Value} signalStrength
@@ -101,4 +171,40 @@ Polymer({
getSignalStrengthString_(signalStrength) {
return signalStrength ? signalStrength.value.toString() : '';
},
+
+ /**
+ * Returns a boolean flag if the open to settings link should be shown.
+ * @private
+ * @param {chromeos.networkHealth.mojom.Network} network
+ * @return {boolean}
+ */
+ showSettingsLink_(network) {
+ const validStates = [
+ chromeos.networkHealth.mojom.NetworkState.kConnected,
+ chromeos.networkHealth.mojom.NetworkState.kConnecting,
+ chromeos.networkHealth.mojom.NetworkState.kPortal,
+ chromeos.networkHealth.mojom.NetworkState.kOnline
+ ];
+ return validStates.includes(network.state);
+ },
+
+ /**
+ * Returns a URL for the network's settings page.
+ * @private
+ * @param {chromeos.networkHealth.mojom.Network} network
+ * @return {string}
+ */
+ getNetworkUrl_(network) {
+ return 'chrome://os-settings/networkDetail?guid=' + network.guid;
+ },
+
+ /**
+ * Returns a concatenated list of strings.
+ * @private
+ * @param {!Array<string>} addresses
+ * @return {string}
+ */
+ joinAddresses_(addresses) {
+ return addresses.join(', ');
+ },
});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.html
new file mode 100644
index 00000000000..07fb6d31f53
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.html
@@ -0,0 +1,54 @@
+<link rel="import" href="../../../html/i18n_behavior.html">
+<link rel="import" href="../../../html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
+<link rel="import" href="network_diagnostics_mojo.html">
+<link rel="import" href="network_diagnostics_types.html">
+<link rel="import" href="network_health_container.html">
+
+<dom-module id="routine-group">
+ <template>
+ <style>
+ .routine-container {
+ align-items: center;
+ display: flex;
+ height: 20px;
+ margin: 5px;
+ padding: 5px;
+ }
+ .routine-icon {
+ height: 25px;
+ width: auto;
+ }
+ .routine-name {
+ flex: 1;
+ font-size: 0.8rem;
+ padding-inline-start: 10px;
+ }
+ </style>
+
+ <network-health-container expanded="[[expanded]]" label="[[name]]">
+ <span slot="header">
+ <template is="dom-if" if="[[running]]">
+ <paper-spinner-lite active></paper-spinner-lite>
+ </template>
+ <img class="routine-icon" hidden="[[!showGroupIcon]]"
+ src="[[getGroupIcon_(routines.*)]]">
+ </span>
+ <template is="dom-repeat" items="[[routines]]" as="routine"
+ mutable-data>
+ <div class="routine-container" aria-label="[[i18n(routine.name)]]"
+ aria-description="[[routine.ariaDescription]]">
+ <img class="routine-icon" src="[[getRoutineIcon_(routine.result)]]">
+ <div aria-hidden="true" class="routine-name">
+ [[i18n(routine.name)]]
+ </div>
+ <div aria-hidden="true" hidden="[[!routine.resultMsg]]">
+ [[routine.resultMsg]]
+ </div>
+ </div>
+ </template>
+ </network-health-container>
+
+ </template>
+ <script src="routine_group.js"></script>
+</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.js
new file mode 100644
index 00000000000..ee5926cb3f7
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.js
@@ -0,0 +1,151 @@
+// Copyright 2020 The Chromium 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 a group of diagnostic routines.
+ */
+
+Polymer({
+ is: 'routine-group',
+
+ behaviors: [
+ I18nBehavior,
+ ],
+
+ properties: {
+ /**
+ * List of routines to display in the group.
+ * @private {!Array<!Routine>}
+ */
+ routines: {
+ type: Array,
+ value: [],
+ },
+
+ /**
+ * Localized name for the group of routines.
+ * @private {String}
+ */
+ name: {
+ type: String,
+ value: '',
+ },
+
+ /**
+ * Boolean flag if any routines in the group are running.
+ * @private {Boolean}
+ */
+ running: {
+ type: Boolean,
+ computed: 'routinesRunning_(routines.*)',
+ },
+
+ /**
+ * Boolean flag if the container is expanded.
+ * @private {Boolean}
+ */
+ expanded: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
+ * Boolean flag if icon representing the group result should be shown.
+ * @private {Boolean}
+ */
+ showGroupIcon: {
+ type: Boolean,
+ computed: 'showGroupIcon_(running, expanded)',
+ },
+ },
+
+ /**
+ * Helper function to get the icon for a group of routines based on all of
+ * their results.
+ * @param {!PolymerDeepPropertyChange} routines
+ * @return {string}
+ * @private
+ */
+ getGroupIcon_(routines) {
+ // Assume that all tests are complete and passing until proven otherwise.
+ let complete = true;
+ let failed = false;
+
+ for (const routine of /** @type {!Array<!Routine>} */ (routines.base)) {
+ if (!routine.result) {
+ complete = false;
+ continue;
+ }
+
+ switch (routine.result.verdict) {
+ case chromeos.networkDiagnostics.mojom.RoutineVerdict.kNoProblem:
+ continue;
+ case chromeos.networkDiagnostics.mojom.RoutineVerdict.kProblem:
+ failed = true;
+ break;
+ case chromeos.networkDiagnostics.mojom.RoutineVerdict.kNotRun:
+ complete = false;
+ break;
+ }
+ }
+
+ if (failed) {
+ return Icons.TEST_FAILED;
+ }
+ if (!complete) {
+ return Icons.TEST_NOT_RUN;
+ }
+
+ return Icons.TEST_PASSED;
+ },
+
+ /**
+ * Determine if the group routine icon should be showing.
+ * @param {boolean} running
+ * @param {boolean} expanded
+ * @return {boolean}
+ * @private
+ */
+ showGroupIcon_(running, expanded) {
+ return !running && !expanded;
+ },
+
+ /**
+ * Helper function to get the icon for a routine based on the result.
+ * @param {!RoutineResponse} result
+ * @return {string}
+ * @private
+ */
+ getRoutineIcon_(result) {
+ if (!result) {
+ return Icons.TEST_NOT_RUN;
+ }
+
+ switch (result.verdict) {
+ case chromeos.networkDiagnostics.mojom.RoutineVerdict.kNoProblem:
+ return Icons.TEST_PASSED;
+ case chromeos.networkDiagnostics.mojom.RoutineVerdict.kProblem:
+ return Icons.TEST_FAILED;
+ case chromeos.networkDiagnostics.mojom.RoutineVerdict.kNotRun:
+ return Icons.TEST_NOT_RUN;
+ }
+
+ return Icons.TEST_NOT_RUN;
+ },
+
+ /**
+ * Determine if any routines in the group are running.
+ * @param {!PolymerDeepPropertyChange} routines
+ * @return {boolean}
+ * @private
+ */
+ routinesRunning_(routines) {
+ for (const routine of /** @type {!Array<!Routine>} */ (routines.base)) {
+ if (routine.running) {
+ return true;
+ }
+ }
+ return false;
+ },
+});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/os_cr_components.gni b/chromium/ui/webui/resources/cr_components/chromeos/os_cr_components.gni
index b9f33603437..c9fff8cc3e5 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/os_cr_components.gni
+++ b/chromium/ui/webui/resources/cr_components/chromeos/os_cr_components.gni
@@ -11,12 +11,25 @@ cr_components_chromeos_namespace_rewrites = [
"cellularSetup.ButtonBarState|ButtonBarState",
"cellularSetup.CellularSetupPageName|CellularSetupPageName",
"cellular_setup.ESimPageName|ESimPageName",
+ "cellular_setup.ESimUiState|ESimUiState",
"cellularSetup.PSimPageName|PSimPageName",
"cellularSetup.PSimUIState|PSimUIState",
"cellularSetup.getTimeoutMsForPSimUIState|getTimeoutMsForPSimUIState",
"cellular_setup.getCellularSetupRemote|getCellularSetupRemote",
"cellular_setup.setCellularSetupRemoteForTesting|setCellularSetupRemoteForTesting",
+ "cellular_setup.getESimManagerRemote|getESimManagerRemote",
+ "cellular_setup.setESimManagerRemoteForTesting|setESimManagerRemoteForTesting",
+ "cellular_setup.observeESimManager|observeESimManager",
+ "cellular_setup.getPendingESimProfiles|getPendingESimProfiles",
+ "cellular_setup.getEuicc|getEuicc",
+ "cellular_setup.getESimProfile|getESimProfile",
"cellular_setup.CellularSetupDelegate|CellularSetupDelegate",
+ "multidevice_setup.BrowserProxy|BrowserProxy",
+ "multidevice_setup.BrowserProxyImpl|BrowserProxyImpl",
+ "multidevice_setup.MojoInterfaceProvider|MojoInterfaceProvider",
+ "multidevice_setup.MojoInterfaceProviderImpl|MojoInterfaceProviderImpl",
+ "multidevice_setup.MultiDeviceSetupDelegate|MultiDeviceSetupDelegate",
+ "multidevice_setup.PageName|PageName",
"network_config.MojoInterfaceProvider|MojoInterfaceProvider",
"network_config.MojoInterfaceProviderImpl|MojoInterfaceProviderImpl",
"settings.LockScreenProgress|LockScreenProgress",
@@ -26,11 +39,20 @@ cr_components_chromeos_namespace_rewrites = [
cr_components_chromeos_auto_imports = [
"ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.html|CrPolicyIndicatorType",
+ "ui/webui/resources/cr_elements/cr_container_shadow_behavior.html|CrContainerShadowBehavior",
"ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_types.html|ButtonState,Button,ButtonBarState,CellularSetupPageName",
"ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup_delegate.html|CellularSetupDelegate",
"ui/webui/resources/cr_components/chromeos/cellular_setup/subflow_behavior.html|SubflowBehavior",
- "ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html|setCellularSetupRemoteForTesting,getCellularSetupRemote",
+ "ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html|setCellularSetupRemoteForTesting,getCellularSetupRemote,setESimManagerRemoteForTesting,getESimManagerRemote,observeESimManager",
+ "ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.html|getPendingESimProfiles,getEuicc,getESimProfile",
+ "ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.html|ESimManagerListenerBehavior",
+ "ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html|LoadingPageState",
+ "ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html|BrowserProxy,BrowserProxyImpl",
+ "ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.html|MojoInterfaceProvider,MojoInterfaceProviderImpl",
+ "ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html|MultiDeviceSetupDelegate",
+ "ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html|UiPageContainerBehavior",
"ui/webui/resources/cr_components/chromeos/network/cr_policy_network_behavior_mojo.html|CrPolicyNetworkBehaviorMojo",
+ "ui/webui/resources/cr_components/chromeos/network/cellular_utils.html|getSimSlotCount,hasActivePSimNetwork",
"ui/webui/resources/cr_components/chromeos/network/onc_mojo.html|OncMojo",
"ui/webui/resources/cr_components/chromeos/network/network_config_element_behavior.html|NetworkConfigElementBehavior",
"ui/webui/resources/cr_components/chromeos/network/network_listener_behavior.html|NetworkListenerBehavior",
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/BUILD.gn
index 03c04595dce..2307509d23e 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/BUILD.gn
@@ -8,6 +8,7 @@ import("//ui/webui/resources/tools/js_modulizer.gni")
import("../os_cr_components.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [
":pin_keyboard",
":setup_pin_keyboard",
@@ -83,8 +84,6 @@ js_library("setup_pin_keyboard.m") {
extra_deps = [ ":setup_pin_keyboard_module" ]
}
-import("//tools/polymer/polymer.gni")
-
group("polymer3_elements") {
public_deps = [
":modulize",
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 42e29c2a0fd..d3ae8d7f677 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
@@ -92,6 +92,14 @@ Polymer({
value: false,
},
+ // Whether or not non-digit pins are allowed.
+ // If allowNonDigit is false, any characters typed in the pin dialog
+ // will be swallowed.
+ allowNonDigit: {
+ type: Boolean,
+ value: false,
+ },
+
hasError: Boolean,
disabled: {
@@ -401,11 +409,16 @@ Polymer({
/**
* Helper function to check whether a given |event| should be processed by
- * the numeric only input.
+ * the input.
* @param {Event} event The event object.
* @private
*/
isValidEventForInput_(event) {
+ // Valid if the key is a non-digit and allowNonDigit is enabled.
+ if (this.allowNonDigit) {
+ return true;
+ }
+
// Valid if the key is a number, and shift is not pressed.
if ((event.keyCode >= 48 && event.keyCode <= 57) && !event.shiftKey) {
return true;
@@ -453,10 +466,12 @@ Polymer({
return;
}
- // Do not pass events that are not numbers or special keys we care about. We
- // use this instead of input type number because there are several issues
- // with input type number, such as no selectionStart/selectionEnd and
- // entered non numbers causes the caret to jump to the left.
+ // If only digits are allowed in the pin input (allowNonDigit is set to
+ // false), then do not pass events that are not numbers or special keys we
+ // care about. We use this instead of input type number because there are
+ // several issues with input type number, such as no
+ // selectionStart/selectionEnd and entered non numbers causes the caret to
+ // jump to the left.
if (!this.isValidEventForInput_(event)) {
event.preventDefault();
return;
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn
index 0bf953c6789..855cc63a062 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn
@@ -11,13 +11,6 @@ assert(is_chromeos, "SMB Shares is Chrome OS only.")
# TODO(crbug.com/1031947): Fully convert this component to Polymer 3 once
# chrome://os-settings has been migrated.
-js_type_check("closure_compile") {
- deps = [
- ":add_smb_share_dialog",
- ":smb_browser_proxy",
- ]
-}
-
js_type_check("closure_compile_module") {
is_polymer3 = true
deps = [
@@ -26,24 +19,6 @@ js_type_check("closure_compile_module") {
]
}
-js_library("smb_browser_proxy") {
- deps = [ "//ui/webui/resources/js:cr" ]
-}
-
-js_library("add_smb_share_dialog") {
- deps = [
- ":smb_browser_proxy",
- "//ui/webui/resources/cr_elements/cr_button:cr_button",
- "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox",
- "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
- "//ui/webui/resources/cr_elements/cr_input:cr_input",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:i18n_behavior",
- "//ui/webui/resources/js:load_time_data",
- "//ui/webui/resources/js:web_ui_listener_behavior",
- ]
-}
-
js_library("add_smb_share_dialog.m") {
sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.m.js" ]
deps = [
diff --git a/chromium/ui/webui/resources/cr_components/cr_components_images.grdp b/chromium/ui/webui/resources/cr_components/cr_components_images.grdp
deleted file mode 100644
index c0884efcd49..00000000000
--- a/chromium/ui/webui/resources/cr_components/cr_components_images.grdp
+++ /dev/null
@@ -1,134 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<grit-part>
- <!-- CustomizeThemes Images -->
- <include name="IDR_WEBUI_CR_COMPONENTS_CUSTOMIZE_THEMES_COLORIZE_ICON_SVG"
- file="cr_components/customize_themes/colorize.svg"
- type="BINDATA" />
- <include name="IDR_WEBUI_CR_COMPONENTS_CUSTOMIZE_THEMES_BRUSH_ICON_SVG"
- file="cr_components/customize_themes/brush.svg"
- type="BINDATA" />
- <if expr="chromeos">
- <!-- MultiDeviceSetup Images -->
- <include name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_START_SETUP_ICON_1X_PNG"
- file="cr_components/chromeos/multidevice_setup/start_setup_icon_1x.png"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_START_SETUP_ICON_2X_PNG"
- file="cr_components/chromeos/multidevice_setup/start_setup_icon_2x.png"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_SETUP_SUCCEEDED_ICON_1X_PNG"
- file="cr_components/chromeos/multidevice_setup/setup_succeeded_icon_1x.png"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_SETUP_SUCCEEDED_ICON_2X_PNG"
- file="cr_components/chromeos/multidevice_setup/setup_succeeded_icon_2x.png"
- type="BINDATA"
- compress="gzip" />
-
- <!-- CellularSetup Images -->
- <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ACTIVATION_CODE_PAGE_CAMERA_SVG"
- file="cr_components/chromeos/cellular_setup/activation_code_page_camera.svg"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ACTIVATION_CODE_PAGE_CHECKED_SVG"
- file="cr_components/chromeos/cellular_setup/activation_code_page_checked.svg"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ACTIVATION_CODE_PAGE_SWITCH_CAMERA_SVG"
- file="cr_components/chromeos/cellular_setup/activation_code_page_switch_camera.svg"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ERROR_1X_PNG"
- file="cr_components/chromeos/cellular_setup/error_1x.png"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ERROR_2X_PNG"
- file="cr_components/chromeos/cellular_setup/error_2x.png"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_FINAL_PAGE_SUCCESS_1X_PNG"
- file="cr_components/chromeos/cellular_setup/final_page_success_1x.png"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_FINAL_PAGE_SUCCESS_2X_PNG"
- file="cr_components/chromeos/cellular_setup/final_page_success_2x.png"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_PSIM_1X_PNG"
- file="cr_components/chromeos/cellular_setup/psim_1x.png"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_PSIM_2X_PNG"
- file="cr_components/chromeos/cellular_setup/psim_2x.png"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ESIM_1X_PNG"
- file="cr_components/chromeos/cellular_setup/esim_1x.png"
- type="BINDATA"
- compress="gzip" />
- <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ESIM_2X_PNG"
- file="cr_components/chromeos/cellular_setup/esim_2x.png"
- type="BINDATA"
- compress="gzip" />
-
- <!-- NetworkIcon Images -->
- <include name="IDR_CR_ELEMENTS_CELLULAR_0_WITH_X_SVG"
- file="cr_components/chromeos/network/cellular_0_with_x.svg"
- type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_CELLULAR_0_SVG"
- file="cr_components/chromeos/network/cellular_0.svg"
- type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_CELLULAR_1_SVG"
- file="cr_components/chromeos/network/cellular_1.svg"
- type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_CELLULAR_2_SVG"
- file="cr_components/chromeos/network/cellular_2.svg"
- type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_CELLULAR_3_SVG"
- file="cr_components/chromeos/network/cellular_3.svg"
- type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_CELLULAR_4_SVG"
- file="cr_components/chromeos/network/cellular_4.svg"
- type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_CELLULAR_OFF_SVG"
- file="cr_components/chromeos/network/cellular_off.svg"
- type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_ETHERNET_SVG"
- file="cr_components/chromeos/network/ethernet.svg" type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_VPN_SVG"
- file="cr_components/chromeos/network/vpn.svg" type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_WIFI_0_WITH_X_SVG"
- file="cr_components/chromeos/network/wifi_0_with_x.svg"
- type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_WIFI_0_SVG"
- file="cr_components/chromeos/network/wifi_0.svg" type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_WIFI_1_SVG"
- file="cr_components/chromeos/network/wifi_1.svg" type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_WIFI_2_SVG"
- file="cr_components/chromeos/network/wifi_2.svg" type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_WIFI_3_SVG"
- file="cr_components/chromeos/network/wifi_3.svg" type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_WIFI_4_SVG"
- file="cr_components/chromeos/network/wifi_4.svg" type="BINDATA" />
- <include name="IDR_CR_ELEMENTS_WIFI_OFF_SVG"
- file="cr_components/chromeos/network/wifi_off.svg" type="BINDATA" />
-
- <!-- NetworkDiagnostics Images -->
- <include name="IDR_CR_COMPONENTS_CHROMEOS_NETWORK_DIAGNOSTICS_CANCELED_ICON"
- file="cr_components/chromeos/network_health/test_canceled.png"
- type="BINDATA" />
- <include name="IDR_CR_COMPONENTS_CHROMEOS_NETWORK_DIAGNOSTICS_FAILED_ICON"
- file="cr_components/chromeos/network_health/test_failed.png"
- type="BINDATA" />
- <include name="IDR_CR_COMPONENTS_CHROMEOS_NETWORK_DIAGNOSTICS_NOT_RUN_ICON"
- file="cr_components/chromeos/network_health/test_not_run.png"
- type="BINDATA" />
- <include name="IDR_CR_COMPONENTS_CHROMEOS_NETWORK_DIAGNOSTICS_PASSED_ICON"
- file="cr_components/chromeos/network_health/test_passed.png"
- type="BINDATA" />
- <include name="IDR_CR_COMPONENTS_CHROMEOS_NETWORK_DIAGNOSTICS_WARNING_ICON"
- file="cr_components/chromeos/network_health/test_warning.png"
- type="BINDATA" />
- </if>
-</grit-part>
diff --git a/chromium/ui/webui/resources/cr_components/customize_themes/BUILD.gn b/chromium/ui/webui/resources/cr_components/customize_themes/BUILD.gn
index 2f2f94cf709..526e533a88a 100644
--- a/chromium/ui/webui/resources/cr_components/customize_themes/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/customize_themes/BUILD.gn
@@ -8,7 +8,7 @@ import("//tools/polymer/html_to_js.gni")
group("web_components") {
public_deps = [
- ":mojom_js",
+ ":mojom_webui_js",
":web_components_local",
]
}
@@ -20,6 +20,8 @@ mojom("mojom") {
"//mojo/public/mojom/base",
"//skia/public/mojom",
]
+
+ webui_module_path = "chrome://resources/cr_components/customize_themes/"
}
html_to_js("web_components_local") {
@@ -31,6 +33,7 @@ html_to_js("web_components_local") {
js_type_check("closure_compile") {
is_polymer3 = true
+ closure_flags = default_closure_args + mojom_js_args
deps = [
":browser_proxy",
":customize_themes",
@@ -41,9 +44,10 @@ js_type_check("closure_compile") {
js_library("customize_themes") {
deps = [
":browser_proxy",
- ":mojom_js_library_for_compile",
+ ":mojom_webui_js",
":theme_icon",
- "//skia/public/mojom:mojom_js_library_for_compile",
+ "//skia/public/mojom:mojom_webui_js",
+ "//third_party/polymer/v3_0/components-chromium/paper-tooltip:paper-tooltip",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/cr_elements/cr_grid",
"//ui/webui/resources/js:i18n_behavior.m",
@@ -58,7 +62,7 @@ js_library("theme_icon") {
js_library("browser_proxy") {
deps = [
- ":mojom_js_library_for_compile",
+ ":mojom_webui_js",
"//ui/webui/resources/js:cr.m",
]
}
diff --git a/chromium/ui/webui/resources/cr_components/customize_themes/browser_proxy.js b/chromium/ui/webui/resources/cr_components/customize_themes/browser_proxy.js
index a5d2c2a92df..ae7a46b3764 100644
--- a/chromium/ui/webui/resources/cr_components/customize_themes/browser_proxy.js
+++ b/chromium/ui/webui/resources/cr_components/customize_themes/browser_proxy.js
@@ -7,18 +7,16 @@
* interact with the browser.
*/
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
-import 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-lite.js';
-import './customize_themes.mojom-lite.js';
-
import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
+import {CustomizeThemesClientCallbackRouter, CustomizeThemesHandlerFactory, CustomizeThemesHandlerFactoryRemote, CustomizeThemesHandlerInterface, CustomizeThemesHandlerRemote} from './customize_themes.mojom-webui.js';
+
/** @interface */
export class CustomizeThemesBrowserProxy {
- /** @return {customizeThemes.mojom.CustomizeThemesHandlerInterface} */
+ /** @return {CustomizeThemesHandlerInterface} */
handler() {}
- /** @return {customizeThemes.mojom.CustomizeThemesClientCallbackRouter} */
+ /** @return {CustomizeThemesClientCallbackRouter} */
callbackRouter() {}
/** @param {string} url */
@@ -28,16 +26,14 @@ export class CustomizeThemesBrowserProxy {
/** @implements {CustomizeThemesBrowserProxy} */
export class CustomizeThemesBrowserProxyImpl {
constructor() {
- /** @private {customizeThemes.mojom.CustomizeThemesHandlerRemote} */
- this.handler_ = new customizeThemes.mojom.CustomizeThemesHandlerRemote();
+ /** @private {!CustomizeThemesHandlerRemote} */
+ this.handler_ = new CustomizeThemesHandlerRemote();
- /** @private {customizeThemes.mojom.CustomizeThemesClientCallbackRouter} */
- this.callbackRouter_ =
- new customizeThemes.mojom.CustomizeThemesClientCallbackRouter();
+ /** @private {!CustomizeThemesClientCallbackRouter} */
+ this.callbackRouter_ = new CustomizeThemesClientCallbackRouter();
- /** @type {customizeThemes.mojom.CustomizeThemesHandlerFactoryRemote} */
- const factory =
- customizeThemes.mojom.CustomizeThemesHandlerFactory.getRemote();
+ /** @type {!CustomizeThemesHandlerFactoryRemote} */
+ const factory = CustomizeThemesHandlerFactory.getRemote();
factory.createCustomizeThemesHandler(
this.callbackRouter_.$.bindNewPipeAndPassRemote(),
this.handler_.$.bindNewPipeAndPassReceiver());
diff --git a/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.html b/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.html
index d2fc1a6db81..e4a252f11cf 100644
--- a/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.html
+++ b/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.html
@@ -1,4 +1,4 @@
-<style include="cr-hidden-style cr-icons">
+<style include="cr-hidden-style cr-icons cr-shared-style">
:host {
--cr-customize-themes-grid-gap: 20px;
--cr-customize-themes-icon-size: 72px;
@@ -68,18 +68,21 @@
}
#autogeneratedThemeContainer {
- display: flex;
- flex-direction: column;
position: relative;
}
+ /* colorPicker is placed on top of the theme icon to work around
+ https://crbug.com/1162053 */
#colorPicker {
border: 0;
- height: 0;
+ height: var(--cr-customize-themes-icon-size);
+ left: 0;
margin: 0;
padding: 0;
+ position: absolute;
+ top: 0;
visibility: hidden;
- width: 0;
+ width: var(--cr-customize-themes-icon-size);
}
#colorPickerIcon {
@@ -116,6 +119,14 @@
}
}
+ paper-tooltip {
+ --paper-tooltip-delay-in: 100ms;
+ --paper-tooltip-duration-in: 100ms;
+ --paper-tooltip-duration-out: 100ms;
+ --paper-tooltip-min-width: none;
+ --paper-tooltip-padding: 5px 4px;
+ }
+
</style>
<div id="thirdPartyThemeContainer" hidden="[[!isThirdPartyTheme_(selectedTheme)]]">
<div id="thirdPartyTheme">
@@ -135,28 +146,49 @@
</cr-button>
</div>
</div>
-<cr-grid id="themesContainer" columns="6">
- <div id="autogeneratedThemeContainer" title="[[i18n('colorPickerLabel')]]"
- tabindex="0" on-click="onAutogeneratedThemeClick_">
- <cr-theme-icon id="autogeneratedTheme"
- selected$="[[isThemeIconSelected_('autogenerated', selectedTheme)]]">
+<cr-grid id="themesContainer" columns="6" role="radiogroup">
+ <div aria-label="[[i18n('colorPickerLabel')]]"
+ tabindex$="[[getTabIndex_('autogenerated', selectedTheme)]]"
+ on-click="onAutogeneratedThemeClick_" role="radio"
+ aria-checked$="[[getThemeIconCheckedStatus_('autogenerated', selectedTheme)]]">
+ <div id="autogeneratedThemeContainer">
+ <cr-theme-icon id="autogeneratedTheme"
+ selected$="[[isThemeIconSelected_('autogenerated', selectedTheme)]]">
+ </cr-theme-icon>
+ <div id="colorPickerIcon"></div>
+ <input id="colorPicker" type="color"
+ on-change="onCustomFrameColorChange_">
+ </div>
+ <paper-tooltip offset="0" fit-to-visible-bounds>
+ [[i18n('colorPickerLabel')]]
+ </paper-tooltip>
+ </div>
+ <div aria-label="[[i18n('defaultThemeLabel')]]"
+ tabindex$="[[getTabIndex_('default', selectedTheme)]]"
+ on-click="onDefaultThemeClick_" role="radio"
+ aria-checked$="[[getThemeIconCheckedStatus_('default', selectedTheme)]]">
+ <cr-theme-icon id="defaultTheme"
+ selected$="[[isThemeIconSelected_('default', selectedTheme)]]">
</cr-theme-icon>
- <div id="colorPickerIcon"></div>
- <input id="colorPicker" type="color" on-change="onCustomFrameColorChange_">
- </input>
+ <paper-tooltip offset="0" fit-to-visible-bounds>
+ [[i18n('defaultThemeLabel')]]
+ </paper-tooltip>
</div>
- <cr-theme-icon id="defaultTheme" title="[[i18n('defaultThemeLabel')]]"
- on-click="onDefaultThemeClick_" tabindex="0"
- selected$="[[isThemeIconSelected_('default', selectedTheme)]]">
- </cr-theme-icon>
<template is="dom-repeat" id="themes" items="[[chromeThemes_]]">
- <cr-theme-icon title="[[item.label]]" on-click="onChromeThemeClick_"
- style="--cr-theme-icon-frame-color:
- [[skColorToRgba_(item.colors.frame)]];
- --cr-theme-icon-active-tab-color:
- [[skColorToRgba_(item.colors.activeTab)]];"
- tabindex="0"
- selected$="[[isThemeIconSelected_(item.id, selectedTheme)]]">
- </cr-theme-icon>
+ <div aria-label="[[item.label]]"
+ tabindex$="[[getTabIndex_(item.id, selectedTheme)]]"
+ on-click="onChromeThemeClick_" class="chrome-theme-wrapper" role="radio"
+ aria-checked$="[[getThemeIconCheckedStatus_(item.id, selectedTheme)]]">
+ <cr-theme-icon
+ style="--cr-theme-icon-frame-color:
+ [[skColorToRgba_(item.colors.frame)]];
+ --cr-theme-icon-active-tab-color:
+ [[skColorToRgba_(item.colors.activeTab)]];"
+ selected$="[[isThemeIconSelected_(item.id, selectedTheme)]]">
+ </cr-theme-icon>
+ <paper-tooltip offset="0" fit-to-visible-bounds>
+ [[item.label]]
+ </paper-tooltip>
+ </div>
</template>
</cr-grid>
diff --git a/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.js b/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.js
index d5d84bbd109..f1260fcf3c4 100644
--- a/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.js
+++ b/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.js
@@ -7,11 +7,11 @@ import '../../cr_elements/cr_icon_button/cr_icon_button.m.js';
import '../../cr_elements/cr_icons_css.m.js';
import '../../cr_elements/cr_grid/cr_grid.js';
import '../../cr_elements/shared_vars_css.m.js';
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
-import 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-lite.js';
-import './customize_themes.mojom-lite.js';
+import '../../cr_elements/shared_style_css.m.js';
import './theme_icon.js';
+import '//resources/polymer/v3_0/paper-tooltip/paper-tooltip.js';
+import {SkColor} from 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-webui.js';
import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assert} from '../../js/assert.m.js';
@@ -19,6 +19,7 @@ import {hexColorToSkColor, skColorToRgba} from '../../js/color_utils.js';
import {I18nBehavior} from '../../js/i18n_behavior.m.js';
import {CustomizeThemesBrowserProxyImpl} from './browser_proxy.js';
+import {ChromeTheme, CustomizeThemesClientCallbackRouter, CustomizeThemesHandlerRemote, Theme, ThemeType} from './customize_themes.mojom-webui.js';
/**
* Element that lets the user configure the autogenerated theme.
@@ -39,10 +40,11 @@ export class CustomizeThemesElement extends mixinBehaviors
return {
/**
* An object describing the currently selected theme.
- * @type {!customizeThemes.mojom.Theme}
+ * @type {?Theme}
*/
selectedTheme: {
type: Object,
+ value: null,
observer: 'onThemeChange_',
notify: true,
},
@@ -58,17 +60,17 @@ export class CustomizeThemesElement extends mixinBehaviors
value: false,
},
- /** @private {!Array<!customizeThemes.mojom.ChromeTheme>} */
+ /** @private {!Array<!ChromeTheme>} */
chromeThemes_: Array,
};
}
constructor() {
super();
- /** @private {customizeThemes.mojom.CustomizeThemesHandlerRemote} */
+ /** @private {CustomizeThemesHandlerRemote} */
this.handler_ = CustomizeThemesBrowserProxyImpl.getInstance().handler();
- /** @private {customizeThemes.mojom.CustomizeThemesClientCallbackRouter} */
+ /** @private {CustomizeThemesClientCallbackRouter} */
this.callbackRouter_ =
CustomizeThemesBrowserProxyImpl.getInstance().callbackRouter();
@@ -142,8 +144,8 @@ export class CustomizeThemesElement extends mixinBehaviors
/** @private */
onThemeChange_() {
- if (this.selectedTheme.type !==
- customizeThemes.mojom.ThemeType.kAutogenerated) {
+ if (!this.selectedTheme ||
+ this.selectedTheme.type !== ThemeType.kAutogenerated) {
return;
}
const rgbaFrameColor =
@@ -188,29 +190,47 @@ export class CustomizeThemesElement extends mixinBehaviors
return false;
}
if (id === 'autogenerated') {
- return this.selectedTheme.type ===
- customizeThemes.mojom.ThemeType.kAutogenerated;
+ return this.selectedTheme.type === ThemeType.kAutogenerated;
} else if (id === 'default') {
- return this.selectedTheme.type ===
- customizeThemes.mojom.ThemeType.kDefault;
+ return this.selectedTheme.type === ThemeType.kDefault;
} else {
- return this.selectedTheme.type ===
- customizeThemes.mojom.ThemeType.kChrome &&
+ return this.selectedTheme.type === ThemeType.kChrome &&
id === this.selectedTheme.info.chromeThemeId;
}
}
/**
+ * @param {string|number} id
+ * @return {string}
+ * @private
+ */
+ getTabIndex_(id) {
+ if (!this.selectedTheme && id === 'autogenerated') {
+ return '0';
+ }
+ return this.isThemeIconSelected_(id) ? '0' : '-1';
+ }
+
+ /**
+ * @param {string|number} id
+ * @return {string}
+ * @private
+ */
+ getThemeIconCheckedStatus_(id) {
+ return this.isThemeIconSelected_(id) ? 'true' : 'false';
+ }
+
+ /**
* @return {boolean}
* @private
*/
isThirdPartyTheme_() {
- return this.selectedTheme.type ===
- customizeThemes.mojom.ThemeType.kThirdParty;
+ return !!this.selectedTheme &&
+ this.selectedTheme.type === ThemeType.kThirdParty;
}
/**
- * @param {skia.mojom.SkColor} skColor
+ * @param {SkColor} skColor
* @return {string}
* @private
*/
diff --git a/chromium/ui/webui/resources/cr_components/customize_themes/theme_icon.html b/chromium/ui/webui/resources/cr_components/customize_themes/theme_icon.html
index 7a56940625d..9a70c8bda2a 100644
--- a/chromium/ui/webui/resources/cr_components/customize_themes/theme_icon.html
+++ b/chromium/ui/webui/resources/cr_components/customize_themes/theme_icon.html
@@ -1,6 +1,8 @@
<style>
:host {
--cr-theme-icon-size: 72px;
+ cursor: pointer;
+ display: block;
}
:host,
diff --git a/chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn b/chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn
index 0ec7f641f02..3f4a86dcdc7 100644
--- a/chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":managed_footnote" ]
}
diff --git a/chromium/ui/webui/resources/cr_components/omnibox/BUILD.gn b/chromium/ui/webui/resources/cr_components/omnibox/BUILD.gn
index b02454dcd94..978d475683c 100644
--- a/chromium/ui/webui/resources/cr_components/omnibox/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/omnibox/BUILD.gn
@@ -6,7 +6,6 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/html_to_js.gni")
js_type_check("closure_compile") {
- uses_js_modules = true
deps = [ ":cr_autocomplete_match_list" ]
}
diff --git a/chromium/ui/webui/resources/cr_components/omnibox/cr_autocomplete_match_list.js b/chromium/ui/webui/resources/cr_components/omnibox/cr_autocomplete_match_list.js
index c5e48719093..7b22109424b 100644
--- a/chromium/ui/webui/resources/cr_components/omnibox/cr_autocomplete_match_list.js
+++ b/chromium/ui/webui/resources/cr_components/omnibox/cr_autocomplete_match_list.js
@@ -16,11 +16,14 @@
*/
let AutocompleteMatch;
+const staticHtmlPolicy = trustedTypes.createPolicy(
+ 'cr-autocomplete-match', {createHTML: () => `{__html_template__}`});
+
class AutocompleteMatchElement extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
- this.shadowRoot.innerHTML = `{__html_template__}`;
+ this.shadowRoot.innerHTML = staticHtmlPolicy.createHTML('');
}
/** @param {!AutocompleteMatch} match */
@@ -47,8 +50,8 @@ export class AutocompleteMatchListElement extends HTMLElement {
/** @param {!Array<!AutocompleteMatch>} matches */
updateMatches(matches) {
- for (let i = 0; i < matches.length; i++) {
- const shadowRoot = /** @type {!ParentNode} */ (this.shadowRoot);
+ const shadowRoot = /** @type {!ParentNode} */ (this.shadowRoot);
+ for (let i = 0; i < matches.length && i < shadowRoot.children.length; i++) {
shadowRoot.children[i].updateMatch(matches[i]);
}
}
diff --git a/chromium/ui/webui/resources/cr_elements/BUILD.gn b/chromium/ui/webui/resources/cr_elements/BUILD.gn
index 708349fa816..abae49ca3a1 100644
--- a/chromium/ui/webui/resources/cr_elements/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/BUILD.gn
@@ -2,8 +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/chromeos/ui_mode.gni")
import("//third_party/closure_compiler/compile_js.gni")
-import("//tools/grit/preprocess_grit.gni")
+import("//tools/grit/preprocess_if_expr.gni")
import("//tools/polymer/html_to_js.gni")
import("//tools/polymer/polymer.gni")
import("//ui/webui/resources/tools/generate_grd.gni")
@@ -34,14 +35,14 @@ group("preprocess") {
]
}
-preprocess_grit("preprocess_src") {
+preprocess_if_expr("preprocess_src") {
in_folder = "./"
out_folder = "$preprocess_folder"
out_manifest = "$target_gen_dir/$preprocess_src_manifest"
in_files = [ "cr_splitter/cr_splitter.js" ]
}
-preprocess_grit("preprocess_polymer2") {
+preprocess_if_expr("preprocess_polymer2") {
in_folder = "./"
out_folder = "$preprocess_folder"
out_manifest = "$target_gen_dir/$preprocess_polymer2_manifest"
@@ -106,12 +107,8 @@ preprocess_grit("preprocess_polymer2") {
"cr_toast/cr_toast_manager.js",
"cr_toggle/cr_toggle.html",
"cr_toggle/cr_toggle.js",
- "cr_toolbar/cr_toolbar.html",
- "cr_toolbar/cr_toolbar.js",
"cr_toolbar/cr_toolbar_search_field.html",
"cr_toolbar/cr_toolbar_search_field.js",
- "cr_toolbar/cr_toolbar_selection_overlay.html",
- "cr_toolbar/cr_toolbar_selection_overlay.js",
"cr_view_manager/cr_view_manager.html",
"cr_view_manager/cr_view_manager.js",
"find_shortcut_behavior.html",
@@ -134,7 +131,7 @@ preprocess_grit("preprocess_polymer2") {
"shared_vars_css.html",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
in_files += [
"chromeos/cros_color_overrides.html",
"chromeos/cr_picture/cr_camera.html",
@@ -154,7 +151,7 @@ preprocess_grit("preprocess_polymer2") {
}
}
-preprocess_grit("preprocess_generated") {
+preprocess_if_expr("preprocess_generated") {
deps = [ ":polymer3_elements" ]
in_folder = target_gen_dir
out_folder = "$preprocess_folder"
@@ -195,9 +192,9 @@ preprocess_grit("preprocess_generated") {
"cr_toast/cr_toast_manager.m.js",
"cr_toast/cr_toast.m.js",
"cr_toggle/cr_toggle.m.js",
- "cr_toolbar/cr_toolbar.m.js",
+ "cr_toolbar/cr_toolbar.js",
"cr_toolbar/cr_toolbar_search_field.m.js",
- "cr_toolbar/cr_toolbar_selection_overlay.m.js",
+ "cr_toolbar/cr_toolbar_selection_overlay.js",
"cr_view_manager/cr_view_manager.m.js",
"find_shortcut_behavior.m.js",
"hidden_style_css.m.js",
@@ -216,7 +213,7 @@ preprocess_grit("preprocess_generated") {
"shared_vars_css.m.js",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
in_files += [
"chromeos/cros_color_overrides.m.js",
"chromeos/cr_picture/cr_camera.m.js",
@@ -285,7 +282,7 @@ group("closure_compile") {
"policy:closure_compile_module",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [
"chromeos:closure_compile",
@@ -298,6 +295,7 @@ group("closure_compile") {
}
js_type_check("cr_elements_resources") {
+ uses_legacy_modules = true
deps = [
":cr_container_shadow_behavior",
":cr_scrollable_behavior",
@@ -426,7 +424,7 @@ group("polymer3_elements") {
"policy:polymer3_elements",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
public_deps += [
"chromeos:polymer3_elements",
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/BUILD.gn b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/BUILD.gn
index fb064493ebc..5a3b0bc6507 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/BUILD.gn
@@ -2,12 +2,14 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
import("//ui/webui/resources/tools/js_modulizer.gni")
import("../os_cr_elements.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [
":cr_camera",
":cr_picture_list",
@@ -74,7 +76,7 @@ js_library("png.m") {
# platforms.
js_library("cr_picture_types.m") {
sources = []
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [ "$root_gen_dir/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_types.m.js" ]
}
extra_deps = [ ":modulize" ]
@@ -95,7 +97,7 @@ group("polymer3_elements") {
# platforms.
js_library("cr_picture_pane.m") {
sources = []
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [ "$root_gen_dir/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.m.js" ]
}
deps = [
@@ -111,7 +113,7 @@ js_library("cr_picture_pane.m") {
# platforms.
js_library("cr_camera.m") {
sources = []
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [ "$root_gen_dir/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.m.js" ]
}
deps = [ ":png.m" ]
@@ -123,7 +125,7 @@ js_library("cr_camera.m") {
# platforms.
js_library("cr_picture_list.m") {
sources = []
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [ "$root_gen_dir/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.m.js" ]
}
deps = [
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 1b14deab74d..22fe07f57bd 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
@@ -325,5 +325,5 @@ Polymer({
return videomode ? cameraLabel : videoLabel;
},
});
-
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
})();
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 6630fd546e0..9ca122210bc 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
@@ -327,3 +327,4 @@ Polymer({
return url + '[0]@2x 2x';
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
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 db3d118cfb5..5f39365ae83 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
@@ -166,3 +166,4 @@ Polymer({
return url;
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/os_cr_elements.gni b/chromium/ui/webui/resources/cr_elements/chromeos/os_cr_elements.gni
index d8068b19601..b9c7dba0c96 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/os_cr_elements.gni
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/os_cr_elements.gni
@@ -7,6 +7,7 @@ import("//third_party/closure_compiler/compile_js.gni")
cr_elements_chromeos_namespace_rewrites = [
"cr.png.convertImageSequenceToPng|convertImageSequenceToPng",
"cr.png.isEncodedPngDataUrlAnimated|isEncodedPngDataUrlAnimated",
+ "cr.ui.Action|Action",
]
cr_elements_chromeos_auto_imports = [
diff --git a/chromium/ui/webui/resources/cr_elements/cr_action_menu/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_action_menu/BUILD.gn
index a9f68f48686..bed5943f049 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_action_menu/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_action_menu/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_action_menu" ]
}
@@ -13,6 +14,7 @@ js_library("cr_action_menu") {
deps = [
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:util",
+ "//ui/webui/resources/js/cr/ui:focus_outline_manager",
"//ui/webui/resources/js/cr/ui:focus_row",
"//ui/webui/resources/js/cr/ui:focus_without_ink",
]
@@ -31,6 +33,7 @@ polymer_modulizer("cr_action_menu") {
"ui/webui/resources/html/polymer.html|dom,html,Polymer",
"ui/webui/resources/html/assert.html|assert",
"ui/webui/resources/html/cr.html|isMac, isWindows",
+ "ui/webui/resources/html/cr/ui/focus_outline_manager.html|FocusOutlineManager",
"ui/webui/resources/html/cr/ui/focus_row.html|FocusRow",
"ui/webui/resources/html/util.html|getDeepActiveElement, hasKeyModifiers",
]
@@ -48,6 +51,7 @@ js_library("cr_action_menu.m") {
"//ui/webui/resources/js:assert.m",
"//ui/webui/resources/js:cr.m",
"//ui/webui/resources/js:util.m",
+ "//ui/webui/resources/js/cr/ui:focus_outline_manager.m",
"//ui/webui/resources/js/cr/ui:focus_row.m",
"//ui/webui/resources/js/cr/ui:focus_without_ink.m",
]
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 c8e1972cf47..e6d1e289a45 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
@@ -2,6 +2,7 @@
<link rel="import" href="../../html/assert.html">
<link rel="import" href="../../html/cr.html">
+<link rel="import" href="../../html/cr/ui/focus_outline_manager.html">
<link rel="import" href="../../html/cr/ui/focus_row.html">
<link rel="import" href="../../html/cr/ui/focus_without_ink.html">
<link rel="import" href="../../html/util.html">
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 22143432f9e..26ec3f46e5c 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 @@ let ShowAtConfig;
/** @const {string} */
const DROPDOWN_ITEM_CLASS = 'dropdown-item';
+/** @const {string} */
+const SELECTABLE_DROPDOWN_ITEM_QUERY =
+ `.${DROPDOWN_ITEM_CLASS}:not([hidden]):not([disabled])`;
+
(function() {
/** @const {number} */
@@ -254,8 +258,8 @@ Polymer({
return;
}
- const query = '.dropdown-item:not([disabled]):not([hidden])';
- const options = Array.from(this.querySelectorAll(query));
+ const options =
+ Array.from(this.querySelectorAll(SELECTABLE_DROPDOWN_ITEM_QUERY));
if (options.length === 0) {
return;
}
@@ -294,8 +298,8 @@ Polymer({
* @private
*/
onMouseover_(e) {
- const query = '.dropdown-item:not([disabled])';
- const item = e.composedPath().find(el => el.matches && el.matches(query));
+ const item = e.composedPath().find(
+ el => el.matches && el.matches(SELECTABLE_DROPDOWN_ITEM_QUERY));
(item || this.$.wrapper).focus();
},
@@ -424,6 +428,19 @@ Polymer({
doc.scrollTop = scrollTop;
doc.scrollLeft = scrollLeft;
this.addListeners_();
+
+ // Focus the first selectable item.
+ const openedByKey = cr.ui.FocusOutlineManager.forDocument(document).visible;
+ if (openedByKey) {
+ const firstSelectableItem =
+ this.querySelector(SELECTABLE_DROPDOWN_ITEM_QUERY);
+ if (firstSelectableItem) {
+ requestAnimationFrame(() => {
+ // Wait for the next animation frame for the dialog to become visible.
+ firstSelectableItem.focus();
+ });
+ }
+ }
},
/** @private */
@@ -507,4 +524,5 @@ Polymer({
}
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
})();
diff --git a/chromium/ui/webui/resources/cr_elements/cr_button/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_button/BUILD.gn
index aa1cc36cf99..7f6dae0aec2 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_button/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_button/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_button" ]
}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_button/cr_button.js b/chromium/ui/webui/resources/cr_elements/cr_button/cr_button.js
index f31d61c3a87..c82e93d0994 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_button/cr_button.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_button/cr_button.js
@@ -207,3 +207,4 @@ Polymer({
return ripple;
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn
index 74c4a13a2b8..f7f9dee0ef1 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_checkbox" ]
}
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 dd96835d470..04709bcfb32 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
@@ -162,3 +162,4 @@ Polymer({
return ripple;
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn
index 930c63c9e85..f80650e6e58 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_dialog" ]
}
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 2e14f41d854..66a36e9747a 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
@@ -71,7 +71,8 @@
:host ::slotted([slot=title]) {
color: var(--cr-primary-text-color);
flex: 1;
- font-size: calc(15 / 13 * 100%);
+ font-family: var(--cr-dialog-font-family, inherit);
+ font-size: var(--cr-dialog-title-font-size, calc(15 / 13 * 100%));
line-height: 1;
padding-bottom: var(--cr-dialog-title-slot-padding-bottom, 16px);
padding-inline-end: var(--cr-dialog-title-slot-padding-end, 20px);
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 aa4bfb6175d..45b68193801 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
@@ -342,3 +342,4 @@ Polymer({
this.$$('.title-container').focus();
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn
index fa80a4450c4..5278be6707c 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_drawer" ]
}
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 0396618c9d7..b11ab231352 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
@@ -145,3 +145,4 @@ Polymer({
this.fire('close');
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_expand_button/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_expand_button/BUILD.gn
index b95011cfb77..c0bc8f39ba2 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_expand_button/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_expand_button/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_expand_button" ]
}
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 6a31d9158e6..af8c2140091 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
@@ -32,9 +32,9 @@ Polymer({
},
/** A11y text descriptor for this control. */
- alt: {
+ ariaLabel: {
type: String,
- observer: 'onAltChange_',
+ observer: 'onAriaLabelChange_',
},
tabIndex: {
@@ -66,10 +66,10 @@ Polymer({
},
/** @private */
- onAltChange_() {
- if (this.alt) {
+ onAriaLabelChange_() {
+ if (this.ariaLabel) {
this.$.icon.removeAttribute('aria-labelledby');
- this.$.icon.setAttribute('aria-label', this.alt);
+ this.$.icon.setAttribute('aria-label', this.ariaLabel);
} else {
this.$.icon.removeAttribute('aria-label');
this.$.icon.setAttribute('aria-labelledby', 'label');
@@ -105,3 +105,4 @@ Polymer({
}
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn
index bf19ba93144..d16e38bb1a2 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_fingerprint_progress_arc" ]
}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js b/chromium/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js
index 347fc7022dd..3425ce28f52 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// #import {CrLottieElement} from '../cr_lottie/cr_lottie.m.js';
-
/** @type {string} */
/* #export */ const FINGEPRINT_TICK_DARK_URL =
'chrome://theme/IDR_FINGERPRINT_COMPLETE_TICK_DARK';
@@ -424,4 +422,5 @@ Polymer({
return this.isComplete_;
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
})();
diff --git a/chromium/ui/webui/resources/cr_elements/cr_icon_button/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_icon_button/BUILD.gn
index fa12081e5ff..ad2d8613851 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_icon_button/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_icon_button/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_icon_button" ]
}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html b/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html
index 31727bd9a17..6e931290d54 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html
@@ -58,6 +58,7 @@
-webkit-mask-position: center;
-webkit-mask-repeat: no-repeat;
-webkit-mask-size: var(--cr-icon-button-icon-size);
+ -webkit-transform: var(--cr-icon-image-transform, none);
background-color: var(--cr-icon-button-fill-color);
height: 100%;
transition: background-color var(--cr-icon-button-transition);
diff --git a/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js b/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js
index efcd199a2ed..d06a35bee1c 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js
@@ -263,3 +263,4 @@ Polymer({
return ripple;
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_input/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_input/BUILD.gn
index c8792942c65..5eebbd6a854 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_input/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_input/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_input" ]
}
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 b12e77a65e0..13d6012b761 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
@@ -81,7 +81,12 @@
form with cr-inputs that can be invalid, this space is also desired
in order to have consistent spacing.
- If spacing is not needed, apply "--cr-input-error-display: none". */
+ If spacing is not needed, apply "--cr-input-error-display: none".
+
+ When grouping cr-inputs horizontally, it might be helpful to set
+ --cr-input-error-white-space to "nowrap" and set a fixed width for
+ each cr-input so that a long error label does not shift the inputs
+ forward. */
color: var(--cr-input-error-color);
display: var(--cr-input-error-display, block);
font-size: var(--cr-form-field-label-font-size);
@@ -89,6 +94,7 @@
line-height: var(--cr-form-field-label-line-height);
margin: 8px 0;
visibility: hidden;
+ white-space: var(--cr-input-error-white-space);
}
:host([invalid]) #error {
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 cd207120b59..1c455bbb1ad 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
@@ -424,4 +424,5 @@ Polymer({
return !this.invalid;
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
})();
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 94fa57a6004..cf34040bf71 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
@@ -55,6 +55,7 @@
color: var(--cr-input-color);
font-family: inherit;
font-size: inherit;
+ font-weight: inherit;
line-height: inherit;
min-height: var(--cr-input-min-height, auto);
outline: none;
@@ -95,7 +96,7 @@
:host([invalid]) #underline,
:host([force-underline]) #underline,
- :host([focused_]:not([readonly])) #underline {
+ :host([focused_]) #underline {
opacity: 1;
transition: opacity 120ms ease-in, width 180ms ease-out;
width: 100%;
diff --git a/chromium/ui/webui/resources/cr_elements/cr_lazy_render/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_lazy_render/BUILD.gn
index f04a480c7bd..6a9231335a7 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_lazy_render/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_lazy_render/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_lazy_render" ]
}
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 b3d2419dcd1..67124f7c885 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
@@ -70,3 +70,4 @@ Polymer({
}
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_link_row/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_link_row/BUILD.gn
index 7e22f871037..a8f9be64378 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_link_row/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_link_row/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_link_row" ]
}
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 e5e41217d31..7b5da7ef4e6 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
@@ -80,8 +80,9 @@
</div>
<slot></slot>
<cr-icon-button id="icon" iron-icon="[[getIcon_(external)]]" role="link"
- aria-roledescription$="[[roleDescription]]" aria-describedby="subLabel"
- aria-labelledby="label" disabled="[[disabled]]"></cr-icon-button>
+ aria-roledescription$="[[roleDescription]]"
+ aria-labelledby="label subLabel" disabled="[[disabled]]">
+ </cr-icon-button>
</template>
<script src="cr_link_row.js"></script>
</dom-module>
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 9f320e23a05..79308b13bf4 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
@@ -83,3 +83,4 @@ Polymer({
return this.external ? 'cr:open-in-new' : 'cr:arrow-right';
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_lottie/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_lottie/BUILD.gn
index d6fac4abfac..3c561858ca9 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_lottie/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_lottie/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_lottie" ]
}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.js b/chromium/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.js
index 58f4216022c..06dd077ebc8 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.js
@@ -273,3 +273,4 @@ Polymer({
}
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js b/chromium/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js
index 7b1254a8a3a..3f2225bc2bf 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js
@@ -46,9 +46,10 @@ export class CrMenuSelector extends HTMLElement {
// If the focus was moved by keyboard and is coming in from a relatedTarget
// that is not within this menu, move the focus to the first menu item. This
// ensures that the first menu item is always the first focused item when
- // focusing into the menu.
+ // focusing into the menu. A null relatedTarget means the focus was moved
+ // from outside the WebContents.
const focusMovedWithKeyboard = this.focusOutlineManager_.visible;
- const focusMovedFromOutside = e.relatedTarget &&
+ const focusMovedFromOutside = e.relatedTarget === null ||
!this.contains(/** @type {!HTMLElement} */ (e.relatedTarget));
if (focusMovedWithKeyboard && focusMovedFromOutside) {
this.getItems_()[0].focus();
diff --git a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn
index 2ae5ef9b050..9090f8c61b6 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [
":cr_profile_avatar_selector",
":cr_profile_avatar_selector_grid",
diff --git a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html
index c8f6922e4f4..7bf7f4a1e7e 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html
@@ -2,13 +2,15 @@
<link rel="import" href="../cr_button/cr_button.html">
<link rel="import" href="../shared_vars_css.html">
+<link rel="import" href="../shared_style_css.html">
<link rel="import" href="../../html/icon.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-tooltip/paper-tooltip.html">;
<link rel="import" href="cr_profile_avatar_selector_grid.html">
<dom-module id="cr-profile-avatar-selector">
<template>
- <style>
+ <style include="cr-shared-style">
:host {
--avatar-size: 96px;
--avatar-spacing: 24px;
@@ -60,15 +62,29 @@
cr-button {
background-size: var(--avatar-size);
}
+
+ paper-tooltip {
+ --paper-tooltip-delay-in: 100ms;
+ --paper-tooltip-duration-in: 100ms;
+ --paper-tooltip-duration-out: 100ms;
+ --paper-tooltip-min-width: none;
+ }
</style>
- <cr-profile-avatar-selector-grid id="avatar-grid"
+ <cr-profile-avatar-selector-grid id="avatar-grid" role="radiogroup"
ignore-modified-key-events="[[ignoreModifiedKeyEvents]]">
<template is="dom-repeat" items="[[avatars]]">
- <cr-button class$="avatar [[getSelectedClass_(item.selected)]]"
- title="[[item.label]]"
+ <cr-button id="[[getAvatarId_(index)]]" aria-label="[[item.label]]"
+ tabindex$="[[getTabIndex_(index, item, tabFocusableAvatar_)]]"
+ class$="avatar [[getSelectedClass_(item, selectedAvatar)]]"
style$="background-image: [[getIconImageSet_(item.url)]]"
- on-click="onAvatarTap_">
+ on-click="onAvatarTap_"
+ role="radio"
+ aria-checked$="[[getCheckedAttribute_(item, selectedAvatar)]]">
</cr-button>
+ <paper-tooltip for="[[getAvatarId_(index)]]"
+ offset="0" fit-to-visible-bounds>
+ [[item.label]]
+ </paper-tooltip>
</template>
</cr-profile-avatar-selector-grid>
</template>
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 96950a03fba..9b7a4e708c0 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
@@ -40,20 +40,85 @@ Polymer({
notify: true,
},
- /** @private {?HTMLElement} */
- selectedAvatarElement_: Object,
-
ignoreModifiedKeyEvents: {
type: Boolean,
value: false,
},
+
+ /**
+ * The currently selected profile avatar icon index, or '-1' if none is
+ * selected.
+ * @type {number}
+ */
+ tabFocusableAvatar_: {
+ type: Number,
+ computed: 'computeTabFocusableAvatar_(avatars, selectedAvatar)',
+ },
+ },
+
+ /**
+ * @param {number} index
+ * @return {string}
+ * @private
+ */
+ getAvatarId_(index) {
+ return 'avatarId' + index;
+ },
+
+ /**
+ * @param {number} index
+ * @param {!AvatarIcon} item
+ * @return {string}
+ * @private
+ */
+ getTabIndex_(index, item) {
+ if (item.index === this.tabFocusableAvatar_) {
+ return '0';
+ }
+
+ // If no avatar is selected, focus the first element of the grid on 'tab'.
+ if (this.tabFocusableAvatar_ === -1 && index === 0) {
+ return '0';
+ }
+ return '-1';
+ },
+
+ /**
+ * @return {number}
+ * @private
+ */
+ computeTabFocusableAvatar_() {
+ const selectedAvatar =
+ this.avatars.find(avatar => this.isAvatarSelected(avatar));
+ return selectedAvatar ? selectedAvatar.index : -1;
},
/** @private */
- getSelectedClass_(isSelected) {
+ getSelectedClass_(avatarItem) {
// TODO(dpapad): Rename 'iron-selected' to 'selected' now that this CSS
// class is not assigned by any iron-* behavior.
- return isSelected ? 'iron-selected' : '';
+ return this.isAvatarSelected(avatarItem) ? 'iron-selected' : '';
+ },
+
+ /**
+ * @param {AvatarIcon} avatarItem
+ * @return {string}
+ * @private
+ */
+ getCheckedAttribute_(avatarItem) {
+ return this.isAvatarSelected(avatarItem) ? 'true' : 'false';
+ },
+
+ /**
+ * @param {AvatarIcon} avatarItem
+ * @return {boolean}
+ * @private
+ */
+ isAvatarSelected(avatarItem) {
+ return !!avatarItem &&
+ (avatarItem.selected ||
+ (!!this.selectedAvatar &&
+ this.selectedAvatar.index === avatarItem.index));
},
/**
@@ -70,16 +135,10 @@ Polymer({
* @private
*/
onAvatarTap_(e) {
- // Manual selection for profile creation
- if (this.selectedAvatarElement_) {
- this.selectedAvatarElement_.classList.remove('iron-selected');
- }
- this.selectedAvatarElement_ = /** @type {!HTMLElement} */ (e.target);
- this.selectedAvatarElement_.classList.add('iron-selected');
-
// |selectedAvatar| is set to pass back selection to the owner of this
// component.
this.selectedAvatar =
/** @type {!{model: {item: !AvatarIcon}}} */ (e).model.item;
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
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 bc9417b1486..5e223742c5c 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
@@ -95,3 +95,4 @@ Polymer({
assert(this.parentNode.activeElement === nextItem);
}
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn
index cdfd3e6b911..66890945890 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn
@@ -7,6 +7,7 @@ import("//tools/polymer/polymer.gni")
import("../../tools/js_modulizer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [
":cr_card_radio_button",
":cr_radio_button",
diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_card_radio_button.html b/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_card_radio_button.html
index 68f46000969..7b27e3b2d48 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_card_radio_button.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_card_radio_button.html
@@ -18,6 +18,13 @@
width: var(--cr-card-radio-button-width, 200px);
}
+ /* TODO(crbug/1148515): Reenable the ripple effect after fixing
+ * paper-ripple to accomodate for cr-card-radio-button.
+ */
+ paper-ripple {
+ --paper-ripple-opacity: 0;
+ }
+
:host([checked]) {
border-color: var(--cr-checked-color);
}
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 245b9262d6e..047b8f04e89 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
@@ -144,3 +144,4 @@ const CrRadioButtonBehaviorImpl = {
Polymer.PaperRippleBehavior,
CrRadioButtonBehaviorImpl,
];
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn
index 0485ad82569..b1805b291b7 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_radio_group" ]
}
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 7def963811c..1db5848958e 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
@@ -7,6 +7,7 @@ import("//tools/polymer/polymer.gni")
import("../../tools/js_modulizer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [
":cr_search_field",
":cr_search_field_behavior",
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 99ec7838878..a38bfd2059c 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
@@ -171,3 +171,4 @@
onSearchTermInput() {}
}
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn
index 0eafe64caa9..ce8dfdcbb55 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_searchable_drop_down" ]
}
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 06823f7b8f6..ff4fc193902 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
@@ -119,15 +119,23 @@ Polymer({
/** @private {number} */
openDropdownTimeoutId_: 0,
+ /** @private {?ResizeObserver} */
+ resizeObserver_: null,
+
/** @override */
attached() {
this.pointerDownListener_ = this.onPointerDown_.bind(this);
document.addEventListener('pointerdown', this.pointerDownListener_);
+ this.resizeObserver_ = new ResizeObserver(() => {
+ this.resizeDropdown_();
+ });
+ this.resizeObserver_.observe(this.$.search);
},
/** @override */
detached() {
document.removeEventListener('pointerdown', this.pointerDownListener_);
+ this.resizeObserver_.unobserve(this.$.search);
},
/**
@@ -145,6 +153,19 @@ Polymer({
}
},
+ /**
+ * Keeps the dropdown from expanding beyond the width of the search input when
+ * its width is specified as a percentage.
+ * @private
+ */
+ resizeDropdown_() {
+ const dropdown = this.$$('iron-dropdown').containedElement;
+ const dropdownWidth =
+ Math.max(dropdown.offsetWidth, this.$.search.offsetWidth);
+ dropdown.style.width = `${dropdownWidth}px`;
+ this.enqueueDropdownRefit_();
+ },
+
/** @private */
openDropdown_() {
this.$$('iron-dropdown').open();
@@ -439,7 +460,7 @@ Polymer({
* leave the user's text in the dropdown search bar when focus is changed.
* @private
*/
- onBlur_ : function () {
+ onBlur_() {
if (!this.updateValueOnInput) {
this.$.search.value = this.value;
}
@@ -453,8 +474,9 @@ Polymer({
* |invalid| to false.
* @private
*/
- updateInvalid_: function () {
+ updateInvalid_() {
this.invalid =
!this.updateValueOnInput && (this.value !== this.$.search.value);
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_slider/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_slider/BUILD.gn
index 1229cf7b414..232786c9f74 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_slider/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_slider/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_slider" ]
}
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 4d77f318a6e..2b0235e78d5 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
@@ -470,6 +470,7 @@ cr.define('cr_slider', function() {
});
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
SliderTick: SliderTick,
};
diff --git a/chromium/ui/webui/resources/cr_elements/cr_tabs/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_tabs/BUILD.gn
index ab8059dddfa..bd113ea3595 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_tabs/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_tabs/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_tabs" ]
}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.js b/chromium/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.js
index b0b555eb326..677c21b5671 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.js
@@ -190,3 +190,4 @@ Polymer({
this.updateSelectionBar_(left, right - left);
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn
index a29159d168d..af927112ecd 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [
":cr_toast",
":cr_toast_manager",
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 97b4d555467..c2cc82043ad 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
@@ -38,7 +38,7 @@ Polymer({
if (this.open && this.duration !== 0) {
this.hideTimeoutId_ = window.setTimeout(() => {
- this._setOpen(false);
+ this.hide();
}, this.duration);
}
},
@@ -59,6 +59,10 @@ Polymer({
// the same as a previous toast.
this.removeAttribute('role');
+ // Reset the aria-hidden attribute as screen readers need to access the
+ // contents of an opened toast.
+ this.removeAttribute('aria-hidden');
+
this._setOpen(true);
this.setAttribute('role', 'alert');
@@ -67,8 +71,13 @@ Polymer({
}
},
- /** Hides the toast. */
+ /**
+ * Hides the toast and ensures that screen readers cannot its contents while
+ * hidden.
+ */
hide() {
+ this.setAttribute('aria-hidden', 'true');
this._setOpen(false);
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js
index 53009cdffbf..acc9637ba09 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js
@@ -102,6 +102,7 @@ cr.define('cr.toastManager', () => {
});
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
getToastManager: getToastManager,
};
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn
index 07edfe5313c..fa5439ec42d 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_toggle" ]
}
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 f86716c8efb..ea32e2b2632 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
@@ -227,3 +227,4 @@ Polymer({
return ripple;
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn
index 7d0f4a7203e..1f168042f4f 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn
@@ -6,11 +6,8 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
- deps = [
- ":cr_toolbar",
- ":cr_toolbar_search_field",
- ":cr_toolbar_selection_overlay",
- ]
+ uses_legacy_modules = true
+ deps = [ ":cr_toolbar_search_field" ]
}
js_library("cr_toolbar_search_field") {
@@ -19,13 +16,6 @@ js_library("cr_toolbar_search_field") {
]
}
-js_library("cr_toolbar_selection_overlay") {
-}
-
-js_library("cr_toolbar") {
- deps = [ ":cr_toolbar_search_field" ]
-}
-
group("polymer3_elements") {
public_deps = [
":cr_toolbar_module",
@@ -37,8 +27,7 @@ group("polymer3_elements") {
polymer_modulizer("cr_toolbar") {
js_file = "cr_toolbar.js"
html_file = "cr_toolbar.html"
- html_type = "dom-module"
- auto_imports = [ "ui/webui/resources/html/polymer.html|html,Polymer" ]
+ html_type = "v3-ready"
}
polymer_modulizer("cr_toolbar_search_field") {
@@ -51,27 +40,23 @@ polymer_modulizer("cr_toolbar_search_field") {
polymer_modulizer("cr_toolbar_selection_overlay") {
js_file = "cr_toolbar_selection_overlay.js"
html_file = "cr_toolbar_selection_overlay.html"
- html_type = "dom-module"
+ html_type = "v3-ready"
}
js_type_check("closure_compile_module") {
is_polymer3 = true
deps = [
- ":cr_toolbar.m",
+ ":cr_toolbar",
":cr_toolbar_search_field.m",
- ":cr_toolbar_selection_overlay.m",
+ ":cr_toolbar_selection_overlay",
]
}
-js_library("cr_toolbar.m") {
- sources = [
- "$root_gen_dir/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.m.js",
- ]
+js_library("cr_toolbar") {
deps = [
":cr_toolbar_search_field.m",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
]
- extra_deps = [ ":cr_toolbar_module" ]
}
js_library("cr_toolbar_search_field.m") {
@@ -83,10 +68,9 @@ js_library("cr_toolbar_search_field.m") {
extra_deps = [ ":cr_toolbar_search_field_module" ]
}
-js_library("cr_toolbar_selection_overlay.m") {
- sources = [ "$root_gen_dir/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.m.js" ]
+js_library("cr_toolbar_selection_overlay") {
deps = [
+ "//third_party/polymer/v3_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
]
- extra_deps = [ ":cr_toolbar_selection_overlay_module" ]
}
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 98231ed6793..2470260a4b5 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
@@ -1,15 +1,3 @@
-<link rel="import" href="../../html/polymer.html">
-
-<link rel="import" href="../cr_icon_button/cr_icon_button.html">
-<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="../icons.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">
-
-<dom-module id="cr-toolbar">
- <template>
<style include="cr-icons cr-hidden-style">
:host {
align-items: center;
@@ -135,6 +123,3 @@
<slot></slot>
</div>
</div>
- </template>
- <script src="cr_toolbar.js"></script>
-</dom-module>
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js
index 46af1382867..f949fa1c2b0 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js
@@ -2,9 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import {html, Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import '../cr_icon_button/cr_icon_button.m.js';
+import '../cr_icons_css.m.js';
+import './cr_toolbar_search_field.m.js';
+import '../hidden_style_css.m.js';
+import '../icons.m.js';
+import '../shared_vars_css.m.js';
+import '//resources/polymer/v3_0/iron-media-query/iron-media-query.js';
+
Polymer({
is: 'cr-toolbar',
+ _template: html`{__html_template__}`,
+
properties: {
// Name to display in the toolbar, in titlecase.
pageName: String,
@@ -69,4 +81,20 @@ Polymer({
this.fire('cr-toolbar-menu-tap');
},
+ focusMenuButton() {
+ requestAnimationFrame(() => {
+ // Wait for next animation frame in case dom-if has not applied yet and
+ // added the menu button.
+ const menuButton = this.shadowRoot.querySelector('#menuButton');
+ if (menuButton) {
+ menuButton.focus();
+ }
+ });
+ },
+
+ /** @return {boolean} */
+ isMenuFocused() {
+ return Boolean(this.shadowRoot.activeElement) &&
+ this.shadowRoot.activeElement.id === 'menuButton';
+ }
});
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 27a5c19e4ab..09d53868d35 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
@@ -183,6 +183,7 @@
<label id="prompt" for="searchInput" aria-hidden="true">[[label]]</label>
<input id="searchInput"
aria-labelledby="prompt"
+ autocapitalize="off"
autocomplete="off"
type="search"
on-input="onSearchTermInput"
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 28243f0a16f..2cd069ff2f4 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
@@ -1,12 +1,3 @@
-<link rel="import" href="../../html/polymer.html">
-
-<link rel="import" href="../cr_button/cr_button.html">
-<link rel="import" href="../cr_icon_button/cr_icon_button.html">
-<link rel="import" href="../icons.html">
-<link rel="import" href="../shared_vars_css.html">
-
-<dom-module id="cr-toolbar-selection-overlay">
- <template>
<style>
:host {
background-color: white;
@@ -78,6 +69,3 @@
</cr-button>
</div>
</template>
- </template>
- <script src="cr_toolbar_selection_overlay.js"></script>
-</dom-module>
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 7a93044f0c2..280f185f5a2 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
@@ -13,9 +13,19 @@
* tab-traversal.
*/
+import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {IronA11yAnnouncer} from '//resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
+import '../cr_button/cr_button.m.js';
+import '../cr_icon_button/cr_icon_button.m.js';
+import '../icons.m.js';
+import '../shared_vars_css.m.js';
+
Polymer({
is: 'cr-toolbar-selection-overlay',
+ _template: html`{__html_template__}`,
+
properties: {
show: {
type: Boolean,
@@ -42,6 +52,10 @@ Polymer({
'updateSelectionLabel_(show, selectionLabel)',
],
+ hostAttributes: {
+ 'role': 'toolbar',
+ },
+
/** @return {HTMLElement} */
get deleteButton() {
return /** @type {HTMLElement} */ (this.$$('#delete'));
@@ -64,6 +78,10 @@ Polymer({
this.debounce('updateSelectionLabel_', () => {
this.selectionLabel_ =
this.show ? this.selectionLabel : this.selectionLabel_;
+ this.setAttribute('aria-label', this.selectionLabel_);
+
+ IronA11yAnnouncer.requestAvailability();
+ this.fire('iron-announce', {text: this.selectionLabel});
});
},
diff --git a/chromium/ui/webui/resources/cr_elements/cr_view_manager/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_view_manager/BUILD.gn
index 8e2ab87baa3..14130ea192c 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_view_manager/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_view_manager/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [ ":cr_view_manager" ]
}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_view_manager/cr_view_manager.js b/chromium/ui/webui/resources/cr_elements/cr_view_manager/cr_view_manager.js
index ec1f2009cbc..10633d899f5 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_view_manager/cr_view_manager.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_view_manager/cr_view_manager.js
@@ -114,4 +114,5 @@ Polymer({
return Promise.all(promises);
},
});
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
})();
diff --git a/chromium/ui/webui/resources/cr_elements/icons.html b/chromium/ui/webui/resources/cr_elements/icons.html
index a19c7bd7904..0d46919254f 100644
--- a/chromium/ui/webui/resources/cr_elements/icons.html
+++ b/chromium/ui/webui/resources/cr_elements/icons.html
@@ -87,6 +87,10 @@ blurry at 20 px). Please use 20 px icons when available.
d="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z">
</path>
</g>
+ <g id="work">
+ <path d="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z">
+ </path>
+ </g>
</if>
<g id="cancel">
<path
diff --git a/chromium/ui/webui/resources/cr_elements/mwb_shared_style.html b/chromium/ui/webui/resources/cr_elements/mwb_shared_style.html
index 0ad5679bedb..0dc24281c8e 100644
--- a/chromium/ui/webui/resources/cr_elements/mwb_shared_style.html
+++ b/chromium/ui/webui/resources/cr_elements/mwb_shared_style.html
@@ -1,32 +1,19 @@
<template>
<style>
::-webkit-scrollbar-thumb {
- background: var(--google-grey-refresh-300);
- }
-
- /* TODO(crbug.com/1110109): Add WCAG compliant dark mode support. */
- @media (prefers-color-scheme: dark) {
- ::-webkit-scrollbar-thumb {
- background: var(--google-grey-refresh-500);
- }
+ background-color: var(--mwb-scrollbar-thumb-color);
}
::-webkit-scrollbar-thumb:hover {
- background: var(--google-grey-refresh-500);
- }
-
- @media (prefers-color-scheme: dark) {
- ::-webkit-scrollbar-thumb:hover {
- background: var(--google-grey-refresh-300);
- }
+ background-color: var(--mwb-scrollbar-thumb-hover-color);
}
::-webkit-scrollbar-track {
- background: var(--mwb-background-color);
+ background-color: var(--mwb-scrollbar-track-color);
}
::-webkit-scrollbar {
- width: 4px;
+ width: var(--mwb-scrollbar-width);
}
.mwb-list-item {
diff --git a/chromium/ui/webui/resources/cr_elements/mwb_shared_vars.html b/chromium/ui/webui/resources/cr_elements/mwb_shared_vars.html
index b83244d4024..31a4ca151c4 100644
--- a/chromium/ui/webui/resources/cr_elements/mwb_shared_vars.html
+++ b/chromium/ui/webui/resources/cr_elements/mwb_shared_vars.html
@@ -2,20 +2,31 @@
<style>
html {
--mwb-background-color: white;
+ --mwb-icon-button-fill-color: var(--google-grey-refresh-700);
+ --mwb-icon-button-focus-ring-color: rgba(var(--google-blue-600-rgb), 0.4);
+ --mwb-icon-button-hover-background-color: rgba(var(--google-grey-900-rgb), 0.1);
--mwb-icon-size: 16px;
--mwb-item-height: 56px;
--mwb-list-item-horizontal-margin: 16px;
--mwb-list-item-hover-background-color: rgba(var(--google-grey-900-rgb), 0.1);
--mwb-list-item-selected-background-color: rgba(var(--google-grey-900-rgb), 0.14);
--mwb-primary-text-font-size: 13px;
+ --mwb-scrollbar-thumb-color: var(--google-grey-refresh-300);
+ --mwb-scrollbar-thumb-hover-color: var(--google-grey-refresh-500);
+ --mwb-scrollbar-track-color: var(--mwb-background-color);
+ --mwb-scrollbar-width: 4px;
--mwb-secondary-text-font-size: 12px;
}
@media (prefers-color-scheme: dark) {
html {
--mwb-background-color: var(--google-grey-900);
+ --mwb-icon-button-fill-color: var(--google-grey-refresh-300);
+ --mwb-icon-button-hover-background-color: rgba(255, 255, 255, 0.1);
--mwb-list-item-hover-background-color: rgb(55, 56, 58); /* #37383a */
--mwb-list-item-selected-background-color: rgb(68, 69, 71); /* #444547 */
+ --mwb-scrollbar-thumb-color: var(--google-grey-refresh-500);
+ --mwb-scrollbar-thumb-hover-color: var(--google-grey-refresh-300);
}
}
</style>
diff --git a/chromium/ui/webui/resources/cr_elements/policy/BUILD.gn b/chromium/ui/webui/resources/cr_elements/policy/BUILD.gn
index 0e61e9f13cc..63950e4423c 100644
--- a/chromium/ui/webui/resources/cr_elements/policy/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/policy/BUILD.gn
@@ -7,6 +7,7 @@ import("//tools/polymer/polymer.gni")
import("../../tools/js_modulizer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [
":cr_policy_indicator",
":cr_policy_indicator_behavior",
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 626549dd852..7f1e85363aa 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
@@ -159,3 +159,4 @@ var CrPolicyStrings;
return '';
},
};
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html b/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html
index 23962b2144f..21447b7dd55 100644
--- a/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html
+++ b/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html
@@ -19,7 +19,7 @@
}
</style>
<iron-icon id="indicator" tabindex="0" aria-label$="[[iconAriaLabel]]"
- aria-describedby="tooltip" icon="[[iconClass]]"></iron-icon>
+ aria-describedby="tooltip" icon="[[iconClass]]" role="img"></iron-icon>
<paper-tooltip id="tooltip"
for="indicator" position="[[tooltipPosition]]"
fit-to-visible-bounds part="tooltip">
diff --git a/chromium/ui/webui/resources/cr_elements/shared_style_css.html b/chromium/ui/webui/resources/cr_elements/shared_style_css.html
index e5f836283c7..a71eec20481 100644
--- a/chromium/ui/webui/resources/cr_elements/shared_style_css.html
+++ b/chromium/ui/webui/resources/cr_elements/shared_style_css.html
@@ -158,6 +158,29 @@
line-height: var(--cr-form-field-label-line-height);
margin-bottom: 8px;
}
+
+ .cr-vertical-tab {
+ align-items: center;
+ display: flex;
+ }
+
+ .cr-vertical-tab::before {
+ border-radius: 0 3px 3px 0;
+ content: '';
+ display: block;
+ flex-shrink: 0;
+ height: var(--cr-vertical-tab-height, 100%);
+ width: 4px;
+ }
+
+ .cr-vertical-tab.selected::before {
+ background: var(--cr-vertical-tab-selected-color, var(--cr-checked-color));
+ }
+
+ :host-context([dir=rtl]) .cr-vertical-tab::before {
+ /* Border-radius based on block/inline is not yet supported. */
+ transform: scaleX(-1);
+ }
</style>
</template>
</dom-module>
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 df1e1f42726..4e7eb2ad96d 100644
--- a/chromium/ui/webui/resources/cr_elements/shared_vars_css.html
+++ b/chromium/ui/webui/resources/cr_elements/shared_vars_css.html
@@ -152,7 +152,6 @@
* items etc. */
--cr-section-min-height: 48px;
--cr-section-two-line-min-height: 64px;
- --cr-section-three-line-min-height: 84px;
--cr-section-padding: 20px;
--cr-section-vertical-padding: 12px;
diff --git a/chromium/ui/webui/resources/cr_elements_images.grdp b/chromium/ui/webui/resources/cr_elements_images.grdp
deleted file mode 100644
index 61a8eab915c..00000000000
--- a/chromium/ui/webui/resources/cr_elements_images.grdp
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<grit-part>
- <!-- TODO(dschuyler): Many of these may be included for the unit tests which
- don't appear to flatten the html. We may be able to avoid including
- these if the browser_tests would not try to load them. -->
- <include name="IDR_WEBUI_IMAGES_200_LOGO_GOOGLE_G_PNG"
- file="images/200-logo_googleg.png" type="BINDATA" compress="gzip" />
- <include name="IDR_WEBUI_IMAGES_ARROW_DOWN_SVG"
- file="images/arrow_down.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ARROW_RIGHT_SVG"
- file="images/arrow_right.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_BUSINESS" file="images/business.svg"
- type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_DARK_ARROW_DOWN_SVG"
- file="images/dark/arrow_down.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_DARK_ICON_SEARCH_SVG"
- file="images/dark/icon_search.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_ARROW_BACK_SVG"
- file="images/icon_arrow_back.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_ARROW_DROPDOWN_SVG"
- file="images/icon_arrow_dropdown.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_CANCEL_SVG"
- file="images/icon_cancel.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_CLEAR_SVG"
- file="images/icon_clear.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_DELETE_GRAY_SVG"
- file="images/icon_delete_gray.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_EDIT_SVG"
- file="images/icon_edit.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_EXPAND_LESS_SVG"
- file="images/icon_expand_less.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_EXPAND_MORE_SVG"
- file="images/icon_expand_more.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_EXTERNAL_SVG"
- file="images/open_in_new.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_MORE_VERT_SVG"
- file="images/icon_more_vert.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_PICTURE_DELETE_SVG"
- file="images/icon_picture_delete.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_REFRESH_SVG"
- file="images/icon_refresh.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_SEARCH_SVG"
- file="images/icon_search.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_SETTINGS_SVG"
- file="images/icon_settings.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_VISIBILITY_SVG"
- file="images/icon_visibility.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_VISIBILITY_OFF_SVG"
- file="images/icon_visibility_off.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ICON_COPY_CONTENT_SVG"
- file="images/icon_copy_content.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_OPEN_IN_NEW_SVG"
- file="images/open_in_new.svg" type="BINDATA" />
-</grit-part>
diff --git a/chromium/ui/webui/resources/css/BUILD.gn b/chromium/ui/webui/resources/css/BUILD.gn
index 755e164eae6..28641746bce 100644
--- a/chromium/ui/webui/resources/css/BUILD.gn
+++ b/chromium/ui/webui/resources/css/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//tools/grit/preprocess_grit.gni")
+import("//tools/grit/preprocess_if_expr.gni")
import("//ui/webui/resources/tools/generate_grd.gni")
include_polymer = !is_android && !is_ios
@@ -18,7 +18,7 @@ generate_grd("build_grdp") {
resource_path_prefix = "css"
}
-preprocess_grit("preprocess_src") {
+preprocess_if_expr("preprocess_src") {
in_folder = "./"
out_folder = "$preprocess_folder"
out_manifest = "$target_gen_dir/$preprocess_src_manifest"
@@ -26,8 +26,6 @@ preprocess_grit("preprocess_src") {
"action_link.css",
"apps/common.css",
"apps/topbutton_bar.css",
- "bubble_button.css",
- "bubble.css",
"butter_bar.css",
"chrome_shared.css",
"dialogs.css",
diff --git a/chromium/ui/webui/resources/css/bubble.css b/chromium/ui/webui/resources/css/bubble.css
deleted file mode 100644
index cf76818ac07..00000000000
--- a/chromium/ui/webui/resources/css/bubble.css
+++ /dev/null
@@ -1,97 +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. */
-
-.bubble {
- position: absolute;
- white-space: normal;
- /* Height is dynamic, width fixed. */
- width: 300px;
- z-index: 9999;
-}
-
-.bubble-content {
- color: black;
- line-height: 150%;
- margin: 1px;
- padding: 8px 11px 12px;
- position: relative;
- z-index: 3;
-}
-
-/* When the close button is there, we need more padding on the right of the
- * bubble. */
-.bubble-close:not([hidden]) ~ .bubble-content {
- padding-inline-end: 22px;
-}
-
-.bubble-close {
- height: 16px;
- position: absolute;
- right: 6px;
- top: 6px;
- width: 16px;
- z-index: 4;
-}
-
-html[dir='rtl'] .bubble-close {
- left: 6px;
- right: auto;
-}
-
-.bubble-close {
- background-image: -webkit-image-set(
- url(../../../resources/default_100_percent/close_2.png) 1x,
- url(../../../resources/default_200_percent/close_2.png) 2x);
-}
-
-.bubble-close:hover {
- background-image: -webkit-image-set(
- url(../../../resources/default_100_percent/close_2_hover.png) 1x,
- url(../../../resources/default_200_percent/close_2_hover.png) 2x);
-}
-
-.bubble-close:active {
- background-image: -webkit-image-set(
- url(../../../resources/default_100_percent/close_2_pressed.png) 1x,
- url(../../../resources/default_200_percent/close_2_pressed.png) 2x);
-}
-
-.bubble-shadow {
- bottom: 0;
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
- left: 0;
- position: absolute;
- right: 0;
- top: 0;
- z-index: 1;
-}
-
-.bubble-arrow {
- box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.15);
- height: 15px;
- position: absolute;
- transform: rotate(45deg);
- width: 15px;
- z-index: 2;
-}
-
-.bubble-content,
-.bubble-arrow {
- background: white;
-}
-
-.bubble-shadow,
-.bubble-arrow {
- border: 1px solid rgba(0, 0, 0, 0.3);
-}
-
-.bubble-shadow,
-.bubble-content {
- border-radius: 6px;
- box-sizing: border-box;
-}
-
-.auto-close-bubble {
- position: fixed;
-}
diff --git a/chromium/ui/webui/resources/css/bubble_button.css b/chromium/ui/webui/resources/css/bubble_button.css
deleted file mode 100644
index d92c4a58cec..00000000000
--- a/chromium/ui/webui/resources/css/bubble_button.css
+++ /dev/null
@@ -1,20 +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. */
-
-.bubble-button {
- display: inline-block;
- height: 0;
- line-height: 1;
- margin-inline-start: 4px;
- vertical-align: middle;
- width: 16px;
-}
-
-.bubble-button > div {
- background-size: 16px;
- height: 16px;
- position: relative;
- top: -9px;
- width: 16px;
-}
diff --git a/chromium/ui/webui/resources/css/controlled_indicator.css b/chromium/ui/webui/resources/css/controlled_indicator.css
deleted file mode 100644
index 340ac931baa..00000000000
--- a/chromium/ui/webui/resources/css/controlled_indicator.css
+++ /dev/null
@@ -1,100 +0,0 @@
-/* Copyright 2013 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-/* Controlled setting indicator and bubble. */
-
-.controlled-setting-with-label input:disabled + span {
- color: #999;
-}
-
-.controlled-setting-indicator {
- margin-inline-end: 0.3em;
-}
-
-.controlled-setting-indicator:not([controlled-by]) {
- display: none;
-}
-
-.controlled-setting-indicator[controlled-by] > div {
- background-position: 50%;
- background-size: 18px;
-}
-
-.controlled-setting-indicator:-webkit-any([controlled-by='recommended'],
- [controlled-by='hasRecommendation']) > div,
- .controlled-setting-indicator[controlled-by='policy'] > div {
- background-image: url(../images/business.svg);
-}
-
-.controlled-setting-indicator[controlled-by='owner'] > div {
- background-image: url(../images/account_circle.svg);
-}
-
-.controlled-setting-indicator[controlled-by='extension'] > div {
- background-image: url(../images/extension.svg);
-}
-
-<if expr="chromeos">
-.controlled-setting-indicator[controlled-by='shared'] > div {
- background-image: url(../images/group.svg);
-}
-</if>
-
-.controlled-setting-indicator[controlled-by='child-custodian'] > div {
- background-image: url(../images/account_child_invert.svg);
-}
-
-.controlled-setting-indicator[controlled-by='supervised-user-custodian'] > div {
- background-image: url(../images/supervisor_account.svg);
-}
-
-.controlled-setting-bubble-action {
- padding: 0 !important;
-}
-
-.controlled-setting-bubble-header {
- margin-top: 3px;
-}
-
-.controlled-setting-bubble-content-row {
- height: 35px;
- position: relative;
-}
-
-.controlled-setting-bubble-extension-name {
- background-repeat: no-repeat;
- font-weight: bold;
- height: 24px;
- margin-top: -9px;
- overflow: hidden;
- padding-inline-start: 30px;
- padding-top: 3px;
- position: absolute;
- text-overflow: ellipsis;
- top: 50%;
- white-space: nowrap;
- width: 215px;
-}
-
-html[dir='rtl'] .controlled-setting-bubble-extension-name {
- background-position: right top;
-}
-
-.controlled-setting-bubble-extension-manage-link {
- margin-left: -0.35em;
- margin-top: -0.30em;
- position: absolute;
- top: 50%;
-}
-
-.controlled-setting-bubble-extension-disable-button {
- bottom: 0;
- position: absolute;
- right: 0;
-}
-
-html[dir='rtl'] .controlled-setting-bubble-extension-disable-button {
- left: 0;
- right: auto;
-}
diff --git a/chromium/ui/webui/resources/html/BUILD.gn b/chromium/ui/webui/resources/html/BUILD.gn
index c1eff1165a7..5ae61e89f5a 100644
--- a/chromium/ui/webui/resources/html/BUILD.gn
+++ b/chromium/ui/webui/resources/html/BUILD.gn
@@ -32,7 +32,6 @@ generate_grd("build_grdp") {
"cr/ui/menu_button.html",
"cr/ui/menu.html",
"cr/ui/menu_item.html",
- "cr/ui/overlay.html",
"cr/ui/position_util.html",
"cr/ui/splitter.html",
"cr/ui/store_client.html",
diff --git a/chromium/ui/webui/resources/html/cr/ui/overlay.html b/chromium/ui/webui/resources/html/cr/ui/overlay.html
deleted file mode 100644
index 5251684beab..00000000000
--- a/chromium/ui/webui/resources/html/cr/ui/overlay.html
+++ /dev/null
@@ -1 +0,0 @@
-<script src="../../../js/cr/ui/overlay.js"></script>
diff --git a/chromium/ui/webui/resources/html/test_loader.html b/chromium/ui/webui/resources/html/test_loader.html
index 4aeb21f85a6..9eb3d485e7e 100644
--- a/chromium/ui/webui/resources/html/test_loader.html
+++ b/chromium/ui/webui/resources/html/test_loader.html
@@ -1,7 +1,9 @@
<!DOCTYPE html>
<html>
<body>
- <script src="test_loader.js"></script>
+ <script src="chrome://test/mocha.js"></script>
+ <script src="chrome://test/mocha_adapter.js"></script>
+ <script type="module" src="test_loader.js"></script>
</body>
</html>
diff --git a/chromium/ui/webui/resources/images/BUILD.gn b/chromium/ui/webui/resources/images/BUILD.gn
new file mode 100644
index 00000000000..0cc5a5bdfbc
--- /dev/null
+++ b/chromium/ui/webui/resources/images/BUILD.gn
@@ -0,0 +1,77 @@
+# Copyright 2020 The Chromium 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/chromeos/ui_mode.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
+
+generate_grd("build_grdp") {
+ grd_prefix = "webui_images"
+ out_grd = "$target_gen_dir/resources.grdp"
+ input_files_base_dir = rebase_path(".", "//")
+ input_files = [
+ # Component apps common image resources - 1x
+ "apps/topbar_button_close.png",
+ "apps/topbar_button_maximize.png",
+ "apps/topbar_button_minimize.png",
+
+ # Component apps common image resources - 2x
+ "2x/apps/topbar_button_close.png",
+ "2x/apps/topbar_button_maximize.png",
+ "2x/apps/topbar_button_minimize.png",
+
+ # Non-apps images
+ "add.svg",
+ "cancel_red.svg",
+ "check_circle_green.svg",
+ "check.png",
+ "checkbox_black.png",
+ "checkbox_white.png",
+ "disabled_select.png",
+ "error.svg",
+ "icon_search.svg",
+ "icon_refresh.svg",
+ "select.png",
+ "throbber_medium.svg",
+ "throbber_small.svg",
+ ]
+
+ if (!is_android && !is_ios) {
+ input_files += [
+ "200-logo_googleg.png",
+ "arrow_down.svg",
+ "arrow_right.svg",
+ "business.svg",
+ "dark/arrow_down.svg",
+ "dark/icon_search.svg",
+ "icon_arrow_back.svg",
+ "icon_arrow_dropdown.svg",
+ "icon_cancel.svg",
+ "icon_clear.svg",
+ "icon_copy_content.svg",
+ "icon_delete_gray.svg",
+ "icon_edit.svg",
+ "icon_expand_less.svg",
+ "icon_expand_more.svg",
+ "icon_more_vert.svg",
+ "icon_picture_delete.svg",
+ "icon_settings.svg",
+ "icon_visibility_off.svg",
+ "icon_visibility.svg",
+ "open_in_new.svg",
+ ]
+ }
+
+ if (is_chromeos_ash) {
+ input_files += [
+ # Similar to error.svg except that it is white-filled instead of
+ # transparent-filled. Useful for badging images where the background may
+ # be red.
+ # TODO(dpapad) Move to
+ # chrome/browser/resources/settings/chromeos/os_people_page/, only used
+ # there.
+ "error_badge.svg",
+ ]
+ }
+ resource_path_prefix = "images"
+}
diff --git a/chromium/ui/webui/resources/images/icon_tabs.svg b/chromium/ui/webui/resources/images/icon_tabs.svg
deleted file mode 100644
index ad673608b68..00000000000
--- a/chromium/ui/webui/resources/images/icon_tabs.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M0 0h24v24H0V0z"/><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13zM6 4h5v16H6V4zm5 7h7v9h-7v-9z" fill="#000"/></g></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/menu.svg b/chromium/ui/webui/resources/images/menu.svg
deleted file mode 100644
index fc0da0efe53..00000000000
--- a/chromium/ui/webui/resources/images/menu.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#5F6368"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/images/supervisor_account.svg b/chromium/ui/webui/resources/images/supervisor_account.svg
deleted file mode 100644
index 4d933d14849..00000000000
--- a/chromium/ui/webui/resources/images/supervisor_account.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="#626262"><path d="M0 0h48v48H0z" fill="none"/><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"/></svg> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/js/BUILD.gn b/chromium/ui/webui/resources/js/BUILD.gn
index 597d8f7e369..b4dd498a817 100644
--- a/chromium/ui/webui/resources/js/BUILD.gn
+++ b/chromium/ui/webui/resources/js/BUILD.gn
@@ -2,8 +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/chromeos/ui_mode.gni")
import("//third_party/closure_compiler/compile_js.gni")
-import("//tools/grit/preprocess_grit.gni")
+import("//tools/grit/preprocess_if_expr.gni")
import("//ui/webui/resources/tools/generate_grd.gni")
import("../tools/js_modulizer.gni")
@@ -32,7 +33,7 @@ group("preprocess") {
]
}
-preprocess_grit("preprocess_src") {
+preprocess_if_expr("preprocess_src") {
in_folder = "./"
out_folder = "$preprocess_folder"
out_manifest = "$target_gen_dir/$preprocess_src_manifest"
@@ -52,11 +53,12 @@ preprocess_grit("preprocess_src") {
"plural_string_proxy.js",
"promise_resolver.js",
"test_loader.js",
+ "test_loader_util.js",
"util.js",
"webui_resource_test.js",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
in_files += [ "i18n_template_process.js" ]
}
@@ -69,9 +71,16 @@ preprocess_grit("preprocess_src") {
"web_ui_listener_behavior.js",
]
}
+
+ if (is_ios) {
+ in_files += [
+ "ios/mojo_api.js",
+ "ios/web_ui.js",
+ ]
+ }
}
-preprocess_grit("preprocess_generated") {
+preprocess_if_expr("preprocess_generated") {
deps = [ ":modulize" ]
in_folder = target_gen_dir
out_folder = "$preprocess_folder"
@@ -107,6 +116,7 @@ group("closure_compile") {
}
js_type_check("js_resources") {
+ uses_legacy_modules = true
deps = [
":action_link",
":assert",
@@ -124,7 +134,7 @@ js_type_check("js_resources") {
":web_ui_listener_behavior",
":webui_resource_test",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ ":i18n_template_process" ]
}
if (is_ios) {
diff --git a/chromium/ui/webui/resources/js/assert.js b/chromium/ui/webui/resources/js/assert.js
index 7bb03af99fb..7c40d465eee 100644
--- a/chromium/ui/webui/resources/js/assert.js
+++ b/chromium/ui/webui/resources/js/assert.js
@@ -81,3 +81,5 @@
}
return value;
}
+
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/js/color_utils.js b/chromium/ui/webui/resources/js/color_utils.js
index e5b6c530cb7..4331132e423 100644
--- a/chromium/ui/webui/resources/js/color_utils.js
+++ b/chromium/ui/webui/resources/js/color_utils.js
@@ -6,12 +6,12 @@
* @fileoverview Helper functions for color manipulations.
*/
-import 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-lite.js';
+import {SkColor} from 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-webui.js';
/**
* Converts an SkColor object to a string in the form
* "rgba(<red>, <green>, <blue>, <alpha>)".
- * @param {skia.mojom.SkColor} skColor The input color.
+ * @param {SkColor} skColor The input color.
* @return {string} The rgba string.
*/
export function skColorToRgba(skColor) {
@@ -25,7 +25,7 @@ export function skColorToRgba(skColor) {
/**
* Converts a string of the form "#rrggbb" to an SkColor object.
* @param {string} hexColor The color string.
- * @return {!skia.mojom.SkColor} The SkColor object,
+ * @return {!SkColor} The SkColor object,
*/
export function hexColorToSkColor(hexColor) {
if (!/^#[0-9a-f]{6}$/.test(hexColor)) {
diff --git a/chromium/ui/webui/resources/js/cr/BUILD.gn b/chromium/ui/webui/resources/js/cr/BUILD.gn
index 3163c760db7..577de971dd2 100644
--- a/chromium/ui/webui/resources/js/cr/BUILD.gn
+++ b/chromium/ui/webui/resources/js/cr/BUILD.gn
@@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni")
import("../../tools/js_modulizer.gni")
js_type_check("closure_compile") {
+ uses_legacy_modules = true
deps = [
":event_target",
":ui",
@@ -13,7 +14,6 @@ js_type_check("closure_compile") {
}
js_type_check("closure_compile_modules") {
- uses_js_modules = true
deps = [
":event_target.m",
":ui.m",
diff --git a/chromium/ui/webui/resources/js/cr/event_target.js b/chromium/ui/webui/resources/js/cr/event_target.js
index 86deebc53ea..1197eb52369 100644
--- a/chromium/ui/webui/resources/js/cr/event_target.js
+++ b/chromium/ui/webui/resources/js/cr/event_target.js
@@ -21,5 +21,6 @@ cr.define('cr', function() {
/** @override */ NativeEventTarget.prototype.removeEventListener;
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {EventTarget: NativeEventTarget};
});
diff --git a/chromium/ui/webui/resources/js/cr/ui.js b/chromium/ui/webui/resources/js/cr/ui.js
index aefe25ca9ce..4fe73f481fd 100644
--- a/chromium/ui/webui/resources/js/cr/ui.js
+++ b/chromium/ui/webui/resources/js/cr/ui.js
@@ -210,6 +210,7 @@ cr.define('cr.ui', function() {
}
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
decorate: decorate,
define: define,
diff --git a/chromium/ui/webui/resources/js/cr/ui/BUILD.gn b/chromium/ui/webui/resources/js/cr/ui/BUILD.gn
index 0e10c8d0ec2..88cf2c9bb64 100644
--- a/chromium/ui/webui/resources/js/cr/ui/BUILD.gn
+++ b/chromium/ui/webui/resources/js/cr/ui/BUILD.gn
@@ -2,8 +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/chromeos/ui_mode.gni")
import("//third_party/closure_compiler/compile_js.gni")
-import("//tools/grit/preprocess_grit.gni")
+import("//tools/grit/preprocess_if_expr.gni")
import("//ui/webui/resources/tools/generate_grd.gni")
import("../../../tools/js_modulizer.gni")
import("../../cr.gni")
@@ -30,18 +31,14 @@ group("preprocess") {
]
}
-preprocess_grit("preprocess_src") {
+preprocess_if_expr("preprocess_src") {
in_folder = "./"
out_folder = "$preprocess_folder"
out_manifest = "$target_gen_dir/$preprocess_src_manifest"
in_files = [
"array_data_model.js",
- "bubble_button.js",
- "bubble.js",
- "card_slider.js",
"command.js",
"context_menu_handler.js",
- "controlled_indicator.js",
"dialogs.js",
"drag_wrapper.js",
"focus_grid.js",
@@ -57,13 +54,11 @@ preprocess_grit("preprocess_src") {
"menu_button.js",
"menu_item.js",
"menu.js",
- "overlay.js",
"position_util.js",
"splitter.js",
"store_client.js",
"store.js",
"tabs.js",
- "touch_handler.js",
"tree.js",
]
@@ -74,22 +69,27 @@ preprocess_grit("preprocess_src") {
]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
in_files += [ "grid.js" ]
}
}
-preprocess_grit("preprocess_generated") {
+preprocess_if_expr("preprocess_generated") {
deps = [ ":modulize" ]
in_folder = target_gen_dir
out_folder = "$preprocess_folder"
out_manifest = "$target_gen_dir/$preprocess_gen_manifest"
in_files = [
+ "array_data_model.m.js",
"drag_wrapper.m.js",
"focus_grid.m.js",
"focus_outline_manager.m.js",
"focus_row.m.js",
"keyboard_shortcut_list.m.js",
+ "list_item.m.js",
+ "list.m.js",
+ "list_selection_controller.m.js",
+ "list_selection_model.m.js",
"store_client.m.js",
"store.m.js",
"tabs.m.js",
@@ -98,27 +98,22 @@ preprocess_grit("preprocess_generated") {
if (!is_android) {
in_files += [
+ "command.m.js",
+ "context_menu_handler.m.js",
"focus_row_behavior.m.js",
"focus_without_ink.m.js",
+ "menu_button.m.js",
+ "menu_item.m.js",
+ "menu.m.js",
+ "position_util.m.js",
]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
in_files += [
- "array_data_model.m.js",
- "command.m.js",
- "context_menu_handler.m.js",
"dialogs.m.js",
"grid.m.js",
- "list_item.m.js",
- "list.m.js",
- "list_selection_controller.m.js",
- "list_selection_model.m.js",
"list_single_selection_model.m.js",
- "menu_button.m.js",
- "menu_item.m.js",
- "menu.m.js",
- "position_util.m.js",
"splitter.m.js",
]
}
@@ -132,6 +127,7 @@ group("closure_compile") {
}
js_type_check("ui_resources") {
+ uses_legacy_modules = true
deps = [
":array_data_model",
":command",
@@ -153,7 +149,6 @@ js_type_check("ui_resources") {
":menu",
":menu_button",
":menu_item",
- ":overlay",
":position_util",
":splitter",
":store",
@@ -162,7 +157,7 @@ js_type_check("ui_resources") {
":tree",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ ":grid" ]
}
}
@@ -174,14 +169,6 @@ js_library("array_data_model") {
]
}
-js_library("bubble") {
- deps = [
- "..:ui",
- "../..:cr",
- "../..:event_tracker",
- ]
-}
-
js_library("command") {
deps = [
":keyboard_shortcut_list",
@@ -320,13 +307,6 @@ js_library("menu") {
]
}
-js_library("overlay") {
- deps = [
- "../..:cr",
- "../..:util",
- ]
-}
-
js_library("position_util") {
deps = [ "../..:cr" ]
}
@@ -354,6 +334,7 @@ js_library("tabs") {
":focus_outline_manager",
"..:ui",
"../..:cr",
+ "../..:util",
]
}
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 1621859b64d..81da62d6986 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
@@ -453,5 +453,6 @@ cr.define('cr.ui', function() {
}
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {ArrayDataModel: ArrayDataModel};
});
diff --git a/chromium/ui/webui/resources/js/cr/ui/bubble.js b/chromium/ui/webui/resources/js/cr/ui/bubble.js
deleted file mode 100644
index 7623e1513b5..00000000000
--- a/chromium/ui/webui/resources/js/cr/ui/bubble.js
+++ /dev/null
@@ -1,569 +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.
-
-// require: event_tracker.js
-
-cr.define('cr.ui', function() {
- /**
- * The arrow location specifies how the arrow and bubble are positioned in
- * relation to the anchor node.
- * @enum {string}
- */
- const ArrowLocation = {
- // The arrow is positioned at the top and the start of the bubble. In left
- // to right mode this is the top left. The entire bubble is positioned below
- // the anchor node.
- TOP_START: 'top-start',
- // The arrow is positioned at the top and the end of the bubble. In left to
- // right mode this is the top right. The entire bubble is positioned below
- // the anchor node.
- TOP_END: 'top-end',
- // The arrow is positioned at the bottom and the start of the bubble. In
- // left to right mode this is the bottom left. The entire bubble is
- // positioned above the anchor node.
- BOTTOM_START: 'bottom-start',
- // The arrow is positioned at the bottom and the end of the bubble. In
- // left to right mode this is the bottom right. The entire bubble is
- // positioned above the anchor node.
- BOTTOM_END: 'bottom-end'
- };
-
- /**
- * The bubble alignment specifies the position of the bubble in relation to
- * the anchor node.
- * @enum {string}
- */
- const BubbleAlignment = {
- // The bubble is positioned just above or below the anchor node (as
- // specified by the arrow location) so that the arrow points at the midpoint
- // of the anchor.
- ARROW_TO_MID_ANCHOR: 'arrow-to-mid-anchor',
- // The bubble is positioned just above or below the anchor node (as
- // specified by the arrow location) so that its reference edge lines up with
- // the edge of the anchor.
- BUBBLE_EDGE_TO_ANCHOR_EDGE: 'bubble-edge-anchor-edge',
- // The bubble is positioned so that it is entirely within view and does not
- // obstruct the anchor element, if possible. The specified arrow location is
- // taken into account as the preferred alignment but may be overruled if
- // there is insufficient space (see BubbleBase.reposition for the exact
- // placement algorithm).
- ENTIRELY_VISIBLE: 'entirely-visible'
- };
-
- /**
- * Abstract base class that provides common functionality for implementing
- * free-floating informational bubbles with a triangular arrow pointing at an
- * anchor node.
- * @constructor
- * @extends {HTMLDivElement}
- * @implements {EventListener}
- */
- const BubbleBase = cr.ui.define('div');
-
- /**
- * The horizontal distance between the tip of the arrow and the reference edge
- * of the bubble (as specified by the arrow location). In pixels.
- * @type {number}
- * @const
- */
- BubbleBase.ARROW_OFFSET = 30;
-
- /**
- * Minimum horizontal spacing between edge of bubble and edge of viewport
- * (when using the ENTIRELY_VISIBLE alignment). In pixels.
- * @type {number}
- * @const
- */
- BubbleBase.MIN_VIEWPORT_EDGE_MARGIN = 2;
-
- /**
- * This is used to create TrustedHTML.
- * @type {!TrustedTypePolicy}
- */
- const staticHtmlPolicy = trustedTypes.createPolicy('cr-ui-bubble-js-static', {
- createHTML: () => {
- return '<div class="bubble-content"></div>' +
- '<div class="bubble-shadow"></div>' +
- '<div class="bubble-arrow"></div>';
- },
- });
-
- BubbleBase.prototype = {
- // Set up the prototype chain.
- __proto__: HTMLDivElement.prototype,
-
- /**
- * @type {Node}
- * @private
- */
- anchorNode_: null,
-
- /**
- * Initialization function for the cr.ui framework.
- */
- decorate() {
- this.className = 'bubble';
- // TODO(Jun.Kokatsu@microsoft.com): remove an empty string argument
- // once supported.
- // https://github.com/w3c/webappsec-trusted-types/issues/278
- this.innerHTML = staticHtmlPolicy.createHTML('');
- this.hidden = true;
- this.bubbleAlignment = cr.ui.BubbleAlignment.ENTIRELY_VISIBLE;
- },
-
- /**
- * Set the anchor node, i.e. the node that this bubble points at. Only
- * available when the bubble is not being shown.
- * @param {HTMLElement} node The new anchor node.
- */
- set anchorNode(node) {
- if (!this.hidden) {
- return;
- }
-
- this.anchorNode_ = node;
- },
-
- /**
- * Set the conent of the bubble. Only available when the bubble is not being
- * shown.
- * @param {HTMLElement} node The root node of the new content.
- */
- set content(node) {
- if (!this.hidden) {
- return;
- }
-
- const bubbleContent = this.querySelector('.bubble-content');
- bubbleContent.innerHTML = trustedTypes.emptyHTML;
- bubbleContent.appendChild(node);
- },
-
- /**
- * Set the arrow location. Only available when the bubble is not being
- * shown.
- * @param {cr.ui.ArrowLocation} location The new arrow location.
- */
- set arrowLocation(location) {
- if (!this.hidden) {
- return;
- }
-
- this.arrowAtRight_ = location === cr.ui.ArrowLocation.TOP_END ||
- location === cr.ui.ArrowLocation.BOTTOM_END;
- if (document.documentElement.dir === 'rtl') {
- this.arrowAtRight_ = !this.arrowAtRight_;
- }
- this.arrowAtTop_ = location === cr.ui.ArrowLocation.TOP_START ||
- location === cr.ui.ArrowLocation.TOP_END;
- },
-
- /**
- * Set the bubble alignment. Only available when the bubble is not being
- * shown.
- * @param {cr.ui.BubbleAlignment} alignment The new bubble alignment.
- */
- set bubbleAlignment(alignment) {
- if (!this.hidden) {
- return;
- }
-
- this.bubbleAlignment_ = alignment;
- },
-
- /**
- * Update the position of the bubble. Whenever the layout may have changed,
- * the bubble should either be repositioned by calling this function or
- * hidden so that it does not point to a nonsensical location on the page.
- */
- reposition() {
- 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.
- left = this.arrowAtRight_ ?
- anchorMid + BubbleBase.ARROW_OFFSET - bubble.width :
- anchorMid - BubbleBase.ARROW_OFFSET;
- const maxLeftPos =
- documentWidth - bubble.width - BubbleBase.MIN_VIEWPORT_EDGE_MARGIN;
- const minLeftPos = BubbleBase.MIN_VIEWPORT_EDGE_MARGIN;
- if (document.documentElement.dir === 'rtl') {
- left = Math.min(Math.max(left, minLeftPos), maxLeftPos);
- } else {
- left = Math.max(Math.min(left, maxLeftPos), minLeftPos);
- }
- const arrowTip = Math.min(
- Math.max(
- arrow.width / 2,
- this.arrowAtRight_ ? left + bubble.width - anchorMid :
- anchorMid - left),
- bubble.width - arrow.width / 2);
-
- // Work out the vertical placement, attempting to fit the bubble
- // entirely into view. The following placements are considered in
- // decreasing order of preference:
- // * Outside the anchor, arrow tip touching the anchor (arrow at
- // top/bottom as specified by the arrow location).
- // * Outside the anchor, arrow tip touching the anchor (arrow at
- // bottom/top, opposite the specified arrow location).
- // * Outside the anchor, arrow tip overlapping the anchor (arrow at
- // top/bottom as specified by the arrow location).
- // * Outside the anchor, arrow tip overlapping the anchor (arrow at
- // bottom/top, opposite the specified arrow location).
- // * Overlapping the anchor.
- const offsetTop = Math.min(
- documentHeight - anchor.bottom - bubble.height, arrow.height / 2);
- const offsetBottom =
- Math.min(anchor.top - bubble.height, arrow.height / 2);
- if (offsetTop < 0 && offsetBottom < 0) {
- top = 0;
- this.updateArrowPosition_(false, false, arrowTip);
- } else if (
- offsetTop > offsetBottom ||
- offsetTop === offsetBottom && this.arrowAtTop_) {
- top = anchor.bottom + offsetTop;
- this.updateArrowPosition_(true, true, arrowTip);
- } else {
- top = anchor.top - bubble.height - offsetBottom;
- this.updateArrowPosition_(true, false, arrowTip);
- }
- } else {
- if (this.bubbleAlignment_ ===
- cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE) {
- left = this.arrowAtRight_ ? anchor.right - bubble.width : anchor.left;
- } else {
- left = this.arrowAtRight_ ?
- anchorMid - this.clientWidth + BubbleBase.ARROW_OFFSET :
- anchorMid - BubbleBase.ARROW_OFFSET;
- }
- top = this.arrowAtTop_ ?
- anchor.bottom + arrow.height / 2 :
- anchor.top - this.clientHeight - arrow.height / 2;
- this.updateArrowPosition_(
- true, this.arrowAtTop_, BubbleBase.ARROW_OFFSET);
- }
-
- this.style.left = left + 'px';
- this.style.top = top + 'px';
- },
-
- /**
- * Show the bubble.
- */
- show() {
- if (!this.hidden) {
- return;
- }
-
- this.attachToDOM_();
- this.hidden = false;
- this.reposition();
-
- const doc = assert(this.ownerDocument);
- this.eventTracker_ = new EventTracker;
- this.eventTracker_.add(doc, 'keydown', this, true);
- this.eventTracker_.add(doc, 'mousedown', this, true);
- },
-
- /**
- * Hide the bubble.
- */
- hide() {
- if (this.hidden) {
- return;
- }
-
- this.eventTracker_.removeAll();
- this.hidden = true;
- this.parentNode.removeChild(this);
- },
-
- /**
- * Handle keyboard events, dismissing the bubble if necessary.
- * @param {Event} event The event.
- */
- handleEvent(event) {
- // Close the bubble when the user presses <Esc>.
- if (event.type === 'keydown' && event.keyCode === 27) {
- this.hide();
- event.preventDefault();
- event.stopPropagation();
- }
- },
-
- /**
- * Attach the bubble to the document's DOM.
- * @private
- */
- attachToDOM_() {
- document.body.appendChild(this);
- },
-
- /**
- * Update the arrow so that it appears at the correct position.
- * @param {boolean} visible Whether the arrow should be visible.
- * @param {boolean} atTop Whether the arrow should be at the top of the
- * bubble.
- * @param {number} tipOffset The horizontal distance between the tip of the
- * arrow and the reference edge of the bubble (as specified by the arrow
- * location).
- * @private
- */
- updateArrowPosition_(visible, atTop, tipOffset) {
- const bubbleArrow = this.querySelector('.bubble-arrow');
- bubbleArrow.hidden = !visible;
- if (!visible) {
- return;
- }
-
- let edgeOffset = (-bubbleArrow.clientHeight / 2) + 'px';
- bubbleArrow.style.top = atTop ? edgeOffset : 'auto';
- bubbleArrow.style.bottom = atTop ? 'auto' : edgeOffset;
-
- edgeOffset = (tipOffset - bubbleArrow.offsetWidth / 2) + 'px';
- bubbleArrow.style.left = this.arrowAtRight_ ? 'auto' : edgeOffset;
- bubbleArrow.style.right = this.arrowAtRight_ ? edgeOffset : 'auto';
- },
- };
-
- /**
- * A bubble that remains open until the user explicitly dismisses it or clicks
- * outside the bubble after it has been shown for at least the specified
- * amount of time (making it less likely that the user will unintentionally
- * dismiss the bubble). The bubble repositions itself on layout changes.
- * @constructor
- * @extends {cr.ui.BubbleBase}
- */
- const Bubble = cr.ui.define('div');
-
- Bubble.prototype = {
- // Set up the prototype chain.
- __proto__: BubbleBase.prototype,
-
- /**
- * Initialization function for the cr.ui framework.
- */
- decorate() {
- BubbleBase.prototype.decorate.call(this);
-
- const close = document.createElement('div');
- close.className = 'bubble-close';
- this.insertBefore(close, this.querySelector('.bubble-content'));
-
- this.handleCloseEvent = this.hide;
- this.deactivateToDismissDelay_ = 0;
- this.bubbleAlignment = cr.ui.BubbleAlignment.ARROW_TO_MID_ANCHOR;
- },
-
- /**
- * Handler for close events triggered when the close button is clicked. By
- * default, set to this.hide. Only available when the bubble is not being
- * shown.
- * @param {function(): *} handler The new handler, a function with no
- * parameters.
- */
- set handleCloseEvent(handler) {
- if (!this.hidden) {
- return;
- }
-
- this.handleCloseEvent_ = handler;
- },
-
- /**
- * Set the delay before the user is allowed to click outside the bubble to
- * dismiss it. Using a delay makes it less likely that the user will
- * unintentionally dismiss the bubble.
- * @param {number} delay The delay in milliseconds.
- */
- set deactivateToDismissDelay(delay) {
- this.deactivateToDismissDelay_ = delay;
- },
-
- /**
- * Hide or show the close button.
- * @param {boolean} isVisible True if the close button should be visible.
- */
- set closeButtonVisible(isVisible) {
- this.querySelector('.bubble-close').hidden = !isVisible;
- },
-
- /**
- * Show the bubble.
- */
- show() {
- if (!this.hidden) {
- return;
- }
-
- BubbleBase.prototype.show.call(this);
-
- this.showTime_ = Date.now();
- this.eventTracker_.add(window, 'resize', this.reposition.bind(this));
- },
-
- /**
- * Handle keyboard and mouse events, dismissing the bubble if necessary.
- * @param {Event} event The event.
- * @suppress {checkTypes}
- * TODO(vitalyp): remove suppression when the extern
- * Node.prototype.contains() will be fixed.
- */
- handleEvent(event) {
- BubbleBase.prototype.handleEvent.call(this, event);
-
- if (event.type === 'mousedown') {
- // Dismiss the bubble when the user clicks on the close button.
- if (event.target === this.querySelector('.bubble-close')) {
- this.handleCloseEvent_();
- // Dismiss the bubble when the user clicks outside it after the
- // specified delay has passed.
- } else if (
- !this.contains(event.target) &&
- Date.now() - this.showTime_ >= this.deactivateToDismissDelay_) {
- this.hide();
- }
- }
- },
- };
-
- /**
- * A bubble that closes automatically when the user clicks or moves the focus
- * outside the bubble and its target element, scrolls the underlying document
- * or resizes the window.
- * @constructor
- * @extends {cr.ui.BubbleBase}
- */
- const AutoCloseBubble = cr.ui.define('div');
-
- AutoCloseBubble.prototype = {
- // Set up the prototype chain.
- __proto__: BubbleBase.prototype,
-
- /**
- * Initialization function for the cr.ui framework.
- */
- decorate() {
- BubbleBase.prototype.decorate.call(this);
- this.classList.add('auto-close-bubble');
- },
-
- /**
- * Set the DOM sibling node, i.e. the node as whose sibling the bubble
- * should join the DOM to ensure that focusable elements inside the bubble
- * follow the target element in the document's tab order. Only available
- * when the bubble is not being shown.
- * @param {HTMLElement} node The new DOM sibling node.
- */
- set domSibling(node) {
- if (!this.hidden) {
- return;
- }
-
- this.domSibling_ = node;
- },
-
- /**
- * Show the bubble.
- */
- show() {
- if (!this.hidden) {
- return;
- }
-
- BubbleBase.prototype.show.call(this);
- this.domSibling_.showingBubble = true;
-
- 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);
- this.eventTracker_.add(doc, 'elementFocused', this, true);
- this.eventTracker_.add(window, 'resize', this);
- },
-
- /**
- * Hide the bubble.
- */
- hide() {
- BubbleBase.prototype.hide.call(this);
- this.domSibling_.showingBubble = false;
- },
-
- /**
- * Handle events, closing the bubble when the user clicks or moves the focus
- * outside the bubble and its target element, scrolls the underlying
- * document or resizes the window.
- * @param {Event} event The event.
- * @suppress {checkTypes}
- * TODO(vitalyp): remove suppression when the extern
- * Node.prototype.contains() will be fixed.
- */
- handleEvent(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':
- 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':
- target = assertInstanceof(event.target, Node);
- if (this.contains(target)) {
- break;
- }
- // Close the bubble when the window is resized.
- case 'resize':
- this.hide();
- break;
- // Close the bubble when the focus moves to an element that is not the
- // bubble target and is not inside the bubble.
- case 'elementFocused':
- target = assertInstanceof(event.target, Node);
- if (!this.anchorNode_.contains(target) && !this.contains(target)) {
- this.hide();
- }
- break;
- }
- },
-
- /**
- * Attach the bubble to the document's DOM, making it a sibling of the
- * |domSibling_| so that focusable elements inside the bubble follow the
- * target element in the document's tab order.
- * @private
- */
- attachToDOM_() {
- const parent = this.domSibling_.parentNode;
- parent.insertBefore(this, this.domSibling_.nextSibling);
- },
- };
-
- return {
- ArrowLocation: ArrowLocation,
- AutoCloseBubble: AutoCloseBubble,
- BubbleAlignment: BubbleAlignment,
- BubbleBase: BubbleBase,
- Bubble: Bubble,
- };
-});
diff --git a/chromium/ui/webui/resources/js/cr/ui/bubble_button.js b/chromium/ui/webui/resources/js/cr/ui/bubble_button.js
deleted file mode 100644
index b1accdd7a44..00000000000
--- a/chromium/ui/webui/resources/js/cr/ui/bubble_button.js
+++ /dev/null
@@ -1,94 +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.
-
-cr.define('cr.ui', function() {
- /**
- * An image button that brings up an informative bubble when activated by
- * keyboard or mouse.
- * @constructor
- * @extends {HTMLSpanElement}
- * @implements {EventListener}
- */
- const BubbleButton = cr.ui.define('span');
-
- BubbleButton.prototype = {
- __proto__: HTMLSpanElement.prototype,
-
- /**
- * Decorates the base element to show the proper icon.
- */
- decorate() {
- this.className = 'bubble-button';
- this.location = cr.ui.ArrowLocation.TOP_END;
- this.image = document.createElement('div');
- this.image.tabIndex = 0;
- this.image.setAttribute('role', 'button');
- this.image.addEventListener('click', this);
- this.image.addEventListener('keydown', this);
- this.image.addEventListener('mousedown', this);
- this.appendChild(this.image);
- },
-
- /**
- * Whether the button is currently showing a bubble.
- * @type {boolean}
- */
- get showingBubble() {
- return this.image.classList.contains('showing-bubble');
- },
- set showingBubble(showing) {
- this.image.classList.toggle('showing-bubble', showing);
- },
-
- /**
- * Handle mouse and keyboard events, allowing the user to open and close an
- * informative bubble.
- * @param {Event} event Mouse or keyboard event.
- */
- handleEvent(event) {
- switch (event.type) {
- // Toggle the bubble on left click. Let any other clicks propagate.
- case 'click':
- if (event.button !== 0) {
- return;
- }
- break;
- // Toggle the bubble when <Return> or <Space> is pressed. Let any other
- // key presses propagate.
- case 'keydown':
- switch (event.keyCode) {
- case 13: // Return.
- case 32: // Space.
- break;
- default:
- return;
- }
- break;
- // Blur focus when a mouse button is pressed, matching the behavior of
- // other Web UI elements.
- case 'mousedown':
- if (document.activeElement) {
- document.activeElement.blur();
- }
- event.preventDefault();
- return;
- }
- this.toggleBubble();
- event.preventDefault();
- event.stopPropagation();
- },
-
- /**
- * Abstract method: subclasses should overwrite it. There is no way to mark
- * method as abstract for Closure Compiler, as of
- * https://github.com/google/closure-compiler/issues/104.
- * @type {!Function|undefined}
- * @protected
- */
- toggleBubble: assertNotReached,
- };
-
- // Export.
- return {BubbleButton: BubbleButton};
-});
diff --git a/chromium/ui/webui/resources/js/cr/ui/card_slider.js b/chromium/ui/webui/resources/js/cr/ui/card_slider.js
deleted file mode 100644
index af7e5904c55..00000000000
--- a/chromium/ui/webui/resources/js/cr/ui/card_slider.js
+++ /dev/null
@@ -1,693 +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.
-
-/**
- * @fileoverview Card slider implementation. Allows you to create interactions
- * that have items that can slide left to right to reveal additional items.
- * Works by adding the necessary event handlers to a specific DOM structure
- * including a frame, container and cards.
- * - The frame defines the boundary of one item. Each card will be expanded to
- * fill the width of the frame. This element is also overflow hidden so that
- * the additional items left / right do not trigger horizontal scrolling.
- * - The container is what all the touch events are attached to. This element
- * will be expanded to be the width of all cards.
- * - The cards are the individual viewable items. There should be one card for
- * each item in the list. Only one card will be visible at a time. Two cards
- * will be visible while you are transitioning between cards.
- *
- * This class is designed to work well on any hardware-accelerated touch device.
- * It should still work on pre-hardware accelerated devices it just won't feel
- * very good. It should also work well with a mouse.
- */
-
-// Use an anonymous function to enable strict mode just for this file (which
-// will be concatenated with other files when embedded in Chrome
-cr.define('cr.ui', function() {
- 'use strict';
-
- /**
- * @constructor
- * @param {!Element} frame The bounding rectangle that cards are visible in.
- * @param {!Element} container The surrounding element that will have event
- * listeners attached to it.
- * @param {number} cardWidth The width of each card should have.
- */
- function CardSlider(frame, container, cardWidth) {
- /**
- * @type {!Element}
- * @private
- */
- this.frame_ = frame;
-
- /**
- * @type {!Element}
- * @private
- */
- this.container_ = container;
-
- /**
- * Array of card elements.
- * @type {!Array<!Element>}
- * @private
- */
- this.cards_ = [];
-
- /**
- * Index of currently shown card.
- * @type {number}
- * @private
- */
- this.currentCard_ = -1;
-
- /**
- * @type {number}
- * @private
- */
- this.cardWidth_ = cardWidth;
-
- /**
- * @type {!cr.ui.TouchHandler}
- * @private
- */
- this.touchHandler_ = new cr.ui.TouchHandler(this.container_);
- }
-
-
- /**
- * The time to transition between cards when animating. Measured in ms.
- * @type {number}
- * @private
- * @const
- */
- CardSlider.TRANSITION_TIME_ = 200;
-
-
- /**
- * The minimum velocity required to transition cards if they did not drag past
- * the halfway point between cards. Measured in pixels / ms.
- * @type {number}
- * @private
- * @const
- */
- CardSlider.TRANSITION_VELOCITY_THRESHOLD_ = 0.2;
-
-
- CardSlider.prototype = {
- /**
- * The current left offset of the container relative to the frame. This
- * position does not include deltas from active drag operations, and
- * always aligns with a frame boundary.
- * @type {number}
- * @private
- */
- currentLeft_: 0,
-
- /**
- * Current offset relative to |currentLeft_| due to an active drag
- * operation.
- * @type {number}
- * @private
- */
- deltaX_: 0,
-
- /**
- * Initialize all elements and event handlers. Must call after construction
- * and before usage.
- * @param {boolean} ignoreMouseWheelEvents If true, horizontal mouse wheel
- * events will be ignored, rather than flipping between pages.
- */
- initialize(ignoreMouseWheelEvents) {
- const view = this.container_.ownerDocument.defaultView;
- assert(
- view.getComputedStyle(this.container_).display === '-webkit-box',
- 'Container should be display -webkit-box.');
- assert(
- view.getComputedStyle(this.frame_).overflow === 'hidden',
- 'Frame should be overflow hidden.');
- assert(
- view.getComputedStyle(this.container_).position === 'static',
- 'Container should be position static.');
-
- this.updateCardWidths_();
-
- this.mouseWheelScrollAmount_ = 0;
- this.mouseWheelCardSelected_ = false;
- this.mouseWheelIsContinuous_ = false;
- this.scrollClearTimeout_ = null;
- if (!ignoreMouseWheelEvents) {
- this.frame_.addEventListener(
- 'mousewheel', this.onMouseWheel_.bind(this));
- }
- this.container_.addEventListener(
- 'transitionend', this.onTransitionEnd_.bind(this));
-
- // Also support touch events in case a touch screen happens to be
- // 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).
- const TouchHandler = cr.ui.TouchHandler;
- this.container_.addEventListener(
- TouchHandler.EventType.TOUCH_START, this.onTouchStart_.bind(this));
- this.container_.addEventListener(
- TouchHandler.EventType.DRAG_START, this.onDragStart_.bind(this));
- this.container_.addEventListener(
- TouchHandler.EventType.DRAG_MOVE, this.onDragMove_.bind(this));
- this.container_.addEventListener(
- TouchHandler.EventType.DRAG_END, this.onDragEnd_.bind(this));
-
- this.touchHandler_.enable(/* opt_capture */ false);
- },
-
- /**
- * Use in cases where the width of the frame has changed in order to update
- * the width of cards. For example should be used when orientation changes
- * in full width sliders.
- * @param {number} newCardWidth Width all cards should have, in pixels.
- */
- resize(newCardWidth) {
- if (newCardWidth !== this.cardWidth_) {
- this.cardWidth_ = newCardWidth;
-
- this.updateCardWidths_();
-
- // Must upate the transform on the container to show the correct card.
- this.transformToCurrentCard_();
- }
- },
-
- /**
- * Sets the cards used. Can be called more than once to switch card sets.
- * @param {!Array<!Element>} cards The individual viewable cards.
- * @param {number} index Index of the card to in the new set of cards to
- * navigate to.
- */
- setCards(cards, index) {
- assert(
- index >= 0 && index < cards.length,
- 'Invalid index in CardSlider#setCards');
- this.cards_ = cards;
-
- this.updateCardWidths_();
- this.updateSelectedCardAttributes_();
-
- // Jump to the given card index.
- this.selectCard(index, false, false, true);
- },
-
- /**
- * Ensures that for all cards:
- * - if the card is the current card, then it has 'selected-card' in its
- * classList, and is visible for accessibility
- * - if the card is not the selected card, then it does not have
- * 'selected-card' in its classList, and is invisible for accessibility.
- * @private
- */
- updateSelectedCardAttributes_() {
- 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');
- } else {
- this.cards_[i].classList.remove('selected-card');
- this.cards_[i].setAttribute('aria-hidden', true);
- }
- }
- },
-
- /**
- * Updates the width of each card.
- * @private
- */
- updateCardWidths_() {
- for (let i = 0, card; card = this.cards_[i]; i++) {
- card.style.width = this.cardWidth_ + 'px';
- }
- },
-
- /**
- * Returns the index of the current card.
- * @return {number} index of the current card.
- */
- get currentCard() {
- return this.currentCard_;
- },
-
- /**
- * Allows setting the current card index.
- * @param {number} index A new index to set the current index to.
- * @return {number} The new index after having been set.
- */
- set currentCard(index) {
- return (this.currentCard_ = index);
- },
-
- /**
- * Returns the number of cards.
- * @return {number} number of cards.
- */
- get cardCount() {
- return this.cards_.length;
- },
-
- /**
- * Returns the current card itself.
- * @return {!Element} the currently shown card.
- */
- get currentCardValue() {
- return this.cards_[this.currentCard_];
- },
-
- /**
- * Returns the frame holding the cards.
- * @return {Element} The frame used to position the cards.
- */
- get frame() {
- return this.frame_;
- },
-
- /**
- * Handle horizontal scrolls to flip between pages.
- * @private
- */
- onMouseWheel_(e) {
- if (e.wheelDeltaX === 0) {
- return;
- }
-
- // Continuous devices such as an Apple Touchpad or Apple MagicMouse will
- // send arbitrary delta values. Conversly, standard mousewheels will
- // send delta values in increments of 120. (There is of course a small
- // 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.)
- 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_) {
- return;
- }
- this.mouseWheelScrollAmount_ += e.wheelDeltaX;
- if (Math.abs(this.mouseWheelScrollAmount_) >= 600) {
- let pagesToScroll = this.mouseWheelScrollAmount_ > 0 ? 1 : -1;
- if (!isRTL()) {
- pagesToScroll *= -1;
- }
- let newCardIndex = this.currentCard + pagesToScroll;
- newCardIndex =
- Math.min(this.cards_.length - 1, Math.max(0, newCardIndex));
- this.selectCard(newCardIndex, true);
- this.mouseWheelCardSelected_ = true;
- }
- } else {
- // For discrete devices, consider each wheel tick a page change.
- let pagesToScroll = e.wheelDeltaX / DISCRETE_DELTA;
- if (!isRTL()) {
- pagesToScroll *= -1;
- }
- 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) {
- 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) {
- this.scrollClearTimeout_ =
- setTimeout(this.clearMouseWheelScroll_.bind(this), 500);
- }
- },
-
- /**
- * Resets the amount of horizontal scroll we've seen to 0. See
- * onMouseWheel_.
- * @private
- */
- clearMouseWheelScroll_() {
- this.mouseWheelScrollAmount_ = 0;
- this.mouseWheelCardSelected_ = false;
- },
-
- /**
- * Handles the ends of transitions on transform (animated
- * card switches).
- * @param {Event} e The transitionend event.
- * @private
- */
- onTransitionEnd_(e) {
- // Ignore irrelevant transitions that might bubble up.
- if (e.target !== this.container_ || e.propertyName !== 'transform') {
- return;
- }
- this.fireChangeEndedEvent_(true);
- },
-
- /**
- * Dispatches a simple event to tell subscribers we're done moving to the
- * newly selected card.
- * @param {boolean} wasAnimated whether or not the change was animated.
- * @private
- */
- fireChangeEndedEvent_(wasAnimated) {
- const e = document.createEvent('Event');
- e.initEvent('cardSlider:card_change_ended', true, true);
- e.cardSlider = this;
- e.changedTo = this.currentCard_;
- e.wasAnimated = wasAnimated;
- this.container_.dispatchEvent(e);
- },
-
- /**
- * Add a card to the card slider at a particular index. If the card being
- * added is inserted in front of the current card, cardSlider.currentCard
- * will be adjusted accordingly (to current card + 1).
- * @param {!Node} card A card that will be added to the card slider.
- * @param {number} index An index at which the given |card| should be
- * inserted. Must be positive and less than the number of cards.
- */
- addCardAtIndex(card, index) {
- assert(card instanceof Node, '|card| isn\'t a Node');
- this.assertValidIndex_(index);
- this.cards_ = Array.prototype.concat.call(
- this.cards_.slice(0, index), card, this.cards_.slice(index));
-
- this.updateSelectedCardAttributes_();
-
- if (this.currentCard_ === -1) {
- this.currentCard_ = 0;
- } else if (index <= this.currentCard_) {
- this.selectCard(this.currentCard_ + 1, false, true, true);
- }
-
- this.fireAddedEvent_(card, index);
- },
-
- /**
- * Append a card to the end of the list.
- * @param {!Element} card A card to add at the end of the card slider.
- */
- appendCard(card) {
- this.cards_.push(assertInstanceof(card, Element));
- this.fireAddedEvent_(card, this.cards_.length - 1);
- },
-
- /**
- * Dispatches a simple event to tell interested subscribers that a card was
- * added to this card slider.
- * @param {Node} card The recently added card.
- * @param {number} index The position of the newly added card.
- * @private
- */
- fireAddedEvent_(card, index) {
- this.assertValidIndex_(index);
- const e = document.createEvent('Event');
- e.initEvent('cardSlider:card_added', true, true);
- e.addedIndex = index;
- e.addedCard = card;
- this.container_.dispatchEvent(e);
- },
-
- /**
- * Returns the card at a particular index.
- * @param {number} index The index of the card to return.
- * @return {!Element} The card at the given index.
- */
- getCardAtIndex(index) {
- this.assertValidIndex_(index);
- return this.cards_[index];
- },
-
- /**
- * Removes a card by index from the card slider. If the card to be removed
- * is the current card or in front of the current card, the current card
- * will be updated (to current card - 1).
- * @param {!Element} card A card to be removed.
- */
- removeCard(card) {
- this.removeCardAtIndex(
- this.cards_.indexOf(assertInstanceof(card, Element)));
- },
-
- /**
- * Removes a card by index from the card slider. If the card to be removed
- * is the current card or in front of the current card, the current card
- * will be updated (to current card - 1).
- * @param {number} index The index of the tile that should be removed.
- */
- removeCardAtIndex(index) {
- this.assertValidIndex_(index);
- const removed = this.cards_.splice(index, 1).pop();
-
- if (this.cards_.length === 0) {
- this.currentCard_ = -1;
- } else if (index < this.currentCard_) {
- this.selectCard(this.currentCard_ - 1, false, true);
- }
-
- this.fireRemovedEvent_(removed, index);
- },
-
- /**
- * Dispatches a cardSlider:card_removed event so interested subscribers know
- * when a card was removed from this card slider.
- * @param {Node} card The recently removed card.
- * @param {number} index The index of the card before it was removed.
- * @private
- */
- fireRemovedEvent_(card, index) {
- const e = document.createEvent('Event');
- e.initEvent('cardSlider:card_removed', true, true);
- e.removedCard = card;
- e.removedIndex = index;
- this.container_.dispatchEvent(e);
- },
-
- /**
- * This re-syncs the transform that's used to position the frame in
- * the likely event it needs to be updated by a card being inserted or
- * removed in the flow.
- */
- repositionFrame() {
- this.transformToCurrentCard_();
- },
-
- /**
- * Checks the the given |index| exists in this.cards_.
- * @param {number} index An index to check.
- * @private
- */
- assertValidIndex_(index) {
- assert(index >= 0 && index < this.cards_.length);
- },
-
- /**
- * Selects a new card, ensuring that it is a valid index, transforming the
- * view and possibly calling the change card callback.
- * @param {number} newCardIndex Index of card to show.
- * @param {boolean=} opt_animate If true will animate transition from
- * current position to new position.
- * @param {boolean=} opt_dontNotify If true, don't tell subscribers that
- * we've changed cards.
- * @param {boolean=} opt_forceChange If true, ignore if the card already
- * selected.
- */
- selectCard(newCardIndex, opt_animate, opt_dontNotify, opt_forceChange) {
- this.assertValidIndex_(newCardIndex);
-
- const previousCard = this.currentCardValue;
- let isChangingCard =
- !this.cards_[newCardIndex].classList.contains('selected-card');
-
- if (typeof opt_forceChange !== 'undefined' && opt_forceChange) {
- isChangingCard = true;
- }
-
- if (isChangingCard) {
- this.currentCard_ = newCardIndex;
- this.updateSelectedCardAttributes_();
- }
-
- const willTransitionHappen = this.transformToCurrentCard_(opt_animate);
-
- if (isChangingCard && !opt_dontNotify) {
- const event = document.createEvent('Event');
- event.initEvent('cardSlider:card_changed', true, true);
- event.cardSlider = this;
- event.wasAnimated = !!opt_animate;
- this.container_.dispatchEvent(event);
-
- // We also dispatch an event on the cards themselves.
- if (previousCard) {
- cr.dispatchSimpleEvent(previousCard, 'carddeselected', true, true);
- }
- cr.dispatchSimpleEvent(
- this.currentCardValue, 'cardselected', true, true);
- }
-
- // If we're not changing, animated, or transitioning, fire a
- // cardSlider:card_change_ended event right away.
- if ((!isChangingCard || !opt_animate || !willTransitionHappen) &&
- !opt_dontNotify) {
- this.fireChangeEndedEvent_(false);
- }
- },
-
- /**
- * Selects a card from the stack. Passes through to selectCard.
- * @param {!Element} newCard The card that should be selected.
- * @param {boolean=} opt_animate Whether to animate.
- */
- selectCardByValue(newCard, opt_animate) {
- const i = this.cards_.indexOf(newCard);
- assert(i !== -1);
- this.selectCard(i, opt_animate);
- },
-
- /**
- * Centers the view on the card denoted by this.currentCard. Can either
- * animate to that card or snap to it.
- * @param {boolean=} opt_animate If true will animate transition from
- * current position to new position.
- * @return {boolean} Whether or not a transformation was necessary.
- * @private
- */
- transformToCurrentCard_(opt_animate) {
- 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) {
- 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.
- let transition = '';
- if (opt_animate) {
- transition =
- 'transform ' + CardSlider.TRANSITION_TIME_ + 'ms ease-in-out';
- }
- this.container_.style.transition = transition;
- this.translateTo_(this.currentLeft_);
-
- return true;
- },
-
- /**
- * Moves the view to the specified position.
- * @param {number} x Horizontal position to move to.
- * @private
- */
- translateTo_(x) {
- // We use a transform to slide because this is GPU accelerated on
- // Chrome and iOS. Once Chrome does GPU acceleration on the position
- // fixed-layout elements we could simply set the element's position to
- // fixed and modify 'left' instead.
- this.deltaX_ = x - this.currentLeft_;
- this.container_.style.transform = 'translate3d(' + x + 'px, 0, 0)';
- },
-
- /* Touch ******************************************************************/
-
- /**
- * Clear any transition that is in progress and enable dragging for the
- * touch.
- * @param {!Event} e The TouchHandler event.
- * @private
- */
- onTouchStart_(e) {
- e = /** @type {!cr.ui.TouchHandler.Event} */ (e);
- this.container_.style.transition = '';
- e.enableDrag = true;
- },
-
- /**
- * Tell the TouchHandler that dragging is acceptable when the user begins by
- * scrolling horizontally and there is more than one card to slide.
- * @param {!Event} e The TouchHandler event.
- * @private
- */
- onDragStart_(e) {
- e = /** @type {!cr.ui.TouchHandler.Event} */ (e);
- e.enableDrag =
- this.cardCount > 1 && Math.abs(e.dragDeltaX) > Math.abs(e.dragDeltaY);
- },
-
- /**
- * On each drag move event reposition the container appropriately so the
- * cards look like they are sliding.
- * @param {!Event} e The TouchHandler event.
- * @private
- */
- onDragMove_(e) {
- e = /** @type {!cr.ui.TouchHandler.Event} */ (e);
- 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 ||
- this.currentCard === (this.cards_.length - 1) && deltaX < 0) {
- deltaX /= 2;
- }
- this.translateTo_(this.currentLeft_ + deltaX);
- },
-
- /**
- * On drag end events we may want to transition to another card, depending
- * on the ending position of the drag and the velocity of the drag.
- * @param {!Event} e The TouchHandler event.
- * @private
- */
- onDragEnd_(e) {
- e = /** @type {!cr.ui.TouchHandler.Event} */ (e);
- 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_) {
- // The drag wasn't far enough to change cards but the velocity was
- // high enough to transition anyways. If the velocity is to the left
- // (negative) then the user wishes to go right (card + 1).
- newCardIndex += velocity > 0 ? -1 : 1;
- }
- // 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) {
- newCardIndex = 0;
- } else if (newCardIndex >= this.cardCount) {
- newCardIndex = this.cardCount - 1;
- }
- this.selectCard(newCardIndex, /* animate */ true);
- },
-
- /**
- * Cancel any current touch/slide as if we saw a touch end
- */
- cancelTouch() {
- // Stop listening to any current touch
- this.touchHandler_.cancelTouch();
-
- // Ensure we're at a card bounary
- this.transformToCurrentCard_(true);
- },
- };
-
- return {CardSlider: CardSlider};
-});
diff --git a/chromium/ui/webui/resources/js/cr/ui/command.js b/chromium/ui/webui/resources/js/cr/ui/command.js
index 53257dff86a..73d14df8b83 100644
--- a/chromium/ui/webui/resources/js/cr/ui/command.js
+++ b/chromium/ui/webui/resources/js/cr/ui/command.js
@@ -301,6 +301,7 @@ cr.define('cr.ui', function() {
// Export
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
Command: Command,
CanExecuteEvent: CanExecuteEvent,
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 4a1bf527959..801d4bdd7ea 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
@@ -320,6 +320,7 @@ cr.define('cr.ui', function() {
// Export
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
contextMenuHandler: contextMenuHandler,
};
diff --git a/chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js b/chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js
deleted file mode 100644
index ad7c8556e45..00000000000
--- a/chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('cr.ui', function() {
- /** @const */ const BubbleButton = cr.ui.BubbleButton;
-
- /**
- * An indicator that can be placed on a UI element as a hint to the user that
- * the value is controlled by some external entity such as policy or an
- * extension.
- * @constructor
- * @extends {cr.ui.BubbleButton}
- */
- 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
- */
- let bubble;
-
- ControlledIndicator.prototype = {
- __proto__: cr.ui.BubbleButton.prototype,
-
- /**
- * Decorates the base element to show the proper icon.
- */
- decorate() {
- cr.ui.BubbleButton.prototype.decorate.call(this);
- this.classList.add('controlled-setting-indicator');
- },
-
- /**
- * Shows an informational bubble displaying |content|.
- * @param {HTMLDivElement} content The content of the bubble.
- */
- showBubble(content) {
- this.hideBubble();
-
- bubble = new cr.ui.AutoCloseBubble;
- bubble.anchorNode = this.image;
- bubble.domSibling = this;
- bubble.arrowLocation = this.location;
- bubble.content = content;
- bubble.show();
- },
-
- /**
- * Hides the currently visible bubble, if any.
- */
- hideBubble() {
- if (bubble) {
- bubble.hide();
- }
- },
-
- /**
- * Returns a dictionary of the form { |controlled-by|: |bubbleText| }, where
- * |controlled-by| is a valid value of the controlled-by property (see
- * below), i.e. 'policy'. |bubbleText| is the default text to be shown for
- * UI items with this controlled-by property value. The default
- * implementation does not set any strings.
- * @return {Object}
- */
- getDefaultStrings() {
- return {};
- },
-
- /**
- * Returns the text shown in the bubble.
- * @return {string}
- */
- getBubbleText() {
- const defaultStrings = this.getDefaultStrings();
- let text = defaultStrings[this.controlledBy];
-
- if (this.hasAttribute('text' + this.controlledBy)) {
- text = this.getAttribute('text' + this.controlledBy);
- } else if (this.controlledBy === 'extension' && this['extensionName']) {
- text = defaultStrings['extensionWithName'];
- }
-
- return text || '';
- },
-
- /**
- * Returns the DOM tree for a showing the message |text|.
- * @param {string} text to be shown in the bubble.
- */
- createDomTree(text) {
- const content = document.createElement('div');
- content.textContent = text;
- return content;
- },
-
- /**
- * Open or close a bubble with further information about the pref.
- * @override
- */
- toggleBubble() {
- if (this.showingBubble) {
- this.hideBubble();
- } else {
- this.showBubble(this.createDomTree(this.getBubbleText()));
- }
- },
- };
-
- /**
- * The status of the associated preference:
- * - 'policy': A specific value is enforced by policy.
- * - 'extension': A specific value is enforced by an extension.
- * - 'recommended': A value is recommended by policy. The user could
- * override this recommendation but has not done so.
- * - 'hasRecommendation': A value is recommended by policy. The user has
- * overridden this recommendation.
- * - 'owner': A value is controlled by the owner of the device
- * (Chrome OS only).
- * - 'shared': A value belongs to the primary user but can be
- * modified (Chrome OS only).
- * - unset: The value is controlled by the user alone.
- */
- cr.defineProperty(ControlledIndicator, 'controlledBy', cr.PropertyKind.ATTR);
-
- return {ControlledIndicator: ControlledIndicator};
-});
diff --git a/chromium/ui/webui/resources/js/cr/ui/dialogs.js b/chromium/ui/webui/resources/js/cr/ui/dialogs.js
index 6c17b44d3b5..c645f29665a 100644
--- a/chromium/ui/webui/resources/js/cr/ui/dialogs.js
+++ b/chromium/ui/webui/resources/js/cr/ui/dialogs.js
@@ -18,6 +18,18 @@ cr.define('cr.ui.dialogs', function() {
// so we can restore it when we're hidden.
this.previousActiveElement_ = null;
+ /**
+ * If set true, BaseDialog assumes that focus traversal of elements inside
+ * the dialog due to 'Tab' key events is handled by its container (and the
+ * practical example is this.parentNode_ is a modal <dialog> element).
+ *
+ * The default is false: BaseDialog handles focus traversal for the entire
+ * DOM document. See findFocusableElements_(), also crbug.com/1078300.
+ *
+ * @protected {boolean}
+ */
+ this.hasModalContainer = false;
+
/** @private{boolean} */
this.showing_ = false;
@@ -245,14 +257,21 @@ cr.define('cr.ui.dialogs', function() {
BaseDialog.prototype.show_ = function(
title, opt_onOk, opt_onCancel, opt_onShow) {
this.showing_ = true;
- // Make all outside nodes unfocusable while the dialog is active.
- this.deactivatedNodes_ = this.findFocusableElements_(this.document_);
- this.tabIndexes_ = this.deactivatedNodes_.map(function(n) {
- return n.getAttribute('tabindex');
- });
- this.deactivatedNodes_.forEach(function(n) {
- n.tabIndex = -1;
- });
+
+ // Modal containers manage dialog focus traversal. Otherwise, the focus
+ // is managed by |this| dialog, by making all outside nodes unfocusable
+ // while the dialog is shown.
+ if (!this.hasModalContainer) {
+ this.deactivatedNodes_ = this.findFocusableElements_(this.document_);
+ this.tabIndexes_ = this.deactivatedNodes_.map(function(n) {
+ return n.getAttribute('tabindex');
+ });
+ this.deactivatedNodes_.forEach(function(n) {
+ n.tabIndex = -1;
+ });
+ } else {
+ this.deactivatedNodes_ = [];
+ }
this.previousActiveElement_ = this.document_.activeElement;
this.parentNode_.appendChild(this.container);
@@ -288,7 +307,8 @@ cr.define('cr.ui.dialogs', function() {
/** @param {Function=} opt_onHide */
BaseDialog.prototype.hide = function(opt_onHide) {
this.showing_ = false;
- // Restore focusability.
+
+ // Restore focusability for the non-modal container case.
for (let i = 0; i < this.deactivatedNodes_.length; i++) {
const node = this.deactivatedNodes_[i];
if (this.tabIndexes_[i] === null) {
@@ -301,13 +321,13 @@ cr.define('cr.ui.dialogs', function() {
this.tabIndexes_ = null;
this.container.classList.remove('shown');
+ this.container.classList.remove('pulse');
if (this.previousActiveElement_) {
this.previousActiveElement_.focus();
} else {
this.document_.body.focus();
}
- this.frame.classList.remove('pulse');
const self = this;
setTimeout(function() {
@@ -417,6 +437,7 @@ cr.define('cr.ui.dialogs', function() {
};
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
BaseDialog: BaseDialog,
AlertDialog: AlertDialog,
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 af78b675f05..3aae1c7d2bb 100644
--- a/chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js
+++ b/chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js
@@ -140,6 +140,7 @@ cr.define('cr.ui', function() {
}
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
DragWrapper: DragWrapper,
DragWrapperDelegate: DragWrapperDelegate,
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 48824fc0301..151749bba59 100644
--- a/chromium/ui/webui/resources/js/cr/ui/focus_grid.js
+++ b/chromium/ui/webui/resources/js/cr/ui/focus_grid.js
@@ -187,6 +187,7 @@ cr.define('cr.ui', function() {
}
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
FocusGrid: FocusGrid,
};
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 461c172aee5..706afc3933a 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
@@ -87,5 +87,6 @@ cr.define('cr.ui', function() {
}
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {FocusOutlineManager: FocusOutlineManager};
});
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
index 1695e4ff438..2103e4f3648 100644
--- a/chromium/ui/webui/resources/js/cr/ui/focus_row_behavior.js
+++ b/chromium/ui/webui/resources/js/cr/ui/focus_row_behavior.js
@@ -383,6 +383,7 @@ cr.define('cr.ui', function() {
};
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
FocusRowBehaviorDelegate,
VirtualFocusRow,
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 33219cba986..884e910dc70 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
@@ -48,5 +48,6 @@ cr.define('cr.ui', function() {
};
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
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 7c372342876..bdf950353a4 100644
--- a/chromium/ui/webui/resources/js/cr/ui/grid.js
+++ b/chromium/ui/webui/resources/js/cr/ui/grid.js
@@ -444,6 +444,7 @@ cr.define('cr.ui', function() {
};
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
Grid: Grid,
GridItem: GridItem,
diff --git a/chromium/ui/webui/resources/js/cr/ui/keyboard_shortcut_list.js b/chromium/ui/webui/resources/js/cr/ui/keyboard_shortcut_list.js
index 65f9c89fd48..0322d992dd3 100644
--- a/chromium/ui/webui/resources/js/cr/ui/keyboard_shortcut_list.js
+++ b/chromium/ui/webui/resources/js/cr/ui/keyboard_shortcut_list.js
@@ -91,6 +91,7 @@ cr.define('cr.ui', function() {
}
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
KeyboardShortcutList: KeyboardShortcutList,
};
diff --git a/chromium/ui/webui/resources/js/cr/ui/list.js b/chromium/ui/webui/resources/js/cr/ui/list.js
index d68e3160eca..c0eaff10884 100644
--- a/chromium/ui/webui/resources/js/cr/ui/list.js
+++ b/chromium/ui/webui/resources/js/cr/ui/list.js
@@ -1399,11 +1399,8 @@ cr.define('cr.ui', function() {
* @param {Event} e The mouse event object.
*/
function handleMouseDown(e) {
- e.target = /** @type {!HTMLElement} */ (e.target);
- const listItem = this.getListItemAncestor(e.target);
- if (!listItem) {
- return;
- }
+ const target = /** @type {!HTMLElement} */ (e.target);
+ const listItem = this.getListItemAncestor(target);
const wasSelected = listItem && listItem.selected;
this.handlePointerDownUp_(e);
@@ -1422,7 +1419,7 @@ cr.define('cr.ui', function() {
//
// [1] For example, clicking non-focusable area gives focus on the first
// form control in the item.
- if (!containsFocusableElement(e.target, listItem) &&
+ if (!containsFocusableElement(target, listItem) &&
listItem.contains(listItem.ownerDocument.activeElement)) {
e.preventDefault();
}
@@ -1473,6 +1470,7 @@ cr.define('cr.ui', function() {
}
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
List: List,
Size: Size,
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 a2c1ba8f1d9..71164ca173a 100644
--- a/chromium/ui/webui/resources/js/cr/ui/list_item.js
+++ b/chromium/ui/webui/resources/js/cr/ui/list_item.js
@@ -90,5 +90,6 @@ cr.define('cr.ui', function() {
ListItem.prototype, 'listIndex', cr.getPropertyDescriptor('listIndex'));
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {ListItem: ListItem};
});
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 0692f919594..f6ed0f99bfe 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
@@ -308,5 +308,6 @@ cr.define('cr.ui', function() {
};
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {ListSelectionController: ListSelectionController};
});
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 bd49f601684..f3774d6e678 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
@@ -397,5 +397,6 @@ cr.define('cr.ui', function() {
}
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {ListSelectionModel: ListSelectionModel};
});
diff --git a/chromium/ui/webui/resources/js/cr/ui/menu.js b/chromium/ui/webui/resources/js/cr/ui/menu.js
index 1f4fe262370..e45910eb444 100644
--- a/chromium/ui/webui/resources/js/cr/ui/menu.js
+++ b/chromium/ui/webui/resources/js/cr/ui/menu.js
@@ -400,5 +400,6 @@ cr.define('cr.ui', function() {
// Export
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {Menu: Menu};
});
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 3b9d998d110..0cfd92b6fb0 100644
--- a/chromium/ui/webui/resources/js/cr/ui/menu_button.js
+++ b/chromium/ui/webui/resources/js/cr/ui/menu_button.js
@@ -351,6 +351,7 @@ cr.define('cr.ui', function() {
// Export
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
HideType: HideType,
MenuButton: MenuButton,
diff --git a/chromium/ui/webui/resources/js/cr/ui/overlay.js b/chromium/ui/webui/resources/js/cr/ui/overlay.js
deleted file mode 100644
index 4790f5b4461..00000000000
--- a/chromium/ui/webui/resources/js/cr/ui/overlay.js
+++ /dev/null
@@ -1,158 +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.
-
-/**
- * @fileoverview Provides dialog-like behaviors for the tracing UI.
- */
-cr.define('cr.ui.overlay', function() {
- /**
- * Gets the top, visible overlay. It makes the assumption that if multiple
- * overlays are visible, the last in the byte order is topmost.
- * TODO(estade): rely on aria-visibility instead?
- * @return {HTMLElement} The overlay.
- */
- function getTopOverlay() {
- const overlays = /** @type !NodeList<!HTMLElement> */ (
- document.querySelectorAll('.overlay:not([hidden])'));
- return overlays[overlays.length - 1];
- }
-
- /**
- * Returns a visible default button of the overlay, if it has one. If the
- * overlay has more than one, the first one will be returned.
- *
- * @param {HTMLElement} overlay The .overlay.
- * @return {HTMLElement} The default button.
- */
- function getDefaultButton(overlay) {
- function isHidden(node) {
- return node.hidden;
- }
- const defaultButtons = /** @type !NodeList<!HTMLElement> */ (
- overlay.querySelectorAll('.page .button-strip > .default-button'));
- for (let i = 0; i < defaultButtons.length; i++) {
- if (!findAncestor(defaultButtons[i], isHidden)) {
- return defaultButtons[i];
- }
- }
- return null;
- }
-
- /** @type {boolean} */
- let globallyInitialized = false;
-
- /**
- * Makes initializations which must hook at the document level.
- */
- function globalInitialization() {
- if (!globallyInitialized) {
- document.addEventListener('keydown', function(e) {
- const overlay = getTopOverlay();
- if (!overlay) {
- return;
- }
-
- // Close the overlay on 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.
- const forbiddenTagNames = /^(A|BUTTON|SELECT|TEXTAREA)$/;
- if (e.key === 'Enter' &&
- !forbiddenTagNames.test(document.activeElement.tagName)) {
- const button = getDefaultButton(overlay);
- if (button) {
- button.click();
- // Executing the default button may result in focus moving to a
- // different button. Calling preventDefault is necessary to not have
- // that button execute as well.
- e.preventDefault();
- }
- }
- });
-
- window.addEventListener('resize', setMaxHeightAllPages);
- globallyInitialized = true;
- }
-
- setMaxHeightAllPages();
- }
-
- /**
- * Sets the max-height of all pages in all overlays, based on the window
- * height.
- */
- function setMaxHeightAllPages() {
- const pages =
- document.querySelectorAll('.overlay .page:not(.not-resizable)');
-
- const maxHeight = Math.min(0.9 * window.innerHeight, 640) + 'px';
- for (let i = 0; i < pages.length; i++) {
- pages[i].style.maxHeight = maxHeight;
- }
- }
-
- /**
- * Adds behavioral hooks for the given overlay.
- * @param {HTMLElement} overlay The .overlay.
- *
- * TODO(crbug.com/425829): This function makes use of deprecated getter or
- * setter functions.
- * @suppress {deprecated}
- */
- function setupOverlay(overlay) {
- // Close the overlay on clicking any of the pages' close buttons.
- 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) {
- cr.ui.FocusOutlineManager.forDocument(document).updateVisibility();
- }
- cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
- });
- }
-
- // TODO(crbug.com/425829): Remove above suppression once we no longer use
- // deprecated functions defineSetter, and defineGetter.
- // Remove the 'pulse' animation any time the overlay is hidden or shown.
- // eslint-disable-next-line no-restricted-properties
- overlay.__defineSetter__('hidden', function(value) {
- this.classList.remove('pulse');
- if (value) {
- this.setAttribute('hidden', true);
- } else {
- this.removeAttribute('hidden');
- }
- });
- // eslint-disable-next-line no-restricted-properties
- overlay.__defineGetter__('hidden', function() {
- return this.hasAttribute('hidden');
- });
-
- // 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) {
- return;
- }
-
- // This may be null while the overlay is closing.
- const overlayPage = this.querySelector('.page:not([hidden])');
- if (overlayPage) {
- overlayPage.classList.add('pulse');
- }
- });
- overlay.addEventListener('animationend', function(e) {
- e.target.classList.remove('pulse');
- });
- }
-
- return {
- getDefaultButton: getDefaultButton,
- globalInitialization: globalInitialization,
- setupOverlay: setupOverlay,
- };
-});
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 40b59f7c1f9..8357b57d1ce 100644
--- a/chromium/ui/webui/resources/js/cr/ui/position_util.js
+++ b/chromium/ui/webui/resources/js/cr/ui/position_util.js
@@ -239,6 +239,7 @@ cr.define('cr.ui', function() {
// Export
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
AnchorType: AnchorType,
positionPopupAroundElement: positionPopupAroundElement,
diff --git a/chromium/ui/webui/resources/js/cr/ui/splitter.js b/chromium/ui/webui/resources/js/cr/ui/splitter.js
index 0c214cf4fa9..93941da675d 100644
--- a/chromium/ui/webui/resources/js/cr/ui/splitter.js
+++ b/chromium/ui/webui/resources/js/cr/ui/splitter.js
@@ -278,5 +278,6 @@ cr.define('cr.ui', function() {
};
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {Splitter: Splitter};
});
diff --git a/chromium/ui/webui/resources/js/cr/ui/store.js b/chromium/ui/webui/resources/js/cr/ui/store.js
index c1d12c80505..d7d735ab7aa 100644
--- a/chromium/ui/webui/resources/js/cr/ui/store.js
+++ b/chromium/ui/webui/resources/js/cr/ui/store.js
@@ -159,6 +159,7 @@ cr.define('cr.ui', function() {
}
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
Action: Action,
DeferredAction: DeferredAction,
diff --git a/chromium/ui/webui/resources/js/cr/ui/store_client.js b/chromium/ui/webui/resources/js/cr/ui/store_client.js
index 519efbacbb4..e2ba2efaadd 100644
--- a/chromium/ui/webui/resources/js/cr/ui/store_client.js
+++ b/chromium/ui/webui/resources/js/cr/ui/store_client.js
@@ -135,6 +135,7 @@ cr.define('cr.ui', function() {
};
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
StoreClient: StoreClient,
};
diff --git a/chromium/ui/webui/resources/js/cr/ui/tabs.js b/chromium/ui/webui/resources/js/cr/ui/tabs.js
index 45d51ce3985..522ec843696 100644
--- a/chromium/ui/webui/resources/js/cr/ui/tabs.js
+++ b/chromium/ui/webui/resources/js/cr/ui/tabs.js
@@ -246,6 +246,7 @@ cr.define('cr.ui', function() {
cr.getPropertyDescriptor('selected', cr.PropertyKind.BOOL_ATTR));
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
TabBox: TabBox,
Tabs: Tabs,
diff --git a/chromium/ui/webui/resources/js/cr/ui/touch_handler.js b/chromium/ui/webui/resources/js/cr/ui/touch_handler.js
deleted file mode 100644
index d7135393662..00000000000
--- a/chromium/ui/webui/resources/js/cr/ui/touch_handler.js
+++ /dev/null
@@ -1,884 +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.
-
-/**
- * @fileoverview Touch Handler. Class that handles all touch events and
- * uses them to interpret higher level gestures and behaviors. TouchEvent is a
- * built in mobile safari type:
- * http://developer.apple.com/safari/library/documentation/UserExperience/Reference/TouchEventClassReference/TouchEvent/TouchEvent.html.
- * This class is intended to work with all webkit browsers, tested on Chrome and
- * iOS.
- *
- * The following types of gestures are currently supported. See the definition
- * of TouchHandler.EventType for details.
- *
- * Single Touch:
- * This provides simple single-touch events. Any secondary touch is
- * ignored.
- *
- * Drag:
- * A single touch followed by some movement. This behavior will handle all
- * of the required events and report the properties of the drag to you
- * while the touch is happening and at the end of the drag sequence. This
- * behavior will NOT perform the actual dragging (redrawing the element)
- * for you, this responsibility is left to the client code.
- *
- * Long press:
- * When your element is touched and held without any drag occuring, the
- * LONG_PRESS event will fire.
- */
-
-// Use an anonymous function to enable strict mode just for this file (which
-// will be concatenated with other files when embedded in Chrome)
-cr.define('cr.ui', function() {
- 'use strict';
-
- /**
- * A TouchHandler attaches to an Element, listents for low-level touch (or
- * mouse) events and dispatching higher-level events on the element.
- * @param {!Element} element The element to listen on and fire events
- * for.
- * @constructor
- */
- function TouchHandler(element) {
- /**
- * @type {!Element}
- * @private
- */
- this.element_ = element;
-
- /**
- * The absolute sum of all touch y deltas.
- * @type {number}
- * @private
- */
- this.totalMoveY_ = 0;
-
- /**
- * The absolute sum of all touch x deltas.
- * @type {number}
- * @private
- */
- this.totalMoveX_ = 0;
-
- /**
- * An array of tuples where the first item is the horizontal component of a
- * recent relevant touch and the second item is the touch's time stamp. Old
- * touches are removed based on the max tracking time and when direction
- * changes.
- * @type {!Array<number>}
- * @private
- */
- this.recentTouchesX_ = [];
-
- /**
- * An array of tuples where the first item is the vertical component of a
- * recent relevant touch and the second item is the touch's time stamp. Old
- * touches are removed based on the max tracking time and when direction
- * changes.
- * @type {!Array<number>}
- * @private
- */
- this.recentTouchesY_ = [];
-
- /**
- * Used to keep track of all events we subscribe to so we can easily clean
- * up
- * @type {EventTracker}
- * @private
- */
- this.events_ = new EventTracker();
- }
-
-
- /**
- * DOM Events that may be fired by the TouchHandler at the element
- */
- TouchHandler.EventType = {
- // Fired whenever the element is touched as the only touch to the device.
- // enableDrag defaults to false, set to true to permit dragging.
- TOUCH_START: 'touchHandler:touch_start',
-
- // Fired when an element is held for a period of time. Prevents dragging
- // from occuring (even if enableDrag was set to true).
- LONG_PRESS: 'touchHandler:long_press',
-
- // If enableDrag was set to true at TOUCH_START, DRAG_START will fire when
- // the touch first moves sufficient distance. enableDrag is set to true but
- // can be reset to false to cancel the drag.
- DRAG_START: 'touchHandler:drag_start',
-
- // If enableDrag was true after DRAG_START, DRAG_MOVE will fire whenever the
- // touch is moved.
- DRAG_MOVE: 'touchHandler:drag_move',
-
- // Fired just before TOUCH_END when a drag is released. Correlates 1:1 with
- // a DRAG_START.
- DRAG_END: 'touchHandler:drag_end',
-
- // Fired whenever a touch that is being tracked has been released.
- // Correlates 1:1 with a TOUCH_START.
- TOUCH_END: 'touchHandler:touch_end',
-
- // Fired whenever the element is tapped in a short time and no dragging is
- // detected.
- TAP: 'touchHandler:tap'
- };
-
-
- /**
- * The type of event sent by TouchHandler
- * @constructor
- * @extends {Event}
- * @param {string} type The type of event (one of cr.ui.Grabber.EventType).
- * @param {boolean} bubbles Whether or not the event should bubble.
- * @param {number} clientX The X location of the touch.
- * @param {number} clientY The Y location of the touch.
- * @param {!Element} touchedElement The element at the current location of the
- * touch.
- */
- TouchHandler.Event = function(
- type, bubbles, clientX, clientY, touchedElement) {
- const event = document.createEvent('Event');
- event.initEvent(type, bubbles, true);
- event.__proto__ = TouchHandler.Event.prototype;
-
- /**
- * The X location of the touch affected
- * @type {number}
- */
- event.clientX = clientX;
-
- /**
- * The Y location of the touch affected
- * @type {number}
- */
- event.clientY = clientY;
-
- /**
- * The element at the current location of the touch.
- * @type {!Element}
- */
- event.touchedElement = touchedElement;
-
- return event;
- };
-
- TouchHandler.Event.prototype = {
- __proto__: Event.prototype,
-
- /**
- * For TOUCH_START and DRAG START events, set to true to enable dragging or
- * false to disable dragging.
- * @type {boolean|undefined}
- */
- enableDrag: undefined,
-
- /**
- * For DRAG events, provides the horizontal component of the
- * drag delta. Drag delta is defined as the delta of the start touch
- * position and the current drag position.
- * @type {number|undefined}
- */
- dragDeltaX: undefined,
-
- /**
- * For DRAG events, provides the vertical component of the
- * drag delta.
- * @type {number|undefined}
- */
- dragDeltaY: undefined
- };
-
- /**
- * Maximum movement of touch required to be considered a tap.
- * @type {number}
- * @private
- */
- 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.
- * @type {number}
- * @private
- */
- TouchHandler.MAX_TRACKING_TIME_ = 250;
-
- /**
- * The maximum number of touches to track.
- * @type {number}
- * @private
- */
- 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
- * very fast drag velocity.
- * @type {number}
- * @private
- */
- 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
- * thread is blocked for the duration of the drag. This is a low velocity to
- * prevent the content from moving quickly after a slow drag. It is less
- * jarring if the content moves slowly after a fast drag.
- * @type {number}
- * @private
- */
- TouchHandler.VELOCITY_FOR_INCORRECT_EVENTS_ = 1;
-
- /**
- * The time, in milliseconds, that a touch must be held to be considered
- * 'long'.
- * @type {number}
- * @private
- */
- TouchHandler.TIME_FOR_LONG_PRESS_ = 500;
-
- TouchHandler.prototype = {
- /**
- * If defined, the identifer of the single touch that is active. Note that
- * 0 is a valid touch identifier - it should not be treated equivalently to
- * undefined.
- * @type {number|undefined}
- * @private
- */
- activeTouch_: undefined,
-
- /**
- * @type {boolean|undefined}
- * @private
- */
- tracking_: undefined,
-
- /**
- * @type {number|undefined}
- * @private
- */
- startTouchX_: undefined,
-
- /**
- * @type {number|undefined}
- * @private
- */
- startTouchY_: undefined,
-
- /**
- * @type {number|undefined}
- * @private
- */
- endTouchX_: undefined,
-
- /**
- * @type {number|undefined}
- * @private
- */
- endTouchY_: undefined,
-
- /**
- * Time of the touchstart event.
- * @type {number|undefined}
- * @private
- */
- startTime_: undefined,
-
- /**
- * The time of the touchend event.
- * @type {number|undefined}
- * @private
- */
- endTime_: undefined,
-
- /**
- * @type {number|undefined}
- * @private
- */
- lastTouchX_: undefined,
-
- /**
- * @type {number|undefined}
- * @private
- */
- lastTouchY_: undefined,
-
- /**
- * @type {number|undefined}
- * @private
- */
- lastMoveX_: undefined,
-
- /**
- * @type {number|undefined}
- * @private
- */
- lastMoveY_: undefined,
-
- /**
- * @type {number|undefined}
- * @private
- */
- longPressTimeout_: undefined,
-
- /**
- * If defined and true, the next click event should be swallowed
- * @type {boolean|undefined}
- * @private
- */
- swallowNextClick_: undefined,
-
- /**
- * @type {boolean}
- * @private
- */
- draggingEnabled_: false,
-
- /**
- * Start listenting for events.
- * @param {boolean=} opt_capture True if the TouchHandler should listen to
- * during the capture phase.
- * @param {boolean=} opt_mouse True if the TouchHandler should generate
- * events for mouse input (in addition to touch input).
- */
- enable(opt_capture, opt_mouse) {
- 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
- // don't want to incur the cost of lots of no-op handlers on the document.
- this.events_.add(
- this.element_, 'touchstart', this.onStart_.bind(this), capture);
- if (opt_mouse) {
- this.events_.add(
- this.element_, 'mousedown',
- this.mouseToTouchCallback_(this.onStart_.bind(this)), capture);
- }
-
- // If the element is long-pressed, we may need to swallow a click
- this.events_.add(this.element_, 'click', this.onClick_.bind(this), true);
- },
-
- /**
- * Stop listening to all events.
- */
- disable() {
- this.stopTouching_();
- this.events_.removeAll();
- },
-
- /**
- * Wraps a callback with translations of mouse events to touch events.
- * NOTE: These types really should be function(Event) but then we couldn't
- * use this with bind (which operates on any type of function). Doesn't
- * JSDoc support some sort of polymorphic types?
- * @param {Function} callback The event callback.
- * @return {Function} The wrapping callback.
- * @private
- */
- mouseToTouchCallback_(callback) {
- return function(e) {
- // Note that there may be synthesizes mouse events caused by touch
- // events (a mouseDown after a touch-click). We leave it up to the
- // 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).
- 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,
- clientX: e.clientX,
- clientY: e.clientY,
- target: e.target
- };
- e.touches = [];
- e.targetTouches = [];
- e.changedTouches = [touch];
- if (e.type !== 'mouseup') {
- e.touches[0] = touch;
- e.targetTouches[0] = touch;
- }
- callback(e);
- };
- },
-
- /**
- * Begin tracking the touchable element, it is eligible for dragging.
- * @private
- */
- beginTracking_() {
- this.tracking_ = true;
- },
-
- /**
- * Stop tracking the touchable element, it is no longer dragging.
- * @private
- */
- endTracking_() {
- this.tracking_ = false;
- this.dragging_ = false;
- this.totalMoveY_ = 0;
- this.totalMoveX_ = 0;
- },
-
- /**
- * Reset the touchable element as if we never saw the touchStart
- * Doesn't dispatch any end events - be careful of existing listeners.
- */
- cancelTouch() {
- this.stopTouching_();
- this.endTracking_();
- // If clients needed to be aware of this, we could fire a cancel event
- // here.
- },
-
- /**
- * Record that touching has stopped
- * @private
- */
- stopTouching_() {
- // Mark as no longer being touched
- this.activeTouch_ = undefined;
-
- // If we're waiting for a long press, stop
- window.clearTimeout(this.longPressTimeout_);
-
- // Stop listening for move/end events until there's another touch.
- // We don't want to leave handlers piled up on the document.
- // Note that there's no harm in removing handlers that weren't added, so
- // rather than track whether we're using mouse or touch we do both.
- this.events_.remove(document, 'touchmove');
- this.events_.remove(document, 'touchend');
- this.events_.remove(document, 'touchcancel');
- this.events_.remove(document, 'mousemove');
- this.events_.remove(document, 'mouseup');
- },
-
- /**
- * Touch start handler.
- * @param {!TouchEvent} e The touchstart event.
- * @private
- */
- onStart_(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) {
- // 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) {
- return;
- }
-
- const touch = e.targetTouches[0];
- this.activeTouch_ = touch.identifier;
-
- // We've just started touching so shouldn't swallow any upcoming click
- if (this.swallowNextClick_) {
- this.swallowNextClick_ = false;
- }
-
- this.disableTap_ = false;
-
- // Sign up for end/cancel notifications for this touch.
- // Note that we do this on the document so that even if the user drags
- // their finger off the element, we'll still know what they're doing.
- if (e.type === 'mousedown') {
- this.events_.add(
- document, 'mouseup',
- this.mouseToTouchCallback_(this.onEnd_.bind(this)), false);
- } else {
- this.events_.add(document, 'touchend', this.onEnd_.bind(this), false);
- this.events_.add(
- document, 'touchcancel', this.onEnd_.bind(this), false);
- }
-
- // This timeout is cleared on touchEnd and onDrag
- // If we invoke the function then we have a real long press
- window.clearTimeout(this.longPressTimeout_);
- this.longPressTimeout_ = window.setTimeout(
- this.onLongPress_.bind(this), TouchHandler.TIME_FOR_LONG_PRESS_);
-
- // Dispatch the TOUCH_START event
- this.draggingEnabled_ =
- !!this.dispatchEvent_(TouchHandler.EventType.TOUCH_START, touch);
-
- // We want dragging notifications
- if (e.type === 'mousedown') {
- this.events_.add(
- document, 'mousemove',
- this.mouseToTouchCallback_(this.onMove_.bind(this)), false);
- } else {
- this.events_.add(document, 'touchmove', this.onMove_.bind(this), false);
- }
-
- this.startTouchX_ = this.lastTouchX_ = touch.clientX;
- this.startTouchY_ = this.lastTouchY_ = touch.clientY;
- this.startTime_ = e.timeStamp;
-
- this.recentTouchesX_ = [];
- this.recentTouchesY_ = [];
- this.recentTouchesX_.push(touch.clientX, e.timeStamp);
- this.recentTouchesY_.push(touch.clientY, e.timeStamp);
-
- this.beginTracking_();
- },
-
- /**
- * Given a list of Touches, find the one matching our activeTouch
- * identifier. Note that Chrome currently always uses 0 as the identifier.
- * In that case we'll end up always choosing the first element in the list.
- * @param {TouchList} touches The list of Touch objects to search.
- * @return {!Touch|undefined} The touch matching our active ID if any.
- * @private
- */
- findActiveTouch_(touches) {
- 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 (let i = 0; i < touches.length; i++) {
- if (touches[i].identifier === this.activeTouch_) {
- return touches[i];
- }
- }
- return undefined;
- },
-
- /**
- * Touch move handler.
- * @param {!TouchEvent} e The touchmove event.
- * @private
- */
- onMove_(e) {
- if (!this.tracking_) {
- return;
- }
-
- // Our active touch should always be in the list of touches still active
- assert(this.findActiveTouch_(e.touches), 'Missing touchEnd');
-
- const that = this;
- const touch = this.findActiveTouch_(e.changedTouches);
- if (!touch) {
- return;
- }
-
- const clientX = touch.clientX;
- const clientY = touch.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;
-
- const couldBeTap =
- this.totalMoveY_ <= TouchHandler.MAX_TRACKING_FOR_TAP_ ||
- this.totalMoveX_ <= TouchHandler.MAX_TRACKING_FOR_TAP_;
-
- if (!couldBeTap) {
- this.disableTap_ = true;
- }
-
- if (this.draggingEnabled_ && !this.dragging_ && !couldBeTap) {
- // If we're waiting for a long press, stop
- window.clearTimeout(this.longPressTimeout_);
-
- // Dispatch the DRAG_START event and record whether dragging should be
- // allowed or not. Note that this relies on the current value of
- // startTouchX/Y - handlers may use the initial drag delta to determine
- // if dragging should be permitted.
- this.dragging_ =
- this.dispatchEvent_(TouchHandler.EventType.DRAG_START, touch);
-
- if (this.dragging_) {
- // Update the start position here so that drag deltas have better
- // values but don't touch the recent positions so that velocity
- // calculations can still use touchstart position in the time and
- // distance delta.
- this.startTouchX_ = clientX;
- this.startTouchY_ = clientY;
- this.startTime_ = e.timeStamp;
- } else {
- this.endTracking_();
- }
- }
-
- if (this.dragging_) {
- this.dispatchEvent_(TouchHandler.EventType.DRAG_MOVE, touch);
-
- this.removeTouchesInWrongDirection_(
- this.recentTouchesX_, this.lastMoveX_, moveX);
- this.removeTouchesInWrongDirection_(
- this.recentTouchesY_, this.lastMoveY_, moveY);
- this.removeOldTouches_(this.recentTouchesX_, e.timeStamp);
- this.removeOldTouches_(this.recentTouchesY_, e.timeStamp);
- this.recentTouchesX_.push(clientX, e.timeStamp);
- this.recentTouchesY_.push(clientY, e.timeStamp);
- }
-
- this.lastMoveX_ = moveX;
- this.lastMoveY_ = moveY;
- },
-
- /**
- * Filters the provided recent touches array to remove all touches except
- * the last if the move direction has changed.
- * @param {!Array<number>} recentTouches An array of tuples where the first
- * item is the x or y component of the recent touch and the second item
- * is the touch time stamp.
- * @param {number|undefined} lastMove The x or y component of the previous
- * move.
- * @param {number} recentMove The x or y component of the most recent move.
- * @private
- */
- removeTouchesInWrongDirection_(recentTouches, lastMove, recentMove) {
- if (lastMove && recentMove && recentTouches.length > 2 &&
- (lastMove > 0 ^ recentMove > 0)) {
- recentTouches.splice(0, recentTouches.length - 2);
- }
- },
-
- /**
- * Filters the provided recent touches array to remove all touches older
- * than the max tracking time or the 5th most recent touch.
- * @param {!Array<number>} recentTouches An array of tuples where the first
- * item is the x or y component of the recent touch and the second item
- * is the touch time stamp.
- * @param {number} recentTime The time of the most recent event.
- * @private
- */
- removeOldTouches_(recentTouches, recentTime) {
- while (recentTouches.length &&
- recentTime - recentTouches[1] >
- TouchHandler.MAX_TRACKING_TIME_ ||
- recentTouches.length > TouchHandler.MAX_TRACKING_TOUCHES_ * 2) {
- recentTouches.splice(0, 2);
- }
- },
-
- /**
- * Touch end handler.
- * @param {!TouchEvent} e The touchend event.
- * @private
- */
- onEnd_(e) {
- 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.
- 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
- // occur at almost the same time with both having empty 'touches' lists.
- // I.e., 'touches' seems like it can be a bit more up to date than the
- // current event.
- return;
- }
-
- // This is touchEnd for the touch we're monitoring
- assert(
- !this.findActiveTouch_(e.touches), 'Touch ended also still active');
-
- // Indicate that touching has finished
- this.stopTouching_();
-
- if (this.tracking_) {
- const clientX = touch.clientX;
- const clientY = touch.clientY;
-
- if (this.dragging_) {
- this.endTime_ = e.timeStamp;
- this.endTouchX_ = clientX;
- this.endTouchY_ = clientY;
-
- this.removeOldTouches_(this.recentTouchesX_, e.timeStamp);
- this.removeOldTouches_(this.recentTouchesY_, e.timeStamp);
-
- this.dispatchEvent_(TouchHandler.EventType.DRAG_END, touch);
-
- // Note that in some situations we can get a click event here as well.
- // For now this isn't a problem, but we may want to consider having
- // some logic that hides clicks that appear to be caused by a touchEnd
- // used for dragging.
- }
-
- this.endTracking_();
- }
- this.draggingEnabled_ = false;
-
- // Note that we dispatch the touchEnd event last so that events at
- // different levels of semantics nest nicely (similar to how DOM
- // drag-and-drop events are nested inside of the mouse events that trigger
- // them).
- this.dispatchEvent_(TouchHandler.EventType.TOUCH_END, touch);
- if (!this.disableTap_) {
- this.dispatchEvent_(TouchHandler.EventType.TAP, touch);
- }
- },
-
- /**
- * Get end velocity of the drag. This method is specific to drag behavior,
- * so if touch behavior and drag behavior is split then this should go with
- * drag behavior. End velocity is defined as deltaXY / deltaTime where
- * deltaXY is the difference between endPosition and the oldest recent
- * position, and deltaTime is the difference between endTime and the oldest
- * recent time stamp.
- * @return {Object} The x and y velocity.
- */
- getEndVelocity() {
- // Note that we could move velocity to just be an end-event parameter.
- let velocityX = this.recentTouchesX_.length ?
- (this.endTouchX_ - this.recentTouchesX_[0]) /
- (this.endTime_ - this.recentTouchesX_[1]) :
- 0;
- let velocityY = this.recentTouchesY_.length ?
- (this.endTouchY_ - this.recentTouchesY_[0]) /
- (this.endTime_ - this.recentTouchesY_[1]) :
- 0;
-
- velocityX = this.correctVelocity_(velocityX);
- velocityY = this.correctVelocity_(velocityY);
-
- return {x: velocityX, y: velocityY};
- },
-
- /**
- * Correct erroneous velocities by capping the velocity if we think it's too
- * high, or setting it to a default velocity if know that the event data is
- * bad.
- * @param {number} velocity The x or y velocity component.
- * @return {number} The corrected velocity.
- * @private
- */
- correctVelocity_(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
- // for the duration of the drag and we received events in quick succession
- // with the wrong time stamps.
- if (absVelocity > TouchHandler.MAXIMUM_VELOCITY_) {
- absVelocity = this.recentTouchesY_.length < 3 ?
- TouchHandler.VELOCITY_FOR_INCORRECT_EVENTS_ :
- TouchHandler.MAXIMUM_VELOCITY_;
- }
- return absVelocity * (velocity < 0 ? -1 : 1);
- },
-
- /**
- * Handler when an element has been pressed for a long time
- * @private
- */
- onLongPress_() {
- // Swallow any click that occurs on this element without an intervening
- // touch start event. This simple click-busting technique should be
- // sufficient here since a real click should have a touchstart first.
- this.swallowNextClick_ = true;
- this.disableTap_ = true;
-
- // Dispatch to the LONG_PRESS
- assert(typeof this.startTouchX_ === 'number');
- assert(typeof this.startTouchY_ === 'number');
- this.dispatchEventXY_(
- TouchHandler.EventType.LONG_PRESS, this.element_,
- /** @type {number} */ (this.startTouchX_),
- /** @type {number} */ (this.startTouchY_));
- },
-
- /**
- * Click handler - used to swallow clicks after a long-press
- * @param {!Event} e The click event.
- * @private
- */
- onClick_(e) {
- if (this.swallowNextClick_) {
- e.preventDefault();
- e.stopPropagation();
- this.swallowNextClick_ = false;
- }
- },
-
- /**
- * Dispatch a TouchHandler event to the element
- * @param {string} eventType The event to dispatch.
- * @param {Touch} touch The touch triggering this event.
- * @return {boolean|undefined} The value of enableDrag after dispatching
- * the event.
- * @private
- */
- dispatchEvent_(eventType, touch) {
- // Determine which element was touched. For mouse events, this is always
- // the event/touch target. But for touch events, the target is always the
- // target of the touchstart (and it's unlikely we can change this
- // since the common implementation of touch dragging relies on it). Since
- // 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} */
- let touchedElement;
- if (eventType === TouchHandler.EventType.TOUCH_START) {
- touchedElement = assertInstanceof(touch.target, Element);
- } else {
- touchedElement = assert(this.element_.ownerDocument.elementFromPoint(
- touch.clientX, touch.clientY));
- }
-
- return this.dispatchEventXY_(
- eventType, touchedElement, touch.clientX, touch.clientY);
- },
-
- /**
- * Dispatch a TouchHandler event to the element
- * @param {string} eventType The event to dispatch.
- * @param {!Element} touchedElement
- * @param {number} clientX The X location for the event.
- * @param {number} clientY The Y location for the event.
- * @return {boolean|undefined} The value of enableDrag after dispatching
- * the event.
- * @private
- */
- dispatchEventXY_(eventType, touchedElement, clientX, clientY) {
- 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.
- const bubbles = !isDrag;
-
- const event = new TouchHandler.Event(
- eventType, bubbles, clientX, clientY, touchedElement);
-
- // Set enableDrag when it can be overridden
- if (eventType === TouchHandler.EventType.TOUCH_START) {
- event.enableDrag = false;
- } else if (eventType === TouchHandler.EventType.DRAG_START) {
- event.enableDrag = true;
- }
-
- if (isDrag) {
- event.dragDeltaX = clientX - this.startTouchX_;
- event.dragDeltaY = clientY - this.startTouchY_;
- }
-
- this.element_.dispatchEvent(event);
- return event.enableDrag;
- }
- };
-
- return {TouchHandler: TouchHandler};
-});
diff --git a/chromium/ui/webui/resources/js/cr/ui/tree.js b/chromium/ui/webui/resources/js/cr/ui/tree.js
index 3ce3a3c79e8..94a78f1d122 100644
--- a/chromium/ui/webui/resources/js/cr/ui/tree.js
+++ b/chromium/ui/webui/resources/js/cr/ui/tree.js
@@ -783,5 +783,6 @@ cr.define('cr.ui', function() {
// Export
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {Tree: Tree, TreeItem: TreeItem};
});
diff --git a/chromium/ui/webui/resources/js/event_tracker.js b/chromium/ui/webui/resources/js/event_tracker.js
index bad9b7f73d1..21fe8f72a22 100644
--- a/chromium/ui/webui/resources/js/event_tracker.js
+++ b/chromium/ui/webui/resources/js/event_tracker.js
@@ -89,3 +89,5 @@
* capture: boolean}}
*/
EventTracker.Entry;
+
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/js/i18n_behavior.js b/chromium/ui/webui/resources/js/i18n_behavior.js
index 022702fa77b..01acdcdba65 100644
--- a/chromium/ui/webui/resources/js/i18n_behavior.js
+++ b/chromium/ui/webui/resources/js/i18n_behavior.js
@@ -143,3 +143,5 @@
* }}
*/
I18nBehavior.Proto;
+
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/js/icon.js b/chromium/ui/webui/resources/js/icon.js
index 8376d8c7141..d0af7fd3c0d 100644
--- a/chromium/ui/webui/resources/js/icon.js
+++ b/chromium/ui/webui/resources/js/icon.js
@@ -154,6 +154,7 @@ cr.define('cr.icon', function() {
}
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
getFavicon: getFavicon,
getFaviconForPageURL: getFaviconForPageURL,
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 6812f5419cd..5a9f75a2abd 100644
--- a/chromium/ui/webui/resources/js/list_property_update_behavior.js
+++ b/chromium/ui/webui/resources/js/list_property_update_behavior.js
@@ -21,44 +21,62 @@
/* #export */ const ListPropertyUpdateBehavior = {
/**
* @param {string} propertyPath
- * @param {function(!Object): string} itemUidGetter
+ * @param {function(!Object): (!Object|string)} identityGetter
* @param {!Array<!Object>} updatedList
- * @param {boolean} uidBasedUpdate
+ * @param {boolean=} identityBasedUpdate
* @returns {boolean} True if notifySplices was called.
*/
- updateList(propertyPath, itemUidGetter, updatedList, uidBasedUpdate = false) {
- const list = this.get(propertyPath);
- const splices = Polymer.ArraySplice.calculateSplices(
- updatedList.map(itemUidGetter), list.map(itemUidGetter));
+ updateList(
+ propertyPath, identityGetter, updatedList, identityBasedUpdate = false) {
+ return updateListProperty(
+ this, propertyPath, identityGetter, updatedList, identityBasedUpdate);
+ },
+};
+
+/**
+ * @param {Object} instance
+ * @param {string} propertyPath
+ * @param {function(!Object): (!Object|string)} identityGetter
+ * @param {!Array<!Object>} updatedList
+ * @param {boolean=} identityBasedUpdate
+ * @returns {boolean} True if notifySplices was called.
+ */
+/* #export */ function updateListProperty(
+ instance, propertyPath, identityGetter, updatedList,
+ identityBasedUpdate = false) {
+ const list = instance.get(propertyPath);
+ const splices = Polymer.ArraySplice.calculateSplices(
+ updatedList.map(identityGetter), list.map(identityGetter));
+
+ splices.forEach(splice => {
+ const index = splice.index;
+ const deleteCount = splice.removed.length;
+ // Transform splices to the expected format of notifySplices().
+ // Convert !Array<string> to !Array<!Object>.
+ splice.removed = list.slice(index, index + deleteCount);
+ splice.object = list;
+ splice.type = 'splice';
- splices.forEach(splice => {
- const index = splice.index;
- const deleteCount = splice.removed.length;
- // Transform splices to the expected format of notifySplices().
- // Convert !Array<string> to !Array<!Object>.
- splice.removed = list.slice(index, index + deleteCount);
- splice.object = list;
- splice.type = 'splice';
+ const added = updatedList.slice(index, index + splice.addedCount);
+ const spliceParams = [index, deleteCount].concat(added);
+ list.splice.apply(list, spliceParams);
+ });
- const added = updatedList.slice(index, index + splice.addedCount);
- const spliceParams = [index, deleteCount].concat(added);
- list.splice.apply(list, spliceParams);
+ let updated = splices.length > 0;
+ if (!identityBasedUpdate) {
+ list.forEach((item, index) => {
+ const updatedItem = updatedList[index];
+ if (JSON.stringify(item) !== JSON.stringify(updatedItem)) {
+ instance.set([propertyPath, index], updatedItem);
+ updated = true;
+ }
});
+ }
- let updated = splices.length > 0;
- if (!uidBasedUpdate) {
- list.forEach((item, index) => {
- const updatedItem = updatedList[index];
- if (JSON.stringify(item) !== JSON.stringify(updatedItem)) {
- this.set([propertyPath, index], updatedItem);
- updated = true;
- }
- });
- }
+ if (splices.length > 0) {
+ instance.notifySplices(propertyPath, splices);
+ }
+ return updated;
+}
- if (splices.length > 0) {
- this.notifySplices(propertyPath, splices);
- }
- return updated;
- },
-};
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/js/load_time_data.js b/chromium/ui/webui/resources/js/load_time_data.js
index a4e3054b620..2935f76e1d7 100644
--- a/chromium/ui/webui/resources/js/load_time_data.js
+++ b/chromium/ui/webui/resources/js/load_time_data.js
@@ -243,3 +243,5 @@ function LoadTimeData(){}
// local.
window.loadTimeData = loadTimeData;
})();
+
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/js/parse_html_subset.js b/chromium/ui/webui/resources/js/parse_html_subset.js
index b5d25c37a42..95407fff946 100644
--- a/chromium/ui/webui/resources/js/parse_html_subset.js
+++ b/chromium/ui/webui/resources/js/parse_html_subset.js
@@ -84,14 +84,10 @@
* This policy maps a given string to a `TrustedHTML` object
* without performing any validation. Callsites must ensure
* that the resulting object will only be used in inert
- * documents.
+ * documents. Initialized lazily.
* @type {!TrustedTypePolicy}
*/
let unsanitizedPolicy;
- if (window.trustedTypes) {
- unsanitizedPolicy = trustedTypes.createPolicy(
- 'parse-html-subset', {createHTML: untrustedHTML => untrustedHTML});
- }
/**
* @param {!Array<string>} optTags an Array to merge.
@@ -154,6 +150,10 @@
r.selectNode(doc.body);
if (window.trustedTypes) {
+ if (!unsanitizedPolicy) {
+ unsanitizedPolicy = trustedTypes.createPolicy(
+ 'parse-html-subset', {createHTML: untrustedHTML => untrustedHTML});
+ }
s = unsanitizedPolicy.createHTML(s);
}
@@ -181,3 +181,5 @@
return df;
};
})();
+
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/js/plural_string_proxy.js b/chromium/ui/webui/resources/js/plural_string_proxy.js
index 5d38a70d862..801a4149222 100644
--- a/chromium/ui/webui/resources/js/plural_string_proxy.js
+++ b/chromium/ui/webui/resources/js/plural_string_proxy.js
@@ -20,6 +20,32 @@ export class PluralStringProxy {
* string for |messageName| with |itemCount| items.
*/
getPluralString(messageName, itemCount) {}
+
+ /**
+ * Fetches both plural strings, concatenated to one string with a comma.
+ * @param {!string} messageName1 The name of the first message.
+ * @param {!number} itemCount1 The number of items in the first message.
+ * @param {!string} messageName2 The name of the second message.
+ * @param {!number} itemCount2 The number of items in the second message.
+ * @return {!Promise<string>} Promise resolved with the appropriate plural
+ * strings for both messages, concatenated with a comma+whitespace in
+ * between them.
+ */
+ getPluralStringTupleWithComma(
+ messageName1, itemCount1, messageName2, itemCount2) {}
+
+ /**
+ * Fetches both plural strings, concatenated to one string with periods.
+ * @param {!string} messageName1 The name of the first message.
+ * @param {!number} itemCount1 The number of items in the first message.
+ * @param {!string} messageName2 The name of the second message.
+ * @param {!number} itemCount2 The number of items in the second message.
+ * @return {!Promise<string>} Promise resolved with the appropriate plural
+ * strings for both messages, concatenated with a period+whitespace after
+ * the first message, and a period after the second message.
+ */
+ getPluralStringTupleWithPeriods(
+ messageName1, itemCount1, messageName2, itemCount2) {}
}
/** @implements {PluralStringProxy} */
@@ -28,6 +54,22 @@ export class PluralStringProxyImpl {
getPluralString(messageName, itemCount) {
return sendWithPromise('getPluralString', messageName, itemCount);
}
+
+ /** @override */
+ getPluralStringTupleWithComma(
+ messageName1, itemCount1, messageName2, itemCount2) {
+ return sendWithPromise(
+ 'getPluralStringTupleWithComma', messageName1, itemCount1, messageName2,
+ itemCount2);
+ }
+
+ /** @override */
+ getPluralStringTupleWithPeriods(
+ messageName1, itemCount1, messageName2, itemCount2) {
+ return sendWithPromise(
+ 'getPluralStringTupleWithPeriods', messageName1, itemCount1,
+ messageName2, itemCount2);
+ }
}
addSingletonGetter(PluralStringProxyImpl);
diff --git a/chromium/ui/webui/resources/js/promise_resolver.js b/chromium/ui/webui/resources/js/promise_resolver.js
index 20a88b42947..cd78115b6b1 100644
--- a/chromium/ui/webui/resources/js/promise_resolver.js
+++ b/chromium/ui/webui/resources/js/promise_resolver.js
@@ -80,3 +80,5 @@
assertNotReached();
}
};
+
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/js/search_highlight_utils.js b/chromium/ui/webui/resources/js/search_highlight_utils.js
index f76e24f1d9e..aca22d545df 100644
--- a/chromium/ui/webui/resources/js/search_highlight_utils.js
+++ b/chromium/ui/webui/resources/js/search_highlight_utils.js
@@ -169,6 +169,7 @@ cr.define('cr.search_highlight_utils', function() {
}
// #cr_define_end
+ console.warn('crbug/1173575, non-JS module files deprecated.');
return {
Range,
createEmptySearchBubble,
diff --git a/chromium/ui/webui/resources/js/test_loader.js b/chromium/ui/webui/resources/js/test_loader.js
index dd40a21410b..54e0dcb8652 100644
--- a/chromium/ui/webui/resources/js/test_loader.js
+++ b/chromium/ui/webui/resources/js/test_loader.js
@@ -15,11 +15,7 @@
// chrome://test/ data source only exists in a testing context, so using this
// script in production will result in a failed network request.
-(function() {
-const params = new URLSearchParams(window.location.search);
-const module = params.get('module');
-const script = document.createElement('script');
-script.type = 'module';
-script.src = `chrome://test/${module}`;
-document.body.appendChild(script);
-})();
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {loadTestModule} from './test_loader_util.js';
+
+assert(loadTestModule());
diff --git a/chromium/ui/webui/resources/js/test_loader_util.js b/chromium/ui/webui/resources/js/test_loader_util.js
new file mode 100644
index 00000000000..f3f042387b0
--- /dev/null
+++ b/chromium/ui/webui/resources/js/test_loader_util.js
@@ -0,0 +1,17 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @return {boolean} Whether a test module was loaded. */
+export function loadTestModule() {
+ const params = new URLSearchParams(window.location.search);
+ const module = params.get('module');
+ if (!module) {
+ return false;
+ }
+ const script = document.createElement('script');
+ script.type = 'module';
+ script.src = `chrome://test/${module}`;
+ document.body.appendChild(script);
+ return true;
+}
diff --git a/chromium/ui/webui/resources/js/util.js b/chromium/ui/webui/resources/js/util.js
index 69091dfda6c..f4c4b01be7a 100644
--- a/chromium/ui/webui/resources/js/util.js
+++ b/chromium/ui/webui/resources/js/util.js
@@ -337,3 +337,5 @@
/* #export */ function isTextInputElement(el) {
return el.tagName === 'INPUT' || el.tagName === 'TEXTAREA';
}
+
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
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 e5c09b9d644..837518397f7 100644
--- a/chromium/ui/webui/resources/js/web_ui_listener_behavior.js
+++ b/chromium/ui/webui/resources/js/web_ui_listener_behavior.js
@@ -46,3 +46,5 @@
}
},
};
+
+/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.');
diff --git a/chromium/ui/webui/resources/tools/generate_grd.py b/chromium/ui/webui/resources/tools/generate_grd.py
index d65706e61ae..1b01dc7e4bb 100644
--- a/chromium/ui/webui/resources/tools/generate_grd.py
+++ b/chromium/ui/webui/resources/tools/generate_grd.py
@@ -5,7 +5,7 @@
# Generates a grit grd file from a list of input manifest files. This is useful
# for preventing the need to list JS files in multiple locations, as files can
# be listed just once in the BUILD.gn file as inputs for a build rule that knows
-# how to output such a manifest (e.g. preprocess_grit).
+# how to output such a manifest (e.g. preprocess_if_expr).
#
# Variables:
# manifest-files:
@@ -147,11 +147,19 @@ def main(argv):
if args.input_files != None:
assert(args.input_files_base_dir)
+ args.input_files_base_dir = args.input_files_base_dir.replace('\\', '/')
+ args.root_gen_dir = args.root_gen_dir.replace('\\', '/')
+
+ # Detect whether the input files reside under $root_src_dir or
+ # $root_gen_dir.
+ base_dir = os.path.join('${root_src_dir}', args.input_files_base_dir)
+ if args.input_files_base_dir.startswith(args.root_gen_dir + '/'):
+ base_dir = args.input_files_base_dir.replace(args.root_gen_dir + '/', '${root_gen_dir}/')
+
for filename in args.input_files:
- filepath = os.path.join(
- args.input_files_base_dir, filename).replace('\\', '/')
+ filepath = os.path.join(base_dir, filename).replace('\\', '/')
grd_file.write(_generate_include_row(
- args.grd_prefix, filename, '${root_src_dir}/' + filepath,
+ args.grd_prefix, filename, filepath,
resource_path_rewrites, args.resource_path_prefix))
if args.manifest_files != None:
diff --git a/chromium/ui/webui/resources/tools/generate_grd_test.py b/chromium/ui/webui/resources/tools/generate_grd_test.py
index c42d4f7eafe..70b0c5b0725 100755
--- a/chromium/ui/webui/resources/tools/generate_grd_test.py
+++ b/chromium/ui/webui/resources/tools/generate_grd_test.py
@@ -111,6 +111,15 @@ class GenerateGrdTest(unittest.TestCase):
input_files = [ 'images/test_svg.svg', 'test_html_in_src.html' ],
input_files_base_dir = 'test_src_dir')
+ def testSuccessWithGeneratedInputFiles(self):
+ # For generated |input_files|, |input_files_base_dir| must be a
+ # sub-directory of |root_gen_dir|.
+ base_dir = os.path.join(_CWD, pathToHere, 'tests', 'foo', 'bar')
+ self._run_test_(
+ 'expected_grd_with_generated_input_files.grd',
+ input_files = [ 'baz/a.svg', 'b.svg' ],
+ input_files_base_dir = base_dir)
+
def testSuccessWithGrdpFiles(self):
self._run_test_(
EXPECTED_GRD_WITH_GRDP_FILES,
diff --git a/chromium/ui/webui/resources/tools/js_modulizer.gni b/chromium/ui/webui/resources/tools/js_modulizer.gni
index f70bc47aa11..1fb046a68b3 100644
--- a/chromium/ui/webui/resources/tools/js_modulizer.gni
+++ b/chromium/ui/webui/resources/tools/js_modulizer.gni
@@ -25,7 +25,8 @@ common_namespace_rewrites = [
"cr.ui.focusWithoutInk|focusWithoutInk",
"cr.ui.KeyboardShortcutList|KeyboardShortcutList",
"cr.ui.Store|Store",
- "Polymer.dom.flush|flush",
+ "Polymer.dom.|",
+ "Polymer.dom(|dom(",
"Polymer.IronA11yAnnouncer|IronA11yAnnouncer",
"Polymer.PaperRippleBehavior|PaperRippleBehavior",
"Polymer.RenderStatus.afterNextRender|afterNextRender",
diff --git a/chromium/ui/webui/resources/webui_resources.grd b/chromium/ui/webui/resources/webui_resources.grd
index 461cd851af1..50939260fc8 100644
--- a/chromium/ui/webui/resources/webui_resources.grd
+++ b/chromium/ui/webui/resources/webui_resources.grd
@@ -16,73 +16,27 @@ without changes to the corresponding grd file. -->
<include name="IDR_WEBUI_JS_JSTEMPLATE_COMPILED_JS"
file="../../../third_party/jstemplate/jstemplate_compiled.js"
resource_path="js/jstemplate_compiled.js" type="BINDATA"/>
- <!-- Roboto Font. Roboto-Regular and Roboto-Light is already available on
- Android, and Roboto-Medium is not used on Android. All 6 weights of
- Roboto are available on Chrome OS.-->
- <if expr="not is_android and not chromeos">
- <include name="IDR_WEBUI_ROBOTO_ROBOTO_REGULAR_WOFF2" file="roboto/roboto-regular.woff2" type="BINDATA" />
- <include name="IDR_WEBUI_ROBOTO_ROBOTO_MEDIUM_WOFF2" file="roboto/roboto-medium.woff2" type="BINDATA" />
- <include name="IDR_WEBUI_ROBOTO_ROBOTO_BOLD_WOFF2" file="roboto/roboto-bold.woff2" type="BINDATA" />
+ <if expr="chromeos">
+ <include name="IDR_WEBUI_CROS_COLORS_CSS"
+ file="${root_gen_dir}/ui/chromeos/colors/cros_colors.generated.css"
+ resource_path="chromeos/colors/cros_colors.generated.css"
+ type="chrome_html"
+ use_base_dir="false" />
</if>
-
- <!-- Component apps common image resources - 1x -->
- <!-- Misc buttons -->
- <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_CLOSE_PNG"
- file="images/apps/topbar_button_close.png" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_MAXIMIZE_PNG"
- file="images/apps/topbar_button_maximize.png" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_MINIMIZE_PNG"
- file="images/apps/topbar_button_minimize.png" type="BINDATA" />
-
- <!-- Component apps common image resources - 2x -->
- <!-- Misc buttons -->
- <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_2X_CLOSE_PNG"
- file="images/2x/apps/topbar_button_close.png" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_2X_MAXIMIZE_PNG"
- file="images/2x/apps/topbar_button_maximize.png" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_2X_MINIMIZE_PNG"
- file="images/2x/apps/topbar_button_minimize.png" type="BINDATA" />
-
- <!-- Non-apps images -->
- <include name="IDR_WEBUI_IMAGES_ADD_SVG"
- file="images/add.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_CHECK_PNG"
- file="images/check.png" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_CHECKBOX_BLACK_PNG"
- file="images/checkbox_black.png" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_CHECKBOX_WHITE_PNG"
- file="images/checkbox_white.png" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_DISABLED_SELECT_PNG"
- file="images/disabled_select.png" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_ERROR_SVG"
- file="images/error.svg" type="BINDATA" />
- <!-- 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_SVG"
- file="images/error_badge.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_SELECT_PNG"
- file="images/select.png" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_THROBBER_MEDIUM_SVG"
- file="images/throbber_medium.svg" type="BINDATA" />
- <include name="IDR_WEBUI_IMAGES_THROBBER_SMALL_SVG"
- file="images/throbber_small.svg" type="BINDATA" />
-
- <if expr="not is_android">
- <part file="cr_components/cr_components_images.grdp" />
- <part file="cr_elements_images.grdp" />
+ <if expr="not is_android and not is_ios">
+ <include name="IDR_LOTTIE_LOTTIE_WORKER_MIN_JS"
+ file="../../../third_party/lottie/lottie_worker.min.js"
+ resource_path="lottie/lottie_worker.min.js"
+ type="BINDATA" />
</if>
</includes>
<structures>
- <structure name="IDR_WEBUI_CSS_CONTROLLED_INDICATOR_CSS"
- file="css/controlled_indicator.css" type="chrome_html" flattenhtml="true" />
<structure name="IDR_WEBUI_CSS_MENU_CSS"
file="css/menu.css" type="chrome_html"
flattenhtml="true" />
<structure name="IDR_WEBUI_CSS_MENU_BUTTON_CSS"
file="css/menu_button.css" type="chrome_html"
flattenhtml="true" />
- <structure name="IDR_WEBUI_CSS_OVERLAY_CSS"
- file="css/overlay.css" type="chrome_html"
- flattenhtml="true" />
<structure name="IDR_WEBUI_CSS_SPINNER_CSS"
file="css/spinner.css" type="chrome_html"
flattenhtml="true" />
@@ -92,25 +46,10 @@ without changes to the corresponding grd file. -->
<structure name="IDR_WEBUI_CSS_WIDGETS_CSS"
file="css/widgets.css" type="chrome_html"
flattenhtml="true" />
-
<if expr="chromeos">
- <structure name="IDR_WEBUI_CROS_COLORS_CSS"
- file="${root_gen_dir}/ui/chromeos/colors/cros_colors.generated.css"
- type="chrome_html"
- use_base_dir="false" />
- </if>
-
- <if expr="is_ios">
- <structure name="IDR_WEBUI_JS_IOS_WEB_UI"
- file="js/ios/web_ui.js" type="chrome_html" />
- <structure name="IDR_WEBUI_JS_IOS_MOJO_API"
- file="js/ios/mojo_api.js" type="chrome_html" />
- </if>
-
- <if expr="not is_android and not is_ios">
- <structure name="IDR_LOTTIE_LOTTIE_WORKER_MIN_JS"
- file="../../../third_party/lottie/lottie_worker.min.js"
- type="chrome_html" />
+ <structure name="IDR_WEBUI_CSS_OVERLAY_CSS"
+ file="css/overlay.css" type="chrome_html"
+ flattenhtml="true" />
</if>
</structures>
</release>
diff --git a/chromium/ui/webui/untrusted_web_ui_browsertest_util.cc b/chromium/ui/webui/untrusted_web_ui_browsertest_util.cc
new file mode 100644
index 00000000000..2167ab28f0c
--- /dev/null
+++ b/chromium/ui/webui/untrusted_web_ui_browsertest_util.cc
@@ -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.
+
+#include "ui/webui/untrusted_web_ui_browsertest_util.h"
+
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/url_constants.h"
+
+namespace ui {
+
+TestUntrustedWebUIControllerFactory::TestUntrustedWebUIControllerFactory() =
+ default;
+
+TestUntrustedWebUIControllerFactory::~TestUntrustedWebUIControllerFactory() =
+ default;
+
+const ui::UntrustedWebUIControllerFactory::WebUIConfigMap&
+TestUntrustedWebUIControllerFactory::GetWebUIConfigMap() {
+ return configs_;
+}
+
+TestUntrustedWebUIConfig::TestUntrustedWebUIConfig(base::StringPiece host)
+ : WebUIConfig(content::kChromeUIUntrustedScheme, host) {}
+
+TestUntrustedWebUIConfig::TestUntrustedWebUIConfig(
+ base::StringPiece host,
+ const content::TestUntrustedDataSourceCSP& content_security_policy)
+ : WebUIConfig(content::kChromeUIUntrustedScheme, host),
+ content_security_policy_(content_security_policy) {}
+
+TestUntrustedWebUIConfig::~TestUntrustedWebUIConfig() = default;
+
+std::unique_ptr<content::WebUIController>
+TestUntrustedWebUIConfig::CreateWebUIController(content::WebUI* web_ui) {
+ return std::make_unique<TestUntrustedWebUIController>(
+ web_ui, host(), content_security_policy_);
+}
+
+TestUntrustedWebUIController::TestUntrustedWebUIController(
+ content::WebUI* web_ui,
+ const std::string& host,
+ const content::TestUntrustedDataSourceCSP& content_security_policy)
+ : ui::UntrustedWebUIController(web_ui) {
+ content::AddUntrustedDataSource(web_ui->GetWebContents()->GetBrowserContext(),
+ host, content_security_policy);
+}
+
+TestUntrustedWebUIController::~TestUntrustedWebUIController() = default;
+
+} // namespace ui
diff --git a/chromium/ui/webui/untrusted_web_ui_browsertest_util.h b/chromium/ui/webui/untrusted_web_ui_browsertest_util.h
new file mode 100644
index 00000000000..dc9f124301b
--- /dev/null
+++ b/chromium/ui/webui/untrusted_web_ui_browsertest_util.h
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium 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_WEBUI_UNTRUSTED_WEB_UI_BROWSERTEST_UTIL_H_
+#define UI_WEBUI_UNTRUSTED_WEB_UI_BROWSERTEST_UTIL_H_
+
+#include "content/public/test/web_ui_browsertest_util.h"
+#include "ui/webui/untrusted_web_ui_controller.h"
+#include "ui/webui/untrusted_web_ui_controller_factory.h"
+#include "ui/webui/webui_config.h"
+
+namespace ui {
+
+class TestUntrustedWebUIControllerFactory
+ : public ui::UntrustedWebUIControllerFactory {
+ public:
+ TestUntrustedWebUIControllerFactory();
+ ~TestUntrustedWebUIControllerFactory() override;
+
+ void add_web_ui_config(std::unique_ptr<ui::WebUIConfig> config) {
+ const std::string host = config->host();
+ configs_.insert(std::make_pair(host, std::move(config)));
+ }
+
+ protected:
+ const WebUIConfigMap& GetWebUIConfigMap() override;
+
+ private:
+ WebUIConfigMap configs_;
+};
+
+class TestUntrustedWebUIConfig : public ui::WebUIConfig {
+ public:
+ explicit TestUntrustedWebUIConfig(base::StringPiece host);
+ explicit TestUntrustedWebUIConfig(
+ base::StringPiece host,
+ const content::TestUntrustedDataSourceCSP& content_security_policy);
+ ~TestUntrustedWebUIConfig() override;
+
+ std::unique_ptr<content::WebUIController> CreateWebUIController(
+ content::WebUI* web_ui) override;
+ const content::TestUntrustedDataSourceCSP content_security_policy_;
+};
+
+class TestUntrustedWebUIController : public ui::UntrustedWebUIController {
+ public:
+ explicit TestUntrustedWebUIController(
+ content::WebUI* web_ui,
+ const std::string& host,
+ const content::TestUntrustedDataSourceCSP& content_security_policy);
+ ~TestUntrustedWebUIController() override;
+};
+
+} // namespace ui
+
+#endif // UI_WEBUI_UNTRUSTED_WEB_UI_BROWSERTEST_UTIL_H_
diff --git a/chromium/ui/webui/untrusted_web_ui_controller.cc b/chromium/ui/webui/untrusted_web_ui_controller.cc
new file mode 100644
index 00000000000..370d08761c5
--- /dev/null
+++ b/chromium/ui/webui/untrusted_web_ui_controller.cc
@@ -0,0 +1,20 @@
+// Copyright 2020 The Chromium 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/webui/untrusted_web_ui_controller.h"
+
+#include "content/public/browser/web_ui.h"
+#include "content/public/common/bindings_policy.h"
+
+namespace ui {
+
+UntrustedWebUIController::UntrustedWebUIController(content::WebUI* web_ui)
+ : content::WebUIController(web_ui) {
+ // UntrustedWebUIController should never enable bindings.
+ web_ui->SetBindings(content::BINDINGS_POLICY_NONE);
+}
+
+UntrustedWebUIController::~UntrustedWebUIController() = default;
+
+} // namespace ui
diff --git a/chromium/ui/webui/untrusted_web_ui_controller.h b/chromium/ui/webui/untrusted_web_ui_controller.h
new file mode 100644
index 00000000000..a74f048d5fe
--- /dev/null
+++ b/chromium/ui/webui/untrusted_web_ui_controller.h
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium 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_WEBUI_UNTRUSTED_WEB_UI_CONTROLLER_H_
+#define UI_WEBUI_UNTRUSTED_WEB_UI_CONTROLLER_H_
+
+#include "content/public/browser/web_ui_controller.h"
+
+namespace content {
+class WebUI;
+}
+
+namespace ui {
+
+// UntrustedWebUIController is intended for WebUI pages that process untrusted
+// content. These WebUIController should never request WebUI bindings.
+class UntrustedWebUIController : public content::WebUIController {
+ public:
+ explicit UntrustedWebUIController(content::WebUI* contents);
+ ~UntrustedWebUIController() override;
+ UntrustedWebUIController(UntrustedWebUIController&) = delete;
+ UntrustedWebUIController& operator=(const UntrustedWebUIController&) = delete;
+};
+
+} // namespace ui
+
+#endif // UI_WEBUI_UNTRUSTED_WEB_UI_CONTROLLER_H_
diff --git a/chromium/ui/webui/untrusted_web_ui_controller_factory.cc b/chromium/ui/webui/untrusted_web_ui_controller_factory.cc
new file mode 100644
index 00000000000..d42607a2e17
--- /dev/null
+++ b/chromium/ui/webui/untrusted_web_ui_controller_factory.cc
@@ -0,0 +1,66 @@
+// Copyright 2020 The Chromium 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/webui/untrusted_web_ui_controller_factory.h"
+
+#include "base/no_destructor.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/common/url_constants.h"
+#include "ui/webui/webui_config.h"
+#include "url/gurl.h"
+
+namespace ui {
+
+UntrustedWebUIControllerFactory::UntrustedWebUIControllerFactory() = default;
+
+UntrustedWebUIControllerFactory::~UntrustedWebUIControllerFactory() = default;
+
+content::WebUI::TypeID UntrustedWebUIControllerFactory::GetWebUIType(
+ content::BrowserContext* browser_context,
+ const GURL& url) {
+ auto* config = GetConfigIfWebUIEnabled(browser_context, url);
+ if (!config)
+ return content::WebUI::kNoWebUI;
+
+ return reinterpret_cast<content::WebUI::TypeID>(config);
+}
+
+bool UntrustedWebUIControllerFactory::UseWebUIForURL(
+ content::BrowserContext* browser_context,
+ const GURL& url) {
+ return GetConfigIfWebUIEnabled(browser_context, url);
+}
+
+std::unique_ptr<content::WebUIController>
+UntrustedWebUIControllerFactory::CreateWebUIControllerForURL(
+ content::WebUI* web_ui,
+ const GURL& url) {
+ auto* browser_context = web_ui->GetWebContents()->GetBrowserContext();
+ auto* config = GetConfigIfWebUIEnabled(browser_context, url);
+ if (!config)
+ return nullptr;
+
+ return config->CreateWebUIController(web_ui);
+}
+
+ui::WebUIConfig* UntrustedWebUIControllerFactory::GetConfigIfWebUIEnabled(
+ content::BrowserContext* browser_context,
+ const GURL& url) {
+ // This factory doesn't support non chrome-untrusted:// WebUIs.
+ if (!url.SchemeIs(content::kChromeUIUntrustedScheme))
+ return nullptr;
+
+ auto it = GetWebUIConfigMap().find(url.host_piece());
+ if (it == GetWebUIConfigMap().end())
+ return nullptr;
+
+ if (!it->second->IsWebUIEnabled(browser_context))
+ return nullptr;
+
+ return it->second.get();
+}
+
+} // namespace ui
diff --git a/chromium/ui/webui/untrusted_web_ui_controller_factory.h b/chromium/ui/webui/untrusted_web_ui_controller_factory.h
new file mode 100644
index 00000000000..8e14c260cc7
--- /dev/null
+++ b/chromium/ui/webui/untrusted_web_ui_controller_factory.h
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium 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_WEBUI_UNTRUSTED_WEB_UI_CONTROLLER_FACTORY_H_
+#define UI_WEBUI_UNTRUSTED_WEB_UI_CONTROLLER_FACTORY_H_
+
+#include "content/public/browser/web_ui_controller_factory.h"
+
+class GURL;
+
+namespace content {
+class BrowserContext;
+class WebUIController;
+} // namespace content
+
+namespace ui {
+class WebUIConfig;
+
+// Factory class for WebUIControllers for chrome-untrusted:// URLs.
+//
+// To add a new WebUIController, subclass ui::WebUIConfig and add it to
+// `CreateConfigs()` in the .cc.
+class UntrustedWebUIControllerFactory : public content::WebUIControllerFactory {
+ public:
+ UntrustedWebUIControllerFactory();
+ ~UntrustedWebUIControllerFactory() override;
+ UntrustedWebUIControllerFactory(const UntrustedWebUIControllerFactory&) =
+ delete;
+ UntrustedWebUIControllerFactory& operator=(
+ const UntrustedWebUIControllerFactory&) = delete;
+
+ content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context,
+ const GURL& url) final;
+ bool UseWebUIForURL(content::BrowserContext* browser_context,
+ const GURL& url) final;
+ std::unique_ptr<content::WebUIController> CreateWebUIControllerForURL(
+ content::WebUI* web_ui,
+ const GURL& url) final;
+
+ protected:
+ // Map of hosts to their corresponding WebUIConfigs.
+ using WebUIConfigMap =
+ base::flat_map<std::string, std::unique_ptr<ui::WebUIConfig>>;
+ virtual const WebUIConfigMap& GetWebUIConfigMap() = 0;
+
+ private:
+ // Returns the WebUIConfig for |url| if it's registered and the WebUI is
+ // enabled. (WebUIs can be disabled based on the profile or feature flags.)
+ ui::WebUIConfig* GetConfigIfWebUIEnabled(
+ content::BrowserContext* browser_context,
+ const GURL& url);
+};
+
+} // namespace ui
+
+#endif // UI_WEBUI_UNTRUSTED_WEB_UI_CONTROLLER_FACTORY_H_
diff --git a/chromium/ui/webui/webui_config.cc b/chromium/ui/webui/webui_config.cc
new file mode 100644
index 00000000000..a6da93234d2
--- /dev/null
+++ b/chromium/ui/webui/webui_config.cc
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium 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/webui/webui_config.h"
+
+namespace ui {
+
+WebUIConfig::WebUIConfig(base::StringPiece scheme, base::StringPiece host)
+ : scheme_(scheme), host_(host) {}
+
+WebUIConfig::~WebUIConfig() = default;
+
+bool WebUIConfig::IsWebUIEnabled(content::BrowserContext* browser_context) {
+ return true;
+}
+
+} // namespace ui
diff --git a/chromium/ui/webui/webui_config.h b/chromium/ui/webui/webui_config.h
new file mode 100644
index 00000000000..9664e1ff567
--- /dev/null
+++ b/chromium/ui/webui/webui_config.h
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium 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_WEBUI_WEBUI_CONFIG_H_
+#define UI_WEBUI_WEBUI_CONFIG_H_
+
+#include <memory>
+#include <string>
+
+#include "base/strings/string_piece.h"
+
+namespace content {
+class BrowserContext;
+class WebUIController;
+class WebUI;
+} // namespace content
+
+namespace ui {
+
+// Class that stores properties for a WebUI.
+class WebUIConfig {
+ public:
+ explicit WebUIConfig(base::StringPiece scheme, base::StringPiece host);
+ virtual ~WebUIConfig();
+ WebUIConfig(const WebUIConfig&) = delete;
+ WebUIConfig& operator=(const WebUIConfig&) = delete;
+
+ // Scheme for the WebUI.
+ const std::string& scheme() const { return scheme_; }
+
+ // Host the WebUI serves.
+ const std::string& host() const { return host_; }
+
+ // Returns whether the WebUI is enabled e.g. the necessary feature flags are
+ // on/off, the WebUI is enabled in incognito, etc. Defaults to true.
+ virtual bool IsWebUIEnabled(content::BrowserContext* browser_context);
+
+ // Returns a WebUIController for the WebUI.
+ virtual std::unique_ptr<content::WebUIController> CreateWebUIController(
+ content::WebUI* web_ui) = 0;
+
+ private:
+ const std::string scheme_;
+ const std::string host_;
+};
+
+} // namespace ui
+
+#endif // UI_WEBUI_WEBUI_CONFIG_H_
diff --git a/chromium/ui/wm/BUILD.gn b/chromium/ui/wm/BUILD.gn
index bec18064d40..f92f96279d8 100644
--- a/chromium/ui/wm/BUILD.gn
+++ b/chromium/ui/wm/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
import("//testing/test.gni")
@@ -65,6 +66,7 @@ component("wm") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//skia",
"//ui/aura",
"//ui/base",
@@ -85,7 +87,7 @@ component("wm") {
"//ui/wm/public",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [
"core/ime_util_chromeos.cc",
"core/ime_util_chromeos.h",
@@ -140,6 +142,7 @@ test("wm_unittests") {
":wm",
"//base",
"//base/test:test_support",
+ "//build:chromeos_buildflags",
"//mojo/core/embedder",
"//skia",
"//testing/gtest",
@@ -163,7 +166,7 @@ test("wm_unittests") {
data_deps = [ "//ui/resources:ui_test_pak_data" ]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
sources += [ "core/ime_util_chromeos_unittest.cc" ]
}
}
diff --git a/chromium/ui/wm/DIR_METADATA b/chromium/ui/wm/DIR_METADATA
new file mode 100644
index 00000000000..f31293e3139
--- /dev/null
+++ b/chromium/ui/wm/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "UI"
+}
diff --git a/chromium/ui/wm/OWNERS b/chromium/ui/wm/OWNERS
deleted file mode 100644
index e7169536f86..00000000000
--- a/chromium/ui/wm/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# COMPONENT: UI
diff --git a/chromium/ui/wm/core/accelerator_filter.cc b/chromium/ui/wm/core/accelerator_filter.cc
index 598b141a885..a31247d527c 100644
--- a/chromium/ui/wm/core/accelerator_filter.cc
+++ b/chromium/ui/wm/core/accelerator_filter.cc
@@ -8,7 +8,6 @@
#include "build/build_config.h"
#include "ui/base/accelerators/accelerator.h"
-#include "ui/base/accelerators/accelerator_history.h"
#include "ui/events/event.h"
#include "ui/wm/core/accelerator_delegate.h"
@@ -18,12 +17,8 @@ namespace wm {
// AcceleratorFilter, public:
AcceleratorFilter::AcceleratorFilter(
- std::unique_ptr<AcceleratorDelegate> delegate,
- ui::AcceleratorHistory* accelerator_history)
- : delegate_(std::move(delegate)),
- accelerator_history_(accelerator_history) {
- DCHECK(accelerator_history);
-}
+ std::unique_ptr<AcceleratorDelegate> delegate)
+ : delegate_(std::move(delegate)) {}
AcceleratorFilter::~AcceleratorFilter() {
}
@@ -53,17 +48,8 @@ void AcceleratorFilter::OnKeyEvent(ui::KeyEvent* event) {
return;
ui::Accelerator accelerator(*event);
- accelerator_history_->StoreCurrentAccelerator(accelerator);
-
if (delegate_->ProcessAccelerator(*event, accelerator))
event->StopPropagation();
}
-void AcceleratorFilter::OnMouseEvent(ui::MouseEvent* event) {
- if (event->type() == ui::ET_MOUSE_PRESSED ||
- event->type() == ui::ET_MOUSE_RELEASED) {
- accelerator_history_->InterruptCurrentAccelerator();
- }
-}
-
} // namespace wm
diff --git a/chromium/ui/wm/core/accelerator_filter.h b/chromium/ui/wm/core/accelerator_filter.h
index 18f2764512a..f5c67576747 100644
--- a/chromium/ui/wm/core/accelerator_filter.h
+++ b/chromium/ui/wm/core/accelerator_filter.h
@@ -11,10 +11,6 @@
#include "ui/events/event_handler.h"
#include "ui/wm/core/wm_core_export.h"
-namespace ui {
-class AcceleratorHistory;
-}
-
namespace wm {
class AcceleratorDelegate;
@@ -24,8 +20,7 @@ class WM_CORE_EXPORT AcceleratorFilter : public ui::EventHandler {
public:
// AcceleratorFilter doesn't own |accelerator_history|, it's owned by
// AcceleratorController.
- AcceleratorFilter(std::unique_ptr<AcceleratorDelegate> delegate,
- ui::AcceleratorHistory* accelerator_history);
+ explicit AcceleratorFilter(std::unique_ptr<AcceleratorDelegate> delegate);
~AcceleratorFilter() override;
// If the return value is true, |event| should be filtered out.
@@ -33,11 +28,9 @@ class WM_CORE_EXPORT AcceleratorFilter : public ui::EventHandler {
// Overridden from ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
- void OnMouseEvent(ui::MouseEvent* event) override;
private:
std::unique_ptr<AcceleratorDelegate> delegate_;
- ui::AcceleratorHistory* accelerator_history_;
DISALLOW_COPY_AND_ASSIGN(AcceleratorFilter);
};
diff --git a/chromium/ui/wm/core/compound_event_filter.cc b/chromium/ui/wm/core/compound_event_filter.cc
index 12bba293428..4938b32a4ea 100644
--- a/chromium/ui/wm/core/compound_event_filter.cc
+++ b/chromium/ui/wm/core/compound_event_filter.cc
@@ -7,6 +7,7 @@
#include "base/check.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/env.h"
@@ -25,7 +26,7 @@ namespace {
// Returns true if the cursor should be hidden on touch events.
// TODO(tdanderson|rsadam): Move this function into CursorClient.
bool ShouldHideCursorOnTouch(const ui::TouchEvent& event) {
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
return true;
#else
// Linux Aura does not hide the cursor on touch by default.
@@ -249,4 +250,8 @@ void CompoundEventFilter::OnGestureEvent(ui::GestureEvent* event) {
}
}
+base::StringPiece CompoundEventFilter::GetLogContext() const {
+ return "CompoundEventFilter";
+}
+
} // namespace wm
diff --git a/chromium/ui/wm/core/compound_event_filter.h b/chromium/ui/wm/core/compound_event_filter.h
index ff96335af29..e012f7254c5 100644
--- a/chromium/ui/wm/core/compound_event_filter.h
+++ b/chromium/ui/wm/core/compound_event_filter.h
@@ -8,6 +8,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/observer_list.h"
+#include "base/strings/string_piece.h"
#include "ui/events/event.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/native_widget_types.h"
@@ -73,6 +74,7 @@ class WM_CORE_EXPORT CompoundEventFilter : public ui::EventHandler {
void OnScrollEvent(ui::ScrollEvent* event) override;
void OnTouchEvent(ui::TouchEvent* event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
+ base::StringPiece GetLogContext() const override;
// Additional pre-target event handlers.
base::ObserverList<ui::EventHandler, true>::Unchecked handlers_;
diff --git a/chromium/ui/wm/core/compound_event_filter_unittest.cc b/chromium/ui/wm/core/compound_event_filter_unittest.cc
index 51fcf0e53ec..75a2d07f851 100644
--- a/chromium/ui/wm/core/compound_event_filter_unittest.cc
+++ b/chromium/ui/wm/core/compound_event_filter_unittest.cc
@@ -6,6 +6,7 @@
#include "base/macros.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/env.h"
#include "ui/aura/test/aura_test_base.h"
@@ -21,12 +22,11 @@
namespace {
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
base::TimeTicks GetTime() {
return ui::EventTimeForNow();
}
-#endif // defined(OS_CHROMEOS) || defined(OS_WIN)
-
+#endif // BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
}
namespace wm {
@@ -50,7 +50,7 @@ class ConsumeGestureEventFilter : public ui::EventHandler {
typedef aura::test::AuraTestBase CompoundEventFilterTest;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// A keypress only hides the cursor on ChromeOS (crbug.com/304296).
TEST_F(CompoundEventFilterTest, CursorVisibilityChange) {
std::unique_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
@@ -108,9 +108,9 @@ TEST_F(CompoundEventFilterTest, CursorVisibilityChange) {
aura::Env::GetInstance()->RemovePreTargetHandler(compound_filter.get());
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
// Touch visually hides the cursor on ChromeOS and Windows.
TEST_F(CompoundEventFilterTest, TouchHidesCursor) {
std::unique_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
@@ -165,7 +165,7 @@ TEST_F(CompoundEventFilterTest, TouchHidesCursor) {
EXPECT_FALSE(cursor_client.IsCursorVisible());
aura::Env::GetInstance()->RemovePreTargetHandler(compound_filter.get());
}
-#endif // defined(OS_CHROMEOS) || defined(OS_WIN)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
// Tests that if an event filter consumes a gesture, then it doesn't focus the
// window.
diff --git a/chromium/ui/wm/core/focus_controller.cc b/chromium/ui/wm/core/focus_controller.cc
index fe10d1e9d7f..30d779881e6 100644
--- a/chromium/ui/wm/core/focus_controller.cc
+++ b/chromium/ui/wm/core/focus_controller.cc
@@ -84,8 +84,7 @@ bool FocusController::CanActivateWindow(const aura::Window* window) const {
////////////////////////////////////////////////////////////////////////////////
// FocusController, aura::client::FocusClient implementation:
-void FocusController::AddObserver(
- aura::client::FocusChangeObserver* observer) {
+void FocusController::AddObserver(aura::client::FocusChangeObserver* observer) {
focus_observers_.AddObserver(observer);
}
@@ -114,8 +113,7 @@ aura::Window* FocusController::GetFocusedWindow() {
////////////////////////////////////////////////////////////////////////////////
// FocusController, ui::EventHandler implementation:
-void FocusController::OnKeyEvent(ui::KeyEvent* event) {
-}
+void FocusController::OnKeyEvent(ui::KeyEvent* event) {}
void FocusController::OnMouseEvent(ui::MouseEvent* event) {
if (event->type() == ui::ET_MOUSE_PRESSED && !event->handled())
@@ -123,21 +121,22 @@ void FocusController::OnMouseEvent(ui::MouseEvent* event) {
event);
}
-void FocusController::OnScrollEvent(ui::ScrollEvent* event) {
-}
+void FocusController::OnScrollEvent(ui::ScrollEvent* event) {}
-void FocusController::OnTouchEvent(ui::TouchEvent* event) {
-}
+void FocusController::OnTouchEvent(ui::TouchEvent* event) {}
void FocusController::OnGestureEvent(ui::GestureEvent* event) {
if (event->type() == ui::ET_GESTURE_BEGIN &&
- event->details().touch_points() == 1 &&
- !event->handled()) {
+ event->details().touch_points() == 1 && !event->handled()) {
WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()),
event);
}
}
+base::StringPiece FocusController::GetLogContext() const {
+ return "FocusController";
+}
+
////////////////////////////////////////////////////////////////////////////////
// FocusController, aura::WindowObserver implementation:
@@ -155,16 +154,17 @@ void FocusController::OnWindowDestroying(aura::Window* window) {
// We may have already stopped observing |window| if `SetActiveWindow()` was
// called inside `WindowLostFocusFromDispositionChange()`.
- if (observer_manager_.IsObserving(window))
- observer_manager_.Remove(window);
+ if (observation_manager_.IsObservingSource(window))
+ observation_manager_.RemoveObservation(window);
}
void FocusController::OnWindowHierarchyChanging(
const HierarchyChangeParams& params) {
if (params.receiver == active_window_ &&
- params.target->Contains(params.receiver) && (!params.new_parent ||
- aura::client::GetFocusClient(params.new_parent) !=
- aura::client::GetFocusClient(params.receiver))) {
+ params.target->Contains(params.receiver) &&
+ (!params.new_parent ||
+ aura::client::GetFocusClient(params.new_parent) !=
+ aura::client::GetFocusClient(params.receiver))) {
WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
}
}
@@ -172,9 +172,10 @@ void FocusController::OnWindowHierarchyChanging(
void FocusController::OnWindowHierarchyChanged(
const HierarchyChangeParams& params) {
if (params.receiver == focused_window_ &&
- params.target->Contains(params.receiver) && (!params.new_parent ||
- aura::client::GetFocusClient(params.new_parent) !=
- aura::client::GetFocusClient(params.receiver))) {
+ params.target->Contains(params.receiver) &&
+ (!params.new_parent ||
+ aura::client::GetFocusClient(params.new_parent) !=
+ aura::client::GetFocusClient(params.receiver))) {
WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
}
}
@@ -258,13 +259,15 @@ void FocusController::SetFocusedWindow(aura::Window* window) {
aura::WindowTracker window_tracker;
if (lost_focus)
window_tracker.Add(lost_focus);
- if (focused_window_ && observer_manager_.IsObserving(focused_window_) &&
+ if (focused_window_ &&
+ observation_manager_.IsObservingSource(focused_window_) &&
focused_window_ != active_window_) {
- observer_manager_.Remove(focused_window_);
+ observation_manager_.RemoveObservation(focused_window_);
}
focused_window_ = window;
- if (focused_window_ && !observer_manager_.IsObserving(focused_window_))
- observer_manager_.Add(focused_window_);
+ if (focused_window_ &&
+ !observation_manager_.IsObservingSource(focused_window_))
+ observation_manager_.AddObservation(focused_window_);
for (auto& observer : focus_observers_) {
observer.OnWindowFocused(
@@ -326,8 +329,8 @@ bool FocusController::SetActiveWindow(
// Start observing the window gaining activation at this point since it maybe
// destroyed at an early stage, e.g. the activating phase.
- if (window && !observer_manager_.IsObserving(window))
- observer_manager_.Add(window);
+ if (window && !observation_manager_.IsObservingSource(window))
+ observation_manager_.AddObservation(window);
for (auto& observer : activation_observers_) {
observer.OnWindowActivating(reason, window, active_window_);
@@ -335,9 +338,10 @@ bool FocusController::SetActiveWindow(
MAYBE_ACTIVATION_INTERRUPTED();
}
- if (active_window_ && observer_manager_.IsObserving(active_window_) &&
+ if (active_window_ &&
+ observation_manager_.IsObservingSource(active_window_) &&
focused_window_ != active_window_) {
- observer_manager_.Remove(active_window_);
+ observation_manager_.RemoveObservation(active_window_);
}
active_window_ = window;
@@ -383,9 +387,8 @@ void FocusController::StackActiveWindow() {
}
}
-void FocusController::WindowLostFocusFromDispositionChange(
- aura::Window* window,
- aura::Window* next) {
+void FocusController::WindowLostFocusFromDispositionChange(aura::Window* window,
+ aura::Window* next) {
// TODO(beng): See if this function can be replaced by a call to
// FocusWindow().
// Activation adjustments are handled first in the event of a disposition
diff --git a/chromium/ui/wm/core/focus_controller.h b/chromium/ui/wm/core/focus_controller.h
index ee6f51f7449..19014a7c255 100644
--- a/chromium/ui/wm/core/focus_controller.h
+++ b/chromium/ui/wm/core/focus_controller.h
@@ -11,7 +11,8 @@
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_multi_source_observation.h"
+#include "base/strings/string_piece.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window_observer.h"
#include "ui/events/event_handler.h"
@@ -75,6 +76,7 @@ class WM_CORE_EXPORT FocusController : public ActivationClient,
void OnScrollEvent(ui::ScrollEvent* event) override;
void OnTouchEvent(ui::TouchEvent* event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
+ base::StringPiece GetLogContext() const override;
// Overridden from aura::WindowObserver:
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
@@ -136,7 +138,8 @@ class WM_CORE_EXPORT FocusController : public ActivationClient,
base::ObserverList<aura::client::FocusChangeObserver>::Unchecked
focus_observers_;
- ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_{this};
+ base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
+ observation_manager_{this};
DISALLOW_COPY_AND_ASSIGN(FocusController);
};
diff --git a/chromium/ui/wm/core/ime_util_chromeos.cc b/chromium/ui/wm/core/ime_util_chromeos.cc
index 03e9807652e..552ea8cbda4 100644
--- a/chromium/ui/wm/core/ime_util_chromeos.cc
+++ b/chromium/ui/wm/core/ime_util_chromeos.cc
@@ -59,9 +59,6 @@ DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Rect,
nullptr)
void RestoreWindowBoundsOnClientFocusLost(aura::Window* window) {
- window->GetRootWindow()->ClearProperty(
- aura::client::kEmbeddedWindowEnsureNotInRect);
-
// Get restore bounds of the window
gfx::Rect* vk_restore_bounds =
window->GetProperty(kVirtualKeyboardRestoreBoundsKey);
@@ -97,37 +94,4 @@ void EnsureWindowNotInRect(aura::Window* window,
MoveWindowToEnsureCaretNotInRect(window, rect_in_screen);
}
-EnsureWindowNotInRectHelper::EnsureWindowNotInRectHelper(
- aura::Window* embedding_root)
- : embedding_root_(embedding_root) {
- embedding_root_->AddObserver(this);
-}
-
-EnsureWindowNotInRectHelper::~EnsureWindowNotInRectHelper() {
- if (embedding_root_)
- embedding_root_->RemoveObserver(this);
-}
-
-void EnsureWindowNotInRectHelper::OnWindowPropertyChanged(aura::Window* window,
- const void* key,
- intptr_t old) {
- DCHECK_EQ(embedding_root_, window);
-
- if (key != aura::client::kEmbeddedWindowEnsureNotInRect)
- return;
-
- aura::Window* top_level = embedding_root_->GetToplevelWindow();
- gfx::Rect* rect_in_screen = embedding_root_->GetProperty(
- aura::client::kEmbeddedWindowEnsureNotInRect);
- if (rect_in_screen)
- EnsureWindowNotInRect(top_level, *rect_in_screen);
- else
- RestoreWindowBoundsOnClientFocusLost(top_level);
-}
-
-void EnsureWindowNotInRectHelper::OnWindowDestroyed(aura::Window* window) {
- DCHECK_EQ(embedding_root_, window);
- embedding_root_ = nullptr;
-}
-
} // namespace wm
diff --git a/chromium/ui/wm/core/ime_util_chromeos.h b/chromium/ui/wm/core/ime_util_chromeos.h
index 346820cece0..eb5faae96f7 100644
--- a/chromium/ui/wm/core/ime_util_chromeos.h
+++ b/chromium/ui/wm/core/ime_util_chromeos.h
@@ -6,7 +6,6 @@
#define UI_WM_CORE_IME_UTIL_CHROMEOS_H_
#include "ui/aura/window.h"
-#include "ui/aura/window_observer.h"
#include "ui/wm/core/wm_core_export.h"
namespace gfx {
@@ -20,11 +19,7 @@ namespace wm {
WM_CORE_EXPORT extern const aura::WindowProperty<gfx::Rect*>* const
kVirtualKeyboardRestoreBoundsKey;
-// Moves |window| to ensure it does not intersect with |rect_in_screen| if it
-// does not belong to an embedded window tree. Otherwise, sets |rect_in_screen|
-// in kEmbeddedWindowEnsureNotInRect window property on the root window of the
-// embedded tree so that the embedding side could forward the call to the
-// relevant top level window. See also EnsureWindowNotInRectHelper.
+// Moves |window| to ensure it does not intersect with |rect_in_screen|.
WM_CORE_EXPORT void EnsureWindowNotInRect(aura::Window* window,
const gfx::Rect& rect_in_screen);
@@ -32,25 +27,6 @@ WM_CORE_EXPORT void EnsureWindowNotInRect(aura::Window* window,
WM_CORE_EXPORT void RestoreWindowBoundsOnClientFocusLost(
aura::Window* top_level_window);
-// Helper to call EnsureWindowNotInRect/RestoreWindowBoundsOnClientFocusLost
-// on the top-level window of an embedding root when its
-// kEmbeddedWindowEnsureNotInRect window property changes.
-class WM_CORE_EXPORT EnsureWindowNotInRectHelper : public aura::WindowObserver {
- public:
- explicit EnsureWindowNotInRectHelper(aura::Window* embedding_root);
- ~EnsureWindowNotInRectHelper() override;
-
- private:
- // aura::WindowObsever:
- void OnWindowPropertyChanged(aura::Window* window,
- const void* key,
- intptr_t old) override;
- void OnWindowDestroyed(aura::Window* window) override;
-
- aura::Window* embedding_root_ = nullptr;
- DISALLOW_COPY_AND_ASSIGN(EnsureWindowNotInRectHelper);
-};
-
} // namespace wm
#endif // UI_WM_CORE_IME_UTIL_CHROMEOS_H_
diff --git a/chromium/ui/wm/core/ime_util_chromeos_unittest.cc b/chromium/ui/wm/core/ime_util_chromeos_unittest.cc
index 3096705ed1e..41fe2f194be 100644
--- a/chromium/ui/wm/core/ime_util_chromeos_unittest.cc
+++ b/chromium/ui/wm/core/ime_util_chromeos_unittest.cc
@@ -128,23 +128,4 @@ TEST_F(ImeUtilChromeosTest, MoveUpThenRestore) {
EXPECT_EQ(original_bounds, window->GetBoundsInScreen());
}
-// Tests that setting/clearing kEmbeddedWindowEnsureNotInRect window property
-// triggers the relevant top level to be moved/restored.
-TEST_F(ImeUtilChromeosTest, EnsureWindowNotInRectHelper) {
- const gfx::Rect original_bounds(10, 10, 100, 100);
- aura::Window* top_level = aura::test::CreateTestWindow(
- SK_ColorWHITE, 1, original_bounds, root_window());
- aura::Window* embedding_root = aura::test::CreateTestWindowWithBounds(
- gfx::Rect(original_bounds.size()), top_level);
- EnsureWindowNotInRectHelper helper(embedding_root);
-
- gfx::Rect occluded_rect(50, 50, 200, 200);
- embedding_root->SetProperty(aura::client::kEmbeddedWindowEnsureNotInRect,
- new gfx::Rect(occluded_rect));
- EXPECT_EQ(gfx::Rect(10, 0, 100, 100), top_level->bounds());
-
- embedding_root->ClearProperty(aura::client::kEmbeddedWindowEnsureNotInRect);
- EXPECT_EQ(original_bounds, top_level->bounds());
-}
-
} // namespace wm
diff --git a/chromium/ui/wm/core/shadow_controller.cc b/chromium/ui/wm/core/shadow_controller.cc
index 6b6712ca266..591abd7a960 100644
--- a/chromium/ui/wm/core/shadow_controller.cc
+++ b/chromium/ui/wm/core/shadow_controller.cc
@@ -8,11 +8,11 @@
#include "base/check.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/no_destructor.h"
-#include "base/scoped_observer.h"
-#include "base/stl_util.h"
+#include "base/scoped_multi_source_observation.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
#include "ui/aura/env_observer.h"
@@ -128,7 +128,8 @@ class ShadowController::Impl :
void CreateShadowForWindow(aura::Window* window);
aura::Env* const env_;
- ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
+ base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
+ observation_manager_{this};
std::unique_ptr<ShadowControllerDelegate> delegate_;
@@ -146,14 +147,14 @@ ShadowController::Impl* ShadowController::Impl::GetInstance(aura::Env* env) {
}
bool ShadowController::Impl::IsShadowVisibleForWindow(aura::Window* window) {
- if (!observer_manager_.IsObserving(window))
+ if (!observation_manager_.IsObservingSource(window))
return false;
ui::Shadow* shadow = GetShadowForWindow(window);
return shadow && shadow->layer()->visible();
}
void ShadowController::Impl::UpdateShadowForWindow(aura::Window* window) {
- DCHECK(observer_manager_.IsObserving(window));
+ DCHECK(observation_manager_.IsObservingSource(window));
HandlePossibleShadowVisibilityChange(window);
}
@@ -162,7 +163,7 @@ void ShadowController::Impl::OnWindowInitialized(aura::Window* window) {
// root window. That must be checked in the first visibility change
DCHECK(!window->parent());
DCHECK(!window->TargetVisibility());
- observer_manager_.Add(window);
+ observation_manager_.AddObservation(window);
}
void ShadowController::Impl::OnWindowParentChanged(aura::Window* window,
@@ -198,7 +199,7 @@ void ShadowController::Impl::OnWindowVisibilityChanging(aura::Window* window,
// which clips to the root window bounds; filling any rounded corners the
// window may have.
if (window->IsRootWindow()) {
- observer_manager_.Remove(window);
+ observation_manager_.RemoveObservation(window);
return;
}
@@ -217,7 +218,7 @@ void ShadowController::Impl::OnWindowBoundsChanged(
void ShadowController::Impl::OnWindowDestroyed(aura::Window* window) {
window->ClearProperty(kShadowLayerKey);
- observer_manager_.Remove(window);
+ observation_manager_.RemoveObservation(window);
}
void ShadowController::Impl::OnWindowActivated(ActivationReason reason,
@@ -286,7 +287,7 @@ void ShadowController::Impl::CreateShadowForWindow(aura::Window* window) {
}
ShadowController::Impl::Impl(aura::Env* env)
- : env_(env), observer_manager_(this) {
+ : env_(env), observation_manager_(this) {
GetInstances()->insert(this);
env_->AddObserver(this);
}
diff --git a/chromium/ui/wm/core/transient_window_manager.cc b/chromium/ui/wm/core/transient_window_manager.cc
index e5fa6ea3623..f045c10f854 100644
--- a/chromium/ui/wm/core/transient_window_manager.cc
+++ b/chromium/ui/wm/core/transient_window_manager.cc
@@ -8,7 +8,7 @@
#include <functional>
#include "base/auto_reset.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "ui/aura/client/transient_window_client.h"
#include "ui/aura/client/transient_window_client_observer.h"
#include "ui/aura/window.h"
diff --git a/chromium/ui/wm/core/window_animations.cc b/chromium/ui/wm/core/window_animations.cc
index f26851877b5..0d27971f235 100644
--- a/chromium/ui/wm/core/window_animations.cc
+++ b/chromium/ui/wm/core/window_animations.cc
@@ -13,10 +13,10 @@
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
+#include "base/containers/contains.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
#include "base/time/time.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
@@ -443,10 +443,7 @@ void AddLayerAnimationsForRotate(aura::Window* window, bool show) {
base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
kWindowAnimation_Rotate_DurationMS);
- RotateHidingWindowAnimationObserver* observer = nullptr;
-
if (!show) {
- observer = new RotateHidingWindowAnimationObserver(window);
window->layer()->GetAnimator()->SchedulePauseForProperties(
duration * (100 - kWindowAnimation_Rotate_OpacityDurationPercent) / 100,
ui::LayerAnimationElement::OPACITY);
@@ -494,10 +491,17 @@ void AddLayerAnimationsForRotate(aura::Window* window, bool show) {
std::move(rotation), duration);
ui::LayerAnimationSequence* last_sequence =
new ui::LayerAnimationSequence(std::move(transition));
+ auto weak_last_sequence = last_sequence->AsWeakPtr();
window->layer()->GetAnimator()->ScheduleAnimation(last_sequence);
-
- if (observer) {
- observer->SetLastSequence(last_sequence);
+ // If the animation is immediate, then |last_sequence| will have been
+ // deleted.
+ last_sequence = nullptr;
+
+ if (!show && weak_last_sequence) {
+ // RotateHidingWindowAnimationObserver deletes itself when no longer
+ // needed.
+ auto* observer = new RotateHidingWindowAnimationObserver(window);
+ observer->SetLastSequence(weak_last_sequence.get());
observer->DetachAndRecreateLayers();
}
@@ -663,6 +667,15 @@ bool AnimateWindow(aura::Window* window, WindowAnimationType type) {
}
bool WindowAnimationsDisabled(aura::Window* window) {
+ // WARNING: this function is called from VisibilityController to determine
+ // if an animation should happen when the Window's visibility changes.
+ // Returning false results in VisibilityController applying default
+ // handling of the transition. This can result in dramatically different
+ // results than if an animation occurs. For example, VisibilityController
+ // doesn't change the opacity, yet many of the animations do. Similarly,
+ // ash's animations may change the bounds, which VisibilityController won't
+ // do. Take care when adding a new path that returns false.
+
// Individual windows can choose to skip animations.
if (window && window->GetProperty(aura::client::kAnimationsDisabledKey))
return true;
diff --git a/chromium/ui/wm/core/window_animations_unittest.cc b/chromium/ui/wm/core/window_animations_unittest.cc
index 5eac66a3064..e0c60ed85ae 100644
--- a/chromium/ui/wm/core/window_animations_unittest.cc
+++ b/chromium/ui/wm/core/window_animations_unittest.cc
@@ -6,8 +6,8 @@
#include <memory>
+#include "base/containers/contains.h"
#include "base/macros.h"
-#include "base/stl_util.h"
#include "base/time/time.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/test_windows.h"
@@ -285,7 +285,7 @@ TEST_F(WindowAnimationsTest, RotateHideNoLeak) {
ui::ScopedAnimationDurationScaleMode::FAST_DURATION);
std::unique_ptr<aura::Window> window(
- aura::test::CreateTestWindowWithId(0, NULL));
+ aura::test::CreateTestWindowWithId(0, nullptr));
ui::Layer* animating_layer = window->layer();
wm::SetWindowVisibilityAnimationType(window.get(),
WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE);
@@ -296,6 +296,37 @@ TEST_F(WindowAnimationsTest, RotateHideNoLeak) {
animating_layer->GetAnimator()->StopAnimating();
}
+// The rotation animation for hiding a window should not crash with a zero
+// duration.
+TEST_F(WindowAnimationsTest, RotateHideNoCrashZeroDuration) {
+ std::unique_ptr<aura::Window> window(
+ aura::test::CreateTestWindowWithId(0, nullptr));
+ wm::SetWindowVisibilityAnimationType(window.get(),
+ WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE);
+
+ AnimateOnChildWindowVisibilityChanged(window.get(), true);
+ AnimateOnChildWindowVisibilityChanged(window.get(), false);
+}
+
+TEST_F(WindowAnimationsTest, RotateHideCreatesNewLayer) {
+ ui::ScopedAnimationDurationScaleMode scale_mode(
+ ui::ScopedAnimationDurationScaleMode::FAST_DURATION);
+
+ std::unique_ptr<aura::Window> window(
+ aura::test::CreateTestWindowWithId(0, nullptr));
+ wm::SetWindowVisibilityAnimationType(window.get(),
+ WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE);
+ AnimateOnChildWindowVisibilityChanged(window.get(), true);
+ window->layer()->GetAnimator()->StopAnimating();
+
+ auto* original_layer = window->layer();
+ AnimateOnChildWindowVisibilityChanged(window.get(), false);
+ // The layer should have changed, as the Layer is cloned and detached.
+ EXPECT_NE(original_layer, window->layer());
+ // Need to stop the animation, otherwise there is a leak.
+ original_layer->GetAnimator()->StopAnimating();
+}
+
// The rotation animation for hiding a window should not crash when terminated
// by LayerAnimator::StopAnimating().
TEST_F(WindowAnimationsTest, RotateHideNoCrash) {
diff --git a/chromium/ui/wm/core/window_modality_controller.cc b/chromium/ui/wm/core/window_modality_controller.cc
index c3503e62036..2a1bf8506c9 100644
--- a/chromium/ui/wm/core/window_modality_controller.cc
+++ b/chromium/ui/wm/core/window_modality_controller.cc
@@ -132,6 +132,10 @@ void WindowModalityController::OnTouchEvent(ui::TouchEvent* event) {
event->SetHandled();
}
+base::StringPiece WindowModalityController::GetLogContext() const {
+ return "WindowModalityController";
+}
+
////////////////////////////////////////////////////////////////////////////////
// WindowModalityController, aura::EnvObserver implementation:
diff --git a/chromium/ui/wm/core/window_modality_controller.h b/chromium/ui/wm/core/window_modality_controller.h
index 8a9f9293b61..faffc15d5fe 100644
--- a/chromium/ui/wm/core/window_modality_controller.h
+++ b/chromium/ui/wm/core/window_modality_controller.h
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "ui/aura/env_observer.h"
#include "ui/aura/window_observer.h"
#include "ui/events/event_handler.h"
@@ -49,6 +50,7 @@ class WM_CORE_EXPORT WindowModalityController : public ui::EventHandler,
void OnKeyEvent(ui::KeyEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
void OnTouchEvent(ui::TouchEvent* event) override;
+ base::StringPiece GetLogContext() const override;
// Overridden from aura::EnvObserver:
void OnWindowInitialized(aura::Window* window) override;